From 4ff86faf913caac8b938ab1d7c14075d73c61904 Mon Sep 17 00:00:00 2001 From: Jottyfan Date: Mon, 28 Nov 2022 23:22:22 +0100 Subject: [PATCH] filter for the block stacker --- gradle.properties | 2 +- .../quickiefabric/QuickieFabricClient.java | 10 +- .../blockentity/BlockStackerEntity.java | 123 +++++++++++- .../blocks/BlockStackerDown.java | 42 +++++ .../blocks/BlockStackerEast.java | 42 +++++ .../blocks/BlockStackerNorth.java | 42 +++++ .../blocks/BlockStackerSouth.java | 42 +++++ .../quickiefabric/blocks/BlockStackerUp.java | 42 +++++ .../blocks/BlockStackerWest.java | 42 +++++ .../blocks/help/BlockStacker.java | 3 +- .../container/BlockStackerInventory.java | 176 ++++++++++++++++++ .../container/BlockStackerScreen.java | 51 +++++ .../container/BlockStackerScreenHandler.java | 76 ++++++++ .../container/ImplementedInventory.java | 133 +++++++++++++ .../quickiefabric/init/RegistryManager.java | 7 +- 15 files changed, 817 insertions(+), 16 deletions(-) create mode 100644 src/main/java/de/jottyfan/minecraft/quickiefabric/container/BlockStackerInventory.java create mode 100644 src/main/java/de/jottyfan/minecraft/quickiefabric/container/BlockStackerScreen.java create mode 100644 src/main/java/de/jottyfan/minecraft/quickiefabric/container/BlockStackerScreenHandler.java create mode 100644 src/main/java/de/jottyfan/minecraft/quickiefabric/container/ImplementedInventory.java diff --git a/gradle.properties b/gradle.properties index 1751aa1..fdfc541 100644 --- a/gradle.properties +++ b/gradle.properties @@ -9,7 +9,7 @@ loader_version=0.14.9 # Mod Properties - mod_version = 1.19.2.0 + mod_version = 1.19.2.1 maven_group = de.jottyfan.minecraft archives_base_name = quickiefabric diff --git a/src/main/java/de/jottyfan/minecraft/quickiefabric/QuickieFabricClient.java b/src/main/java/de/jottyfan/minecraft/quickiefabric/QuickieFabricClient.java index f529d23..f8b1859 100644 --- a/src/main/java/de/jottyfan/minecraft/quickiefabric/QuickieFabricClient.java +++ b/src/main/java/de/jottyfan/minecraft/quickiefabric/QuickieFabricClient.java @@ -2,24 +2,26 @@ package de.jottyfan.minecraft.quickiefabric; import de.jottyfan.minecraft.quickiefabric.blocks.QuickieBlocks; import de.jottyfan.minecraft.quickiefabric.container.BackpackScreen; +import de.jottyfan.minecraft.quickiefabric.container.BlockStackerScreen; import de.jottyfan.minecraft.quickiefabric.init.RegistryManager; import net.fabricmc.api.ClientModInitializer; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.fabricmc.fabric.api.blockrenderlayer.v1.BlockRenderLayerMap; -import net.fabricmc.fabric.api.client.screenhandler.v1.ScreenRegistry; +import net.minecraft.client.gui.screen.ingame.HandledScreens; import net.minecraft.client.render.RenderLayer; /** - * + * * @author jotty * */ @Environment(EnvType.CLIENT) public class QuickieFabricClient implements ClientModInitializer { @Override - public void onInitializeClient() { - ScreenRegistry.register(RegistryManager.BACKPACK_SCREEN_HANDLER, BackpackScreen::new); + public void onInitializeClient() { + HandledScreens.register(RegistryManager.BACKPACK_SCREEN_HANDLER, BackpackScreen::new); + HandledScreens.register(RegistryManager.BLOCKSTACKER_SCREEN_HANDLER, BlockStackerScreen::new); // make cotton plant block transparent BlockRenderLayerMap.INSTANCE.putBlock(QuickieBlocks.COTTONPLANT, RenderLayer.getCutout()); } diff --git a/src/main/java/de/jottyfan/minecraft/quickiefabric/blockentity/BlockStackerEntity.java b/src/main/java/de/jottyfan/minecraft/quickiefabric/blockentity/BlockStackerEntity.java index f341b70..d258b4f 100644 --- a/src/main/java/de/jottyfan/minecraft/quickiefabric/blockentity/BlockStackerEntity.java +++ b/src/main/java/de/jottyfan/minecraft/quickiefabric/blockentity/BlockStackerEntity.java @@ -1,14 +1,28 @@ package de.jottyfan.minecraft.quickiefabric.blockentity; +import java.util.ArrayList; +import java.util.List; + import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import de.jottyfan.minecraft.quickiefabric.blocks.help.BlockStacker; +import de.jottyfan.minecraft.quickiefabric.container.BlockStackerScreenHandler; +import de.jottyfan.minecraft.quickiefabric.container.ImplementedInventory; import net.minecraft.block.BlockState; import net.minecraft.block.entity.BlockEntity; import net.minecraft.block.entity.LootableContainerBlockEntity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.inventory.Inventories; +import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.item.Items; +import net.minecraft.nbt.NbtCompound; +import net.minecraft.screen.NamedScreenHandlerFactory; +import net.minecraft.screen.ScreenHandler; +import net.minecraft.text.Text; +import net.minecraft.util.collection.DefaultedList; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; @@ -17,13 +31,55 @@ import net.minecraft.world.World; * @author jotty * */ -public class BlockStackerEntity extends BlockEntity { +public class BlockStackerEntity extends BlockEntity implements NamedScreenHandlerFactory, ImplementedInventory { private static final Logger LOGGER = LogManager.getLogger(BlockStackerEntity.class); + private final DefaultedList inventory = DefaultedList.ofSize(9, ItemStack.EMPTY); + public BlockStackerEntity(BlockPos blockPos, BlockState blockState) { super(QuickieFabricBlockEntity.BLOCKSTACKER_ENTITY, blockPos, blockState); } + @Override + public DefaultedList getItems() { + return inventory; + } + + @Override + public ScreenHandler createMenu(int syncId, PlayerInventory playerInventory, PlayerEntity player) { + return new BlockStackerScreenHandler(syncId, playerInventory, this); + } + + @Override + public Text getDisplayName() { + return Text.translatable(getCachedState().getBlock().getTranslationKey()); + } + @Override + public void readNbt(NbtCompound nbt) { + super.readNbt(nbt); + Inventories.readNbt(nbt, inventory); + } + + @Override + public void writeNbt(NbtCompound nbt) { + Inventories.writeNbt(nbt, inventory); + super.writeNbt(nbt); + } + + /** + * if whitelist, return true if current == pattern; return false otherwise + * + * @param current the current item stack + * @param pattern the item stack to compare with + * @param whitelist if true, filter only current == pattern, if false, filter + * all but that + * @return true or false + */ + public static final Boolean filter(ItemStack current, ItemStack pattern, Boolean whitelist) { + Boolean matches = pattern.getItem().equals(current.getItem()); + return whitelist ? matches : !matches; + } + public static void tick(World world, BlockPos pos, BlockState state, BlockStackerEntity entity) { if (!world.isClient) { pos.down(); @@ -35,13 +91,23 @@ public class BlockStackerEntity extends BlockEntity { if (sourceIsLootable && destIsLootable) { LootableContainerBlockEntity lootableSource = (LootableContainerBlockEntity) source; LootableContainerBlockEntity lootableDest = (LootableContainerBlockEntity) dest; - transferOneStack(lootableSource, lootableDest); + List checked = new ArrayList<>(); + Boolean found = false; + Item item = findNextItem(entity.getItems(), checked); + while(!found && item != null) { + checked.add(item); + Boolean whitelist = true; + found = transferOneStack(lootableSource, lootableDest, item, whitelist); + item = findNextItem(entity.getItems(), checked); + } } } } - private static final void transferOneStack(LootableContainerBlockEntity source, LootableContainerBlockEntity dest) { - Integer sourceSlot = findItemStackPos(source, false); + private static final Boolean transferOneStack(LootableContainerBlockEntity source, LootableContainerBlockEntity dest, + Item filterItem, Boolean whitelist) { + Boolean result = false; + Integer sourceSlot = findItemStackPos(source, filterItem, whitelist); if (sourceSlot != null && !Items.AIR.equals(source.getStack(sourceSlot).getItem())) { ItemStack sourceStack = source.getStack(sourceSlot); Integer destSlot = findItemStackPos(dest, sourceStack); @@ -51,21 +117,38 @@ public class BlockStackerEntity extends BlockEntity { Integer candidates = source.getStack(sourceSlot).getCount(); Integer travellers = candidates > free ? free : candidates; if (travellers > 0) { - LOGGER.debug("transfer {}/{} of {} from slot {} to slot {} on top of {} ones", travellers, candidates, source.getStack(sourceSlot).getItem().toString(), sourceSlot, destSlot, occupied); + LOGGER.debug("transfer {}/{} of {} from slot {} to slot {} on top of {} ones", travellers, candidates, + source.getStack(sourceSlot).getItem().toString(), sourceSlot, destSlot, occupied); source.getStack(sourceSlot).decrement(travellers); if (source.getStack(sourceSlot).getCount() < 1) { source.removeStack(sourceSlot); // make empty slots really empty } dest.getStack(destSlot).increment(travellers); + result = true; } } else { Integer destFreeSlot = findItemStackPos(dest, true); if (destFreeSlot != null) { - LOGGER.debug("transfer all of {} from slot {} to slot {}", source.getStack(sourceSlot).getItem().toString(), sourceSlot, destSlot); + LOGGER.debug("transfer all of {} from slot {} to slot {}", source.getStack(sourceSlot).getItem().toString(), + sourceSlot, destSlot); dest.setStack(destFreeSlot, source.removeStack(sourceSlot)); + result = true; } } } + return result; + } + + private static final Item findNextItem(List inventory, List exclude) { + for (ItemStack stack : inventory) { + if (!stack.isEmpty()) { + Item item = stack.getItem(); + if (!exclude.contains(item)) { + return item; + } + } + } + return null; } private static final Integer findItemStackPos(LootableContainerBlockEntity lcbe, ItemStack sourceStack) { @@ -73,7 +156,7 @@ public class BlockStackerEntity extends BlockEntity { while (counter > 0) { counter--; ItemStack stack = lcbe.getStack(counter); - if (stack.getItem().equals(sourceStack.getItem())) { + if (sourceStack.getItem().equals(stack.getItem())) { if (stack.getCount() < stack.getMaxCount()) { return counter; } @@ -93,4 +176,30 @@ public class BlockStackerEntity extends BlockEntity { } return null; } + + private static final Integer findItemStackPos(LootableContainerBlockEntity lcbe, Item item, Boolean whitelist) { + if (item == null) { + return findItemStackPos(lcbe, false); + } else { + if (whitelist == null) { + whitelist = true; + LOGGER.error("whitelist is null"); + } + Integer counter = lcbe.size(); + while (counter > 0) { + counter--; + ItemStack stack = lcbe.getStack(counter); + Boolean found = item.equals(stack.getItem()); + if (whitelist ? found : !found) { + return counter; + } + } + return null; + } + } + + @Override + public int size() { + return inventory.size(); + } } diff --git a/src/main/java/de/jottyfan/minecraft/quickiefabric/blocks/BlockStackerDown.java b/src/main/java/de/jottyfan/minecraft/quickiefabric/blocks/BlockStackerDown.java index 9f5c233..8efb340 100644 --- a/src/main/java/de/jottyfan/minecraft/quickiefabric/blocks/BlockStackerDown.java +++ b/src/main/java/de/jottyfan/minecraft/quickiefabric/blocks/BlockStackerDown.java @@ -14,8 +14,15 @@ import net.minecraft.block.Material; import net.minecraft.block.entity.BlockEntity; import net.minecraft.block.entity.BlockEntityTicker; import net.minecraft.block.entity.BlockEntityType; +import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.ItemStack; import net.minecraft.loot.context.LootContext.Builder; +import net.minecraft.screen.NamedScreenHandlerFactory; +import net.minecraft.screen.ScreenHandler; +import net.minecraft.util.ActionResult; +import net.minecraft.util.Hand; +import net.minecraft.util.ItemScatterer; +import net.minecraft.util.hit.BlockHitResult; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Direction; import net.minecraft.world.World; @@ -64,4 +71,39 @@ public class BlockStackerDown extends BlockWithEntity implements BlockStacker { return checkType(type, QuickieFabricBlockEntity.BLOCKSTACKER_ENTITY, (world1, pos, state1, be) -> BlockStackerEntity.tick(world1, pos, state1, be)); } + + @Override + public ActionResult onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, + BlockHitResult hit) { + if (!world.isClient) { + NamedScreenHandlerFactory screenHandlerFactory = state.createScreenHandlerFactory(world, pos); + if (screenHandlerFactory != null) { + player.openHandledScreen(screenHandlerFactory); + } + } + return ActionResult.SUCCESS; + } + + @Override + public void onStateReplaced(BlockState state, World world, BlockPos pos, BlockState newState, boolean moved) { + if (state.getBlock() != newState.getBlock()) { + BlockEntity blockEntity = world.getBlockEntity(pos); + if (blockEntity instanceof BlockStackerEntity) { + ItemScatterer.spawn(world, pos, (BlockStackerEntity) blockEntity); + // update comparators + world.updateComparators(pos, this); + } + super.onStateReplaced(state, world, pos, newState, moved); + } + } + + @Override + public boolean hasComparatorOutput(BlockState state) { + return true; + } + + @Override + public int getComparatorOutput(BlockState state, World world, BlockPos pos) { + return ScreenHandler.calculateComparatorOutput(world.getBlockEntity(pos)); + } } diff --git a/src/main/java/de/jottyfan/minecraft/quickiefabric/blocks/BlockStackerEast.java b/src/main/java/de/jottyfan/minecraft/quickiefabric/blocks/BlockStackerEast.java index 6898e24..6afd0a6 100644 --- a/src/main/java/de/jottyfan/minecraft/quickiefabric/blocks/BlockStackerEast.java +++ b/src/main/java/de/jottyfan/minecraft/quickiefabric/blocks/BlockStackerEast.java @@ -14,8 +14,15 @@ import net.minecraft.block.Material; import net.minecraft.block.entity.BlockEntity; import net.minecraft.block.entity.BlockEntityTicker; import net.minecraft.block.entity.BlockEntityType; +import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.ItemStack; import net.minecraft.loot.context.LootContext.Builder; +import net.minecraft.screen.NamedScreenHandlerFactory; +import net.minecraft.screen.ScreenHandler; +import net.minecraft.util.ActionResult; +import net.minecraft.util.Hand; +import net.minecraft.util.ItemScatterer; +import net.minecraft.util.hit.BlockHitResult; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Direction; import net.minecraft.world.World; @@ -64,4 +71,39 @@ public class BlockStackerEast extends BlockWithEntity implements BlockStacker { return checkType(type, QuickieFabricBlockEntity.BLOCKSTACKER_ENTITY, (world1, pos, state1, be) -> BlockStackerEntity.tick(world1, pos, state1, be)); } + + @Override + public ActionResult onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, + BlockHitResult hit) { + if (!world.isClient) { + NamedScreenHandlerFactory screenHandlerFactory = state.createScreenHandlerFactory(world, pos); + if (screenHandlerFactory != null) { + player.openHandledScreen(screenHandlerFactory); + } + } + return ActionResult.SUCCESS; + } + + @Override + public void onStateReplaced(BlockState state, World world, BlockPos pos, BlockState newState, boolean moved) { + if (state.getBlock() != newState.getBlock()) { + BlockEntity blockEntity = world.getBlockEntity(pos); + if (blockEntity instanceof BlockStackerEntity) { + ItemScatterer.spawn(world, pos, (BlockStackerEntity) blockEntity); + // update comparators + world.updateComparators(pos, this); + } + super.onStateReplaced(state, world, pos, newState, moved); + } + } + + @Override + public boolean hasComparatorOutput(BlockState state) { + return true; + } + + @Override + public int getComparatorOutput(BlockState state, World world, BlockPos pos) { + return ScreenHandler.calculateComparatorOutput(world.getBlockEntity(pos)); + } } diff --git a/src/main/java/de/jottyfan/minecraft/quickiefabric/blocks/BlockStackerNorth.java b/src/main/java/de/jottyfan/minecraft/quickiefabric/blocks/BlockStackerNorth.java index b59fff9..50e6981 100644 --- a/src/main/java/de/jottyfan/minecraft/quickiefabric/blocks/BlockStackerNorth.java +++ b/src/main/java/de/jottyfan/minecraft/quickiefabric/blocks/BlockStackerNorth.java @@ -14,8 +14,15 @@ import net.minecraft.block.Material; import net.minecraft.block.entity.BlockEntity; import net.minecraft.block.entity.BlockEntityTicker; import net.minecraft.block.entity.BlockEntityType; +import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.ItemStack; import net.minecraft.loot.context.LootContext.Builder; +import net.minecraft.screen.NamedScreenHandlerFactory; +import net.minecraft.screen.ScreenHandler; +import net.minecraft.util.ActionResult; +import net.minecraft.util.Hand; +import net.minecraft.util.ItemScatterer; +import net.minecraft.util.hit.BlockHitResult; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Direction; import net.minecraft.world.World; @@ -64,4 +71,39 @@ public class BlockStackerNorth extends BlockWithEntity implements BlockStacker { return checkType(type, QuickieFabricBlockEntity.BLOCKSTACKER_ENTITY, (world1, pos, state1, be) -> BlockStackerEntity.tick(world1, pos, state1, be)); } + + @Override + public ActionResult onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, + BlockHitResult hit) { + if (!world.isClient) { + NamedScreenHandlerFactory screenHandlerFactory = state.createScreenHandlerFactory(world, pos); + if (screenHandlerFactory != null) { + player.openHandledScreen(screenHandlerFactory); + } + } + return ActionResult.SUCCESS; + } + + @Override + public void onStateReplaced(BlockState state, World world, BlockPos pos, BlockState newState, boolean moved) { + if (state.getBlock() != newState.getBlock()) { + BlockEntity blockEntity = world.getBlockEntity(pos); + if (blockEntity instanceof BlockStackerEntity) { + ItemScatterer.spawn(world, pos, (BlockStackerEntity) blockEntity); + // update comparators + world.updateComparators(pos, this); + } + super.onStateReplaced(state, world, pos, newState, moved); + } + } + + @Override + public boolean hasComparatorOutput(BlockState state) { + return true; + } + + @Override + public int getComparatorOutput(BlockState state, World world, BlockPos pos) { + return ScreenHandler.calculateComparatorOutput(world.getBlockEntity(pos)); + } } diff --git a/src/main/java/de/jottyfan/minecraft/quickiefabric/blocks/BlockStackerSouth.java b/src/main/java/de/jottyfan/minecraft/quickiefabric/blocks/BlockStackerSouth.java index 8fa8d2e..75d8761 100644 --- a/src/main/java/de/jottyfan/minecraft/quickiefabric/blocks/BlockStackerSouth.java +++ b/src/main/java/de/jottyfan/minecraft/quickiefabric/blocks/BlockStackerSouth.java @@ -14,8 +14,15 @@ import net.minecraft.block.Material; import net.minecraft.block.entity.BlockEntity; import net.minecraft.block.entity.BlockEntityTicker; import net.minecraft.block.entity.BlockEntityType; +import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.ItemStack; import net.minecraft.loot.context.LootContext.Builder; +import net.minecraft.screen.NamedScreenHandlerFactory; +import net.minecraft.screen.ScreenHandler; +import net.minecraft.util.ActionResult; +import net.minecraft.util.Hand; +import net.minecraft.util.ItemScatterer; +import net.minecraft.util.hit.BlockHitResult; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Direction; import net.minecraft.world.World; @@ -64,4 +71,39 @@ public class BlockStackerSouth extends BlockWithEntity implements BlockStacker { return checkType(type, QuickieFabricBlockEntity.BLOCKSTACKER_ENTITY, (world1, pos, state1, be) -> BlockStackerEntity.tick(world1, pos, state1, be)); } + + @Override + public ActionResult onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, + BlockHitResult hit) { + if (!world.isClient) { + NamedScreenHandlerFactory screenHandlerFactory = state.createScreenHandlerFactory(world, pos); + if (screenHandlerFactory != null) { + player.openHandledScreen(screenHandlerFactory); + } + } + return ActionResult.SUCCESS; + } + + @Override + public void onStateReplaced(BlockState state, World world, BlockPos pos, BlockState newState, boolean moved) { + if (state.getBlock() != newState.getBlock()) { + BlockEntity blockEntity = world.getBlockEntity(pos); + if (blockEntity instanceof BlockStackerEntity) { + ItemScatterer.spawn(world, pos, (BlockStackerEntity) blockEntity); + // update comparators + world.updateComparators(pos, this); + } + super.onStateReplaced(state, world, pos, newState, moved); + } + } + + @Override + public boolean hasComparatorOutput(BlockState state) { + return true; + } + + @Override + public int getComparatorOutput(BlockState state, World world, BlockPos pos) { + return ScreenHandler.calculateComparatorOutput(world.getBlockEntity(pos)); + } } diff --git a/src/main/java/de/jottyfan/minecraft/quickiefabric/blocks/BlockStackerUp.java b/src/main/java/de/jottyfan/minecraft/quickiefabric/blocks/BlockStackerUp.java index aef7813..92ddaf8 100644 --- a/src/main/java/de/jottyfan/minecraft/quickiefabric/blocks/BlockStackerUp.java +++ b/src/main/java/de/jottyfan/minecraft/quickiefabric/blocks/BlockStackerUp.java @@ -14,8 +14,15 @@ import net.minecraft.block.Material; import net.minecraft.block.entity.BlockEntity; import net.minecraft.block.entity.BlockEntityTicker; import net.minecraft.block.entity.BlockEntityType; +import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.ItemStack; import net.minecraft.loot.context.LootContext.Builder; +import net.minecraft.screen.NamedScreenHandlerFactory; +import net.minecraft.screen.ScreenHandler; +import net.minecraft.util.ActionResult; +import net.minecraft.util.Hand; +import net.minecraft.util.ItemScatterer; +import net.minecraft.util.hit.BlockHitResult; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Direction; import net.minecraft.world.World; @@ -64,4 +71,39 @@ public class BlockStackerUp extends BlockWithEntity implements BlockStacker { return checkType(type, QuickieFabricBlockEntity.BLOCKSTACKER_ENTITY, (world1, pos, state1, be) -> BlockStackerEntity.tick(world1, pos, state1, be)); } + + @Override + public ActionResult onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, + BlockHitResult hit) { + if (!world.isClient) { + NamedScreenHandlerFactory screenHandlerFactory = state.createScreenHandlerFactory(world, pos); + if (screenHandlerFactory != null) { + player.openHandledScreen(screenHandlerFactory); + } + } + return ActionResult.SUCCESS; + } + + @Override + public void onStateReplaced(BlockState state, World world, BlockPos pos, BlockState newState, boolean moved) { + if (state.getBlock() != newState.getBlock()) { + BlockEntity blockEntity = world.getBlockEntity(pos); + if (blockEntity instanceof BlockStackerEntity) { + ItemScatterer.spawn(world, pos, (BlockStackerEntity) blockEntity); + // update comparators + world.updateComparators(pos, this); + } + super.onStateReplaced(state, world, pos, newState, moved); + } + } + + @Override + public boolean hasComparatorOutput(BlockState state) { + return true; + } + + @Override + public int getComparatorOutput(BlockState state, World world, BlockPos pos) { + return ScreenHandler.calculateComparatorOutput(world.getBlockEntity(pos)); + } } diff --git a/src/main/java/de/jottyfan/minecraft/quickiefabric/blocks/BlockStackerWest.java b/src/main/java/de/jottyfan/minecraft/quickiefabric/blocks/BlockStackerWest.java index 6d285de..5552c9d 100644 --- a/src/main/java/de/jottyfan/minecraft/quickiefabric/blocks/BlockStackerWest.java +++ b/src/main/java/de/jottyfan/minecraft/quickiefabric/blocks/BlockStackerWest.java @@ -14,8 +14,15 @@ import net.minecraft.block.Material; import net.minecraft.block.entity.BlockEntity; import net.minecraft.block.entity.BlockEntityTicker; import net.minecraft.block.entity.BlockEntityType; +import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.ItemStack; import net.minecraft.loot.context.LootContext.Builder; +import net.minecraft.screen.NamedScreenHandlerFactory; +import net.minecraft.screen.ScreenHandler; +import net.minecraft.util.ActionResult; +import net.minecraft.util.Hand; +import net.minecraft.util.ItemScatterer; +import net.minecraft.util.hit.BlockHitResult; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Direction; import net.minecraft.world.World; @@ -64,4 +71,39 @@ public class BlockStackerWest extends BlockWithEntity implements BlockStacker { return checkType(type, QuickieFabricBlockEntity.BLOCKSTACKER_ENTITY, (world1, pos, state1, be) -> BlockStackerEntity.tick(world1, pos, state1, be)); } + + @Override + public ActionResult onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, + BlockHitResult hit) { + if (!world.isClient) { + NamedScreenHandlerFactory screenHandlerFactory = state.createScreenHandlerFactory(world, pos); + if (screenHandlerFactory != null) { + player.openHandledScreen(screenHandlerFactory); + } + } + return ActionResult.SUCCESS; + } + + @Override + public void onStateReplaced(BlockState state, World world, BlockPos pos, BlockState newState, boolean moved) { + if (state.getBlock() != newState.getBlock()) { + BlockEntity blockEntity = world.getBlockEntity(pos); + if (blockEntity instanceof BlockStackerEntity) { + ItemScatterer.spawn(world, pos, (BlockStackerEntity) blockEntity); + // update comparators + world.updateComparators(pos, this); + } + super.onStateReplaced(state, world, pos, newState, moved); + } + } + + @Override + public boolean hasComparatorOutput(BlockState state) { + return true; + } + + @Override + public int getComparatorOutput(BlockState state, World world, BlockPos pos) { + return ScreenHandler.calculateComparatorOutput(world.getBlockEntity(pos)); + } } diff --git a/src/main/java/de/jottyfan/minecraft/quickiefabric/blocks/help/BlockStacker.java b/src/main/java/de/jottyfan/minecraft/quickiefabric/blocks/help/BlockStacker.java index 5bb3e81..7d62e2c 100644 --- a/src/main/java/de/jottyfan/minecraft/quickiefabric/blocks/help/BlockStacker.java +++ b/src/main/java/de/jottyfan/minecraft/quickiefabric/blocks/help/BlockStacker.java @@ -1,5 +1,6 @@ package de.jottyfan.minecraft.quickiefabric.blocks.help; +import net.minecraft.block.BlockEntityProvider; import net.minecraft.util.math.Direction; /** @@ -7,7 +8,7 @@ import net.minecraft.util.math.Direction; * @author jotty * */ -public interface BlockStacker { +public interface BlockStacker extends BlockEntityProvider { /** * define the source offset * diff --git a/src/main/java/de/jottyfan/minecraft/quickiefabric/container/BlockStackerInventory.java b/src/main/java/de/jottyfan/minecraft/quickiefabric/container/BlockStackerInventory.java new file mode 100644 index 0000000..eda79b1 --- /dev/null +++ b/src/main/java/de/jottyfan/minecraft/quickiefabric/container/BlockStackerInventory.java @@ -0,0 +1,176 @@ +package de.jottyfan.minecraft.quickiefabric.container; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import de.jottyfan.minecraft.quickiefabric.items.ItemBackpack; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.inventory.SimpleInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NbtCompound; +import net.minecraft.nbt.NbtElement; +import net.minecraft.nbt.NbtList; +import net.minecraft.sound.SoundCategory; +import net.minecraft.sound.SoundEvents; +import net.minecraft.util.Hand; + +/** + * + * @author jotty + * + */ +public class BlockStackerInventory extends SimpleInventory { + private static final String NBT_BLOCKSTACKER = "blockstacer"; + private static final String NBT_SLOT = "slot"; + private static final String NBT_ITEMS = "items"; + + private Hand hand; + + private BlockStackerInventory(NbtCompound tag, BlockStackerScreenHandler handler) { + super(1); + readItemsFromTag(super.size(), tag); + } + + public BlockStackerInventory(ItemStack stack) { + this(init(stack).getOrCreateNbt().getCompound(NBT_BLOCKSTACKER), null); + } + + public static final BlockStackerInventory getInventory(BlockStackerScreenHandler handler, PlayerEntity player, + ItemStack stack) { + return new BlockStackerInventory(init(stack).getOrCreateNbt().getCompound(NBT_BLOCKSTACKER), handler); + } + + private final static ItemStack init(ItemStack stack) { + if (stack != null) { + if (!stack.getOrCreateNbt().contains(NBT_BLOCKSTACKER)) { + stack.getOrCreateNbt().put(NBT_BLOCKSTACKER, new NbtCompound()); + } + } + return stack; + } + + @Override + public void onOpen(PlayerEntity player) { + super.onOpen(player); + player.playSound(SoundEvents.BLOCK_CHEST_OPEN, SoundCategory.PLAYERS, 1f, 1f); + } + + @Override + public void onClose(PlayerEntity player) { + super.onClose(player); + ItemStack stack = player.getStackInHand(hand); + if (stack != null) { + stack.getOrCreateNbt().put(NBT_BLOCKSTACKER, writeItemsToTag(super.size())); + } + player.getStackInHand(hand).setNbt(stack.getNbt()); + player.playSound(SoundEvents.BLOCK_CHEST_CLOSE, SoundCategory.PLAYERS, 1f, 1f); + } + + private void readItemsFromTag(Integer size, NbtCompound tag) { + NbtList listTag = tag.getList(NBT_ITEMS, NbtElement.COMPOUND_TYPE); + for (int i = 0; i < listTag.size(); ++i) { + NbtCompound compoundTag = listTag.getCompound(i); + int slot = compoundTag.getInt(NBT_SLOT); + if (slot >= 0 && slot < size) { + super.setStack(slot, ItemStack.fromNbt(compoundTag)); + } + } + } + + private NbtCompound writeItemsToTag(int slotsize) { + NbtList listTag = new NbtList(); + for (int slot = 0; slot < slotsize; ++slot) { + ItemStack itemStack = super.getStack(slot); + if (!(itemStack == null) && !itemStack.isEmpty()) { + listTag.add(prepareCompoundTag(slot, itemStack)); + } + } + NbtCompound tag = new NbtCompound(); + tag.put(NBT_ITEMS, listTag); + return tag; + } + + private static final NbtCompound prepareCompoundTag(Integer slot, ItemStack stack) { + NbtCompound compoundTag = new NbtCompound(); + compoundTag.putInt(NBT_SLOT, slot); + stack.writeNbt(compoundTag); + return compoundTag; + } + + public void setHand(Hand hand) { + this.hand = hand; + } + + /** + * get the items from the itemStack that contains the backpack + * + * @param itemStack the itemStack of the backpack + * @return the list of found itemStacks in the backpack + */ + public static List getItemsFromBackpack(ItemStack itemStack) { + NbtCompound backpackNbt = init(itemStack).getOrCreateNbt().getCompound(NBT_BLOCKSTACKER); + NbtList listTag = backpackNbt.getList(NBT_ITEMS, NbtElement.COMPOUND_TYPE); + List items = new ArrayList<>(); + for (int i = 0; i < listTag.size(); ++i) { + NbtCompound compoundTag = listTag.getCompound(i); + int slot = compoundTag.getInt(NBT_SLOT); + if (slot >= 0 && slot < ItemBackpack.SLOTSIZE) { + ItemStack stack = ItemStack.fromNbt(compoundTag); + items.add(stack); + } + } + return items; + } + + /** + * set the items in the itemStack that contains the backpack + * + * @param itemStack the backpack's itemStack + * @param itemStacks the collection of lists of itemStacks for the backpack + */ + public static void setItemsToBackpack(ItemStack itemStack, Collection> itemStacks) { + NbtList listTag = new NbtList(); + Integer slot = 0; + for (List stacks : itemStacks) { + if (stacks != null && stacks.size() > 0) { + ItemStack stack = stacks.get(0); + Integer leftCount = 0; + for (ItemStack is : stacks) { + leftCount += is.getCount(); + } + while (leftCount > 0) { + if (leftCount > stack.getMaxCount()) { + stack.setCount(stack.getMaxCount()); + leftCount = leftCount - stack.getMaxCount(); + } else { + stack.setCount(leftCount); + leftCount = 0; + } + listTag.add(prepareCompoundTag(slot, stack)); + slot++; + } + } + } + NbtCompound tag = new NbtCompound(); + tag.put(NBT_ITEMS, listTag); + itemStack.getOrCreateNbt().put(NBT_BLOCKSTACKER, tag); + } + + /** + * replace every slot of the backpack with the content of backpackInventory + * + * @param itemStack the backpack's itemStack + * @param backpackInventory the replacement inventory + */ + public static void setItemsToBackpack(ItemStack itemStack, BlockStackerInventory backpackInventory) { + Collection> itemStacks = new ArrayList<>(); + for (int i = 0; i < backpackInventory.size(); i++) { + ItemStack stack = backpackInventory.getStack(i); + List list = new ArrayList<>(); + list.add(stack); + itemStacks.add(list); + } + setItemsToBackpack(itemStack, itemStacks); + } +} diff --git a/src/main/java/de/jottyfan/minecraft/quickiefabric/container/BlockStackerScreen.java b/src/main/java/de/jottyfan/minecraft/quickiefabric/container/BlockStackerScreen.java new file mode 100644 index 0000000..4a406ea --- /dev/null +++ b/src/main/java/de/jottyfan/minecraft/quickiefabric/container/BlockStackerScreen.java @@ -0,0 +1,51 @@ +package de.jottyfan.minecraft.quickiefabric.container; + +import com.mojang.blaze3d.systems.RenderSystem; + +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.minecraft.client.gui.screen.ingame.HandledScreen; +import net.minecraft.client.gui.screen.ingame.ScreenHandlerProvider; +import net.minecraft.client.render.GameRenderer; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.text.Text; +import net.minecraft.util.Identifier; + +/** + * + * @author jotty + * + */ +@Environment(EnvType.CLIENT) +public class BlockStackerScreen extends HandledScreen + implements ScreenHandlerProvider { + private final static Identifier TEXTURE = new Identifier("minecraft", "textures/gui/container/dispenser.png"); + + public BlockStackerScreen(BlockStackerScreenHandler handler, PlayerInventory inventory, Text text) { + super(handler, inventory, text); + } + + @Override + protected void init() { + super.init(); + this.titleX = (backgroundWidth - textRenderer.getWidth(title)) / 2; + } + + @Override + public void render(MatrixStack matrices, int mouseX, int mouseY, float partialTicks) { + this.renderBackground(matrices); + super.render(matrices, mouseX, mouseY, partialTicks); + this.drawMouseoverTooltip(matrices, mouseX, mouseY); + } + + @Override + protected void drawBackground(MatrixStack matrices, float delta, int mouseX, int mouseY) { + RenderSystem.setShader(GameRenderer::getPositionTexShader); + RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F); + RenderSystem.setShaderTexture(0, TEXTURE); + int x = (width - backgroundWidth) / 2; + int y = (height - backgroundHeight) / 2; + drawTexture(matrices, x, y, 0, 0, backgroundWidth, backgroundHeight); + } +} diff --git a/src/main/java/de/jottyfan/minecraft/quickiefabric/container/BlockStackerScreenHandler.java b/src/main/java/de/jottyfan/minecraft/quickiefabric/container/BlockStackerScreenHandler.java new file mode 100644 index 0000000..71c0054 --- /dev/null +++ b/src/main/java/de/jottyfan/minecraft/quickiefabric/container/BlockStackerScreenHandler.java @@ -0,0 +1,76 @@ +package de.jottyfan.minecraft.quickiefabric.container; + +import de.jottyfan.minecraft.quickiefabric.init.RegistryManager; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.inventory.Inventory; +import net.minecraft.inventory.SimpleInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.screen.ScreenHandler; +import net.minecraft.screen.slot.Slot; + +/** + * + * @author jotty + * + */ +public class BlockStackerScreenHandler extends ScreenHandler { + + public static final Integer SLOTSIZE = 9; + + private final Inventory inventory; + + public BlockStackerScreenHandler(int syncId, PlayerInventory playerInventory) { + this(syncId, playerInventory, new SimpleInventory(SLOTSIZE)); + } + + public BlockStackerScreenHandler(int syncId, PlayerInventory playerInventory, Inventory inventory) { + super(RegistryManager.BLOCKSTACKER_SCREEN_HANDLER, syncId); + checkSize(inventory, SLOTSIZE); + this.inventory = inventory; + inventory.onOpen(playerInventory.player); + int m; + int l; + for (m = 0; m < 3; ++m) { + for (l = 0; l < 3; ++l) { + this.addSlot(new Slot(inventory, l + m * 3, 62 + l * 18, 17 + m * 18)); + } + } + for (m = 0; m < 3; ++m) { + for (l = 0; l < 9; ++l) { + this.addSlot(new Slot(playerInventory, l + m * 9 + 9, 8 + l * 18, 84 + m * 18)); + } + } + for (m = 0; m < 9; ++m) { + this.addSlot(new Slot(playerInventory, m, 8 + m * 18, 142)); + } + } + + @Override + public boolean canUse(PlayerEntity player) { + return this.inventory.canPlayerUse(player); + } + + @Override + public ItemStack transferSlot(PlayerEntity player, int invSlot) { + ItemStack newStack = ItemStack.EMPTY; + Slot slot = this.slots.get(invSlot); + if (slot != null && slot.hasStack()) { + ItemStack originalStack = slot.getStack(); + newStack = originalStack.copy(); + if (invSlot < this.inventory.size()) { + if (!this.insertItem(originalStack, this.inventory.size(), this.slots.size(), true)) { + return ItemStack.EMPTY; + } + } else if (!this.insertItem(originalStack, 0, this.inventory.size(), false)) { + return ItemStack.EMPTY; + } + if (originalStack.isEmpty()) { + slot.setStack(ItemStack.EMPTY); + } else { + slot.markDirty(); + } + } + return newStack; + } +} diff --git a/src/main/java/de/jottyfan/minecraft/quickiefabric/container/ImplementedInventory.java b/src/main/java/de/jottyfan/minecraft/quickiefabric/container/ImplementedInventory.java new file mode 100644 index 0000000..f6651ab --- /dev/null +++ b/src/main/java/de/jottyfan/minecraft/quickiefabric/container/ImplementedInventory.java @@ -0,0 +1,133 @@ +package de.jottyfan.minecraft.quickiefabric.container; + +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.inventory.Inventories; +import net.minecraft.inventory.Inventory; +import net.minecraft.item.ItemStack; +import net.minecraft.util.collection.DefaultedList; + +/** + * + * @author jotty + * + * @see https://fabricmc.net/wiki/tutorial:inventory + * + */ +public interface ImplementedInventory extends Inventory { + + /** + * Retrieves the item list of this inventory. + * Must return the same instance every time it's called. + */ + DefaultedList getItems(); + + /** + * Creates an inventory from the item list. + */ + static ImplementedInventory of(DefaultedList items) { + return () -> items; + } + + /** + * Creates a new inventory with the specified size. + */ + static ImplementedInventory ofSize(int size) { + return of(DefaultedList.ofSize(size, ItemStack.EMPTY)); + } + + /** + * Returns the inventory size. + */ + @Override + default int size() { + return getItems().size(); + } + + /** + * Checks if the inventory is empty. + * @return true if this inventory has only empty stacks, false otherwise. + */ + @Override + default boolean isEmpty() { + for (int i = 0; i < size(); i++) { + ItemStack stack = getStack(i); + if (!stack.isEmpty()) { + return false; + } + } + return true; + } + + /** + * Retrieves the item in the slot. + */ + @Override + default ItemStack getStack(int slot) { + return getItems().get(slot); + } + + /** + * Removes items from an inventory slot. + * @param slot The slot to remove from. + * @param count How many items to remove. If there are less items in the slot than what are requested, + * takes all items in that slot. + */ + @Override + default ItemStack removeStack(int slot, int count) { + ItemStack result = Inventories.splitStack(getItems(), slot, count); + if (!result.isEmpty()) { + markDirty(); + } + return result; + } + + /** + * Removes all items from an inventory slot. + * @param slot The slot to remove from. + */ + @Override + default ItemStack removeStack(int slot) { + return Inventories.removeStack(getItems(), slot); + } + + /** + * Replaces the current stack in an inventory slot with the provided stack. + * @param slot The inventory slot of which to replace the itemstack. + * @param stack The replacing itemstack. If the stack is too big for + * this inventory ({@link Inventory#getMaxCountPerStack()}), + * it gets resized to this inventory's maximum amount. + */ + @Override + default void setStack(int slot, ItemStack stack) { + getItems().set(slot, stack); + if (stack.getCount() > stack.getMaxCount()) { + stack.setCount(stack.getMaxCount()); + } + } + + /** + * Clears the inventory. + */ + @Override + default void clear() { + getItems().clear(); + } + + /** + * Marks the state as dirty. + * Must be called after changes in the inventory, so that the game can properly save + * the inventory contents and notify neighboring blocks of inventory changes. + */ + @Override + default void markDirty() { + // Override if you want behavior. + } + + /** + * @return true if the player can use the inventory, false otherwise. + */ + @Override + default boolean canPlayerUse(PlayerEntity player) { + return true; + } +} \ No newline at end of file diff --git a/src/main/java/de/jottyfan/minecraft/quickiefabric/init/RegistryManager.java b/src/main/java/de/jottyfan/minecraft/quickiefabric/init/RegistryManager.java index 59bde2a..0281eb1 100644 --- a/src/main/java/de/jottyfan/minecraft/quickiefabric/init/RegistryManager.java +++ b/src/main/java/de/jottyfan/minecraft/quickiefabric/init/RegistryManager.java @@ -6,7 +6,6 @@ import java.util.function.Predicate; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import de.jottyfan.minecraft.quickiefabric.blockentity.BlockSpreaderEntity; import de.jottyfan.minecraft.quickiefabric.blockentity.BlockStackerEntity; import de.jottyfan.minecraft.quickiefabric.blockentity.DrillBlockDownEntity; import de.jottyfan.minecraft.quickiefabric.blockentity.DrillBlockEastEntity; @@ -19,6 +18,7 @@ import de.jottyfan.minecraft.quickiefabric.blockentity.MonsterHoarderBlockEntity import de.jottyfan.minecraft.quickiefabric.blockentity.QuickieFabricBlockEntity; import de.jottyfan.minecraft.quickiefabric.blocks.QuickieBlocks; import de.jottyfan.minecraft.quickiefabric.container.BackpackScreenHandler; +import de.jottyfan.minecraft.quickiefabric.container.BlockStackerScreenHandler; import de.jottyfan.minecraft.quickiefabric.event.BreakBlockCallback; import de.jottyfan.minecraft.quickiefabric.event.EventBlockBreak; import de.jottyfan.minecraft.quickiefabric.items.QuickieItems; @@ -72,6 +72,9 @@ public class RegistryManager { public static final Identifier BACKPACK_IDENTIFIER = new Identifier(QUICKIEFABRIC, "backpack"); public static final ScreenHandlerType BACKPACK_SCREEN_HANDLER = ScreenHandlerRegistry .registerExtended(RegistryManager.BACKPACK_IDENTIFIER, BackpackScreenHandler::new); + public static final Identifier STACKER_IDENTIFIER = new Identifier(QUICKIEFABRIC, "stacker"); + public static final ScreenHandlerType BLOCKSTACKER_SCREEN_HANDLER = ScreenHandlerRegistry + .registerSimple(RegistryManager.STACKER_IDENTIFIER, BlockStackerScreenHandler::new); @SuppressWarnings("unchecked") public static final ConfiguredFeature CF_ORESULPHOR = new ConfiguredFeature(Feature.ORE, new OreFeatureConfig( @@ -216,8 +219,6 @@ public class RegistryManager { "blockstackerentity", BlockStackerEntity::new, QuickieBlocks.BLOCKSTACKERUP, QuickieBlocks.BLOCKSTACKERDOWN, QuickieBlocks.BLOCKSTACKEREAST, QuickieBlocks.BLOCKSTACKERWEST, QuickieBlocks.BLOCKSTACKERNORTH, QuickieBlocks.BLOCKSTACKERSOUTH); - QuickieFabricBlockEntity.BLOCKSPREADER_ENTITY = (BlockEntityType) registerBlockEntity( - "blockspreaderentity", BlockSpreaderEntity::new, QuickieBlocks.BLOCKSPREADER); } public static final void registerBlocks() {