70public final class SendPlayerUpdate
extends OutgoingPacket {
72 private static final Logger logger = LogManager.getLogger(SendPlayerUpdate.class);
74 public SendPlayerUpdate() {
79 public boolean encode(
Player player) {
80 if (player.regionChange) {
88 updateMovement(player, builder);
91 updatePlayer(blockBuf, player, player, UpdateState.UPDATE_SELF);
102 builder.writeBit(
true);
103 builder.writeBits(2, 3);
106 updateMovement(other, builder);
109 updatePlayer(blockBuf, player, other, UpdateState.UPDATE_LOCAL);
117 for (
Player localPlayer : localPlayers) {
123 if (player.viewport.
add(localPlayer)) {
125 addNewPlayer(builder, player, localPlayer);
126 updatePlayer(blockBuf, player, localPlayer, UpdateState.ADD_LOCAL);
131 if (blockBuf.content().readableBytes() > 0) {
132 builder.writeBits(11, 2047);
134 builder.writeBuffer(blockBuf.content());
138 }
catch (Exception ex) {
139 logger.error(String.format(
"error updating player=%s", player), ex);
147 packetBuf.writeBits(11, other.getIndex())
150 .writeBits(5, other.
getY() - player.
getY())
151 .writeBits(5, other.
getX() - player.
getX());
161 final EnumSet<UpdateFlag> updateFlags = other.updateFlags;
163 if (updateFlags.contains(flag) && flag.canApply(player, other, state)) {
164 mask |= flag.playerMask;
170 blockBuf.writeByte(mask & 0xFF);
171 blockBuf.writeByte(mask >> 8);
173 blockBuf.writeByte(mask);
184 appendForceMovementMask(player, other, blockBuf);
188 appendGraphicMask(other, blockBuf);
192 appendAnimationMask(other, blockBuf);
196 appendForceChatMask(other, blockBuf);
200 appendChatMask(blockBuf, other);
204 appendFaceEntityMask(other, blockBuf);
208 appendAppearanceMask(other, blockBuf);
212 appendFaceCoordinteMask(other, blockBuf);
216 appendHitMask(other, blockBuf);
220 appendSecondHitMask(other, blockBuf);
228 final Position lastPosition = player.lastPosition;
230 final int startX = otherPosition.
getLocalX(lastPosition);
231 final int startY = otherPosition.
getLocalY(lastPosition);
234 final int endX = end.
getX();
235 final int endY = end.
getY();
247 blockBuf.writeString(other.forceChat);
251 Mob mob = other.interactingWith;
253 int index = mob.getIndex();
270 .writeShort(((currentPos.
getY() + currentDir.getDirectionY()) << 1) + 1,
ByteOrder.
LE);
292 final byte[] encoded = message.getEncoded();
293 blockBuf.writeShort(((message.getColor().getCode() & 0xFF) << 8) | (message.getEffect().getCode() & 0xFF),
ByteOrder.
LE)
296 .writeBytesReverse(encoded);
301 final var overrides = other.overrides;
303 tempBuf.writeByte(other.appearance.
getGender().ordinal())
304 .writeByte(other.headIcon)
306 .writeByte(other.valueIcon);
308 if (other.id != -1) {
309 tempBuf.writeShort(-1);
310 tempBuf.writeShort(other.id);
314 tempBuf.writeShort(0x200 + overrides.get(
Equipment.HELM_SLOT).getId());
315 }
else if (helm !=
null && helm.getId() > 1) {
316 tempBuf.writeShort(0x200 + other.equipment.
get(
Equipment.HELM_SLOT).getId());
318 tempBuf.writeByte(0);
321 if (overrides.hasOverride(
Equipment.CAPE_SLOT)) {
322 tempBuf.writeShort(0x200 + overrides.get(
Equipment.CAPE_SLOT).getId());
323 }
else if (other.equipment.
get(
Equipment.CAPE_SLOT) !=
null) {
324 tempBuf.writeShort(0x200 + other.equipment.
get(
Equipment.CAPE_SLOT).getId());
326 tempBuf.writeByte(0);
329 if (overrides.hasOverride(
Equipment.AMULET_SLOT)) {
330 tempBuf.writeShort(0x200 + overrides.get(
Equipment.AMULET_SLOT).getId());
331 }
else if (other.equipment.
get(
Equipment.AMULET_SLOT) !=
null) {
332 tempBuf.writeShort(0x200 + other.equipment.
get(
Equipment.AMULET_SLOT).getId());
334 tempBuf.writeByte(0);
337 if (overrides.hasOverride(
Equipment.WEAPON_SLOT)) {
338 tempBuf.writeShort(0x200 + overrides.get(
Equipment.WEAPON_SLOT).getId());
339 }
else if (other.equipment.
get(
Equipment.WEAPON_SLOT) !=
null) {
340 tempBuf.writeShort(0x200 + other.equipment.
get(
Equipment.WEAPON_SLOT).getId());
342 tempBuf.writeByte(0);
346 if (overrides.hasOverride(
Equipment.CHEST_SLOT)) {
347 tempBuf.writeShort(0x200 + overrides.get(
Equipment.CHEST_SLOT).getId());
348 }
else if (torso !=
null && torso.getId() > 1) {
349 tempBuf.writeShort(0x200 + other.equipment.
get(
Equipment.CHEST_SLOT).getId());
351 tempBuf.writeShort(0x100 + other.appearance.
getTorso());
354 if (overrides.hasOverride(
Equipment.SHIELD_SLOT)) {
355 tempBuf.writeShort(0x200 + overrides.get(
Equipment.SHIELD_SLOT).getId());
356 }
else if (other.equipment.
get(
Equipment.SHIELD_SLOT) !=
null) {
357 if (overrides.hasOverride(
Equipment.WEAPON_SLOT) && overrides.get(
Equipment.WEAPON_SLOT).isTwoHanded()) {
358 tempBuf.writeByte(0);
360 tempBuf.writeShort(0x200 + other.equipment.
get(
Equipment.SHIELD_SLOT).getId());
363 tempBuf.writeByte(0);
366 if (torso !=
null && torso.getId() > 1 && torso.getEquipmentType().equals(
EquipmentType.BODY) ||
368 tempBuf.writeByte(0);
370 tempBuf.writeShort(0x100 + other.appearance.
getArms());
373 if (overrides.hasOverride(
Equipment.LEGS_SLOT)) {
374 tempBuf.writeShort(0x200 + overrides.get(
Equipment.LEGS_SLOT).getId());
375 }
else if (other.equipment.
get(
Equipment.LEGS_SLOT) !=
null) {
376 tempBuf.writeShort(0x200 + other.equipment.
get(
Equipment.LEGS_SLOT).getId());
378 tempBuf.writeShort(0x100 + other.appearance.
getLegs());
382 boolean beard =
true;
384 if (helm !=
null && helm.getId() > 1) {
397 tempBuf.writeShort(0x100 + other.appearance.
getHead());
399 tempBuf.writeByte(0);
402 if (overrides.hasOverride(
Equipment.HANDS_SLOT)) {
403 tempBuf.writeShort(0x200 + overrides.get(
Equipment.HANDS_SLOT).getId());
404 }
else if (other.equipment.
get(
Equipment.HANDS_SLOT) !=
null) {
405 tempBuf.writeShort(0x200 + other.equipment.
get(
Equipment.HANDS_SLOT).getId());
407 tempBuf.writeShort(0x100 + other.appearance.
getHands());
410 if (overrides.hasOverride(
Equipment.FEET_SLOT)) {
411 tempBuf.writeShort(0x200 + overrides.get(
Equipment.FEET_SLOT).getId());
412 }
else if (other.equipment.
get(
Equipment.FEET_SLOT) !=
null) {
413 tempBuf.writeShort(0x200 + other.equipment.
get(
Equipment.FEET_SLOT).getId());
415 tempBuf.writeShort(0x100 + other.appearance.
getFeet());
420 tempBuf.writeShort(0x100 + other.appearance.
getBeard());
422 tempBuf.writeByte(0);
425 tempBuf.writeByte(0);
435 .writeShort(other.mobAnimation.getStand())
436 .writeShort(other.mobAnimation.getTurn())
437 .writeShort(other.mobAnimation.getWalk())
438 .writeShort(other.mobAnimation.getTurn180())
439 .writeShort(other.mobAnimation.getTurn90CW())
440 .writeShort(other.mobAnimation.getTurn90CCW())
441 .writeShort(other.mobAnimation.getRun())
443 .writeString(other.playerTitle.
getTitle())
444 .writeInt(other.playerTitle.
getColor())
445 .writeString(other.clanChannel ==
null ?
"" : other.clanChannel.getOwner())
446 .writeString(other.clanTag)
447 .writeString(other.clanTagColor)
448 .writeLong(Double.doubleToLongBits(other.skills.
getCombatLevel()))
452 blockBuf.writeBytes(tempBuf.content());
459 Hit hit = player.firstHit;
461 boolean multipleHits = hit.getMultipleHits() !=
null;
462 blockBuf.writeByte(multipleHits ? 1 : 0);
465 int max = player.getMaximumHealth() >= 500 ? 200 : 100;
466 int health = player.getCurrentHealth() * max / player.getMaximumHealth();
467 if (health > max) health = max;
470 blockBuf.writeByte(hit.getMultipleHits().length);
472 for(
int index = 0; index < hit.getMultipleHits().length; index++) {
473 Hit currentHit = hit.getMultipleHits()[index];
481 blockBuf.writeByte(currentHit.
getDamage());
499 blockBuf.writeByte(health);
503 private static void appendSecondHitMask(
final Player player,
final PacketBuilder blockBuf) {
504 Hit hit = player.secondHit;
506 boolean multipleHits = hit.getMultipleHits() !=
null;
507 blockBuf.writeByte(multipleHits ? 1 : 0);
509 int max = player.getMaximumHealth() >= 500 ? 200 : 100;
510 int health = player.getCurrentHealth() * max / player.getMaximumHealth();
511 if (health > max) health = max;
514 blockBuf.writeByte(hit.getMultipleHits().length);
516 for(
int index = 0; index < hit.getMultipleHits().length; index++) {
517 Hit currentHit = hit.getMultipleHits()[index];
525 blockBuf.writeByte(currentHit.
getDamage());
541 blockBuf.writeByte(health);
546 final boolean teleported = player.positionChange || player.teleportRegion;
549 packetBuf.writeBit(
true)
552 .writeBits(1, player.regionChange ? 0 : 1)
553 .writeBit(updateRequired)
556 }
else if (player.movement.getRunningDirection() != -1) {
557 packetBuf.writeBit(
true)
559 .writeBits(3, player.movement.getWalkingDirection())
560 .writeBits(3, player.movement.getRunningDirection())
562 }
else if (player.movement.getWalkingDirection() != -1) {
563 packetBuf.writeBit(
true)
565 .writeBits(3, player.movement.getWalkingDirection())
568 if (updateRequired) {
569 packetBuf.writeBit(
true)
572 packetBuf.writeBit(
false);
577public enum UpdateState {