diff --git a/build.gradle b/build.gradle index a826bc2..aef383d 100644 --- a/build.gradle +++ b/build.gradle @@ -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") diff --git a/src/generated/resources/assets/functionalstorage/blockstates/compacting_framed_drawer.json b/src/generated/resources/assets/functionalstorage/blockstates/compacting_framed_drawer.json new file mode 100644 index 0000000..8212fa3 --- /dev/null +++ b/src/generated/resources/assets/functionalstorage/blockstates/compacting_framed_drawer.json @@ -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 + } + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/functionalstorage/blockstates/framed_1.json b/src/generated/resources/assets/functionalstorage/blockstates/framed_1.json new file mode 100644 index 0000000..45d6d00 --- /dev/null +++ b/src/generated/resources/assets/functionalstorage/blockstates/framed_1.json @@ -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 + } + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/functionalstorage/blockstates/framed_2.json b/src/generated/resources/assets/functionalstorage/blockstates/framed_2.json new file mode 100644 index 0000000..d786d1c --- /dev/null +++ b/src/generated/resources/assets/functionalstorage/blockstates/framed_2.json @@ -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 + } + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/functionalstorage/blockstates/framed_4.json b/src/generated/resources/assets/functionalstorage/blockstates/framed_4.json new file mode 100644 index 0000000..3226cad --- /dev/null +++ b/src/generated/resources/assets/functionalstorage/blockstates/framed_4.json @@ -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 + } + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/functionalstorage/lang/en_us.json b/src/generated/resources/assets/functionalstorage/lang/en_us.json index 2da1184..701b46b 100644 --- a/src/generated/resources/assets/functionalstorage/lang/en_us.json +++ b/src/generated/resources/assets/functionalstorage/lang/en_us.json @@ -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" } \ No newline at end of file diff --git a/src/generated/resources/assets/functionalstorage/models/block/compacting_framed_drawer_locked.json b/src/generated/resources/assets/functionalstorage/models/block/compacting_framed_drawer_locked.json new file mode 100644 index 0000000..df26b0b --- /dev/null +++ b/src/generated/resources/assets/functionalstorage/models/block/compacting_framed_drawer_locked.json @@ -0,0 +1,6 @@ +{ + "parent": "functionalstorage:block/compacting_framed_drawer", + "textures": { + "lock_icon": "functionalstorage:blocks/lock" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/functionalstorage/models/block/framed_1_locked.json b/src/generated/resources/assets/functionalstorage/models/block/framed_1_locked.json new file mode 100644 index 0000000..6346d27 --- /dev/null +++ b/src/generated/resources/assets/functionalstorage/models/block/framed_1_locked.json @@ -0,0 +1,6 @@ +{ + "parent": "functionalstorage:block/framed_1", + "textures": { + "lock_icon": "functionalstorage:blocks/lock" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/functionalstorage/models/block/framed_2_locked.json b/src/generated/resources/assets/functionalstorage/models/block/framed_2_locked.json new file mode 100644 index 0000000..f039cf1 --- /dev/null +++ b/src/generated/resources/assets/functionalstorage/models/block/framed_2_locked.json @@ -0,0 +1,6 @@ +{ + "parent": "functionalstorage:block/framed_2", + "textures": { + "lock_icon": "functionalstorage:blocks/lock" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/functionalstorage/models/block/framed_4_locked.json b/src/generated/resources/assets/functionalstorage/models/block/framed_4_locked.json new file mode 100644 index 0000000..9ac9598 --- /dev/null +++ b/src/generated/resources/assets/functionalstorage/models/block/framed_4_locked.json @@ -0,0 +1,6 @@ +{ + "parent": "functionalstorage:block/framed_4", + "textures": { + "lock_icon": "functionalstorage:blocks/lock" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/functionalstorage/models/item/compacting_framed_drawer.json b/src/generated/resources/assets/functionalstorage/models/item/compacting_framed_drawer.json new file mode 100644 index 0000000..e262581 --- /dev/null +++ b/src/generated/resources/assets/functionalstorage/models/item/compacting_framed_drawer.json @@ -0,0 +1,3 @@ +{ + "parent": "functionalstorage:block/compacting_framed_drawer" +} \ No newline at end of file diff --git a/src/generated/resources/assets/functionalstorage/models/item/framed_1.json b/src/generated/resources/assets/functionalstorage/models/item/framed_1.json new file mode 100644 index 0000000..bac28e9 --- /dev/null +++ b/src/generated/resources/assets/functionalstorage/models/item/framed_1.json @@ -0,0 +1,3 @@ +{ + "parent": "functionalstorage:block/framed_1" +} \ No newline at end of file diff --git a/src/generated/resources/assets/functionalstorage/models/item/framed_2.json b/src/generated/resources/assets/functionalstorage/models/item/framed_2.json new file mode 100644 index 0000000..9585ba6 --- /dev/null +++ b/src/generated/resources/assets/functionalstorage/models/item/framed_2.json @@ -0,0 +1,3 @@ +{ + "parent": "functionalstorage:block/framed_2" +} \ No newline at end of file diff --git a/src/generated/resources/assets/functionalstorage/models/item/framed_4.json b/src/generated/resources/assets/functionalstorage/models/item/framed_4.json new file mode 100644 index 0000000..906e0ec --- /dev/null +++ b/src/generated/resources/assets/functionalstorage/models/item/framed_4.json @@ -0,0 +1,3 @@ +{ + "parent": "functionalstorage:block/framed_4" +} \ No newline at end of file diff --git a/src/generated/resources/data/functionalstorage/loot_tables/blocks/compacting_framed_drawer.json b/src/generated/resources/data/functionalstorage/loot_tables/blocks/compacting_framed_drawer.json new file mode 100644 index 0000000..68701f9 --- /dev/null +++ b/src/generated/resources/data/functionalstorage/loot_tables/blocks/compacting_framed_drawer.json @@ -0,0 +1,3 @@ +{ + "type": "minecraft:block" +} \ No newline at end of file diff --git a/src/generated/resources/data/functionalstorage/loot_tables/blocks/framed_1.json b/src/generated/resources/data/functionalstorage/loot_tables/blocks/framed_1.json new file mode 100644 index 0000000..68701f9 --- /dev/null +++ b/src/generated/resources/data/functionalstorage/loot_tables/blocks/framed_1.json @@ -0,0 +1,3 @@ +{ + "type": "minecraft:block" +} \ No newline at end of file diff --git a/src/generated/resources/data/functionalstorage/loot_tables/blocks/framed_2.json b/src/generated/resources/data/functionalstorage/loot_tables/blocks/framed_2.json new file mode 100644 index 0000000..68701f9 --- /dev/null +++ b/src/generated/resources/data/functionalstorage/loot_tables/blocks/framed_2.json @@ -0,0 +1,3 @@ +{ + "type": "minecraft:block" +} \ No newline at end of file diff --git a/src/generated/resources/data/functionalstorage/loot_tables/blocks/framed_4.json b/src/generated/resources/data/functionalstorage/loot_tables/blocks/framed_4.json new file mode 100644 index 0000000..68701f9 --- /dev/null +++ b/src/generated/resources/data/functionalstorage/loot_tables/blocks/framed_4.json @@ -0,0 +1,3 @@ +{ + "type": "minecraft:block" +} \ No newline at end of file diff --git a/src/generated/resources/data/functionalstorage/recipes/compacting_framed_drawer.json b/src/generated/resources/data/functionalstorage/recipes/compacting_framed_drawer.json new file mode 100644 index 0000000..a09a119 --- /dev/null +++ b/src/generated/resources/data/functionalstorage/recipes/compacting_framed_drawer.json @@ -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" + } + } + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/functionalstorage/recipes/framed_1.json b/src/generated/resources/data/functionalstorage/recipes/framed_1.json new file mode 100644 index 0000000..de3af52 --- /dev/null +++ b/src/generated/resources/data/functionalstorage/recipes/framed_1.json @@ -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" + } + } + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/functionalstorage/recipes/framed_2.json b/src/generated/resources/data/functionalstorage/recipes/framed_2.json new file mode 100644 index 0000000..e8487a2 --- /dev/null +++ b/src/generated/resources/data/functionalstorage/recipes/framed_2.json @@ -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 + } + } + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/functionalstorage/recipes/framed_4.json b/src/generated/resources/data/functionalstorage/recipes/framed_4.json new file mode 100644 index 0000000..96b46f4 --- /dev/null +++ b/src/generated/resources/data/functionalstorage/recipes/framed_4.json @@ -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 + } + } + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/minecraft/tags/blocks/mineable/axe.json b/src/generated/resources/data/minecraft/tags/blocks/mineable/axe.json index 6dff867..9e05415 100644 --- a/src/generated/resources/data/minecraft/tags/blocks/mineable/axe.json +++ b/src/generated/resources/data/minecraft/tags/blocks/mineable/axe.json @@ -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" ] } \ No newline at end of file diff --git a/src/generated/resources/data/minecraft/tags/blocks/mineable/pickaxe.json b/src/generated/resources/data/minecraft/tags/blocks/mineable/pickaxe.json index 03f3bd9..0db3f6e 100644 --- a/src/generated/resources/data/minecraft/tags/blocks/mineable/pickaxe.json +++ b/src/generated/resources/data/minecraft/tags/blocks/mineable/pickaxe.json @@ -2,6 +2,7 @@ "replace": false, "values": [ "functionalstorage:compacting_drawer", + "functionalstorage:compacting_framed_drawer", "functionalstorage:storage_controller", "functionalstorage:armory_cabinet", "functionalstorage:ender_drawer" diff --git a/src/main/java/com/buuz135/functionalstorage/FunctionalStorage.java b/src/main/java/com/buuz135/functionalstorage/FunctionalStorage.java index a283f1c..bd3e0f3 100644 --- a/src/main/java/com/buuz135/functionalstorage/FunctionalStorage.java +++ b/src/main/java/com/buuz135/functionalstorage/FunctionalStorage.java @@ -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 WOOD_TYPES = new ArrayList<>(); @@ -97,6 +100,7 @@ public class FunctionalStorage extends ModuleController { public static Pair, RegistryObject>> DRAWER_CONTROLLER; public static Pair, RegistryObject>> ARMORY_CABINET; public static Pair, RegistryObject>> ENDER_DRAWER; + public static Pair, RegistryObject>> FRAMED_COMPACTING_DRAWER; public static RegistryObject LINKING_TOOL; public static HashMap> 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) COMPACTING_DRAWER.getRight().get(), p_173571_ -> new CompactingDrawerRenderer()); + registerRenderers.registerBlockEntityRenderer((BlockEntityType) FRAMED_COMPACTING_DRAWER.getRight().get(), p_173571_ -> new CompactingDrawerRenderer()); registerRenderers.registerBlockEntityRenderer((BlockEntityType) DRAWER_CONTROLLER.getRight().get(), p -> new ControllerRenderer()); registerRenderers.registerBlockEntityRenderer((BlockEntityType) 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 diff --git a/src/main/java/com/buuz135/functionalstorage/block/CompactingDrawerBlock.java b/src/main/java/com/buuz135/functionalstorage/block/CompactingDrawerBlock.java index 18f7336..b44cd50 100644 --- a/src/main/java/com/buuz135/functionalstorage/block/CompactingDrawerBlock.java +++ b/src/main/java/com/buuz135/functionalstorage/block/CompactingDrawerBlock.java @@ -70,8 +70,8 @@ public class CompactingDrawerBlock extends RotatableBlock } - 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)); } diff --git a/src/main/java/com/buuz135/functionalstorage/block/CompactingFramedDrawerBlock.java b/src/main/java/com/buuz135/functionalstorage/block/CompactingFramedDrawerBlock.java new file mode 100644 index 0000000..5c602cb --- /dev/null +++ b/src/main/java/com/buuz135/functionalstorage/block/CompactingFramedDrawerBlock.java @@ -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> 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 getTileEntityFactory() { + return (blockPos, state) -> new CompactingFramedDrawerTile(this, (BlockEntityType) 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 getDrops(BlockState p_60537_, LootContext.Builder builder) { + NonNullList 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 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 components, TooltipFlag p_49819_) { + components.add(new TranslatableComponent("frameddrawer.use").withStyle(ChatFormatting.GRAY)); + super.appendHoverText(p_49816_, p_49817_, components, p_49819_); + } +} diff --git a/src/main/java/com/buuz135/functionalstorage/block/DrawerBlock.java b/src/main/java/com/buuz135/functionalstorage/block/DrawerBlock.java index 0c15874..3c1e481 100644 --- a/src/main/java/com/buuz135/functionalstorage/block/DrawerBlock.java +++ b/src/main/java/com/buuz135/functionalstorage/block/DrawerBlock.java @@ -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 { 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 p_206840_1_) { super.createBlockStateDefinition(p_206840_1_); @@ -319,7 +321,7 @@ public class DrawerBlock extends RotatableBlock { @Override public void appendHoverText(ItemStack p_49816_, @Nullable BlockGetter p_49817_, List 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("")); diff --git a/src/main/java/com/buuz135/functionalstorage/block/FramedDrawerBlock.java b/src/main/java/com/buuz135/functionalstorage/block/FramedDrawerBlock.java new file mode 100644 index 0000000..ea8cd2d --- /dev/null +++ b/src/main/java/com/buuz135/functionalstorage/block/FramedDrawerBlock.java @@ -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 getTileEntityFactory() { + return (blockPos, state) -> new FramedDrawerTile(this, (BlockEntityType) 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 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 getDrops(BlockState p_60537_, LootContext.Builder builder) { + NonNullList 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 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 components, TooltipFlag p_49819_) { + components.add(new TranslatableComponent("frameddrawer.use").withStyle(ChatFormatting.GRAY)); + super.appendHoverText(p_49816_, p_49817_, components, p_49819_); + } +} diff --git a/src/main/java/com/buuz135/functionalstorage/block/tile/CompactingFramedDrawerTile.java b/src/main/java/com/buuz135/functionalstorage/block/tile/CompactingFramedDrawerTile.java new file mode 100644 index 0000000..994a5a5 --- /dev/null +++ b/src/main/java/com/buuz135/functionalstorage/block/tile/CompactingFramedDrawerTile.java @@ -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 base, BlockEntityType 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(); + } +} diff --git a/src/main/java/com/buuz135/functionalstorage/block/tile/FramedDrawerTile.java b/src/main/java/com/buuz135/functionalstorage/block/tile/FramedDrawerTile.java new file mode 100644 index 0000000..e6ecd12 --- /dev/null +++ b/src/main/java/com/buuz135/functionalstorage/block/tile/FramedDrawerTile.java @@ -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 base, BlockEntityType 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(); + } +} diff --git a/src/main/java/com/buuz135/functionalstorage/client/loader/DynamicBakedWrapper.java b/src/main/java/com/buuz135/functionalstorage/client/loader/DynamicBakedWrapper.java new file mode 100644 index 0000000..e3a6004 --- /dev/null +++ b/src/main/java/com/buuz135/functionalstorage/client/loader/DynamicBakedWrapper.java @@ -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 Baked model parent + */ +@SuppressWarnings("WeakerAccess") +public abstract class DynamicBakedWrapper extends BakedModelWrapper { + + protected DynamicBakedWrapper(T originalModel) { + super(originalModel); + } + + /** + * @deprecated use {@link #getQuads(BlockState, Direction, Random, IModelData)} + */ + @Override + @Deprecated + public List getQuads(@Nullable BlockState state, @Nullable Direction side, Random rand) { + return this.getQuads(state, side, rand, EmptyModelData.INSTANCE); + } + + @Override + public abstract List getQuads(@Nullable BlockState state, @Nullable Direction side, Random rand, IModelData extraData); +} diff --git a/src/main/java/com/buuz135/functionalstorage/client/loader/ModelConfigurationWrapper.java b/src/main/java/com/buuz135/functionalstorage/client/loader/ModelConfigurationWrapper.java new file mode 100644 index 0000000..0f1c971 --- /dev/null +++ b/src/main/java/com/buuz135/functionalstorage/client/loader/ModelConfigurationWrapper.java @@ -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); + } +} \ No newline at end of file diff --git a/src/main/java/com/buuz135/functionalstorage/client/loader/ModelHelper.java b/src/main/java/com/buuz135/functionalstorage/client/loader/ModelHelper.java new file mode 100644 index 0000000..c0fb09a --- /dev/null +++ b/src/main/java/com/buuz135/functionalstorage/client/loader/ModelHelper.java @@ -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 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 Class type + * @return Block model, or null if its missing or the wrong class type + */ + @Nullable + public static T getBakedModel(BlockState state, Class 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 Class type + * @return Item model, or null if its missing or the wrong class type + */ + @Nullable + public static T getBakedModel(ItemLike item, Class 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 Output type + * @return Vector3f of data + * @throws JsonParseException If there is no array or the length is wrong + */ + public static T arrayToObject(JsonObject json, String name, int size, Function 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(); + } + } +} diff --git a/src/main/java/com/buuz135/functionalstorage/client/loader/ModelTextureIteratable.java b/src/main/java/com/buuz135/functionalstorage/client/loader/ModelTextureIteratable.java new file mode 100644 index 0000000..84a083b --- /dev/null +++ b/src/main/java/com/buuz135/functionalstorage/client/loader/ModelTextureIteratable.java @@ -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>> { + /** Initial map for iteration */ + @Nullable + private final Map> startMap; + /** Initial model for iteration */ + @Nullable + private final BlockModel startModel; + + public ModelTextureIteratable(@Nullable Map> 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>> { + + public MapIterator(@Nullable Map> initial, @Nullable BlockModel model) { + this.initial = initial; + this.model = model; + } + + /** Initial map for iteration */ + @Nullable + private Map> initial; + /** current model in the iterator */ + @Nullable + private BlockModel model; + + @Override + public boolean hasNext() { + return initial != null || model != null; + } + + @Override + public Map> next() { + Map> map; + if (initial != null) { + map = initial; + initial = null; + } else if (model != null) { + map = model.textureMap; + model = model.parent; + } else { + throw new NoSuchElementException(); + } + return map; + } + } +} diff --git a/src/main/java/com/buuz135/functionalstorage/client/loader/RetexturedHelper.java b/src/main/java/com/buuz135/functionalstorage/client/loader/RetexturedHelper.java new file mode 100644 index 0000000..12c300e --- /dev/null +++ b/src/main/java/com/buuz135/functionalstorage/client/loader/RetexturedHelper.java @@ -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); + } + } + } +} \ No newline at end of file diff --git a/src/main/java/com/buuz135/functionalstorage/client/loader/RetexturedModel.java b/src/main/java/com/buuz135/functionalstorage/client/loader/RetexturedModel.java new file mode 100644 index 0000000..280727d --- /dev/null +++ b/src/main/java/com/buuz135/functionalstorage/client/loader/RetexturedModel.java @@ -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 { + private final SimpleBlockModel model; + private final Set retextured; + + public RetexturedModel(SimpleBlockModel model, Set retextured) { + this.model = model; + this.retextured = retextured; + } + + @Override + public Collection getTextures(IModelConfiguration owner, Function modelGetter, Set> missingTextureErrors) { + return model.getTextures(owner, modelGetter, missingTextureErrors); + } + + @Override + public BakedModel bake(IModelConfiguration owner, ModelBakery bakery, Function 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 getAllRetextured(IModelConfiguration owner, SimpleBlockModel model, Set originalSet) { + Set retextured = Sets.newHashSet(originalSet); + for (Map> 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 { + 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 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 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 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 { + /** Cache of texture name to baked model */ + private final Map 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 retextured; + + public Baked(BakedModel baked, IModelConfiguration owner, SimpleBlockModel model, ModelState transform, Set 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 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 retextured; + /** Replacement texture */ + private final HashMap 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 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); + } + } +} diff --git a/src/main/java/com/buuz135/functionalstorage/client/loader/SimpleBlockModel.java b/src/main/java/com/buuz135/functionalstorage/client/loader/SimpleBlockModel.java new file mode 100644 index 0000000..a411435 --- /dev/null +++ b/src/main/java/com/buuz135/functionalstorage/client/loader/SimpleBlockModel.java @@ -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 { + /** + * 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 parts; + /** + * Fallback textures in case the owner does not contain a block model + */ + private final Map> 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> textures, List 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 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 modelGetter) { + // no work if no parent or the parent is fetched already + if (parent != null || parentLocation == null) { + return; + } + + // iterate through model parents + Set 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 modelGetter, Set 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 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 getTextures(IModelConfiguration owner, List elements, Set> missingTextureErrors) { + // always need a particle texture + Set 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 getTextures(IModelConfiguration owner, Function modelGetter, Set> 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 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 elements, ModelState transform, ItemOverrides overrides, Function 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 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 spriteGetter, ResourceLocation location) { + return bakeModel(owner, this.getElements(), transform, overrides, spriteGetter, location); + } + + @Override + public BakedModel bake(IModelConfiguration owner, ModelBakery bakery, Function 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> textureMap; + if (json.has("textures")) { + ImmutableMap.Builder> builder = new ImmutableMap.Builder<>(); + ResourceLocation atlas = InventoryMenu.BLOCK_ATLAS; + JsonObject textures = GsonHelper.getAsJsonObject(json, "textures"); + for (Entry 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 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 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 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 { + @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> getTextures() { + return textures; + } + + public BlockModel getParent() { + return parent; + } +} \ No newline at end of file diff --git a/src/main/java/com/buuz135/functionalstorage/client/model/FramedDrawerBlockModel.java b/src/main/java/com/buuz135/functionalstorage/client/model/FramedDrawerBlockModel.java new file mode 100644 index 0000000..289513f --- /dev/null +++ b/src/main/java/com/buuz135/functionalstorage/client/model/FramedDrawerBlockModel.java @@ -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>, Direction>, List> CACHE = CacheBuilder.newBuilder().build(); + private VertexFormat format; + private BakedModel previousModel; + private Map> prevQuads = new HashMap<>(); + + public FramedDrawerBlockModel(BakedModel previousConveyor) { + this.previousModel = previousConveyor; + this.format = DefaultVertexFormat.BLOCK; + } + + @Nonnull + @Override + public List getQuads(@Nullable BlockState state, @Nullable Direction side, @Nonnull Random rand, @Nonnull IModelData extraData) { + List 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 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(); + } +} \ No newline at end of file diff --git a/src/main/java/com/buuz135/functionalstorage/client/model/FramedDrawerModelData.java b/src/main/java/com/buuz135/functionalstorage/client/model/FramedDrawerModelData.java new file mode 100644 index 0000000..03ee38f --- /dev/null +++ b/src/main/java/com/buuz135/functionalstorage/client/model/FramedDrawerModelData.java @@ -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 { + + public static final ModelProperty FRAMED_PROPERTY = new ModelProperty<>(); + private Map design; + + private String code = ""; + + public FramedDrawerModelData(Map design) { + this.design = design; + this.generateCode(); + } + + public Map 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; + } +} diff --git a/src/main/java/com/buuz135/functionalstorage/data/FunctionalStorageLangProvider.java b/src/main/java/com/buuz135/functionalstorage/data/FunctionalStorageLangProvider.java index 7c59044..455546a 100644 --- a/src/main/java/com/buuz135/functionalstorage/data/FunctionalStorageLangProvider.java +++ b/src/main/java/com/buuz135/functionalstorage/data/FunctionalStorageLangProvider.java @@ -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"); } } diff --git a/src/main/java/com/buuz135/functionalstorage/recipe/FramedDrawerRecipe.java b/src/main/java/com/buuz135/functionalstorage/recipe/FramedDrawerRecipe.java new file mode 100644 index 0000000..fb0dc7c --- /dev/null +++ b/src/main/java/com/buuz135/functionalstorage/recipe/FramedDrawerRecipe.java @@ -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 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; + } +} diff --git a/src/main/java/com/buuz135/functionalstorage/util/DrawerWoodType.java b/src/main/java/com/buuz135/functionalstorage/util/DrawerWoodType.java index fc46631..891cec6 100644 --- a/src/main/java/com/buuz135/functionalstorage/util/DrawerWoodType.java +++ b/src/main/java/com/buuz135/functionalstorage/util/DrawerWoodType.java @@ -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; diff --git a/src/main/resources/META-INF/accesstransformer.cfg b/src/main/resources/META-INF/accesstransformer.cfg index 74631bb..aac003a 100644 --- a/src/main/resources/META-INF/accesstransformer.cfg +++ b/src/main/resources/META-INF/accesstransformer.cfg @@ -1 +1,7 @@ -public net.minecraft.client.renderer.RenderStateShard$LineStateShard \ No newline at end of file +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 \ No newline at end of file diff --git a/src/main/resources/assets/functionalstorage/models/block/base_x_2_framed.json b/src/main/resources/assets/functionalstorage/models/block/base_x_2_framed.json new file mode 100644 index 0000000..ddd75f5 --- /dev/null +++ b/src/main/resources/assets/functionalstorage/models/block/base_x_2_framed.json @@ -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] + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/functionalstorage/models/block/base_x_4_framed.json b/src/main/resources/assets/functionalstorage/models/block/base_x_4_framed.json new file mode 100644 index 0000000..c5ca637 --- /dev/null +++ b/src/main/resources/assets/functionalstorage/models/block/base_x_4_framed.json @@ -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] + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/functionalstorage/models/block/compacting_framed_drawer.json b/src/main/resources/assets/functionalstorage/models/block/compacting_framed_drawer.json new file mode 100644 index 0000000..110fc14 --- /dev/null +++ b/src/main/resources/assets/functionalstorage/models/block/compacting_framed_drawer.json @@ -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] + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/functionalstorage/models/block/framed_1.json b/src/main/resources/assets/functionalstorage/models/block/framed_1.json new file mode 100644 index 0000000..28d22a1 --- /dev/null +++ b/src/main/resources/assets/functionalstorage/models/block/framed_1.json @@ -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" ] +} \ No newline at end of file diff --git a/src/main/resources/assets/functionalstorage/models/block/framed_2.json b/src/main/resources/assets/functionalstorage/models/block/framed_2.json new file mode 100644 index 0000000..c70ee1b --- /dev/null +++ b/src/main/resources/assets/functionalstorage/models/block/framed_2.json @@ -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" ] +} \ No newline at end of file diff --git a/src/main/resources/assets/functionalstorage/models/block/framed_4.json b/src/main/resources/assets/functionalstorage/models/block/framed_4.json new file mode 100644 index 0000000..b7d9650 --- /dev/null +++ b/src/main/resources/assets/functionalstorage/models/block/framed_4.json @@ -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" ] +} \ No newline at end of file diff --git a/src/main/resources/assets/functionalstorage/textures/blocks/framed_front_2.png b/src/main/resources/assets/functionalstorage/textures/blocks/framed_front_2.png new file mode 100644 index 0000000..8baa0d0 Binary files /dev/null and b/src/main/resources/assets/functionalstorage/textures/blocks/framed_front_2.png differ diff --git a/src/main/resources/assets/functionalstorage/textures/blocks/framed_front_4.png b/src/main/resources/assets/functionalstorage/textures/blocks/framed_front_4.png new file mode 100644 index 0000000..1c7f3bc Binary files /dev/null and b/src/main/resources/assets/functionalstorage/textures/blocks/framed_front_4.png differ diff --git a/src/main/resources/assets/functionalstorage/textures/blocks/framed_front_compacting.png b/src/main/resources/assets/functionalstorage/textures/blocks/framed_front_compacting.png new file mode 100644 index 0000000..ef4cf13 Binary files /dev/null and b/src/main/resources/assets/functionalstorage/textures/blocks/framed_front_compacting.png differ diff --git a/src/main/resources/assets/functionalstorage/textures/blocks/framed_side.png b/src/main/resources/assets/functionalstorage/textures/blocks/framed_side.png new file mode 100644 index 0000000..26a2762 Binary files /dev/null and b/src/main/resources/assets/functionalstorage/textures/blocks/framed_side.png differ diff --git a/src/main/resources/data/functionalstorage/recipes/framed.json b/src/main/resources/data/functionalstorage/recipes/framed.json new file mode 100644 index 0000000..d05b81a --- /dev/null +++ b/src/main/resources/data/functionalstorage/recipes/framed.json @@ -0,0 +1,3 @@ +{ + "type": "functionalstorage:framed_recipe" +} \ No newline at end of file