package net.scapeemulator.game.update; import java.util.HashMap; import java.util.Map; import net.scapeemulator.game.model.mob.Direction; import net.scapeemulator.game.model.player.Player; import net.scapeemulator.game.msg.impl.PlayerUpdateMessage; import net.scapeemulator.game.net.game.DataOrder; import net.scapeemulator.game.net.game.DataType; import net.scapeemulator.game.net.game.GameFrameBuilder; public abstract class PlayerDescriptor { public static PlayerDescriptor create(Player player, int[] tickets) { Direction firstDirection = player.getFirstDirection(); Direction secondDirection = player.getSecondDirection(); if (firstDirection == Direction.NONE) return new IdlePlayerDescriptor(player, tickets); else if (secondDirection == Direction.NONE) return new WalkPlayerDescriptor(player, tickets); else return new RunPlayerDescriptor(player, tickets); } private final Map<Class<? extends PlayerBlock>, PlayerBlock> blocks = new HashMap<>(); public PlayerDescriptor(Player player, int[] tickets) { this(player, tickets, false); } public PlayerDescriptor(Player player, int[] tickets, boolean force) { if (player.isActive()) { /* * This active check is required for the RemovePlayerDescriptor. The * player id would be -1 in this case, which causes the following * code to crash. Skipping this code doesn't matter as no update * blocks can be sent when removing a player. */ int id = player.getId() - 1; int ticket = player.getAppearanceTicket(); if (tickets[id] != ticket || force) { tickets[id] = ticket; addBlock(new AppearancePlayerBlock(player)); } } if (player.isChatUpdated()) addBlock(new ChatPlayerBlock(player)); if (player.isHitOneUpdated()) addBlock(new HitOnePlayerBlock(player)); if (player.isHitTwoUpdated()) addBlock(new HitTwoPlayerBlock(player)); if (player.isChatForced()) addBlock(new ForceChatPlayerBlock(player)); if (player.isAnimationUpdated()) addBlock(new AnimationPlayerBlock(player)); if (player.isSpotAnimationUpdated()) addBlock(new SpotAnimationPlayerBlock(player)); if (player.isTurnToPositionUpdated()) addBlock(new TurnToPositionPlayerBlock(player)); if (player.isTurnToTargetUpdated()) addBlock(new TurnToMobPlayerBlock(player)); if (player.isForceMovementUpdated()) addBlock(new ForceMovementPlayerBlock(player)); } private void addBlock(PlayerBlock block) { blocks.put(block.getClass(), block); } public boolean isBlockUpdatedRequired() { return !blocks.isEmpty(); } public void encode(PlayerUpdateMessage message, GameFrameBuilder builder, GameFrameBuilder blockBuilder) { encodeDescriptor(message, builder, blockBuilder); if (isBlockUpdatedRequired()) { int flags = 0; for (PlayerBlock block : blocks.values()) flags |= block.getFlag(); if (flags > 0xFF) { flags |= 0x10; blockBuilder.put(DataType.SHORT, DataOrder.LITTLE, flags); } else { blockBuilder.put(DataType.BYTE, flags); } encodeBlock(message, blockBuilder, ChatPlayerBlock.class); encodeBlock(message, blockBuilder, HitOnePlayerBlock.class); encodeBlock(message, blockBuilder, AnimationPlayerBlock.class); encodeBlock(message, blockBuilder, AppearancePlayerBlock.class); encodeBlock(message, blockBuilder, TurnToMobPlayerBlock.class); encodeBlock(message, blockBuilder, ForceMovementPlayerBlock.class); encodeBlock(message, blockBuilder, ForceChatPlayerBlock.class); encodeBlock(message, blockBuilder, HitTwoPlayerBlock.class); // encodeBlock(message, blockBuilder, ???.class); //0x800 encodeBlock(message, blockBuilder, SpotAnimationPlayerBlock.class); encodeBlock(message, blockBuilder, TurnToPositionPlayerBlock.class); } } private void encodeBlock(PlayerUpdateMessage message, GameFrameBuilder builder, Class<? extends PlayerBlock> type) { PlayerBlock block = blocks.get(type); if (block != null) { block.encode(message, builder); } } public abstract void encodeDescriptor(PlayerUpdateMessage message, GameFrameBuilder builder, GameFrameBuilder blockBuilder); }