Skip to content

Commit

Permalink
feat: implement pick block with block entity data
Browse files Browse the repository at this point in the history
  • Loading branch information
smartcmd committed Jan 14, 2025
1 parent 3a2d0b0 commit 1ab2f61
Show file tree
Hide file tree
Showing 6 changed files with 106 additions and 21 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ Unless otherwise specified, any version comparison below is the comparison of se
- (API) Implemented brewing stand, and several related interfaces & objects including `BlockEntityBrewingStand`,
`BrewingStandContainer`, `Registries#POTION_MIX_RECIPES`, `PotionMixRecipe` are added to api module. See commit
history for more details.
- (API) Implemented picking block with block entity data. The following methods are added: `ItemBaseComponent#getBlockEntityNBT`,
`ItemBaseComponent#setBlockEntityNBT`, `ItemBaseComponent#clearBlockEntityNBT` and `ItemBaseComponent#hasBlockEntityNBT`.
- (API) Introduced a number of overloads of `Dimension#addSound`.
- Implemented trapdoor except redstone feature (Redstone feature requires the implementation of redstone system).
- Implemented sponge and wet sponge.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,14 @@
public class PlayerBlockPickEvent extends PlayerEvent implements CancellableEvent {
protected BlockStateWithPos clickedBlock;
@Setter
protected boolean addUserData;
protected boolean includeBlockEntity;
@Setter
protected ItemStack itemBlock;

public PlayerBlockPickEvent(EntityPlayer player, BlockStateWithPos clickedBlock, boolean addUserData, ItemStack itemBlock) {
public PlayerBlockPickEvent(EntityPlayer player, BlockStateWithPos clickedBlock, boolean includeBlockEntity, ItemStack itemBlock) {
super(player);
this.clickedBlock = clickedBlock;
this.addUserData = addUserData;
this.includeBlockEntity = includeBlockEntity;
this.itemBlock = itemBlock;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -581,4 +581,41 @@ default Set<EnchantmentType> getIncompatibleEnchantmentTypes(EnchantmentType typ
.filter(enchantmentType -> enchantmentType.isIncompatibleWith(type))
.collect(Collectors.toSet());
}

/**
* Get the block entity nbt in the item.
* <p>
* The block entity nbt will be stored in the item if player pick a block with ctrl pressed,
* and the nbt will be used when the player place the block. Note that not every block has
* block entity, so setting block entity nbt in an item whose block doesn't have block entity
* will have no effect.
*
* @return the block entity nbt in the item, or {@code null} if the item doesn't have block entity nbt.
*/
NbtMap getBlockEntityNBT();

/**
* Set the block entity nbt in the item.
* <p>
* The position information in the nbt will be simply removed when placing block.
*
* @param blockEntityNBT the block entity nbt to set, can be {@code null} to clean the block entity nbt.
*/
void setBlockEntityNBT(NbtMap blockEntityNBT);

/**
* Clear the block entity nbt in the item.
*/
default void clearBlockEntityNBT() {
setBlockEntityNBT(null);
}

/**
* Check if the item has block entity nbt.
*
* @return {@code true} if the item has block entity nbt, {@code false} otherwise.
*/
default boolean hasBlockEntityNBT() {
return getBlockEntityNBT() != null;
}
}
3 changes: 3 additions & 0 deletions api/src/main/java/org/allaymc/api/world/Dimension.java
Original file line number Diff line number Diff line change
Expand Up @@ -816,6 +816,9 @@ default BlockEntity getBlockEntity(int x, int y, int z) {
return chunk.getBlockEntity(x & 15, y, z & 15);
}

/**
* @see #getBlockEntity(int, int, int)
*/
default BlockEntity getBlockEntity(Vector3ic pos) {
return getBlockEntity(pos.x(), pos.y(), pos.z());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ public class ItemBaseComponentImpl implements ItemBaseComponent {
protected static final String TAG_NAME = "Name";
protected static final String TAG_LORE = "Lore";
protected static final String TAG_ENCHANTMENT = "ench";
protected static final String TAG_BLOCK_ENTITY = "BlockEntityTag";
protected static final String TAG_CUSTOM_NBT = "CustomNBT";

private static int STACK_NETWORK_ID_COUNTER = 1;
Expand Down Expand Up @@ -96,6 +97,9 @@ public class ItemBaseComponentImpl implements ItemBaseComponent {
protected NbtMap customNBTContent = NbtMap.EMPTY;
@Getter
@Setter
protected NbtMap blockEntityNBT;
@Getter
@Setter
protected int stackNetworkId;

public ItemBaseComponentImpl(ItemStackInitInfo initInfo) {
Expand Down Expand Up @@ -133,6 +137,8 @@ public void loadExtraTag(NbtMap extraTag) {
this.enchantments.put(enchantment.getType(), enchantment);
}));

extraTag.listenForCompound(TAG_BLOCK_ENTITY, nbt -> this.blockEntityNBT = nbt);

extraTag.listenForCompound(TAG_CUSTOM_NBT, customNbt -> this.customNBTContent = customNbt);

var event = new CItemLoadExtraTagEvent(extraTag);
Expand Down Expand Up @@ -164,6 +170,10 @@ public NbtMap saveExtraTag() {
nbtBuilder.putList(TAG_ENCHANTMENT, NbtType.COMPOUND, enchantmentNBT);
}

if (blockEntityNBT != null) {
nbtBuilder.putCompound(TAG_BLOCK_ENTITY, blockEntityNBT);
}

// TODO: item lock type

// Custom NBT content
Expand Down Expand Up @@ -316,15 +326,38 @@ protected boolean tryPlaceBlockState(Dimension dimension, BlockState blockState,
}

var result = blockType.getBlockBehavior().place(dimension, blockState, placeBlockPos, placementInfo);
if (result && player != null) {
if (result) {
dimension.addLevelSoundEvent(placeBlockPos.x() + 0.5f, placeBlockPos.y() + 0.5f, placeBlockPos.z() + 0.5f, SoundEvent.PLACE, blockState.blockStateHash());
tryConsumeItem(player);
var e = new CItemPlacedAsBlockEvent(dimension, placeBlockPos, thisItemStack);
manager.callEvent(e);
tryApplyBlockEntityNBT(dimension, placeBlockPos);
if (player != null) {
tryConsumeItem(player);
}
manager.callEvent(new CItemPlacedAsBlockEvent(dimension, placeBlockPos, thisItemStack));
}

return result;
}

protected void tryApplyBlockEntityNBT(Dimension dimension, Vector3ic placeBlockPos) {
if (this.blockEntityNBT == null) {
return;
}

var blockEntity = dimension.getBlockEntity(placeBlockPos);
// Block entity should also being spawned when placing block
// if the block entity is implemented
if (blockEntity == null) {
return;
}

// The position data should be removed
var builder = blockEntityNBT.toBuilder();
builder.remove("x");
builder.remove("y");
builder.remove("z");
blockEntity.loadNBT(this.blockEntityNBT);
}

protected void tryConsumeItem(EntityPlayer player) {
if (player == null || player.getGameType() != GameType.CREATIVE) {
thisItemStack.reduceCount(1);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
import org.cloudburstmc.protocol.bedrock.packet.BedrockPacketType;
import org.cloudburstmc.protocol.bedrock.packet.BlockPickRequestPacket;

import java.util.List;

/**
* @author Cool_Loong
*/
Expand All @@ -21,9 +23,9 @@ public class BlockPickRequestPacketProcessor extends PacketProcessor<BlockPickRe
@Override
public void handleSync(EntityPlayer player, BlockPickRequestPacket packet, long receiveTime) {
var blockPos = MathUtils.CBVecToJOMLVec(packet.getBlockPosition());
// TODO: UserData
var addUserData = packet.isAddUserData();
if (!player.canReachBlock(blockPos) || player.getGameType() != GameType.CREATIVE) return;
if (!player.canReachBlock(blockPos) || player.getGameType() != GameType.CREATIVE) {
return;
}

var block = player.getLocation().dimension().getBlockState(blockPos);
if (block.getBlockType() == BlockTypes.AIR) {
Expand All @@ -34,16 +36,19 @@ public void handleSync(EntityPlayer player, BlockPickRequestPacket packet, long
var item = block.toItemStack();
item.setCount(item.getItemData().maxStackSize());

var event = new PlayerBlockPickEvent(
player,
new BlockStateWithPos(block, new Position3i(blockPos, player.getDimension()), 0),
addUserData,
item
);
if (!event.call()) return;
var event = new PlayerBlockPickEvent(player, new BlockStateWithPos(block, new Position3i(blockPos, player.getDimension()), 0), packet.isAddUserData(), item);
if (!event.call()) {
return;
}

item = event.getItemBlock();
addUserData = event.isAddUserData();
if (event.isIncludeBlockEntity()) {
var blockEntity = player.getDimension().getBlockEntity(blockPos);
if (blockEntity != null) {
item.setBlockEntityNBT(blockEntity.saveNBT());
item.setLore(List.of("+(DATA)"));
}
}

var inventory = player.getContainer(FullContainerType.PLAYER_INVENTORY);
// Foreach hot bar
Expand All @@ -63,10 +68,15 @@ public void handleSync(EntityPlayer player, BlockPickRequestPacket packet, long
}
}

if (success) return;
if (success) {
return;
}

if (minEmptySlot != -1) inventory.setItemStack(minEmptySlot, item);
else inventory.setItemInHand(item); // Hot bar is full
if (minEmptySlot != -1) {
inventory.setItemStack(minEmptySlot, item);
} else {
inventory.setItemInHand(item); // Hot bar is full
}
}

@Override
Expand Down

0 comments on commit 1ab2f61

Please sign in to comment.