basic block stacker, but still with bugs

This commit is contained in:
Jottyfan
2025-12-31 20:43:19 +01:00
parent c4eb56aa29
commit cc66e0d5d9
24 changed files with 359 additions and 20 deletions

View File

@@ -0,0 +1,84 @@
package de.jottyfan.minecraft.block;
import org.jspecify.annotations.Nullable;
import com.mojang.serialization.MapCodec;
import de.jottyfan.minecraft.blockentity.BlockStackerEntity;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.item.context.BlockPlaceContext;
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.block.state.StateDefinition.Builder;
import net.minecraft.world.level.block.state.properties.EnumProperty;
/**
*
* @author jotty
*
*/
public class BlockStacker extends Block implements EntityBlock {
public static final MapCodec<BlockStacker> CODEC = simpleCodec(BlockStacker::new);
public static final EnumProperty<Direction> SOURCE = EnumProperty.create("source", Direction.class, Direction.NORTH,
Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN);
public static final EnumProperty<Direction> DEST = EnumProperty.create("dest", Direction.class, Direction.NORTH,
Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN);
public BlockStacker(Properties properties) {
super(properties);
registerDefaultState(stateDefinition.any().setValue(SOURCE, Direction.UP).setValue(DEST, Direction.DOWN));
}
@Override
protected void createBlockStateDefinition(Builder<Block, BlockState> builder) {
builder.add(SOURCE, DEST);
}
@Override
public BlockState getStateForPlacement(BlockPlaceContext context) {
return this.defaultBlockState().setValue(SOURCE, context.getNearestLookingDirection()).setValue(DEST, context.getNearestLookingDirection().getOpposite());
}
@Override
public <T extends BlockEntity> @Nullable BlockEntityTicker<T> getTicker(Level level, BlockState blockState,
BlockEntityType<T> type) {
return (lambdaLevel, pos, state, blockEntity) -> BlockStackerEntity.tick(lambdaLevel, pos, state, blockEntity);
}
@Override
public @Nullable BlockEntity newBlockEntity(BlockPos pos, BlockState blockState) {
return new BlockStackerEntity(pos, blockState);
}
public static MapCodec<BlockStacker> getCodec() {
return CODEC;
}
public Direction getSource(BlockState state) {
return state.getValue(SOURCE);
}
public Direction getDest(BlockState state) {
return state.getValue(DEST);
}
public BlockPos getOffset(BlockState state, EnumProperty<Direction> sourceOrDest) {
BlockPos pos = new BlockPos(0, 0, 0);
return switch (state.getValue(sourceOrDest)) {
case Direction.UP -> pos.above();
case Direction.DOWN -> pos.below();
case Direction.NORTH -> pos.north();
case Direction.EAST -> pos.east();
case Direction.SOUTH -> pos.south();
case Direction.WEST -> pos.west();
default -> pos;
};
}
}

View File

@@ -4,6 +4,7 @@ import java.util.function.Function;
import de.jottyfan.minecraft.Quickly;
import de.jottyfan.minecraft.blockentity.BlockEntityRegister;
import de.jottyfan.minecraft.blockentity.BlockStackerEntity;
import de.jottyfan.minecraft.blockentity.DrillBlockEntity;
import de.jottyfan.minecraft.blockentity.ItemHoarderBlockEntity;
import de.jottyfan.minecraft.item.QuicklyItems;
@@ -55,8 +56,8 @@ public class QuicklyBlocks {
properties -> new Monsterhoarder(properties));
public static final Block ITEMHOARDER = registerBlock("itemhoarder", properties -> new Itemhoarder(properties));
public static final Block DRILL = registerBlock("drill", properties -> new BlockDrill(properties));
public static final Block STACKER = registerBlock("blockstacker", properties -> new BlockStacker(properties.strength(2.5f)));
// TODO: add blockstacker
// TODO: add salpeter ore, sulfor ore
// TODO: merge lavahoarder and emptylavahoarder into one block using a BooleanProperty for the lava fill state
@@ -64,6 +65,8 @@ public class QuicklyBlocks {
.registerBlockEntity("itemhoarderblockentity", ItemHoarderBlockEntity::new, ITEMHOARDER);
public static final BlockEntityType<DrillBlockEntity> BLOCKENTITY_DRILL = new BlockEntityRegister<DrillBlockEntity>()
.registerBlockEntity("drillblockentity", DrillBlockEntity::new, DRILL);
public static final BlockEntityType<BlockStackerEntity> BLOCKSTACKER_BLOCKENTITY = new BlockEntityRegister<BlockStackerEntity>()
.registerBlockEntity("blockstackerentity", BlockStackerEntity::new, STACKER);
private static final Block registerBlock(String name, Properties properties) {
return QuicklyBlocks.registerBlock(name, properties, p -> new Block(p));
@@ -95,6 +98,7 @@ public class QuicklyBlocks {
block.accept(MONSTERHOARDER);
block.accept(ITEMHOARDER);
block.accept(DRILL);
block.accept(STACKER);
});
}
}

View File

@@ -0,0 +1,168 @@
package de.jottyfan.minecraft.blockentity;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.jspecify.annotations.Nullable;
import com.mojang.serialization.Codec;
import de.jottyfan.minecraft.Quickly;
import de.jottyfan.minecraft.block.BlockStacker;
import de.jottyfan.minecraft.block.QuicklyBlocks;
import net.minecraft.core.BlockPos;
import net.minecraft.world.Container;
import net.minecraft.world.entity.SlotAccess;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BaseContainerBlockEntity;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
/**
*
* @author jotty
*
*/
public class BlockStackerEntity extends BlockEntity implements Container {
public static final Codec<Map<String, ItemStack>> ITEM_STACK_MAP_CODEC = Codec.unboundedMap(Codec.STRING,
ItemStack.CODEC);
private List<ItemStack> inventory = new ArrayList<>();
public BlockStackerEntity(BlockPos pos, BlockState blockState) {
super(QuicklyBlocks.BLOCKSTACKER_BLOCKENTITY, pos, blockState);
}
public static <T extends BlockEntity> Object tick(Level level, BlockPos pos, BlockState state, T entity) {
pos.below();
BlockStacker block = (BlockStacker) state.getBlock();
BlockEntity source = level.getBlockEntity(pos.offset(block.getOffset(state, BlockStacker.SOURCE)));
BlockEntity dest = level.getBlockEntity(pos.offset(block.getOffset(state, BlockStacker.DEST)));
Boolean sourceIsLootable = source instanceof BaseContainerBlockEntity;
Boolean destIsLootable = dest instanceof BaseContainerBlockEntity;
if (sourceIsLootable && destIsLootable) {
BaseContainerBlockEntity lootableSource = (BaseContainerBlockEntity) source;
BaseContainerBlockEntity lootableDest = (BaseContainerBlockEntity) dest;
transferOneStack(lootableSource, lootableDest);
}
return null;
}
public static final Boolean transferOneStack(BaseContainerBlockEntity source, BaseContainerBlockEntity dest) {
Boolean result = false;
Integer sourceSlot = findItemStackPos(source, false);
if (sourceSlot != null && !Items.AIR.equals(source.getSlot(sourceSlot).get().getItem())) {
ItemStack sourceStack = source.getSlot(sourceSlot).get();
Integer destSlot = findItemStackPos(dest, sourceStack);
if (destSlot != null) {
ItemStack destStack = dest.getSlot(destSlot).get();
Integer occupied = destStack.getCount();
Integer free = destStack.getCount() - occupied;
Integer candidates = sourceStack.getCount();
Integer travellers = candidates > free ? free : candidates;
if (travellers > 0) {
Quickly.LOGGER.debug("transfer {}/{} of {} from slot {} to slot {} on top of {} ones", travellers, candidates,
sourceStack.getItem().toString(), sourceSlot, destSlot, occupied);
sourceStack.shrink(travellers);
destStack.grow(travellers);
result = true;
}
} else {
Integer destFreeSlot = findItemStackPos(dest, true);
if (destFreeSlot != null) {
Quickly.LOGGER.debug("transfer all of {} from slot {} to slot {}", sourceStack.getItem().toString(),
sourceSlot, destSlot);
dest.setItem(destFreeSlot, new ItemStack(sourceStack.getItem(), sourceStack.getCount()));
sourceStack.shrink(sourceSlot);
result = true;
}
}
}
return result;
}
private static final Integer findItemStackPos(BaseContainerBlockEntity blockEntity, ItemStack sourceStack) {
Integer counter = blockEntity.getContainerSize();
while (counter > 0) {
counter--;
@Nullable
SlotAccess slotAccess = blockEntity.getSlot(counter);
if (slotAccess != null) {
ItemStack stack = slotAccess.get();
if (sourceStack.getItem().equals(stack.getItem())) {
if (stack.getCount() < stack.getCount()) {
return counter;
}
}
}
}
return null;
}
private static final Integer findItemStackPos(BaseContainerBlockEntity blockEntity, Boolean empty) {
Integer counter = blockEntity.getContainerSize();
while (counter > 0) {
counter--;
@Nullable
SlotAccess slotAccess = blockEntity.getSlot(counter);
if (slotAccess != null) {
ItemStack stack = slotAccess.get();
if (empty.equals(ItemStack.EMPTY.equals(stack))) {
return counter;
}
}
}
return null;
}
@Override
public void clearContent() {
inventory.clear();
}
@Override
public int getContainerSize() {
return inventory.size();
}
@Override
public boolean isEmpty() {
return false;
}
@Override
public ItemStack getItem(int slot) {
return inventory.get(slot);
}
@Override
public ItemStack removeItem(int slot, int count) {
ItemStack stack = inventory.get(slot);
stack.shrink(count);
setChanged();
return stack;
}
@Override
public ItemStack removeItemNoUpdate(int slot) {
ItemStack stack = inventory.get(slot);
stack.shrink(stack.getCount());
return stack;
}
@Override
public void setItem(int slot, ItemStack itemStack) {
inventory.set(slot, itemStack);
setChanged();
}
@Override
public boolean stillValid(Player player) {
return false;
}
}