From 47c8a87c7c67705745aa6e4a48e8a83a00abc525 Mon Sep 17 00:00:00 2001 From: P3pp3rF1y Date: Tue, 3 Dec 2024 08:34:27 +0100 Subject: [PATCH] =?UTF-8?q?feat:=20=E2=9C=A8=20Added=20new=20Decoration=20?= =?UTF-8?q?Table=20block=20-=20allows=20applying=20block=20"materials=20to?= =?UTF-8?q?=20barrels"=20in=20much=20easier=20and=20more=20customizable=20?= =?UTF-8?q?way=20than=20the=20material=20recipe=20-=20also=20allows=20appl?= =?UTF-8?q?ying=20color=20tints=20to=20any=20storage=20block=20in=20much?= =?UTF-8?q?=20straight=20forward=20way=20(just=20a=20single=20color=20pick?= =?UTF-8?q?=20instead=20of=20multiple=20dyes=20applied=20to=20get=20the=20?= =?UTF-8?q?color=20wanted)=20-=20uses=20much=20less=20blocks=20/=20dyes=20?= =?UTF-8?q?when=20making=20these=20cosmetic=20changes=20to=20storages=20th?= =?UTF-8?q?an=20the=20recipes=20do?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gradle.properties | 4 +- .../minecraft/tags/blocks/mineable/axe.json | 3 +- .../recipes/misc/decoration_table.json | 35 ++ .../loot_tables/blocks/decoration_table.json | 22 + .../recipes/decoration_table.json | 24 + .../block/DecorationTableBlock.java | 98 +++ .../block/DecorationTableBlockEntity.java | 569 ++++++++++++++++++ .../client/ClientEventHandler.java | 1 + .../client/gui/DecorationTableScreen.java | 565 +++++++++++++++++ .../client/render/BarrelBakedModelBase.java | 10 +- .../render/DecorationTableRenderer.java | 36 ++ .../common/gui/DecorationTableMenu.java | 294 +++++++++ .../crafting/BarrelMaterialRecipe.java | 66 +- .../data/BlockTagProvider.java | 3 +- .../data/StorageBlockLootProvider.java | 2 + .../data/StorageRecipeProvider.java | 14 +- .../sophisticatedstorage/init/ModBlocks.java | 30 +- .../init/ModBlocksClient.java | 0 .../item/BarrelBlockItem.java | 60 ++ .../compression/CompressionInventoryPart.java | 6 +- .../compression/CompressionUpgradeItem.java | 5 +- .../resources/META-INF/accesstransformer.cfg | 3 +- .../blockstates/decoration_table.json | 19 + .../sophisticatedstorage/lang/en_us.json | 16 +- .../models/block/decoration_table.json | 167 +++++ .../models/item/decoration_table.json | 3 + .../textures/block/decoration_table.png | Bin 0 -> 3230 bytes .../textures/gui/decoration_table.png | Bin 0 -> 1177 bytes .../gui/decoration_table_elements.png | Bin 0 -> 2739 bytes .../textures/item/empty_blue_dye_slot.png | Bin 0 -> 273 bytes .../textures/item/empty_green_dye_slot.png | Bin 0 -> 274 bytes .../textures/item/empty_material_slot.png | Bin 0 -> 181 bytes .../textures/item/empty_red_dye_slot.png | Bin 0 -> 292 bytes .../CompressionInventoryPartTest.java | 30 +- 34 files changed, 1977 insertions(+), 108 deletions(-) create mode 100644 src/generated/resources/data/sophisticatedstorage/advancements/recipes/misc/decoration_table.json create mode 100644 src/generated/resources/data/sophisticatedstorage/loot_tables/blocks/decoration_table.json create mode 100644 src/generated/resources/data/sophisticatedstorage/recipes/decoration_table.json create mode 100644 src/main/java/net/p3pp3rf1y/sophisticatedstorage/block/DecorationTableBlock.java create mode 100644 src/main/java/net/p3pp3rf1y/sophisticatedstorage/block/DecorationTableBlockEntity.java create mode 100644 src/main/java/net/p3pp3rf1y/sophisticatedstorage/client/gui/DecorationTableScreen.java create mode 100644 src/main/java/net/p3pp3rf1y/sophisticatedstorage/client/render/DecorationTableRenderer.java create mode 100644 src/main/java/net/p3pp3rf1y/sophisticatedstorage/common/gui/DecorationTableMenu.java create mode 100644 src/main/java/net/p3pp3rf1y/sophisticatedstorage/init/ModBlocksClient.java create mode 100644 src/main/resources/assets/sophisticatedstorage/blockstates/decoration_table.json create mode 100644 src/main/resources/assets/sophisticatedstorage/models/block/decoration_table.json create mode 100644 src/main/resources/assets/sophisticatedstorage/models/item/decoration_table.json create mode 100644 src/main/resources/assets/sophisticatedstorage/textures/block/decoration_table.png create mode 100644 src/main/resources/assets/sophisticatedstorage/textures/gui/decoration_table.png create mode 100644 src/main/resources/assets/sophisticatedstorage/textures/gui/decoration_table_elements.png create mode 100644 src/main/resources/assets/sophisticatedstorage/textures/item/empty_blue_dye_slot.png create mode 100644 src/main/resources/assets/sophisticatedstorage/textures/item/empty_green_dye_slot.png create mode 100644 src/main/resources/assets/sophisticatedstorage/textures/item/empty_material_slot.png create mode 100644 src/main/resources/assets/sophisticatedstorage/textures/item/empty_red_dye_slot.png diff --git a/gradle.properties b/gradle.properties index 0d161c3db..fe8ccaf0a 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,7 +3,7 @@ org.gradle.daemon=false mod_id=sophisticatedstorage mod_group_id=sophisticatedstorage -mod_version=0.10.50 +mod_version=0.11.0 sonar_project_key=sophisticatedstorage:SophisticatedStorage github_package_url=https://maven.pkg.github.com/P3pp3rF1y/SophisticatedStorage @@ -30,6 +30,6 @@ jade_cf_file_id=4614153 chipped_cf_file_id=5077656 resourcefullib_cf_file_id=5070629 athena_cf_file_id=4764357 -sc_version=[1.20.1-0.7.3,1.20.4) +sc_version=[1.20.1-0.7.12,1.20.4) sb_version=[1.20.1-3.20.5,1.20.4) parchment_version=2023.09.03-1.20.1 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 96c5f6a41..dcb08a507 100644 --- a/src/generated/resources/data/minecraft/tags/blocks/mineable/axe.json +++ b/src/generated/resources/data/minecraft/tags/blocks/mineable/axe.json @@ -35,6 +35,7 @@ "sophisticatedstorage:iron_chest", "sophisticatedstorage:gold_chest", "sophisticatedstorage:diamond_chest", - "sophisticatedstorage:netherite_chest" + "sophisticatedstorage:netherite_chest", + "sophisticatedstorage:decoration_table" ] } \ No newline at end of file diff --git a/src/generated/resources/data/sophisticatedstorage/advancements/recipes/misc/decoration_table.json b/src/generated/resources/data/sophisticatedstorage/advancements/recipes/misc/decoration_table.json new file mode 100644 index 000000000..bcf5c0d76 --- /dev/null +++ b/src/generated/resources/data/sophisticatedstorage/advancements/recipes/misc/decoration_table.json @@ -0,0 +1,35 @@ +{ + "parent": "minecraft:recipes/root", + "criteria": { + "has_the_recipe": { + "conditions": { + "recipe": "sophisticatedstorage:decoration_table" + }, + "trigger": "minecraft:recipe_unlocked" + }, + "has_upgrade_base": { + "conditions": { + "items": [ + { + "items": [ + "sophisticatedstorage:upgrade_base" + ] + } + ] + }, + "trigger": "minecraft:inventory_changed" + } + }, + "requirements": [ + [ + "has_upgrade_base", + "has_the_recipe" + ] + ], + "rewards": { + "recipes": [ + "sophisticatedstorage:decoration_table" + ] + }, + "sends_telemetry_event": false +} \ No newline at end of file diff --git a/src/generated/resources/data/sophisticatedstorage/loot_tables/blocks/decoration_table.json b/src/generated/resources/data/sophisticatedstorage/loot_tables/blocks/decoration_table.json new file mode 100644 index 000000000..8eaf37784 --- /dev/null +++ b/src/generated/resources/data/sophisticatedstorage/loot_tables/blocks/decoration_table.json @@ -0,0 +1,22 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "bonus_rolls": 0.0, + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ], + "entries": [ + { + "type": "minecraft:item", + "name": "sophisticatedstorage:decoration_table" + } + ], + "name": "main", + "rolls": 1.0 + } + ], + "random_sequence": "sophisticatedstorage:blocks/decoration_table" +} \ No newline at end of file diff --git a/src/generated/resources/data/sophisticatedstorage/recipes/decoration_table.json b/src/generated/resources/data/sophisticatedstorage/recipes/decoration_table.json new file mode 100644 index 000000000..197251ee6 --- /dev/null +++ b/src/generated/resources/data/sophisticatedstorage/recipes/decoration_table.json @@ -0,0 +1,24 @@ +{ + "type": "minecraft:crafting_shaped", + "category": "misc", + "key": { + "B": { + "item": "sophisticatedstorage:upgrade_base" + }, + "L": { + "tag": "minecraft:logs" + }, + "P": { + "tag": "minecraft:planks" + } + }, + "pattern": [ + "LLL", + "PBP", + "P P" + ], + "result": { + "item": "sophisticatedstorage:decoration_table" + }, + "show_notification": true +} \ No newline at end of file diff --git a/src/main/java/net/p3pp3rf1y/sophisticatedstorage/block/DecorationTableBlock.java b/src/main/java/net/p3pp3rf1y/sophisticatedstorage/block/DecorationTableBlock.java new file mode 100644 index 000000000..1775b6861 --- /dev/null +++ b/src/main/java/net/p3pp3rf1y/sophisticatedstorage/block/DecorationTableBlock.java @@ -0,0 +1,98 @@ +package net.p3pp3rf1y.sophisticatedstorage.block; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.network.chat.Component; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.SimpleMenuProvider; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.context.BlockPlaceContext; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.*; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.StateDefinition; +import net.minecraft.world.level.block.state.properties.DirectionProperty; +import net.minecraft.world.level.material.FluidState; +import net.minecraft.world.level.material.MapColor; +import net.minecraft.world.level.pathfinder.PathComputationType; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.shapes.CollisionContext; +import net.minecraft.world.phys.shapes.Shapes; +import net.minecraft.world.phys.shapes.VoxelShape; +import net.minecraftforge.network.NetworkHooks; +import net.p3pp3rf1y.sophisticatedcore.util.BlockBase; +import net.p3pp3rf1y.sophisticatedcore.util.WorldHelper; +import net.p3pp3rf1y.sophisticatedstorage.common.gui.DecorationTableMenu; + +import javax.annotation.Nullable; + +public class DecorationTableBlock extends BlockBase implements EntityBlock { + public static final DirectionProperty FACING = HorizontalDirectionalBlock.FACING; + protected static final VoxelShape SHAPE = Shapes.or( + Block.box(0, 12, 0, 16, 16, 16), + Block.box(1, 8, 1, 15, 12, 15), + Block.box(1, 0, 1, 4, 8, 4), + Block.box(12, 0, 1, 15, 8, 4), + Block.box(1, 0, 12, 4, 8, 15), + Block.box(12, 0, 12, 15, 8, 15) + ); + + public DecorationTableBlock() { + super(Properties.of().mapColor(MapColor.WOOD).strength(2.5F, 2.5F).sound(SoundType.WOOD)); + registerDefaultState(stateDefinition.any().setValue(FACING, Direction.NORTH)); + } + + @Override + public VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) { + return SHAPE; + } + + @Nullable + @Override + public BlockState getStateForPlacement(BlockPlaceContext context) { + return this.defaultBlockState().setValue(FACING, context.getHorizontalDirection().getOpposite()); + } + + @SuppressWarnings("deprecation") + @Override + public InteractionResult use(BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit) { + if (level.isClientSide) { + return InteractionResult.SUCCESS; + } + + NetworkHooks.openScreen((ServerPlayer) player, new SimpleMenuProvider((w, p, pl) -> new DecorationTableMenu(w, pl, pos), getName()), pos); + + return InteractionResult.CONSUME; + } + + @Override + public boolean onDestroyedByPlayer(BlockState state, Level level, BlockPos pos, Player player, boolean willHarvest, FluidState fluid) { + //TODO drop contents either here or in loot table + return super.onDestroyedByPlayer(state, level, pos, player, willHarvest, fluid); + } + + @Nullable + @Override + public DecorationTableBlockEntity newBlockEntity(BlockPos pos, BlockState state) { + return new DecorationTableBlockEntity(pos, state); + } + + @SuppressWarnings("deprecation") + @Override + public BlockState mirror(BlockState state, Mirror mirror) { + return state.rotate(mirror.getRotation(state.getValue(FACING))); + } + + @Override + protected void createBlockStateDefinition(StateDefinition.Builder builder) { + builder.add(FACING); + } + + @Override + public boolean isPathfindable(BlockState pState, BlockGetter pLevel, BlockPos pPos, PathComputationType pType) { + return false; + } +} diff --git a/src/main/java/net/p3pp3rf1y/sophisticatedstorage/block/DecorationTableBlockEntity.java b/src/main/java/net/p3pp3rf1y/sophisticatedstorage/block/DecorationTableBlockEntity.java new file mode 100644 index 000000000..29eaa587a --- /dev/null +++ b/src/main/java/net/p3pp3rf1y/sophisticatedstorage/block/DecorationTableBlockEntity.java @@ -0,0 +1,569 @@ +package net.p3pp3rf1y.sophisticatedstorage.block; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.Tag; +import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.FastColor; +import net.minecraft.world.item.BlockItem; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.common.Tags; +import net.minecraftforge.items.ItemStackHandler; +import net.p3pp3rf1y.sophisticatedcore.util.InventoryHelper; +import net.p3pp3rf1y.sophisticatedcore.util.WorldHelper; +import net.p3pp3rf1y.sophisticatedstorage.init.ModBlocks; +import net.p3pp3rf1y.sophisticatedstorage.item.BarrelBlockItem; +import net.p3pp3rf1y.sophisticatedstorage.item.StorageBlockItem; + +import javax.annotation.Nullable; +import java.util.*; + +public class DecorationTableBlockEntity extends BlockEntity { + public static final int TOP_INNER_TRIM_SLOT = 0; + public static final int TOP_TRIM_SLOT = 1; + public static final int SIDE_TRIM_SLOT = 2; + public static final int BOTTOM_TRIM_SLOT = 3; + public static final int TOP_CORE_SLOT = 4; + public static final int SIDE_CORE_SLOT = 5; + public static final int BOTTOM_CORE_SLOT = 6; + public static final int RED_DYE_SLOT = 0; + public static final int GREEN_DYE_SLOT = 1; + public static final int BLUE_DYE_SLOT = 2; + + public static final int BLOCK_TOTAL_PARTS = 24; + private static final int MAIN_COLOR_PARTS = 18; + private static final int ACCENT_COLOR_PARTS = 6; + private static final Map DECORATIVE_SLOT_PARTS_NEEDED = Map.of( + TOP_INNER_TRIM_SLOT, 1, + TOP_TRIM_SLOT, 1, + SIDE_TRIM_SLOT, 4, + BOTTOM_TRIM_SLOT, 1, + TOP_CORE_SLOT, 3, + SIDE_CORE_SLOT, 12, + BOTTOM_CORE_SLOT, 3 + ); + + private static final Set STORAGES_WIHOUT_TOP_INNER_TRIM = Set.of(ModBlocks.BARREL_ITEM.get(), ModBlocks.COPPER_BARREL_ITEM.get(), ModBlocks.IRON_BARREL_ITEM.get(), ModBlocks.GOLD_BARREL_ITEM.get(), ModBlocks.DIAMOND_BARREL_ITEM.get(), ModBlocks.NETHERITE_BARREL_ITEM.get(), + ModBlocks.LIMITED_BARREL_1_ITEM.get(), ModBlocks.LIMITED_COPPER_BARREL_1_ITEM.get(), ModBlocks.LIMITED_IRON_BARREL_1_ITEM.get(), ModBlocks.LIMITED_GOLD_BARREL_1_ITEM.get(), ModBlocks.LIMITED_DIAMOND_BARREL_1_ITEM.get(), ModBlocks.LIMITED_NETHERITE_BARREL_1_ITEM.get()); + + private final Map remainingParts = new HashMap<>(); + + private final ItemStackHandler decorativeBlocks = new ItemStackHandler(7) { + @Override + protected void onContentsChanged(int slot) { + super.onContentsChanged(slot); + updateResultAndSetChanged(); + } + + @Override + public boolean isItemValid(int slot, ItemStack stack) { + return stack.getItem() instanceof BlockItem && !(stack.getItem() instanceof StorageBlockItem); + } + }; + + private final ItemStackHandler dyes = new ItemStackHandler(3) { + @Override + protected void onContentsChanged(int slot) { + super.onContentsChanged(slot); + updateResultAndSetChanged(); + } + + @Override + public boolean isItemValid(int slot, ItemStack stack) { + return switch (slot) { + case RED_DYE_SLOT -> stack.is(Tags.Items.DYES_RED); + case GREEN_DYE_SLOT -> stack.is(Tags.Items.DYES_GREEN); + case BLUE_DYE_SLOT -> stack.is(Tags.Items.DYES_BLUE); + default -> false; + }; + } + }; + + public void updateResultAndSetChanged() { + updateResult(); + setChanged(); + } + + private final ItemStackHandler storageBlock = new ItemStackHandler(1) { + @Override + protected void onContentsChanged(int slot) { + super.onContentsChanged(slot); + updateResultAndSetChanged(); + } + + @Override + public boolean isItemValid(int slot, ItemStack stack) { + return stack.getItem() instanceof StorageBlockItem; + } + }; + + private ItemStack result = ItemStack.EMPTY; + + private final Map slotMaterialInheritance = new HashMap<>(); + private int accentColor = -1; + private int mainColor = -1; + + private final Set missingDyes = new HashSet<>(); + + private void updateResult() { + missingDyes.clear(); + + ItemStack storage = storageBlock.getStackInSlot(0); + if (storage.isEmpty() || ( + (InventoryHelper.isEmpty(decorativeBlocks) + || !(storage.getItem() instanceof BarrelBlockItem) + || isTintedStorage(storage) + ) && colorsTransparentOrSameAs(storage))) { //TODO once dyes and materials can be combined make sure to create combined result here + result = ItemStack.EMPTY; + return; + } + if (!(storage.getItem() instanceof BarrelBlockItem) || InventoryHelper.isEmpty(decorativeBlocks) || isTintedStorage(storage)) { + result = storage.copy(); + result.setCount(1); + + if (result.getItem() instanceof BlockItem blockItem && blockItem instanceof ITintableBlockItem tintableBlockItem) { + if (mainColor != -1) { + tintableBlockItem.setMainColor(result, mainColor & 0x00FFFFFF); + } + if (accentColor != -1) { + tintableBlockItem.setAccentColor(result, accentColor & 0x00FFFFFF); + } + } + calculateMissingDyes(storage); + return; + } + + //TODO remove the check for tinted barrel here once barrel model can support combination of tinted and material + if (InventoryHelper.isEmpty(decorativeBlocks)) { + result = ItemStack.EMPTY; + return; + } + + Map materials = new EnumMap<>(BarrelMaterial.class); + materials.putAll(BarrelBlockItem.getMaterials(storage)); + BarrelBlockItem.uncompactMaterials(materials); + + setMaterialsFromDecorativeBlocks(materials, !STORAGES_WIHOUT_TOP_INNER_TRIM.contains(storage.getItem())); + BarrelBlockItem.compactMaterials(materials); + + if (allMaterialsMatch(materials, BarrelBlockItem.getMaterials(storage))) { + result = ItemStack.EMPTY; + return; + } + + //TODO if dyed and any of the parts doesn't have material make sure that dye shows + result = storage.copy(); + result.setCount(1); + + BarrelBlockItem.removeCoveredTints(result, materials); + BarrelBlockItem.setMaterials(result, materials); + } + + private boolean isTintedStorage(ItemStack storage) { + return StorageBlockItem.getMainColorFromStack(storage).isPresent() || StorageBlockItem.getAccentColorFromStack(storage).isPresent(); + } + + private boolean allMaterialsMatch(Map newMaterials, Map currentMaterials) { + if (newMaterials.size() != currentMaterials.size()) { + return false; + } + + for (Map.Entry entry : newMaterials.entrySet()) { + if (!entry.getValue().equals(currentMaterials.get(entry.getKey()))) { + return false; + } + } + + return true; + } + + private void calculateMissingDyes(ItemStack storage) { + if (!dyes.getStackInSlot(RED_DYE_SLOT).isEmpty() && !dyes.getStackInSlot(GREEN_DYE_SLOT).isEmpty() && !dyes.getStackInSlot(BLUE_DYE_SLOT).isEmpty()) { + return; + } + + Map partsNeeded = new HashMap<>(); + addDyePartsNeeded(storage, partsNeeded); + + for (Map.Entry entry : partsNeeded.entrySet()) { + if (entry.getKey().equals(Tags.Items.DYES_RED.location()) && dyes.getStackInSlot(RED_DYE_SLOT).isEmpty()) { + missingDyes.add(entry.getKey()); + } else if (entry.getKey().equals(Tags.Items.DYES_GREEN.location()) && dyes.getStackInSlot(GREEN_DYE_SLOT).isEmpty()) { + missingDyes.add(entry.getKey()); + } else if (entry.getKey().equals(Tags.Items.DYES_BLUE.location()) && dyes.getStackInSlot(BLUE_DYE_SLOT).isEmpty()) { + missingDyes.add(entry.getKey()); + } + } + } + + public Set getMissingDyes() { + return missingDyes; + } + + private boolean colorsTransparentOrSameAs(ItemStack storage) { + return (mainColor == -1 || mainColor == StorageBlockItem.getMainColorFromStack(storage).orElse(-1)) && (accentColor == -1 || accentColor == StorageBlockItem.getAccentColorFromStack(storage).orElse(-1)); + } + + private void setMaterialsFromDecorativeBlocks(Map materials, boolean supportsInnerTrim) { + ResourceLocation topInnerTrimMaterialLocation = setMaterialFromBlock(TOP_INNER_TRIM_SLOT, null, materials, BarrelMaterial.TOP_INNER_TRIM, supportsInnerTrim); + ResourceLocation topTrimMaterialLocation = setMaterialFromBlock(TOP_TRIM_SLOT, topInnerTrimMaterialLocation, materials, BarrelMaterial.TOP_TRIM, true); + ResourceLocation sideTrimMaterialLocation = setMaterialFromBlock(SIDE_TRIM_SLOT, topTrimMaterialLocation, materials, BarrelMaterial.SIDE_TRIM, true); + setMaterialFromBlock(BOTTOM_TRIM_SLOT, sideTrimMaterialLocation, materials, BarrelMaterial.BOTTOM_TRIM, true); + ResourceLocation topMaterialLocation = setMaterialFromBlock(TOP_CORE_SLOT, topTrimMaterialLocation, materials, BarrelMaterial.TOP, true); + ResourceLocation sideMaterialLocation = setMaterialFromBlock(SIDE_CORE_SLOT, topMaterialLocation, materials, BarrelMaterial.SIDE, true); + setMaterialFromBlock(BOTTOM_CORE_SLOT, sideMaterialLocation, materials, BarrelMaterial.BOTTOM, true); + } + + @Nullable + private ResourceLocation setMaterialFromBlock(int slotIndex, @Nullable ResourceLocation defaultMaterialLocation, Map materials, BarrelMaterial material, boolean addToMaterials) { + ItemStack decorativeBlock = decorativeBlocks.getStackInSlot(slotIndex); + ResourceLocation materialLocation = getMaterialLocation(decorativeBlock).orElse(isSlotMaterialInherited(slotIndex) ? defaultMaterialLocation : null); + if (materialLocation != null) { + if (addToMaterials) { + materials.put(material, materialLocation); + } + return materialLocation; + } + return null; + } + + private Optional getMaterialLocation(ItemStack stack) { + if (stack.getItem() instanceof BlockItem blockItem) { + return Optional.of(BuiltInRegistries.BLOCK.getKey(blockItem.getBlock())); + } + return Optional.empty(); + } + + public DecorationTableBlockEntity(BlockPos pos, BlockState blockState) { + super(ModBlocks.DECORATION_TABLE_BLOCK_ENTITY_TYPE.get(), pos, blockState); + } + + public ItemStackHandler getDecorativeBlocks() { + return decorativeBlocks; + } + + public ItemStackHandler getDyes() { + return dyes; + } + + public ItemStackHandler getStorageBlock() { + return storageBlock; + } + + public ItemStack getResult() { + return result; + } + + public ItemStack extractResult(int count) { + ItemStack result = getResult(); + if (result.isEmpty()) { + return ItemStack.EMPTY; + } + ItemStack extracted = result.copy(); + extracted.setCount(count); + if (count >= result.getCount()) { + this.result = ItemStack.EMPTY; + } else { + result.shrink(count); + } + setChanged(); + return extracted; + } + + public boolean isSlotMaterialInherited(int slot) { + return slotMaterialInheritance.getOrDefault(slot, true); + } + + public ItemStack getInheritedItem(int childSlot) { + while (isSlotMaterialInherited(childSlot)) { + int parentSlot = getSlotInheritedFrom(childSlot); + if (parentSlot == -1) { + return ItemStack.EMPTY; + } else if (!decorativeBlocks.getStackInSlot(parentSlot).isEmpty()) { + return decorativeBlocks.getStackInSlot(parentSlot); + } + childSlot = parentSlot; + } + return ItemStack.EMPTY; + } + + public int getSlotInheritedFrom(int slot) { + return switch (slot) { + case TOP_TRIM_SLOT -> TOP_INNER_TRIM_SLOT; + case SIDE_TRIM_SLOT -> TOP_TRIM_SLOT; + case BOTTOM_TRIM_SLOT -> SIDE_TRIM_SLOT; + case TOP_CORE_SLOT -> TOP_TRIM_SLOT; + case SIDE_CORE_SLOT -> TOP_CORE_SLOT; + case BOTTOM_CORE_SLOT -> SIDE_CORE_SLOT; + default -> -1; + }; + } + + public void setSlotMaterialInheritance(int slot, boolean value) { + if (value) { + slotMaterialInheritance.remove(slot); + } else { + slotMaterialInheritance.put(slot, false); + } + updateResultAndSetChanged(); + } + + @Nullable + @Override + public ClientboundBlockEntityDataPacket getUpdatePacket() { + return ClientboundBlockEntityDataPacket.create(this); + } + + @Override + public CompoundTag getUpdateTag() { + CompoundTag tag = super.getUpdateTag(); + saveData(tag); + return tag; + } + + @Override + public void load(CompoundTag tag) { + super.load(tag); + decorativeBlocks.deserializeNBT(tag.getCompound("decorativeBlocks")); + dyes.deserializeNBT(tag.getCompound("dyes")); + storageBlock.deserializeNBT(tag.getCompound("storageBlock")); + result = tag.contains("result") ? ItemStack.of(tag.getCompound("result")) : ItemStack.EMPTY; + slotMaterialInheritance.clear(); + ListTag inheritance = tag.getList("slotMaterialInheritance", Tag.TAG_COMPOUND); + for (int i = 0; i < inheritance.size(); i++) { + CompoundTag slotTag = inheritance.getCompound(i); + slotMaterialInheritance.put(slotTag.getInt("slot"), slotTag.getBoolean("value")); + } + remainingParts.clear(); + ListTag remainingPartsTag = tag.getList("remainingParts", Tag.TAG_COMPOUND); + for (int i = 0; i < remainingPartsTag.size(); i++) { + CompoundTag partTag = remainingPartsTag.getCompound(i); + ResourceLocation key = ResourceLocation.tryParse(partTag.getString("key")); + if (key == null) { + continue; + } + remainingParts.put(key, partTag.getInt("value")); + } + + mainColor = tag.getInt("mainColor"); + accentColor = tag.getInt("accentColor"); + } + + @Override + protected void saveAdditional(CompoundTag tag) { + super.saveAdditional(tag); + saveData(tag); + } + + private void saveData(CompoundTag tag) { + tag.put("decorativeBlocks", decorativeBlocks.serializeNBT()); + tag.put("dyes", dyes.serializeNBT()); + tag.put("storageBlock", storageBlock.serializeNBT()); + if (!result.isEmpty()) { + tag.put("result", result.save(new CompoundTag())); + } + ListTag inheritance = new ListTag(); + slotMaterialInheritance.forEach((slot, value) -> { + CompoundTag slotTag = new CompoundTag(); + slotTag.putInt("slot", slot); + slotTag.putBoolean("value", value); + inheritance.add(slotTag); + }); + tag.put("slotMaterialInheritance", inheritance); + ListTag remainingPartsTag = new ListTag(); + remainingParts.forEach((key, value) -> { + CompoundTag partTag = new CompoundTag(); + partTag.putString("key", key.toString()); + partTag.putInt("value", value); + remainingPartsTag.add(partTag); + }); + tag.put("remainingParts", remainingPartsTag); + + tag.putInt("mainColor", mainColor); + tag.putInt("accentColor", accentColor); + } + + public void consumeIngredientsOnCraft() { + if (InventoryHelper.isEmpty(decorativeBlocks)) { //TODO once dyes and materials can be combined make sure to consume from both here and change the dye calculation to only count with parts visible + consumeDyes(); + } else { + consumeMaterials(); + } + + setChanged(); + WorldHelper.notifyBlockUpdate(this); + } + + private void consumeDyes() { + ItemStack storageStack = storageBlock.getStackInSlot(0); + Map partsNeeded = new HashMap<>(); + Map firstSlotWithMaterial = new HashMap<>(); + firstSlotWithMaterial.put(Tags.Items.DYES_RED.location(), RED_DYE_SLOT); + firstSlotWithMaterial.put(Tags.Items.DYES_GREEN.location(), GREEN_DYE_SLOT); + firstSlotWithMaterial.put(Tags.Items.DYES_BLUE.location(), BLUE_DYE_SLOT); + + addDyePartsNeeded(storageStack, partsNeeded); + + if (partsNeeded.isEmpty()) { + return; + } + + consumePartsNeeded(partsNeeded, firstSlotWithMaterial, dyes); + } + + private void addDyePartsNeeded(ItemStack storageStack, Map partsNeeded) { + if (mainColor != -1 && mainColor != StorageBlockItem.getMainColorFromStack(storageStack).orElse(-1)) { + int[] rgbPartsNeeded = calculateRGBPartsNeeded(mainColor, MAIN_COLOR_PARTS); + addPartsNeededIfAny(rgbPartsNeeded, partsNeeded); + } + if (accentColor != -1 && accentColor != StorageBlockItem.getAccentColorFromStack(storageStack).orElse(-1)) { + int[] rgbPartsNeeded = calculateRGBPartsNeeded(accentColor, ACCENT_COLOR_PARTS); + addPartsNeededIfAny(rgbPartsNeeded, partsNeeded); + } + } + + private static void addPartsNeededIfAny(int[] rgbPartsNeeded, Map partsNeeded) { + addPartsNeededIfAny(rgbPartsNeeded[0], partsNeeded, Tags.Items.DYES_RED.location()); + addPartsNeededIfAny(rgbPartsNeeded[1], partsNeeded, Tags.Items.DYES_GREEN.location()); + addPartsNeededIfAny(rgbPartsNeeded[2], partsNeeded, Tags.Items.DYES_BLUE.location()); + } + + private static void addPartsNeededIfAny(int parts, Map partsNeeded, ResourceLocation dyeName) { + if (parts != 0) { + partsNeeded.compute(dyeName, (location, partsTotal) -> partsTotal == null ? parts : partsTotal + parts); + } + } + + private int[] calculateRGBPartsNeeded(int color, int totalParts) { + float[] ratios = new float[3]; + ratios[0] = FastColor.ARGB32.red(color) / 255f; + ratios[1] = FastColor.ARGB32.green(color) / 255f; + ratios[2] = FastColor.ARGB32.blue(color) / 255f; + + float totalRaios = ratios[0] + ratios[1] + ratios[2]; + ratios[0] /= totalRaios; + ratios[1] /= totalRaios; + ratios[2] /= totalRaios; + + int n = ratios.length; + int[] result = new int[n]; + double[] remainders = new double[n]; + + double[] scaled = new double[n]; + for (int i = 0; i < n; i++) { + scaled[i] = ratios[i] * totalParts; + result[i] = (int) scaled[i]; + remainders[i] = scaled[i] - result[i]; + } + + int remaining = totalParts - Arrays.stream(result).sum(); + + Integer[] indices = new Integer[n]; + for (int i = 0; i < n; i++) indices[i] = i; + + Arrays.sort(indices, Comparator.comparingDouble(i -> -remainders[i])); + + for (int i = 0; i < remaining; i++) { + result[indices[i % n]]++; + } + + return result; + } + + private void consumeMaterials() { + Map partsNeeded = new HashMap<>(); + Map firstSlotWithMaterial = new HashMap<>(); + addMaterialPartsNeeded(partsNeeded, firstSlotWithMaterial); + consumePartsNeeded(partsNeeded, firstSlotWithMaterial, decorativeBlocks); + } + + private void addMaterialPartsNeeded(Map partsNeeded, Map firstSlotWithMaterial) { + ResourceLocation topInnerTrimMaterialLocation = addMaterialCostForSlotAndGetMaterial(TOP_INNER_TRIM_SLOT, null, partsNeeded, firstSlotWithMaterial); + ResourceLocation topTrimMaterialLocation = addMaterialCostForSlotAndGetMaterial(TOP_TRIM_SLOT, topInnerTrimMaterialLocation, partsNeeded, firstSlotWithMaterial); + ResourceLocation sideTrimMaterialLocation = addMaterialCostForSlotAndGetMaterial(SIDE_TRIM_SLOT, topTrimMaterialLocation, partsNeeded, firstSlotWithMaterial); + addMaterialCostForSlotAndGetMaterial(BOTTOM_TRIM_SLOT, sideTrimMaterialLocation, partsNeeded, firstSlotWithMaterial); + ResourceLocation topMaterialLocation = addMaterialCostForSlotAndGetMaterial(TOP_CORE_SLOT, topTrimMaterialLocation, partsNeeded, firstSlotWithMaterial); + ResourceLocation sideMaterialLocation = addMaterialCostForSlotAndGetMaterial(SIDE_CORE_SLOT, topMaterialLocation, partsNeeded, firstSlotWithMaterial); + addMaterialCostForSlotAndGetMaterial(BOTTOM_CORE_SLOT, sideMaterialLocation, partsNeeded, firstSlotWithMaterial); + } + + public Map getPartsNeeded() { + Map partsNeeded = new HashMap<>(); + ItemStack storageStack = storageBlock.getStackInSlot(0); + if (InventoryHelper.isEmpty(decorativeBlocks) || !(storageStack.getItem() instanceof BarrelBlockItem)) { + addDyePartsNeeded(storageStack, partsNeeded); + } else { + addMaterialPartsNeeded(partsNeeded, new HashMap<>()); + } + + return partsNeeded; + } + + private void consumePartsNeeded(Map partsNeeded, Map firstSlotWithMaterial, ItemStackHandler resources) { + partsNeeded.forEach((material, parts) -> { + int remainingParts = this.remainingParts.getOrDefault(material, 0); + if (remainingParts >= parts) { + if (remainingParts == parts) { + this.remainingParts.remove(material); + } else { + this.remainingParts.put(material, remainingParts - parts); + } + } else { + if (firstSlotWithMaterial.get(material) == null) { + return; + } + int slotWithMaterial = firstSlotWithMaterial.get(material); + ItemStack stack = resources.getStackInSlot(slotWithMaterial); + stack.shrink(1); + resources.setStackInSlot(slotWithMaterial, stack); + this.remainingParts.put(material, remainingParts + BLOCK_TOTAL_PARTS - parts); + } + }); + } + + @Nullable + private ResourceLocation addMaterialCostForSlotAndGetMaterial(int slotIndex, @Nullable ResourceLocation defaultMaterialLocation, Map partsNeeded, Map firstSlotWithMaterial) { + boolean hasNoCost = slotIndex == TOP_TRIM_SLOT && defaultMaterialLocation != null; + + ItemStack decorativeBlock = decorativeBlocks.getStackInSlot(slotIndex); + ResourceLocation materialLocation = getMaterialLocation(decorativeBlock).orElse(isSlotMaterialInherited(slotIndex) ? defaultMaterialLocation : null); + if (hasNoCost) { + return materialLocation; + } + + if (materialLocation != null) { + int parts = DECORATIVE_SLOT_PARTS_NEEDED.get(slotIndex); + partsNeeded.compute(materialLocation, (key, value) -> value == null ? parts : value + parts); + firstSlotWithMaterial.putIfAbsent(materialLocation, slotIndex); + } + return materialLocation; + } + + public int getMainColor() { + return mainColor; + } + + public void setMainColor(int mainColor) { + this.mainColor = mainColor; + updateResultAndSetChanged(); + } + + public int getAccentColor() { + return accentColor; + } + + public void setAccentColor(int accentColor) { + this.accentColor = accentColor; + updateResultAndSetChanged(); + } + + public Map getPartsStored() { + return remainingParts; + } +} diff --git a/src/main/java/net/p3pp3rf1y/sophisticatedstorage/client/ClientEventHandler.java b/src/main/java/net/p3pp3rf1y/sophisticatedstorage/client/ClientEventHandler.java index 2f73fc936..03aa96c76 100644 --- a/src/main/java/net/p3pp3rf1y/sophisticatedstorage/client/ClientEventHandler.java +++ b/src/main/java/net/p3pp3rf1y/sophisticatedstorage/client/ClientEventHandler.java @@ -254,5 +254,6 @@ private static void registerEntityRenderers(EntityRenderersEvent.RegisterRendere event.registerBlockEntityRenderer(ModBlocks.CHEST_BLOCK_ENTITY_TYPE.get(), ChestRenderer::new); event.registerBlockEntityRenderer(ModBlocks.SHULKER_BOX_BLOCK_ENTITY_TYPE.get(), ShulkerBoxRenderer::new); event.registerBlockEntityRenderer(ModBlocks.CONTROLLER_BLOCK_ENTITY_TYPE.get(), context -> new ControllerRenderer()); + event.registerBlockEntityRenderer(ModBlocks.DECORATION_TABLE_BLOCK_ENTITY_TYPE.get(), DecorationTableRenderer::new); } } diff --git a/src/main/java/net/p3pp3rf1y/sophisticatedstorage/client/gui/DecorationTableScreen.java b/src/main/java/net/p3pp3rf1y/sophisticatedstorage/client/gui/DecorationTableScreen.java new file mode 100644 index 000000000..1c165cee0 --- /dev/null +++ b/src/main/java/net/p3pp3rf1y/sophisticatedstorage/client/gui/DecorationTableScreen.java @@ -0,0 +1,565 @@ + +package net.p3pp3rf1y.sophisticatedstorage.client.gui; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.mojang.math.Axis; +import net.minecraft.ChatFormatting; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.components.events.GuiEventListener; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.entity.ItemRenderer; +import net.minecraft.client.renderer.texture.OverlayTexture; +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.core.registries.Registries; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.tags.TagKey; +import net.minecraft.util.Tuple; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.inventory.Slot; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemDisplayContext; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.phys.Vec2; +import net.minecraftforge.client.extensions.common.IClientItemExtensions; +import net.p3pp3rf1y.sophisticatedcore.client.gui.controls.*; +import net.p3pp3rf1y.sophisticatedcore.client.gui.utils.*; +import net.p3pp3rf1y.sophisticatedcore.util.Easing; +import net.p3pp3rf1y.sophisticatedstorage.SophisticatedStorage; +import net.p3pp3rf1y.sophisticatedstorage.block.DecorationTableBlockEntity; +import net.p3pp3rf1y.sophisticatedstorage.common.gui.DecorationTableMenu; +import org.joml.Matrix4f; + +import javax.annotation.Nullable; +import java.util.*; +import java.util.function.Function; +import java.util.function.IntConsumer; +import java.util.function.Supplier; + +public class DecorationTableScreen extends AbstractContainerScreen { + public static final ResourceLocation GUI_BACKGROUND = SophisticatedStorage.getRL("textures/gui/decoration_table.png"); + public static final ResourceLocation GUI_DECORATION_TABLE_ELEMENTS = SophisticatedStorage.getRL("textures/gui/decoration_table_elements.png"); + public static final Dimension SQUARE_64 = new Dimension(64, 64); + public static final Dimension SQUARE_8 = new Dimension(8, 8); + public static final TextureBlitData TOP_INNER_TRIM_HIGHLIGHT = new TextureBlitData(GUI_DECORATION_TABLE_ELEMENTS, SQUARE_64, new UV(0, 0), Dimension.SQUARE_16); + public static final TextureBlitData TOP_TRIM_HIGHLIGHT = new TextureBlitData(GUI_DECORATION_TABLE_ELEMENTS, SQUARE_64, new UV(0, 16), Dimension.SQUARE_16); + public static final TextureBlitData SIDE_TRIM_HIGHLIGHT = new TextureBlitData(GUI_DECORATION_TABLE_ELEMENTS, SQUARE_64, new UV(0, 32), Dimension.SQUARE_16); + public static final TextureBlitData BOTTOM_TRIM_HIGHLIGHT = new TextureBlitData(GUI_DECORATION_TABLE_ELEMENTS, SQUARE_64, new UV(0, 48), Dimension.SQUARE_16); + public static final TextureBlitData TOP_CORE_HIGHLIGHT = new TextureBlitData(GUI_DECORATION_TABLE_ELEMENTS, SQUARE_64, new UV(16, 16), Dimension.SQUARE_16); + public static final TextureBlitData SIDE_CORE_HIGHLIGHT = new TextureBlitData(GUI_DECORATION_TABLE_ELEMENTS, SQUARE_64, new UV(16, 32), Dimension.SQUARE_16); + public static final TextureBlitData BOTTOM_CORE_HIGHLIGHT = new TextureBlitData(GUI_DECORATION_TABLE_ELEMENTS, SQUARE_64, new UV(16, 48), Dimension.SQUARE_16); + public static final TextureBlitData ACCENT_TINT_HIGHLIGHT = new TextureBlitData(GUI_DECORATION_TABLE_ELEMENTS, SQUARE_64, new UV(32, 48), Dimension.SQUARE_16); + public static final TextureBlitData MAIN_TINT_HIGHLIGHT = new TextureBlitData(GUI_DECORATION_TABLE_ELEMENTS, SQUARE_64, new UV(48, 48), Dimension.SQUARE_16); + public static final TextureBlitData STORAGE_INFO = new TextureBlitData(GUI_DECORATION_TABLE_ELEMENTS, SQUARE_64, new UV(32, 16), Dimension.SQUARE_16); + + private static final TextureBlitData VERTICAL_ARROW_BACKGROUND = new TextureBlitData(GUI_DECORATION_TABLE_ELEMENTS, SQUARE_64, new UV(56, 0), SQUARE_8); + private static final TextureBlitData VERTICAL_ARROW_HOVERED_BACKGROUND = new TextureBlitData(GUI_DECORATION_TABLE_ELEMENTS, SQUARE_64, new UV(48, 0), SQUARE_8); + private static final TextureBlitData HORIZONTAL_ARROW_BACKGROUND = new TextureBlitData(GUI_DECORATION_TABLE_ELEMENTS, SQUARE_64, new UV(56, 8), SQUARE_8); + private static final TextureBlitData HORIZONTAL_ARROW_HOVERED_BACKGROUND = new TextureBlitData(GUI_DECORATION_TABLE_ELEMENTS, SQUARE_64, new UV(48, 8), SQUARE_8); + + private static final ButtonDefinition.Toggle VERTICAL_INHERITANCE_ARROW = new ButtonDefinition.Toggle<>(SQUARE_8, VERTICAL_ARROW_BACKGROUND, Map.of( + true, new ToggleButton.StateData(new TextureBlitData(GUI_DECORATION_TABLE_ELEMENTS, SQUARE_64, new UV(32, 0), SQUARE_8), + Component.translatable(StorageTranslationHelper.INSTANCE.translButton("decoration_inheritance_on"))), + false, new ToggleButton.StateData(new TextureBlitData(GUI_DECORATION_TABLE_ELEMENTS, SQUARE_64, new UV(40, 0), SQUARE_8), + Component.translatable(StorageTranslationHelper.INSTANCE.translButton("decoration_inheritance_off"))) + ), VERTICAL_ARROW_HOVERED_BACKGROUND); + + private static final ButtonDefinition.Toggle HORIZONTAL_INHERITANCE_ARROW = new ButtonDefinition.Toggle<>(SQUARE_8, HORIZONTAL_ARROW_BACKGROUND, Map.of( + true, new ToggleButton.StateData(new TextureBlitData(GUI_DECORATION_TABLE_ELEMENTS, SQUARE_64, new UV(32, 8), SQUARE_8), + Component.translatable(StorageTranslationHelper.INSTANCE.translButton("decoration_inheritance_on"))), + false, new ToggleButton.StateData(new TextureBlitData(GUI_DECORATION_TABLE_ELEMENTS, SQUARE_64, new UV(40, 8), SQUARE_8), + Component.translatable(StorageTranslationHelper.INSTANCE.translButton("decoration_inheritance_off"))) + ), HORIZONTAL_ARROW_HOVERED_BACKGROUND); + + private BlockPreviewWidget blockPreview; + private long lastRotationSetTime = 0; + + @Nullable + private ColorPicker colorPicker; + + private final List resultPartsNeededTooltip = new ArrayList<>(); + + public DecorationTableScreen(DecorationTableMenu menu, Inventory playerInventory, Component title) { + super(menu, playerInventory, title); + imageWidth = 250; + imageHeight = 226; + inventoryLabelX = 45; + } + + @Override + protected void init() { + super.init(); + inventoryLabelY = getMenu().getSlot(DecorationTableBlockEntity.BOTTOM_TRIM_SLOT).y + 18 + 2; + int lastDyeSlotIndex = getMenu().getDyeSlotRange().firstSlot() + getMenu().getDyeSlotRange().numberOfSlots() - 1; + Slot lastDyeSlot = getMenu().getSlot(lastDyeSlotIndex); + Slot resultSlot = menu.getResultSlot(); + blockPreview = new BlockPreviewWidget(new Position(leftPos + lastDyeSlot.x + 16 + 1 + 8 + 1, topPos + lastDyeSlot.y), new Dimension(80, resultSlot.y - lastDyeSlot.y + 16 + 4), () -> menu.getSlot(11).getItem()); + + addRenderableWidget(blockPreview); + addVerticalInheritanceArrow(DecorationTableBlockEntity.TOP_TRIM_SLOT); + addVerticalInheritanceArrow(DecorationTableBlockEntity.SIDE_TRIM_SLOT); + addVerticalInheritanceArrow(DecorationTableBlockEntity.BOTTOM_TRIM_SLOT); + + int slotIndex = DecorationTableBlockEntity.TOP_CORE_SLOT; + addInheritanceArrow(slotIndex, -11, 4, HORIZONTAL_INHERITANCE_ARROW); + + addVerticalInheritanceArrow(DecorationTableBlockEntity.SIDE_CORE_SLOT); + addVerticalInheritanceArrow(DecorationTableBlockEntity.BOTTOM_CORE_SLOT); + + addPartHint(DecorationTableBlockEntity.TOP_INNER_TRIM_SLOT, TOP_INNER_TRIM_HIGHLIGHT, "top_inner_trim"); + addPartHint(DecorationTableBlockEntity.TOP_TRIM_SLOT, TOP_TRIM_HIGHLIGHT, "top_trim"); + addPartHint(DecorationTableBlockEntity.SIDE_TRIM_SLOT, SIDE_TRIM_HIGHLIGHT, "side_trim"); + addPartHint(DecorationTableBlockEntity.BOTTOM_TRIM_SLOT, BOTTOM_TRIM_HIGHLIGHT, "bottom_trim"); + addPartHint(DecorationTableBlockEntity.TOP_CORE_SLOT, TOP_CORE_HIGHLIGHT, "top_core"); + addPartHint(DecorationTableBlockEntity.SIDE_CORE_SLOT, SIDE_CORE_HIGHLIGHT, "side_core"); + addPartHint(DecorationTableBlockEntity.BOTTOM_CORE_SLOT, BOTTOM_CORE_HIGHLIGHT, "bottom_core"); + + Slot slot = menu.getSlot(DecorationTableBlockEntity.TOP_INNER_TRIM_SLOT); + addRenderableWidget(new PartStorageInfo(new Position(leftPos + slot.x + 57, topPos + slot.y), menu::getPartsStored)); + + addDyeElements(); + + if (colorPicker != null) { + colorPicker.setPosition(new Position(leftPos + (imageWidth - ColorPicker.DIMENSIONS.width()) / 2, topPos + (imageHeight - ColorPicker.DIMENSIONS.height()) / 2)); + } + } + + private void addDyeElements() { + Slot greenDyeSlot = menu.getSlot(menu.getDyeSlotRange().firstSlot() + 1); + Slot topTrimSlot = menu.getSlot(DecorationTableBlockEntity.TOP_TRIM_SLOT); + Slot sideTrimSlot = menu.getSlot(DecorationTableBlockEntity.SIDE_TRIM_SLOT); + + ColorButton mainColorButton = new ColorButton(new Position(leftPos + greenDyeSlot.x - 1, topPos + topTrimSlot.y), new Dimension(18, 18), menu::getMainColor, + button -> openColorPicker(menu.getMainColor(), menu::setMainColor), Component.translatable(StorageTranslationHelper.INSTANCE.translButton("pick_color"))); + addRenderableWidget(mainColorButton); + ColorButton accentColorButton = new ColorButton(new Position(leftPos + greenDyeSlot.x - 1, topPos + sideTrimSlot.y), new Dimension(18, 18), menu::getAccentColor, + button -> openColorPicker(menu.getAccentColor(), menu::setAccentColor), Component.translatable(StorageTranslationHelper.INSTANCE.translButton("pick_color"))); + addRenderableWidget(accentColorButton); + + addRenderableWidget(new PartIcon(new Position(mainColorButton.getX() + mainColorButton.getWidth() + 1, mainColorButton.getY() + 1), MAIN_TINT_HIGHLIGHT, Component.translatable(StorageTranslationHelper.INSTANCE.translGui("tint.main")))); + addRenderableWidget(new PartIcon(new Position(accentColorButton.getX() + accentColorButton.getWidth() + 1, accentColorButton.getY() + 1), ACCENT_TINT_HIGHLIGHT, Component.translatable(StorageTranslationHelper.INSTANCE.translGui("tint.accent")))); + } + + private void openColorPicker(int color, IntConsumer colorSetter) { + colorPicker = new ColorPicker(this, new Position(leftPos + (imageWidth - ColorPicker.DIMENSIONS.width()) / 2, topPos + (imageHeight - ColorPicker.DIMENSIONS.height()) / 2), + color, c -> { + colorSetter.accept(c); + colorPicker = null; + blockPreview.setVisible(true); + }); + blockPreview.setVisible(false); + } + + private void addVerticalInheritanceArrow(int slotIndex) { + addInheritanceArrow(slotIndex, 4, -11, VERTICAL_INHERITANCE_ARROW); + } + + private void addInheritanceArrow(int slotIndex, int xOffset, int yOffset, ButtonDefinition.Toggle arrowDefinition) { + Slot slot = menu.getSlot(slotIndex); + addRenderableWidget(new ToggleButton<>(new Position(leftPos + slot.x + xOffset, topPos + slot.y + yOffset), arrowDefinition, + button -> { + resultPartsNeededTooltip.clear(); + getMenu().setSlotMaterialInheritance(slotIndex, !getMenu().isSlotMaterialInherited(slotIndex)); + }, () -> getMenu().isSlotMaterialInherited(slotIndex)) { + @Override + public void render(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTicks) { + super.render(guiGraphics, mouseX, mouseY, partialTicks); + if (isMouseOver(mouseX, mouseY)) { + Vec2 rotations = SLOT_PREVIEW_ROTATIONS.get(slotIndex); + if (rotations != null) { + setPreviewRotations((int) rotations.x, (int) rotations.y); + } + } + } + }); + } + + @Override + protected void renderBg(GuiGraphics guiGraphics, float v, int i, int i1) { + guiGraphics.blit(GUI_BACKGROUND, leftPos, topPos, 0, 0, this.imageWidth, this.imageHeight); + + renderDyeSlotsOverlays(guiGraphics); + + if (colorPicker != null) { + PoseStack pose = guiGraphics.pose(); + pose.pushPose(); + pose.translate(0, 0, 500); + colorPicker.renderBg(guiGraphics, minecraft, i, i1); + pose.popPose(); + } + } + + private void renderDyeSlotsOverlays(GuiGraphics guiGraphics) { + PoseStack pose = guiGraphics.pose(); + pose.pushPose(); + pose.translate(leftPos, topPos, 0); + Slot redSlot = getMenu().getSlot(getMenu().getDyeSlotRange().firstSlot()); + renderSlotOverlay(guiGraphics, redSlot, 0x33_FF0000); + Slot greenSlot = getMenu().getSlot(getMenu().getDyeSlotRange().firstSlot() + 1); + renderSlotOverlay(guiGraphics, greenSlot, 0x33_00FF00); + Slot blueSlot = getMenu().getSlot(getMenu().getDyeSlotRange().firstSlot() + 2); + renderSlotOverlay(guiGraphics, blueSlot, 0x33_0000FF); + pose.popPose(); + } + + private void renderSlotOverlay(GuiGraphics guiGraphics, Slot slot, int slotColor) { + RenderSystem.enableBlend(); + RenderSystem.disableDepthTest(); + RenderSystem.colorMask(true, true, true, false); + guiGraphics.fill(slot.x, slot.y, slot.x + 16, slot.y + 16, 0, slotColor); + RenderSystem.colorMask(true, true, true, true); + RenderSystem.enableDepthTest(); + RenderSystem.disableBlend(); + } + + private void addPartHint(int slotIndex, TextureBlitData texture, String barrelPart) { + Slot slot = menu.getSlot(slotIndex); + addRenderableWidget(new PartIcon(new Position(leftPos + slot.x + 18, topPos + slot.y), texture, Component.translatable(StorageTranslationHelper.INSTANCE.translGui("barrel_part." + barrelPart)))); + } + + @Override + public void render(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTick) { + renderBackground(guiGraphics); + updatePreviewRotation(mouseX, mouseY); + super.render(guiGraphics, mouseX, mouseY, partialTick); + + if (colorPicker != null) { + renderBackground(guiGraphics); + RenderSystem.disableBlend(); + PoseStack pose = guiGraphics.pose(); + pose.pushPose(); + pose.translate(0, 0, 500); + colorPicker.render(guiGraphics, mouseX, mouseY, partialTick); + colorPicker.renderTooltip(this, guiGraphics, mouseX, mouseY); + pose.popPose(); + } else { + this.renderTooltip(guiGraphics, mouseX, mouseY); + } + } + + @Override + protected void renderSlot(GuiGraphics guiGraphics, Slot slot) { + if (colorPicker != null) { + return; + } + + if (slot.getItem().isEmpty() && getMenu().isSlotMaterialInherited(slot.index)) { + ItemStack inheritedItem = getMenu().getInheritedItem(slot.index); + if (!inheritedItem.isEmpty()) { + guiGraphics.renderItem(inheritedItem, slot.x, slot.y, slot.x + slot.y * this.imageWidth); + PoseStack pose = guiGraphics.pose(); + pose.pushPose(); + RenderSystem.enableBlend(); + RenderSystem.disableDepthTest(); + guiGraphics.blit(GuiHelper.GUI_CONTROLS, slot.x, slot.y, 77, 0, 16, 16); + RenderSystem.enableDepthTest(); + RenderSystem.disableBlend(); + pose.popPose(); + } + } + super.renderSlot(guiGraphics, slot); + } + + @Override + protected List getTooltipFromContainerItem(ItemStack stack) { + List tooltip = super.getTooltipFromContainerItem(stack); + if (hoveredSlot == getMenu().getResultSlot() && !hoveredSlot.getItem().isEmpty()) { + Map partsNeeded = getMenu().getPartsNeeded(); + tooltip.addAll(getResultPartsNeededTooltip(partsNeeded)); + } else if (!resultPartsNeededTooltip.isEmpty()) { + resultPartsNeededTooltip.clear(); + } + + return tooltip; + } + + private List getResultPartsNeededTooltip(Map partsNeeded) { + if (!resultPartsNeededTooltip.isEmpty()) { + return resultPartsNeededTooltip; + } + addPartCountInfo(partsNeeded, resultPartsNeededTooltip, location -> getMenu().getMissingDyes().contains(location) ? ChatFormatting.RED : ChatFormatting.DARK_GRAY); + return resultPartsNeededTooltip; + } + + private static void addPartCountInfo(Map partCounts, List tooltip, Function getPartFormatting) { + Map> itemCounts = new LinkedHashMap<>(); + partCounts.forEach((part, count) -> { + if (BuiltInRegistries.ITEM.containsKey(part)) { + Item item = BuiltInRegistries.ITEM.get(part); + itemCounts.put(new ItemStack(item), new Tuple<>(part, count)); + } else { + BuiltInRegistries.ITEM.getTag(TagKey.create(Registries.ITEM, part)) + .flatMap(set -> set.stream().findFirst()).ifPresent(dye -> itemCounts.put(new ItemStack(dye), new Tuple<>(part, count))); + } + }); + + itemCounts.entrySet().stream().sorted(Comparator.comparing(entry -> entry.getKey().getHoverName().getString())).forEach(entry -> { + ItemStack itemStack = entry.getKey(); + ResourceLocation location = entry.getValue().getA(); + int count = entry.getValue().getB(); + MutableComponent partCountText = Component.literal(count + "/" + DecorationTableBlockEntity.BLOCK_TOTAL_PARTS + " (" + String.format("%.0f%%", (float) count / DecorationTableBlockEntity.BLOCK_TOTAL_PARTS * 100) + ") of "); + tooltip.add(partCountText.append(itemStack.getHoverName()).withStyle(getPartFormatting.apply(location))); + }); + } + + private static final Map SLOT_PREVIEW_ROTATIONS = Map.of( + 0, new Vec2(90, 0), + 1, new Vec2(90, 0), + 4, new Vec2(90, 0), + 2, new Vec2(0, 0), + 5, new Vec2(0, 0), + 3, new Vec2(-90, 0), + 6, new Vec2(-90, 0) + ); + + private void updatePreviewRotation(int mouseX, int mouseY) { + SLOT_PREVIEW_ROTATIONS.forEach( + (slotIndex, rotation) -> updatePreviewRotationForSlot(slotIndex, mouseX, mouseY, (int) rotation.x, (int) rotation.y) + ); + if (lastRotationSetTime != 0 && System.currentTimeMillis() - lastRotationSetTime > 1000) { + blockPreview.setTargetRotations(30, 45); + } + } + + private void updatePreviewRotationForSlot(int slotIndex, int mouseX, int mouseY, int xAxisRotation, int yAxisRotation) { + Slot slot = getMenu().getSlot(slotIndex); + int slotLeft = leftPos + slot.x; + int slotTop = topPos + slot.y; + if (leftPos + slot.x <= mouseX && mouseX < slotLeft + 16 + 18 && slotTop <= mouseY && mouseY < slotTop + 16) { + setPreviewRotations(xAxisRotation, yAxisRotation); + } + } + + private void setPreviewRotations(int xAxisRotation, int yAxisRotation) { + blockPreview.setTargetRotations(xAxisRotation, yAxisRotation); + lastRotationSetTime = System.currentTimeMillis(); + } + + @Override + public boolean mouseDragged(double mouseX, double mouseY, int button, double dragX, double dragY) { + if (colorPicker != null) { + return colorPicker.mouseDragged(mouseX, mouseY, button, dragX, dragY); + } + + for (GuiEventListener child : children()) { + if (child.isMouseOver(mouseX, mouseY) && child.mouseDragged(mouseX, mouseY, button, dragX, dragY)) { + if (child instanceof BlockPreviewWidget) { + lastRotationSetTime = System.currentTimeMillis() + 100_000; + } + + return true; + } + } + return super.mouseDragged(mouseX, mouseY, button, dragX, dragY); + } + + @Override + protected void renderTooltip(GuiGraphics guiGraphics, int x, int y) { + super.renderTooltip(guiGraphics, x, y); + + renderables.forEach(renderable -> { + if (renderable instanceof WidgetBase widget) { + widget.renderTooltip(this, guiGraphics, x, y); + } + }); + } + + @Override + public boolean mouseClicked(double mouseX, double mouseY, int button) { + if (colorPicker != null) { + return colorPicker.mouseClicked(mouseX, mouseY, button); + } + GuiEventListener focused = getFocused(); + if (focused != null && !focused.isMouseOver(mouseX, mouseY) && (focused instanceof WidgetBase widgetBase)) { + widgetBase.setFocused(false); + } + + return super.mouseClicked(mouseX, mouseY, button); + } + + @Override + public boolean keyPressed(int keyCode, int scanCode, int modifiers) { + return super.keyPressed(keyCode, scanCode, modifiers); + } + + private static class PartIcon extends WidgetBase { + private final TextureBlitData texture; + private final Component tooltip; + + protected PartIcon(Position position, TextureBlitData texture, Component tooltip) { + super(position, new Dimension(texture.getWidth(), texture.getHeight())); + this.texture = texture; + this.tooltip = tooltip; + } + + @Override + protected void renderBg(GuiGraphics guiGraphics, Minecraft minecraft, int mouseX, int mouseY) { + GuiHelper.blit(guiGraphics, x, y, texture); + } + + @Override + protected void renderWidget(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTicks) { + //noop + } + + @Override + public void renderTooltip(Screen screen, GuiGraphics guiGraphics, int mouseX, int mouseY) { + if (isMouseOver(mouseX, mouseY)) { + guiGraphics.renderTooltip(screen.getMinecraft().font, tooltip, mouseX, mouseY); + } + } + } + + private static class PartStorageInfo extends WidgetBase { + private final List partStorageTooltip = new ArrayList<>(); + private final Supplier> getPartsStored; + + protected PartStorageInfo(Position position, Supplier> getPartsStored) { + super(position, Dimension.SQUARE_16); + this.getPartsStored = getPartsStored; + } + + @Override + protected void renderBg(GuiGraphics guiGraphics, Minecraft minecraft, int mouseX, int mouseY) { + if (hasNoPartsToShow()) { + return; + } + + GuiHelper.blit(guiGraphics, x, y, STORAGE_INFO); + } + + private boolean hasNoPartsToShow() { + return getPartsStored.get().isEmpty(); + } + + @Override + protected void renderWidget(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTicks) { + //noop + } + + @Override + public void renderTooltip(Screen screen, GuiGraphics guiGraphics, int mouseX, int mouseY) { + if (hasNoPartsToShow()) { + return; + } + + if (isMouseOver(mouseX, mouseY)) { + guiGraphics.renderTooltip(screen.getMinecraft().font, getPartStorageTooltip(), Optional.empty(), mouseX, mouseY); + } else if (!partStorageTooltip.isEmpty()) { + partStorageTooltip.clear(); + } + } + + private List getPartStorageTooltip() { + if (!partStorageTooltip.isEmpty() || hasNoPartsToShow()) { + return partStorageTooltip; + } + + partStorageTooltip.add(Component.translatable(StorageTranslationHelper.INSTANCE.translGuiTooltip("parts_stored"))); + DecorationTableScreen.addPartCountInfo(getPartsStored.get(), partStorageTooltip, location -> ChatFormatting.GRAY); + return partStorageTooltip; + } + } + + private static class BlockPreviewWidget extends WidgetBase { + private final Supplier blockStackSupplier; + private float xAxisRotation = 30; + private float yAxisRotation = 45; + + private float fromXAxisRotation = xAxisRotation; + private float fromYAxisRotation = yAxisRotation; + private float targetXAxisRotation = xAxisRotation; + private float targetYAxisRotation = yAxisRotation; + private long lastTargetSetTime = 0; + + protected BlockPreviewWidget(Position position, Dimension dimension, Supplier blockStackSupplier) { + super(position, dimension); + this.blockStackSupplier = blockStackSupplier; + } + + public void setTargetRotations(int xAxisRotation, int yAxisRotation) { + if ((this.targetXAxisRotation == xAxisRotation && this.targetYAxisRotation == yAxisRotation)) { + return; + } + + this.fromXAxisRotation = this.xAxisRotation; + this.fromYAxisRotation = this.yAxisRotation; + this.targetXAxisRotation = xAxisRotation; + this.targetYAxisRotation = yAxisRotation; + lastTargetSetTime = System.currentTimeMillis(); + } + + @Override + protected void renderBg(GuiGraphics guiGraphics, Minecraft minecraft, int mouseX, int mouseY) { + guiGraphics.fill(x, y, x + getWidth(), y + getHeight(), 0xFF_000000); + } + + @Override + protected void renderWidget(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTicks) { + ItemStack slotStack = blockStackSupplier.get(); + if (slotStack.isEmpty()) { + return; + } + + updateRotations(); + + PoseStack pose = guiGraphics.pose(); + pose.pushPose(); + pose.translate(x + getWidth() / 2f, y + getHeight() / 2f, 150); + pose.mulPose(Axis.XN.rotationDegrees(xAxisRotation)); + pose.mulPose(Axis.YP.rotationDegrees(yAxisRotation)); + int scale = 48; + pose.mulPoseMatrix((new Matrix4f()).scaling(scale, -scale, scale)); + pose.translate(-0.5, -0.5, -0.5); + ItemRenderer itemRenderer = minecraft.getItemRenderer(); + BakedModel bakedModel = itemRenderer.getModel(slotStack, null, null, 0); + int combinedLight = 0xf000f0; + if (bakedModel.isCustomRenderer()) { + IClientItemExtensions.of(slotStack).getCustomRenderer().renderByItem(slotStack, ItemDisplayContext.GUI, pose, guiGraphics.bufferSource(), combinedLight, OverlayTexture.NO_OVERLAY); + } else { + Iterator renderPasses = bakedModel.getRenderPasses(slotStack, true).iterator(); + renderPasses.forEachRemaining(model -> { + Iterator renderTypes = model.getRenderTypes(slotStack, true).iterator(); + renderTypes.forEachRemaining(renderType -> { + VertexConsumer vertexconsumer = ItemRenderer.getFoilBufferDirect(guiGraphics.bufferSource(), renderType, true, slotStack.hasFoil()); + itemRenderer.renderModelLists(model, slotStack, combinedLight, OverlayTexture.NO_OVERLAY, pose, vertexconsumer); + }); + }); + } + guiGraphics.flush(); + pose.popPose(); + } + + private void updateRotations() { + float secondsDuration = 1; + long currentTime = System.currentTimeMillis(); + if (currentTime - lastTargetSetTime <= secondsDuration * 1000) { + float ratio = (currentTime - lastTargetSetTime) / (secondsDuration * 1000); + ratio = Easing.EASE_IN_OUT_CUBIC.ease(ratio); + xAxisRotation = (fromXAxisRotation + (targetXAxisRotation - fromXAxisRotation) * ratio); + yAxisRotation = (fromYAxisRotation + (targetYAxisRotation - fromYAxisRotation) * ratio); + } else { + xAxisRotation = targetXAxisRotation; + yAxisRotation = targetYAxisRotation; + } + } + + @Override + public boolean mouseDragged(double mouseX, double mouseY, int button, double dragX, double dragY) { + yAxisRotation += 2 * dragX; + yAxisRotation = yAxisRotation % 360; + xAxisRotation += 2 * dragY; + xAxisRotation = xAxisRotation % 360; + targetXAxisRotation = xAxisRotation; + targetYAxisRotation = yAxisRotation; + return true; + } + } +} diff --git a/src/main/java/net/p3pp3rf1y/sophisticatedstorage/client/render/BarrelBakedModelBase.java b/src/main/java/net/p3pp3rf1y/sophisticatedstorage/client/render/BarrelBakedModelBase.java index eaf0c7973..69bc6d03a 100644 --- a/src/main/java/net/p3pp3rf1y/sophisticatedstorage/client/render/BarrelBakedModelBase.java +++ b/src/main/java/net/p3pp3rf1y/sophisticatedstorage/client/render/BarrelBakedModelBase.java @@ -211,7 +211,7 @@ public List getQuads(@Nullable BlockState state, @Nullable Direction List ret = new ArrayList<>(); - boolean isBakedDynamically = !materials.isEmpty() && woodDynamicBakingData.containsKey(woodName); + boolean isBakedDynamically = !materials.isEmpty(); Set materialModelParts = materials.keySet().stream().map(BarrelMaterial::getMaterialModelPart).collect(Collectors.toSet()); boolean rendersUsingSplitModel = materialModelParts.contains(BarrelMaterial.MaterialModelPart.CORE) || materialModelParts.contains(BarrelMaterial.MaterialModelPart.TRIM); @@ -287,7 +287,7 @@ private static Direction getSpriteSide(@Nullable BlockState state, @Nullable Dir private List bakeAndAddDynamicQuads(@Nullable Direction spriteSide, RandomSource rand, @Nullable String woodName, Map barrelMaterials, boolean rendersUsingSplitModel, boolean renderCore, boolean renderTrim) { - Map bakingData = woodDynamicBakingData.get(woodName); + Map bakingData = woodDynamicBakingData.get(woodName != null ? woodName : WoodType.ACACIA.name()); Map> materials = new HashMap<>(); for (Map.Entry entry : barrelMaterials.entrySet()) { @@ -770,14 +770,14 @@ public BakedModel resolve(BakedModel model, ItemStack stack, @Nullable ClientLev boolean hasMainColor = StorageBlockItem.getMainColorFromStack(stack).isPresent(); boolean hasAccentColor = StorageBlockItem.getAccentColorFromStack(stack).isPresent(); + Map materials = BarrelBlockItem.getMaterials(stack); String woodName = WoodStorageBlockItem.getWoodType(stack).map(WoodType::name) - .orElse(barrelBakedModel.barrelHasAccentColor && barrelBakedModel.barrelHasMainColor ? null : WoodType.ACACIA.name()); + .orElse(barrelBakedModel.barrelHasAccentColor && barrelBakedModel.barrelHasMainColor && materials.isEmpty() ? null : WoodType.ACACIA.name()); //TODO possibly remove materials check from here if a separate dynamic model is going to be used for materials boolean packed = WoodStorageBlockItem.isPacked(stack); boolean barrelShowsTier = StorageBlockItem.showsTier(stack); Item item = stack.getItem(); - Map materials = BarrelBlockItem.getMaterials(stack); - int hash = Objects.hash(item, woodName, hasMainColor, hasAccentColor, packed, barrelShowsTier, materials); + int hash = Objects.hash(item, woodName, hasMainColor, hasAccentColor, packed, barrelShowsTier, flatTop, materials); BakedModel resolvedModel = resolvedModels.getIfPresent(hash); if (resolvedModel == null) { diff --git a/src/main/java/net/p3pp3rf1y/sophisticatedstorage/client/render/DecorationTableRenderer.java b/src/main/java/net/p3pp3rf1y/sophisticatedstorage/client/render/DecorationTableRenderer.java new file mode 100644 index 000000000..d314cfbcb --- /dev/null +++ b/src/main/java/net/p3pp3rf1y/sophisticatedstorage/client/render/DecorationTableRenderer.java @@ -0,0 +1,36 @@ +package net.p3pp3rf1y.sophisticatedstorage.client.render; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.math.Axis; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.blockentity.BlockEntityRenderer; +import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; +import net.minecraft.client.renderer.entity.ItemRenderer; +import net.minecraft.world.item.ItemDisplayContext; +import net.p3pp3rf1y.sophisticatedstorage.block.DecorationTableBlock; +import net.p3pp3rf1y.sophisticatedstorage.block.DecorationTableBlockEntity; + +public class DecorationTableRenderer implements BlockEntityRenderer { + private final ItemRenderer itemRenderer; + + public DecorationTableRenderer(BlockEntityRendererProvider.Context context) { + itemRenderer = context.getItemRenderer(); + } + + @Override + public void render(DecorationTableBlockEntity table, float v, PoseStack poseStack, MultiBufferSource bufferSource, int packedLight, int packedOverlay) { + if (table.getResult().isEmpty()) { + return; + } + + poseStack.pushPose(); + poseStack.translate(0.5, 1.125, 0.5); + poseStack.mulPose(table.getBlockState().getValue(DecorationTableBlock.FACING).getOpposite().getRotation()); + poseStack.mulPose(Axis.XN.rotationDegrees(90)); + poseStack.translate(0, 0, -0.1); + poseStack.scale(0.5f, 0.5f, 0.5f); + itemRenderer.renderStatic(table.getResult(), ItemDisplayContext.FIXED, packedLight, packedOverlay, poseStack, bufferSource, table.getLevel(), 0); + + poseStack.popPose(); + } +} diff --git a/src/main/java/net/p3pp3rf1y/sophisticatedstorage/common/gui/DecorationTableMenu.java b/src/main/java/net/p3pp3rf1y/sophisticatedstorage/common/gui/DecorationTableMenu.java new file mode 100644 index 000000000..15280e9d9 --- /dev/null +++ b/src/main/java/net/p3pp3rf1y/sophisticatedstorage/common/gui/DecorationTableMenu.java @@ -0,0 +1,294 @@ +package net.p3pp3rf1y.sophisticatedstorage.common.gui; + +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.SimpleContainer; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.AbstractContainerMenu; +import net.minecraft.world.inventory.InventoryMenu; +import net.minecraft.world.inventory.Slot; +import net.minecraft.world.item.ItemStack; +import net.minecraftforge.items.ItemStackHandler; +import net.minecraftforge.items.SlotItemHandler; +import net.p3pp3rf1y.sophisticatedcore.common.gui.ISyncedContainer; +import net.p3pp3rf1y.sophisticatedcore.network.PacketHandler; +import net.p3pp3rf1y.sophisticatedcore.network.SyncContainerClientDataMessage; +import net.p3pp3rf1y.sophisticatedcore.util.SlotRange; +import net.p3pp3rf1y.sophisticatedstorage.SophisticatedStorage; +import net.p3pp3rf1y.sophisticatedstorage.block.DecorationTableBlockEntity; +import net.p3pp3rf1y.sophisticatedstorage.init.ModBlocks; + +import java.util.Map; +import java.util.Set; +import java.util.function.Consumer; + +public class DecorationTableMenu extends AbstractContainerMenu implements ISyncedContainer { + private static final String SET_INHERITANCE_ACTION = "setInheritance"; + private static final ResourceLocation EMPTY_RED_DYE_SLOT_BACKGROUND = SophisticatedStorage.getRL("item/empty_red_dye_slot"); + private static final ResourceLocation EMPTY_GREEN_DYE_SLOT_BACKGROUND = SophisticatedStorage.getRL("item/empty_green_dye_slot"); + private static final ResourceLocation EMPTY_BLUE_DYE_SLOT_BACKGROUND = SophisticatedStorage.getRL("item/empty_blue_dye_slot"); + private static final ResourceLocation EMPTY_MATERIAL_SLOT_BACKGROUND = SophisticatedStorage.getRL("item/empty_material_slot"); + public static final int DECORATION_SLOT_PADDING = 12; + private final DecorationTableBlockEntity blockEntity; + + private Slot resultSlot; + + private SlotRange decorationSlotRange; + private SlotRange dyeSlotRange; + private SlotRange storageSlotRange; + private SlotRange playerSlotRange; + + public DecorationTableMenu(int containerId, Player player, BlockPos pos) { + super(ModBlocks.DECORATION_TABLE_CONTAINER_TYPE.get(), containerId); + blockEntity = player.level().getBlockEntity(pos, ModBlocks.DECORATION_TABLE_BLOCK_ENTITY_TYPE.get()).orElse(null); + if (blockEntity == null) { + throw new IllegalStateException("No block entity found at position " + pos); + } + + int y = addDecorationSlots(); + addStorageSlots(); + y += 14; + addPlayerSlots(player.getInventory(), y); + } + + private void addStorageSlots() { + ItemStackHandler storageBlock = blockEntity.getStorageBlock(); + SlotItemHandler storageSlot = new SlotItemHandler(storageBlock, 0, getSlot(dyeSlotRange.firstSlot()).x, getSlot(DecorationTableBlockEntity.BOTTOM_TRIM_SLOT).y); + addSlot(storageSlot); + + storageSlotRange = new SlotRange(dyeSlotRange.firstSlot() + dyeSlotRange.numberOfSlots(), 1); + + resultSlot = new Slot(new SimpleContainer(1) { + @Override + public ItemStack getItem(int index) { + return blockEntity.getResult(); + } + + @Override + public ItemStack removeItem(int index, int count) { + return index == 0 ? blockEntity.extractResult(count) : ItemStack.EMPTY; + } + }, 0, storageSlot.x + 18 + 18, storageSlot.y) { + @Override + public boolean mayPlace(ItemStack stack) { + return false; + } + + @Override + public boolean mayPickup(Player player) { + return super.mayPickup(player) && getMissingDyes().isEmpty(); + } + + @Override + public ItemStack remove(int amount) { + return super.remove(amount); + } + + @Override + public void onTake(Player player, ItemStack stack) { + super.onTake(player, stack); + if (player.level().isClientSide()) { + return; + } + blockEntity.consumeIngredientsOnCraft(); + blockEntity.getStorageBlock().extractItem(0, 1, false); + } + }; + addSlot(resultSlot); + } + + private int addDecorationSlots() { + int xOffset = 8; + int yOffset = 17; + ItemStackHandler decorativeBlocks = blockEntity.getDecorativeBlocks(); + int x = xOffset; + int y = yOffset; + int slotIndex = 0; + y = addDecorationSlot(decorativeBlocks, slotIndex, x, y, DECORATION_SLOT_PADDING); + y = addDecorationSlot(decorativeBlocks, 1, x, y, DECORATION_SLOT_PADDING); + y = addDecorationSlot(decorativeBlocks, 2, x, y, DECORATION_SLOT_PADDING); + addDecorationSlot(decorativeBlocks, 3, x, y, DECORATION_SLOT_PADDING); + y = yOffset + 18 + DECORATION_SLOT_PADDING; + x += 48; + y = addDecorationSlot(decorativeBlocks, 4, x, y, DECORATION_SLOT_PADDING); + y = addDecorationSlot(decorativeBlocks, 5, x, y, DECORATION_SLOT_PADDING); + y = addDecorationSlot(decorativeBlocks, 6, x, y, 0); + decorationSlotRange = new SlotRange(0, decorativeBlocks.getSlots()); + x += 44; + + ItemStackHandler dyes = blockEntity.getDyes(); + addSlot(new SlotItemHandler(dyes, 0, x, yOffset).setBackground(InventoryMenu.BLOCK_ATLAS, EMPTY_RED_DYE_SLOT_BACKGROUND)); + x += 18; + addSlot(new SlotItemHandler(dyes, 1, x, yOffset).setBackground(InventoryMenu.BLOCK_ATLAS, EMPTY_GREEN_DYE_SLOT_BACKGROUND)); + x += 18; + addSlot(new SlotItemHandler(dyes, 2, x, yOffset).setBackground(InventoryMenu.BLOCK_ATLAS, EMPTY_BLUE_DYE_SLOT_BACKGROUND)); + dyeSlotRange = new SlotRange(decorationSlotRange.firstSlot() + decorationSlotRange.numberOfSlots(), dyes.getSlots()); + + return y; + } + + private int addDecorationSlot(ItemStackHandler itemHandler, int slotIndex, int xOffset, int y, int yPadding) { + addSlot(new SlotItemHandler(itemHandler, slotIndex, xOffset, y).setBackground(InventoryMenu.BLOCK_ATLAS, EMPTY_MATERIAL_SLOT_BACKGROUND)); + y += 18; + y += yPadding; + return y; + } + + private void addPlayerSlots(Inventory playerInventory, int y) { + int playerSlotXOffset = 45; + int hotbarPadding = 4; + + for (int row = 0; row < 3; ++row) { + for (int col = 0; col < 9; ++col) { + addSlot(new Slot(playerInventory, col + row * 9 + 9, playerSlotXOffset + col * 18, y + row * 18)); + } + } + + for (int col = 0; col < 9; ++col) { + Slot slot = new Slot(playerInventory, col, playerSlotXOffset + col * 18, y + 3 * 18 + hotbarPadding); + addSlot(slot); + } + + playerSlotRange = new SlotRange(storageSlotRange.firstSlot() + storageSlotRange.numberOfSlots() + 1, 36); + } + + @Override + public ItemStack quickMoveStack(Player player, int slotIndex) { + Slot slot = getSlot(slotIndex); + ItemStack slotStack = slot.getItem(); + ItemStack slotStackCopy = slotStack.copy(); + if (isPlayerSlot(slotIndex)) { + if (blockEntity.getDecorativeBlocks().isItemValid(decorationSlotRange.firstSlot(), slotStack) + && !moveItemStackTo(slotStack, decorationSlotRange, false)) { + return ItemStack.EMPTY; + } else if (isValidDye(slotStack) + && !moveItemStackTo(slotStack, dyeSlotRange, false)) { + return ItemStack.EMPTY; + } else if (blockEntity.getStorageBlock().isItemValid(0, slotStack) + && !moveItemStackTo(slotStack, storageSlotRange, false)) { + return ItemStack.EMPTY; + } + } else { + if (!moveItemStackTo(slotStack, playerSlotRange, true)) { + return ItemStack.EMPTY; + } + } + + if (slotStackCopy.getCount() == slotStack.getCount()) { + return ItemStack.EMPTY; + } + + blockEntity.updateResultAndSetChanged(); + slot.onTake(player, slotStackCopy); + return slotStackCopy; + } + + private boolean isValidDye(ItemStack stack) { + ItemStackHandler dyes = blockEntity.getDyes(); + + for (int slot = 0; slot < dyes.getSlots(); slot++) { + if (dyes.isItemValid(slot, stack)) { + return true; + } + } + + return false; + } + + private boolean moveItemStackTo(ItemStack stack, SlotRange slotRange, boolean reverse) { + return moveItemStackTo(stack, slotRange.firstSlot(), slotRange.firstSlot() + slotRange.numberOfSlots(), reverse); + } + + private boolean isPlayerSlot(int slotIndex) { + return playerSlotRange.isInRange(slotIndex); + } + + public SlotRange getDyeSlotRange() { + return dyeSlotRange; + } + + @Override + public boolean stillValid(Player player) { + return player.distanceToSqr((double) blockEntity.getBlockPos().getX() + 0.5D, (double) blockEntity.getBlockPos().getY() + 0.5D, (double) blockEntity.getBlockPos().getZ() + 0.5D) <= 64.0D; + } + + public static DecorationTableMenu fromBuffer(int containerId, Inventory playerInventory, FriendlyByteBuf buffer) { + return new DecorationTableMenu(containerId, playerInventory.player, buffer.readBlockPos()); + } + + public void setSlotMaterialInheritance(int slot, boolean inheritance) { + blockEntity.setSlotMaterialInheritance(slot, inheritance); + sendToServer(tag -> { + tag.putString("action", SET_INHERITANCE_ACTION); + tag.putInt("slot", slot); + tag.putBoolean("inheritance", inheritance); + }); + } + + public void setMainColor(int color) { + blockEntity.setMainColor(color); + sendToServer(tag -> tag.putInt("mainColor", color)); + } + + public void setAccentColor(int color) { + blockEntity.setAccentColor(color); + sendToServer(tag -> tag.putInt("accentColor", color)); + } + + public boolean isSlotMaterialInherited(int slot) { + return blockEntity.isSlotMaterialInherited(slot); + } + + public ItemStack getInheritedItem(int childSlot) { + return blockEntity.getInheritedItem(childSlot); + } + + public int getMainColor() { + return blockEntity.getMainColor(); + } + + public int getAccentColor() { + return blockEntity.getAccentColor(); + } + + public Slot getResultSlot() { + return resultSlot; + } + + protected void sendToServer(Consumer addData) { + if (blockEntity.getLevel() == null || !blockEntity.getLevel().isClientSide) { + return; + } + + CompoundTag data = new CompoundTag(); + addData.accept(data); + PacketHandler.INSTANCE.sendToServer(new SyncContainerClientDataMessage(data)); + } + + public Map getPartsNeeded() { + return blockEntity.getPartsNeeded(); + } + + public Set getMissingDyes() { + return blockEntity.getMissingDyes(); + } + + @Override + public void handleMessage(CompoundTag data) { + String action = data.getString("action"); + if (action.equals(SET_INHERITANCE_ACTION)) { + setSlotMaterialInheritance(data.getInt("slot"), data.getBoolean("inheritance")); + } else if (data.contains("mainColor")) { + setMainColor(data.getInt("mainColor")); + } else if (data.contains("accentColor")) { + setAccentColor(data.getInt("accentColor")); + } + } + + public Map getPartsStored() { + return blockEntity.getPartsStored(); + } +} diff --git a/src/main/java/net/p3pp3rf1y/sophisticatedstorage/crafting/BarrelMaterialRecipe.java b/src/main/java/net/p3pp3rf1y/sophisticatedstorage/crafting/BarrelMaterialRecipe.java index a5e76cd71..d862b3bfe 100644 --- a/src/main/java/net/p3pp3rf1y/sophisticatedstorage/crafting/BarrelMaterialRecipe.java +++ b/src/main/java/net/p3pp3rf1y/sophisticatedstorage/crafting/BarrelMaterialRecipe.java @@ -109,79 +109,19 @@ public ItemStack assemble(CraftingContainer container, RegistryAccess registryAc Map materials = new EnumMap<>(BarrelMaterial.class); materials.putAll(BarrelBlockItem.getMaterials(barrelStackCopy)); - uncompactMaterials(materials); + BarrelBlockItem.uncompactMaterials(materials); fillGridMaterials(container, barrelColumn, barrelRow, materials); fillEmptyMaterialsWithDefaults(materials); - compactMaterials(materials); + BarrelBlockItem.compactMaterials(materials); BarrelBlockItem.setMaterials(barrelStackCopy, materials); - removeCoveredTints(barrelStackCopy, materials); + BarrelBlockItem.removeCoveredTints(barrelStackCopy, materials); return barrelStackCopy; } - private void uncompactMaterials(Map materials) { - if (materials.isEmpty()) { - return; - } - - Map uncompactedMaterials = new EnumMap<>(BarrelMaterial.class); - materials.forEach((mat, texture) -> { - for (BarrelMaterial child : mat.getChildren()) { - uncompactedMaterials.put(child, texture); - } - }); - - materials.clear(); - materials.putAll(uncompactedMaterials); - } - - private static void removeCoveredTints(ItemStack barrelStackCopy, Map materials) { - if (barrelStackCopy.getItem() instanceof ITintableBlockItem tintableBlockItem) { - boolean hasMainTint = tintableBlockItem.getMainColor(barrelStackCopy).isPresent(); - boolean hasAccentTint = tintableBlockItem.getAccentColor(barrelStackCopy).isPresent(); - - if (hasMainTint || hasAccentTint) { - Set materialModelParts = materials.keySet().stream().map(BarrelMaterial::getMaterialModelPart).collect(Collectors.toSet()); - - if (hasMainTint && (materialModelParts.contains(BarrelMaterial.MaterialModelPart.BOTH) || materialModelParts.contains(BarrelMaterial.MaterialModelPart.CORE))) { - tintableBlockItem.removeMainColor(barrelStackCopy); - } - if (hasAccentTint && (materialModelParts.contains(BarrelMaterial.MaterialModelPart.BOTH) || materialModelParts.contains(BarrelMaterial.MaterialModelPart.TRIM))) { - tintableBlockItem.removeAccentColor(barrelStackCopy); - } - } - } - } - - private static void compactMaterials(Map materials) { - for (BarrelMaterial material : BarrelMaterial.values()) { - if (!material.isLeaf()) { - //if all children have the same texture remove them and convert to the parent - ResourceLocation firstChildTexture = null; - boolean allChildrenHaveSameTexture = true; - for (BarrelMaterial child : material.getChildren()) { - ResourceLocation texture = materials.get(child); - if (texture == null || (firstChildTexture != null && !firstChildTexture.equals(texture))) { - allChildrenHaveSameTexture = false; - break; - } else if (firstChildTexture == null) { - firstChildTexture = texture; - } - } - - if (firstChildTexture != null && allChildrenHaveSameTexture) { - materials.put(material, firstChildTexture); - for (BarrelMaterial child : material.getChildren()) { - materials.remove(child); - } - } - } - } - } - private static void fillEmptyMaterialsWithDefaults(Map materials) { for (BarrelMaterial material : BarrelMaterial.values()) { if (material.isLeaf() && !materials.containsKey(material)) { diff --git a/src/main/java/net/p3pp3rf1y/sophisticatedstorage/data/BlockTagProvider.java b/src/main/java/net/p3pp3rf1y/sophisticatedstorage/data/BlockTagProvider.java index 2740306f8..e0c75fd65 100644 --- a/src/main/java/net/p3pp3rf1y/sophisticatedstorage/data/BlockTagProvider.java +++ b/src/main/java/net/p3pp3rf1y/sophisticatedstorage/data/BlockTagProvider.java @@ -25,7 +25,8 @@ protected void addTags(HolderLookup.Provider pProvider) { ModBlocks.LIMITED_BARREL_2.get(), ModBlocks.LIMITED_COPPER_BARREL_2.get(), ModBlocks.LIMITED_IRON_BARREL_2.get(), ModBlocks.LIMITED_GOLD_BARREL_2.get(), ModBlocks.LIMITED_DIAMOND_BARREL_2.get(), ModBlocks.LIMITED_NETHERITE_BARREL_2.get(), ModBlocks.LIMITED_BARREL_3.get(), ModBlocks.LIMITED_COPPER_BARREL_3.get(), ModBlocks.LIMITED_IRON_BARREL_3.get(), ModBlocks.LIMITED_GOLD_BARREL_3.get(), ModBlocks.LIMITED_DIAMOND_BARREL_3.get(), ModBlocks.LIMITED_NETHERITE_BARREL_3.get(), ModBlocks.LIMITED_BARREL_4.get(), ModBlocks.LIMITED_COPPER_BARREL_4.get(), ModBlocks.LIMITED_IRON_BARREL_4.get(), ModBlocks.LIMITED_GOLD_BARREL_4.get(), ModBlocks.LIMITED_DIAMOND_BARREL_4.get(), ModBlocks.LIMITED_NETHERITE_BARREL_4.get(), - ModBlocks.CHEST.get(), ModBlocks.COPPER_CHEST.get(), ModBlocks.IRON_CHEST.get(), ModBlocks.GOLD_CHEST.get(), ModBlocks.DIAMOND_CHEST.get(), ModBlocks.NETHERITE_CHEST.get() + ModBlocks.CHEST.get(), ModBlocks.COPPER_CHEST.get(), ModBlocks.IRON_CHEST.get(), ModBlocks.GOLD_CHEST.get(), ModBlocks.DIAMOND_CHEST.get(), ModBlocks.NETHERITE_CHEST.get(), + ModBlocks.DECORATION_TABLE.get() ); tag(BlockTags.MINEABLE_WITH_PICKAXE).add( ModBlocks.SHULKER_BOX.get(), ModBlocks.COPPER_SHULKER_BOX.get(), ModBlocks.IRON_SHULKER_BOX.get(), ModBlocks.GOLD_SHULKER_BOX.get(), ModBlocks.DIAMOND_SHULKER_BOX.get(), ModBlocks.NETHERITE_SHULKER_BOX.get(), diff --git a/src/main/java/net/p3pp3rf1y/sophisticatedstorage/data/StorageBlockLootProvider.java b/src/main/java/net/p3pp3rf1y/sophisticatedstorage/data/StorageBlockLootProvider.java index 1f3e93873..f73dea985 100644 --- a/src/main/java/net/p3pp3rf1y/sophisticatedstorage/data/StorageBlockLootProvider.java +++ b/src/main/java/net/p3pp3rf1y/sophisticatedstorage/data/StorageBlockLootProvider.java @@ -85,6 +85,8 @@ public void generate() { add(ModBlocks.STORAGE_IO.get(), dropBlock(ModBlocks.STORAGE_IO_ITEM.get())); add(ModBlocks.STORAGE_INPUT.get(), dropBlock(ModBlocks.STORAGE_INPUT_ITEM.get())); add(ModBlocks.STORAGE_OUTPUT.get(), dropBlock(ModBlocks.STORAGE_OUTPUT_ITEM.get())); + + add(ModBlocks.DECORATION_TABLE.get(), dropBlock(ModBlocks.DECORATION_TABLE_ITEM.get())); } @Override diff --git a/src/main/java/net/p3pp3rf1y/sophisticatedstorage/data/StorageRecipeProvider.java b/src/main/java/net/p3pp3rf1y/sophisticatedstorage/data/StorageRecipeProvider.java index eb7384885..17e058d7d 100644 --- a/src/main/java/net/p3pp3rf1y/sophisticatedstorage/data/StorageRecipeProvider.java +++ b/src/main/java/net/p3pp3rf1y/sophisticatedstorage/data/StorageRecipeProvider.java @@ -2,9 +2,7 @@ import net.minecraft.data.BlockFamily; import net.minecraft.data.DataGenerator; -import net.minecraft.data.recipes.FinishedRecipe; -import net.minecraft.data.recipes.RecipeProvider; -import net.minecraft.data.recipes.SpecialRecipeBuilder; +import net.minecraft.data.recipes.*; import net.minecraft.resources.ResourceLocation; import net.minecraft.tags.ItemTags; import net.minecraft.world.item.BlockItem; @@ -71,6 +69,16 @@ protected void buildRecipes(Consumer consumer) { .unlockedBy("has_slime", has(Tags.Items.SLIMEBALLS)) .condition(new DropPackedDisabledCondition()) .save(consumer); + + ShapedRecipeBuilder.shaped(RecipeCategory.MISC, ModBlocks.DECORATION_TABLE_ITEM.get()) + .pattern("LLL") + .pattern("PBP") + .pattern("P P") + .define('L', ItemTags.LOGS) + .define('P', ItemTags.PLANKS) + .define('B', ModItems.UPGRADE_BASE.get()) + .unlockedBy("has_upgrade_base", has(ModItems.UPGRADE_BASE.get())) + .save(consumer); } private void addBackpackUpgradeConversionRecipes(Consumer consumer) { diff --git a/src/main/java/net/p3pp3rf1y/sophisticatedstorage/init/ModBlocks.java b/src/main/java/net/p3pp3rf1y/sophisticatedstorage/init/ModBlocks.java index b7d2e99c5..75c0b2f52 100644 --- a/src/main/java/net/p3pp3rf1y/sophisticatedstorage/init/ModBlocks.java +++ b/src/main/java/net/p3pp3rf1y/sophisticatedstorage/init/ModBlocks.java @@ -42,14 +42,8 @@ import net.p3pp3rf1y.sophisticatedstorage.Config; import net.p3pp3rf1y.sophisticatedstorage.SophisticatedStorage; import net.p3pp3rf1y.sophisticatedstorage.block.*; -import net.p3pp3rf1y.sophisticatedstorage.client.gui.LimitedBarrelScreen; -import net.p3pp3rf1y.sophisticatedstorage.client.gui.LimitedBarrelSettingsScreen; -import net.p3pp3rf1y.sophisticatedstorage.client.gui.StorageScreen; -import net.p3pp3rf1y.sophisticatedstorage.client.gui.StorageSettingsScreen; -import net.p3pp3rf1y.sophisticatedstorage.common.gui.LimitedBarrelContainerMenu; -import net.p3pp3rf1y.sophisticatedstorage.common.gui.LimitedBarrelSettingsContainerMenu; -import net.p3pp3rf1y.sophisticatedstorage.common.gui.StorageContainerMenu; -import net.p3pp3rf1y.sophisticatedstorage.common.gui.StorageSettingsContainerMenu; +import net.p3pp3rf1y.sophisticatedstorage.client.gui.*; +import net.p3pp3rf1y.sophisticatedstorage.common.gui.*; import net.p3pp3rf1y.sophisticatedstorage.crafting.*; import net.p3pp3rf1y.sophisticatedstorage.item.BarrelBlockItem; import net.p3pp3rf1y.sophisticatedstorage.item.ChestBlockItem; @@ -61,7 +55,8 @@ public class ModBlocks { private static final String LIMITED_BARREL_NAME = "limited_barrel"; - private ModBlocks() {} + private ModBlocks() { + } public static final TagKey BASE_TIER_WOODEN_STORAGE_TAG = TagKey.create(ForgeRegistries.ITEMS.getRegistryKey(), SophisticatedStorage.getRL("base_tier_wooden_storage")); public static final DeferredRegister BLOCKS = DeferredRegister.create(ForgeRegistries.BLOCKS, SophisticatedStorage.MOD_ID); @@ -168,7 +163,7 @@ private ModBlocks() {} private static final String CHEST_REG_NAME = "chest"; public static final RegistryObject CHEST = BLOCKS.register(CHEST_REG_NAME, () -> new ChestBlock(Config.SERVER.woodChest.inventorySlotCount, Config.SERVER.woodChest.upgradeSlotCount)); - public static final RegistryObject COPPER_CHEST = BLOCKS.register("copper_chest", () -> new ChestBlock(Config.SERVER.copperChest.inventorySlotCount, Config.SERVER.copperChest.upgradeSlotCount)); + public static final RegistryObject COPPER_CHEST = BLOCKS.register("copper_chest", () -> new ChestBlock(Config.SERVER.copperChest.inventorySlotCount, Config.SERVER.copperChest.upgradeSlotCount)); public static final RegistryObject IRON_CHEST = BLOCKS.register("iron_chest", () -> new ChestBlock(Config.SERVER.ironChest.inventorySlotCount, Config.SERVER.ironChest.upgradeSlotCount)); public static final RegistryObject GOLD_CHEST = BLOCKS.register("gold_chest", () -> new ChestBlock(Config.SERVER.goldChest.inventorySlotCount, Config.SERVER.goldChest.upgradeSlotCount)); public static final RegistryObject DIAMOND_CHEST = BLOCKS.register("diamond_chest", () -> new ChestBlock(Config.SERVER.diamondChest.inventorySlotCount, Config.SERVER.diamondChest.upgradeSlotCount)); @@ -182,7 +177,7 @@ private ModBlocks() {} private static final String SHULKER_BOX_REG_NAME = "shulker_box"; public static final RegistryObject SHULKER_BOX = BLOCKS.register(SHULKER_BOX_REG_NAME, () -> new ShulkerBoxBlock(Config.SERVER.shulkerBox.inventorySlotCount, Config.SERVER.shulkerBox.upgradeSlotCount)); - public static final RegistryObject COPPER_SHULKER_BOX = BLOCKS.register("copper_shulker_box", () -> new ShulkerBoxBlock(Config.SERVER.copperShulkerBox.inventorySlotCount, Config.SERVER.copperShulkerBox.upgradeSlotCount)); + public static final RegistryObject COPPER_SHULKER_BOX = BLOCKS.register("copper_shulker_box", () -> new ShulkerBoxBlock(Config.SERVER.copperShulkerBox.inventorySlotCount, Config.SERVER.copperShulkerBox.upgradeSlotCount)); public static final RegistryObject IRON_SHULKER_BOX = BLOCKS.register("iron_shulker_box", () -> new ShulkerBoxBlock(Config.SERVER.ironShulkerBox.inventorySlotCount, Config.SERVER.ironShulkerBox.upgradeSlotCount)); public static final RegistryObject GOLD_SHULKER_BOX = BLOCKS.register("gold_shulker_box", () -> new ShulkerBoxBlock(Config.SERVER.goldShulkerBox.inventorySlotCount, Config.SERVER.goldShulkerBox.upgradeSlotCount)); public static final RegistryObject DIAMOND_SHULKER_BOX = BLOCKS.register("diamond_shulker_box", () -> new ShulkerBoxBlock(Config.SERVER.diamondShulkerBox.inventorySlotCount, Config.SERVER.diamondShulkerBox.upgradeSlotCount)); @@ -221,6 +216,10 @@ public BlockEntity newBlockEntity(BlockPos pos, BlockState state) { public static final RegistryObject STORAGE_INPUT_ITEM = ITEMS.register(STORAGE_INPUT_REG_NAME, () -> new BlockItemBase(STORAGE_INPUT.get(), new Item.Properties())); public static final RegistryObject STORAGE_OUTPUT_ITEM = ITEMS.register(STORAGE_OUTPUT_REG_NAME, () -> new BlockItemBase(STORAGE_OUTPUT.get(), new Item.Properties())); + public static final Supplier DECORATION_TABLE = BLOCKS.register("decoration_table", DecorationTableBlock::new); + + public static final Supplier DECORATION_TABLE_ITEM = ITEMS.register("decoration_table", () -> new BlockItemBase(DECORATION_TABLE.get(), new Properties())); + @SuppressWarnings("ConstantConditions") //no datafixer type needed public static final RegistryObject> BARREL_BLOCK_ENTITY_TYPE = BLOCK_ENTITY_TYPES.register(BARREL_REG_NAME, () -> BlockEntityType.Builder.of(BarrelBlockEntity::new, BARREL.get(), COPPER_BARREL.get(), IRON_BARREL.get(), GOLD_BARREL.get(), DIAMOND_BARREL.get(), NETHERITE_BARREL.get()) @@ -271,6 +270,10 @@ public BlockEntity newBlockEntity(BlockPos pos, BlockState state) { BlockEntityType.Builder.of(StorageOutputBlockEntity::new, STORAGE_OUTPUT.get()) .build(null)); + public static final RegistryObject> DECORATION_TABLE_BLOCK_ENTITY_TYPE = BLOCK_ENTITY_TYPES.register("decoration_table", () -> + BlockEntityType.Builder.of(DecorationTableBlockEntity::new, DECORATION_TABLE.get()) + .build(null)); + public static final RegistryObject> STORAGE_CONTAINER_TYPE = MENU_TYPES.register("storage", () -> IForgeMenuType.create(StorageContainerMenu::fromBuffer)); @@ -283,6 +286,9 @@ public BlockEntity newBlockEntity(BlockPos pos, BlockState state) { public static final RegistryObject> LIMITED_BARREL_SETTINGS_CONTAINER_TYPE = MENU_TYPES.register("limited_barrel_settings", () -> IForgeMenuType.create(LimitedBarrelSettingsContainerMenu::fromBuffer)); + public static final Supplier> DECORATION_TABLE_CONTAINER_TYPE = MENU_TYPES.register("decoration_table", + () -> IForgeMenuType.create(DecorationTableMenu::fromBuffer)); + private static final DeferredRegister> RECIPE_SERIALIZERS = DeferredRegister.create(ForgeRegistries.RECIPE_SERIALIZERS, SophisticatedStorage.MOD_ID); public static final RegistryObject> STORAGE_DYE_RECIPE_SERIALIZER = RECIPE_SERIALIZERS.register("storage_dye", () -> new SimpleCraftingRecipeSerializer<>(StorageDyeRecipe::new)); public static final RegistryObject> STORAGE_TIER_UPGRADE_RECIPE_SERIALIZER = RECIPE_SERIALIZERS.register("storage_tier_upgrade", StorageTierUpgradeRecipe.Serializer::new); @@ -319,6 +325,7 @@ private static void registerContainers(FMLClientSetupEvent evt) { MenuScreens.register(SETTINGS_CONTAINER_TYPE.get(), StorageSettingsScreen::constructScreen); MenuScreens.register(LIMITED_BARREL_CONTAINER_TYPE.get(), LimitedBarrelScreen::new); MenuScreens.register(LIMITED_BARREL_SETTINGS_CONTAINER_TYPE.get(), LimitedBarrelSettingsScreen::new); + MenuScreens.register(DECORATION_TABLE_CONTAINER_TYPE.get(), DecorationTableScreen::new); }); } @@ -388,6 +395,7 @@ protected void removePaint(ItemStack stack) { @SuppressWarnings("java:S6548") //singleton is correct here public static class WoodStorageCauldronInteraction extends StorageCauldronInteraction { private static final WoodStorageCauldronInteraction INSTANCE = new WoodStorageCauldronInteraction(); + @Override protected void removePaint(ItemStack stack) { super.removePaint(stack); diff --git a/src/main/java/net/p3pp3rf1y/sophisticatedstorage/init/ModBlocksClient.java b/src/main/java/net/p3pp3rf1y/sophisticatedstorage/init/ModBlocksClient.java new file mode 100644 index 000000000..e69de29bb diff --git a/src/main/java/net/p3pp3rf1y/sophisticatedstorage/item/BarrelBlockItem.java b/src/main/java/net/p3pp3rf1y/sophisticatedstorage/item/BarrelBlockItem.java index e083f284e..72a04fcb6 100644 --- a/src/main/java/net/p3pp3rf1y/sophisticatedstorage/item/BarrelBlockItem.java +++ b/src/main/java/net/p3pp3rf1y/sophisticatedstorage/item/BarrelBlockItem.java @@ -7,8 +7,10 @@ import net.minecraft.world.level.block.Block; import net.p3pp3rf1y.sophisticatedcore.util.NBTHelper; import net.p3pp3rf1y.sophisticatedstorage.block.BarrelMaterial; +import net.p3pp3rf1y.sophisticatedstorage.block.ITintableBlockItem; import net.p3pp3rf1y.sophisticatedstorage.client.gui.StorageTranslationHelper; +import java.util.EnumMap; import java.util.Map; import java.util.Optional; @@ -52,6 +54,64 @@ public static void removeMaterials(ItemStack stack) { NBTHelper.removeTag(stack, MATERIALS_TAG); } + public static void uncompactMaterials(Map materials) { + if (materials.isEmpty()) { + return; + } + + Map uncompactedMaterials = new EnumMap<>(BarrelMaterial.class); + materials.forEach((mat, texture) -> { + for (BarrelMaterial child : mat.getChildren()) { + uncompactedMaterials.put(child, texture); + } + }); + + materials.clear(); + materials.putAll(uncompactedMaterials); + } + + public static void compactMaterials(Map materials) { + for (BarrelMaterial material : BarrelMaterial.values()) { + if (!material.isLeaf()) { + //if all children have the same texture remove them and convert to the parent + ResourceLocation firstChildTexture = null; + boolean allChildrenHaveSameTexture = true; + for (BarrelMaterial child : material.getChildren()) { + ResourceLocation texture = materials.get(child); + if (texture == null || (firstChildTexture != null && !firstChildTexture.equals(texture))) { + allChildrenHaveSameTexture = false; + break; + } else if (firstChildTexture == null) { + firstChildTexture = texture; + } + } + + if (firstChildTexture != null && allChildrenHaveSameTexture) { + materials.put(material, firstChildTexture); + for (BarrelMaterial child : material.getChildren()) { + materials.remove(child); + } + } + } + } + } + + public static void removeCoveredTints(ItemStack barrelStackCopy, Map materials) { + if (barrelStackCopy.getItem() instanceof ITintableBlockItem tintableBlockItem) { + boolean hasMainTint = tintableBlockItem.getMainColor(barrelStackCopy).isPresent(); + boolean hasAccentTint = tintableBlockItem.getAccentColor(barrelStackCopy).isPresent(); + + if (hasMainTint || hasAccentTint) { + if (hasMainTint && (materials.containsKey(BarrelMaterial.ALL) || materials.containsKey(BarrelMaterial.ALL_BUT_TRIM))) { + tintableBlockItem.removeMainColor(barrelStackCopy); + } + if (hasAccentTint && (materials.containsKey(BarrelMaterial.ALL) || materials.containsKey(BarrelMaterial.ALL_TRIM))) { + tintableBlockItem.removeAccentColor(barrelStackCopy); + } + } + } + } + @Override public Component getName(ItemStack stack) { Component name; diff --git a/src/main/java/net/p3pp3rf1y/sophisticatedstorage/upgrades/compression/CompressionInventoryPart.java b/src/main/java/net/p3pp3rf1y/sophisticatedstorage/upgrades/compression/CompressionInventoryPart.java index 89905f2dd..dbea430e8 100644 --- a/src/main/java/net/p3pp3rf1y/sophisticatedstorage/upgrades/compression/CompressionInventoryPart.java +++ b/src/main/java/net/p3pp3rf1y/sophisticatedstorage/upgrades/compression/CompressionInventoryPart.java @@ -9,9 +9,9 @@ import net.minecraftforge.items.ItemHandlerHelper; import net.p3pp3rf1y.sophisticatedcore.inventory.IInventoryPartHandler; import net.p3pp3rf1y.sophisticatedcore.inventory.InventoryHandler; -import net.p3pp3rf1y.sophisticatedcore.inventory.InventoryPartitioner; import net.p3pp3rf1y.sophisticatedcore.settings.memory.MemorySettingsCategory; import net.p3pp3rf1y.sophisticatedcore.util.RecipeHelper; +import net.p3pp3rf1y.sophisticatedcore.util.SlotRange; import net.p3pp3rf1y.sophisticatedstorage.Config; import net.p3pp3rf1y.sophisticatedstorage.SophisticatedStorage; import org.apache.commons.lang3.function.TriFunction; @@ -32,7 +32,7 @@ public class CompressionInventoryPart implements IInventoryPartHandler { public static final String NAME = "compression"; public static final Pair EMPTY_COMPRESSION_SLOT = new Pair<>(InventoryMenu.BLOCK_ATLAS, SophisticatedStorage.getRL("item/empty_compression_slot")); private final InventoryHandler parent; - private final InventoryPartitioner.SlotRange slotRange; + private final SlotRange slotRange; private final Supplier getMemorySettings; @SuppressWarnings("FieldCanBeLocal") //need field instead of local variable because it's wrapped in WeakReference in RecipeHelper private final Runnable recipeChangeListener = () -> calculateStacks(false); @@ -40,7 +40,7 @@ public class CompressionInventoryPart implements IInventoryPartHandler { private Map slotDefinitions = new HashMap<>(); private final Map calculatedStacks = new HashMap<>(); - public CompressionInventoryPart(InventoryHandler parent, InventoryPartitioner.SlotRange slotRange, Supplier getMemorySettings) { + public CompressionInventoryPart(InventoryHandler parent, SlotRange slotRange, Supplier getMemorySettings) { this.parent = parent; this.slotRange = slotRange; this.getMemorySettings = getMemorySettings; diff --git a/src/main/java/net/p3pp3rf1y/sophisticatedstorage/upgrades/compression/CompressionUpgradeItem.java b/src/main/java/net/p3pp3rf1y/sophisticatedstorage/upgrades/compression/CompressionUpgradeItem.java index 36c83b6ce..9ea1eddc9 100644 --- a/src/main/java/net/p3pp3rf1y/sophisticatedstorage/upgrades/compression/CompressionUpgradeItem.java +++ b/src/main/java/net/p3pp3rf1y/sophisticatedstorage/upgrades/compression/CompressionUpgradeItem.java @@ -17,6 +17,7 @@ import net.p3pp3rf1y.sophisticatedcore.upgrades.compacting.CompactingUpgradeItem; import net.p3pp3rf1y.sophisticatedcore.util.NBTHelper; import net.p3pp3rf1y.sophisticatedcore.util.RecipeHelper; +import net.p3pp3rf1y.sophisticatedcore.util.SlotRange; import net.p3pp3rf1y.sophisticatedstorage.Config; import net.p3pp3rf1y.sophisticatedstorage.client.gui.StorageTranslationHelper; @@ -40,7 +41,7 @@ public UpgradeType getType() { } private UpgradeSlotChangeResult checkCompressionSpace(IStorageWrapper storageWrapper) { - Optional slotRange = storageWrapper.getInventoryHandler().getInventoryPartitioner().getFirstSpace(Config.SERVER.compressionUpgrade.maxNumberOfSlots.get()); + Optional slotRange = storageWrapper.getInventoryHandler().getInventoryPartitioner().getFirstSpace(Config.SERVER.compressionUpgrade.maxNumberOfSlots.get()); return slotRange.map(range -> canUseForCompression(storageWrapper, range)) .orElseGet(() -> new UpgradeSlotChangeResult.Fail(StorageTranslationHelper.INSTANCE.translError("add.compression_no_space"), Collections.emptySet(), Collections.emptySet(), Collections.emptySet())); @@ -60,7 +61,7 @@ public List getUpgradeConflicts() { return UPGRADE_CONFLICT_DEFINITIONS; } - private UpgradeSlotChangeResult canUseForCompression(IStorageWrapper storageWrapper, InventoryPartitioner.SlotRange slotRange) { + private UpgradeSlotChangeResult canUseForCompression(IStorageWrapper storageWrapper, SlotRange slotRange) { boolean allRemainingSlotsMustBeEmpty = false; Item nextItemToMatch = Items.AIR; Set errorSlots = new LinkedHashSet<>(); diff --git a/src/main/resources/META-INF/accesstransformer.cfg b/src/main/resources/META-INF/accesstransformer.cfg index 7ba90ce65..2bfe7937d 100644 --- a/src/main/resources/META-INF/accesstransformer.cfg +++ b/src/main/resources/META-INF/accesstransformer.cfg @@ -19,4 +19,5 @@ public net.minecraft.client.gui.font.FontManager f_94999_ # fontSets public net.minecraft.client.gui.font.FontManager f_94998_ # missingFontSet public net.minecraft.world.item.crafting.ShapelessRecipe f_44243_ # result public net.minecraft.client.renderer.MultiBufferSource$BufferSource f_109904_ # builder -public net.minecraft.client.multiplayer.MultiPlayerGameMode f_105195_ # destroyDelay \ No newline at end of file +public net.minecraft.client.multiplayer.MultiPlayerGameMode f_105195_ # destroyDelay +protected net.minecraft.client.gui.screens.inventory.AbstractContainerScreen m_280092_(Lnet/minecraft/client/gui/GuiGraphics;Lnet/minecraft/world/inventory/Slot;)V # renderSlot \ No newline at end of file diff --git a/src/main/resources/assets/sophisticatedstorage/blockstates/decoration_table.json b/src/main/resources/assets/sophisticatedstorage/blockstates/decoration_table.json new file mode 100644 index 000000000..0ea6feeb4 --- /dev/null +++ b/src/main/resources/assets/sophisticatedstorage/blockstates/decoration_table.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=east": { + "model": "sophisticatedstorage:block/decoration_table", + "y": 90 + }, + "facing=north": { + "model": "sophisticatedstorage:block/decoration_table" + }, + "facing=south": { + "model": "sophisticatedstorage:block/decoration_table", + "y": 180 + }, + "facing=west": { + "model": "sophisticatedstorage:block/decoration_table", + "y": 270 + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/sophisticatedstorage/lang/en_us.json b/src/main/resources/assets/sophisticatedstorage/lang/en_us.json index 3d7bdb23d..f35679e23 100644 --- a/src/main/resources/assets/sophisticatedstorage/lang/en_us.json +++ b/src/main/resources/assets/sophisticatedstorage/lang/en_us.json @@ -81,6 +81,7 @@ "block.sophisticatedstorage.gold_chest": "%s%sGold Chest", "block.sophisticatedstorage.diamond_chest": "%s%sDiamond Chest", "block.sophisticatedstorage.netherite_chest": "%s%sNetherite Chest", + "block.sophisticatedstorage.decoration_table": "Decoration Table", "item.sophisticatedstorage.shulker_box": "Shulker Box", "block.sophisticatedstorage.shulker_box": "Shulker Box", "item.sophisticatedstorage.copper_shulker_box": "Copper Shulker Box", @@ -227,8 +228,20 @@ "gui.sophisticatedstorage.block_side.back": "Back", "gui.sophisticatedstorage.block_side.left": "Left", "gui.sophisticatedstorage.block_side.right": "Right", + "gui.sophisticatedstorage.barrel_part.top_inner_trim": "Top Inner Accent", + "gui.sophisticatedstorage.barrel_part.top_trim": "Top Accent", + "gui.sophisticatedstorage.barrel_part.side_trim": "Side Accent", + "gui.sophisticatedstorage.barrel_part.bottom_trim": "Bottom Accent", + "gui.sophisticatedstorage.barrel_part.top_core": "Top Main", + "gui.sophisticatedstorage.barrel_part.side_core": "Side Main", + "gui.sophisticatedstorage.barrel_part.bottom_core": "Bottom Main", + "gui.sophisticatedstorage.tint.accent": "Accent Tint", + "gui.sophisticatedstorage.tint.main": "Main Tint", "gui.sophisticatedstorage.buttons.upgrade_switch_enabled": "ON", "gui.sophisticatedstorage.buttons.upgrade_switch_disabled": "OFF", + "gui.sophisticatedstorage.buttons.decoration_inheritance_on": "Reuse Material", + "gui.sophisticatedstorage.buttons.decoration_inheritance_off": "Don't Reuse Material", + "gui.sophisticatedstorage.buttons.pick_color": "Click to Pick Color", "gui.sophisticatedstorage.settings.buttons.context_storage": "Storage", "gui.sophisticatedstorage.settings.buttons.context_storage.tooltip": "This Storage's settings", "gui.sophisticatedstorage.settings.buttons.context_storage.tooltip_detail": "Inherited from player or overriden for this storage", @@ -236,5 +249,6 @@ "keybind.sophisticatedstorage.sort": "Sort Storage", "gui.sophisticatedstorage.status.too_many_item_entity_drops": "Can't break the %s as it would cause too many (%s) item entities to drop from it\nConsider using %s or break it while sneaking to skip this check", "gui.sophisticatedstorage.status.too_low_tier_upgrade_count": "Upgrading requires %s %ss", - "gui.sophisticatedstorage.status.packing_tape_disabled": "Config set to drop all storages as packed without the need for packing tape" + "gui.sophisticatedstorage.status.packing_tape_disabled": "Config set to drop all storages as packed without the need for packing tape", + "gui.sophisticatedstorage.tooltip.parts_stored": "Parts Stored" } \ No newline at end of file diff --git a/src/main/resources/assets/sophisticatedstorage/models/block/decoration_table.json b/src/main/resources/assets/sophisticatedstorage/models/block/decoration_table.json new file mode 100644 index 000000000..55d871a9f --- /dev/null +++ b/src/main/resources/assets/sophisticatedstorage/models/block/decoration_table.json @@ -0,0 +1,167 @@ +{ + "credit": "Made with Blockbench", + "parent": "minecraft:block/block", + "texture_size": [64, 64], + "textures": { + "particle": "minecraft:block/stripped_oak_log", + "0": "sophisticatedstorage:block/decoration_table" + }, + "elements": [ + { + "from": [0, 12, 0], + "to": [16, 16, 16], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 10.75, 8]}, + "faces": { + "north": {"uv": [7.5, 0, 11.5, 1], "texture": "#0"}, + "east": {"uv": [7.5, 1, 11.5, 2], "texture": "#0"}, + "south": {"uv": [7.5, 2, 11.5, 3], "texture": "#0"}, + "west": {"uv": [4, 7, 8, 8], "texture": "#0"}, + "up": {"uv": [4, 4, 0, 0], "rotation": 270, "texture": "#0"}, + "down": {"uv": [4, 4, 0, 8], "rotation": 90, "texture": "#0"} + } + }, + { + "from": [1, 0, 12], + "to": [4, 8, 15], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 10.75, 8]}, + "faces": { + "north": {"uv": [0.75, 8, 1.5, 10], "texture": "#0"}, + "east": {"uv": [1.5, 8, 2.25, 10], "texture": "#0"}, + "south": {"uv": [2.25, 8, 3, 10], "texture": "#0"}, + "west": {"uv": [0, 8, 0.75, 10], "texture": "#0"}, + "up": {"uv": [10.5, 9.75, 9.75, 9], "rotation": 270, "texture": "#0"}, + "down": {"uv": [10.5, 9.75, 9.75, 10.5], "rotation": 90, "texture": "#0"} + } + }, + { + "from": [12, 0, 12], + "to": [15, 8, 15], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 10.75, 8]}, + "faces": { + "north": {"uv": [3.75, 8, 4.5, 10], "texture": "#0"}, + "east": {"uv": [4.5, 8, 5.25, 10], "texture": "#0"}, + "south": {"uv": [5.25, 8, 6, 10], "texture": "#0"}, + "west": {"uv": [3, 8, 3.75, 10], "texture": "#0"}, + "up": {"uv": [0.75, 10.75, 0, 10], "rotation": 270, "texture": "#0"}, + "down": {"uv": [1.5, 10, 0.75, 10.75], "rotation": 90, "texture": "#0"} + } + }, + { + "from": [12, 0, 1], + "to": [15, 8, 4], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 10.75, 8]}, + "faces": { + "north": {"uv": [6.75, 8, 7.5, 10], "texture": "#0"}, + "east": {"uv": [8, 7, 8.75, 9], "texture": "#0"}, + "south": {"uv": [8.75, 7, 9.5, 9], "texture": "#0"}, + "west": {"uv": [6, 8, 6.75, 10], "texture": "#0"}, + "up": {"uv": [2.25, 10.75, 1.5, 10], "rotation": 270, "texture": "#0"}, + "down": {"uv": [3, 10, 2.25, 10.75], "rotation": 90, "texture": "#0"} + } + }, + { + "from": [1, 0, 1], + "to": [4, 8, 4], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 10.75, 8]}, + "faces": { + "north": {"uv": [8.25, 9, 9, 11], "texture": "#0"}, + "east": {"uv": [9, 9, 9.75, 11], "texture": "#0"}, + "south": {"uv": [9.5, 7, 10.25, 9], "texture": "#0"}, + "west": {"uv": [7.5, 9, 8.25, 11], "texture": "#0"}, + "up": {"uv": [3.75, 10.75, 3, 10], "rotation": 270, "texture": "#0"}, + "down": {"uv": [4.5, 10, 3.75, 10.75], "rotation": 90, "texture": "#0"} + } + }, + { + "from": [1, 8, 1], + "to": [15, 12, 15], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 10.75, 8]}, + "faces": { + "north": {"uv": [7.5, 4, 11, 5], "texture": "#0"}, + "east": {"uv": [7.5, 5, 11, 6], "texture": "#0"}, + "south": {"uv": [7.5, 6, 11, 7], "texture": "#0"}, + "west": {"uv": [7.5, 3, 11, 4], "texture": "#0"}, + "up": {"uv": [7.5, 3.5, 4, 0], "rotation": 270, "texture": "#0"}, + "down": {"uv": [7.5, 3.5, 4, 7], "rotation": 90, "texture": "#0"} + } + }, + { + "from": [3, 16, 10], + "to": [7, 21, 14], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 10.75, 8]}, + "faces": { + "north": {"uv": [2, 10.75, 3, 12], "texture": "#0"}, + "east": {"uv": [3, 10.75, 4, 12], "texture": "#0"}, + "south": {"uv": [1, 10.75, 2, 12], "texture": "#0"}, + "west": {"uv": [4, 10.75, 5, 12], "texture": "#0"}, + "up": {"uv": [0, 10.75, 1, 11.75], "rotation": 270, "texture": "#0"}, + "down": {"uv": [0, 0, 0.75, 0.75], "rotation": 90, "texture": "#0"} + } + }, + { + "from": [6.70284, 16, 11.53491], + "to": [9.70284, 17, 14.53491], + "rotation": {"angle": 22.5, "axis": "y", "origin": [8, 10.75, 8]}, + "faces": { + "north": {"uv": [1.5, 12.5, 2.25, 12.75], "texture": "#0"}, + "east": {"uv": [0.25, 12.75, 1, 13], "texture": "#0"}, + "south": {"uv": [1.5, 12, 2.25, 12.25], "texture": "#0"}, + "west": {"uv": [1.5, 12.25, 2.25, 12.5], "texture": "#0"}, + "up": {"uv": [0.75, 12, 1.5, 12.75], "rotation": 180, "texture": "#0"}, + "down": {"uv": [0, 0, 0.75, 0.75], "rotation": 180, "texture": "#0"} + } + }, + { + "from": [9.70284, 16, 12.53491], + "to": [12.70284, 17, 13.53491], + "rotation": {"angle": 22.5, "axis": "y", "origin": [8, 10.75, 8]}, + "faces": { + "north": {"uv": [0, 12.5, 0.75, 12.75], "texture": "#0"}, + "east": {"uv": [0, 12.75, 0.25, 13], "texture": "#0"}, + "south": {"uv": [0, 12.25, 0.75, 12.5], "texture": "#0"}, + "west": {"uv": [0, 0, 0.25, 0.25], "texture": "#0"}, + "up": {"uv": [0, 12, 0.75, 12.25], "rotation": 180, "texture": "#0"}, + "down": {"uv": [0, 0, 0.75, 0.25], "rotation": 180, "texture": "#0"} + } + }, + { + "from": [12, 16, 3], + "to": [14, 17, 5], + "rotation": {"angle": 22.5, "axis": "y", "origin": [13, 16, 4]}, + "faces": { + "north": {"uv": [2, 13, 2.5, 13.25], "texture": "#0"}, + "east": {"uv": [1.5, 13, 2, 13.25], "texture": "#0"}, + "south": {"uv": [1, 13, 1.5, 13.25], "texture": "#0"}, + "west": {"uv": [0.5, 13, 1, 13.25], "texture": "#0"}, + "up": {"uv": [0, 13, 0.5, 13.5], "texture": "#0"}, + "down": {"uv": [0, 0, 0.5, 0.5], "texture": "#missing"} + } + }, + { + "from": [12, 16.05, 5.4], + "to": [14, 17.05, 7.4], + "rotation": {"angle": 0, "axis": "x", "origin": [13, 16.05, 6.9]}, + "faces": { + "north": {"uv": [2, 13.5, 2.5, 13.75], "texture": "#0"}, + "east": {"uv": [1.5, 13.5, 2, 13.75], "texture": "#0"}, + "south": {"uv": [1, 13.5, 1.5, 13.75], "texture": "#0"}, + "west": {"uv": [0.5, 13.5, 1, 13.75], "texture": "#0"}, + "up": {"uv": [0, 13.5, 0.5, 14], "texture": "#0"}, + "down": {"uv": [2.5, 13.5, 3, 14], "texture": "#0"} + } + }, + { + "from": [6, 10, 0.25], + "to": [10, 11, 1.25], + "rotation": {"angle": 0, "axis": "y", "origin": [0, 0, 0.25]}, + "faces": { + "north": {"uv": [5.25, 11.25, 6.25, 11.5], "texture": "#0"}, + "east": {"uv": [5, 11, 5.25, 11.25], "texture": "#0"}, + "south": {"uv": [0, 0, 1, 0.25], "texture": "#missing"}, + "west": {"uv": [6.25, 11, 6.5, 11.25], "texture": "#0"}, + "up": {"uv": [5.25, 11, 6.25, 11.25], "texture": "#0"}, + "down": {"uv": [5.25, 11.5, 6.25, 11.75], "texture": "#0"} + } + } + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/sophisticatedstorage/models/item/decoration_table.json b/src/main/resources/assets/sophisticatedstorage/models/item/decoration_table.json new file mode 100644 index 000000000..13c1c0408 --- /dev/null +++ b/src/main/resources/assets/sophisticatedstorage/models/item/decoration_table.json @@ -0,0 +1,3 @@ +{ + "parent": "sophisticatedstorage:block/decoration_table" +} \ No newline at end of file diff --git a/src/main/resources/assets/sophisticatedstorage/textures/block/decoration_table.png b/src/main/resources/assets/sophisticatedstorage/textures/block/decoration_table.png new file mode 100644 index 0000000000000000000000000000000000000000..86afbf1678c8505bcd95bc39a4a78ebdd0b7fe8b GIT binary patch literal 3230 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 QL;wH)07*qoM6N<$f-yfmzyJUM literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/sophisticatedstorage/textures/gui/decoration_table.png b/src/main/resources/assets/sophisticatedstorage/textures/gui/decoration_table.png new file mode 100644 index 0000000000000000000000000000000000000000..6e6c4fdb959d16dbd2b8d863077bd8851efd6889 GIT binary patch literal 1177 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 Xe$tUE7khUa00000NkvXXu0mjflmKs4 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/sophisticatedstorage/textures/item/empty_green_dye_slot.png b/src/main/resources/assets/sophisticatedstorage/textures/item/empty_green_dye_slot.png new file mode 100644 index 0000000000000000000000000000000000000000..b69eb5d1bf198600661accf44965914f120bd1e8 GIT binary patch literal 274 zcmV+t0qy>YP) z$}VzId;J0|>Hr}GgbmHh%X=!~g&Q literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/sophisticatedstorage/textures/item/empty_material_slot.png b/src/main/resources/assets/sophisticatedstorage/textures/item/empty_material_slot.png new file mode 100644 index 0000000000000000000000000000000000000000..3b7414dee2c1bed7af85712c3ce69cdad8aef844 GIT binary patch literal 181 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`HJ&bxAr_~%2Hh4spun+sUi5~L zZwc(_MVikx#NSJN-EH^jaiIza<0AWsL0U>dcbo(>TNt<+9*M;n>O9F6bvV8L;HuEs z>+`p?%=w%+dGQUUZ*{i>!&+{xIkV@B@}9j@^SM@N<;r&5bW47;E_3gnDJRY>S+)J` ggyo^Yc)T>raJM0o}pi>FVdQ&MBb@0Q?V1O8@`> literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/sophisticatedstorage/textures/item/empty_red_dye_slot.png b/src/main/resources/assets/sophisticatedstorage/textures/item/empty_red_dye_slot.png new file mode 100644 index 0000000000000000000000000000000000000000..0cd5d17ed5f95e8e412e5be9697a9be9c326f0f2 GIT binary patch literal 292 zcmV+<0o(qGP)$pC+ner5sPQF^6-mYYJFvk7=5SF%m*RYYlMWQVL2b)^(*8`Ki@n zjHHy1QsTY8Fu**|2q92PQOCLjmSyR-Z6oK55CSPBDJ62wXsz+y10aOBb?|ydIGq3& z89+)2!2A7f3)C@y%X-~IYhJAm&fjanQ}o<7&uEM}`o6ze4k6t7I8WNVf^)7br7#S` qEk;U-ecwOG9}a3K&)t*wcjgzko0s;Wzl@;(0000 slotStacksInput, Map slotStacksInput, InventoryHandler invHandler, Supplier getMemorySettings) { - return initCompressionInventoryPart(invHandler, new InventoryPartitioner.SlotRange(Collections.min(slotStacksInput.keySet()), Collections.min(slotStacksInput.keySet()) + slotStacksInput.size()), getMemorySettings); + return initCompressionInventoryPart(invHandler, new SlotRange(Collections.min(slotStacksInput.keySet()), Collections.min(slotStacksInput.keySet()) + slotStacksInput.size()), getMemorySettings); } private CompressionInventoryPart initCompressionInventoryPart(Map slotStacksInput, InventoryHandler invHandler, int minSlot) { - return initCompressionInventoryPart(invHandler, new InventoryPartitioner.SlotRange(minSlot, minSlot + slotStacksInput.size()), () -> getMemorySettings(invHandler, Map.of())); + return initCompressionInventoryPart(invHandler, new SlotRange(minSlot, minSlot + slotStacksInput.size()), () -> getMemorySettings(invHandler, Map.of())); } - private CompressionInventoryPart initCompressionInventoryPart(InventoryHandler invHandler, InventoryPartitioner.SlotRange slotRange, Supplier getMemorySettings) { + private CompressionInventoryPart initCompressionInventoryPart(InventoryHandler invHandler, SlotRange slotRange, Supplier getMemorySettings) { CompressionInventoryPart spiedPart = spy(new CompressionInventoryPart(invHandler, slotRange, getMemorySettings)); doReturn(Optional.empty()).when(spiedPart).getDecompressionResultFromConfig(any(Item.class)); spiedPart.onInit(); @@ -588,7 +588,7 @@ void extractItemAllowsDifferentItemToBeInsertedIfExtractedFully() { Map slotStacksInput = Map.of(0, new ItemStack(Items.IRON_BLOCK, 63), 1, ItemStack.EMPTY, 2, ItemStack.EMPTY); InventoryHandler invHandler = getFilledInventoryHandler(slotStacksInput, 64); - CompressionInventoryPart part = initCompressionInventoryPart(invHandler, new InventoryPartitioner.SlotRange(0, 3), () -> getMemorySettings(invHandler, Map.of())); + CompressionInventoryPart part = initCompressionInventoryPart(invHandler, new SlotRange(0, 3), () -> getMemorySettings(invHandler, Map.of())); part.extractItem(0, 63, false); ItemStack insertResult = part.insertItem(1, new ItemStack(Items.GOLD_NUGGET, 10), false, (s, st, sim) -> ItemStack.EMPTY); @@ -602,7 +602,7 @@ void extractItemDoesntAllowDifferentInMemorizedSlotsEvenIfExtractedFully() { MemorySettingsCategory memorySettings = getMemorySettings(invHandler, Map.of()); when(memorySettings.getSlotFilterStack(eq(0), anyBoolean())).thenReturn(Optional.of(new ItemStack(Items.IRON_BLOCK))); - CompressionInventoryPart part = initCompressionInventoryPart(invHandler, new InventoryPartitioner.SlotRange(0, 3), () -> memorySettings); + CompressionInventoryPart part = initCompressionInventoryPart(invHandler, new SlotRange(0, 3), () -> memorySettings); part.extractItem(0, 32, false); assertStackEquals(new ItemStack(Items.GOLD_BLOCK, 32), part.insertItem(1, new ItemStack(Items.GOLD_BLOCK, 32), true, (s, st, sim) -> ItemStack.EMPTY), "Insert result does not equal"); @@ -614,7 +614,7 @@ void properlyInitializesItemsBasedOnMemorizedSlots() { MemorySettingsCategory memorySettings = getMemorySettings(invHandler, Map.of()); when(memorySettings.getSlotFilterStack(1, true)).thenReturn(Optional.of(new ItemStack(Items.IRON_BLOCK))); - CompressionInventoryPart part = initCompressionInventoryPart(invHandler, new InventoryPartitioner.SlotRange(0, 3), () -> memorySettings); + CompressionInventoryPart part = initCompressionInventoryPart(invHandler, new SlotRange(0, 3), () -> memorySettings); assertStackEquals(new ItemStack(Items.GOLD_BLOCK, 32), part.insertItem(1, new ItemStack(Items.GOLD_BLOCK, 32), true, (s, st, sim) -> ItemStack.EMPTY), "Insert result does not equal"); assertStackEquals(ItemStack.EMPTY, part.insertItem(1, new ItemStack(Items.IRON_BLOCK, 32), true, (s, st, sim) -> ItemStack.EMPTY), "Insert result does not equal"); @@ -677,7 +677,7 @@ void puttingDamagedDecompressibleItemInDoesntHealIt() { InventoryHandler invHandler = getFilledInventoryHandler(Map.of(0, ItemStack.EMPTY, 1, ItemStack.EMPTY, 2, ItemStack.EMPTY), 64); int minSlot = 0; - CompressionInventoryPart part = initCompressionInventoryPart(invHandler, new InventoryPartitioner.SlotRange(minSlot, minSlot + 3), () -> getMemorySettings(invHandler, Map.of())); + CompressionInventoryPart part = initCompressionInventoryPart(invHandler, new SlotRange(minSlot, minSlot + 3), () -> getMemorySettings(invHandler, Map.of())); ItemStack damagedItem = new ItemStack(Items.NETHERITE_AXE); damagedItem.setDamageValue(10); @@ -692,7 +692,7 @@ void initializingWithDamagedDecompressibleItemDoesntHealIt() { damagedItem.setDamageValue(10); InventoryHandler invHandler = getFilledInventoryHandler(Map.of(0, ItemStack.EMPTY, 1, damagedItem, 2, ItemStack.EMPTY), 64); - CompressionInventoryPart part = initCompressionInventoryPart(invHandler, new InventoryPartitioner.SlotRange(0, 3), () -> getMemorySettings(invHandler, Map.of())); + CompressionInventoryPart part = initCompressionInventoryPart(invHandler, new SlotRange(0, 3), () -> getMemorySettings(invHandler, Map.of())); assertStackEquals(damagedItem, part.getStackInSlot(1, s -> ItemStack.EMPTY), "Damaged item doesn't match"); } @@ -705,7 +705,7 @@ void extractingDecompressibleItemWorks() { InventoryHandler invHandler = getFilledInventoryHandler(Map.of(0, ItemStack.EMPTY, 1, damagedItem, 2, ItemStack.EMPTY), 64); int minSlot = 0; - CompressionInventoryPart part = initCompressionInventoryPart(invHandler, new InventoryPartitioner.SlotRange(minSlot, minSlot + 3), () -> getMemorySettings(invHandler, Map.of())); + CompressionInventoryPart part = initCompressionInventoryPart(invHandler, new SlotRange(minSlot, minSlot + 3), () -> getMemorySettings(invHandler, Map.of())); ItemStack damagedItemToMatch = new ItemStack(Items.NETHERITE_AXE); damagedItemToMatch.setDamageValue(10); @@ -717,7 +717,7 @@ void extractingPartOfDecompressibleStackCorrectlyLeavesTheRestIn() { InventoryHandler invHandler = getFilledInventoryHandler(Map.of(0, ItemStack.EMPTY, 1, new ItemStack(Items.COBBLESTONE, 10), 2, ItemStack.EMPTY), 64); int minSlot = 0; - CompressionInventoryPart part = initCompressionInventoryPart(invHandler, new InventoryPartitioner.SlotRange(minSlot, minSlot + 3), () -> getMemorySettings(invHandler, Map.of())); + CompressionInventoryPart part = initCompressionInventoryPart(invHandler, new SlotRange(minSlot, minSlot + 3), () -> getMemorySettings(invHandler, Map.of())); assertStackEquals(new ItemStack(Items.COBBLESTONE, 1), part.extractItem(1, 1, false), "Extracted item doesn't match"); assertStackEquals(new ItemStack(Items.COBBLESTONE, 9), part.getStackInSlot(1, s -> ItemStack.EMPTY), "Item left in slot doesn't match"); @@ -729,7 +729,7 @@ void stackLimitsAreSetCorrectlyOnInit(StackLimitsAreSetCorrectlyOnInitParams par InventoryHandler invHandler = getFilledInventoryHandler(params.stacks(), params.baseLimit()); int minSlot = 0; - CompressionInventoryPart part = initCompressionInventoryPart(invHandler, new InventoryPartitioner.SlotRange(minSlot, minSlot + params.stacks().size()), () -> getMemorySettings(invHandler, Map.of())); + CompressionInventoryPart part = initCompressionInventoryPart(invHandler, new SlotRange(minSlot, minSlot + params.stacks().size()), () -> getMemorySettings(invHandler, Map.of())); params.expectedLimits().forEach((slot, stackLimit) -> assertEquals(stackLimit.getRight(), part.getStackLimit(slot, stackLimit.getLeft()), "Stack limit doesn't match")); } @@ -777,7 +777,7 @@ void insertingAdditionalUncompressibleItemsProperlyCalculatesCount(InsertingAddi InventoryHandler invHandler = getFilledInventoryHandler(params.stacks(), params.baseLimit()); int minSlot = 0; - CompressionInventoryPart part = initCompressionInventoryPart(invHandler, new InventoryPartitioner.SlotRange(minSlot, minSlot + params.stacks().size()), () -> getMemorySettings(invHandler, Map.of())); + CompressionInventoryPart part = initCompressionInventoryPart(invHandler, new SlotRange(minSlot, minSlot + params.stacks().size()), () -> getMemorySettings(invHandler, Map.of())); part.insertItem(params.insertedStack.getLeft(), params.insertedStack.getRight(), false, (slot, itemStack, simulate) -> ItemStack.EMPTY); @@ -820,7 +820,7 @@ void extractingFromFullyFilledSlotsProperlyCalculatesCounts(ExtractingFromFullyF InventoryHandler invHandler = getFilledInventoryHandler(params.stacks(), params.baseLimit()); int minSlot = 0; - CompressionInventoryPart part = initCompressionInventoryPart(invHandler, new InventoryPartitioner.SlotRange(minSlot, minSlot + params.stacks().size()), () -> getMemorySettings(invHandler, Map.of())); + CompressionInventoryPart part = initCompressionInventoryPart(invHandler, new SlotRange(minSlot, minSlot + params.stacks().size()), () -> getMemorySettings(invHandler, Map.of())); part.extractItem(params.extractedStack.getLeft(), params.extractedStack.getRight(), false); @@ -874,7 +874,7 @@ void initializingWithPartiallyNonCompressibleItemsDoesntCrashAndAllowsAccessToNo InventoryHandler invHandler = getFilledInventoryHandler(params.stacks(), params.baseLimit()); int minSlot = 0; - CompressionInventoryPart part = initCompressionInventoryPart(invHandler, new InventoryPartitioner.SlotRange(minSlot, minSlot + params.stacks().size()), () -> getMemorySettings(invHandler, Map.of())); + CompressionInventoryPart part = initCompressionInventoryPart(invHandler, new SlotRange(minSlot, minSlot + params.stacks().size()), () -> getMemorySettings(invHandler, Map.of())); assertCalculatedStacks(params.calculatedStacks(), 0, part); }