From 275b16ddc92db05f875ce7c507d2ebbf60811ddd Mon Sep 17 00:00:00 2001 From: Major- Date: Sun, 3 Nov 2013 04:19:45 +0000 Subject: [PATCH] Fully implement player synchronization. --- src/org/apollo/game/model/Character.java | 36 +- src/org/apollo/game/model/Npc.java | 2 +- src/org/apollo/game/model/Player.java | 58 +- .../game/sync/block/AppearanceBlock.java | 89 ++- src/org/apollo/game/sync/block/ChatBlock.java | 28 +- .../game/sync/block/ForceChatBlock.java | 35 ++ .../game/sync/block/ForceMovementBlock.java | 143 +++++ .../game/sync/block/HitUpdateBlock.java | 82 +++ .../sync/block/InteractingCharacterBlock.java | 36 ++ .../game/sync/block/SecondHitUpdateBlock.java | 83 +++ .../game/sync/block/SynchronizationBlock.java | 53 +- .../sync/block/SynchronizationBlockSet.java | 53 +- .../PlayerSynchronizationEventEncoder.java | 502 ++++++++++------- .../PlayerSynchronizationEventEncoder.java | 527 +++++++++++------- 14 files changed, 1234 insertions(+), 493 deletions(-) create mode 100644 src/org/apollo/game/sync/block/ForceChatBlock.java create mode 100644 src/org/apollo/game/sync/block/ForceMovementBlock.java create mode 100644 src/org/apollo/game/sync/block/HitUpdateBlock.java create mode 100644 src/org/apollo/game/sync/block/InteractingCharacterBlock.java create mode 100644 src/org/apollo/game/sync/block/SecondHitUpdateBlock.java diff --git a/src/org/apollo/game/model/Character.java b/src/org/apollo/game/model/Character.java index 535633fa..399f7c43 100644 --- a/src/org/apollo/game/model/Character.java +++ b/src/org/apollo/game/model/Character.java @@ -5,8 +5,8 @@ import java.util.List; import org.apollo.game.action.Action; import org.apollo.game.event.Event; -import org.apollo.game.event.impl.ServerMessageEvent; import org.apollo.game.model.Inventory.StackMode; +import org.apollo.game.model.def.NpcDefinition; import org.apollo.game.scheduling.impl.SkillNormalizationTask; import org.apollo.game.sync.block.SynchronizationBlock; import org.apollo.game.sync.block.SynchronizationBlockSet; @@ -84,6 +84,12 @@ public abstract class Character { */ private final SkillSet skillSet = new SkillSet(); + /** + * The character's {@link NpcDefinition). This is only used by an instance of the {@link Player} class if they are + * appearing as an npc in-game. + */ + private NpcDefinition definition; + /** * Creates a new character with the specified initial position. * @@ -377,12 +383,30 @@ public abstract class Character { } /** - * Sends a message to the character. + * Updates the character's interacting character. * - * @param message The message. + * @param index The index of the interacting character. */ - public void sendMessage(String message) { - send(new ServerMessageEvent(message)); + public void updateInteractingCharacter(int index) { + blockSet.add(SynchronizationBlock.createInteractingCharacterBlock(index)); } -} + /** + * Gets this character's {@link NpcDefinition}. + * + * @param definition The definition. + */ + public NpcDefinition getNpcDefinition() { + return definition; + } + + /** + * Sets this character's {@link NpcDefinition}. + * + * @param definition The definition. + */ + public void setDefinition(NpcDefinition definition) { + this.definition = definition; + } + +} \ No newline at end of file diff --git a/src/org/apollo/game/model/Npc.java b/src/org/apollo/game/model/Npc.java index 020fde5c..0eb4c400 100644 --- a/src/org/apollo/game/model/Npc.java +++ b/src/org/apollo/game/model/Npc.java @@ -41,7 +41,7 @@ public class Npc extends Character { * * @return The definition. */ - public NpcDefinition getDefinition() { + public NpcDefinition getNpcDefinition() { return definition; } diff --git a/src/org/apollo/game/model/Player.java b/src/org/apollo/game/model/Player.java index 337c5707..612af965 100644 --- a/src/org/apollo/game/model/Player.java +++ b/src/org/apollo/game/model/Player.java @@ -6,6 +6,7 @@ import java.util.Queue; import org.apollo.game.event.Event; import org.apollo.game.event.impl.IdAssignmentEvent; import org.apollo.game.event.impl.LogoutEvent; +import org.apollo.game.event.impl.ServerMessageEvent; import org.apollo.game.event.impl.SwitchTabInterfaceEvent; import org.apollo.game.model.inter.bank.BankConstants; import org.apollo.game.model.inv.AppearanceInventoryListener; @@ -144,6 +145,16 @@ public final class Player extends Character { */ private boolean excessivePlayers = false; + /** + * This player's head icon. + */ + private int headIcon = -1; + + /** + * This player's prayer icon. + */ + private int prayerIcon = -1; + /** * This player's interface set. */ @@ -546,4 +557,49 @@ public final class Player extends Character { interfaceSet.close(); // TODO: should this be done if size == 0? } -} + /** + * Gets the player's prayer icon. + * + * @return The prayer icon. + */ + public int getPrayerIcon() { + return prayerIcon; + } + + /** + * Gets the player's head icon. + * + * @return The head icon. + */ + public int getHeadIcon() { + return headIcon; + } + + /** + * Sends a message to the character. + * + * @param message The message. + */ + public void sendMessage(String message) { + send(new ServerMessageEvent(message)); + } + + /** + * Sets the player's head icon. + * + * @param headIcon The head icon. + */ + public void setHeadIcon(int headIcon) { + this.headIcon = headIcon; + } + + /** + * Sets the player's prayer icon. + * + * @param prayerIcon The prayer icon. + */ + public void setPrayerIcon(int prayerIcon) { + this.prayerIcon = prayerIcon; + } + +} \ No newline at end of file diff --git a/src/org/apollo/game/sync/block/AppearanceBlock.java b/src/org/apollo/game/sync/block/AppearanceBlock.java index d3b22949..eac12b3c 100644 --- a/src/org/apollo/game/sync/block/AppearanceBlock.java +++ b/src/org/apollo/game/sync/block/AppearanceBlock.java @@ -1,7 +1,7 @@ package org.apollo.game.sync.block; -import org.apollo.game.model.Appearance; import org.apollo.game.model.Inventory; +import org.apollo.game.model.Appearance; /** * The appearance {@link SynchronizationBlock}. @@ -10,8 +10,6 @@ import org.apollo.game.model.Inventory; */ public final class AppearanceBlock extends SynchronizationBlock { - // TODO head icons support - /** * The player's name. */ @@ -37,6 +35,21 @@ public final class AppearanceBlock extends SynchronizationBlock { */ private final Inventory equipment; + /** + * The player's prayer icon. + */ + private final int prayerIcon; + + /** + * The player's head icon. + */ + private final int headIcon; + + /** + * The npc id this player is appearing as, if any. + */ + private final int npcId; + /** * Creates the appearance block. * @@ -46,21 +59,25 @@ public final class AppearanceBlock extends SynchronizationBlock { * @param skill The player's skill, or 0 if showing the combat level. * @param equipment The player's equipment. */ - AppearanceBlock(long name, Appearance appearance, int combat, int skill, Inventory equipment) { + AppearanceBlock(long name, Appearance appearance, int combat, int skill, Inventory equipment, int prayerIcon, + int headIcon, int npcId) { this.name = name; this.appearance = appearance; this.combat = combat; this.skill = skill; this.equipment = equipment.clone(); + this.prayerIcon = prayerIcon; + this.headIcon = headIcon; + this.npcId = npcId; } /** - * Gets the player's name. + * If the player is appearing as an npc or not. * - * @return The player's name. + * @return {@code true} if the player is appearing as an npc, otherwise {@code false}. */ - public long getName() { - return name; + public boolean appearingAsNpc() { + return npcId != -1; } /** @@ -81,15 +98,6 @@ public final class AppearanceBlock extends SynchronizationBlock { return combat; } - /** - * Gets the player's skill level. - * - * @return The player's skill level. - */ - public int getSkillLevel() { - return skill; - } - /** * Gets the player's equipment. * @@ -99,4 +107,49 @@ public final class AppearanceBlock extends SynchronizationBlock { return equipment; } -} + /** + * Gets the player's head icon. + * + * @return The head icon. + */ + public int getHeadIcon() { + return headIcon; + } + + /** + * Gets the player's name. + * + * @return The player's name. + */ + public long getName() { + return name; + } + + /** + * Gets the npc id the player is appearing as, if any. + * + * @return The npc id. + */ + public int getNpcId() { + return npcId; + } + + /** + * Gets the player's prayer icon. + * + * @return The prayer icon. + */ + public int getPrayerIcon() { + return prayerIcon; + } + + /** + * Gets the player's skill level. + * + * @return The player's skill level. + */ + public int getSkillLevel() { + return skill; + } + +} \ No newline at end of file diff --git a/src/org/apollo/game/sync/block/ChatBlock.java b/src/org/apollo/game/sync/block/ChatBlock.java index 6374d458..18aadfe1 100644 --- a/src/org/apollo/game/sync/block/ChatBlock.java +++ b/src/org/apollo/game/sync/block/ChatBlock.java @@ -29,12 +29,12 @@ public final class ChatBlock extends SynchronizationBlock { } /** - * Gets the privilege level of the player who said the message. + * Gets the compressed message. * - * @return The privilege level. + * @return The compressed message. */ - public PrivilegeLevel getPrivilegeLevel() { - return privilegeLevel; + public byte[] getCompressedMessage() { + return chatEvent.getCompressedMessage(); } /** @@ -46,6 +46,15 @@ public final class ChatBlock extends SynchronizationBlock { return chatEvent.getMessage(); } + /** + * Gets the privilege level of the player who said the message. + * + * @return The privilege level. + */ + public PrivilegeLevel getPrivilegeLevel() { + return privilegeLevel; + } + /** * Gets the text color. * @@ -64,13 +73,4 @@ public final class ChatBlock extends SynchronizationBlock { return chatEvent.getTextEffects(); } - /** - * Gets the compressed message. - * - * @return The compressed message. - */ - public byte[] getCompressedMessage() { - return chatEvent.getCompressedMessage(); - } - -} +} \ No newline at end of file diff --git a/src/org/apollo/game/sync/block/ForceChatBlock.java b/src/org/apollo/game/sync/block/ForceChatBlock.java new file mode 100644 index 00000000..b365d412 --- /dev/null +++ b/src/org/apollo/game/sync/block/ForceChatBlock.java @@ -0,0 +1,35 @@ +package org.apollo.game.sync.block; + +/** + * The Force Chat {@link SynchronizationBlock}. This is a block that can be implemented in both player and npc + * synchronization tasks, and will cause the character to shout the specified text. It is not possible to add colour or + * effect (e.g. wave or scroll) to this block. + * + * @author Major + */ +public class ForceChatBlock extends SynchronizationBlock { + + /** + * The chat text. + */ + private final String message; + + /** + * Creates a new force chat [@link SynchronizationBlock}. + * + * @param message The message the character will say. + */ + public ForceChatBlock(String message) { + this.message = message; + } + + /** + * Gets the message being sent by this block. + * + * @return The message. + */ + public String getMessage() { + return message; + } + +} \ No newline at end of file diff --git a/src/org/apollo/game/sync/block/ForceMovementBlock.java b/src/org/apollo/game/sync/block/ForceMovementBlock.java new file mode 100644 index 00000000..b07cb077 --- /dev/null +++ b/src/org/apollo/game/sync/block/ForceMovementBlock.java @@ -0,0 +1,143 @@ +package org.apollo.game.sync.block; + +import org.apollo.game.model.Direction; +import org.apollo.game.model.Position; + +/** + * The Force Movement {@link SynchronizationBlock}. + * + * @note This block is used to force a player to walk to a set location. The player can then perform an action (e.g. an + * animation), as used in the Agility skill, hence this block earning the name 'Asynchronous Animation/Walking', + * although the action is not restricted to animations. + * + * @author Major + */ +public class ForceMovementBlock extends SynchronizationBlock { + + /** + * The initial {@link Position} of the player. + */ + private final Position initialPosition; + + /** + * The {@link Position} the player is being moved to. + */ + private final Position finalPosition; + + /** + * The length of time (in game ticks) the player's movement along the X axis will last. + */ + private final int travelDurationX; + + /** + * The length of time (in game ticks) the player's movement along the Y axis will last. + */ + private final int travelDurationY; + + /** + * The direction the player is moving. + */ + private final Direction direction; + + /** + * Creates a new Force Movement block. + * + * @param initialPosition The initial {@link Position} of the player. + * @param finalPosition The final {@link Position} of the player + * @param travelDurationX The length of time (in game ticks) the player's movement along the X axis will last. + * @param travelDurationY The length of time (in game ticks) the player's movement along the Y axis will last. + * @param direction The direction the player should move. + */ + public ForceMovementBlock(Position initialPosition, Position finalPosition, int travelDurationX, + int travelDurationY, Direction direction) { + this.initialPosition = initialPosition; + this.finalPosition = finalPosition; + this.travelDurationX = travelDurationX; + this.travelDurationY = travelDurationY; + this.direction = direction; + } + + /** + * Gets the direction the player should move. + * + * @return The direction. + */ + public Direction getDirection() { + return direction; + } + + /** + * Gets the final position. This shouldn't be used to get the initial X and Y coordinates, see {@link #getFinalX()} + * and {@link #getFinalY()}. + * + * @return The final {@link Position}. + */ + public Position getFinalPosition() { + return finalPosition; + } + + /** + * Gets the X coordinate of the final {@link Position}. + * + * @return The X coordinate. + */ + public int getFinalX() { + return finalPosition.getX(); + } + + /** + * Gets the Y coordinate of the final {@link Position}. + * + * @return The Y coordinate. + */ + public int getFinalY() { + return finalPosition.getY(); + } + + /** + * Gets the initial position. This shouldn't be used to get the initial X and Y coordinates, see + * {@link #getInitialX()} and {@link #getInitialY()}. + * + * @return The initial {@link Position}. + */ + public Position getInitialPosition() { + return initialPosition; + } + + /** + * Gets the X coordinate of the initial {@link Position}. + * + * @return The X coordinate. + */ + public int getInitialX() { + return initialPosition.getX(); + } + + /** + * Gets the Y coordinate of the initial {@link Position}. + * + * @return The Y coordinate. + */ + public int getInitialY() { + return initialPosition.getY(); + } + + /** + * Gets the length of time (in game ticks) the player's movement along the Y axis will last. + * + * @return The time period. + */ + public int getTravelDurationX() { + return travelDurationX; + } + + /** + * Gets the length of time (in game ticks) the player's movement along the Y axis will last. + * + * @return The time period. + */ + public int getTravelDurationY() { + return travelDurationY; + } + +} \ No newline at end of file diff --git a/src/org/apollo/game/sync/block/HitUpdateBlock.java b/src/org/apollo/game/sync/block/HitUpdateBlock.java new file mode 100644 index 00000000..3fee143c --- /dev/null +++ b/src/org/apollo/game/sync/block/HitUpdateBlock.java @@ -0,0 +1,82 @@ +package org.apollo.game.sync.block; + +/** + * The Hit Update {@link SynchronizationBlock}. This is a simple implementation designed so that you can integrate it + * easily with your combat system. Both npcs and players can implement this block. + * + * @author Major + */ +public class HitUpdateBlock extends SynchronizationBlock { + + /** + * The amount of damage the hit will do. + */ + private final int damage; + + /** + * The type of hit (e.g. normal, poison). + */ + private final int type; + + /** + * The {@link org.apollo.game.model.Character}'s current health. + */ + private final int currentHealth; + + /** + * The {@link org.apollo.game.model.Character}'s maximum health. + */ + private final int maximumHealth; + + /** + * Creates a new Hit Update block. + * + * @param hitDamage The damage dealt by the hit. + * @param hitType The type of hit. + * @param currentHealth The current health of the {@link org.apollo.game.model.Character}. + * @param maximumHealth The maximum health of the {@link org.apollo.game.model.Character}. + */ + public HitUpdateBlock(int hitDamage, int hitType, int currentHealth, int maximumHealth) { + damage = hitDamage; + type = hitType; + this.currentHealth = currentHealth; + this.maximumHealth = maximumHealth; + } + + /** + * Gets the current health of the {@link org.apollo.game.model.Character}. + * + * @return The current health; + */ + public int getCurrentHealth() { + return currentHealth; + } + + /** + * Gets the damage done by the hit. + * + * @return The damage. + */ + public int getDamage() { + return damage; + } + + /** + * Gets the maximum health of the {@link org.apollo.game.model.Character}. + * + * @return The maximum health. + */ + public int getMaximumHealth() { + return maximumHealth; + } + + /** + * Gets the hit type. + * + * @return The type. + */ + public int getType() { + return type; + } + +} \ No newline at end of file diff --git a/src/org/apollo/game/sync/block/InteractingCharacterBlock.java b/src/org/apollo/game/sync/block/InteractingCharacterBlock.java new file mode 100644 index 00000000..49d0d72c --- /dev/null +++ b/src/org/apollo/game/sync/block/InteractingCharacterBlock.java @@ -0,0 +1,36 @@ +package org.apollo.game.sync.block; + +/** + * The InteractingCharacterBlock {@link SynchronizationBlock}. + * + * @note As all Apollo events should be immutable to avoid concurency issues, this uses the index of the character + * rather than the actual character. This should not be changed. + * + * @author Major + */ +public class InteractingCharacterBlock extends SynchronizationBlock { + + /** + * The index of the character. + */ + private final int characterIndex; + + /** + * Creates the interacting character block. + * + * @param characterIndex The index of the current interacting character. + */ + public InteractingCharacterBlock(int characterIndex) { + this.characterIndex = characterIndex; + } + + /** + * Gets the interacting character's current index. + * + * @return The index of the character. + */ + public int getInteractingCharacterIndex() { + return characterIndex; + } + +} \ No newline at end of file diff --git a/src/org/apollo/game/sync/block/SecondHitUpdateBlock.java b/src/org/apollo/game/sync/block/SecondHitUpdateBlock.java new file mode 100644 index 00000000..ea4cc4ea --- /dev/null +++ b/src/org/apollo/game/sync/block/SecondHitUpdateBlock.java @@ -0,0 +1,83 @@ +package org.apollo.game.sync.block; + +/** + * The Second Hit Update {@link SynchronizationBlock}. This is believed to be used for when multiple attacks happen at + * once (for example, the dragon-dagger special attack). This block can be implemented by both players and npcs. + * + * + * @author Major + */ +public class SecondHitUpdateBlock extends SynchronizationBlock { + + /** + * The amount of damage the hit will do. + */ + private final int damage; + + /** + * The type of hit (e.g. normal, poison). + */ + private final int type; + + /** + * The character's current health. + */ + private final int currentHealth; + + /** + * The character's maximum health. + */ + private final int maximumHealth; + + /** + * Creates a new Second Hit Update block. + * + * @param hitDamage The damage dealt by the hit. + * @param hitType The type of hit. + * @param currentHealth The current health of the character. + * @param maximumHealth The maximum health of the character. + */ + public SecondHitUpdateBlock(int hitDamage, int hitType, int currentHealth, int maximumHealth) { + damage = hitDamage; + type = hitType; + this.currentHealth = currentHealth; + this.maximumHealth = maximumHealth; + } + + /** + * Gets the current health of the character. + * + * @return The current health; + */ + public int getCurrentHealth() { + return currentHealth; + } + + /** + * Gets the damage done by the hit. + * + * @return The damage. + */ + public int getDamage() { + return damage; + } + + /** + * Gets the maximum health of the character. + * + * @return The maximum health. + */ + public int getMaximumHealth() { + return maximumHealth; + } + + /** + * Gets the hit type. + * + * @return The type. + */ + public int getType() { + return type; + } + +} \ No newline at end of file diff --git a/src/org/apollo/game/sync/block/SynchronizationBlock.java b/src/org/apollo/game/sync/block/SynchronizationBlock.java index 7d8f7057..92bc9e5a 100644 --- a/src/org/apollo/game/sync/block/SynchronizationBlock.java +++ b/src/org/apollo/game/sync/block/SynchronizationBlock.java @@ -2,9 +2,10 @@ package org.apollo.game.sync.block; import org.apollo.game.event.impl.ChatEvent; import org.apollo.game.model.Animation; +import org.apollo.game.model.Direction; import org.apollo.game.model.Graphic; -import org.apollo.game.model.Player; import org.apollo.game.model.Position; +import org.apollo.game.model.Player; import org.apollo.game.sync.seg.SynchronizationSegment; /** @@ -16,6 +17,16 @@ import org.apollo.game.sync.seg.SynchronizationSegment; */ public abstract class SynchronizationBlock { + /** + * Creates an animation block with the specified animation. + * + * @param animation The animation. + * @return The animation block. + */ + public static SynchronizationBlock createAnimationBlock(Animation animation) { + return new AnimationBlock(animation); + } + /** * Creates an appearance block for the specified player. * @@ -24,7 +35,8 @@ public abstract class SynchronizationBlock { */ public static SynchronizationBlock createAppearanceBlock(Player player) { return new AppearanceBlock(player.getEncodedName(), player.getAppearance(), player.getSkillSet() - .getCombatLevel(), 0, player.getEquipment()); + .getCombatLevel(), 0, player.getEquipment(), player.getPrayerIcon(), player.getHeadIcon(), + player.getNpcDefinition() == null ? -1 : player.getNpcDefinition().getId()); } /** @@ -39,13 +51,28 @@ public abstract class SynchronizationBlock { } /** - * Creates an animation block with the specified animation. + * Creates a new force chat block with the specified message. * - * @param animation The animation. - * @return The animation block. + * @param message The message. + * @return The force chat block. */ - public static SynchronizationBlock createAnimationBlock(Animation animation) { - return new AnimationBlock(animation); + public static SynchronizationBlock createForceChatBlock(String message) { + return new ForceChatBlock(message); + } + + /** + * Creates a new force movement block with the specified parameters. + * + * @param initialPosition The initial position of the player. + * @param finalPosition The final position of the player. + * @param travelDurationX The duration motion along the X axis will occur. + * @param travelDurationY The duration motion along the Y axis will occur. + * @param direction The direction the player will face. + * @return The force movement block. + */ + public static SynchronizationBlock createForceMovementBlock(Position initialPosition, Position finalPosition, + int travelDurationX, int travelDurationY, Direction direction) { + return new ForceMovementBlock(initialPosition, finalPosition, travelDurationX, travelDurationY, direction); } /** @@ -58,6 +85,16 @@ public abstract class SynchronizationBlock { return new GraphicBlock(graphic); } + /** + * Creates an interacting character block with the specified character index. + * + * @param index The index of the interacting character. + * @return The interacting character block. + */ + public static SynchronizationBlock createInteractingCharacterBlock(int index) { + return new InteractingCharacterBlock(index); + } + /** * Creates a turn to position block with the specified position. * @@ -68,4 +105,4 @@ public abstract class SynchronizationBlock { return new TurnToPositionBlock(position); } -} +} \ No newline at end of file diff --git a/src/org/apollo/game/sync/block/SynchronizationBlockSet.java b/src/org/apollo/game/sync/block/SynchronizationBlockSet.java index e305a43a..abf5c474 100644 --- a/src/org/apollo/game/sync/block/SynchronizationBlockSet.java +++ b/src/org/apollo/game/sync/block/SynchronizationBlockSet.java @@ -22,7 +22,15 @@ public final class SynchronizationBlockSet implements Cloneable { */ public void add(SynchronizationBlock block) { Class clazz = block.getClass(); - blocks.put(clazz, block); // this will overwrite old updates. best thing to do? + blocks.put(clazz, block); // this will overwrite old updates. best thing + // to do? + } + + /** + * Clears the set. + */ + public void clear() { + blocks.clear(); } @Override @@ -32,22 +40,6 @@ public final class SynchronizationBlockSet implements Cloneable { return copy; } - /** - * Clears the set. - */ - public void clear() { - blocks.clear(); - } - - /** - * Gets the size of the set. - * - * @return The size of the set. - */ - public int size() { - return blocks.size(); - } - /** * Checks if this set contains the specified block. * @@ -58,15 +50,6 @@ public final class SynchronizationBlockSet implements Cloneable { return blocks.containsKey(clazz); } - /** - * Removes a block. - * - * @param clazz The block's class. - */ - public void remove(Class clazz) { - blocks.remove(clazz); - } - /** * Gets a block. * @@ -79,4 +62,22 @@ public final class SynchronizationBlockSet implements Cloneable { return (T) blocks.get(clazz); } + /** + * Removes a block. + * + * @param clazz The block's class. + */ + public void remove(Class clazz) { + blocks.remove(clazz); + } + + /** + * Gets the size of the set. + * + * @return The size of the set. + */ + public int size() { + return blocks.size(); + } + } diff --git a/src/org/apollo/net/release/r317/PlayerSynchronizationEventEncoder.java b/src/org/apollo/net/release/r317/PlayerSynchronizationEventEncoder.java index 49d65017..ddafc644 100644 --- a/src/org/apollo/net/release/r317/PlayerSynchronizationEventEncoder.java +++ b/src/org/apollo/net/release/r317/PlayerSynchronizationEventEncoder.java @@ -2,19 +2,24 @@ package org.apollo.net.release.r317; import org.apollo.game.event.impl.PlayerSynchronizationEvent; import org.apollo.game.model.Animation; -import org.apollo.game.model.Appearance; import org.apollo.game.model.Direction; -import org.apollo.game.model.EquipmentConstants; import org.apollo.game.model.Gender; import org.apollo.game.model.Graphic; import org.apollo.game.model.Inventory; import org.apollo.game.model.Item; import org.apollo.game.model.Position; import org.apollo.game.model.def.EquipmentDefinition; +import org.apollo.game.model.Appearance; +import org.apollo.game.model.EquipmentConstants; import org.apollo.game.sync.block.AnimationBlock; import org.apollo.game.sync.block.AppearanceBlock; import org.apollo.game.sync.block.ChatBlock; +import org.apollo.game.sync.block.ForceChatBlock; +import org.apollo.game.sync.block.ForceMovementBlock; import org.apollo.game.sync.block.GraphicBlock; +import org.apollo.game.sync.block.HitUpdateBlock; +import org.apollo.game.sync.block.InteractingCharacterBlock; +import org.apollo.game.sync.block.SecondHitUpdateBlock; import org.apollo.game.sync.block.SynchronizationBlockSet; import org.apollo.game.sync.block.TurnToPositionBlock; import org.apollo.game.sync.seg.AddCharacterSegment; @@ -34,6 +39,7 @@ import org.apollo.net.release.EventEncoder; * An {@link EventEncoder} for the {@link PlayerSynchronizationEvent}. * * @author Graham + * @author Major */ public final class PlayerSynchronizationEventEncoder extends EventEncoder { @@ -73,16 +79,6 @@ public final class PlayerSynchronizationEventEncoder extends EventEncoder 0; - if (seg.getType() == SegmentType.TELEPORT) { - Position pos = ((TeleportSegment) seg).getDestination(); - builder.putBits(1, 1); - builder.putBits(2, 3); - builder.putBits(2, pos.getHeight()); - builder.putBits(1, event.hasRegionChanged() ? 0 : 1); - builder.putBits(1, updateRequired ? 1 : 0); - builder.putBits(7, pos.getLocalY(event.getLastKnownRegion())); - builder.putBits(7, pos.getLocalX(event.getLastKnownRegion())); - } else if (seg.getType() == SegmentType.RUN) { - Direction[] directions = ((MovementSegment) seg).getDirections(); - builder.putBits(1, 1); - builder.putBits(2, 2); - builder.putBits(3, directions[0].toInteger()); - builder.putBits(3, directions[1].toInteger()); - builder.putBits(1, updateRequired ? 1 : 0); - } else if (seg.getType() == SegmentType.WALK) { - Direction[] directions = ((MovementSegment) seg).getDirections(); - builder.putBits(1, 1); - builder.putBits(2, 1); - builder.putBits(3, directions[0].toInteger()); - builder.putBits(1, updateRequired ? 1 : 0); + private void putAnimationBlock(AnimationBlock block, GamePacketBuilder blockBuilder) { + Animation animation = block.getAnimation(); + blockBuilder.put(DataType.SHORT, DataOrder.LITTLE, animation.getId()); + blockBuilder.put(DataType.BYTE, DataTransformation.NEGATE, animation.getDelay()); + } + + /** + * Puts an appearance block into the specified builder. + * + * @param block The block. + * @param blockBuilder The builder. + */ + private void putAppearanceBlock(AppearanceBlock block, GamePacketBuilder blockBuilder) { + Appearance appearance = block.getAppearance(); + GamePacketBuilder playerProperties = new GamePacketBuilder(); + + playerProperties.put(DataType.BYTE, appearance.getGender().toInteger()); + playerProperties.put(DataType.BYTE, block.getPrayerIcon() < 0 ? 0 : block.getPrayerIcon()); + + if (block.appearingAsNpc()) { + playerProperties.put(DataType.BYTE, 255); + playerProperties.put(DataType.BYTE, 255); + playerProperties.put(DataType.SHORT, block.getNpcId()); } else { - if (updateRequired) { - builder.putBits(1, 1); - builder.putBits(2, 0); + Inventory equipment = block.getEquipment(); + int[] style = appearance.getStyle(); + Item item, chest, helm; + + for (int slot = 0; slot < 4; slot++) { + if ((item = equipment.get(slot)) != null) { + playerProperties.put(DataType.SHORT, 0x200 + item.getId()); + } else { + playerProperties.put(DataType.BYTE, 0); + } + } + + if ((chest = equipment.get(EquipmentConstants.CHEST)) != null) { + playerProperties.put(DataType.SHORT, 0x200 + chest.getId()); } else { - builder.putBits(1, 0); + playerProperties.put(DataType.SHORT, 0x100 + style[2]); + } + + if ((item = equipment.get(EquipmentConstants.SHIELD)) != null) { + playerProperties.put(DataType.SHORT, 0x200 + item.getId()); + } else { + playerProperties.put(DataType.BYTE, 0); + } + + if (chest != null) { + EquipmentDefinition def = EquipmentDefinition.forId(chest.getId()); + if (def != null && !def.isFullBody()) { + playerProperties.put(DataType.SHORT, 0x100 + style[3]); + } else { + playerProperties.put(DataType.BYTE, 0); + } + } else { + playerProperties.put(DataType.SHORT, 0x100 + style[3]); + } + + if ((item = equipment.get(EquipmentConstants.LEGS)) != null) { + playerProperties.put(DataType.SHORT, 0x200 + item.getId()); + } else { + playerProperties.put(DataType.SHORT, 0x100 + style[5]); + } + + if ((helm = equipment.get(EquipmentConstants.HAT)) != null) { + EquipmentDefinition def = EquipmentDefinition.forId(helm.getId()); + if (def != null && !def.isFullHat() && !def.isFullMask()) { + playerProperties.put(DataType.SHORT, 0x100 + style[0]); + } else { + playerProperties.put(DataType.BYTE, 0); + } + } else { + playerProperties.put(DataType.SHORT, 0x100 + style[0]); + } + + if ((item = equipment.get(EquipmentConstants.HANDS)) != null) { + playerProperties.put(DataType.SHORT, 0x200 + item.getId()); + } else { + playerProperties.put(DataType.SHORT, 0x100 + style[4]); + } + + if ((item = equipment.get(EquipmentConstants.FEET)) != null) { + playerProperties.put(DataType.SHORT, 0x200 + item.getId()); + } else { + playerProperties.put(DataType.SHORT, 0x100 + style[6]); + } + + EquipmentDefinition def = null; + if (helm != null) { + def = EquipmentDefinition.forId(helm.getId()); + } + if (def != null && (def.isFullHat() || def.isFullMask()) || appearance.getGender() == Gender.FEMALE) { + playerProperties.put(DataType.BYTE, 0); + } else { + playerProperties.put(DataType.SHORT, 0x100 + style[1]); } } + + int[] colors = appearance.getColors(); + for (int color : colors) { + playerProperties.put(DataType.BYTE, color); + } + + playerProperties.put(DataType.SHORT, 0x328); // stand + playerProperties.put(DataType.SHORT, 0x337); // stand turn + playerProperties.put(DataType.SHORT, 0x333); // walk + playerProperties.put(DataType.SHORT, 0x334); // turn 180 + playerProperties.put(DataType.SHORT, 0x335); // turn 90 cw + playerProperties.put(DataType.SHORT, 0x336); // turn 90 ccw + playerProperties.put(DataType.SHORT, 0x338); // run + + playerProperties.put(DataType.LONG, block.getName()); + playerProperties.put(DataType.BYTE, block.getCombatLevel()); + playerProperties.put(DataType.SHORT, block.getSkillLevel()); + + blockBuilder.put(DataType.BYTE, DataTransformation.NEGATE, playerProperties.getLength()); + + blockBuilder.putRawBuilder(playerProperties); } /** @@ -155,25 +236,36 @@ public final class PlayerSynchronizationEventEncoder extends EventEncoder 0) { int mask = 0; + if (blockSet.contains(ForceMovementBlock.class)) { + mask |= 0x400; + } if (blockSet.contains(GraphicBlock.class)) { mask |= 0x100; } - if (blockSet.contains(AnimationBlock.class)) { mask |= 0x8; } - + if (blockSet.contains(ForceChatBlock.class)) { + mask |= 0x4; + } if (blockSet.contains(ChatBlock.class)) { mask |= 0x80; } - + if (blockSet.contains(InteractingCharacterBlock.class)) { + mask |= 0x1; + } if (blockSet.contains(AppearanceBlock.class)) { mask |= 0x10; } - if (blockSet.contains(TurnToPositionBlock.class)) { mask |= 0x2; } + if (blockSet.contains(HitUpdateBlock.class)) { + mask |= 0x20; + } + if (blockSet.contains(SecondHitUpdateBlock.class)) { + mask |= 0x200; + } if (mask >= 0x100) { mask |= 0x40; @@ -182,30 +274,181 @@ public final class PlayerSynchronizationEventEncoder extends EventEncoder 0; + if (seg.getType() == SegmentType.TELEPORT) { // teleported + Position pos = ((TeleportSegment) seg).getDestination(); + builder.putBits(1, 1); + builder.putBits(2, 3); + builder.putBits(2, pos.getHeight()); + builder.putBits(1, event.hasRegionChanged() ? 0 : 1); + builder.putBits(1, updateRequired ? 1 : 0); + builder.putBits(7, pos.getLocalY(event.getLastKnownRegion())); + builder.putBits(7, pos.getLocalX(event.getLastKnownRegion())); + } else if (seg.getType() == SegmentType.RUN) { // running movement + Direction[] directions = ((MovementSegment) seg).getDirections(); + builder.putBits(1, 1); + builder.putBits(2, 2); + builder.putBits(3, directions[0].toInteger()); + builder.putBits(3, directions[1].toInteger()); + builder.putBits(1, updateRequired ? 1 : 0); + } else if (seg.getType() == SegmentType.WALK) { // walking movement + Direction[] directions = ((MovementSegment) seg).getDirections(); + builder.putBits(1, 1); + builder.putBits(2, 1); + builder.putBits(3, directions[0].toInteger()); + builder.putBits(1, updateRequired ? 1 : 0); + } else { + if (updateRequired) { // no movement + builder.putBits(1, 1); + builder.putBits(2, 0); + } else { + builder.putBits(1, 0); // no sync required + } + } + } + + /** + * Puts a remove character update. + * + * @param builder The builder. + */ + private void putRemoveCharacterUpdate(GamePacketBuilder builder) { + builder.putBits(1, 1); + builder.putBits(2, 3); + } + + /** + * Puts a Second Hit Update block into the specified builder. + * + * @param block The block. + * @param builder The builder. + */ + private void putSecondHitUpdateBlock(SecondHitUpdateBlock block, GamePacketBuilder builder) { + builder.put(DataType.BYTE, block.getDamage()); + builder.put(DataType.BYTE, DataTransformation.SUBTRACT, block.getType()); + builder.put(DataType.BYTE, block.getCurrentHealth()); + builder.put(DataType.BYTE, DataTransformation.NEGATE, block.getMaximumHealth()); + } + + /** + * Puts a Turn To Position block into the specified builder. * * @param block The block. * @param blockBuilder The builder. @@ -216,153 +459,4 @@ public final class PlayerSynchronizationEventEncoder extends EventEncoder { @@ -73,16 +79,6 @@ public final class PlayerSynchronizationEventEncoder extends EventEncoder 0) { + int mask = 0; + + if (blockSet.contains(AnimationBlock.class)) { + mask |= 0x8; + } + if (blockSet.contains(ForceChatBlock.class)) { + mask |= 0x10; + } + if (blockSet.contains(ForceMovementBlock.class)) { + mask |= 0x100; + } + if (blockSet.contains(InteractingCharacterBlock.class)) { + mask |= 0x1; + } + if (blockSet.contains(TurnToPositionBlock.class)) { + mask |= 0x2; + } + if (blockSet.contains(GraphicBlock.class)) { + mask |= 0x200; + } + if (blockSet.contains(AppearanceBlock.class)) { + mask |= 0x4; + } + if (blockSet.contains(SecondHitUpdateBlock.class)) { + mask |= 0x400; + } + if (blockSet.contains(ChatBlock.class)) { + mask |= 0x40; + } + if (blockSet.contains(HitUpdateBlock.class)) { + mask |= 0x80; + } + + if (mask >= 0x100) { + mask |= 0x20; + blockBuilder.put(DataType.SHORT, DataOrder.LITTLE, mask); + } else { + blockBuilder.put(DataType.BYTE, mask); + } + + if (blockSet.contains(AnimationBlock.class)) { + putAnimationBlock(blockSet.get(AnimationBlock.class), blockBuilder); + } + if (blockSet.contains(ForceChatBlock.class)) { + putForceChatBlock(blockSet.get(ForceChatBlock.class), blockBuilder); + } + if (blockSet.contains(ForceMovementBlock.class)) { + putForceMovementBlock(blockSet.get(ForceMovementBlock.class), blockBuilder); + } + if (blockSet.contains(InteractingCharacterBlock.class)) { + putInteractingCharacterBlock(blockSet.get(InteractingCharacterBlock.class), blockBuilder); + } + if (blockSet.contains(TurnToPositionBlock.class)) { + putTurnToPositionBlock(blockSet.get(TurnToPositionBlock.class), blockBuilder); + } + if (blockSet.contains(GraphicBlock.class)) { + putGraphicBlock(blockSet.get(GraphicBlock.class), blockBuilder); + } + if (blockSet.contains(AppearanceBlock.class)) { + putAppearanceBlock(blockSet.get(AppearanceBlock.class), blockBuilder); + } + if (blockSet.contains(SecondHitUpdateBlock.class)) { + putSecondHitUpdateBlock(blockSet.get(SecondHitUpdateBlock.class), blockBuilder); + } + if (blockSet.contains(ChatBlock.class)) { + putChatBlock(blockSet.get(ChatBlock.class), blockBuilder); + } + if (blockSet.contains(HitUpdateBlock.class)) { + putHitUpdateBlock(blockSet.get(HitUpdateBlock.class), blockBuilder); + } + + } + } + + /** + * Puts a chat block into the specified builder. + * + * @param block The block. + * @param blockBuilder The builder. + */ + private void putChatBlock(ChatBlock block, GamePacketBuilder blockBuilder) { + byte[] bytes = block.getCompressedMessage(); + blockBuilder.put(DataType.SHORT, DataOrder.LITTLE, block.getTextEffects() << 8 | block.getTextColor()); + blockBuilder.put(DataType.BYTE, DataTransformation.NEGATE, block.getPrivilegeLevel().toInteger()); + blockBuilder.put(DataType.BYTE, DataTransformation.ADD, bytes.length); + blockBuilder.putBytes(DataTransformation.ADD, bytes); + } + + /** + * Puts a force chat block into the specified builder. + * + * @param block The block. + * @param builder The builder. + */ + private void putForceChatBlock(ForceChatBlock block, GamePacketBuilder builder) { + builder.putString(block.getMessage()); + } + + /** + * Puts a force movement block into the specified builder. + * + * @param block The block. + * @param builder The builder. + */ + private void putForceMovementBlock(ForceMovementBlock block, GamePacketBuilder builder) { + builder.put(DataType.BYTE, DataTransformation.ADD, block.getInitialX()); + builder.put(DataType.BYTE, DataTransformation.NEGATE, block.getInitialY()); + builder.put(DataType.BYTE, DataTransformation.SUBTRACT, block.getFinalX()); + builder.put(DataType.BYTE, block.getFinalY()); + builder.put(DataType.SHORT, block.getTravelDurationX()); + builder.put(DataType.SHORT, DataTransformation.ADD, block.getTravelDurationY()); + builder.put(DataType.BYTE, block.getDirection().toInteger()); + } + + /** + * Puts a graphic block into the specified builder. + * + * @param block The block. + * @param blockBuilder The builder. + */ + private void putGraphicBlock(GraphicBlock block, GamePacketBuilder blockBuilder) { + Graphic graphic = block.getGraphic(); + blockBuilder.put(DataType.SHORT, DataTransformation.ADD, graphic.getId()); + blockBuilder.put(DataType.INT, DataOrder.MIDDLE, graphic.getHeight() << 16 & 0xFFFF0000 | graphic.getDelay() + & 0x0000FFFF); + } + + /** + * Puts a hit update block into the specified builder. + * + * @param block The block. + * @param builder The builder. + */ + private void putHitUpdateBlock(HitUpdateBlock block, GamePacketBuilder builder) { + builder.put(DataType.BYTE, DataTransformation.SUBTRACT, block.getDamage()); + builder.put(DataType.BYTE, DataTransformation.NEGATE, block.getType()); + builder.put(DataType.BYTE, DataTransformation.SUBTRACT, block.getCurrentHealth()); + builder.put(DataType.BYTE, block.getMaximumHealth()); + } + + /** + * Puts an interacting character block into the specified builder. + * + * @param block The block. + * @param builder The builder. + */ + private void putInteractingCharacterBlock(InteractingCharacterBlock block, GamePacketBuilder builder) { + builder.put(DataType.SHORT, DataTransformation.ADD, block.getInteractingCharacterIndex()); + } + /** * Puts a movement update for the specified segment. * @@ -145,63 +427,26 @@ public final class PlayerSynchronizationEventEncoder extends EventEncoder 0) { - int mask = 0; + private void putRemoveCharacterUpdate(GamePacketBuilder builder) { + builder.putBits(1, 1); + builder.putBits(2, 3); + } - if (blockSet.contains(AnimationBlock.class)) { - mask |= 0x8; - } - - if (blockSet.contains(ChatBlock.class)) { - mask |= 0x40; - } - - if (blockSet.contains(GraphicBlock.class)) { - mask |= 0x200; - } - - if (blockSet.contains(AppearanceBlock.class)) { - mask |= 0x4; - } - - if (blockSet.contains(TurnToPositionBlock.class)) { - mask |= 0x2; - } - - if (mask >= 0x100) { - mask |= 0x20; - blockBuilder.put(DataType.SHORT, DataOrder.LITTLE, mask); - } else { - blockBuilder.put(DataType.BYTE, mask); - } - - if (blockSet.contains(AnimationBlock.class)) { - putAnimationBlock(blockSet.get(AnimationBlock.class), blockBuilder); - } - - if (blockSet.contains(ChatBlock.class)) { - putChatBlock(blockSet.get(ChatBlock.class), blockBuilder); - } - - if (blockSet.contains(GraphicBlock.class)) { - putGraphicBlock(blockSet.get(GraphicBlock.class), blockBuilder); - } - - if (blockSet.contains(AppearanceBlock.class)) { - putAppearanceBlock(blockSet.get(AppearanceBlock.class), blockBuilder); - } - - if (blockSet.contains(TurnToPositionBlock.class)) { - putTurnToPositionBlock(blockSet.get(TurnToPositionBlock.class), blockBuilder); - } - } + /** + * Puts a secondary hit update block into the specified builder. + * + * @param block The block. + * @param builder The builder. + */ + private void putSecondHitUpdateBlock(SecondHitUpdateBlock block, GamePacketBuilder builder) { + builder.put(DataType.BYTE, DataTransformation.ADD, block.getDamage()); + builder.put(DataType.BYTE, DataTransformation.SUBTRACT, block.getType()); + builder.put(DataType.BYTE, DataTransformation.NEGATE, block.getCurrentHealth()); + builder.put(DataType.BYTE, block.getMaximumHealth()); } /** @@ -216,152 +461,4 @@ public final class PlayerSynchronizationEventEncoder extends EventEncoder