Most of framed drawer stuff

This commit is contained in:
Buuz135 2022-07-03 20:11:34 +02:00
parent 8ea488059a
commit 302842c798
31 changed files with 1130 additions and 60 deletions

View File

@ -91,7 +91,7 @@ repositories {
dependencies {
minecraft 'net.minecraftforge:forge:1.18.2-40.1.18'
minecraft 'net.minecraftforge:forge:1.18.2-40.1.19'
implementation fg.deobf (project.dependencies.create('com.hrznstudio:titanium:1.18.2-3.5.6-38'))
compileOnly fg.deobf("mezz.jei:jei-1.18.2:9.7.0.180:api")
runtimeOnly fg.deobf("mezz.jei:jei-1.18.2:9.7.0.180")

View File

@ -0,0 +1,34 @@
{
"variants": {
"locked=false,subfacing=north": {
"model": "functionalstorage:block/framed_1"
},
"locked=true,subfacing=north": {
"model": "functionalstorage:block/framed_1_locked"
},
"locked=false,subfacing=south": {
"model": "functionalstorage:block/framed_1",
"y": 180
},
"locked=true,subfacing=south": {
"model": "functionalstorage:block/framed_1_locked",
"y": 180
},
"locked=false,subfacing=west": {
"model": "functionalstorage:block/framed_1",
"y": 270
},
"locked=true,subfacing=west": {
"model": "functionalstorage:block/framed_1_locked",
"y": 270
},
"locked=false,subfacing=east": {
"model": "functionalstorage:block/framed_1",
"y": 90
},
"locked=true,subfacing=east": {
"model": "functionalstorage:block/framed_1_locked",
"y": 90
}
}
}

View File

@ -0,0 +1,34 @@
{
"variants": {
"locked=false,subfacing=north": {
"model": "functionalstorage:block/framed_2"
},
"locked=true,subfacing=north": {
"model": "functionalstorage:block/framed_2_locked"
},
"locked=false,subfacing=south": {
"model": "functionalstorage:block/framed_2",
"y": 180
},
"locked=true,subfacing=south": {
"model": "functionalstorage:block/framed_2_locked",
"y": 180
},
"locked=false,subfacing=west": {
"model": "functionalstorage:block/framed_2",
"y": 270
},
"locked=true,subfacing=west": {
"model": "functionalstorage:block/framed_2_locked",
"y": 270
},
"locked=false,subfacing=east": {
"model": "functionalstorage:block/framed_2",
"y": 90
},
"locked=true,subfacing=east": {
"model": "functionalstorage:block/framed_2_locked",
"y": 90
}
}
}

View File

@ -0,0 +1,34 @@
{
"variants": {
"locked=false,subfacing=north": {
"model": "functionalstorage:block/framed_4"
},
"locked=true,subfacing=north": {
"model": "functionalstorage:block/framed_4_locked"
},
"locked=false,subfacing=south": {
"model": "functionalstorage:block/framed_4",
"y": 180
},
"locked=true,subfacing=south": {
"model": "functionalstorage:block/framed_4_locked",
"y": 180
},
"locked=false,subfacing=west": {
"model": "functionalstorage:block/framed_4",
"y": 270
},
"locked=true,subfacing=west": {
"model": "functionalstorage:block/framed_4_locked",
"y": 270
},
"locked=false,subfacing=east": {
"model": "functionalstorage:block/framed_4",
"y": 90
},
"locked=true,subfacing=east": {
"model": "functionalstorage:block/framed_4_locked",
"y": 90
}
}
}

View File

@ -27,6 +27,9 @@
"block.functionalstorage.warped_1": "Warped Drawer (1x1)",
"block.functionalstorage.warped_2": "Warped Drawer (1x2)",
"block.functionalstorage.warped_4": "Warped Drawer (2x2)",
"block.functionalstorage.framed_1": "Framed Drawer (1x1)",
"block.functionalstorage.framed_2": "Framed Drawer (1x2)",
"block.functionalstorage.framed_4": "Framed Drawer (2x2)",
"configurationtool.configmode": "Config Mode: ",
"configurationtool.configmode.locking": "Locking",
"configurationtool.configmode.toggle_numbers": "Hide/Show Amounts",

View File

@ -0,0 +1,6 @@
{
"parent": "functionalstorage:block/framed_1",
"textures": {
"lock_icon": "functionalstorage:blocks/lock"
}
}

View File

@ -0,0 +1,6 @@
{
"parent": "functionalstorage:block/framed_2",
"textures": {
"lock_icon": "functionalstorage:blocks/lock"
}
}

View File

@ -0,0 +1,6 @@
{
"parent": "functionalstorage:block/framed_4",
"textures": {
"lock_icon": "functionalstorage:blocks/lock"
}
}

View File

@ -0,0 +1,3 @@
{
"parent": "functionalstorage:block/framed_1"
}

View File

@ -0,0 +1,3 @@
{
"parent": "functionalstorage:block/framed_2"
}

View File

@ -0,0 +1,3 @@
{
"parent": "functionalstorage:block/framed_4"
}

View File

@ -1,14 +1,12 @@
package com.buuz135.functionalstorage;
import com.buuz135.functionalstorage.block.*;
import com.buuz135.functionalstorage.block.tile.CompactingDrawerTile;
import com.buuz135.functionalstorage.block.tile.DrawerControllerTile;
import com.buuz135.functionalstorage.block.tile.DrawerTile;
import com.buuz135.functionalstorage.block.tile.EnderDrawerTile;
import com.buuz135.functionalstorage.block.tile.*;
import com.buuz135.functionalstorage.client.CompactingDrawerRenderer;
import com.buuz135.functionalstorage.client.ControllerRenderer;
import com.buuz135.functionalstorage.client.DrawerRenderer;
import com.buuz135.functionalstorage.client.EnderDrawerRenderer;
import com.buuz135.functionalstorage.client.loader.RetexturedModel;
import com.buuz135.functionalstorage.data.FunctionalStorageBlockTagsProvider;
import com.buuz135.functionalstorage.data.FunctionalStorageBlockstateProvider;
import com.buuz135.functionalstorage.data.FunctionalStorageItemTagsProvider;
@ -21,6 +19,7 @@ import com.buuz135.functionalstorage.item.StorageUpgradeItem;
import com.buuz135.functionalstorage.item.UpgradeItem;
import com.buuz135.functionalstorage.network.EnderDrawerSyncMessage;
import com.buuz135.functionalstorage.recipe.DrawerlessWoodIngredient;
import com.buuz135.functionalstorage.recipe.FramedDrawerRecipe;
import com.buuz135.functionalstorage.util.*;
import com.hrznstudio.titanium.block.BasicBlock;
import com.hrznstudio.titanium.block.BasicTileBlock;
@ -28,6 +27,7 @@ import com.hrznstudio.titanium.datagenerator.loot.TitaniumLootTableProvider;
import com.hrznstudio.titanium.datagenerator.model.BlockItemModelGeneratorProvider;
import com.hrznstudio.titanium.event.handler.EventManager;
import com.hrznstudio.titanium.module.ModuleController;
import com.hrznstudio.titanium.nbthandler.NBTManager;
import com.hrznstudio.titanium.network.NetworkHandler;
import com.hrznstudio.titanium.recipe.generator.TitaniumRecipeProvider;
import com.hrznstudio.titanium.recipe.generator.TitaniumShapedRecipeBuilder;
@ -51,7 +51,9 @@ import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.client.event.ColorHandlerEvent;
import net.minecraftforge.client.event.EntityRenderersEvent;
import net.minecraftforge.client.event.ModelRegistryEvent;
import net.minecraftforge.client.event.RenderTooltipEvent;
import net.minecraftforge.client.model.ModelLoaderRegistry;
import net.minecraftforge.client.model.generators.BlockModelProvider;
import net.minecraftforge.client.model.generators.ItemModelProvider;
import net.minecraftforge.common.Tags;
@ -88,7 +90,7 @@ public class FunctionalStorage extends ModuleController {
}
// Directly reference a log4j logger.
private static final Logger LOGGER = LogManager.getLogger();
public static final Logger LOGGER = LogManager.getLogger();
public static List<IWoodType> WOOD_TYPES = new ArrayList<>();
@ -138,6 +140,10 @@ public class FunctionalStorage extends ModuleController {
EventManager.modGeneric(RegistryEvent.Register.class, RecipeSerializer.class).process(register -> {
CraftingHelper.register(DrawerlessWoodIngredient.NAME, DrawerlessWoodIngredient.SERIALIZER);
}).subscribe();
EventManager.modGeneric(RegistryEvent.Register.class, RecipeSerializer.class)
.process(register -> ((RegistryEvent.Register) register).getRegistry()
.registerAll(FramedDrawerRecipe.SERIALIZER.setRegistryName(new ResourceLocation(MOD_ID, "framed_recipe")))).subscribe();
NBTManager.getInstance().scanTileClassForAnnotations(FramedDrawerTile.class);
}
@ -147,8 +153,13 @@ public class FunctionalStorage extends ModuleController {
for (DrawerType value : DrawerType.values()) {
for (IWoodType woodType : WOOD_TYPES) {
String name = woodType.getName() + "_" + value.getSlots();
DRAWER_TYPES.computeIfAbsent(value, drawerType -> new ArrayList<>()).add(getRegistries().registerBlockWithTileItem(name, () -> new DrawerBlock(woodType, value), blockRegistryObject -> () ->
new DrawerBlock.DrawerItem((DrawerBlock) blockRegistryObject.get(), new Item.Properties().tab(TAB))));
if (woodType == DrawerWoodType.FRAMED){
DRAWER_TYPES.computeIfAbsent(value, drawerType -> new ArrayList<>()).add(getRegistries().registerBlockWithTileItem(name, () -> new FramedDrawerBlock(value), blockRegistryObject -> () ->
new DrawerBlock.DrawerItem((DrawerBlock) blockRegistryObject.get(), new Item.Properties().tab(TAB))));
} else {
DRAWER_TYPES.computeIfAbsent(value, drawerType -> new ArrayList<>()).add(getRegistries().registerBlockWithTileItem(name, () -> new DrawerBlock(woodType, value), blockRegistryObject -> () ->
new DrawerBlock.DrawerItem((DrawerBlock) blockRegistryObject.get(), new Item.Properties().tab(TAB))));
}
}
DRAWER_TYPES.get(value).forEach(blockRegistryObject -> TAB.addIconStacks(() -> new ItemStack(blockRegistryObject.getLeft().get())));
}
@ -260,6 +271,9 @@ public class FunctionalStorage extends ModuleController {
}
});
}).subscribe();
EventManager.mod(ModelRegistryEvent.class).process(modelRegistryEvent -> {
ModelLoaderRegistry.registerLoader(new ResourceLocation(MOD_ID, "framed"), RetexturedModel.Loader.INSTANCE);
}).subscribe();
}
@Override

View File

@ -2,10 +2,39 @@ package com.buuz135.functionalstorage.block;
import com.buuz135.functionalstorage.FunctionalStorage;
import com.buuz135.functionalstorage.block.tile.DrawerTile;
import com.buuz135.functionalstorage.block.tile.FramedDrawerTile;
import com.buuz135.functionalstorage.client.model.FramedDrawerModelData;
import com.buuz135.functionalstorage.inventory.item.DrawerCapabilityProvider;
import com.buuz135.functionalstorage.recipe.DrawerlessWoodIngredient;
import com.buuz135.functionalstorage.util.DrawerWoodType;
import com.buuz135.functionalstorage.util.IWoodType;
import com.hrznstudio.titanium.recipe.generator.TitaniumShapedRecipeBuilder;
import com.hrznstudio.titanium.util.ItemHandlerUtil;
import com.hrznstudio.titanium.util.TileUtil;
import net.minecraft.core.BlockPos;
import net.minecraft.data.recipes.FinishedRecipe;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.inventory.tooltip.TooltipComponent;
import net.minecraft.world.item.BlockItem;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraftforge.common.Tags;
import net.minecraftforge.common.capabilities.ICapabilityProvider;
import net.minecraftforge.items.ItemHandlerHelper;
import net.minecraftforge.registries.ForgeRegistries;
import org.apache.commons.lang3.tuple.Pair;
import org.jetbrains.annotations.Nullable;
import java.util.HashMap;
import java.util.Optional;
import java.util.function.Consumer;
public class FramedDrawerBlock extends DrawerBlock{
@ -15,6 +44,63 @@ public class FramedDrawerBlock extends DrawerBlock{
@Override
public BlockEntityType.BlockEntitySupplier<DrawerTile> getTileEntityFactory() {
return (blockPos, state) -> new DrawerTile(this, (BlockEntityType<DrawerTile>) FunctionalStorage.DRAWER_TYPES.get(this.getType()).stream().filter(registryObjectRegistryObjectPair -> registryObjectRegistryObjectPair.getLeft().get().equals(this)).map(Pair::getRight).findFirst().get().get(), blockPos, state, this.getType());
return (blockPos, state) -> new FramedDrawerTile(this, (BlockEntityType<DrawerTile>) FunctionalStorage.DRAWER_TYPES.get(this.getType()).stream().filter(registryObjectRegistryObjectPair -> registryObjectRegistryObjectPair.getLeft().get().equals(this)).map(Pair::getRight).findFirst().get().get(), blockPos, state, this.getType());
}
@Override
public void setPlacedBy(Level level, BlockPos pos, BlockState p_49849_, @Nullable LivingEntity p_49850_, ItemStack stack) {
super.setPlacedBy(level, pos, p_49849_, p_49850_, stack);
TileUtil.getTileEntity(level, pos, FramedDrawerTile.class).ifPresent(framedDrawerTile -> {
framedDrawerTile.setFramedDrawerModelData(getDrawerModelData(stack));
});
}
public static FramedDrawerModelData getDrawerModelData(ItemStack stack){
if (stack.hasTag() && stack.getTag().contains("Style")){
CompoundTag tag = stack.getTag().getCompound("Style");
HashMap<String, Item> data = new HashMap<>();
data.put("particle", ForgeRegistries.ITEMS.getValue(new ResourceLocation(tag.getString("particle"))));
data.put("front", ForgeRegistries.ITEMS.getValue(new ResourceLocation(tag.getString("front"))));
data.put("side", ForgeRegistries.ITEMS.getValue(new ResourceLocation(tag.getString("side"))));
return new FramedDrawerModelData(data);
}
return null;
}
public static ItemStack fill(ItemStack first, ItemStack second, ItemStack drawer){
drawer = ItemHandlerHelper.copyStackWithSize(drawer, 1);
CompoundTag style = drawer.getOrCreateTagElement("Style");
style.putString("particle", first.getItem().getRegistryName().toString());
style.putString("side", first.getItem().getRegistryName().toString());
style.putString("front", second.getItem().getRegistryName().toString());
drawer.getOrCreateTag().put("Style", style);
return drawer;
}
@Override
public void registerRecipe(Consumer<FinishedRecipe> consumer) {
if (this.getType() == FunctionalStorage.DrawerType.X_1) {
TitaniumShapedRecipeBuilder.shapedRecipe(this)
.pattern("PPP").pattern("PCP").pattern("PPP")
.define('P', Items.IRON_NUGGET)
.define('C', Tags.Items.CHESTS_WOODEN)
.save(consumer);
}
if (this.getType() == FunctionalStorage.DrawerType.X_2){
TitaniumShapedRecipeBuilder.shapedRecipe(this, 2)
.pattern("PCP").pattern("PPP").pattern("PCP")
.define('P', Items.IRON_NUGGET)
.define('C', Tags.Items.CHESTS_WOODEN)
.save(consumer);
}
if (this.getType() == FunctionalStorage.DrawerType.X_4){
TitaniumShapedRecipeBuilder.shapedRecipe(this, 4)
.pattern("CPC").pattern("PPP").pattern("CPC")
.define('P', Items.IRON_NUGGET)
.define('C', Tags.Items.CHESTS_WOODEN)
.save(consumer);
}
}
}

View File

@ -1,14 +1,41 @@
package com.buuz135.functionalstorage.block.tile;
import com.buuz135.functionalstorage.FunctionalStorage;
import com.buuz135.functionalstorage.client.model.FramedDrawerModelData;
import com.hrznstudio.titanium.annotation.Save;
import com.hrznstudio.titanium.block.BasicTileBlock;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraftforge.client.model.data.IModelData;
import net.minecraftforge.client.model.data.ModelDataMap;
import javax.annotation.Nonnull;
import java.util.HashMap;
public class FramedDrawerTile extends DrawerTile{
@Save
private FramedDrawerModelData framedDrawerModelData;
public FramedDrawerTile(BasicTileBlock<DrawerTile> base, BlockEntityType<DrawerTile> blockEntityType, BlockPos pos, BlockState state, FunctionalStorage.DrawerType type) {
super(base, blockEntityType, pos, state, type);
this.framedDrawerModelData = new FramedDrawerModelData(new HashMap<>());
}
public FramedDrawerModelData getFramedDrawerModelData() {
return framedDrawerModelData;
}
public void setFramedDrawerModelData(FramedDrawerModelData framedDrawerModelData) {
this.framedDrawerModelData = framedDrawerModelData;
markForUpdate();
if (level.isClientSide) requestModelDataUpdate();
}
@Nonnull
@Override
public IModelData getModelData() {
return new ModelDataMap.Builder().withInitial(FramedDrawerModelData.FRAMED_PROPERTY, framedDrawerModelData).build();
}
}

View File

@ -0,0 +1,40 @@
package com.buuz135.functionalstorage.client.loader;
import net.minecraft.client.renderer.block.model.BakedQuad;
import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.core.Direction;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraftforge.client.model.BakedModelWrapper;
import net.minecraftforge.client.model.data.EmptyModelData;
import net.minecraftforge.client.model.data.IModelData;
import javax.annotation.Nullable;
import java.util.List;
import java.util.Random;
/**
* Class from Mantle {@url https://github.com/SlimeKnights/Mantle/blob/1.18.2/src/main/java/slimeknights/mantle/client/}
*
* Cross between {@link BakedModelWrapper} and {@link net.minecraftforge.client.model.data.IDynamicBakedModel}.
* Used to create a baked model wrapper that has a dynamic {@link #getQuads(BlockState, Direction, Random, IModelData)} without worrying about overriding the deprecated variant.
* @param <T> Baked model parent
*/
@SuppressWarnings("WeakerAccess")
public abstract class DynamicBakedWrapper<T extends BakedModel> extends BakedModelWrapper<T> {
protected DynamicBakedWrapper(T originalModel) {
super(originalModel);
}
/**
* @deprecated use {@link #getQuads(BlockState, Direction, Random, IModelData)}
*/
@Override
@Deprecated
public List<BakedQuad> getQuads(@Nullable BlockState state, @Nullable Direction side, Random rand) {
return this.getQuads(state, side, rand, EmptyModelData.INSTANCE);
}
@Override
public abstract List<BakedQuad> getQuads(@Nullable BlockState state, @Nullable Direction side, Random rand, IModelData extraData);
}

View File

@ -0,0 +1,79 @@
package com.buuz135.functionalstorage.client.loader;
import net.minecraft.client.resources.model.ModelState;
import net.minecraft.client.resources.model.UnbakedModel;
import net.minecraft.client.renderer.block.model.ItemTransforms;
import net.minecraft.client.resources.model.Material;
import net.minecraftforge.client.model.IModelConfiguration;
import net.minecraftforge.client.model.geometry.IModelGeometryPart;
import javax.annotation.Nullable;
/**
* Class from Mantle {@url https://github.com/SlimeKnights/Mantle/blob/1.18.2/src/main/java/slimeknights/mantle/client/}
*
* Wrapper around a {@link IModelConfiguration} instance to allow easier extending, mostly for dynamic textures
*/
@SuppressWarnings("WeakerAccess")
public class ModelConfigurationWrapper implements IModelConfiguration {
private final IModelConfiguration base;
/**
* Creates a new configuration wrapper
* @param base Base model configuration
*/
public ModelConfigurationWrapper(IModelConfiguration base) {
this.base = base;
}
@Nullable
@Override
public UnbakedModel getOwnerModel() {
return base.getOwnerModel();
}
@Override
public String getModelName() {
return base.getModelName();
}
@Override
public boolean isTexturePresent(String name) {
return base.isTexturePresent(name);
}
@Override
public Material resolveTexture(String name) {
return base.resolveTexture(name);
}
@Override
public boolean isShadedInGui() {
return base.isShadedInGui();
}
@Override
public boolean isSideLit() {
return base.isSideLit();
}
@Override
public boolean useSmoothLighting() {
return base.useSmoothLighting();
}
@Override
public ItemTransforms getCameraTransforms() {
return base.getCameraTransforms();
}
@Override
public ModelState getCombinedTransform() {
return base.getCombinedTransform();
}
@Override
public boolean getPartVisibility(IModelGeometryPart part, boolean fallback) {
return base.getPartVisibility(part, fallback);
}
}

View File

@ -0,0 +1,210 @@
package com.buuz135.functionalstorage.client.loader;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.mojang.blaze3d.vertex.VertexFormatElement;
import com.mojang.math.Vector3f;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.block.model.BakedQuad;
import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.client.resources.model.MultiPartBakedModel;
import net.minecraft.client.resources.model.WeightedBakedModel;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.packs.resources.ResourceManagerReloadListener;
import net.minecraft.util.GsonHelper;
import net.minecraft.world.item.BlockItem;
import net.minecraft.world.item.Item;
import net.minecraft.world.level.ItemLike;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraftforge.client.model.pipeline.BakedQuadBuilder;
import net.minecraftforge.client.model.pipeline.VertexTransformer;
import javax.annotation.Nullable;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
/**
* Class from Mantle {@url https://github.com/SlimeKnights/Mantle/blob/1.18.2/src/main/java/slimeknights/mantle/client/}
*
* Utilities to help in custom models
*/
public class ModelHelper {
private static final Map<Block,ResourceLocation> TEXTURE_NAME_CACHE = new ConcurrentHashMap<>();
/** Listener instance to clear cache */
public static final ResourceManagerReloadListener LISTENER = manager -> TEXTURE_NAME_CACHE.clear();
/* Baked models */
/**
* Gets the model for the given block
* @param state Block state
* @param clazz Class type to cast result into
* @param <T> Class type
* @return Block model, or null if its missing or the wrong class type
*/
@Nullable
public static <T extends BakedModel> T getBakedModel(BlockState state, Class<T> clazz) {
Minecraft minecraft = Minecraft.getInstance();
//noinspection ConstantConditions null during run data
if (minecraft == null) {
return null;
}
BakedModel baked = minecraft.getModelManager().getBlockModelShaper().getBlockModel(state);
// map multipart and weighted random into the first variant
if (baked instanceof MultiPartBakedModel) {
baked = ((MultiPartBakedModel)baked).selectors.get(0).getRight();
}
if (baked instanceof WeightedBakedModel) {
baked = ((WeightedBakedModel) baked).wrapped;
}
// final model should match the desired type
if (clazz.isInstance(baked)) {
return clazz.cast(baked);
}
return null;
}
/**
* Gets the model for the given item
* @param item Item provider
* @param clazz Class type to cast result into
* @param <T> Class type
* @return Item model, or null if its missing or the wrong class type
*/
@Nullable
public static <T extends BakedModel> T getBakedModel(ItemLike item, Class<T> clazz) {
Minecraft minecraft = Minecraft.getInstance();
//noinspection ConstantConditions null during run data
if (minecraft == null) {
return null;
}
BakedModel baked = minecraft.getItemRenderer().getItemModelShaper().getItemModel(item.asItem());
if (clazz.isInstance(baked)) {
return clazz.cast(baked);
}
return null;
}
/**
* Gets the texture name for a block from the model manager
* @param block Block to fetch
* @return Texture name for the block
*/
@SuppressWarnings("deprecation")
private static ResourceLocation getParticleTextureInternal(Block block) {
return Minecraft.getInstance().getModelManager().getBlockModelShaper().getBlockModel(block.defaultBlockState()).getParticleIcon().getName();
}
/**
* Gets the name of a particle texture for a block, using the cached value if present
* @param block Block to fetch
* @return Texture name for the block
*/
public static ResourceLocation getParticleTexture(Block block) {
return TEXTURE_NAME_CACHE.computeIfAbsent(block, ModelHelper::getParticleTextureInternal);
}
public static ResourceLocation getParticleTexture(Item block) {
return TEXTURE_NAME_CACHE.computeIfAbsent(Block.byItem(block), ModelHelper::getParticleTextureInternal);
}
/* JSON */
/**
* Converts a JSON float array to the specified object
* @param json JSON object
* @param name Name of the array in the object to fetch
* @param size Expected array size
* @param mapper Functon to map from the array to the output type
* @param <T> Output type
* @return Vector3f of data
* @throws JsonParseException If there is no array or the length is wrong
*/
public static <T> T arrayToObject(JsonObject json, String name, int size, Function<float[], T> mapper) {
JsonArray array = GsonHelper.getAsJsonArray(json, name);
if (array.size() != size) {
throw new JsonParseException("Expected " + size + " " + name + " values, found: " + array.size());
}
float[] vec = new float[size];
for(int i = 0; i < size; ++i) {
vec[i] = GsonHelper.convertToFloat(array.get(i), name + "[" + i + "]");
}
return mapper.apply(vec);
}
/**
* Converts a JSON array with 3 elements into a Vector3f
* @param json JSON object
* @param name Name of the array in the object to fetch
* @return Vector3f of data
* @throws JsonParseException If there is no array or the length is wrong
*/
public static Vector3f arrayToVector(JsonObject json, String name) {
return arrayToObject(json, name, 3, arr -> new Vector3f(arr[0], arr[1], arr[2]));
}
/**
* Gets a rotation from JSON
* @param json JSON parent
* @return Integer of 0, 90, 180, or 270
*/
public static int getRotation(JsonObject json, String key) {
int i = GsonHelper.getAsInt(json, key, 0);
if (i >= 0 && i % 90 == 0 && i / 90 <= 3) {
return i;
} else {
throw new JsonParseException("Invalid '" + key + "' " + i + " found, only 0/90/180/270 allowed");
}
}
public static BakedQuad colorQuad(int color, BakedQuad quad) {
ColorTransformer transformer = new ColorTransformer(color, quad);
quad.pipe(transformer);
return transformer.build();
}
private static class ColorTransformer extends VertexTransformer {
private final float r, g, b, a;
public ColorTransformer(int color, BakedQuad quad) {
super(new BakedQuadBuilder(quad.getSprite()));
int a = (color >> 24);
if (a == 0) {
a = 255;
}
int r = (color >> 16) & 0xFF;
int g = (color >> 8) & 0xFF;
int b = (color >> 0) & 0xFF;
this.r = (float) r / 255f;
this.g = (float) g / 255f;
this.b = (float) b / 255f;
this.a = (float) a / 255f;
}
@Override
public void put(int element, float... data) {
VertexFormatElement.Usage usage = this.parent.getVertexFormat().getElements().get(element).getUsage();
// transform normals and position
if (usage == VertexFormatElement.Usage.COLOR && data.length >= 4) {
data[0] = this.r;
data[1] = this.g;
data[2] = this.b;
data[3] = this.a;
}
super.put(element, data);
}
public BakedQuad build() {
return ((BakedQuadBuilder) this.parent).build();
}
}
}

View File

@ -0,0 +1,91 @@
package com.buuz135.functionalstorage.client.loader;
import com.mojang.datafixers.util.Either;
import net.minecraft.client.renderer.block.model.BlockModel;
import net.minecraft.client.resources.model.UnbakedModel;
import net.minecraft.client.resources.model.Material;
import net.minecraftforge.client.model.IModelConfiguration;
import javax.annotation.Nullable;
import java.util.Iterator;
import java.util.Map;
import java.util.NoSuchElementException;
/**
* Class from Mantle {@url https://github.com/SlimeKnights/Mantle/blob/1.18.2/src/main/java/slimeknights/mantle/client/}
*/
public class ModelTextureIteratable implements Iterable<Map<String,Either<Material, String>>> {
/** Initial map for iteration */
@Nullable
private final Map<String,Either<Material, String>> startMap;
/** Initial model for iteration */
@Nullable
private final BlockModel startModel;
public ModelTextureIteratable(@Nullable Map<String, Either<Material, String>> startMap, @Nullable BlockModel startModel) {
this.startMap = startMap;
this.startModel = startModel;
}
/**
* Creates an iterable over the given model
* @param model Model
*/
public ModelTextureIteratable(BlockModel model) {
this(null, model);
}
/**
*
* @param owner Model configuration owner
* @param fallback Fallback in case the owner does not contain a block model
* @return Iteratable over block model texture maps
*/
public static ModelTextureIteratable of(IModelConfiguration owner, SimpleBlockModel fallback) {
UnbakedModel unbaked = owner.getOwnerModel();
if (unbaked instanceof BlockModel) {
return new ModelTextureIteratable(null, (BlockModel)unbaked);
}
return new ModelTextureIteratable(fallback.getTextures(), fallback.getParent());
}
@Override
public MapIterator iterator() {
return new MapIterator(startMap, startModel);
}
private static class MapIterator implements Iterator<Map<String,Either<Material, String>>> {
public MapIterator(@Nullable Map<String, Either<Material, String>> initial, @Nullable BlockModel model) {
this.initial = initial;
this.model = model;
}
/** Initial map for iteration */
@Nullable
private Map<String,Either<Material, String>> initial;
/** current model in the iterator */
@Nullable
private BlockModel model;
@Override
public boolean hasNext() {
return initial != null || model != null;
}
@Override
public Map<String,Either<Material,String>> next() {
Map<String,Either<Material, String>> map;
if (initial != null) {
map = initial;
initial = null;
} else if (model != null) {
map = model.textureMap;
model = model.parent;
} else {
throw new NoSuchElementException();
}
return map;
}
}
}

View File

@ -0,0 +1,70 @@
package com.buuz135.functionalstorage.client.loader;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraftforge.client.model.data.ModelProperty;
import net.minecraftforge.registries.ForgeRegistries;
import javax.annotation.Nullable;
/**
* Class from Mantle {@url https://github.com/SlimeKnights/Mantle/blob/1.18.2/src/main/java/slimeknights/mantle/client/}
*
* This utility contains helpers to handle the NBT for retexturable blocks
*/
public final class RetexturedHelper {
/** Tag name for texture blocks. Should not be used directly, use the utils to interact */
private static final String TAG_TEXTURE = "texture";
/** Property for tile entities containing a texture block */
/* Getting */
/**
* Gets a block for the given name
* @param name Block name
* @return Block entry, or {@link Blocks#AIR} if no match
*/
public static Block getBlock(String name) {
if (!name.isEmpty()) {
Block block = ForgeRegistries.BLOCKS.getValue(new ResourceLocation(name));
if (block != null) {
return block;
}
}
return Blocks.AIR;
}
/**
* Gets the name of the texture from NBT
* @param nbt NBT tag
* @return Name of the texture, or empty if no texture
*/
public static String getTextureName(@Nullable CompoundTag nbt) {
if (nbt == null) {
return "";
}
return nbt.getString(TAG_TEXTURE);
}
/* Setting */
/**
* Sets the texture in an NBT instance
* @param nbt Tag instance
* @param texture Texture to set
*/
public static void setTexture(@Nullable CompoundTag nbt, String texture) {
if (nbt != null) {
if (texture.isEmpty()) {
nbt.remove(TAG_TEXTURE);
} else {
nbt.putString(TAG_TEXTURE, texture);
}
}
}
}

View File

@ -1,5 +1,7 @@
package com.buuz135.functionalstorage.client.loader;
import com.buuz135.functionalstorage.block.FramedDrawerBlock;
import com.buuz135.functionalstorage.client.model.FramedDrawerModelData;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
import com.google.gson.JsonArray;
@ -25,8 +27,6 @@ import net.minecraft.server.packs.resources.ResourceManager;
import net.minecraft.util.GsonHelper;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraftforge.client.model.IModelConfiguration;
import net.minecraftforge.client.model.IModelLoader;
@ -37,11 +37,7 @@ import net.minecraftforge.client.model.geometry.IModelGeometry;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
@ -56,6 +52,11 @@ public class RetexturedModel implements IModelGeometry<RetexturedModel> {
private final SimpleBlockModel model;
private final Set<String> retextured;
public RetexturedModel(SimpleBlockModel model, Set<String> retextured) {
this.model = model;
this.retextured = retextured;
}
@Override
public Collection<Material> getTextures(IModelConfiguration owner, Function<ResourceLocation,UnbakedModel> modelGetter, Set<Pair<String,String>> missingTextureErrors) {
return model.getTextures(owner, modelGetter, missingTextureErrors);
@ -143,7 +144,7 @@ public class RetexturedModel implements IModelGeometry<RetexturedModel> {
/** Baked variant of the model, used to swap out quads based on the texture */
public static class Baked extends DynamicBakedWrapper<BakedModel> {
/** Cache of texture name to baked model */
private final Map<ResourceLocation,BakedModel> cache = new ConcurrentHashMap<>();
private final Map<String, BakedModel> cache = new ConcurrentHashMap<>();
/* Properties for rebaking */
private final IModelConfiguration owner;
private final SimpleBlockModel model;
@ -161,29 +162,29 @@ public class RetexturedModel implements IModelGeometry<RetexturedModel> {
/**
* Gets the model with the given texture applied
* @param name Texture location
* @param framedDrawerModelData Texture location
* @return Retextured model
*/
private BakedModel getRetexturedModel(ResourceLocation name) {
return model.bakeDynamic(new RetexturedConfiguration(owner, retextured, name), transform);
private BakedModel getRetexturedModel(FramedDrawerModelData framedDrawerModelData) {
return model.bakeDynamic(new RetexturedConfiguration(owner, retextured, framedDrawerModelData), transform);
}
/**
* Gets a cached retextured model, computing it if missing from the cache
* @param block Block determining the texture
* @param framedDrawerModelData Block determining the texture
* @return Retextured model
*/
private BakedModel getCachedModel(Block block) {
return cache.computeIfAbsent(ModelHelper.getParticleTexture(block), this::getRetexturedModel);
private BakedModel getCachedModel(FramedDrawerModelData framedDrawerModelData) {
return cache.computeIfAbsent(framedDrawerModelData.getCode(), (s) -> this.getRetexturedModel(framedDrawerModelData));
}
@Override
public TextureAtlasSprite getParticleIcon(IModelData data) {
// if particle is retextured, fetch particle from the cached model
if (retextured.contains("particle")) {
Block block = data.getData(RetexturedHelper.BLOCK_PROPERTY);
if (block != null) {
return getCachedModel(block).getParticleIcon(data);
FramedDrawerModelData framedDrawerModelData = data.getData(FramedDrawerModelData.FRAMED_PROPERTY);
if (framedDrawerModelData != null) {
return getCachedModel(framedDrawerModelData).getParticleIcon(data);
}
}
return originalModel.getParticleIcon(data);
@ -192,11 +193,11 @@ public class RetexturedModel implements IModelGeometry<RetexturedModel> {
@Nonnull
@Override
public List<BakedQuad> getQuads(@Nullable BlockState state, @Nullable Direction direction, Random random, IModelData data) {
Block block = data.getData(RetexturedHelper.BLOCK_PROPERTY);
if (block == null) {
FramedDrawerModelData framedDrawerModelData = data.getData(FramedDrawerModelData.FRAMED_PROPERTY);
if (framedDrawerModelData == null) {
return originalModel.getQuads(state, direction, random, data);
}
return getCachedModel(block).getQuads(state, direction, random, data);
return getCachedModel(framedDrawerModelData).getQuads(state, direction, random, data);
}
@Override
@ -212,7 +213,7 @@ public class RetexturedModel implements IModelGeometry<RetexturedModel> {
/** List of textures to retexture */
private final Set<String> retextured;
/** Replacement texture */
private final Material texture;
private final HashMap<String, Material> texture;
/**
* Creates a new configuration wrapper
@ -220,24 +221,27 @@ public class RetexturedModel implements IModelGeometry<RetexturedModel> {
* @param retextured Set of textures that should be retextured
* @param texture New texture to replace those in the set
*/
public RetexturedConfiguration(IModelConfiguration base, Set<String> retextured, ResourceLocation texture) {
public RetexturedConfiguration(IModelConfiguration base, Set<String> retextured, FramedDrawerModelData texture) {
super(base);
this.retextured = retextured;
this.texture = ModelLoaderRegistry.blockMaterial(texture);
this.texture = new HashMap<>();
texture.getDesign().forEach((s, item) -> {
this.texture.put(s, ModelLoaderRegistry.blockMaterial(ModelHelper.getParticleTexture(item)));
});
}
@Override
public boolean isTexturePresent(String name) {
if (retextured.contains(name)) {
return !MissingTextureAtlasSprite.getLocation().equals(texture.texture());
if (retextured.contains(name) && texture.containsKey(name)) {
return !MissingTextureAtlasSprite.getLocation().equals(texture.get(name).texture());
}
return super.isTexturePresent(name);
}
@Override
public Material resolveTexture(String name) {
if (retextured.contains(name)) {
return texture;
if (retextured.contains(name) && texture.containsKey(name)) {
return texture.get(name);
}
return super.resolveTexture(name);
}
@ -255,13 +259,13 @@ public class RetexturedModel implements IModelGeometry<RetexturedModel> {
}
// get the block first, ensuring its valid
Block block = RetexturedBlockItem.getTexture(stack);
if (block == Blocks.AIR) {
FramedDrawerModelData data = FramedDrawerBlock.getDrawerModelData(stack);
if (data == null) {
return originalModel;
}
// if valid, use the block
return ((Baked)originalModel).getCachedModel(block);
return ((Baked)originalModel).getCachedModel(data);
}
}
}

View File

@ -47,6 +47,8 @@ import java.util.function.Function;
import java.util.stream.Collectors;
/**
* Class from Mantle {@url https://github.com/SlimeKnights/Mantle/blob/1.18.2/src/main/java/slimeknights/mantle/client/}
*
* Simplier version of {@link BlockModel} for use in an {@link net.minecraftforge.client.model.IModelLoader}, as the owner handles most block model properties
*/
@SuppressWarnings("WeakerAccess")
@ -247,7 +249,7 @@ public class SimpleBlockModel implements IModelGeometry<SimpleBlockModel> {
}
// bake the face
TextureAtlasSprite sprite = spriteGetter.apply(owner.resolveTexture(texture));
BakedQuad bakedQuad = BlockModel.makeBakedQuad(part, face, sprite, direction, transform, location);
BakedQuad bakedQuad = BlockModel.bakeFace(part, face, sprite, direction, transform, location);
// apply cull face
if (face.cullForDirection == null) {
builder.addUnculledFace(bakedQuad);

View File

@ -23,22 +23,56 @@
package com.buuz135.functionalstorage.client.model;
import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.Item;
import net.minecraftforge.client.model.data.ModelProperty;
import net.minecraftforge.common.util.INBTSerializable;
import net.minecraftforge.registries.ForgeRegistries;
import java.util.HashMap;
import java.util.Map;
public class FramedDrawerModelData {
public class FramedDrawerModelData implements INBTSerializable<CompoundTag> {
public static final ModelProperty<FramedDrawerModelData> UPGRADE_PROPERTY = new ModelProperty<>();
private Map<Integer, Item> design;
public static final ModelProperty<FramedDrawerModelData> FRAMED_PROPERTY = new ModelProperty<>();
private Map<String, Item> design;
public FramedDrawerModelData(Map<Integer, Item> design) {
private String code = "";
public FramedDrawerModelData(Map<String, Item> design) {
this.design = design;
this.generateCode();
}
public Map<Integer, Item> getDesign() {
public Map<String, Item> getDesign() {
return design;
}
@Override
public CompoundTag serializeNBT() {
CompoundTag compoundTag = new CompoundTag();
design.forEach((s, item) -> compoundTag.putString(s, item.getRegistryName().toString()));
return compoundTag;
}
@Override
public void deserializeNBT(CompoundTag nbt) {
design = new HashMap<>();
for (String allKey : nbt.getAllKeys()) {
design.put(allKey, ForgeRegistries.ITEMS.getValue(new ResourceLocation(nbt.getString(allKey))));
}
this.generateCode();
}
private void generateCode(){
this.code = "";
this.design.forEach((s, item) -> {
this.code += (s + item.getRegistryName().toString());
});
}
public String getCode() {
return code;
}
}

View File

@ -0,0 +1,53 @@
package com.buuz135.functionalstorage.recipe;
import com.buuz135.functionalstorage.block.FramedDrawerBlock;
import com.google.common.collect.Lists;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.inventory.CraftingContainer;
import net.minecraft.world.item.BlockItem;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.CustomRecipe;
import net.minecraft.world.item.crafting.RecipeSerializer;
import net.minecraft.world.item.crafting.SimpleRecipeSerializer;
import net.minecraft.world.level.Level;
import java.util.List;
public class FramedDrawerRecipe extends CustomRecipe {
public static RecipeSerializer<FramedDrawerRecipe> SERIALIZER = new SimpleRecipeSerializer<>(FramedDrawerRecipe::new);
public FramedDrawerRecipe(ResourceLocation idIn) {
super(idIn);
}
public static boolean matches(ItemStack first, ItemStack second, ItemStack drawer) {
//System.out.println(((BlockItem) drawer.getItem()).getBlock().getClass());
return !first.isEmpty() && first.getItem() instanceof BlockItem && !second.isEmpty() && second.getItem() instanceof BlockItem && !drawer.isEmpty() && drawer.getItem() instanceof BlockItem && ((BlockItem) drawer.getItem()).getBlock() instanceof FramedDrawerBlock;
}
@Override
public boolean matches(CraftingContainer inv, Level worldIn) {
return matches(inv.getItem(0), inv.getItem(1), inv.getItem(2));
}
@Override
public ItemStack assemble(CraftingContainer inv) {
if (matches(inv.getItem(0), inv.getItem(1), inv.getItem(2))){
return FramedDrawerBlock.fill(inv.getItem(0), inv.getItem(1), inv.getItem(2).copy());
}
return ItemStack.EMPTY;
}
@Override
public boolean canCraftInDimensions(int width, int height) {
return width * height >= 2;
}
@Override
public RecipeSerializer<?> getSerializer() {
return SERIALIZER;
}
}

View File

@ -14,7 +14,8 @@ public enum DrawerWoodType implements IWoodType {
ACACIA(Blocks.ACACIA_LOG, Blocks.ACACIA_PLANKS),
DARK_OAK(Blocks.DARK_OAK_LOG, Blocks.DARK_OAK_PLANKS),
CRIMSON(Blocks.CRIMSON_STEM, Blocks.CRIMSON_PLANKS),
WARPED(Blocks.WARPED_STEM, Blocks.WARPED_PLANKS);
WARPED(Blocks.WARPED_STEM, Blocks.WARPED_PLANKS),
FRAMED(Blocks.STONE, Blocks.STONE);
private final Block log;

View File

@ -1 +1,7 @@
public net.minecraft.client.renderer.RenderStateShard$LineStateShard
public net.minecraft.client.renderer.block.model.BlockModel f_111419_ # parentLocation
public net.minecraft.client.renderer.block.model.BlockModel m_111437_(Lnet/minecraft/client/renderer/block/model/BlockElement;Lnet/minecraft/client/renderer/block/model/BlockElementFace;Lnet/minecraft/client/renderer/texture/TextureAtlasSprite;Lnet/minecraft/core/Direction;Lnet/minecraft/client/resources/model/ModelState;Lnet/minecraft/resources/ResourceLocation;)Lnet/minecraft/client/renderer/block/model/BakedQuad; # bakeFace
public net.minecraft.client.renderer.block.model.BlockModel$Deserializer m_111503_(Lnet/minecraft/resources/ResourceLocation;Ljava/lang/String;)Lcom/mojang/datafixers/util/Either; # findTexture
public net.minecraft.client.resources.model.WeightedBakedModel f_119542_ # baseModel
public net.minecraft.client.resources.model.MultiPartBakedModel f_119459_ # selectors

View File

@ -15,16 +15,32 @@
}
},
{
"from": [0, 15, 0],
"to": [16, 16, 16],
"from": [1, 9, 0.5],
"to": [15, 15, 2.5],
"rotation": {"angle": 0, "axis": "y", "origin": [-8, 0, -8]},
"faces": {
"north": {"uv": [0, 0, 1, 16], "rotation": 90, "texture": "#side", "cullface": "north"},
"east": {"uv": [0, 0, 16, 1], "rotation": 180, "texture": "#side", "cullface": "east"},
"south": {"uv": [0, 0, 16, 1], "texture": "#side", "cullface": "south"},
"west": {"uv": [0, 0, 16, 1], "texture": "#side", "cullface": "west"},
"up": {"uv": [0, 0, 16, 16], "texture": "#side", "cullface": "up"},
"down": {"uv": [0, 0, 16, 16], "texture": "#side"}
"north": {"uv": [1, 1, 15, 7], "texture": "#front"},
"down": {"uv": [0, 0, 6, 2], "texture": "#side"}
}
},
{
"name": "divider",
"from": [1, 7, 0],
"to": [15, 9, 2],
"rotation": {"angle": 0, "axis": "y", "origin": [-8, 0, -8]},
"faces": {
"north": {"uv": [1, 7, 15, 9], "texture": "#side", "cullface": "north"},
"up": {"uv": [15, 7, 1, 9], "texture": "#side"},
"down": {"uv": [1, 9, 15, 7], "rotation": 180, "texture": "#side"}
}
},
{
"from": [1, 1, 0.5],
"to": [15, 7, 2.5],
"rotation": {"angle": 0, "axis": "y", "origin": [-8, 0, -8]},
"faces": {
"north": {"uv": [1, 9, 15, 15], "texture": "#front"},
"up": {"uv": [0, 0, 6, 2], "texture": "#side"}
}
},
{
@ -50,6 +66,19 @@
"down": {"uv": [0, 0, 16, 16], "texture": "#side", "cullface": "down"}
}
},
{
"from": [0, 15, 0],
"to": [16, 16, 16],
"rotation": {"angle": 0, "axis": "y", "origin": [-8, 0, -8]},
"faces": {
"north": {"uv": [0, 0, 1, 16], "rotation": 90, "texture": "#side", "cullface": "north"},
"east": {"uv": [0, 0, 16, 1], "rotation": 180, "texture": "#side", "cullface": "east"},
"south": {"uv": [0, 0, 16, 1], "texture": "#side", "cullface": "south"},
"west": {"uv": [0, 0, 16, 1], "texture": "#side", "cullface": "west"},
"up": {"uv": [0, 0, 16, 16], "texture": "#side", "cullface": "up"},
"down": {"uv": [0, 0, 16, 16], "texture": "#side"}
}
},
{
"from": [0, 1, 15],
"to": [16, 15, 16],

View File

@ -0,0 +1,175 @@
{
"credit": "Made with Blockbench",
"textures": {
"lock_icon": "functionalstorage:blocks/unlock"
},
"elements": [
{
"from": [9, 1, 0.5],
"to": [15, 7, 2.5],
"rotation": {"angle": 0, "axis": "y", "origin": [-8, 0, -8]},
"faces": {
"north": {"uv": [1, 9, 7, 15], "texture": "#front"},
"west": {"uv": [0, 0, 2, 6], "texture": "#front"},
"up": {"uv": [0, 0, 6, 2], "texture": "#front"}
}
},
{
"from": [1, 1, 0.5],
"to": [7, 7, 2.5],
"rotation": {"angle": 0, "axis": "y", "origin": [-8, 0, -8]},
"faces": {
"north": {"uv": [9, 9, 15, 15], "texture": "#front"},
"east": {"uv": [0, 0, 2, 6], "texture": "#front"},
"up": {"uv": [0, 0, 6, 2], "texture": "#front"}
}
},
{
"from": [1, 9, 0.5],
"to": [7, 15, 2.5],
"rotation": {"angle": 0, "axis": "y", "origin": [-8, 0, -8]},
"faces": {
"north": {"uv": [9, 1, 15, 7], "texture": "#front"},
"east": {"uv": [0, 0, 2, 6], "texture": "#front"},
"down": {"uv": [0, 0, 6, 2], "texture": "#front"}
}
},
{
"from": [9, 9, 0.5],
"to": [15, 15, 2.5],
"rotation": {"angle": 0, "axis": "y", "origin": [-8, 0, -8]},
"faces": {
"north": {"uv": [1, 1, 7, 7], "texture": "#front"},
"west": {"uv": [0, 0, 2, 6], "texture": "#front"},
"down": {"uv": [0, 0, 6, 2], "texture": "#front"}
}
},
{
"name": "divider",
"from": [7, 1, 0],
"to": [9, 15, 2],
"rotation": {"angle": 0, "axis": "y", "origin": [-8, 0, -8]},
"faces": {
"north": {"uv": [7, 1, 9, 15], "texture": "#side", "cullface": "north"},
"east": {"uv": [9, 1, 7, 15], "texture": "#side"},
"west": {"uv": [9, 1, 7, 15], "texture": "#side"}
}
},
{
"name": "divider",
"from": [9, 7, 0],
"to": [15, 9, 2],
"rotation": {"angle": 0, "axis": "y", "origin": [-8, 0, -8]},
"faces": {
"north": {"uv": [1, 7, 7, 9], "texture": "#side", "cullface": "north"},
"up": {"uv": [7, 7, 1, 9], "texture": "#side"},
"down": {"uv": [7, 7, 1, 9], "texture": "#side"}
}
},
{
"name": "divider",
"from": [1, 7, 0],
"to": [7, 9, 2],
"rotation": {"angle": 0, "axis": "y", "origin": [-8, 0, -8]},
"faces": {
"north": {"uv": [9, 7, 15, 9], "texture": "#side", "cullface": "north"},
"up": {"uv": [15, 7, 9, 9], "texture": "#side"},
"down": {"uv": [15, 7, 9, 9], "texture": "#side"}
}
},
{
"from": [0, 0, 0],
"to": [16, 1, 16],
"rotation": {"angle": 0, "axis": "y", "origin": [-8, 0, -8]},
"faces": {
"north": {"uv": [0, 0, 1, 16], "rotation": 90, "texture": "#side", "cullface": "north"},
"east": {"uv": [0, 0, 16, 1], "rotation": 180, "texture": "#side", "cullface": "east"},
"south": {"uv": [0, 0, 16, 1], "texture": "#side", "cullface": "south"},
"west": {"uv": [0, 0, 16, 1], "texture": "#side", "cullface": "west"},
"up": {"uv": [0, 0, 16, 16], "texture": "#side"},
"down": {"uv": [0, 0, 16, 16], "texture": "#side", "cullface": "down"}
}
},
{
"from": [0, 1, 0],
"to": [1, 15, 15],
"rotation": {"angle": 0, "axis": "y", "origin": [-8, 0, -8]},
"faces": {
"north": {"uv": [1, 15, 15, 16], "rotation": 90, "texture": "#side", "cullface": "north"},
"east": {"uv": [1, 1, 16, 15], "texture": "#side"},
"west": {"uv": [0, 1, 15, 15], "texture": "#side", "cullface": "west"}
}
},
{
"from": [0, 15, 0],
"to": [16, 16, 16],
"rotation": {"angle": 0, "axis": "y", "origin": [-8, 0, -8]},
"faces": {
"north": {"uv": [0, 0, 1, 16], "rotation": 90, "texture": "#side", "cullface": "north"},
"east": {"uv": [0, 0, 16, 1], "rotation": 180, "texture": "#side", "cullface": "east"},
"south": {"uv": [0, 0, 16, 1], "texture": "#side", "cullface": "south"},
"west": {"uv": [0, 0, 16, 1], "texture": "#side", "cullface": "west"},
"up": {"uv": [0, 0, 16, 16], "texture": "#side", "cullface": "up"},
"down": {"uv": [0, 0, 16, 16], "texture": "#side"}
}
},
{
"from": [15, 1, 0],
"to": [16, 15, 15],
"rotation": {"angle": 0, "axis": "y", "origin": [-8, 0, -8]},
"faces": {
"north": {"uv": [1, 15, 15, 16], "rotation": 90, "texture": "#side", "cullface": "north"},
"east": {"uv": [1, 1, 16, 15], "texture": "#side", "cullface": "east"},
"west": {"uv": [0, 1, 15, 15], "texture": "#side"}
}
},
{
"from": [0, 1, 15],
"to": [16, 15, 16],
"rotation": {"angle": 0, "axis": "y", "origin": [-8, 0, -8]},
"faces": {
"east": {"uv": [1, 0, 15, 1], "rotation": 90, "texture": "#side", "cullface": "east"},
"south": {"uv": [0, 1, 16, 15], "texture": "#side", "cullface": "south"},
"west": {"uv": [1, 15, 15, 16], "rotation": 90, "texture": "#side", "cullface": "west"}
}
},
{
"from": [7.5, 15, -0.01],
"to": [8.5, 16, 16],
"faces": {
"north": {"uv": [0, 0, 16, 16], "texture": "#lock_icon", "cullface": "north"}
}
}
],
"display": {
"thirdperson_righthand": {
"rotation": [75, 45, 0],
"translation": [0, 2.5, 0],
"scale": [0.375, 0.375, 0.375]
},
"thirdperson_lefthand": {
"rotation": [75, 45, 0],
"translation": [0, 2.5, 0],
"scale": [0.375, 0.375, 0.375]
},
"firstperson_righthand": {
"rotation": [0, 45, 0],
"scale": [0.4, 0.4, 0.4]
},
"firstperson_lefthand": {
"rotation": [0, 225, 0],
"scale": [0.4, 0.4, 0.4]
},
"ground": {
"translation": [0, 3, 0],
"scale": [0.25, 0.25, 0.25]
},
"gui": {
"rotation": [30, 225, 0],
"scale": [0.625, 0.625, 0.625]
},
"fixed": {
"scale": [0.5, 0.5, 0.5]
}
}
}

View File

@ -2,9 +2,7 @@
"loader": "functionalstorage:framed",
"parent": "functionalstorage:block/base_x_1",
"textures": {
"particle": "functionalstorage:blocks/acacia_front_1",
"front": "functionalstorage:blocks/acacia_front_1",
"side": "functionalstorage:blocks/acacia_side"
},
"retextured": [ "particle", "side" ]
"retextured": [ "particle", "side", "front" ]
}

View File

@ -0,0 +1,8 @@
{
"loader": "functionalstorage:framed",
"parent": "functionalstorage:block/base_x_2_framed",
"textures": {
},
"retextured": [ "particle", "side", "front" ]
}

View File

@ -0,0 +1,8 @@
{
"loader": "functionalstorage:framed",
"parent": "functionalstorage:block/base_x_4_framed",
"textures": {
},
"retextured": [ "particle", "side", "front" ]
}

View File

@ -0,0 +1,3 @@
{
"type": "functionalstorage:framed_recipe"
}