forked from GeyserMC/Geyser
Block breaking refactors (#1336)
Client-side block animations and reach checks are now added. This commit also includes cleanup in BlockChangeTranslator as well as proper Netherite tool support for calculating block breaking. Co-authored-by: rtm516 <rtm516@users.noreply.github.com>
This commit is contained in:
parent
fe23c79053
commit
ade4c14911
7 changed files with 224 additions and 78 deletions
|
@ -39,12 +39,11 @@ import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlaye
|
||||||
import com.nukkitx.math.vector.Vector3f;
|
import com.nukkitx.math.vector.Vector3f;
|
||||||
import com.nukkitx.math.vector.Vector3i;
|
import com.nukkitx.math.vector.Vector3i;
|
||||||
import com.nukkitx.protocol.bedrock.data.LevelEventType;
|
import com.nukkitx.protocol.bedrock.data.LevelEventType;
|
||||||
|
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
||||||
|
import com.nukkitx.protocol.bedrock.data.entity.EntityFlags;
|
||||||
import com.nukkitx.protocol.bedrock.data.inventory.ContainerId;
|
import com.nukkitx.protocol.bedrock.data.inventory.ContainerId;
|
||||||
import com.nukkitx.protocol.bedrock.data.inventory.ContainerType;
|
import com.nukkitx.protocol.bedrock.data.inventory.ContainerType;
|
||||||
import com.nukkitx.protocol.bedrock.packet.ContainerOpenPacket;
|
import com.nukkitx.protocol.bedrock.packet.*;
|
||||||
import com.nukkitx.protocol.bedrock.packet.InventorySlotPacket;
|
|
||||||
import com.nukkitx.protocol.bedrock.packet.InventoryTransactionPacket;
|
|
||||||
import com.nukkitx.protocol.bedrock.packet.LevelEventPacket;
|
|
||||||
import org.geysermc.connector.entity.CommandBlockMinecartEntity;
|
import org.geysermc.connector.entity.CommandBlockMinecartEntity;
|
||||||
import org.geysermc.connector.entity.Entity;
|
import org.geysermc.connector.entity.Entity;
|
||||||
import org.geysermc.connector.entity.ItemFrameEntity;
|
import org.geysermc.connector.entity.ItemFrameEntity;
|
||||||
|
@ -64,9 +63,18 @@ import org.geysermc.connector.utils.InventoryUtils;
|
||||||
|
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BedrockInventoryTransactionTranslator handles most interactions between the client and the world,
|
||||||
|
* or the client and their inventory.
|
||||||
|
*/
|
||||||
@Translator(packet = InventoryTransactionPacket.class)
|
@Translator(packet = InventoryTransactionPacket.class)
|
||||||
public class BedrockInventoryTransactionTranslator extends PacketTranslator<InventoryTransactionPacket> {
|
public class BedrockInventoryTransactionTranslator extends PacketTranslator<InventoryTransactionPacket> {
|
||||||
|
|
||||||
|
private static final float MAXIMUM_BLOCK_PLACING_DISTANCE = 64f;
|
||||||
|
private static final int CREATIVE_EYE_HEIGHT_PLACE_DISTANCE = 49;
|
||||||
|
private static final int SURVIVAL_EYE_HEIGHT_PLACE_DISTANCE = 36;
|
||||||
|
private static final float MAXIMUM_BLOCK_DESTROYING_DISTANCE = 36f;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void translate(InventoryTransactionPacket packet, GeyserSession session) {
|
public void translate(InventoryTransactionPacket packet, GeyserSession session) {
|
||||||
// Send book updates before opening inventories
|
// Send book updates before opening inventories
|
||||||
|
@ -112,6 +120,46 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Vector3i blockPos = BlockUtils.getBlockPosition(packet.getBlockPosition(), packet.getBlockFace());
|
||||||
|
/*
|
||||||
|
Checks to ensure that the range will be accepted by the server.
|
||||||
|
"Not in range" doesn't refer to how far a vanilla client goes (that's a whole other mess),
|
||||||
|
but how much a server will accept from the client maximum
|
||||||
|
*/
|
||||||
|
// CraftBukkit+ check - see https://github.com/PaperMC/Paper/blob/458db6206daae76327a64f4e2a17b67a7e38b426/Spigot-Server-Patches/0532-Move-range-check-for-block-placing-up.patch
|
||||||
|
Vector3f playerPosition = session.getPlayerEntity().getPosition();
|
||||||
|
EntityFlags flags = session.getPlayerEntity().getMetadata().getFlags();
|
||||||
|
|
||||||
|
// Adjust position for current eye height
|
||||||
|
if (flags.getFlag(EntityFlag.SNEAKING)) {
|
||||||
|
playerPosition = playerPosition.sub(0, (EntityType.PLAYER.getOffset() - 1.27f), 0);
|
||||||
|
} else if (flags.getFlag(EntityFlag.SWIMMING) || flags.getFlag(EntityFlag.GLIDING) || flags.getFlag(EntityFlag.DAMAGE_NEARBY_MOBS)) {
|
||||||
|
// Swimming, gliding, or using the trident spin attack
|
||||||
|
playerPosition = playerPosition.sub(0, (EntityType.PLAYER.getOffset() - 0.4f), 0);
|
||||||
|
} else if (flags.getFlag(EntityFlag.SLEEPING)) {
|
||||||
|
playerPosition = playerPosition.sub(0, (EntityType.PLAYER.getOffset() - 0.2f), 0);
|
||||||
|
} // else, we don't have to modify the position
|
||||||
|
|
||||||
|
float diffX = playerPosition.getX() - packet.getBlockPosition().getX();
|
||||||
|
float diffY = playerPosition.getY() - packet.getBlockPosition().getY();
|
||||||
|
float diffZ = playerPosition.getZ() - packet.getBlockPosition().getZ();
|
||||||
|
if (((diffX * diffX) + (diffY * diffY) + (diffZ * diffZ)) >
|
||||||
|
(session.getGameMode().equals(GameMode.CREATIVE) ? CREATIVE_EYE_HEIGHT_PLACE_DISTANCE : SURVIVAL_EYE_HEIGHT_PLACE_DISTANCE)) {
|
||||||
|
restoreCorrectBlock(session, blockPos, packet);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Vanilla check
|
||||||
|
if (!(session.getPlayerEntity().getPosition().sub(0, EntityType.PLAYER.getOffset(), 0)
|
||||||
|
.distanceSquared(packet.getBlockPosition().toFloat().add(0.5f, 0.5f, 0.5f)) < MAXIMUM_BLOCK_PLACING_DISTANCE)) {
|
||||||
|
// The client thinks that its blocks have been successfully placed. Restore the server's blocks instead.
|
||||||
|
restoreCorrectBlock(session, blockPos, packet);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
Block place checks end - client is good to go
|
||||||
|
*/
|
||||||
|
|
||||||
ClientPlayerPlaceBlockPacket blockPacket = new ClientPlayerPlaceBlockPacket(
|
ClientPlayerPlaceBlockPacket blockPacket = new ClientPlayerPlaceBlockPacket(
|
||||||
new Position(packet.getBlockPosition().getX(), packet.getBlockPosition().getY(), packet.getBlockPosition().getZ()),
|
new Position(packet.getBlockPosition().getX(), packet.getBlockPosition().getY(), packet.getBlockPosition().getZ()),
|
||||||
BlockFace.values()[packet.getBlockFace()],
|
BlockFace.values()[packet.getBlockFace()],
|
||||||
|
@ -159,7 +207,6 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector3i blockPos = BlockUtils.getBlockPosition(packet.getBlockPosition(), packet.getBlockFace());
|
|
||||||
ItemEntry handItem = ItemRegistry.getItem(packet.getItemInHand());
|
ItemEntry handItem = ItemRegistry.getItem(packet.getItemInHand());
|
||||||
if (handItem.isBlock()) {
|
if (handItem.isBlock()) {
|
||||||
session.setLastBlockPlacePosition(blockPos);
|
session.setLastBlockPlacePosition(blockPos);
|
||||||
|
@ -184,19 +231,32 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
|
||||||
session.sendDownstreamPacket(useItemPacket);
|
session.sendDownstreamPacket(useItemPacket);
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
int blockState = session.getConnector().getWorldManager().getBlockAt(session, packet.getBlockPosition().getX(), packet.getBlockPosition().getY(), packet.getBlockPosition().getZ());
|
int blockState = session.getGameMode() == GameMode.CREATIVE ?
|
||||||
double blockHardness = BlockTranslator.JAVA_RUNTIME_ID_TO_HARDNESS.get(blockState);
|
session.getConnector().getWorldManager().getBlockAt(session, packet.getBlockPosition()) : session.getBreakingBlock();
|
||||||
if (session.getGameMode() == GameMode.CREATIVE || (session.getConnector().getConfig().isCacheChunks() && blockHardness == 0)) {
|
|
||||||
session.setLastBlockPlacedId(null);
|
|
||||||
session.setLastBlockPlacePosition(null);
|
|
||||||
|
|
||||||
LevelEventPacket blockBreakPacket = new LevelEventPacket();
|
session.setLastBlockPlacedId(null);
|
||||||
blockBreakPacket.setType(LevelEventType.PARTICLE_DESTROY_BLOCK);
|
session.setLastBlockPlacePosition(null);
|
||||||
blockBreakPacket.setPosition(packet.getBlockPosition().toFloat());
|
|
||||||
blockBreakPacket.setData(BlockTranslator.getBedrockBlockId(blockState));
|
// Same deal with vanilla block placing as above.
|
||||||
session.sendUpstreamPacket(blockBreakPacket);
|
// This is working out the distance using 3d Pythagoras and the extra value added to the Y is the sneaking height of a java player.
|
||||||
|
playerPosition = session.getPlayerEntity().getPosition();
|
||||||
|
Vector3f floatBlockPosition = packet.getBlockPosition().toFloat();
|
||||||
|
diffX = playerPosition.getX() - (floatBlockPosition.getX() + 0.5f);
|
||||||
|
diffY = (playerPosition.getY() - EntityType.PLAYER.getOffset()) - (floatBlockPosition.getY() + 0.5f) + 1.5f;
|
||||||
|
diffZ = playerPosition.getZ() - (floatBlockPosition.getZ() + 0.5f);
|
||||||
|
float distanceSquared = diffX * diffX + diffY * diffY + diffZ * diffZ;
|
||||||
|
if (distanceSquared > MAXIMUM_BLOCK_DESTROYING_DISTANCE) {
|
||||||
|
restoreCorrectBlock(session, packet.getBlockPosition(), packet);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LevelEventPacket blockBreakPacket = new LevelEventPacket();
|
||||||
|
blockBreakPacket.setType(LevelEventType.PARTICLE_DESTROY_BLOCK);
|
||||||
|
blockBreakPacket.setPosition(packet.getBlockPosition().toFloat());
|
||||||
|
blockBreakPacket.setData(BlockTranslator.getBedrockBlockId(blockState));
|
||||||
|
session.sendUpstreamPacket(blockBreakPacket);
|
||||||
|
session.setBreakingBlock(BlockTranslator.JAVA_AIR_ID);
|
||||||
|
|
||||||
long frameEntityId = ItemFrameEntity.getItemFrameEntityId(session, packet.getBlockPosition());
|
long frameEntityId = ItemFrameEntity.getItemFrameEntityId(session, packet.getBlockPosition());
|
||||||
if (frameEntityId != -1 && session.getEntityCache().getEntityByJavaId(frameEntityId) != null) {
|
if (frameEntityId != -1 && session.getEntityCache().getEntityByJavaId(frameEntityId) != null) {
|
||||||
ClientPlayerInteractEntityPacket attackPacket = new ClientPlayerInteractEntityPacket((int) frameEntityId, InteractAction.ATTACK, session.isSneaking());
|
ClientPlayerInteractEntityPacket attackPacket = new ClientPlayerInteractEntityPacket((int) frameEntityId, InteractAction.ATTACK, session.isSneaking());
|
||||||
|
@ -270,4 +330,34 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Restore the correct block state from the server without updating the chunk cache.
|
||||||
|
*
|
||||||
|
* @param session the session of the Bedrock client
|
||||||
|
* @param blockPos the block position to restore
|
||||||
|
*/
|
||||||
|
private void restoreCorrectBlock(GeyserSession session, Vector3i blockPos, InventoryTransactionPacket packet) {
|
||||||
|
int javaBlockState = session.getConnector().getWorldManager().getBlockAt(session, blockPos);
|
||||||
|
UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket();
|
||||||
|
updateBlockPacket.setDataLayer(0);
|
||||||
|
updateBlockPacket.setBlockPosition(blockPos);
|
||||||
|
updateBlockPacket.setRuntimeId(BlockTranslator.getBedrockBlockId(javaBlockState));
|
||||||
|
updateBlockPacket.getFlags().addAll(UpdateBlockPacket.FLAG_ALL_PRIORITY);
|
||||||
|
session.sendUpstreamPacket(updateBlockPacket);
|
||||||
|
|
||||||
|
UpdateBlockPacket updateWaterPacket = new UpdateBlockPacket();
|
||||||
|
updateWaterPacket.setDataLayer(1);
|
||||||
|
updateWaterPacket.setBlockPosition(blockPos);
|
||||||
|
updateWaterPacket.setRuntimeId(BlockTranslator.isWaterlogged(javaBlockState) ? BlockTranslator.BEDROCK_WATER_ID : BlockTranslator.BEDROCK_AIR_ID);
|
||||||
|
updateWaterPacket.getFlags().addAll(UpdateBlockPacket.FLAG_ALL_PRIORITY);
|
||||||
|
session.sendUpstreamPacket(updateWaterPacket);
|
||||||
|
|
||||||
|
// Reset the item in hand to prevent "missing" blocks
|
||||||
|
InventorySlotPacket slotPacket = new InventorySlotPacket();
|
||||||
|
slotPacket.setContainerId(ContainerId.INVENTORY);
|
||||||
|
slotPacket.setSlot(packet.getHotbarSlot());
|
||||||
|
slotPacket.setItem(packet.getItemInHand());
|
||||||
|
session.sendUpstreamPacket(slotPacket);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,13 +25,16 @@
|
||||||
|
|
||||||
package org.geysermc.connector.network.translators.bedrock.entity.player;
|
package org.geysermc.connector.network.translators.bedrock.entity.player;
|
||||||
|
|
||||||
|
import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
|
||||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position;
|
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position;
|
||||||
|
import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode;
|
||||||
import com.github.steveice10.mc.protocol.data.game.entity.player.PlayerAction;
|
import com.github.steveice10.mc.protocol.data.game.entity.player.PlayerAction;
|
||||||
import com.github.steveice10.mc.protocol.data.game.entity.player.PlayerState;
|
import com.github.steveice10.mc.protocol.data.game.entity.player.PlayerState;
|
||||||
import com.github.steveice10.mc.protocol.data.game.world.block.BlockFace;
|
import com.github.steveice10.mc.protocol.data.game.world.block.BlockFace;
|
||||||
import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerAbilitiesPacket;
|
import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerAbilitiesPacket;
|
||||||
import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerActionPacket;
|
import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerActionPacket;
|
||||||
import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerStatePacket;
|
import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerStatePacket;
|
||||||
|
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
||||||
import com.nukkitx.math.vector.Vector3i;
|
import com.nukkitx.math.vector.Vector3i;
|
||||||
import com.nukkitx.protocol.bedrock.data.LevelEventType;
|
import com.nukkitx.protocol.bedrock.data.LevelEventType;
|
||||||
import com.nukkitx.protocol.bedrock.data.entity.EntityEventType;
|
import com.nukkitx.protocol.bedrock.data.entity.EntityEventType;
|
||||||
|
@ -40,9 +43,12 @@ import com.nukkitx.protocol.bedrock.packet.LevelEventPacket;
|
||||||
import com.nukkitx.protocol.bedrock.packet.PlayStatusPacket;
|
import com.nukkitx.protocol.bedrock.packet.PlayStatusPacket;
|
||||||
import com.nukkitx.protocol.bedrock.packet.PlayerActionPacket;
|
import com.nukkitx.protocol.bedrock.packet.PlayerActionPacket;
|
||||||
import org.geysermc.connector.entity.Entity;
|
import org.geysermc.connector.entity.Entity;
|
||||||
|
import org.geysermc.connector.inventory.PlayerInventory;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||||
import org.geysermc.connector.network.translators.Translator;
|
import org.geysermc.connector.network.translators.Translator;
|
||||||
|
import org.geysermc.connector.network.translators.item.ItemEntry;
|
||||||
|
import org.geysermc.connector.network.translators.item.ItemRegistry;
|
||||||
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
||||||
import org.geysermc.connector.utils.BlockUtils;
|
import org.geysermc.connector.utils.BlockUtils;
|
||||||
|
|
||||||
|
@ -130,6 +136,27 @@ public class BedrockActionTranslator extends PacketTranslator<PlayerActionPacket
|
||||||
break;
|
break;
|
||||||
case START_BREAK:
|
case START_BREAK:
|
||||||
if (session.getConnector().getConfig().isCacheChunks()) {
|
if (session.getConnector().getConfig().isCacheChunks()) {
|
||||||
|
// Start the block breaking animation
|
||||||
|
if (session.getGameMode() != GameMode.CREATIVE) {
|
||||||
|
int blockState = session.getConnector().getWorldManager().getBlockAt(session, vector);
|
||||||
|
double blockHardness = BlockTranslator.JAVA_RUNTIME_ID_TO_HARDNESS.get(blockState);
|
||||||
|
LevelEventPacket startBreak = new LevelEventPacket();
|
||||||
|
startBreak.setType(LevelEventType.BLOCK_START_BREAK);
|
||||||
|
startBreak.setPosition(vector.toFloat());
|
||||||
|
PlayerInventory inventory = session.getInventory();
|
||||||
|
ItemStack item = inventory.getItemInHand();
|
||||||
|
ItemEntry itemEntry = null;
|
||||||
|
CompoundTag nbtData = new CompoundTag("");
|
||||||
|
if (item != null) {
|
||||||
|
itemEntry = ItemRegistry.getItem(item);
|
||||||
|
nbtData = item.getNbt();
|
||||||
|
}
|
||||||
|
double breakTime = Math.ceil(BlockUtils.getBreakTime(blockHardness, blockState, itemEntry, nbtData, session) * 20);
|
||||||
|
startBreak.setData((int) (65535 / breakTime));
|
||||||
|
session.setBreakingBlock(blockState);
|
||||||
|
session.sendUpstreamPacket(startBreak);
|
||||||
|
}
|
||||||
|
|
||||||
// Account for fire - the client likes to hit the block behind.
|
// Account for fire - the client likes to hit the block behind.
|
||||||
Vector3i fireBlockPos = BlockUtils.getBlockPosition(packet.getBlockPosition(), packet.getFace());
|
Vector3i fireBlockPos = BlockUtils.getBlockPosition(packet.getBlockPosition(), packet.getFace());
|
||||||
int blockUp = session.getConnector().getWorldManager().getBlockAt(session, fireBlockPos);
|
int blockUp = session.getConnector().getWorldManager().getBlockAt(session, fireBlockPos);
|
||||||
|
@ -138,24 +165,33 @@ public class BedrockActionTranslator extends PacketTranslator<PlayerActionPacket
|
||||||
ClientPlayerActionPacket startBreakingPacket = new ClientPlayerActionPacket(PlayerAction.START_DIGGING, new Position(fireBlockPos.getX(),
|
ClientPlayerActionPacket startBreakingPacket = new ClientPlayerActionPacket(PlayerAction.START_DIGGING, new Position(fireBlockPos.getX(),
|
||||||
fireBlockPos.getY(), fireBlockPos.getZ()), BlockFace.values()[packet.getFace()]);
|
fireBlockPos.getY(), fireBlockPos.getZ()), BlockFace.values()[packet.getFace()]);
|
||||||
session.sendDownstreamPacket(startBreakingPacket);
|
session.sendDownstreamPacket(startBreakingPacket);
|
||||||
break;
|
if (session.getGameMode() == GameMode.CREATIVE) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ClientPlayerActionPacket startBreakingPacket = new ClientPlayerActionPacket(PlayerAction.START_DIGGING, new Position(packet.getBlockPosition().getX(),
|
ClientPlayerActionPacket startBreakingPacket = new ClientPlayerActionPacket(PlayerAction.START_DIGGING, position, BlockFace.values()[packet.getFace()]);
|
||||||
packet.getBlockPosition().getY(), packet.getBlockPosition().getZ()), BlockFace.values()[packet.getFace()]);
|
|
||||||
session.sendDownstreamPacket(startBreakingPacket);
|
session.sendDownstreamPacket(startBreakingPacket);
|
||||||
break;
|
break;
|
||||||
case CONTINUE_BREAK:
|
case CONTINUE_BREAK:
|
||||||
|
if (session.getGameMode() == GameMode.CREATIVE) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
LevelEventPacket continueBreakPacket = new LevelEventPacket();
|
LevelEventPacket continueBreakPacket = new LevelEventPacket();
|
||||||
continueBreakPacket.setType(LevelEventType.PARTICLE_CRACK_BLOCK);
|
continueBreakPacket.setType(LevelEventType.PARTICLE_CRACK_BLOCK);
|
||||||
continueBreakPacket.setData(BlockTranslator.getBedrockBlockId(session.getBreakingBlock()));
|
continueBreakPacket.setData((BlockTranslator.getBedrockBlockId(session.getBreakingBlock())) | (packet.getFace() << 24));
|
||||||
continueBreakPacket.setPosition(packet.getBlockPosition().toFloat());
|
continueBreakPacket.setPosition(vector.toFloat());
|
||||||
session.sendUpstreamPacket(continueBreakPacket);
|
session.sendUpstreamPacket(continueBreakPacket);
|
||||||
break;
|
break;
|
||||||
case ABORT_BREAK:
|
case ABORT_BREAK:
|
||||||
ClientPlayerActionPacket abortBreakingPacket = new ClientPlayerActionPacket(PlayerAction.CANCEL_DIGGING, new Position(packet.getBlockPosition().getX(),
|
ClientPlayerActionPacket abortBreakingPacket = new ClientPlayerActionPacket(PlayerAction.CANCEL_DIGGING, position, BlockFace.DOWN);
|
||||||
packet.getBlockPosition().getY(), packet.getBlockPosition().getZ()), BlockFace.DOWN);
|
|
||||||
session.sendDownstreamPacket(abortBreakingPacket);
|
session.sendDownstreamPacket(abortBreakingPacket);
|
||||||
|
LevelEventPacket stopBreak = new LevelEventPacket();
|
||||||
|
stopBreak.setType(LevelEventType.BLOCK_STOP_BREAK);
|
||||||
|
stopBreak.setPosition(vector.toFloat());
|
||||||
|
stopBreak.setData(0);
|
||||||
|
session.setBreakingBlock(BlockTranslator.JAVA_AIR_ID);
|
||||||
|
session.sendUpstreamPacket(stopBreak);
|
||||||
break;
|
break;
|
||||||
case STOP_BREAK:
|
case STOP_BREAK:
|
||||||
// Handled in BedrockInventoryTransactionTranslator
|
// Handled in BedrockInventoryTransactionTranslator
|
||||||
|
|
|
@ -31,8 +31,8 @@ import com.nukkitx.protocol.bedrock.data.LevelEventType;
|
||||||
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
||||||
import com.nukkitx.protocol.bedrock.data.entity.EntityEventType;
|
import com.nukkitx.protocol.bedrock.data.entity.EntityEventType;
|
||||||
import com.nukkitx.protocol.bedrock.packet.EntityEventPacket;
|
import com.nukkitx.protocol.bedrock.packet.EntityEventPacket;
|
||||||
import com.nukkitx.protocol.bedrock.packet.LevelSoundEvent2Packet;
|
|
||||||
import com.nukkitx.protocol.bedrock.packet.LevelEventPacket;
|
import com.nukkitx.protocol.bedrock.packet.LevelEventPacket;
|
||||||
|
import com.nukkitx.protocol.bedrock.packet.LevelSoundEvent2Packet;
|
||||||
import com.nukkitx.protocol.bedrock.packet.SetEntityDataPacket;
|
import com.nukkitx.protocol.bedrock.packet.SetEntityDataPacket;
|
||||||
import com.nukkitx.protocol.bedrock.packet.SetEntityMotionPacket;
|
import com.nukkitx.protocol.bedrock.packet.SetEntityMotionPacket;
|
||||||
import org.geysermc.connector.entity.Entity;
|
import org.geysermc.connector.entity.Entity;
|
||||||
|
@ -183,6 +183,19 @@ public class JavaEntityStatusTranslator extends PacketTranslator<ServerEntitySta
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case LIVING_EQUIPMENT_BREAK_HEAD:
|
||||||
|
case LIVING_EQUIPMENT_BREAK_CHEST:
|
||||||
|
case LIVING_EQUIPMENT_BREAK_LEGS:
|
||||||
|
case LIVING_EQUIPMENT_BREAK_FEET:
|
||||||
|
case LIVING_EQUIPMENT_BREAK_MAIN_HAND:
|
||||||
|
case LIVING_EQUIPMENT_BREAK_OFF_HAND:
|
||||||
|
LevelSoundEvent2Packet equipmentBreakPacket = new LevelSoundEvent2Packet();
|
||||||
|
equipmentBreakPacket.setSound(SoundEvent.BREAK);
|
||||||
|
equipmentBreakPacket.setPosition(entity.getPosition());
|
||||||
|
equipmentBreakPacket.setExtraData(-1);
|
||||||
|
equipmentBreakPacket.setIdentifier("");
|
||||||
|
session.sendUpstreamPacket(equipmentBreakPacket);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
session.sendUpstreamPacket(entityEventPacket);
|
session.sendUpstreamPacket(entityEventPacket);
|
||||||
|
|
|
@ -27,19 +27,20 @@ package org.geysermc.connector.network.translators.java.entity.player;
|
||||||
|
|
||||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
|
import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
|
||||||
import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode;
|
import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode;
|
||||||
|
import com.github.steveice10.mc.protocol.data.game.entity.player.PlayerAction;
|
||||||
import com.github.steveice10.mc.protocol.packet.ingame.server.entity.player.ServerPlayerActionAckPacket;
|
import com.github.steveice10.mc.protocol.packet.ingame.server.entity.player.ServerPlayerActionAckPacket;
|
||||||
import com.github.steveice10.opennbt.tag.builtin.*;
|
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
||||||
import com.nukkitx.math.vector.Vector3f;
|
import com.nukkitx.math.vector.Vector3f;
|
||||||
import com.nukkitx.protocol.bedrock.data.LevelEventType;
|
import com.nukkitx.protocol.bedrock.data.LevelEventType;
|
||||||
import com.nukkitx.protocol.bedrock.packet.LevelEventPacket;
|
import com.nukkitx.protocol.bedrock.packet.LevelEventPacket;
|
||||||
import org.geysermc.connector.inventory.PlayerInventory;
|
import org.geysermc.connector.inventory.PlayerInventory;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||||
|
import org.geysermc.connector.network.translators.Translator;
|
||||||
|
import org.geysermc.connector.network.translators.item.ItemEntry;
|
||||||
import org.geysermc.connector.network.translators.item.ItemRegistry;
|
import org.geysermc.connector.network.translators.item.ItemRegistry;
|
||||||
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
||||||
import org.geysermc.connector.network.translators.item.ItemEntry;
|
|
||||||
import org.geysermc.connector.utils.BlockUtils;
|
import org.geysermc.connector.utils.BlockUtils;
|
||||||
import org.geysermc.connector.network.translators.Translator;
|
|
||||||
import org.geysermc.connector.utils.ChunkUtils;
|
import org.geysermc.connector.utils.ChunkUtils;
|
||||||
|
|
||||||
@Translator(packet = ServerPlayerActionAckPacket.class)
|
@Translator(packet = ServerPlayerActionAckPacket.class)
|
||||||
|
@ -47,54 +48,54 @@ public class JavaPlayerActionAckTranslator extends PacketTranslator<ServerPlayer
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void translate(ServerPlayerActionAckPacket packet, GeyserSession session) {
|
public void translate(ServerPlayerActionAckPacket packet, GeyserSession session) {
|
||||||
LevelEventPacket levelEvent = new LevelEventPacket();
|
ChunkUtils.updateBlock(session, packet.getNewState(), packet.getPosition());
|
||||||
switch (packet.getAction()) {
|
if (packet.getAction() == PlayerAction.START_DIGGING && !packet.isSuccessful()) {
|
||||||
case FINISH_DIGGING:
|
LevelEventPacket stopBreak = new LevelEventPacket();
|
||||||
double blockHardness = BlockTranslator.JAVA_RUNTIME_ID_TO_HARDNESS.get(session.getBreakingBlock());
|
stopBreak.setType(LevelEventType.BLOCK_STOP_BREAK);
|
||||||
if (session.getGameMode() != GameMode.CREATIVE && blockHardness != 0) {
|
stopBreak.setPosition(Vector3f.from(packet.getPosition().getX(), packet.getPosition().getY(), packet.getPosition().getZ()));
|
||||||
levelEvent.setType(LevelEventType.PARTICLE_DESTROY_BLOCK);
|
stopBreak.setData(0);
|
||||||
levelEvent.setPosition(Vector3f.from(packet.getPosition().getX(), packet.getPosition().getY(), packet.getPosition().getZ()));
|
session.setBreakingBlock(BlockTranslator.JAVA_AIR_ID);
|
||||||
levelEvent.setData(BlockTranslator.getBedrockBlockId(session.getBreakingBlock()));
|
session.sendUpstreamPacket(stopBreak);
|
||||||
|
}
|
||||||
|
if (!session.getConnector().getConfig().isCacheChunks()) {
|
||||||
|
LevelEventPacket levelEvent = new LevelEventPacket();
|
||||||
|
switch (packet.getAction()) {
|
||||||
|
case START_DIGGING:
|
||||||
|
if (session.getGameMode() == GameMode.CREATIVE) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
double blockHardness = BlockTranslator.JAVA_RUNTIME_ID_TO_HARDNESS.get(packet.getNewState());
|
||||||
|
levelEvent.setType(LevelEventType.BLOCK_START_BREAK);
|
||||||
|
levelEvent.setPosition(Vector3f.from(
|
||||||
|
packet.getPosition().getX(),
|
||||||
|
packet.getPosition().getY(),
|
||||||
|
packet.getPosition().getZ()
|
||||||
|
));
|
||||||
|
PlayerInventory inventory = session.getInventory();
|
||||||
|
ItemStack item = inventory.getItemInHand();
|
||||||
|
ItemEntry itemEntry = null;
|
||||||
|
CompoundTag nbtData = new CompoundTag("");
|
||||||
|
if (item != null) {
|
||||||
|
itemEntry = ItemRegistry.getItem(item);
|
||||||
|
nbtData = item.getNbt();
|
||||||
|
}
|
||||||
|
double breakTime = Math.ceil(BlockUtils.getBreakTime(blockHardness, packet.getNewState(), itemEntry, nbtData, session) * 20);
|
||||||
|
levelEvent.setData((int) (65535 / breakTime));
|
||||||
|
session.setBreakingBlock(packet.getNewState());
|
||||||
session.sendUpstreamPacket(levelEvent);
|
session.sendUpstreamPacket(levelEvent);
|
||||||
session.setBreakingBlock(0);
|
|
||||||
}
|
|
||||||
ChunkUtils.updateBlock(session, packet.getNewState(), packet.getPosition());
|
|
||||||
break;
|
|
||||||
case START_DIGGING:
|
|
||||||
if (session.getGameMode() == GameMode.CREATIVE) {
|
|
||||||
break;
|
break;
|
||||||
}
|
case CANCEL_DIGGING:
|
||||||
blockHardness = BlockTranslator.JAVA_RUNTIME_ID_TO_HARDNESS.get(packet.getNewState());
|
levelEvent.setType(LevelEventType.BLOCK_STOP_BREAK);
|
||||||
levelEvent.setType(LevelEventType.BLOCK_START_BREAK);
|
levelEvent.setPosition(Vector3f.from(
|
||||||
levelEvent.setPosition(Vector3f.from(
|
packet.getPosition().getX(),
|
||||||
packet.getPosition().getX(),
|
packet.getPosition().getY(),
|
||||||
packet.getPosition().getY(),
|
packet.getPosition().getZ()
|
||||||
packet.getPosition().getZ()
|
));
|
||||||
));
|
levelEvent.setData(0);
|
||||||
PlayerInventory inventory = session.getInventory();
|
session.setBreakingBlock(0);
|
||||||
ItemStack item = inventory.getItemInHand();
|
session.sendUpstreamPacket(levelEvent);
|
||||||
ItemEntry itemEntry = null;
|
break;
|
||||||
CompoundTag nbtData = new CompoundTag("");
|
}
|
||||||
if (item != null) {
|
|
||||||
itemEntry = ItemRegistry.getItem(item);
|
|
||||||
nbtData = item.getNbt();
|
|
||||||
}
|
|
||||||
double breakTime = Math.ceil(BlockUtils.getBreakTime(blockHardness, packet.getNewState(), itemEntry, nbtData, session) * 20);
|
|
||||||
levelEvent.setData((int) (65535 / breakTime));
|
|
||||||
session.setBreakingBlock(packet.getNewState());
|
|
||||||
session.sendUpstreamPacket(levelEvent);
|
|
||||||
break;
|
|
||||||
case CANCEL_DIGGING:
|
|
||||||
levelEvent.setType(LevelEventType.BLOCK_STOP_BREAK);
|
|
||||||
levelEvent.setPosition(Vector3f.from(
|
|
||||||
packet.getPosition().getX(),
|
|
||||||
packet.getPosition().getY(),
|
|
||||||
packet.getPosition().getZ()
|
|
||||||
));
|
|
||||||
levelEvent.setData(0);
|
|
||||||
session.setBreakingBlock(0);
|
|
||||||
session.sendUpstreamPacket(levelEvent);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -26,6 +26,7 @@
|
||||||
package org.geysermc.connector.network.translators.java.world;
|
package org.geysermc.connector.network.translators.java.world;
|
||||||
|
|
||||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position;
|
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position;
|
||||||
|
import com.github.steveice10.mc.protocol.packet.ingame.server.world.ServerBlockChangePacket;
|
||||||
import com.nukkitx.math.vector.Vector3i;
|
import com.nukkitx.math.vector.Vector3i;
|
||||||
import com.nukkitx.protocol.bedrock.data.SoundEvent;
|
import com.nukkitx.protocol.bedrock.data.SoundEvent;
|
||||||
import com.nukkitx.protocol.bedrock.packet.LevelSoundEventPacket;
|
import com.nukkitx.protocol.bedrock.packet.LevelSoundEventPacket;
|
||||||
|
@ -37,17 +38,17 @@ import org.geysermc.connector.network.translators.sound.BlockSoundInteractionHan
|
||||||
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
||||||
import org.geysermc.connector.utils.ChunkUtils;
|
import org.geysermc.connector.utils.ChunkUtils;
|
||||||
|
|
||||||
import com.github.steveice10.mc.protocol.packet.ingame.server.world.ServerBlockChangePacket;
|
|
||||||
|
|
||||||
@Translator(packet = ServerBlockChangePacket.class)
|
@Translator(packet = ServerBlockChangePacket.class)
|
||||||
public class JavaBlockChangeTranslator extends PacketTranslator<ServerBlockChangePacket> {
|
public class JavaBlockChangeTranslator extends PacketTranslator<ServerBlockChangePacket> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void translate(ServerBlockChangePacket packet, GeyserSession session) {
|
public void translate(ServerBlockChangePacket packet, GeyserSession session) {
|
||||||
Position pos = packet.getRecord().getPosition();
|
Position pos = packet.getRecord().getPosition();
|
||||||
boolean updatePlacement = !(session.getConnector().getConfig().isCacheChunks() && session.getConnector().getWorldManager().getBlockAt(session, pos.getX(), pos.getY(), pos.getZ()) == packet.getRecord().getBlock());
|
boolean updatePlacement = session.getConnector().getPlatformType() != PlatformType.SPIGOT && // Spigot simply listens for the block place event
|
||||||
ChunkUtils.updateBlock(session, packet.getRecord().getBlock(), packet.getRecord().getPosition());
|
!(session.getConnector().getConfig().isCacheChunks() &&
|
||||||
if (updatePlacement && session.getConnector().getPlatformType() != PlatformType.SPIGOT) {
|
session.getConnector().getWorldManager().getBlockAt(session, pos) == packet.getRecord().getBlock());
|
||||||
|
ChunkUtils.updateBlock(session, packet.getRecord().getBlock(), pos);
|
||||||
|
if (updatePlacement) {
|
||||||
this.checkPlace(session, packet);
|
this.checkPlace(session, packet);
|
||||||
}
|
}
|
||||||
this.checkInteract(session, packet);
|
this.checkInteract(session, packet);
|
||||||
|
|
|
@ -87,7 +87,9 @@ public class BlockTranslator {
|
||||||
*/
|
*/
|
||||||
public static final int BEDROCK_RUNTIME_COMMAND_BLOCK_ID;
|
public static final int BEDROCK_RUNTIME_COMMAND_BLOCK_ID;
|
||||||
|
|
||||||
// For block breaking animation math
|
/**
|
||||||
|
* A list of all Java runtime wool IDs, for use with block breaking math and shears
|
||||||
|
*/
|
||||||
public static final IntSet JAVA_RUNTIME_WOOL_IDS = new IntOpenHashSet();
|
public static final IntSet JAVA_RUNTIME_WOOL_IDS = new IntOpenHashSet();
|
||||||
public static final int JAVA_RUNTIME_COBWEB_ID;
|
public static final int JAVA_RUNTIME_COBWEB_ID;
|
||||||
|
|
||||||
|
|
|
@ -50,6 +50,7 @@ public class BlockUtils {
|
||||||
if (toolType.equals("shears")) return isWoolBlock ? 5.0 : 15.0;
|
if (toolType.equals("shears")) return isWoolBlock ? 5.0 : 15.0;
|
||||||
if (toolType.equals("")) return 1.0;
|
if (toolType.equals("")) return 1.0;
|
||||||
switch (toolTier) {
|
switch (toolTier) {
|
||||||
|
// https://minecraft.gamepedia.com/Breaking#Speed
|
||||||
case "wooden":
|
case "wooden":
|
||||||
return 2.0;
|
return 2.0;
|
||||||
case "stone":
|
case "stone":
|
||||||
|
@ -58,6 +59,8 @@ public class BlockUtils {
|
||||||
return 6.0;
|
return 6.0;
|
||||||
case "diamond":
|
case "diamond":
|
||||||
return 8.0;
|
return 8.0;
|
||||||
|
case "netherite":
|
||||||
|
return 9.0;
|
||||||
case "golden":
|
case "golden":
|
||||||
return 12.0;
|
return 12.0;
|
||||||
default:
|
default:
|
||||||
|
|
Loading…
Reference in a new issue