mirror of
https://github.com/GeyserMC/Geyser.git
synced 2025-04-17 19:12:14 +02:00
Merge 8e98ac4be2
into 23a462d60c
This commit is contained in:
commit
bae635ef47
7 changed files with 271 additions and 193 deletions
core/src/main/java/org/geysermc/geyser
registry/type
session
translator
inventory
protocol/bedrock
util
|
@ -144,7 +144,7 @@ public class ItemMappings implements DefinitionRegistry<ItemDefinition> {
|
|||
return lightBlock;
|
||||
}
|
||||
|
||||
boolean isBlock = data.getBlockDefinition() != null;
|
||||
boolean isBlock = data.getBlockDefinition() != null && data.getBlockDefinition().getRuntimeId() != 0;
|
||||
boolean hasDamage = data.getDamage() != 0;
|
||||
|
||||
for (ItemMapping mapping : this.items) {
|
||||
|
|
|
@ -407,9 +407,24 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
|
|||
@Setter
|
||||
private BedrockDimension bedrockDimension = this.bedrockOverworldDimension;
|
||||
|
||||
/**
|
||||
* Stores the blockstate of the block being currently broken.
|
||||
*/
|
||||
@Setter
|
||||
private int breakingBlock;
|
||||
|
||||
/**
|
||||
* Stores the block break position of the currently broken block.
|
||||
*/
|
||||
@Setter
|
||||
private Vector3i blockBreakPosition;
|
||||
|
||||
/**
|
||||
* Stores the block breaking progress of the currently broken block.
|
||||
*/
|
||||
@Setter
|
||||
private double blockBreakProgress;
|
||||
|
||||
@Setter
|
||||
private Vector3i lastBlockPlacePosition;
|
||||
|
||||
|
@ -1608,7 +1623,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
|
|||
|
||||
startGamePacket.setAuthoritativeMovementMode(AuthoritativeMovementMode.SERVER);
|
||||
startGamePacket.setRewindHistorySize(0);
|
||||
startGamePacket.setServerAuthoritativeBlockBreaking(false);
|
||||
startGamePacket.setServerAuthoritativeBlockBreaking(true);
|
||||
|
||||
startGamePacket.setServerId("");
|
||||
startGamePacket.setWorldId("");
|
||||
|
|
|
@ -572,9 +572,9 @@ public abstract class InventoryTranslator {
|
|||
case CRAFT_RESULTS_DEPRECATED: // Tends to be called for UI inventories
|
||||
case CRAFT_RECIPE_OPTIONAL: // Anvils and cartography tables will handle this
|
||||
case CRAFT_LOOM: // Looms 1.17.40+
|
||||
case CRAFT_REPAIR_AND_DISENCHANT: { // Grindstones 1.17.40+
|
||||
case CRAFT_REPAIR_AND_DISENCHANT: // Grindstones 1.17.40+
|
||||
case MINE_BLOCK: // Server auth block breaking, confirms durability change
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return rejectRequest(request);
|
||||
}
|
||||
|
|
|
@ -175,6 +175,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
|
|||
break;
|
||||
case ITEM_USE:
|
||||
switch (packet.getActionType()) {
|
||||
// Block placing
|
||||
case 0 -> {
|
||||
final Vector3i packetBlockPosition = packet.getBlockPosition();
|
||||
Vector3i blockPos = BlockUtils.getBlockPosition(packetBlockPosition, packet.getBlockFace());
|
||||
|
|
|
@ -32,7 +32,9 @@ import org.cloudburstmc.protocol.bedrock.data.PlayerActionType;
|
|||
import org.cloudburstmc.protocol.bedrock.data.PlayerBlockActionData;
|
||||
import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.LevelEventPacket;
|
||||
import org.geysermc.geyser.GeyserImpl;
|
||||
import org.geysermc.geyser.api.block.custom.CustomBlockState;
|
||||
import org.geysermc.geyser.entity.EntityDefinitions;
|
||||
import org.geysermc.geyser.entity.type.Entity;
|
||||
import org.geysermc.geyser.entity.type.ItemFrameEntity;
|
||||
import org.geysermc.geyser.inventory.GeyserItemStack;
|
||||
|
@ -44,6 +46,7 @@ import org.geysermc.geyser.registry.type.ItemMapping;
|
|||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.session.cache.SkullCache;
|
||||
import org.geysermc.geyser.translator.item.CustomItemTranslator;
|
||||
import org.geysermc.geyser.translator.protocol.bedrock.BedrockInventoryTransactionTranslator;
|
||||
import org.geysermc.geyser.util.BlockUtils;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.object.Direction;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode;
|
||||
|
@ -62,164 +65,259 @@ final class BedrockBlockActions {
|
|||
session.getBookEditCache().checkForSend();
|
||||
|
||||
for (PlayerBlockActionData blockActionData : playerActions) {
|
||||
handle(session, blockActionData);
|
||||
}
|
||||
}
|
||||
PlayerActionType action = blockActionData.getAction();
|
||||
Vector3i vector = blockActionData.getBlockPosition();
|
||||
int blockFace = blockActionData.getFace();
|
||||
|
||||
private static void handle(GeyserSession session, PlayerBlockActionData blockActionData) {
|
||||
PlayerActionType action = blockActionData.getAction();
|
||||
Vector3i vector = blockActionData.getBlockPosition();
|
||||
int blockFace = blockActionData.getFace();
|
||||
switch (action) {
|
||||
case DROP_ITEM -> {
|
||||
ServerboundPlayerActionPacket dropItemPacket = new ServerboundPlayerActionPacket(PlayerAction.DROP_ITEM,
|
||||
vector, Direction.VALUES[blockFace], 0);
|
||||
session.sendDownstreamGamePacket(dropItemPacket);
|
||||
}
|
||||
case START_BREAK -> {
|
||||
// Ignore START_BREAK when the player is CREATIVE to avoid Spigot receiving 2 packets it interpets as block breaking. https://github.com/GeyserMC/Geyser/issues/4021
|
||||
if (session.getGameMode() == GameMode.CREATIVE) {
|
||||
break;
|
||||
GeyserImpl.getInstance().getLogger().info(blockActionData.toString());
|
||||
|
||||
switch (action) {
|
||||
case DROP_ITEM -> {
|
||||
ServerboundPlayerActionPacket dropItemPacket = new ServerboundPlayerActionPacket(PlayerAction.DROP_ITEM,
|
||||
vector, Direction.VALUES[blockFace], 0);
|
||||
session.sendDownstreamGamePacket(dropItemPacket);
|
||||
}
|
||||
|
||||
if (!canMine(session, vector)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Start the block breaking animation
|
||||
int blockState = session.getGeyser().getWorldManager().getBlockAt(session, vector);
|
||||
LevelEventPacket startBreak = new LevelEventPacket();
|
||||
startBreak.setType(LevelEvent.BLOCK_START_BREAK);
|
||||
startBreak.setPosition(vector.toFloat());
|
||||
double breakTime = BlockUtils.getSessionBreakTimeTicks(session, BlockState.of(blockState).block());
|
||||
|
||||
// If the block is custom or the breaking item is custom, we must keep track of break time ourselves
|
||||
GeyserItemStack item = session.getPlayerInventory().getItemInHand();
|
||||
ItemMapping mapping = item.getMapping(session);
|
||||
ItemDefinition customItem = mapping.isTool() ? CustomItemTranslator.getCustomItem(item.getComponents(), mapping) : null;
|
||||
CustomBlockState blockStateOverride = BlockRegistries.CUSTOM_BLOCK_STATE_OVERRIDES.get(blockState);
|
||||
SkullCache.Skull skull = session.getSkullCache().getSkulls().get(vector);
|
||||
|
||||
session.setBlockBreakStartTime(0);
|
||||
if (blockStateOverride != null || customItem != null || (skull != null && skull.getBlockDefinition() != null)) {
|
||||
session.setBlockBreakStartTime(System.currentTimeMillis());
|
||||
}
|
||||
startBreak.setData((int) (65535 / breakTime));
|
||||
session.setBreakingBlock(blockState);
|
||||
session.sendUpstreamPacket(startBreak);
|
||||
|
||||
// Account for fire - the client likes to hit the block behind.
|
||||
Vector3i fireBlockPos = BlockUtils.getBlockPosition(vector, blockFace);
|
||||
Block block = session.getGeyser().getWorldManager().blockAt(session, fireBlockPos).block();
|
||||
Direction direction = Direction.VALUES[blockFace];
|
||||
if (block == Blocks.FIRE || block == Blocks.SOUL_FIRE) {
|
||||
ServerboundPlayerActionPacket startBreakingPacket = new ServerboundPlayerActionPacket(PlayerAction.START_DIGGING, fireBlockPos,
|
||||
direction, session.getWorldCache().nextPredictionSequence());
|
||||
session.sendDownstreamGamePacket(startBreakingPacket);
|
||||
}
|
||||
|
||||
ServerboundPlayerActionPacket startBreakingPacket = new ServerboundPlayerActionPacket(PlayerAction.START_DIGGING,
|
||||
vector, direction, session.getWorldCache().nextPredictionSequence());
|
||||
session.sendDownstreamGamePacket(startBreakingPacket);
|
||||
|
||||
spawnBlockBreakParticles(session, direction, vector, BlockState.of(blockState));
|
||||
}
|
||||
case CONTINUE_BREAK -> {
|
||||
if (session.getGameMode() == GameMode.CREATIVE) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (!canMine(session, vector)) {
|
||||
return;
|
||||
}
|
||||
|
||||
int breakingBlock = session.getBreakingBlock();
|
||||
if (breakingBlock == -1) {
|
||||
breakingBlock = Block.JAVA_AIR_ID;
|
||||
}
|
||||
|
||||
Vector3f vectorFloat = vector.toFloat();
|
||||
|
||||
BlockState breakingBlockState = BlockState.of(breakingBlock);
|
||||
Direction direction = Direction.VALUES[blockFace];
|
||||
spawnBlockBreakParticles(session, direction, vector, breakingBlockState);
|
||||
|
||||
double breakTime = BlockUtils.getSessionBreakTimeTicks(session, breakingBlockState.block());
|
||||
// If the block is custom, we must keep track of when it should break ourselves
|
||||
long blockBreakStartTime = session.getBlockBreakStartTime();
|
||||
if (blockBreakStartTime != 0) {
|
||||
long timeSinceStart = System.currentTimeMillis() - blockBreakStartTime;
|
||||
// We need to add a slight delay to the break time, otherwise the client breaks blocks too fast
|
||||
if (timeSinceStart >= (breakTime += 2) * 50) {
|
||||
// Play break sound and particle
|
||||
LevelEventPacket effectPacket = new LevelEventPacket();
|
||||
effectPacket.setPosition(vectorFloat);
|
||||
effectPacket.setType(LevelEvent.PARTICLE_DESTROY_BLOCK);
|
||||
effectPacket.setData(session.getBlockMappings().getBedrockBlockId(breakingBlock));
|
||||
session.sendUpstreamPacket(effectPacket);
|
||||
|
||||
// Break the block
|
||||
ServerboundPlayerActionPacket finishBreakingPacket = new ServerboundPlayerActionPacket(PlayerAction.FINISH_DIGGING,
|
||||
vector, direction, session.getWorldCache().nextPredictionSequence());
|
||||
session.sendDownstreamGamePacket(finishBreakingPacket);
|
||||
session.setBlockBreakStartTime(0);
|
||||
case START_BREAK -> handleStartBreak(session, vector, blockFace);
|
||||
case BLOCK_CONTINUE_DESTROY -> {
|
||||
if (session.getGameMode() == GameMode.CREATIVE || isSteeringBoat(session, vector)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Update the break time in the event that player conditions changed (jumping, effects applied)
|
||||
LevelEventPacket updateBreak = new LevelEventPacket();
|
||||
updateBreak.setType(LevelEvent.BLOCK_UPDATE_BREAK);
|
||||
updateBreak.setPosition(vectorFloat);
|
||||
updateBreak.setData((int) (65535 / breakTime));
|
||||
session.sendUpstreamPacket(updateBreak);
|
||||
}
|
||||
case ABORT_BREAK -> {
|
||||
if (session.getGameMode() != GameMode.CREATIVE) {
|
||||
// As of 1.16.210: item frame items are taken out here.
|
||||
// Survival also sends START_BREAK, but by attaching our process here adventure mode also works
|
||||
Entity itemFrameEntity = ItemFrameEntity.getItemFrameEntity(session, vector);
|
||||
if (itemFrameEntity != null) {
|
||||
ServerboundInteractPacket interactPacket = new ServerboundInteractPacket(itemFrameEntity.getEntityId(),
|
||||
InteractAction.ATTACK, Hand.MAIN_HAND, session.isSneaking());
|
||||
session.sendDownstreamGamePacket(interactPacket);
|
||||
|
||||
Direction direction = Direction.VALUES[blockFace];
|
||||
|
||||
// The Bedrock client won't send a new start_break packet, but just continue breaking blocks
|
||||
if (!vector.equals(session.getBlockBreakPosition())) {
|
||||
if (session.getBlockBreakProgress() < 1) {
|
||||
// Abort block breaking for previous block, and start breaking this new block
|
||||
// Otherwise the client will continue showing a block breaking animation for the previous block.
|
||||
stopBreakingBlock(session, session.getBlockBreakPosition().toFloat());
|
||||
ServerboundPlayerActionPacket abortBreakingPacket = new ServerboundPlayerActionPacket(PlayerAction.CANCEL_DIGGING, session.getBlockBreakPosition(), Direction.DOWN, 0);
|
||||
session.sendDownstreamGamePacket(abortBreakingPacket);
|
||||
}
|
||||
|
||||
// Start breaking the new block
|
||||
handleStartBreak(session, vector, blockFace);
|
||||
break;
|
||||
}
|
||||
|
||||
int breakingBlock = session.getBreakingBlock();
|
||||
if (breakingBlock == -1) {
|
||||
breakingBlock = Block.JAVA_AIR_ID;
|
||||
}
|
||||
|
||||
Vector3f vectorFloat = vector.toFloat();
|
||||
|
||||
BlockState breakingBlockState = BlockState.of(breakingBlock);
|
||||
spawnBlockBreakParticles(session, direction, vector, breakingBlockState);
|
||||
|
||||
double breakTime = BlockUtils.getSessionBreakTimeTicks(session, breakingBlockState.block());
|
||||
// If the block is custom, we must keep track of when it should break ourselves
|
||||
long blockBreakStartTime = session.getBlockBreakStartTime();
|
||||
if (blockBreakStartTime != 0) {
|
||||
long timeSinceStart = System.currentTimeMillis() - blockBreakStartTime;
|
||||
// We need to add a slight delay to the break time, otherwise the client breaks blocks too fast
|
||||
if (timeSinceStart >= (breakTime += 2) * 50) {
|
||||
stopBreakingBlock(session, vector.toFloat());
|
||||
// Play break sound and particle
|
||||
LevelEventPacket effectPacket = new LevelEventPacket();
|
||||
effectPacket.setPosition(vectorFloat);
|
||||
effectPacket.setType(LevelEvent.PARTICLE_DESTROY_BLOCK);
|
||||
effectPacket.setData(session.getBlockMappings().getBedrockBlockId(breakingBlock));
|
||||
session.sendUpstreamPacket(effectPacket);
|
||||
|
||||
// Break the block
|
||||
sendJavaPlayerActionPacket(session, PlayerAction.FINISH_DIGGING, vector, Direction.values()[blockFace]);
|
||||
resetSessionVariables(session);
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Update the break time in the event that player conditions changed (jumping, effects applied)
|
||||
LevelEventPacket updateBreak = new LevelEventPacket();
|
||||
updateBreak.setType(LevelEvent.BLOCK_UPDATE_BREAK);
|
||||
updateBreak.setPosition(vectorFloat);
|
||||
updateBreak.setData((int) (65535 / breakTime));
|
||||
session.sendUpstreamPacket(updateBreak);
|
||||
}
|
||||
case ABORT_BREAK -> {
|
||||
if (session.getGameMode() != GameMode.CREATIVE) {
|
||||
// As of 1.16.210: item frame items are taken out here.
|
||||
// Survival also sends START_BREAK, but by attaching our process here adventure mode also works
|
||||
Entity itemFrameEntity = ItemFrameEntity.getItemFrameEntity(session, vector);
|
||||
if (itemFrameEntity != null) {
|
||||
ServerboundInteractPacket interactPacket = new ServerboundInteractPacket(itemFrameEntity.getEntityId(),
|
||||
InteractAction.ATTACK, Hand.MAIN_HAND, session.isSneaking());
|
||||
session.sendDownstreamGamePacket(interactPacket);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ServerboundPlayerActionPacket abortBreakingPacket = new ServerboundPlayerActionPacket(PlayerAction.CANCEL_DIGGING, vector, Direction.DOWN, 0);
|
||||
session.sendDownstreamGamePacket(abortBreakingPacket);
|
||||
// Bedrock "confirms" that it stopped breaking blocks by sending an abort packet after breaking the block
|
||||
if (session.getBlockBreakPosition() == null) {
|
||||
break;
|
||||
}
|
||||
|
||||
LevelEventPacket stopBreak = new LevelEventPacket();
|
||||
stopBreak.setType(LevelEvent.BLOCK_STOP_BREAK);
|
||||
stopBreak.setPosition(vector.toFloat());
|
||||
stopBreak.setData(0);
|
||||
session.setBreakingBlock(-1);
|
||||
session.setBlockBreakStartTime(0);
|
||||
session.sendUpstreamPacket(stopBreak);
|
||||
}
|
||||
// Handled in BedrockInventoryTransactionTranslator
|
||||
case STOP_BREAK -> {
|
||||
|
||||
ServerboundPlayerActionPacket abortBreakingPacket = new ServerboundPlayerActionPacket(PlayerAction.CANCEL_DIGGING, vector, Direction.DOWN, 0);
|
||||
session.sendDownstreamGamePacket(abortBreakingPacket);
|
||||
|
||||
stopBreakingBlock(session, session.getBlockBreakPosition().toFloat());
|
||||
resetSessionVariables(session);
|
||||
}
|
||||
// Handled in BedrockInventoryTransactionTranslator
|
||||
case BLOCK_PREDICT_DESTROY -> {
|
||||
handleBlockDestroy(session, vector, blockFace);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean canMine(GeyserSession session, Vector3i vector) {
|
||||
private static void handleStartBreak(GeyserSession session, Vector3i vector, int blockFace) {
|
||||
|
||||
// Only send block breaking in the BLOCK_PREDICT_DESTROY case
|
||||
if (session.getGameMode() == GameMode.CREATIVE || isSteeringBoat(session, vector)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Entity itemFrameEntity = ItemFrameEntity.getItemFrameEntity(session, vector);
|
||||
if (itemFrameEntity != null) {
|
||||
// Will be handled in ABORT_BREAK
|
||||
return;
|
||||
}
|
||||
|
||||
Vector3f playerPosition = session.getPlayerEntity().getPosition();
|
||||
playerPosition = playerPosition.down(EntityDefinitions.PLAYER.offset() - session.getEyeHeight());
|
||||
if (!BedrockInventoryTransactionTranslator.canInteractWithBlock(session, playerPosition, vector)) {
|
||||
resetSessionVariables(session);
|
||||
stopBreakingBlock(session, vector.toFloat());
|
||||
return;
|
||||
}
|
||||
|
||||
int blockState = session.getGeyser().getWorldManager().getBlockAt(session, vector);
|
||||
double breakTime = BlockUtils.getSessionBreakTimeTicks(session, BlockState.of(blockState).block());
|
||||
|
||||
// Start the block breaking animation
|
||||
LevelEventPacket startBreak = new LevelEventPacket();
|
||||
startBreak.setType(LevelEvent.BLOCK_START_BREAK);
|
||||
startBreak.setPosition(vector.toFloat());
|
||||
startBreak.setData((int) (65535 / breakTime));
|
||||
session.sendUpstreamPacket(startBreak);
|
||||
|
||||
session.setBreakingBlock(blockState);
|
||||
session.setBlockBreakPosition(vector);
|
||||
session.setBlockBreakStartTime(0);
|
||||
|
||||
// If the block is custom or the breaking item is custom, we must keep track of break time ourselves
|
||||
// TODO 1.21.5 use tool attribute
|
||||
GeyserItemStack item = session.getPlayerInventory().getItemInHand();
|
||||
ItemMapping mapping = item.getMapping(session);
|
||||
ItemDefinition customItem = mapping.isTool() ? CustomItemTranslator.getCustomItem(item.getComponents(), mapping) : null;
|
||||
CustomBlockState blockStateOverride = BlockRegistries.CUSTOM_BLOCK_STATE_OVERRIDES.get(blockState);
|
||||
SkullCache.Skull skull = session.getSkullCache().getSkulls().get(vector);
|
||||
|
||||
if (blockStateOverride != null || customItem != null || (skull != null && skull.getBlockDefinition() != null)) {
|
||||
session.setBlockBreakStartTime(System.currentTimeMillis());
|
||||
}
|
||||
|
||||
Direction direction = Direction.VALUES[blockFace];
|
||||
spawnBlockBreakParticles(session, direction, vector, BlockState.of(blockState));
|
||||
|
||||
// Account for fire - the client likes to hit the block behind.
|
||||
Vector3i fireBlockPos = BlockUtils.getBlockPosition(vector, blockFace);
|
||||
Block block = session.getGeyser().getWorldManager().blockAt(session, fireBlockPos).block();
|
||||
if (block == Blocks.FIRE || block == Blocks.SOUL_FIRE) {
|
||||
// TODO test
|
||||
sendJavaPlayerActionPacket(session, PlayerAction.START_DIGGING, fireBlockPos, direction);
|
||||
sendJavaPlayerActionPacket(session, PlayerAction.FINISH_DIGGING, fireBlockPos, direction);
|
||||
}
|
||||
|
||||
sendJavaPlayerActionPacket(session, PlayerAction.START_DIGGING, vector, direction);
|
||||
}
|
||||
|
||||
private static void handleBlockDestroy(GeyserSession session, Vector3i vector, int blockFace) {
|
||||
boolean creative = session.getGameMode() == GameMode.CREATIVE;
|
||||
|
||||
int blockState = creative ? session.getGeyser().getWorldManager().getBlockAt(session, vector) : session.getBreakingBlock();
|
||||
|
||||
// TODO move
|
||||
Entity itemFrameEntity = ItemFrameEntity.getItemFrameEntity(session, vector);
|
||||
if (itemFrameEntity != null) {
|
||||
ServerboundInteractPacket attackPacket = new ServerboundInteractPacket(itemFrameEntity.getEntityId(),
|
||||
InteractAction.ATTACK, session.isSneaking());
|
||||
session.sendDownstreamGamePacket(attackPacket);
|
||||
return;
|
||||
}
|
||||
|
||||
// Already done this check in survival mode
|
||||
if (creative) {
|
||||
Vector3f playerPosition = session.getPlayerEntity().getPosition();
|
||||
playerPosition = playerPosition.down(EntityDefinitions.PLAYER.offset() - session.getEyeHeight());
|
||||
if (!BedrockInventoryTransactionTranslator.canInteractWithBlock(session, playerPosition, vector)) {
|
||||
BedrockInventoryTransactionTranslator.restoreCorrectBlock(session, vector);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (!vector.equals(session.getBlockBreakPosition())) {
|
||||
// Restore correct block if we aren't breaking this one
|
||||
BedrockInventoryTransactionTranslator.restoreCorrectBlock(session, vector);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
session.setLastBlockPlaced(null);
|
||||
session.setLastBlockPlacePosition(null);
|
||||
|
||||
// Same deal with vanilla block placing as above.
|
||||
if (!session.getWorldBorder().isInsideBorderBoundaries()) {
|
||||
BedrockInventoryTransactionTranslator.restoreCorrectBlock(session, vector);
|
||||
return;
|
||||
}
|
||||
|
||||
// -1 means we don't know what block they're breaking
|
||||
if (blockState == -1) {
|
||||
blockState = Block.JAVA_AIR_ID;
|
||||
}
|
||||
|
||||
// TODO
|
||||
session.setBlockBreakProgress(1.0);
|
||||
stopBreakingBlock(session, vector.toFloat());
|
||||
|
||||
LevelEventPacket blockDestroyParticlePacket = new LevelEventPacket();
|
||||
blockDestroyParticlePacket.setType(LevelEvent.PARTICLE_DESTROY_BLOCK);
|
||||
blockDestroyParticlePacket.setPosition(vector.toFloat());
|
||||
blockDestroyParticlePacket.setData(session.getBlockMappings().getBedrockBlockId(blockState));
|
||||
session.sendUpstreamPacket(blockDestroyParticlePacket);
|
||||
|
||||
resetSessionVariables(session);
|
||||
|
||||
PlayerAction action = session.getGameMode() == GameMode.CREATIVE ? PlayerAction.START_DIGGING : PlayerAction.FINISH_DIGGING;
|
||||
sendJavaPlayerActionPacket(session, action, vector, Direction.VALUES[blockFace]);
|
||||
session.getWorldCache().markPositionInSequence(vector);
|
||||
}
|
||||
|
||||
private static boolean isSteeringBoat(GeyserSession session, Vector3i vector) {
|
||||
if (session.isHandsBusy()) {
|
||||
session.setBreakingBlock(-1);
|
||||
session.setBlockBreakStartTime(0);
|
||||
|
||||
LevelEventPacket stopBreak = new LevelEventPacket();
|
||||
stopBreak.setType(LevelEvent.BLOCK_STOP_BREAK);
|
||||
stopBreak.setPosition(vector.toFloat());
|
||||
stopBreak.setData(0);
|
||||
session.setBreakingBlock(-1);
|
||||
session.sendUpstreamPacket(stopBreak);
|
||||
return false;
|
||||
resetSessionVariables(session);
|
||||
stopBreakingBlock(session, vector.toFloat());
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
private static void spawnBlockBreakParticles(GeyserSession session, Direction direction, Vector3i position, BlockState blockState) {
|
||||
private static void resetSessionVariables(GeyserSession session) {
|
||||
session.setBreakingBlock(-1);
|
||||
session.setBlockBreakPosition(null);
|
||||
session.setBlockBreakStartTime(0);
|
||||
}
|
||||
|
||||
private static void stopBreakingBlock(GeyserSession session, Vector3f vector) {
|
||||
LevelEventPacket stopBreak = new LevelEventPacket();
|
||||
stopBreak.setType(LevelEvent.BLOCK_STOP_BREAK);
|
||||
stopBreak.setPosition(vector.toFloat());
|
||||
stopBreak.setData(0);
|
||||
session.sendUpstreamPacket(stopBreak);
|
||||
}
|
||||
|
||||
public static void spawnBlockBreakParticles(GeyserSession session, Direction direction, Vector3i position, BlockState blockState) {
|
||||
LevelEventPacket levelEventPacket = new LevelEventPacket();
|
||||
switch (direction) {
|
||||
case UP -> levelEventPacket.setType(LevelEvent.PARTICLE_BREAK_BLOCK_UP);
|
||||
|
@ -233,4 +331,11 @@ final class BedrockBlockActions {
|
|||
levelEventPacket.setData(session.getBlockMappings().getBedrockBlock(blockState).getRuntimeId());
|
||||
session.sendUpstreamPacket(levelEventPacket);
|
||||
}
|
||||
|
||||
private static void sendJavaPlayerActionPacket(GeyserSession session, PlayerAction action, Vector3i vector, Direction direction) {
|
||||
int sequence = session.getWorldCache().nextPredictionSequence();
|
||||
ServerboundPlayerActionPacket packet = new ServerboundPlayerActionPacket(action, vector, direction, sequence);
|
||||
session.sendDownstreamGamePacket(packet);
|
||||
GeyserImpl.getInstance().getLogger().info(packet.toString());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,16 +30,14 @@ import org.cloudburstmc.math.vector.Vector2f;
|
|||
import org.cloudburstmc.math.vector.Vector3f;
|
||||
import org.cloudburstmc.math.vector.Vector3i;
|
||||
import org.cloudburstmc.protocol.bedrock.data.InputMode;
|
||||
import org.cloudburstmc.protocol.bedrock.data.LevelEvent;
|
||||
import org.cloudburstmc.protocol.bedrock.data.PlayerActionType;
|
||||
import org.cloudburstmc.protocol.bedrock.data.PlayerAuthInputData;
|
||||
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.transaction.ItemUseTransaction;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.AnimatePacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.LevelEventPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.ItemStackResponsePacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.PlayerActionPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.PlayerAuthInputPacket;
|
||||
import org.geysermc.geyser.entity.EntityDefinitions;
|
||||
import org.geysermc.geyser.entity.type.BoatEntity;
|
||||
import org.geysermc.geyser.entity.type.Entity;
|
||||
import org.geysermc.geyser.entity.type.ItemFrameEntity;
|
||||
|
@ -47,25 +45,21 @@ import org.geysermc.geyser.entity.type.living.animal.horse.AbstractHorseEntity;
|
|||
import org.geysermc.geyser.entity.type.living.animal.horse.LlamaEntity;
|
||||
import org.geysermc.geyser.entity.type.player.SessionPlayerEntity;
|
||||
import org.geysermc.geyser.entity.vehicle.ClientVehicle;
|
||||
import org.geysermc.geyser.level.block.type.Block;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.translator.protocol.PacketTranslator;
|
||||
import org.geysermc.geyser.translator.protocol.Translator;
|
||||
import org.geysermc.geyser.translator.protocol.bedrock.BedrockInventoryTransactionTranslator;
|
||||
import org.geysermc.geyser.util.CooldownUtils;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.object.Direction;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.InteractAction;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.PlayerAction;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.PlayerState;
|
||||
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.level.ServerboundMoveVehiclePacket;
|
||||
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundInteractPacket;
|
||||
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundPlayerAbilitiesPacket;
|
||||
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundPlayerActionPacket;
|
||||
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundPlayerCommandPacket;
|
||||
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundSwingPacket;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
@Translator(packet = PlayerAuthInputPacket.class)
|
||||
|
@ -86,6 +80,7 @@ public final class BedrockPlayerAuthInputTranslator extends PacketTranslator<Pla
|
|||
for (PlayerAuthInputData input : inputData) {
|
||||
switch (input) {
|
||||
case PERFORM_ITEM_INTERACTION -> processItemUseTransaction(session, packet.getItemUseTransaction());
|
||||
case PERFORM_ITEM_STACK_REQUEST -> session.getInventoryTranslator().translateRequests(session, session.getPlayerInventory(), List.of(packet.getItemStackRequest()));
|
||||
case PERFORM_BLOCK_ACTIONS -> BedrockBlockActions.translate(session, packet.getPlayerActions());
|
||||
case START_SPRINTING -> {
|
||||
if (!entity.getFlag(EntityFlag.SWIMMING)) {
|
||||
|
@ -185,51 +180,13 @@ public final class BedrockPlayerAuthInputTranslator extends PacketTranslator<Pla
|
|||
|
||||
private static void processItemUseTransaction(GeyserSession session, ItemUseTransaction transaction) {
|
||||
if (transaction.getActionType() == 2) {
|
||||
int blockState = session.getGameMode() == GameMode.CREATIVE ?
|
||||
session.getGeyser().getWorldManager().getBlockAt(session, transaction.getBlockPosition()) : session.getBreakingBlock();
|
||||
|
||||
session.setLastBlockPlaced(null);
|
||||
session.setLastBlockPlacePosition(null);
|
||||
|
||||
// Same deal with vanilla block placing as above.
|
||||
if (!session.getWorldBorder().isInsideBorderBoundaries()) {
|
||||
BedrockInventoryTransactionTranslator.restoreCorrectBlock(session, transaction.getBlockPosition());
|
||||
return;
|
||||
}
|
||||
|
||||
Vector3f playerPosition = session.getPlayerEntity().getPosition();
|
||||
playerPosition = playerPosition.down(EntityDefinitions.PLAYER.offset() - session.getEyeHeight());
|
||||
|
||||
if (!BedrockInventoryTransactionTranslator.canInteractWithBlock(session, playerPosition, transaction.getBlockPosition())) {
|
||||
BedrockInventoryTransactionTranslator.restoreCorrectBlock(session, transaction.getBlockPosition());
|
||||
return;
|
||||
}
|
||||
|
||||
int sequence = session.getWorldCache().nextPredictionSequence();
|
||||
session.getWorldCache().markPositionInSequence(transaction.getBlockPosition());
|
||||
// -1 means we don't know what block they're breaking
|
||||
if (blockState == -1) {
|
||||
blockState = Block.JAVA_AIR_ID;
|
||||
}
|
||||
|
||||
LevelEventPacket blockBreakPacket = new LevelEventPacket();
|
||||
blockBreakPacket.setType(LevelEvent.PARTICLE_DESTROY_BLOCK);
|
||||
blockBreakPacket.setPosition(transaction.getBlockPosition().toFloat());
|
||||
blockBreakPacket.setData(session.getBlockMappings().getBedrockBlockId(blockState));
|
||||
session.sendUpstreamPacket(blockBreakPacket);
|
||||
session.setBreakingBlock(-1);
|
||||
|
||||
// TODO test
|
||||
Entity itemFrameEntity = ItemFrameEntity.getItemFrameEntity(session, transaction.getBlockPosition());
|
||||
if (itemFrameEntity != null) {
|
||||
ServerboundInteractPacket attackPacket = new ServerboundInteractPacket(itemFrameEntity.getEntityId(),
|
||||
InteractAction.ATTACK, session.isSneaking());
|
||||
session.sendDownstreamGamePacket(attackPacket);
|
||||
return;
|
||||
}
|
||||
|
||||
PlayerAction action = session.getGameMode() == GameMode.CREATIVE ? PlayerAction.START_DIGGING : PlayerAction.FINISH_DIGGING;
|
||||
ServerboundPlayerActionPacket breakPacket = new ServerboundPlayerActionPacket(action, transaction.getBlockPosition(), Direction.VALUES[transaction.getBlockFace()], sequence);
|
||||
session.sendDownstreamGamePacket(breakPacket);
|
||||
} else {
|
||||
session.getGeyser().getLogger().error("Unhandled item use transaction type!");
|
||||
if (session.getGeyser().getLogger().isDebug()) {
|
||||
|
|
|
@ -39,7 +39,7 @@ import org.geysermc.mcprotocollib.protocol.data.game.item.component.ToolData;
|
|||
public final class BlockUtils {
|
||||
|
||||
/**
|
||||
* Returns the total mining progress added by mining the block in a single tick
|
||||
* Returns the total mining progress added (in %) by mining the block in a single tick
|
||||
* @return the mining progress added by this tick.
|
||||
*/
|
||||
public static float getBlockMiningProgressPerTick(GeyserSession session, Block block, GeyserItemStack itemInHand) {
|
||||
|
|
Loading…
Add table
Reference in a new issue