From dc30a395f4cec40d4c4e2426c9e547b7ac132363 Mon Sep 17 00:00:00 2001 From: Jottyfan Date: Sun, 28 Dec 2025 20:34:43 +0100 Subject: [PATCH] itemhoarder sucks, but items get lost on harvesting block --- ...Lavahoarder.java => EmptyLavahoarder.java} | 18 +- .../jottyfan/minecraft/block/Itemhoarder.java | 67 ++++++++ ...BlockLavahoarder.java => Lavahoarder.java} | 4 +- ...onsterhoarder.java => Monsterhoarder.java} | 4 +- .../minecraft/block/QuicklyBlocks.java | 23 ++- .../blockentity/ItemHoarderBlockEntity.java | 154 ++++++++++++++++++ .../quickly/blockstates/itemhoarder.json | 7 + .../assets/quickly/items/itemhoarder.json | 6 + .../quickly/models/block/itemhoarder.json | 6 + .../quickly/models/item/itemhoarder.json | 10 ++ .../quickly/textures/block/itemhoarder.png | Bin 0 -> 2894 bytes .../shaped_itemhoarder_from_barrel.json | 16 ++ .../recipe/shaped_itemhoarder_from_chest.json | 16 ++ 13 files changed, 315 insertions(+), 16 deletions(-) rename src/main/java/de/jottyfan/minecraft/block/{BlockEmptyLavahoarder.java => EmptyLavahoarder.java} (86%) create mode 100644 src/main/java/de/jottyfan/minecraft/block/Itemhoarder.java rename src/main/java/de/jottyfan/minecraft/block/{BlockLavahoarder.java => Lavahoarder.java} (97%) rename src/main/java/de/jottyfan/minecraft/block/{BlockMonsterhoarder.java => Monsterhoarder.java} (97%) create mode 100644 src/main/java/de/jottyfan/minecraft/blockentity/ItemHoarderBlockEntity.java create mode 100644 src/main/resources/assets/quickly/blockstates/itemhoarder.json create mode 100644 src/main/resources/assets/quickly/items/itemhoarder.json create mode 100644 src/main/resources/assets/quickly/models/block/itemhoarder.json create mode 100644 src/main/resources/assets/quickly/models/item/itemhoarder.json create mode 100644 src/main/resources/assets/quickly/textures/block/itemhoarder.png create mode 100644 src/main/resources/data/quickly/recipe/shaped_itemhoarder_from_barrel.json create mode 100644 src/main/resources/data/quickly/recipe/shaped_itemhoarder_from_chest.json diff --git a/src/main/java/de/jottyfan/minecraft/block/BlockEmptyLavahoarder.java b/src/main/java/de/jottyfan/minecraft/block/EmptyLavahoarder.java similarity index 86% rename from src/main/java/de/jottyfan/minecraft/block/BlockEmptyLavahoarder.java rename to src/main/java/de/jottyfan/minecraft/block/EmptyLavahoarder.java index d82e7d6..2c29ada 100644 --- a/src/main/java/de/jottyfan/minecraft/block/BlockEmptyLavahoarder.java +++ b/src/main/java/de/jottyfan/minecraft/block/EmptyLavahoarder.java @@ -21,9 +21,9 @@ import net.minecraft.world.level.storage.loot.LootParams.Builder; * @author jotty * */ -public class BlockEmptyLavahoarder extends Block { +public class EmptyLavahoarder extends Block { - public BlockEmptyLavahoarder(Properties properties) { + public EmptyLavahoarder(Properties properties) { super(properties); } @@ -36,12 +36,12 @@ public class BlockEmptyLavahoarder extends Block { @Override protected void tick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) { - boolean found = BlockLavahoarder.suckLava(level, pos.north()); - found = found || BlockLavahoarder.suckLava(level, pos.south()); - found = found || BlockLavahoarder.suckLava(level, pos.east()); - found = found || BlockLavahoarder.suckLava(level, pos.west()); - found = found || BlockLavahoarder.suckLava(level, pos.above()); - found = found || BlockLavahoarder.suckLava(level, pos.below()); + boolean found = Lavahoarder.suckLava(level, pos.north()); + found = found || Lavahoarder.suckLava(level, pos.south()); + found = found || Lavahoarder.suckLava(level, pos.east()); + found = found || Lavahoarder.suckLava(level, pos.west()); + found = found || Lavahoarder.suckLava(level, pos.above()); + found = found || Lavahoarder.suckLava(level, pos.below()); if (found) { level.setBlock(pos, QuicklyBlocks.LAVAHOARDER.defaultBlockState(), 2); level.scheduleTick(pos, QuicklyBlocks.LAVAHOARDER, 1); @@ -116,7 +116,7 @@ public class BlockEmptyLavahoarder extends Block { } } if (count > 0) { - BlockLavahoarder.spawnRandomItems(level, pos.above(), count); + Lavahoarder.spawnRandomItems(level, pos.above(), count); } } else { level.scheduleTick(pos, this, 1); diff --git a/src/main/java/de/jottyfan/minecraft/block/Itemhoarder.java b/src/main/java/de/jottyfan/minecraft/block/Itemhoarder.java new file mode 100644 index 0000000..a1b2f62 --- /dev/null +++ b/src/main/java/de/jottyfan/minecraft/block/Itemhoarder.java @@ -0,0 +1,67 @@ +package de.jottyfan.minecraft.block; + +import java.util.ArrayList; +import java.util.List; + +import org.jspecify.annotations.Nullable; + +import de.jottyfan.minecraft.blockentity.ItemHoarderBlockEntity; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.entity.item.ItemEntity; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.EntityBlock; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityTicker; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.storage.loot.LootParams.Builder; + +/** + * + * @author jotty + * + */ +public class Itemhoarder extends Block implements EntityBlock { + + public Itemhoarder(Properties properties) { + super(properties.strength(2.5f)); + } + + @Override + public @Nullable BlockEntity newBlockEntity(BlockPos pos, BlockState blockState) { + return new ItemHoarderBlockEntity(pos, blockState); + } + + @Nullable + @Override + public BlockEntityTicker getTicker(Level level, BlockState state, + BlockEntityType type) { + return level.isClientSide() ? null : (lvl, pos, st, be) -> { + if (be instanceof ItemHoarderBlockEntity ihbe) { + ItemHoarderBlockEntity.tick(lvl, pos, st, ihbe); + } + }; + } + + @Override + protected List getDrops(BlockState state, Builder params) { + List list = new ArrayList<>(); + list.add(new ItemStack(QuicklyBlocks.ITEMHOARDER)); + return list; + } + + @Override + protected void spawnAfterBreak(BlockState state, ServerLevel level, BlockPos pos, ItemStack tool, + boolean dropExperience) { + BlockEntity blockEntity = level.getBlockEntity(pos); + if (blockEntity instanceof ItemHoarderBlockEntity) { + ItemHoarderBlockEntity ihbe = (ItemHoarderBlockEntity) blockEntity; + for (ItemStack stack : ihbe.getStacks().values()) { + level.addFreshEntity(new ItemEntity(level, pos.getX(), pos.getY(), pos.getZ(), stack)); + } + } + } +} diff --git a/src/main/java/de/jottyfan/minecraft/block/BlockLavahoarder.java b/src/main/java/de/jottyfan/minecraft/block/Lavahoarder.java similarity index 97% rename from src/main/java/de/jottyfan/minecraft/block/BlockLavahoarder.java rename to src/main/java/de/jottyfan/minecraft/block/Lavahoarder.java index e1bf4a7..5d6f12e 100644 --- a/src/main/java/de/jottyfan/minecraft/block/BlockLavahoarder.java +++ b/src/main/java/de/jottyfan/minecraft/block/Lavahoarder.java @@ -27,9 +27,9 @@ import net.minecraft.world.phys.BlockHitResult; * @author jotty * */ -public class BlockLavahoarder extends Block { +public class Lavahoarder extends Block { - public BlockLavahoarder(Properties properties) { + public Lavahoarder(Properties properties) { super(properties); } diff --git a/src/main/java/de/jottyfan/minecraft/block/BlockMonsterhoarder.java b/src/main/java/de/jottyfan/minecraft/block/Monsterhoarder.java similarity index 97% rename from src/main/java/de/jottyfan/minecraft/block/BlockMonsterhoarder.java rename to src/main/java/de/jottyfan/minecraft/block/Monsterhoarder.java index 2a6dabb..3bbff70 100644 --- a/src/main/java/de/jottyfan/minecraft/block/BlockMonsterhoarder.java +++ b/src/main/java/de/jottyfan/minecraft/block/Monsterhoarder.java @@ -31,7 +31,7 @@ import net.minecraft.world.ticks.ScheduledTick; * @author jotty * */ -public class BlockMonsterhoarder extends Block { +public class Monsterhoarder extends Block { private static final Integer MINSUCKRADIUS = 2; private static final Integer MAXSUCKRADIUS = 20; @@ -40,7 +40,7 @@ public class BlockMonsterhoarder extends Block { private static final IntegerProperty SUCKRADIUS = IntegerProperty.create("suckradius", MINSUCKRADIUS, MAXSUCKRADIUS); private static final IntegerProperty BURNTICKS = IntegerProperty.create("burnticks", MINBURNTICKS, MAXBURNTICKS); - public BlockMonsterhoarder(Properties properties) { + public Monsterhoarder(Properties properties) { super(properties.strength(2.5f).lightLevel(state -> state.getValue(SUCKRADIUS))); registerDefaultState(stateDefinition.any().setValue(SUCKRADIUS, MINSUCKRADIUS).setValue(BURNTICKS, MINBURNTICKS)); } diff --git a/src/main/java/de/jottyfan/minecraft/block/QuicklyBlocks.java b/src/main/java/de/jottyfan/minecraft/block/QuicklyBlocks.java index 1bbbc0e..ccfa745 100644 --- a/src/main/java/de/jottyfan/minecraft/block/QuicklyBlocks.java +++ b/src/main/java/de/jottyfan/minecraft/block/QuicklyBlocks.java @@ -3,9 +3,12 @@ package de.jottyfan.minecraft.block; import java.util.function.Function; import de.jottyfan.minecraft.Quickly; +import de.jottyfan.minecraft.blockentity.ItemHoarderBlockEntity; import de.jottyfan.minecraft.item.QuicklyItems; import de.jottyfan.minecraft.tab.QuicklyTab; import net.fabricmc.fabric.api.itemgroup.v1.ItemGroupEvents; +import net.fabricmc.fabric.api.object.builder.v1.block.entity.FabricBlockEntityTypeBuilder; +import net.fabricmc.fabric.api.object.builder.v1.block.entity.FabricBlockEntityTypeBuilder.Factory; import net.minecraft.core.Registry; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.core.registries.Registries; @@ -18,6 +21,8 @@ import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.SoundType; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockBehaviour.Properties; /** @@ -40,15 +45,26 @@ public class QuicklyBlocks { public static final Block CANOLAPLANT = registerBlock("blockcanolaplant", Properties.ofFullCopy(Blocks.WHEAT), properties -> new BlockPlant(properties, "canolaseed", "canola")); public static final Block LAVAHOARDER = registerBlock("lavahoarder", - Properties.of().strength(2.5f).lightLevel(state -> 15), properties -> new BlockLavahoarder(properties)); + Properties.of().strength(2.5f).lightLevel(_ -> 15), properties -> new Lavahoarder(properties)); public static final Block EMPTYLAVAHOARDER = registerBlock("emptylavahoarder", Properties.of().strength(2.5f), - properties -> new BlockEmptyLavahoarder(properties)); + properties -> new EmptyLavahoarder(properties)); public static final Block QUICKIEPOWDER = registerBlock("blockquickiepowder", properties -> new BlockDrops(properties, new ItemStack(QuicklyItems.QUICKIEPOWDER, 9))); public static final Block SPEEDPOWDER = registerBlock("blockspeedpowder", properties -> new BlockDrops(properties, new ItemStack(QuicklyItems.SPEEDPOWDER, 9))); public static final Block MONSTERHOARDER = registerBlock("monsterhoarder", - properties -> new BlockMonsterhoarder(properties)); + properties -> new Monsterhoarder(properties)); + public static final Block ITEMHOARDER = registerBlock("itemhoarder", properties -> new Itemhoarder(properties)); + + public static final BlockEntityType BLOCKENTITY_ITEMHOARDER = (BlockEntityType) registerBlockEntity("itemhoarderblockentity", ItemHoarderBlockEntity::new, ITEMHOARDER); + + private static final BlockEntityType registerBlockEntity(String name, Factory factory, Block block) { + return Registry.register( + BuiltInRegistries.BLOCK_ENTITY_TYPE, + Identifier.fromNamespaceAndPath(Quickly.MOD_ID, name), + FabricBlockEntityTypeBuilder.create(factory, block).build() + ); + } private static final Block registerBlock(String name, Properties properties) { return QuicklyBlocks.registerBlock(name, properties, p -> new Block(p)); @@ -78,6 +94,7 @@ public class QuicklyBlocks { block.accept(SPEEDPOWDER); block.accept(QUICKIEPOWDER); block.accept(MONSTERHOARDER); + block.accept(ITEMHOARDER); }); } } diff --git a/src/main/java/de/jottyfan/minecraft/blockentity/ItemHoarderBlockEntity.java b/src/main/java/de/jottyfan/minecraft/blockentity/ItemHoarderBlockEntity.java new file mode 100644 index 0000000..e822a95 --- /dev/null +++ b/src/main/java/de/jottyfan/minecraft/blockentity/ItemHoarderBlockEntity.java @@ -0,0 +1,154 @@ +package de.jottyfan.minecraft.blockentity; + +import java.util.HashMap; +import java.util.Map; + +import com.mojang.serialization.Codec; + +import de.jottyfan.minecraft.Quickly; +import de.jottyfan.minecraft.block.QuicklyBlocks; +import net.minecraft.core.BlockPos; +import net.minecraft.world.Container; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.item.ItemEntity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.storage.ValueInput; +import net.minecraft.world.level.storage.ValueOutput; +import net.minecraft.world.phys.AABB; + +/** + * + * @author jotty + * + */ +public class ItemHoarderBlockEntity extends BlockEntity implements Container { + + public static final Codec> ITEM_STACK_MAP_CODEC = + Codec.unboundedMap(Codec.STRING, ItemStack.CODEC); + + private Map stacks = new HashMap<>(); + private static final Integer suckradius = 4; + + public ItemHoarderBlockEntity(BlockPos pos, BlockState state) { + super(QuicklyBlocks.BLOCKENTITY_ITEMHOARDER, pos, state); + } + + private static final String getItemId(Item item) { + return item.getName().getString(); + } + + public final static boolean setStackToSlots(ItemStack stack, Map stacks) { + if (stack.isEmpty()) { + Quickly.LOGGER.info("FATAL!!! tried to set empty stack. Check your code!"); + return false; + } + String key = getItemId(stack.getItem()); + ItemStack s = stacks.get(key); + if (s == null) { + stacks.put(key, stack); + Quickly.LOGGER.info("stored {} x {}", stack.getCount(), key); + } else { + stacks.get(key).grow(stack.getCount()); + Quickly.LOGGER.info("added {} x {}", stack.getCount(), key); + } + return true; + } + + private static final void suck(Level level, BlockPos pos, ItemHoarderBlockEntity be) { + AABB checkArea = new AABB(pos).inflate(suckradius); + for (ItemEntity itemEntity : level.getEntitiesOfClass(ItemEntity.class, checkArea, Entity::isAlive)) { + ItemStack stack = itemEntity.getItem(); + if (ItemHoarderBlockEntity.setStackToSlots(stack, be.getStacks())) { + itemEntity.discard(); + } + } + } + + private static final void dropToHopper(Level level, BlockPos pos, BlockState state, ItemHoarderBlockEntity be) { + // TODO: export by hopper + BlockEntity beBelow = level.getBlockEntity(pos.below()); + if (beBelow instanceof Container targetInventory) { + // TODO: fill hopper beyond with item stack if space is left + } + } + + public static void tick(Level level, BlockPos pos, BlockState state, ItemHoarderBlockEntity be) { + suck(level, pos, be); + dropToHopper(level, pos, state, be); + } + + @Override + protected void saveAdditional(ValueOutput output) { + super.saveAdditional(output); + output.store("items", ITEM_STACK_MAP_CODEC, stacks); + } + + @Override + protected void loadAdditional(ValueInput input) { + super.loadAdditional(input); + stacks.clear(); + stacks.putAll(input.read("items", ITEM_STACK_MAP_CODEC).orElse(Map.of())); + } + + public float getSuckradius() { + return suckradius; + } + + @Override + public int getContainerSize() { + return stacks.size() + 1; + } + + @Override + public boolean isEmpty() { + return stacks.isEmpty(); + } + + @Override + public ItemStack getItem(int slot) { + // buggy; do not use this. The map wants to have an item name instead + return ItemStack.EMPTY; + } + + @Override + public ItemStack removeItem(int slot, int count) { + // buggy; do not use this. The map wants to have an item name instead + return ItemStack.EMPTY; + } + + @Override + public ItemStack removeItemNoUpdate(int slot) { + // buggy; do not use this. The map wants to have an item name instead + return ItemStack.EMPTY; + } + + @Override + public void setItem(int slot, ItemStack itemStack) { + if (slot < stacks.size()) { + stacks.get(itemStack.getItem().getName().getString()).grow(itemStack.getCount()); + } else if (!itemStack.isEmpty()) { + stacks.put(itemStack.getItem().getName().getString(), itemStack); + } + setChanged(); + } + + @Override + public boolean stillValid(Player player) { + return true; + } + + @Override + public void clearContent() { + stacks.clear(); + setChanged(); + } + + public Map getStacks() { + return stacks; + } +} diff --git a/src/main/resources/assets/quickly/blockstates/itemhoarder.json b/src/main/resources/assets/quickly/blockstates/itemhoarder.json new file mode 100644 index 0000000..989e03a --- /dev/null +++ b/src/main/resources/assets/quickly/blockstates/itemhoarder.json @@ -0,0 +1,7 @@ +{ + "variants": { + "": { + "model": "quickly:block/itemhoarder" + } + } +} diff --git a/src/main/resources/assets/quickly/items/itemhoarder.json b/src/main/resources/assets/quickly/items/itemhoarder.json new file mode 100644 index 0000000..9d8021d --- /dev/null +++ b/src/main/resources/assets/quickly/items/itemhoarder.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "quickly:block/itemhoarder" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/quickly/models/block/itemhoarder.json b/src/main/resources/assets/quickly/models/block/itemhoarder.json new file mode 100644 index 0000000..534a48d --- /dev/null +++ b/src/main/resources/assets/quickly/models/block/itemhoarder.json @@ -0,0 +1,6 @@ +{ + "parent": "block/cube_all", + "textures": { + "all": "quickly:block/itemhoarder" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/quickly/models/item/itemhoarder.json b/src/main/resources/assets/quickly/models/item/itemhoarder.json new file mode 100644 index 0000000..f2ffacb --- /dev/null +++ b/src/main/resources/assets/quickly/models/item/itemhoarder.json @@ -0,0 +1,10 @@ +{ + "parent": "quickly:block/itemhoarder", + "display": { + "thirdperson": { + "rotation": [ 10, -45, 170 ], + "translation": [ 0, 1.5, -2.75 ], + "scale": [ 0.375, 0.375, 0.375 ] + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/quickly/textures/block/itemhoarder.png b/src/main/resources/assets/quickly/textures/block/itemhoarder.png new file mode 100644 index 0000000000000000000000000000000000000000..f505ab41a89f00a96dc6c80e021216882a4fff3c GIT binary patch literal 2894 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