Extracted position sending from Entity#tick and improved checks, also removed duplicate code from Player#update

This commit is contained in:
Németh Noel 2021-05-01 02:21:11 +02:00
parent c027d649cf
commit 66f1c8847d
2 changed files with 73 additions and 89 deletions

View File

@ -138,6 +138,8 @@ public class Entity implements Viewable, Tickable, EventHandler, DataContainer,
*/
private final Object entityTypeLock = new Object();
private final boolean isNettyClient;
public Entity(@NotNull EntityType entityType, @NotNull UUID uuid) {
this.id = generateId();
this.entityType = entityType;
@ -152,6 +154,8 @@ public class Entity implements Viewable, Tickable, EventHandler, DataContainer,
setAutoViewable(true);
isNettyClient = PlayerUtils.isNettyClient(this);
Entity.ENTITY_BY_ID.put(id, this);
Entity.ENTITY_BY_UUID.put(uuid, this);
}
@ -493,47 +497,7 @@ public class Entity implements Viewable, Tickable, EventHandler, DataContainer,
}
}
final boolean isNettyClient = PlayerUtils.isNettyClient(this);
// Synchronization with updated fields in #getPosition()
{
final boolean positionChange = !position.isSimilar(lastSyncedPosition);
final boolean viewChange = !position.hasSimilarView(lastSyncedPosition);
final double distance = positionChange ? position.getDistance(lastSyncedPosition) : 0;
if (distance >= 8 || (positionChange && isNettyClient)) {
// Teleport has the priority over everything else
teleport(position);
} else if (positionChange && viewChange) {
EntityPositionAndRotationPacket positionAndRotationPacket =
EntityPositionAndRotationPacket.getPacket(getEntityId(),
position, lastSyncedPosition, isOnGround());
sendPacketToViewersAndSelf(positionAndRotationPacket);
refreshPosition(position.clone());
// Fix head rotation
EntityHeadLookPacket entityHeadLookPacket = new EntityHeadLookPacket();
entityHeadLookPacket.entityId = getEntityId();
entityHeadLookPacket.yaw = position.getYaw();
sendPacketToViewersAndSelf(entityHeadLookPacket);
} else if (positionChange) {
EntityPositionPacket entityPositionPacket = EntityPositionPacket.getPacket(getEntityId(),
position, lastSyncedPosition, isOnGround());
sendPacketToViewersAndSelf(entityPositionPacket);
refreshPosition(position.clone());
} else if (viewChange) {
// Yaw/Pitch
setView(position);
}
}
sendPositionUpdate();
// Entity tick
{
@ -713,6 +677,70 @@ public class Entity implements Viewable, Tickable, EventHandler, DataContainer,
}
}
/**
* Sends the correct packets to update the entity's position, should be called
* every tick. The movement is checked inside the method!
* <p>
* The following packets are sent to viewers (check are performed in this order):
* <ol>
* <li>{@link EntityTeleportPacket} if <pre>distanceX > 8 || distanceY > 8 || distanceZ > 8</pre>
* <i>(performed using {@link #synchronizePosition()})</i></li>
* <li>{@link EntityPositionAndRotationPacket} if <pre>positionChange && viewChange</pre></li>
* <li>{@link EntityPositionPacket} if <pre>positionChange</pre></li>
* <li>{@link EntityRotationPacket} if <pre>viewChange</pre>
* <i>(performed using {@link #setView(float, float)})</i></li>
* </ol>
* In case of a player's position and/or view change an additional {@link PlayerPositionAndLookPacket}
* is sent to self.
*/
protected void sendPositionUpdate() {
final boolean viewChange = !position.hasSimilarView(lastSyncedPosition);
final double distanceX = Math.abs(position.getX()-lastSyncedPosition.getX());
final double distanceY = Math.abs(position.getY()-lastSyncedPosition.getY());
final double distanceZ = Math.abs(position.getZ()-lastSyncedPosition.getZ());
final boolean positionChange = (distanceX+distanceY+distanceZ) > 0;
if (distanceX > 8 || distanceY > 8 || distanceZ > 8) {
synchronizePosition();
// #synchronizePosition sets sync fields, it's safe to return
return;
} else if (positionChange && viewChange) {
EntityPositionAndRotationPacket positionAndRotationPacket = EntityPositionAndRotationPacket
.getPacket(getEntityId(), position, lastSyncedPosition, isOnGround());
sendPacketToViewers(positionAndRotationPacket);
// Fix head rotation
EntityHeadLookPacket entityHeadLookPacket = new EntityHeadLookPacket();
entityHeadLookPacket.entityId = getEntityId();
entityHeadLookPacket.yaw = position.getYaw();
sendPacketToViewersAndSelf(entityHeadLookPacket);
} else if (positionChange) {
final EntityPositionPacket entityPositionPacket = EntityPositionPacket
.getPacket(getEntityId(), position, lastSyncedPosition, onGround);
sendPacketToViewers(entityPositionPacket);
} else if (viewChange) {
setView(position.getYaw(), position.getPitch());
/*
#setView indirectly sets last sync field and it appears that EntityRotation packet
can be used for players as well, so it's safe to return
*/
return;
} else {
// Nothing changed, return
return;
}
if (isNettyClient) {
final PlayerPositionAndLookPacket playerPositionAndLookPacket = new PlayerPositionAndLookPacket();
playerPositionAndLookPacket.flags = 0b111;
playerPositionAndLookPacket.position = position.clone().subtract(lastSyncedPosition.getX(), lastSyncedPosition.getY(), lastSyncedPosition.getZ());
playerPositionAndLookPacket.teleportId = ((Player)this).getNextTeleportId();
((Player) this).getPlayerConnection().sendPacket(playerPositionAndLookPacket);
}
lastSyncedPosition.set(position);
}
/**
* Gets the number of ticks this entity has been active for.
*

View File

@ -148,9 +148,6 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
// Only used if multi player breaking is disabled, contains only this player
private final Set<Player> targetBreakers = Collections.singleton(this);
// Position synchronization with viewers
private final Position lastSyncedPlayerPosition;
// Experience orb pickup
protected Cooldown experiencePickupCooldown = new Cooldown(new UpdateOption(10, TimeUnit.TICK));
@ -187,7 +184,6 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
setBoundingBox(0.6f, 1.8f, 0.6f);
setRespawnPoint(new Position(0, 0, 0));
this.lastSyncedPlayerPosition = new Position();
this.settings = new PlayerSettings();
this.inventory = new PlayerInventory(this);
@ -421,50 +417,6 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
// Tick event
callEvent(PlayerTickEvent.class, playerTickEvent);
// Multiplayer sync
if (!viewers.isEmpty()) {
final boolean positionChanged = !position.isSimilar(lastSyncedPlayerPosition);
final boolean viewChanged = !position.hasSimilarView(lastSyncedPlayerPosition);
if (positionChanged || viewChanged) {
// Player moved since last time
ServerPacket updatePacket;
ServerPacket optionalUpdatePacket = null;
if (positionChanged && viewChanged) {
updatePacket = EntityPositionAndRotationPacket.getPacket(getEntityId(),
position, lastSyncedPlayerPosition, onGround);
} else if (positionChanged) {
updatePacket = EntityPositionPacket.getPacket(getEntityId(),
position, lastSyncedPlayerPosition, onGround);
} else {
// View changed
updatePacket = EntityRotationPacket.getPacket(getEntityId(),
position.getYaw(), position.getPitch(), onGround);
}
if (viewChanged) {
// Yaw from the rotation packet seems to be ignored, which is why this is required
EntityHeadLookPacket entityHeadLookPacket = new EntityHeadLookPacket();
entityHeadLookPacket.entityId = getEntityId();
entityHeadLookPacket.yaw = position.getYaw();
optionalUpdatePacket = entityHeadLookPacket;
}
// Send the update packet
if (optionalUpdatePacket != null) {
sendPacketsToViewers(updatePacket, optionalUpdatePacket);
} else {
sendPacketToViewers(updatePacket);
}
}
// Update sync data
lastSyncedPlayerPosition.set(position);
}
}
@Override
@ -2007,6 +1959,10 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
playerConnection.sendPacket(updateViewPositionPacket);
}
public int getNextTeleportId() {
return teleportId.getAndIncrement();
}
public int getLastSentTeleportId() {
return teleportId.get();
}