Merge branch 'framed' into main

This commit is contained in:
Buuz135 2022-07-09 17:05:33 +02:00
commit 5c41c5bb62
55 changed files with 2702 additions and 35 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/compacting_framed_drawer"
},
"locked=true,subfacing=north": {
"model": "functionalstorage:block/compacting_framed_drawer_locked"
},
"locked=false,subfacing=south": {
"model": "functionalstorage:block/compacting_framed_drawer",
"y": 180
},
"locked=true,subfacing=south": {
"model": "functionalstorage:block/compacting_framed_drawer_locked",
"y": 180
},
"locked=false,subfacing=west": {
"model": "functionalstorage:block/compacting_framed_drawer",
"y": 270
},
"locked=true,subfacing=west": {
"model": "functionalstorage:block/compacting_framed_drawer_locked",
"y": 270
},
"locked=false,subfacing=east": {
"model": "functionalstorage:block/compacting_framed_drawer",
"y": 90
},
"locked=true,subfacing=east": {
"model": "functionalstorage:block/compacting_framed_drawer_locked",
"y": 90
}
}
}

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,10 @@
"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)",
"block.functionalstorage.compacting_framed_drawer": "Compacting Framed Drawer",
"configurationtool.configmode": "Config Mode: ",
"configurationtool.configmode.locking": "Locking",
"configurationtool.configmode.toggle_numbers": "Hide/Show Amounts",
@ -66,5 +70,6 @@
"storageupgrade.desc": "Multiplies the block storage by ",
"upgrade.type": "Type: ",
"upgrade.type.storage": "Storage",
"upgrade.type.utility": "Utility"
"upgrade.type.utility": "Utility",
"frameddrawer.use": "How 2 Change Texture: \nInside a crafting window place the block you want use the texture of for the outside of the drawer in the first slot of the crafting window, on the second slot put the block that will be used for the texture on the inside of the framed drawer and on the third slot put a framed drawer. \n"
}

View File

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

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/compacting_framed_drawer"
}

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

@ -0,0 +1,3 @@
{
"type": "minecraft:block"
}

View File

@ -0,0 +1,3 @@
{
"type": "minecraft:block"
}

View File

@ -0,0 +1,3 @@
{
"type": "minecraft:block"
}

View File

@ -0,0 +1,3 @@
{
"type": "minecraft:block"
}

View File

@ -0,0 +1,51 @@
{
"type": "forge:conditional",
"recipes": [
{
"conditions": [
{
"values": [
{
"item": "functionalstorage:compacting_framed_drawer",
"type": "forge:item_exists"
}
],
"type": "forge:and"
}
],
"recipe": {
"type": "minecraft:crafting_shaped",
"pattern": [
"SSS",
"PDP",
"SIS"
],
"key": {
"S": {
"item": "minecraft:stone"
},
"P": {
"item": "minecraft:piston"
},
"D": [
{
"item": "functionalstorage:framed_1"
},
{
"item": "functionalstorage:framed_2"
},
{
"item": "functionalstorage:framed_4"
}
],
"I": {
"tag": "forge:ingots/iron"
}
},
"result": {
"item": "functionalstorage:compacting_framed_drawer"
}
}
}
]
}

View File

@ -0,0 +1,37 @@
{
"type": "forge:conditional",
"recipes": [
{
"conditions": [
{
"values": [
{
"item": "functionalstorage:framed_1",
"type": "forge:item_exists"
}
],
"type": "forge:and"
}
],
"recipe": {
"type": "minecraft:crafting_shaped",
"pattern": [
"PPP",
"PCP",
"PPP"
],
"key": {
"P": {
"item": "minecraft:iron_nugget"
},
"C": {
"tag": "forge:chests/wooden"
}
},
"result": {
"item": "functionalstorage:framed_1"
}
}
}
]
}

View File

@ -0,0 +1,38 @@
{
"type": "forge:conditional",
"recipes": [
{
"conditions": [
{
"values": [
{
"item": "functionalstorage:framed_2",
"type": "forge:item_exists"
}
],
"type": "forge:and"
}
],
"recipe": {
"type": "minecraft:crafting_shaped",
"pattern": [
"PCP",
"PPP",
"PCP"
],
"key": {
"P": {
"item": "minecraft:iron_nugget"
},
"C": {
"tag": "forge:chests/wooden"
}
},
"result": {
"item": "functionalstorage:framed_2",
"count": 2
}
}
}
]
}

View File

@ -0,0 +1,38 @@
{
"type": "forge:conditional",
"recipes": [
{
"conditions": [
{
"values": [
{
"item": "functionalstorage:framed_4",
"type": "forge:item_exists"
}
],
"type": "forge:and"
}
],
"recipe": {
"type": "minecraft:crafting_shaped",
"pattern": [
"CPC",
"PPP",
"CPC"
],
"key": {
"P": {
"item": "minecraft:iron_nugget"
},
"C": {
"tag": "forge:chests/wooden"
}
},
"result": {
"item": "functionalstorage:framed_4",
"count": 4
}
}
}
]
}

View File

@ -1,14 +1,15 @@
{
"replace": false,
"values": [
"functionalstorage:oak_1",
"functionalstorage:spruce_1",
"functionalstorage:birch_1",
"functionalstorage:jungle_1",
"functionalstorage:acacia_1",
"functionalstorage:dark_oak_1",
"functionalstorage:crimson_1",
"functionalstorage:warped_1",
"functionalstorage:oak_2",
"functionalstorage:spruce_2",
"functionalstorage:birch_2",
"functionalstorage:jungle_2",
"functionalstorage:acacia_2",
"functionalstorage:dark_oak_2",
"functionalstorage:crimson_2",
"functionalstorage:warped_2",
"functionalstorage:framed_2",
"functionalstorage:oak_4",
"functionalstorage:spruce_4",
"functionalstorage:birch_4",
@ -17,13 +18,15 @@
"functionalstorage:dark_oak_4",
"functionalstorage:crimson_4",
"functionalstorage:warped_4",
"functionalstorage:oak_2",
"functionalstorage:spruce_2",
"functionalstorage:birch_2",
"functionalstorage:jungle_2",
"functionalstorage:acacia_2",
"functionalstorage:dark_oak_2",
"functionalstorage:crimson_2",
"functionalstorage:warped_2"
"functionalstorage:framed_4",
"functionalstorage:oak_1",
"functionalstorage:spruce_1",
"functionalstorage:birch_1",
"functionalstorage:jungle_1",
"functionalstorage:acacia_1",
"functionalstorage:dark_oak_1",
"functionalstorage:crimson_1",
"functionalstorage:warped_1",
"functionalstorage:framed_1"
]
}

View File

@ -2,6 +2,7 @@
"replace": false,
"values": [
"functionalstorage:compacting_drawer",
"functionalstorage:compacting_framed_drawer",
"functionalstorage:storage_controller",
"functionalstorage:armory_cabinet",
"functionalstorage:ender_drawer"

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,13 +19,14 @@ 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;
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;
@ -46,12 +45,16 @@ import net.minecraft.world.item.Items;
import net.minecraft.world.item.crafting.Ingredient;
import net.minecraft.world.item.crafting.RecipeSerializer;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockBehaviour;
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 +91,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<>();
@ -97,6 +100,7 @@ public class FunctionalStorage extends ModuleController {
public static Pair<RegistryObject<Block>, RegistryObject<BlockEntityType<?>>> DRAWER_CONTROLLER;
public static Pair<RegistryObject<Block>, RegistryObject<BlockEntityType<?>>> ARMORY_CABINET;
public static Pair<RegistryObject<Block>, RegistryObject<BlockEntityType<?>>> ENDER_DRAWER;
public static Pair<RegistryObject<Block>, RegistryObject<BlockEntityType<?>>> FRAMED_COMPACTING_DRAWER;
public static RegistryObject<Item> LINKING_TOOL;
public static HashMap<StorageUpgradeItem.StorageTier, RegistryObject<Item>> STORAGE_UPGRADES = new HashMap<>();
@ -138,6 +142,11 @@ 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);
NBTManager.getInstance().scanTileClassForAnnotations(CompactingFramedDrawerTile.class);
}
@ -146,13 +155,21 @@ public class FunctionalStorage extends ModuleController {
WOOD_TYPES.addAll(List.of(DrawerWoodType.values()));
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))));
var name = woodType.getName() + "_" + value.getSlots();
if (woodType == DrawerWoodType.FRAMED){
var pair = getRegistries().registerBlockWithTileItem(name, () -> new FramedDrawerBlock(value), blockRegistryObject -> () ->
new DrawerBlock.DrawerItem((DrawerBlock) blockRegistryObject.get(), new Item.Properties().tab(TAB)));
DRAWER_TYPES.computeIfAbsent(value, drawerType -> new ArrayList<>()).add(pair);
CompactingFramedDrawerBlock.FRAMED.add(pair.getLeft());
} else {
DRAWER_TYPES.computeIfAbsent(value, drawerType -> new ArrayList<>()).add(getRegistries().registerBlockWithTileItem(name, () -> new DrawerBlock(woodType, value, BlockBehaviour.Properties.copy(woodType.getPlanks())), 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())));
}
COMPACTING_DRAWER = getRegistries().registerBlockWithTile("compacting_drawer", () -> new CompactingDrawerBlock("compacting_drawer"));
COMPACTING_DRAWER = getRegistries().registerBlockWithTile("compacting_drawer", () -> new CompactingDrawerBlock("compacting_drawer", BlockBehaviour.Properties.copy(Blocks.STONE_BRICKS)));
FRAMED_COMPACTING_DRAWER = getRegistries().registerBlockWithTile("compacting_framed_drawer", () -> new CompactingFramedDrawerBlock("compacting_framed_drawer"));
DRAWER_CONTROLLER = getRegistries().registerBlockWithTile("storage_controller", DrawerControllerBlock::new);
LINKING_TOOL = getRegistries().registerGeneric(Item.class, "linking_tool", LinkingToolItem::new);
for (StorageUpgradeItem.StorageTier value : StorageUpgradeItem.StorageTier.values()) {
@ -204,6 +221,7 @@ public class FunctionalStorage extends ModuleController {
});
}
registerRenderers.registerBlockEntityRenderer((BlockEntityType<? extends CompactingDrawerTile>) COMPACTING_DRAWER.getRight().get(), p_173571_ -> new CompactingDrawerRenderer());
registerRenderers.registerBlockEntityRenderer((BlockEntityType<? extends CompactingDrawerTile>) FRAMED_COMPACTING_DRAWER.getRight().get(), p_173571_ -> new CompactingDrawerRenderer());
registerRenderers.registerBlockEntityRenderer((BlockEntityType<? extends DrawerControllerTile>) DRAWER_CONTROLLER.getRight().get(), p -> new ControllerRenderer());
registerRenderers.registerBlockEntityRenderer((BlockEntityType<? extends EnderDrawerTile>) ENDER_DRAWER.getRight().get(), p_173571_ -> new EnderDrawerRenderer());
}).subscribe();
@ -241,6 +259,7 @@ public class FunctionalStorage extends ModuleController {
}
}
ItemBlockRenderTypes.setRenderLayer(COMPACTING_DRAWER.getLeft().get(), RenderType.cutout());
ItemBlockRenderTypes.setRenderLayer(FRAMED_COMPACTING_DRAWER.getLeft().get(), RenderType.cutout());
ItemBlockRenderTypes.setRenderLayer(ENDER_DRAWER.getLeft().get(), RenderType.cutout());
}).subscribe();
EventManager.forge(RenderTooltipEvent.Pre.class).process(itemTooltipEvent -> {
@ -260,6 +279,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

@ -70,8 +70,8 @@ public class CompactingDrawerBlock extends RotatableBlock<CompactingDrawerTile>
}
public CompactingDrawerBlock(String name) {
super(name, Properties.copy(Blocks.STONE_BRICKS), CompactingDrawerTile.class);
public CompactingDrawerBlock(String name, Properties properties) {
super(name, properties, CompactingDrawerTile.class);
setItemGroup(FunctionalStorage.TAB);
registerDefaultState(defaultBlockState().setValue(RotatableBlock.FACING_HORIZONTAL, Direction.NORTH).setValue(DrawerBlock.LOCKED, false));
}

View File

@ -0,0 +1,101 @@
package com.buuz135.functionalstorage.block;
import com.buuz135.functionalstorage.FunctionalStorage;
import com.buuz135.functionalstorage.block.tile.CompactingDrawerTile;
import com.buuz135.functionalstorage.block.tile.CompactingFramedDrawerTile;
import com.buuz135.functionalstorage.block.tile.FramedDrawerTile;
import com.hrznstudio.titanium.recipe.generator.TitaniumShapedRecipeBuilder;
import com.hrznstudio.titanium.util.TileUtil;
import net.minecraft.ChatFormatting;
import net.minecraft.core.BlockPos;
import net.minecraft.core.NonNullList;
import net.minecraft.data.recipes.FinishedRecipe;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.TranslatableComponent;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.TooltipFlag;
import net.minecraft.world.item.crafting.Ingredient;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
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.minecraft.world.level.storage.loot.LootContext;
import net.minecraft.world.level.storage.loot.parameters.LootContextParams;
import net.minecraft.world.phys.HitResult;
import net.minecraftforge.common.Tags;
import net.minecraftforge.registries.RegistryObject;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
public class CompactingFramedDrawerBlock extends CompactingDrawerBlock{
public static List<RegistryObject<Block>> FRAMED = new ArrayList<>();
public CompactingFramedDrawerBlock(String name) {
super(name, Properties.copy(Blocks.STONE).noOcclusion().isViewBlocking((p_61036_, p_61037_, p_61038_) -> false));
}
@Override
public BlockEntityType.BlockEntitySupplier<CompactingDrawerTile> getTileEntityFactory() {
return (blockPos, state) -> new CompactingFramedDrawerTile(this, (BlockEntityType<CompactingDrawerTile>) FunctionalStorage.FRAMED_COMPACTING_DRAWER.getValue().get(), blockPos, state);
}
@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, CompactingFramedDrawerTile.class).ifPresent(framedDrawerTile -> {
framedDrawerTile.setFramedDrawerModelData(FramedDrawerBlock.getDrawerModelData(stack));
});
}
@Override
public List<ItemStack> getDrops(BlockState p_60537_, LootContext.Builder builder) {
NonNullList<ItemStack> stacks = NonNullList.create();
ItemStack stack = new ItemStack(this);
BlockEntity drawerTile = builder.getOptionalParameter(LootContextParams.BLOCK_ENTITY);
if (drawerTile instanceof CompactingFramedDrawerTile) {
if (!((CompactingFramedDrawerTile) drawerTile).isEverythingEmpty()) {
stack.getOrCreateTag().put("Tile", drawerTile.saveWithoutMetadata());
}
stack.getOrCreateTag().put("Style", ((CompactingFramedDrawerTile) drawerTile).getFramedDrawerModelData().serializeNBT());
}
stacks.add(stack);
return stacks;
}
@Override
public ItemStack getCloneItemStack(BlockState state, HitResult target, BlockGetter level, BlockPos pos, Player player) {
BlockEntity entity = level.getBlockEntity(pos);
if (entity instanceof FramedDrawerTile framedDrawerTile && framedDrawerTile.getFramedDrawerModelData() != null && !framedDrawerTile.getFramedDrawerModelData().getDesign().isEmpty()){
ItemStack stack = new ItemStack(this);
stack.getOrCreateTag().put("Style", framedDrawerTile.getFramedDrawerModelData().serializeNBT());
return stack;
}
return super.getCloneItemStack(state, target, level, pos, player);
}
@Override
public void registerRecipe(Consumer<FinishedRecipe> consumer) {
TitaniumShapedRecipeBuilder.shapedRecipe(this)
.pattern("SSS").pattern("PDP").pattern("SIS")
.define('S', Blocks.STONE)
.define('P', Blocks.PISTON)
.define('D', Ingredient.of(FRAMED.stream().map(itemSupplier -> new ItemStack(itemSupplier.get()))))
.define('I', Tags.Items.INGOTS_IRON)
.save(consumer);
}
@Override
public void appendHoverText(ItemStack p_49816_, @Nullable BlockGetter p_49817_, List<Component> components, TooltipFlag p_49819_) {
components.add(new TranslatableComponent("frameddrawer.use").withStyle(ChatFormatting.GRAY));
super.appendHoverText(p_49816_, p_49817_, components, p_49819_);
}
}

View File

@ -38,6 +38,7 @@ import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition;
import net.minecraft.world.level.block.state.properties.BooleanProperty;
@ -121,14 +122,15 @@ public class DrawerBlock extends RotatableBlock<DrawerTile> {
private final FunctionalStorage.DrawerType type;
private final IWoodType woodType;
public DrawerBlock(IWoodType woodType, FunctionalStorage.DrawerType type) {
super(woodType.getName() + "_" + type.getSlots(), Properties.copy(woodType.getPlanks()), DrawerTile.class);
public DrawerBlock(IWoodType woodType, FunctionalStorage.DrawerType type, BlockBehaviour.Properties properties) {
super(woodType.getName() + "_" + type.getSlots(), properties, DrawerTile.class);
this.woodType = woodType;
this.type = type;
setItemGroup(FunctionalStorage.TAB);
registerDefaultState(defaultBlockState().setValue(RotatableBlock.FACING_HORIZONTAL, Direction.NORTH).setValue(LOCKED, false));
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> p_206840_1_) {
super.createBlockStateDefinition(p_206840_1_);
@ -319,7 +321,7 @@ public class DrawerBlock extends RotatableBlock<DrawerTile> {
@Override
public void appendHoverText(ItemStack p_49816_, @Nullable BlockGetter p_49817_, List<net.minecraft.network.chat.Component> tooltip, TooltipFlag p_49819_) {
super.appendHoverText(p_49816_, p_49817_, tooltip, p_49819_);
if (p_49816_.hasTag()) {
if (p_49816_.hasTag() && p_49816_.getTag().contains("Tile")) {
TranslatableComponent text = new TranslatableComponent("drawer.block.contents");
tooltip.add(text.withStyle(ChatFormatting.GRAY));
tooltip.add(new TextComponent(""));

View File

@ -0,0 +1,150 @@
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.ChatFormatting;
import net.minecraft.core.BlockPos;
import net.minecraft.core.NonNullList;
import net.minecraft.data.recipes.FinishedRecipe;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.TranslatableComponent;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.inventory.tooltip.TooltipComponent;
import net.minecraft.world.item.*;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Blocks;
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.minecraft.world.level.material.Material;
import net.minecraft.world.level.material.MaterialColor;
import net.minecraft.world.level.storage.loot.LootContext;
import net.minecraft.world.level.storage.loot.parameters.LootContextParams;
import net.minecraft.world.phys.HitResult;
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.List;
import java.util.Optional;
import java.util.function.Consumer;
public class FramedDrawerBlock extends DrawerBlock{
public FramedDrawerBlock(FunctionalStorage.DrawerType type) {
super(DrawerWoodType.FRAMED, type, Properties.copy(Blocks.OAK_PLANKS).noOcclusion().isViewBlocking((p_61036_, p_61037_, p_61038_) -> false));
}
@Override
public BlockEntityType.BlockEntitySupplier<DrawerTile> getTileEntityFactory() {
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"))));
data.put("front_divider", ForgeRegistries.ITEMS.getValue(new ResourceLocation(tag.getString("front_divider"))));
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());
style.putString("front_divider", first.getItem().getRegistryName().toString());
drawer.getOrCreateTag().put("Style", style);
return drawer;
}
@Override
public List<ItemStack> getDrops(BlockState p_60537_, LootContext.Builder builder) {
NonNullList<ItemStack> stacks = NonNullList.create();
ItemStack stack = new ItemStack(this);
BlockEntity drawerTile = builder.getOptionalParameter(LootContextParams.BLOCK_ENTITY);
if (drawerTile instanceof FramedDrawerTile) {
if (!((FramedDrawerTile) drawerTile).isEverythingEmpty()) {
stack.getOrCreateTag().put("Tile", drawerTile.saveWithoutMetadata());
}
stack.getOrCreateTag().put("Style", ((FramedDrawerTile) drawerTile).getFramedDrawerModelData().serializeNBT());
}
stacks.add(stack);
return stacks;
}
@Override
public ItemStack getCloneItemStack(BlockState state, HitResult target, BlockGetter level, BlockPos pos, Player player) {
BlockEntity entity = level.getBlockEntity(pos);
if (entity instanceof FramedDrawerTile framedDrawerTile && framedDrawerTile.getFramedDrawerModelData() != null && !framedDrawerTile.getFramedDrawerModelData().getDesign().isEmpty()){
ItemStack stack = new ItemStack(this);
stack.getOrCreateTag().put("Style", framedDrawerTile.getFramedDrawerModelData().serializeNBT());
return stack;
}
return super.getCloneItemStack(state, target, level, pos, player);
}
@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);
}
}
@Override
public void appendHoverText(ItemStack p_49816_, @Nullable BlockGetter p_49817_, List<Component> components, TooltipFlag p_49819_) {
components.add(new TranslatableComponent("frameddrawer.use").withStyle(ChatFormatting.GRAY));
super.appendHoverText(p_49816_, p_49817_, components, p_49819_);
}
}

View File

@ -0,0 +1,40 @@
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.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 CompactingFramedDrawerTile extends CompactingDrawerTile{
@Save
private FramedDrawerModelData framedDrawerModelData;
public CompactingFramedDrawerTile(BasicTileBlock<CompactingDrawerTile> base, BlockEntityType<CompactingDrawerTile> blockEntityType, BlockPos pos, BlockState state) {
super(base, blockEntityType, pos, state);
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,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

@ -0,0 +1,271 @@
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;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonSyntaxException;
import com.mojang.datafixers.util.Either;
import com.mojang.datafixers.util.Pair;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.renderer.block.model.BakedQuad;
import net.minecraft.client.renderer.block.model.ItemOverrides;
import net.minecraft.client.renderer.texture.MissingTextureAtlasSprite;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.client.resources.model.Material;
import net.minecraft.client.resources.model.ModelBakery;
import net.minecraft.client.resources.model.ModelState;
import net.minecraft.client.resources.model.UnbakedModel;
import net.minecraft.core.Direction;
import net.minecraft.resources.ResourceLocation;
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.state.BlockState;
import net.minecraftforge.client.model.IModelConfiguration;
import net.minecraftforge.client.model.IModelLoader;
import net.minecraftforge.client.model.ModelLoaderRegistry;
import net.minecraftforge.client.model.data.IModelData;
import net.minecraftforge.client.model.geometry.IModelGeometry;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.*;
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/model/RetexturedModel.java}
*
* Model that dynamically retextures a list of textures based on data from {@link RetexturedHelper}.
*/
@SuppressWarnings("WeakerAccess")
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);
}
@Override
public BakedModel bake(IModelConfiguration owner, ModelBakery bakery, Function<Material,TextureAtlasSprite> spriteGetter, ModelState transform, ItemOverrides overrides, ResourceLocation location) {
// bake the model and return
BakedModel baked = model.bakeModel(owner, transform, overrides, spriteGetter, location);
return new Baked(baked, owner, model, transform, getAllRetextured(owner, this.model, retextured));
}
/**
* Gets a list of all names to retexture based on the block model texture references
* @param owner Model config instance
* @param model Model fallback
* @param originalSet Original list of names to retexture
* @return Set of textures including parent textures
*/
public static Set<String> getAllRetextured(IModelConfiguration owner, SimpleBlockModel model, Set<String> originalSet) {
Set<String> retextured = Sets.newHashSet(originalSet);
for (Map<String,Either<Material, String>> textures : ModelTextureIteratable.of(owner, model)) {
textures.forEach((name, either) ->
either.ifRight(parent -> {
if (retextured.contains(parent)) {
retextured.add(name);
}
})
);
}
return ImmutableSet.copyOf(retextured);
}
/** Registered model loader instance registered */
public static class Loader implements IModelLoader<RetexturedModel> {
public static final Loader INSTANCE = new Loader();
private Loader() {}
@Override
public void onResourceManagerReload(ResourceManager resourceManager) {}
@Override
public RetexturedModel read(JsonDeserializationContext context, JsonObject json) {
// get base model
SimpleBlockModel model = SimpleBlockModel.deserialize(context, json);
// get list of textures to retexture
Set<String> retextured = getRetextured(json);
// return retextured model
return new RetexturedModel(model, retextured);
}
/**
* Gets the list of retextured textures from the model
* @param json Model json
* @return List of textures
*/
public static Set<String> getRetextured(JsonObject json) {
if (json.has("retextured")) {
// if an array, set from each texture in array
JsonElement retextured = json.get("retextured");
if (retextured.isJsonArray()) {
JsonArray array = retextured.getAsJsonArray();
if (array.size() == 0) {
throw new JsonSyntaxException("Must have at least one texture in retextured");
}
ImmutableSet.Builder<String> builder = ImmutableSet.builder();
for (int i = 0; i < array.size(); i++) {
builder.add(GsonHelper.convertToString(array.get(i), "retextured[" + i + "]"));
}
return builder.build();
}
// if string, single texture
if (retextured.isJsonPrimitive()) {
return ImmutableSet.of(retextured.getAsString());
}
}
// if neither or missing, error
throw new JsonSyntaxException("Missing retextured, expected to find a String or a JsonArray");
}
}
/** 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<String, BakedModel> cache = new ConcurrentHashMap<>();
/* Properties for rebaking */
private final IModelConfiguration owner;
private final SimpleBlockModel model;
private final ModelState transform;
/** List of texture names that are retextured */
private final Set<String> retextured;
public Baked(BakedModel baked, IModelConfiguration owner, SimpleBlockModel model, ModelState transform, Set<String> retextured) {
super(baked);
this.model = model;
this.owner = owner;
this.transform = transform;
this.retextured = retextured;
}
/**
* Gets the model with the given texture applied
* @param framedDrawerModelData Texture location
* @return Retextured model
*/
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 framedDrawerModelData Block determining the texture
* @return Retextured model
*/
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")) {
FramedDrawerModelData framedDrawerModelData = data.getData(FramedDrawerModelData.FRAMED_PROPERTY);
if (framedDrawerModelData != null) {
return getCachedModel(framedDrawerModelData).getParticleIcon(data);
}
}
return originalModel.getParticleIcon(data);
}
@Nonnull
@Override
public List<BakedQuad> getQuads(@Nullable BlockState state, @Nullable Direction direction, Random random, IModelData data) {
FramedDrawerModelData framedDrawerModelData = data.getData(FramedDrawerModelData.FRAMED_PROPERTY);
if (framedDrawerModelData == null) {
return originalModel.getQuads(state, direction, random, data);
}
return getCachedModel(framedDrawerModelData).getQuads(state, direction, random, data);
}
@Override
public ItemOverrides getOverrides() {
return RetexturedOverride.INSTANCE;
}
}
/**
* Model configuration wrapper to retexture the block
*/
public static class RetexturedConfiguration extends ModelConfigurationWrapper {
/** List of textures to retexture */
private final Set<String> retextured;
/** Replacement texture */
private final HashMap<String, Material> texture;
/**
* Creates a new configuration wrapper
* @param base Original model configuration
* @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, FramedDrawerModelData texture) {
super(base);
this.retextured = retextured;
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) && 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) && texture.containsKey(name)) {
return texture.get(name);
}
return super.resolveTexture(name);
}
}
/** Override list to swap the texture in from NBT */
private static class RetexturedOverride extends ItemOverrides {
private static final RetexturedOverride INSTANCE = new RetexturedOverride();
@Nullable
@Override
public BakedModel resolve(BakedModel originalModel, ItemStack stack, @Nullable ClientLevel world, @Nullable LivingEntity entity, int pSeed) {
if (stack.isEmpty() || !stack.hasTag()) {
return originalModel;
}
// get the block first, ensuring its valid
FramedDrawerModelData data = FramedDrawerBlock.getDrawerModelData(stack);
if (data == null) {
return originalModel;
}
// if valid, use the block
return ((Baked)originalModel).getCachedModel(data);
}
}
}

View File

@ -0,0 +1,414 @@
package com.buuz135.functionalstorage.client.loader;
import com.buuz135.functionalstorage.FunctionalStorage;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Sets;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonSyntaxException;
import com.mojang.datafixers.util.Either;
import com.mojang.datafixers.util.Pair;
import net.minecraft.client.renderer.block.model.BakedQuad;
import net.minecraft.client.renderer.block.model.BlockElement;
import net.minecraft.client.renderer.block.model.BlockElementFace;
import net.minecraft.client.renderer.block.model.BlockModel;
import net.minecraft.client.renderer.block.model.ItemOverrides;
import net.minecraft.client.renderer.texture.MissingTextureAtlasSprite;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.client.resources.model.Material;
import net.minecraft.client.resources.model.ModelBakery;
import net.minecraft.client.resources.model.ModelState;
import net.minecraft.client.resources.model.SimpleBakedModel;
import net.minecraft.client.resources.model.UnbakedModel;
import net.minecraft.core.Direction;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.packs.resources.ResourceManager;
import net.minecraft.util.GsonHelper;
import net.minecraft.world.inventory.InventoryMenu;
import net.minecraftforge.client.model.ForgeModelBakery;
import net.minecraftforge.client.model.IModelConfiguration;
import net.minecraftforge.client.model.IModelLoader;
import net.minecraftforge.client.model.geometry.IModelGeometry;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Set;
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")
public class SimpleBlockModel implements IModelGeometry<SimpleBlockModel> {
/**
* Model loader for vanilla block model, mainly intended for use in fallback registration
*/
public static final Loader LOADER = new Loader();
/**
* Location used for baking dynamic models, name does not matter so just using a constant
*/
private static final ResourceLocation BAKE_LOCATION = new ResourceLocation(FunctionalStorage.MOD_ID, "dynamic_model_baking");
/**
* Parent model location, used to fetch parts and for textures if the owner is not a block model
*/
@Nullable
private ResourceLocation parentLocation;
/**
* Model parts for baked model, if empty uses parent parts
*/
private final List<BlockElement> parts;
/**
* Fallback textures in case the owner does not contain a block model
*/
private final Map<String, Either<Material, String>> textures;
private BlockModel parent;
/**
* Creates a new simple block model
*
* @param parentLocation Location of the parent model, if unset has no parent
* @param textures List of textures for iteration, in case the owner is not BlockModel
* @param parts List of parts in the model
*/
public SimpleBlockModel(@Nullable ResourceLocation parentLocation, Map<String, Either<Material, String>> textures, List<BlockElement> parts) {
this.parts = parts;
this.textures = textures;
this.parentLocation = parentLocation;
}
/* Properties */
/**
* Gets the elements in this simple block model
*
* @return Elements in the model
*/
@SuppressWarnings("deprecation")
public List<BlockElement> getElements() {
return parts.isEmpty() && parent != null ? parent.getElements() : parts;
}
/* Textures */
/**
* Fetches parent models for this model and its parents
*
* @param modelGetter Model getter function
*/
public void fetchParent(IModelConfiguration owner, Function<ResourceLocation, UnbakedModel> modelGetter) {
// no work if no parent or the parent is fetched already
if (parent != null || parentLocation == null) {
return;
}
// iterate through model parents
Set<UnbakedModel> chain = Sets.newLinkedHashSet();
// load the first model directly
parent = getParent(modelGetter, chain, parentLocation, owner.getModelName());
// null means no model, so set missing
if (parent == null) {
parent = getMissing(modelGetter);
parentLocation = ModelBakery.MISSING_MODEL_LOCATION;
}
// loop through each parent, adding in parents
for (BlockModel link = parent; link.parentLocation != null && link.parent == null; link = link.parent) {
chain.add(link);
// fetch model parent
link.parent = getParent(modelGetter, chain, link.parentLocation, link.name);
// null means no model, so set missing
if (link.parent == null) {
link.parent = getMissing(modelGetter);
link.parentLocation = ModelBakery.MISSING_MODEL_LOCATION;
}
}
}
/**
* Gets the parent for a model
*
* @param modelGetter Model getter function
* @param chain Chain of models that are in progress
* @param location Location to fetch
* @param name Name of the model being fetched
* @return Block model instance, null if there was an error
*/
@Nullable
private static BlockModel getParent(Function<ResourceLocation, UnbakedModel> modelGetter, Set<UnbakedModel> chain, ResourceLocation location, String name) {
// model must exist
UnbakedModel unbaked = modelGetter.apply(location);
if (unbaked == null) {
FunctionalStorage.LOGGER.warn("No parent '{}' while loading model '{}'", location, name);
return null;
}
// no loops in chain
if (chain.contains(unbaked)) {
FunctionalStorage.LOGGER.warn("Found 'parent' loop while loading model '{}' in chain: {} -> {}", name, chain.stream().map(Object::toString).collect(Collectors.joining(" -> ")), location);
return null;
}
// model must be block model, this is a serious error in vanilla
if (!(unbaked instanceof BlockModel)) {
throw new IllegalStateException("BlockModel parent has to be a block model.");
}
return (BlockModel) unbaked;
}
/**
* Gets the missing model, ensuring its the right type
*
* @param modelGetter Model getter function
* @return Missing model as a {@link BlockModel}
*/
@Nonnull
private static BlockModel getMissing(Function<ResourceLocation, UnbakedModel> modelGetter) {
UnbakedModel model = modelGetter.apply(ModelBakery.MISSING_MODEL_LOCATION);
if (!(model instanceof BlockModel)) {
throw new IllegalStateException("Failed to load missing model");
}
return (BlockModel) model;
}
/**
* Gets the texture dependencies for a list of elements, allows calling outside a simple block model
*
* @param owner Model configuration
* @param elements List of elements to check for textures
* @param missingTextureErrors Missing texture set
* @return Textures dependencies
*/
public static Collection<Material> getTextures(IModelConfiguration owner, List<BlockElement> elements, Set<Pair<String, String>> missingTextureErrors) {
// always need a particle texture
Set<Material> textures = Sets.newHashSet(owner.resolveTexture("particle"));
// iterate all elements, fetching needed textures from the material
for (BlockElement part : elements) {
for (BlockElementFace face : part.faces.values()) {
Material material = owner.resolveTexture(face.texture);
if (Objects.equals(material.texture(), MissingTextureAtlasSprite.getLocation())) {
missingTextureErrors.add(Pair.of(face.texture, owner.getModelName()));
}
textures.add(material);
}
}
return textures;
}
/**
* Gets the texture and model dependencies for a block model
*
* @param owner Model configuration
* @param modelGetter Model getter to fetch parent models
* @param missingTextureErrors Missing texture set
* @return Textures dependencies
*/
@Override
public Collection<Material> getTextures(IModelConfiguration owner, Function<ResourceLocation, UnbakedModel> modelGetter, Set<Pair<String, String>> missingTextureErrors) {
this.fetchParent(owner, modelGetter);
return getTextures(owner, getElements(), missingTextureErrors);
}
/* Baking */
/**
* Bakes a single part of the model into the builder
*
* @param builder Baked model builder
* @param owner Model owner
* @param part Part to bake
* @param transform Model transforms
* @param spriteGetter Sprite getter
* @param location Model location
*/
public static void bakePart(SimpleBakedModel.Builder builder, IModelConfiguration owner, BlockElement part, ModelState transform, Function<Material, TextureAtlasSprite> spriteGetter, ResourceLocation location) {
for (Direction direction : part.faces.keySet()) {
BlockElementFace face = part.faces.get(direction);
// ensure the name is not prefixed (it always is)
String texture = face.texture;
if (texture.charAt(0) == '#') {
texture = texture.substring(1);
}
// bake the face
TextureAtlasSprite sprite = spriteGetter.apply(owner.resolveTexture(texture));
BakedQuad bakedQuad = BlockModel.bakeFace(part, face, sprite, direction, transform, location);
// apply cull face
if (face.cullForDirection == null) {
builder.addUnculledFace(bakedQuad);
} else {
builder.addCulledFace(Direction.rotate(transform.getRotation().getMatrix(), face.cullForDirection), bakedQuad);
}
}
}
/**
* Bakes a list of block part elements into a model
*
* @param owner Model configuration
* @param elements Model elements
* @param transform Model transform
* @param overrides Model overrides
* @param spriteGetter Sprite getter instance
* @param location Model bake location
* @return Baked model
*/
public static BakedModel bakeModel(IModelConfiguration owner, List<BlockElement> elements, ModelState transform, ItemOverrides overrides, Function<Material, TextureAtlasSprite> spriteGetter, ResourceLocation location) {
// iterate parts, adding to the builder
TextureAtlasSprite particle = spriteGetter.apply(owner.resolveTexture("particle"));
SimpleBakedModel.Builder builder = new SimpleBakedModel.Builder(owner, overrides).particle(particle);
for (BlockElement part : elements) {
bakePart(builder, owner, part, transform, spriteGetter, location);
}
return builder.build();
}
/**
* Same as {@link #bakeModel(IModelConfiguration, List, ModelState, ItemOverrides, Function, ResourceLocation)}, but passes in sensible defaults for values unneeded in dynamic models
*
* @param owner Model configuration
* @param elements Elements to bake
* @param transform Model transform
* @return Baked model
*/
public static BakedModel bakeDynamic(IModelConfiguration owner, List<BlockElement> elements, ModelState transform) {
return bakeModel(owner, elements, transform, ItemOverrides.EMPTY, ForgeModelBakery.defaultTextureGetter(), BAKE_LOCATION);
}
/**
* Bakes the given block model
*
* @param owner Model configuration
* @param transform Transform to apply
* @param overrides Item overrides in baking
* @param spriteGetter Sprite getter instance
* @param location Bake location
* @return Baked model
*/
public BakedModel bakeModel(IModelConfiguration owner, ModelState transform, ItemOverrides overrides, Function<Material, TextureAtlasSprite> spriteGetter, ResourceLocation location) {
return bakeModel(owner, this.getElements(), transform, overrides, spriteGetter, location);
}
@Override
public BakedModel bake(IModelConfiguration owner, ModelBakery bakery, Function<Material, TextureAtlasSprite> spriteGetter, ModelState transform, ItemOverrides overrides, ResourceLocation location) {
return bakeModel(owner, transform, overrides, spriteGetter, location);
}
/**
* Same as {@link #bakeModel(IModelConfiguration, ModelState, ItemOverrides, Function, ResourceLocation)}, but passes in sensible defaults for values unneeded in dynamic models
*
* @param owner Model configuration
* @param transform Transform to apply
* @return Baked model
*/
public BakedModel bakeDynamic(IModelConfiguration owner, ModelState transform) {
return bakeDynamic(owner, this.getElements(), transform);
}
/* Deserializing */
/**
* Deserializes a SimpleBlockModel from JSON
*
* @param context Json Context
* @param json Json element containing the model
* @return Serialized JSON
*/
public static SimpleBlockModel deserialize(JsonDeserializationContext context, JsonObject json) {
// parent, null if missing
String parentName = GsonHelper.getAsString(json, "parent", "");
ResourceLocation parent = parentName.isEmpty() ? null : new ResourceLocation(parentName);
// textures, empty map if missing
Map<String, Either<Material, String>> textureMap;
if (json.has("textures")) {
ImmutableMap.Builder<String, Either<Material, String>> builder = new ImmutableMap.Builder<>();
ResourceLocation atlas = InventoryMenu.BLOCK_ATLAS;
JsonObject textures = GsonHelper.getAsJsonObject(json, "textures");
for (Entry<String, JsonElement> entry : textures.entrySet()) {
builder.put(entry.getKey(), BlockModel.Deserializer.parseTextureLocationOrReference(atlas, entry.getValue().getAsString()));
}
textureMap = builder.build();
} else {
textureMap = Collections.emptyMap();
}
// elements, empty list if missing
List<BlockElement> parts;
if (json.has("elements")) {
parts = getModelElements(context, GsonHelper.getAsJsonArray(json, "elements"), "elements");
} else {
parts = Collections.emptyList();
}
return new SimpleBlockModel(parent, textureMap, parts);
}
/**
* Gets a list of models from a JSON array
*
* @param context Json Context
* @param array Json array
* @return Model list
*/
public static List<BlockElement> getModelElements(JsonDeserializationContext context, JsonElement array, String name) {
// if just one element, array is optional
if (array.isJsonObject()) {
return ImmutableList.of(context.deserialize(array.getAsJsonObject(), BlockElement.class));
}
// if an array, get array of elements
if (array.isJsonArray()) {
ImmutableList.Builder<BlockElement> builder = ImmutableList.builder();
for (JsonElement json : array.getAsJsonArray()) {
builder.add((BlockElement) context.deserialize(json, BlockElement.class));
}
return builder.build();
}
throw new JsonSyntaxException("Missing " + name + ", expected to find a JsonArray or JsonObject");
}
/**
* Logic to implement a vanilla block model
*/
private static class Loader implements IModelLoader<SimpleBlockModel> {
@Override
public void onResourceManagerReload(ResourceManager resourceManager) {
}
@Override
public SimpleBlockModel read(JsonDeserializationContext context, JsonObject json) {
return deserialize(context, json);
}
}
@Nullable
public ResourceLocation getParentLocation() {
return parentLocation;
}
public Map<String, Either<Material, String>> getTextures() {
return textures;
}
public BlockModel getParent() {
return parent;
}
}

View File

@ -0,0 +1,135 @@
/*
* This file is part of Industrial Foregoing.
*
* Copyright 2021, Buuz135
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so, subject to the
* following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies
* or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
* FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package com.buuz135.functionalstorage.client.model;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.mojang.blaze3d.vertex.DefaultVertexFormat;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexFormat;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.block.model.BakedQuad;
import net.minecraft.client.renderer.block.model.ItemOverrides;
import net.minecraft.client.renderer.block.model.ItemTransforms;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.core.Direction;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraftforge.client.model.data.IDynamicBakedModel;
import net.minecraftforge.client.model.data.IModelData;
import net.minecraftforge.client.model.pipeline.BakedQuadBuilder;
import org.apache.commons.lang3.tuple.Pair;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.*;
public class FramedDrawerBlockModel implements IDynamicBakedModel {
public static Cache<Pair<Pair<String, Pair<Direction, Direction>>, Direction>, List<BakedQuad>> CACHE = CacheBuilder.newBuilder().build();
private VertexFormat format;
private BakedModel previousModel;
private Map<Direction, List<BakedQuad>> prevQuads = new HashMap<>();
public FramedDrawerBlockModel(BakedModel previousConveyor) {
this.previousModel = previousConveyor;
this.format = DefaultVertexFormat.BLOCK;
}
@Nonnull
@Override
public List<BakedQuad> getQuads(@Nullable BlockState state, @Nullable Direction side, @Nonnull Random rand, @Nonnull IModelData extraData) {
List<BakedQuad> bakedQuads = new ArrayList<>();
BakedModel otherModel = Minecraft.getInstance().getBlockRenderer().getBlockModel(Blocks.STONE.defaultBlockState());
for (BakedQuad quad : previousModel.getQuads(state, side, rand)) {
if (otherModel.getQuads(state, side, rand).size() > 0) {
BakedQuadBuilder bakedQuadBuilder = new BakedQuadBuilder(otherModel.getQuads(state, side, rand).get(0).getSprite());
bakedQuadBuilder.setQuadOrientation(quad.getDirection());
bakedQuadBuilder.setQuadTint(quad.getTintIndex());
bakedQuadBuilder.setApplyDiffuseLighting(quad.isShade());
quad.pipe(bakedQuadBuilder);
bakedQuadBuilder.setTexture(otherModel.getQuads(state, side, rand).get(0).getSprite());
System.out.println(otherModel.getQuads(state, side, rand).get(0).getVertices().length);
BakedQuad extra = bakedQuadBuilder.build();
System.out.println(Arrays.toString(extra.getVertices()));
bakedQuads.add(extra);
//bakedQuadBuilder.getVertexFormat()
//bakedQuads.add(bakedQuadBuilder.build());
}
}
return bakedQuads;/*
if (state == null) {
if (!prevQuads.containsKey(side))
prevQuads.put(side, previousModel.getQuads(state, side, rand));
return prevQuads.get(side);
}
if (!prevQuads.containsKey(side))
prevQuads.put(side, previousModel.getQuads(state, side, rand));
List<BakedQuad> quads = new ArrayList<>(prevQuads.get(side));
return quads;*/
}
@Override
public boolean useAmbientOcclusion() {
return previousModel.useAmbientOcclusion();
}
@Override
public boolean isGui3d() {
return previousModel.isGui3d();
}
@Override
public boolean usesBlockLight() {
return previousModel.usesBlockLight();
}
@Override
public boolean isCustomRenderer() {
return previousModel.isCustomRenderer();
}
@Nonnull
@Override
public TextureAtlasSprite getParticleIcon() {
return previousModel.getParticleIcon();
}
@Nonnull
@Override
public ItemOverrides getOverrides() {
return previousModel.getOverrides();
}
@Override
public BakedModel handlePerspective(ItemTransforms.TransformType cameraTransformType, PoseStack mat) {
return previousModel.handlePerspective(cameraTransformType, mat);
}
@Override
public ItemTransforms getTransforms() {
return previousModel.getTransforms();
}
}

View File

@ -0,0 +1,78 @@
/*
* This file is part of Industrial Foregoing.
*
* Copyright 2021, Buuz135
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so, subject to the
* following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies
* or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
* FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package com.buuz135.functionalstorage.client.model;
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 implements INBTSerializable<CompoundTag> {
public static final ModelProperty<FramedDrawerModelData> FRAMED_PROPERTY = new ModelProperty<>();
private Map<String, Item> design;
private String code = "";
public FramedDrawerModelData(Map<String, Item> design) {
this.design = design;
this.generateCode();
}
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

@ -68,5 +68,6 @@ public class FunctionalStorageLangProvider extends LanguageProvider {
this.add("linkingtool.ender.frequency", "Frequency: ");
this.add("linkingtool.ender.clear", "Sneak + Right Click in the air to clear frequency.");
this.add("drawer.block.contents", "Contents: ");
this.add("frameddrawer.use", "How 2 Change Texture: \nInside a crafting window place the block you want use the texture of for the outside of the drawer in the first slot of the crafting window, on the second slot put the block that will be used for the texture on the inside of the framed drawer and on the third slot put a framed drawer. \n");
}
}

View File

@ -0,0 +1,59 @@
package com.buuz135.functionalstorage.recipe;
import com.buuz135.functionalstorage.block.CompactingDrawerBlock;
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;
}
public static boolean matchesCompacting(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 CompactingDrawerBlock;
}
@Override
public boolean matches(CraftingContainer inv, Level worldIn) {
return matches(inv.getItem(0), inv.getItem(1), inv.getItem(2)) || matchesCompacting(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)) || matchesCompacting(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

@ -0,0 +1,131 @@
{
"credit": "Made with Blockbench",
"textures": {
"lock_icon": "functionalstorage:blocks/unlock"
},
"elements": [
{
"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": [1, 9, 0.5],
"to": [15, 15, 2.5],
"rotation": {"angle": 0, "axis": "y", "origin": [-8, 0, -8]},
"faces": {
"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": "#front_divider", "cullface": "north"},
"up": {"uv": [15, 7, 1, 9], "texture": "#front_divider"},
"down": {"uv": [1, 9, 15, 7], "rotation": 180, "texture": "#front_divider"}
}
},
{
"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"}
}
},
{
"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, 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, 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],
"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

@ -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": "#front_divider", "cullface": "north"},
"east": {"uv": [9, 1, 7, 15], "texture": "#front_divider"},
"west": {"uv": [9, 1, 7, 15], "texture": "#front_divider"}
}
},
{
"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": "#front_divider", "cullface": "north"},
"up": {"uv": [7, 7, 1, 9], "texture": "#front_divider"},
"down": {"uv": [7, 7, 1, 9], "texture": "#front_divider"}
}
},
{
"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": "#front_divider", "cullface": "north"},
"up": {"uv": [15, 7, 9, 9], "texture": "#front_divider"},
"down": {"uv": [15, 7, 9, 9], "texture": "#front_divider"}
}
},
{
"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

@ -0,0 +1,158 @@
{
"loader": "functionalstorage:framed",
"credit": "Made with Blockbench",
"textures": {
"front": "functionalstorage:blocks/framed_side",
"particle": "functionalstorage:blocks/framed_side",
"side": "functionalstorage:blocks/framed_side",
"front_divider": "functionalstorage:blocks/framed_front_compacting",
"lock_icon": "functionalstorage:blocks/unlock"
},
"retextured": [ "particle", "side", "front", "front_divider" ],
"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": [15, 15, 2.5],
"rotation": {"angle": 0, "axis": "y", "origin": [-8, 0, -8]},
"faces": {
"north": {"uv": [1, 1, 15, 7], "texture": "#front"},
"down": {"uv": [0, 0, 14, 2], "texture": "#front"}
}
},
{
"from": [15, 1, 0],
"to": [16, 15, 15],
"rotation": {"angle": 0, "axis": "y", "origin": [-8, 0, -8]},
"faces": {
"north": {"uv": [0, 1, 1, 15], "texture": "#side", "cullface": "north"},
"east": {"uv": [1, 1, 16, 15], "texture": "#side", "cullface": "east"},
"west": {"uv": [0, 1, 15, 15], "texture": "#side"}
}
},
{
"from": [0, 15, 0],
"to": [16, 16, 16],
"rotation": {"angle": 0, "axis": "y", "origin": [-8, 0, -8]},
"faces": {
"north": {"uv": [0, 0, 16, 1], "texture": "#side", "cullface": "north"},
"east": {"uv": [0, 0, 16, 1], "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, 0],
"to": [1, 15, 15],
"rotation": {"angle": 0, "axis": "y", "origin": [-8, 0, -8]},
"faces": {
"north": {"uv": [15, 1, 16, 15], "texture": "#side", "cullface": "north"},
"east": {"uv": [1, 1, 16, 15], "texture": "#side"},
"west": {"uv": [0, 1, 15, 15], "texture": "#side", "cullface": "west"}
}
},
{
"from": [0, 0, 0],
"to": [16, 1, 16],
"rotation": {"angle": 0, "axis": "y", "origin": [-8, 0, -8]},
"faces": {
"north": {"uv": [0, 15, 16, 16], "texture": "#side", "cullface": "north"},
"east": {"uv": [0, 15, 16, 16], "texture": "#side", "cullface": "east"},
"south": {"uv": [0, 15, 16, 16], "texture": "#side", "cullface": "south"},
"west": {"uv": [0, 15, 16, 16], "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, 15],
"to": [16, 15, 16],
"rotation": {"angle": 0, "axis": "y", "origin": [-8, 0, -8]},
"faces": {
"east": {"uv": [0, 1, 1, 15], "texture": "#side", "cullface": "east"},
"south": {"uv": [0, 1, 16, 15], "texture": "#side", "cullface": "south"},
"west": {"uv": [15, 1, 16, 15], "texture": "#side", "cullface": "west"}
}
},
{
"name": "divider",
"from": [1, 7, 0],
"to": [15, 9, 1],
"faces": {
"north": {"uv": [1, 7, 15, 9], "texture": "#front_divider", "cullface": "north"},
"up": {"uv": [15, 8, 1, 7], "texture": "#front_divider"},
"down": {"uv": [15, 8, 1, 9], "texture": "#front_divider"}
}
},
{
"name": "divider",
"from": [7, 1, 0],
"to": [9, 7, 1],
"faces": {
"north": {"uv": [7, 9, 9, 15], "texture": "#front_divider", "cullface": "north"},
"east": {"uv": [7, 9, 8, 15], "texture": "#front_divider"},
"south": {"uv": [0, 0, 2, 6], "texture": "#front_divider"},
"west": {"uv": [8, 9, 9, 15], "texture": "#front_divider"}
}
},
{
"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, 135, 0],
"scale": [0.4, 0.4, 0.4]
},
"firstperson_lefthand": {
"rotation": [0, 135, 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

@ -0,0 +1,10 @@
{
"loader": "functionalstorage:framed",
"parent": "functionalstorage:block/base_x_1",
"textures": {
"front": "functionalstorage:blocks/framed_side",
"particle": "functionalstorage:blocks/framed_side",
"side": "functionalstorage:blocks/framed_side"
},
"retextured": [ "particle", "side", "front", "front_divider" ]
}

View File

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

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

View File

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