Skip to content

Commit

Permalink
More work on block breaking translation
Browse files Browse the repository at this point in the history
  • Loading branch information
RaphiMC committed Oct 14, 2024
1 parent bc4d4fa commit 9df738e
Show file tree
Hide file tree
Showing 7 changed files with 58 additions and 35 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,11 @@ public BlockPosition position() {
}

public boolean isValidBlockTag(final String tag) {
return this.validBlockTags.contains(tag);
if (tag == null) {
return false;
} else {
return this.validBlockTags.contains(tag);
}
}

protected void onSlotChanged(final int slot, final BedrockItem oldItem, final BedrockItem newItem) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,9 @@ public void sendPlayerAuthInputPacketToServer(final ClientPlayMode playMode) {
}

this.authInputData.add(PlayerAuthInputPacket_InputData.BlockBreakingDelayEnabled);
if (this.onGround) {
this.authInputData.add(PlayerAuthInputPacket_InputData.VerticalCollision);
}
if (this.sneaking) {
this.addAuthInputData(PlayerAuthInputPacket_InputData.SneakDown, PlayerAuthInputPacket_InputData.Sneaking, PlayerAuthInputPacket_InputData.WantDown);
}
Expand Down Expand Up @@ -193,7 +196,8 @@ public void sendPlayerAuthInputPacketToServer(final ClientPlayMode playMode) {
for (AuthInputBlockAction blockAction : this.authInputBlockActions) {
playerAuthInput.write(BedrockTypes.VAR_INT, blockAction.action.getValue()); // action
switch (blockAction.action) {
case StartDestroyBlock, AbortDestroyBlock, StopDestroyBlock, CrackBlock, PredictDestroyBlock, ContinueDestroyBlock -> {
// StopDestroyBlock does not have additional data even tho bedrock protocol docs claim it does
case StartDestroyBlock, AbortDestroyBlock, CrackBlock, PredictDestroyBlock, ContinueDestroyBlock -> {
playerAuthInput.write(BedrockTypes.POSITION_3I, blockAction.position); // position
playerAuthInput.write(BedrockTypes.VAR_INT, blockAction.direction); // facing
}
Expand Down Expand Up @@ -592,6 +596,11 @@ public record BlockBreakingInfo(BlockPosition position, Direction direction) {
}

public record AuthInputBlockAction(PlayerActionType action, BlockPosition position, int direction) {

public AuthInputBlockAction(final PlayerActionType action) {
this(action, null, -1);
}

}

}
13 changes: 13 additions & 0 deletions src/main/java/net/raphimc/viabedrock/api/util/PacketFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,19 @@ public static void sendJavaRotateHead(final UserConnection user, final Entity en
rotateHead.send(BedrockProtocol.class);
}

public static void sendJavaBlockChangedAck(final UserConnection user, final int sequence) {
final PacketWrapper blockChangedAck = PacketWrapper.create(ClientboundPackets1_21.BLOCK_CHANGED_ACK, user);
blockChangedAck.write(Types.VAR_INT, sequence); // sequence number
blockChangedAck.send(BedrockProtocol.class);
}

public static void sendJavaBlockUpdate(final UserConnection user, final BlockPosition position, final int blockState) {
final PacketWrapper blockUpdate = PacketWrapper.create(ClientboundPackets1_21.BLOCK_UPDATE, user);
blockUpdate.write(Types.BLOCK_POSITION1_14, position); // position
blockUpdate.write(Types.VAR_INT, blockState); // block state
blockUpdate.send(BedrockProtocol.class);
}

public static void sendBedrockContainerClose(final UserConnection user, final byte containerId, final ContainerType containerType) {
final PacketWrapper containerClose = PacketWrapper.create(ServerboundBedrockPackets.CONTAINER_CLOSE, user);
containerClose.write(Types.BYTE, containerId); // container id
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,7 @@ protected void register() {
if (true) return; // TODO: Remove once block breaking is fully working
final GameSessionStorage gameSession = wrapper.user().get(GameSessionStorage.class);
final ClientPlayerEntity clientPlayer = wrapper.user().get(EntityTracker.class).getClientPlayer();
final ChunkTracker chunkTracker = wrapper.user().get(ChunkTracker.class);
final PlayerActionAction action = PlayerActionAction.values()[wrapper.read(Types.VAR_INT)]; // action
final BlockPosition position = wrapper.read(Types.BLOCK_POSITION1_14); // block position
final Direction direction = Direction.values()[wrapper.read(Types.UNSIGNED_BYTE)]; // face
Expand All @@ -283,28 +284,19 @@ protected void register() {
final boolean isMining = action == PlayerActionAction.START_DESTROY_BLOCK || action == PlayerActionAction.ABORT_DESTROY_BLOCK || action == PlayerActionAction.STOP_DESTROY_BLOCK;
if (isMining && (gameSession.isImmutableWorld() || !clientPlayer.abilities().getBooleanValue(AbilitiesIndex.Mine))) {
// TODO: Prevent breaking and cancel any packets that would be sent (swing, player action)
final PacketWrapper blockUpdate = PacketWrapper.create(ClientboundPackets1_21.BLOCK_UPDATE, wrapper.user());
blockUpdate.write(Types.BLOCK_POSITION1_14, position); // position
blockUpdate.write(Types.VAR_INT, wrapper.user().get(ChunkTracker.class).getJavaBlockState(position)); // block state
blockUpdate.send(BedrockProtocol.class);
PacketFactory.sendJavaBlockUpdate(wrapper.user(), position, chunkTracker.getJavaBlockState(position));
PacketFactory.sendJavaBlockChangedAck(wrapper.user(), sequence);
return;
}

// TODO: Set block to air in chunk tracker

if (sequence > 0) {
final PacketWrapper blockChangedAck = PacketWrapper.create(ClientboundPackets1_21.BLOCK_CHANGED_ACK, wrapper.user());
blockChangedAck.write(Types.VAR_INT, sequence); // sequence number
blockChangedAck.send(BedrockProtocol.class);
}

switch (action) {
case START_DESTROY_BLOCK -> {
clientPlayer.sendSwingPacketToServer();
clientPlayer.cancelNextSwingPacket();
clientPlayer.setBlockBreakingInfo(new ClientPlayerEntity.BlockBreakingInfo(position, direction));
// TODO: Handle instant breaking
// TODO: Handle creative mode mining
// TODO: Test breaking fire

if (gameSession.getMovementMode() == ServerAuthMovementMode.ClientAuthoritative) {
clientPlayer.sendPlayerActionPacketToServer(PlayerActionType.StartDestroyBlock, position, direction.ordinal());
Expand All @@ -331,7 +323,7 @@ protected void register() {
// TODO: InventoryTransactionPacket
clientPlayer.sendPlayerActionPacketToServer(PlayerActionType.AbortDestroyBlock, position, 0);
} else {
clientPlayer.addAuthInputBlockAction(new ClientPlayerEntity.AuthInputBlockAction(PlayerActionType.StopDestroyBlock, new BlockPosition(0, 0, 0), 0));
clientPlayer.addAuthInputBlockAction(new ClientPlayerEntity.AuthInputBlockAction(PlayerActionType.StopDestroyBlock));
clientPlayer.addAuthInputBlockAction(new ClientPlayerEntity.AuthInputBlockAction(PlayerActionType.AbortDestroyBlock, position, 0));
}
} else {
Expand All @@ -345,18 +337,26 @@ protected void register() {
clientPlayer.addAuthInputBlockAction(new ClientPlayerEntity.AuthInputBlockAction(PlayerActionType.AbortDestroyBlock, position, 0));
}
}

chunkTracker.handleBlockChange(position, 0, chunkTracker.airId());
PacketFactory.sendJavaBlockUpdate(wrapper.user(), position, 0);
}
case DROP_ALL_ITEMS, DROP_ITEM -> {
// TODO: Implement DROP_ALL_ITEMS, DROP_ITEM
PacketFactory.sendJavaContainerSetContent(wrapper.user(), wrapper.user().get(InventoryTracker.class).getInventoryContainer());
}
case RELEASE_USE_ITEM -> {
// TODO: Implement RELEASE_USE_ITEM
PacketFactory.sendJavaContainerSetContent(wrapper.user(), wrapper.user().get(InventoryTracker.class).getInventoryContainer());
}
case SWAP_ITEM_WITH_OFFHAND -> {
}
default -> throw new IllegalStateException("Unhandled PlayerActionAction: " + action);
}

if (sequence > 0) {
PacketFactory.sendJavaBlockChangedAck(wrapper.user(), sequence);
}
});
protocol.registerServerbound(ServerboundPackets1_20_5.INTERACT, ServerboundBedrockPackets.INVENTORY_TRANSACTION, wrapper -> {
final EntityTracker entityTracker = wrapper.user().get(EntityTracker.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -498,7 +498,7 @@ private static void handleJavaClientGameJoin(final UserConnection user) {
updateTags.write(Types.VAR_INT, tag.size()); // number of tags
for (Map.Entry<String, Tag> tagEntry : tag.entrySet()) {
updateTags.write(Types.STRING, tagEntry.getKey()); // tag name
updateTags.write(Types.VAR_INT_ARRAY_PRIMITIVE, ((IntArrayTag) tagEntry.getValue()).getValue()); // tag ids
updateTags.write(Types.VAR_INT_ARRAY_PRIMITIVE, ((IntArrayTag) tagEntry.getValue()).getValue().clone()); // tag ids
}
}
updateTags.send(BedrockProtocol.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -434,10 +434,7 @@ protected void register() {

final BlockEntity javaBlockEntity = BlockEntityRewriter.toJava(wrapper.user(), chunkTracker.getBlockState(bedrockBlockEntity.position()), bedrockBlockEntity);
if (javaBlockEntity instanceof BlockEntityWithBlockState blockEntityWithBlockState) {
final PacketWrapper blockChange = PacketWrapper.create(ClientboundPackets1_21.BLOCK_UPDATE, wrapper.user());
blockChange.write(Types.BLOCK_POSITION1_14, bedrockBlockEntity.position()); // position
blockChange.write(Types.VAR_INT, blockEntityWithBlockState.blockState()); // block state
blockChange.send(BedrockProtocol.class);
PacketFactory.sendJavaBlockUpdate(wrapper.user(), bedrockBlockEntity.position(), blockEntityWithBlockState.blockState());
}

if (javaBlockEntity != null && javaBlockEntity.tag() != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,10 +114,10 @@ public BedrockChunk createChunk(final int chunkX, final int chunkZ, final int no
if (!this.isInRenderDistance(chunkX, chunkZ)) {
ViaBedrock.getPlatform().getLogger().log(Level.WARNING, "Received chunk outside of render distance, but within load distance: " + chunkX + ", " + chunkZ);
final EntityTracker entityTracker = this.user().get(EntityTracker.class);
final PacketWrapper updateViewPosition = PacketWrapper.create(ClientboundPackets1_21.SET_CHUNK_CACHE_CENTER, this.user());
updateViewPosition.write(Types.VAR_INT, (int) entityTracker.getClientPlayer().position().x() >> 4); // chunk x
updateViewPosition.write(Types.VAR_INT, (int) entityTracker.getClientPlayer().position().z() >> 4); // chunk z
updateViewPosition.send(BedrockProtocol.class);
final PacketWrapper setChunkCacheCenter = PacketWrapper.create(ClientboundPackets1_21.SET_CHUNK_CACHE_CENTER, this.user());
setChunkCacheCenter.write(Types.VAR_INT, (int) entityTracker.getClientPlayer().position().x() >> 4); // chunk x
setChunkCacheCenter.write(Types.VAR_INT, (int) entityTracker.getClientPlayer().position().z() >> 4); // chunk z
setChunkCacheCenter.send(BedrockProtocol.class);
}

final BedrockChunk chunk = new BedrockChunk(chunkX, chunkZ, new BedrockChunkSection[this.worldHeight >> 4]);
Expand Down Expand Up @@ -360,7 +360,7 @@ public IntObjectPair<BlockEntity> handleBlockChange(final BlockPosition blockPos
return new IntObjectImmutablePair<>(remappedBlockState, javaBlockEntity);
}
} else if (BlockStateRewriter.TAG_ITEM_FRAME.equals(tag)) {
this.user().get(EntityTracker.class).spawnItemFrame(blockPosition, blockStateRewriter.blockState(blockState));
entityTracker.spawnItemFrame(blockPosition, blockStateRewriter.blockState(blockState));
}
}

Expand All @@ -384,20 +384,20 @@ public void sendChunk(final int chunkX, final int chunkZ) {
}
final Chunk remappedChunk = this.remapChunk(chunk);

final PacketWrapper wrapper = PacketWrapper.create(ClientboundPackets1_21.LEVEL_CHUNK_WITH_LIGHT, this.user());
final PacketWrapper levelChunkWithLight = PacketWrapper.create(ClientboundPackets1_21.LEVEL_CHUNK_WITH_LIGHT, this.user());
final BitSet lightMask = new BitSet();
lightMask.set(0, remappedChunk.getSections().length + 2);
wrapper.write(this.chunkType, remappedChunk); // chunk
wrapper.write(Types.LONG_ARRAY_PRIMITIVE, lightMask.toLongArray()); // sky light mask
wrapper.write(Types.LONG_ARRAY_PRIMITIVE, new long[0]); // block light mask
wrapper.write(Types.LONG_ARRAY_PRIMITIVE, new long[0]); // empty sky light mask
wrapper.write(Types.LONG_ARRAY_PRIMITIVE, lightMask.toLongArray()); // empty block light mask
wrapper.write(Types.VAR_INT, remappedChunk.getSections().length + 2); // sky light length
levelChunkWithLight.write(this.chunkType, remappedChunk); // chunk
levelChunkWithLight.write(Types.LONG_ARRAY_PRIMITIVE, lightMask.toLongArray()); // sky light mask
levelChunkWithLight.write(Types.LONG_ARRAY_PRIMITIVE, new long[0]); // block light mask
levelChunkWithLight.write(Types.LONG_ARRAY_PRIMITIVE, new long[0]); // empty sky light mask
levelChunkWithLight.write(Types.LONG_ARRAY_PRIMITIVE, lightMask.toLongArray()); // empty block light mask
levelChunkWithLight.write(Types.VAR_INT, remappedChunk.getSections().length + 2); // sky light length
for (int i = 0; i < remappedChunk.getSections().length + 2; i++) {
wrapper.write(Types.BYTE_ARRAY_PRIMITIVE, FULL_LIGHT); // sky light
levelChunkWithLight.write(Types.BYTE_ARRAY_PRIMITIVE, FULL_LIGHT); // sky light
}
wrapper.write(Types.VAR_INT, 0); // block light length
wrapper.send(BedrockProtocol.class);
levelChunkWithLight.write(Types.VAR_INT, 0); // block light length
levelChunkWithLight.send(BedrockProtocol.class);
}

public Dimension getDimension() {
Expand Down

0 comments on commit 9df738e

Please sign in to comment.