Skip to content

Commit

Permalink
added more adjustments and inventory handling to storage blocks (wip!)
Browse files Browse the repository at this point in the history
  • Loading branch information
JR1811 committed Sep 10, 2024
1 parent ccb96dc commit 91008a3
Show file tree
Hide file tree
Showing 9 changed files with 174 additions and 84 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.mojang.serialization.MapCodec;
import io.fabricatedatelier.mayor.util.ConnectedBlockUtil;
import io.fabricatedatelier.mayor.util.HandledInventory;
import net.minecraft.block.Block;
import net.minecraft.block.BlockRenderType;
import net.minecraft.block.BlockState;
Expand All @@ -19,6 +20,7 @@
import net.minecraft.util.ActionResult;
import net.minecraft.util.Hand;
import net.minecraft.util.ItemActionResult;
import net.minecraft.util.ItemScatterer;
import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
Expand Down Expand Up @@ -56,7 +58,7 @@ protected ActionResult onUse(BlockState state, World world, BlockPos pos, Player
BlockPos originPos = getOrigin(world, pos).orElse(pos);
if (world.getBlockEntity(originPos) instanceof AbstractVillageContainerBlockEntity blockEntity && !world.isClient()) {
// extract
Optional<ItemStack> removedStack = blockEntity.extract(hit.getSide());
Optional<ItemStack> removedStack = blockEntity.extractFromOrigin(hit.getSide());
if (removedStack.isPresent() && !removedStack.get().isEmpty()) {
player.getInventory().offerOrDrop(removedStack.get());
return ActionResult.SUCCESS;
Expand All @@ -68,9 +70,15 @@ protected ActionResult onUse(BlockState state, World world, BlockPos pos, Player
@Override
protected ItemActionResult onUseWithItem(ItemStack stack, BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult hit) {
BlockPos originPos = getOrigin(world, pos).orElse(pos);
if (world.getBlockEntity(originPos) instanceof AbstractVillageContainerBlockEntity blockEntity && !world.isClient()) {
// inset
if (blockEntity.insert(player.getStackInHand(hand).copyAndEmpty(), hit.getSide())) {

if (world.isClient())
return super.onUseWithItem(stack, state, world, pos, player, hand, hit);
if (!(world.getBlockEntity(originPos) instanceof AbstractVillageContainerBlockEntity blockEntity))
return super.onUseWithItem(stack, state, world, pos, player, hand, hit);

if (blockEntity.canInsert(player.getStackInHand(hand).copy(), hit.getSide())) {
if (blockEntity.insertIntoOrigin(player.getStackInHand(hand).copy(), hit.getSide())) {
player.getStackInHand(hand).decrementUnlessCreative(player.getStackInHand(hand).getCount(), player);
return ItemActionResult.SUCCESS;
}
}
Expand All @@ -91,13 +99,26 @@ public void onPlaced(World world, BlockPos pos, BlockState state, @Nullable Livi
if (!box.hasHoles() && box.isSquare()) {
state = state.with(POSITION, getPositionFromConnectedWalls(world, pos));
world.setBlockState(pos, state);
if (world.getBlockEntity(pos) instanceof AbstractVillageContainerBlockEntity blockEntity) { // TODO: only if origin
if (world.getBlockEntity(pos) instanceof AbstractVillageContainerBlockEntity blockEntity) {
box.getConnectedPosList().forEach(blockEntity::addConnectedBlocks);
}
}
if (world.getBlockEntity(pos) instanceof AbstractVillageContainerBlockEntity blockEntity) {
blockEntity.setStructureOriginPos(getOrigin(world, pos).orElse(pos));
}
super.onPlaced(world, pos, state, placer, itemStack);
}

@Override
public BlockState onBreak(World world, BlockPos pos, BlockState state, PlayerEntity player) {
if (!world.isClient()) {
if (world.getBlockEntity(pos) instanceof HandledInventory inventory && !inventory.isEmpty()) {
ItemScatterer.spawn(world, pos, inventory);
}
}
return super.onBreak(world, pos, state, player);
}

@Override
public BlockState getStateForNeighborUpdate(BlockState state, Direction direction, BlockState neighborState, WorldAccess world, BlockPos pos, BlockPos neighborPos) {
if (state.get(Properties.WATERLOGGED)) {
Expand All @@ -110,6 +131,9 @@ public BlockState getStateForNeighborUpdate(BlockState state, Direction directio
} else {
state = state.with(POSITION, MayorProperties.Position.SINGLE);
}
if (world.getBlockEntity(pos) instanceof AbstractVillageContainerBlockEntity blockEntity) {
blockEntity.setStructureOriginPos(originPos);
}
return state;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
package io.fabricatedatelier.mayor.block;

import io.fabricatedatelier.mayor.util.AbstractStorageCallback;
import io.fabricatedatelier.mayor.util.HandledInventory;
import io.fabricatedatelier.mayor.util.NbtKeys;
import io.fabricatedatelier.mayor.util.StorageCallback;
import net.minecraft.block.BlockState;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.block.entity.BlockEntityType;
import net.minecraft.inventory.Inventories;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.network.listener.ClientPlayPacketListener;
import net.minecraft.network.packet.Packet;
import net.minecraft.network.packet.s2c.play.BlockEntityUpdateS2CPacket;
import net.minecraft.registry.RegistryWrapper;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraft.util.math.Direction;
import org.jetbrains.annotations.Nullable;

import java.util.HashSet;
Expand All @@ -24,45 +25,44 @@
public abstract class AbstractVillageContainerBlockEntity extends BlockEntity implements HandledInventory {
private BlockPos structureOriginPos;
private final HashSet<BlockPos> connectedBlocks = new HashSet<>();
private AbstractStorageCallback callback;
private StorageCallback callback = null;

public AbstractVillageContainerBlockEntity(BlockEntityType<?> type, BlockPos pos, BlockState state) {
super(type, pos, state);
}

public void registerCallback(AbstractStorageCallback callback) {
/**
* If you want to listen to the {@link AbstractVillageContainerBlockEntity StorageBlockEntity}
* {@link StorageCallback callbacks}, you will need to register the callback first.<br>
* In the class, where you want to listen to those signals, implement the {@link StorageCallback} interface.<br>
* Then wherever you get access to the current {@link AbstractVillageContainerBlockEntity StorageBlockEntity},
* call its {@link AbstractVillageContainerBlockEntity#registerCallback(StorageCallback) registerCallback()} method
* with your current class's instance as the parameter (usually just a <code>this</code> call)
*
* @param callback Your current class, which implements the {@link StorageCallback} interface
*/
public void registerCallback(StorageCallback callback) {
this.callback = callback;
}

@Override
protected void readNbt(NbtCompound nbt, RegistryWrapper.WrapperLookup registryLookup) {
super.readNbt(nbt, registryLookup);
Inventories.readNbt(nbt, this.getItems(), registryLookup);
if (nbt.contains(NbtKeys.BLOCK_ENTITY_ORIGIN_POS)) {
this.setStructureOriginPos(BlockPos.fromLong(nbt.getLong(NbtKeys.BLOCK_ENTITY_ORIGIN_POS)));
}
public boolean canInsert(int slot, ItemStack stack, @Nullable Direction dir) {
if (!this.isStructureOrigin()) return false;
return HandledInventory.super.canInsert(slot, stack, dir);
}

this.connectedBlocks.clear();
NbtCompound blockPosListNbt = nbt.getCompound(NbtKeys.CONNECTED_BLOCKS);
for (String index : blockPosListNbt.getKeys()) {
BlockPos connectedPos = BlockPos.fromLong(blockPosListNbt.getLong(index));
this.connectedBlocks.add(connectedPos);
}
/**
* Use this method if you are not concerned about a specific slot.
* It will test for the condition on the first stack in the inventory.
*/
public boolean canInsert(ItemStack stack, @Nullable Direction direction) {
return canInsert(0, stack, direction);
}

@Override
protected void writeNbt(NbtCompound nbt, RegistryWrapper.WrapperLookup registryLookup) {
super.writeNbt(nbt, registryLookup);
Inventories.writeNbt(nbt, this.getItems(), registryLookup);
this.getStructureOriginPos().ifPresent(originPos -> nbt.putLong(NbtKeys.BLOCK_ENTITY_ORIGIN_POS, originPos.asLong()));

List<BlockPos> blockPosList = connectedBlocks.stream().toList();
NbtCompound blockPosListNbt = new NbtCompound();
for (int i = 0; i < blockPosList.size(); i++) {
BlockPos connectedPos = blockPosList.get(i);
blockPosListNbt.putLong(String.valueOf(i), connectedPos.asLong());
}
nbt.put(NbtKeys.CONNECTED_BLOCKS, blockPosListNbt);
public boolean canExtract(int slot, ItemStack stack, Direction dir) {
if (!this.isStructureOrigin()) return false;
return HandledInventory.super.canExtract(slot, stack, dir);
}

public boolean isStructureOrigin() {
Expand All @@ -74,11 +74,33 @@ public Optional<BlockPos> getStructureOriginPos() {
}

public void setStructureOriginPos(BlockPos newStructureOriginPos) {
callback.onOriginChanged(this, new BlockPos(this.structureOriginPos), new BlockPos(newStructureOriginPos));
if (callback != null) {
callback.onOriginChanged(this, new BlockPos(this.structureOriginPos), new BlockPos(newStructureOriginPos));
}
this.structureOriginPos = newStructureOriginPos;
markDirty();
}

public boolean insertIntoOrigin(ItemStack stack, @Nullable Direction direction) {
if (this.getWorld() == null || this.getWorld().isClient()) return false;
if (this.getStructureOriginPos().isEmpty()) return false;
if (!(this.getWorld().getBlockEntity(this.getStructureOriginPos().get()) instanceof AbstractVillageContainerBlockEntity blockEntity))
return false;
boolean inserted = blockEntity.insert(stack, direction);
if (inserted) blockEntity.markDirty();
return inserted;
}

public Optional<ItemStack> extractFromOrigin(@Nullable Direction direction) {
if (this.getWorld() == null || this.getWorld().isClient()) return Optional.empty();
if (this.getStructureOriginPos().isEmpty()) return Optional.empty();
if (!(this.getWorld().getBlockEntity(this.getStructureOriginPos().get()) instanceof AbstractVillageContainerBlockEntity blockEntity))
return Optional.empty();
Optional<ItemStack> extractedStack = blockEntity.extract(direction);
if (extractedStack.isPresent()) blockEntity.markDirty();
return extractedStack;
}

public HashSet<BlockPos> getConnectedBlocks() {
return this.connectedBlocks;
}
Expand All @@ -88,11 +110,13 @@ public void addConnectedBlocks(BlockPos... pos) {
if (entry.equals(this.pos)) continue;
this.connectedBlocks.add(entry);
}
callback.onConnectedBlocksChanged(this);
if (callback != null) {
callback.onConnectedBlocksChanged(this);
}
markDirty();
}

// Network
// --- Network & Data ---

@Override
public void markDirty() {
Expand All @@ -113,26 +137,34 @@ public Packet<ClientPlayPacketListener> toUpdatePacket() {
return BlockEntityUpdateS2CPacket.create(this);
}

@Override
protected void readNbt(NbtCompound nbt, RegistryWrapper.WrapperLookup registryLookup) {
super.readNbt(nbt, registryLookup);
Inventories.readNbt(nbt, this.getItems(), registryLookup);
if (nbt.contains(NbtKeys.BLOCK_ENTITY_ORIGIN_POS)) {
this.setStructureOriginPos(BlockPos.fromLong(nbt.getLong(NbtKeys.BLOCK_ENTITY_ORIGIN_POS)));
}

// Util

public StructureDimensions getMaxStructureDimensions() {
return new StructureDimensions(3);
}

public static Optional<HashSet<BlockPos>> getConnectedBlocksFromOrigin(AbstractVillageContainerBlockEntity blockEntity) {
World world = blockEntity.getWorld();
if (world == null) return Optional.empty();
if (blockEntity.getStructureOriginPos().isEmpty()) return Optional.empty();
if (!(world.getBlockEntity(blockEntity.getStructureOriginPos().get()) instanceof AbstractVillageContainerBlockEntity originBlockEntity))
return Optional.empty();
return Optional.ofNullable(originBlockEntity.getConnectedBlocks());
this.connectedBlocks.clear();
NbtCompound blockPosListNbt = nbt.getCompound(NbtKeys.CONNECTED_BLOCKS);
for (String index : blockPosListNbt.getKeys()) {
BlockPos connectedPos = BlockPos.fromLong(blockPosListNbt.getLong(index));
this.connectedBlocks.add(connectedPos);
}
}

@Override
protected void writeNbt(NbtCompound nbt, RegistryWrapper.WrapperLookup registryLookup) {
super.writeNbt(nbt, registryLookup);
Inventories.writeNbt(nbt, this.getItems(), registryLookup);
this.getStructureOriginPos().ifPresent(originPos -> nbt.putLong(NbtKeys.BLOCK_ENTITY_ORIGIN_POS, originPos.asLong()));

public record StructureDimensions(int width, int height, int length) {
public StructureDimensions(int length) {
this(length, length, length);
List<BlockPos> blockPosList = connectedBlocks.stream().toList();
NbtCompound blockPosListNbt = new NbtCompound();
for (int i = 0; i < blockPosList.size(); i++) {
BlockPos connectedPos = blockPosList.get(i);
blockPosListNbt.putLong(String.valueOf(i), connectedPos.asLong());
}
nbt.put(NbtKeys.CONNECTED_BLOCKS, blockPosListNbt);
}
}
11 changes: 5 additions & 6 deletions src/main/java/io/fabricatedatelier/mayor/init/Items.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
package io.fabricatedatelier.mayor.init;

import io.fabricatedatelier.mayor.Mayor;
import io.fabricatedatelier.mayor.item.LumberStorageBlockItem;
import io.fabricatedatelier.mayor.item.StoneStorageBlockItem;
import io.fabricatedatelier.mayor.item.StorageBlockItem;
import net.minecraft.item.Item;
import net.minecraft.registry.Registries;
import net.minecraft.registry.Registry;
Expand All @@ -11,11 +10,11 @@
import java.util.List;

public class Items {
public static final LumberStorageBlockItem LUMBER_STORAGE_BLOCK = register("lumber_storage_block",
new LumberStorageBlockItem(Blocks.LUMBER_STORAGE, new Item.Settings()), List.of(ItemGroups.MAYOR_BLOCKS));
public static final StorageBlockItem LUMBER_STORAGE_BLOCK = register("lumber_storage_block",
new StorageBlockItem(Blocks.LUMBER_STORAGE, new Item.Settings()), List.of(ItemGroups.MAYOR_BLOCKS));

public static final StoneStorageBlockItem STONE_STORAGE_BLOCK = register("stone_storage_block",
new StoneStorageBlockItem(Blocks.STONE_STORAGE, new Item.Settings()), List.of(ItemGroups.MAYOR_BLOCKS));
public static final StorageBlockItem STONE_STORAGE_BLOCK = register("stone_storage_block",
new StorageBlockItem(Blocks.STONE_STORAGE, new Item.Settings()), List.of(ItemGroups.MAYOR_BLOCKS));


private static <T extends Item> T register(String name, T item, @Nullable List<ItemGroups.ItemGroupEntry> itemGroups) {
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,8 @@
import net.minecraft.block.Block;
import net.minecraft.item.BlockItem;

public class StoneStorageBlockItem extends BlockItem {
public StoneStorageBlockItem(Block block, Settings settings) {
public class StorageBlockItem extends BlockItem {
public StorageBlockItem(Block block, Settings settings) {
super(block, settings);
}

}
45 changes: 45 additions & 0 deletions src/main/java/io/fabricatedatelier/mayor/mixin/BlockItemMixin.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package io.fabricatedatelier.mayor.mixin;

import io.fabricatedatelier.mayor.block.custom.LumberStorageBlock;
import io.fabricatedatelier.mayor.block.custom.StoneStorageBlock;
import io.fabricatedatelier.mayor.datagen.TagProvider;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.item.BlockItem;
import net.minecraft.item.ItemStack;
import net.minecraft.item.ItemUsageContext;
import net.minecraft.util.ActionResult;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;

@Mixin(BlockItem.class)
public abstract class BlockItemMixin {

@Shadow
public abstract Block getBlock();

// Note: This is probably a scuffed implementation, so change it if there is something better!
// The issue was that BlockItems which were placed in storage blocks with right click sometimes
// flashed up for a split second as if they were placed in the world before being inserted in the inventory
@Inject(method = "useOnBlock", at = @At("HEAD"), cancellable = true)
private void avoidPlacementIfUsedOnStorage(ItemUsageContext context, CallbackInfoReturnable<ActionResult> cir) {
BlockState targetBlockState = context.getWorld().getBlockState(context.getBlockPos());
ItemStack blockItemStack = new ItemStack((BlockItem) (Object) this);

if (blockItemStack.isIn(TagProvider.ItemTags.LUMBER_STORAGE_STORABLE)) {
if (targetBlockState.getBlock() instanceof LumberStorageBlock) {
cir.setReturnValue(ActionResult.PASS);
return;
}
}
if (blockItemStack.isIn(TagProvider.ItemTags.STONE_STORAGE_STORABLE)) {
if (targetBlockState.getBlock() instanceof StoneStorageBlock) {
cir.setReturnValue(ActionResult.PASS);
return;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ default Optional<ItemStack> extract(@Nullable Direction direction) {

@Override
default boolean isEmpty() {
return size() <= 0;
return size() <= 0 || getItems().stream().allMatch(ItemStack::isEmpty);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import io.fabricatedatelier.mayor.block.AbstractVillageContainerBlockEntity;
import net.minecraft.util.math.BlockPos;

public interface AbstractStorageCallback {
public interface StorageCallback {
void onOriginChanged(AbstractVillageContainerBlockEntity blockEntity, BlockPos oldPos, BlockPos newPos);

void onConnectedBlocksChanged(AbstractVillageContainerBlockEntity blockEntity);
Expand Down
Loading

0 comments on commit 91008a3

Please sign in to comment.