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;
}
}

View File

@@ -0,0 +1,10 @@
{
"variants": {
"dest=up": { "model": "quickly:block/blockstackerup" },
"dest=down": { "model": "quickly:block/blockstackerdown" },
"dest=east": { "model": "quickly:block/blockstackereast" },
"dest=south": { "model": "quickly:block/blockstackersouth" },
"dest=west": { "model": "quickly:block/blockstackerwest" },
"dest=north": { "model": "quickly:block/blockstackernorth" }
}
}

View File

@@ -1,6 +1,6 @@
{
"model": {
"type": "minecraft:model",
"model": "quickly:block/drilleast"
"model": "quickly:block/blockstackerdown"
}
}

View File

@@ -1,6 +0,0 @@
{
"model": {
"type": "minecraft:model",
"model": "quickly:block/drillnorth"
}
}

View File

@@ -1,6 +0,0 @@
{
"model": {
"type": "minecraft:model",
"model": "quickly:block/drillsouth"
}
}

View File

@@ -1,6 +0,0 @@
{
"model": {
"type": "minecraft:model",
"model": "quickly:block/drillwest"
}
}

View File

@@ -6,6 +6,7 @@
"item.quickly.blockcottonplant": "Baumwollpflanze",
"item.quickly.blockquickiepowder": "Eilpulverblock",
"item.quickly.blockspeedpowder": "Fluchtpulverblock",
"item.quickly.blockstacker": "Stapler",
"item.quickly.blockturquoise": "Türkisblock",
"item.quickly.canola": "Raps",
"item.quickly.canolabottle": "Rapsöl",

View File

@@ -6,6 +6,7 @@
"item.quickly.blockcottonplant": "cotton plant",
"item.quickly.blockquickiepowder": "quickie powder block",
"item.quickly.blockspeedpowder": "speed powder block",
"item.quickly.blockstacker": "stacker",
"item.quickly.blockturquoise": "block of turquoise",
"item.quickly.canola": "canola",
"item.quickly.canolabottle": "canola oil",

View File

@@ -0,0 +1,8 @@
{
"parent": "minecraft:block/cube_bottom_top",
"textures": {
"bottom": "quickly:block/blockstackerout",
"side": "quickly:block/blockstackerdown",
"top": "quickly:block/blockstackerin"
}
}

View File

@@ -0,0 +1,11 @@
{
"parent": "block/cube_directional",
"textures": {
"up": "quickly:block/blockstackerright",
"down": "quickly:block/blockstackerleft",
"north": "quickly:block/blockstackerleft",
"east": "quickly:block/blockstackerout",
"south": "quickly:block/blockstackerright",
"west": "quickly:block/blockstackerin"
}
}

View File

@@ -0,0 +1,11 @@
{
"parent": "block/cube_directional",
"textures": {
"up": "quickly:block/blockstackerup",
"down": "quickly:block/blockstackerup",
"north": "quickly:block/blockstackerout",
"east": "quickly:block/blockstackerup",
"south": "quickly:block/blockstackerin",
"west": "quickly:block/blockstackerup"
}
}

View File

@@ -0,0 +1,11 @@
{
"parent": "block/cube_directional",
"textures": {
"up": "quickly:block/blockstackerdown",
"down": "quickly:block/blockstackerdown",
"north": "quickly:block/blockstackerin",
"east": "quickly:block/blockstackerdown",
"south": "quickly:block/blockstackerout",
"west": "quickly:block/blockstackerdown"
}
}

View File

@@ -0,0 +1,8 @@
{
"parent": "block/cube_bottom_top",
"textures": {
"bottom": "quickly:block/blockstackerin",
"side": "quickly:block/blockstackerup",
"top": "quickly:block/blockstackerout"
}
}

View File

@@ -0,0 +1,11 @@
{
"parent": "block/cube_directional",
"textures": {
"up": "quickly:block/blockstackerleft",
"down": "quickly:block/blockstackerright",
"north": "quickly:block/blockstackerright",
"east": "quickly:block/blockstackerin",
"south": "quickly:block/blockstackerleft",
"west": "quickly:block/blockstackerout"
}
}

View File

@@ -0,0 +1,10 @@
{
"parent": "quickly:block/blockstackerdown",
"display": {
"thirdperson": {
"rotation": [ 10, -45, 170 ],
"translation": [ 0, 1.5, -2.75 ],
"scale": [ 0.375, 0.375, 0.375 ]
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

View File

@@ -0,0 +1,19 @@
{
"type": "minecraft:crafting_shaped",
"pattern": [
"s s",
"scs",
" s "
],
"key": {
"s": "quickky:speedingot",
"c": [
"minecraft:chest",
"minecraft:barrel"
]
},
"result": {
"id": "quickly:blockstacker",
"count": 4
}
}