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 0000000..f505ab4 Binary files /dev/null and b/src/main/resources/assets/quickly/textures/block/itemhoarder.png differ diff --git a/src/main/resources/data/quickly/recipe/shaped_itemhoarder_from_barrel.json b/src/main/resources/data/quickly/recipe/shaped_itemhoarder_from_barrel.json new file mode 100644 index 0000000..2dbf895 --- /dev/null +++ b/src/main/resources/data/quickly/recipe/shaped_itemhoarder_from_barrel.json @@ -0,0 +1,16 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + "ooo", + "obo", + "ooo" + ], + "key": { + "o": "quickly:speedingot", + "b": "minecraft:barrel" + }, + "result": { + "id": "quickly:itemhoarder", + "count": 1 + } +} \ No newline at end of file diff --git a/src/main/resources/data/quickly/recipe/shaped_itemhoarder_from_chest.json b/src/main/resources/data/quickly/recipe/shaped_itemhoarder_from_chest.json new file mode 100644 index 0000000..dcfa3c2 --- /dev/null +++ b/src/main/resources/data/quickly/recipe/shaped_itemhoarder_from_chest.json @@ -0,0 +1,16 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + "ooo", + "oco", + "ooo" + ], + "key": { + "o": "quickly:speedingot", + "c": "minecraft:chest" + }, + "result": { + "id": "quickly:itemhoarder", + "count": 1 + } +} \ No newline at end of file