Skip to content

Commit

Permalink
Respect block range attribute where we can
Browse files Browse the repository at this point in the history
  • Loading branch information
Camotoy committed Jul 21, 2024
1 parent c9e423a commit 7d5c4a3
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 41 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ public enum GeyserAttributeType {
ATTACK_SPEED("minecraft:generic.attack_speed", null, 0f, 1024f, 4f),
MAX_HEALTH("minecraft:generic.max_health", null, 0f, 1024f, 20f),
SCALE("minecraft:generic.scale", null, 0.0625f, 16f, 1f),
BLOCK_INTERACTION_RANGE("minecraft:player.block_interaction_range", null, 0.0f, 64f, 4.5f),

// Bedrock Attributes
ABSORPTION(null, "minecraft:absorption", 0f, 1024f, 0f),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,11 @@ public class SessionPlayerEntity extends PlayerEntity {
*/
@Getter
protected final Map<GeyserAttributeType, AttributeData> attributes = new Object2ObjectOpenHashMap<>();
/**
* Java-only attribute
*/
@Getter
private double blockInteractionRange = GeyserAttributeType.BLOCK_INTERACTION_RANGE.getDefaultValue();
/**
* Used in PlayerInputTranslator for movement checks.
*/
Expand Down Expand Up @@ -232,6 +237,8 @@ protected boolean hasShield(boolean offhand) {
protected void updateAttribute(Attribute javaAttribute, List<AttributeData> newAttributes) {
if (javaAttribute.getType() == AttributeType.Builtin.GENERIC_ATTACK_SPEED) {
session.setAttackSpeed(AttributeUtils.calculateValue(javaAttribute));
} else if (javaAttribute.getType() == AttributeType.Builtin.PLAYER_BLOCK_INTERACTION_RANGE) {
this.blockInteractionRange = AttributeUtils.calculateValue(javaAttribute);
} else {
super.updateAttribute(javaAttribute, newAttributes);
}
Expand Down Expand Up @@ -295,6 +302,7 @@ public void resetMetadata() {
public void resetAttributes() {
attributes.clear();
maxHealth = GeyserAttributeType.MAX_HEALTH.getDefaultValue();
blockInteractionRange = GeyserAttributeType.BLOCK_INTERACTION_RANGE.getDefaultValue();

UpdateAttributesPacket attributesPacket = new UpdateAttributesPacket();
attributesPacket.setRuntimeEntityId(geyserId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,15 +70,23 @@
import org.geysermc.geyser.translator.item.ItemTranslator;
import org.geysermc.geyser.translator.protocol.PacketTranslator;
import org.geysermc.geyser.translator.protocol.Translator;
import org.geysermc.geyser.util.*;
import org.geysermc.geyser.util.BlockUtils;
import org.geysermc.geyser.util.CooldownUtils;
import org.geysermc.geyser.util.EntityUtils;
import org.geysermc.geyser.util.InteractionResult;
import org.geysermc.geyser.util.InventoryUtils;
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.item.ItemStack;
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundContainerClickPacket;
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.*;
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundInteractPacket;
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundMovePlayerPosRotPacket;
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundPlayerActionPacket;
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundSwingPacket;
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundUseItemOnPacket;

import java.util.List;
import java.util.concurrent.TimeUnit;
Expand All @@ -90,11 +98,6 @@
@Translator(packet = InventoryTransactionPacket.class)
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
public void translate(GeyserSession session, InventoryTransactionPacket packet) {
if (packet.getTransactionType() == InventoryTransactionType.NORMAL && packet.getActions().size() == 3) {
Expand Down Expand Up @@ -243,17 +246,13 @@ public void translate(GeyserSession session, InventoryTransactionPacket packet)
return;
}

// CraftBukkit+ check - see https://github.com/PaperMC/Paper/blob/458db6206daae76327a64f4e2a17b67a7e38b426/Spigot-Server-Patches/0532-Move-range-check-for-block-placing-up.patch
// As of 1.21, Paper does not have any additional range checks that would inconvenience normal players.
// Note that, before these changes, I could replicate on Paper 1.20.4 and iPad 1.21.2 an instance of block ghosting
// that we had not previously implemented. Might be some sort of ray tracing that is currently unimplemented.
Vector3f playerPosition = session.getPlayerEntity().getPosition();
playerPosition = playerPosition.down(EntityDefinitions.PLAYER.offset() - session.getEyeHeight());

boolean creative = session.getGameMode() == GameMode.CREATIVE;

float diffX = playerPosition.getX() - packetBlockPosition.getX();
float diffY = playerPosition.getY() - packetBlockPosition.getY();
float diffZ = playerPosition.getZ() - packetBlockPosition.getZ();
if (((diffX * diffX) + (diffY * diffY) + (diffZ * diffZ)) >
(creative ? CREATIVE_EYE_HEIGHT_PLACE_DISTANCE : SURVIVAL_EYE_HEIGHT_PLACE_DISTANCE)) {
if (!canInteractWithBlock(session, playerPosition, packetBlockPosition)) {
restoreCorrectBlock(session, blockPos, packet);
return;
}
Expand All @@ -262,26 +261,8 @@ public void translate(GeyserSession session, InventoryTransactionPacket packet)
double clickPositionFullY = (double) packetBlockPosition.getY() + (double) packet.getClickPosition().getY();
double clickPositionFullZ = (double) packetBlockPosition.getZ() + (double) packet.getClickPosition().getZ();

// More recent Paper check - https://github.com/PaperMC/Paper/blob/87e11bf7fdf48ecdf3e1cae383c368b9b61d7df9/patches/server/0470-Move-range-check-for-block-placing-up.patch
double clickDiffX = playerPosition.getX() - clickPositionFullX;
double clickDiffY = playerPosition.getY() - clickPositionFullY;
double clickDiffZ = playerPosition.getZ() - clickPositionFullZ;
if (((clickDiffX * clickDiffX) + (clickDiffY * clickDiffY) + (clickDiffZ * clickDiffZ)) >
(creative ? CREATIVE_EYE_HEIGHT_PLACE_DISTANCE : SURVIVAL_EYE_HEIGHT_PLACE_DISTANCE)) {
restoreCorrectBlock(session, blockPos, packet);
return;
}

Vector3f blockCenter = Vector3f.from(packetBlockPosition.getX() + 0.5f, packetBlockPosition.getY() + 0.5f, packetBlockPosition.getZ() + 0.5f);
// Vanilla check
if (!(session.getPlayerEntity().getPosition().sub(0, EntityDefinitions.PLAYER.offset(), 0)
.distanceSquared(blockCenter) < 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;
}

// More recent vanilla check (as of 1.18.2)
double clickDistanceX = clickPositionFullX - blockCenter.getX();
double clickDistanceY = clickPositionFullY - blockCenter.getY();
double clickDistanceZ = clickPositionFullZ - blockCenter.getZ();
Expand Down Expand Up @@ -433,14 +414,10 @@ public void translate(GeyserSession session, InventoryTransactionPacket packet)
return;
}

// 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.
Vector3f playerPosition = session.getPlayerEntity().getPosition();
Vector3f floatBlockPosition = packet.getBlockPosition().toFloat();
float diffX = playerPosition.getX() - (floatBlockPosition.getX() + 0.5f);
float diffY = (playerPosition.getY() - EntityDefinitions.PLAYER.offset()) - (floatBlockPosition.getY() + 0.5f) + 1.5f;
float diffZ = playerPosition.getZ() - (floatBlockPosition.getZ() + 0.5f);
float distanceSquared = diffX * diffX + diffY * diffY + diffZ * diffZ;
if (distanceSquared > MAXIMUM_BLOCK_DESTROYING_DISTANCE) {
playerPosition = playerPosition.down(EntityDefinitions.PLAYER.offset() - session.getEyeHeight());

if (!canInteractWithBlock(session, playerPosition, packet.getBlockPosition())) {
restoreCorrectBlock(session, packet.getBlockPosition(), packet);
return;
}
Expand Down Expand Up @@ -550,6 +527,28 @@ private void processEntityInteraction(GeyserSession session, InventoryTransactio
}
}

private boolean canInteractWithBlock(GeyserSession session, Vector3f playerPosition, Vector3i packetBlockPosition) {
// ViaVersion sends this 1.20.5+ attribute also, so older servers will have correct range checks.
double blockInteractionRange = session.getPlayerEntity().getBlockInteractionRange();

// Mojmap Player#canInteractWithBlock
double additionalRangeCheck = blockInteractionRange + 1.0d;

// AABB.<init>(BlockPos)
float minX = packetBlockPosition.getX();
float minY = packetBlockPosition.getY();
float minZ = packetBlockPosition.getZ();
float maxX = packetBlockPosition.getX() + 1;
float maxY = packetBlockPosition.getY() + 1;
float maxZ = packetBlockPosition.getZ() + 1;

// AABB#distanceToSqr
float diffX = Math.max(Math.max(minX - playerPosition.getX(), playerPosition.getX() - maxX), 0);
float diffY = Math.max(Math.max(minY - playerPosition.getY(), playerPosition.getY() - maxY), 0);
float diffZ = Math.max(Math.max(minZ - playerPosition.getZ(), playerPosition.getZ() - maxZ), 0);
return ((diffX * diffX) + (diffY * diffY) + (diffZ * diffZ)) < (additionalRangeCheck * additionalRangeCheck);
}

/**
* Restore the correct block state from the server without updating the chunk cache.
*
Expand Down Expand Up @@ -696,4 +695,4 @@ private void lookAt(GeyserSession session, Vector3f target) {
}, 150, TimeUnit.MILLISECONDS));
}
}
}
}

0 comments on commit 7d5c4a3

Please sign in to comment.