Code:
package org.apollo.network.release.release83.encoder;
import org.apollo.game.event.impl.NpcSynchronizationEvent;
import org.apollo.game.model.Direction;
import org.apollo.game.model.Position;
import org.apollo.game.model.Graphic;
import org.apollo.game.model.Animation;
import org.apollo.game.sync.block.SynchronizationBlockSet;
import org.apollo.game.sync.block.AnimationBlock;
import org.apollo.game.sync.block.ForceChatBlock;
import org.apollo.game.sync.block.GraphicBlock;
import org.apollo.game.sync.block.HitUpdateBlock;
import org.apollo.game.sync.block.InteractingMobBlock;
import org.apollo.game.sync.block.SecondaryHitUpdateBlock;
import org.apollo.game.sync.block.TurnToPositionBlock;
import org.apollo.game.sync.block.TransformBlock;
import org.apollo.game.sync.seg.AddNpcSegment;
import org.apollo.game.sync.seg.MovementSegment;
import org.apollo.game.sync.seg.SegmentType;
import org.apollo.game.sync.seg.SynchronizationSegment;
import org.apollo.network.codec.game.DataType;
import org.apollo.network.codec.game.DataOrder;
import org.apollo.network.codec.game.DataTransformation;
import org.apollo.network.codec.game.GamePacket;
import org.apollo.network.codec.game.GamePacketBuilder;
import org.apollo.network.meta.PacketType;
import org.apollo.network.release.EventEncoder;
/**
*
* Transforms a {@link NpcSynchronizationEvent} into a {@link GamePacket}.
*
* @author Whis
*
*/
public final class NpcSynchronizationEventEncoder extends EventEncoder<NpcSynchronizationEvent> {
@Override
public GamePacket encode(NpcSynchronizationEvent event) {
// TODO write packet 147 instead of 178 if the location distance between the player and npc takes
// 8 bits (max 256) instead of 5 bits (max 32)
GamePacketBuilder bldr = new GamePacketBuilder(178, PacketType.VARIABLE_SHORT);
bldr.switchToBitAccess();
GamePacketBuilder block = new GamePacketBuilder();
bldr.putBits(8, event.getLocalNpcCount());
for (SynchronizationSegment seg : event.getSegments()) {
SegmentType type = seg.getType();
if (type == SegmentType.REMOVE_MOB) {
putRemoveNpcUpdate(bldr);
} else if (type == SegmentType.ADD_MOB) {
putAddNpcUpdate((AddNpcSegment) seg, event, bldr);
putBlocks(seg, block);
} else {
putMovementUpdate(seg, event, bldr);
putBlocks(seg, block);
}
}
if (block.getLength() > 0) {
bldr.putBits(15, 32767);
bldr.switchToByteAccess();
bldr.putRawBuilder(block);
} else {
bldr.switchToByteAccess();
}
return bldr.toGamePacket();
}
/**
* Puts an add npc update.
* @Param seg The segment.
* @Param event The message.
* @Param bldr The builder.
*/
private void putAddNpcUpdate(AddNpcSegment seg, NpcSynchronizationEvent event, GamePacketBuilder bldr) {
boolean updateReq = seg.getBlockSet().size() > 0;
Position npc = event.getPosition();
Position other = seg.getPosition();
int x = other.getX() - npc.getX();
int y = other.getY() - npc.getY();
bldr.putBits(15, seg.getIndex());
bldr.putBits(5, y);
bldr.putBits(5, x);
bldr.putBits(1, updateReq ? 1 : 0);
bldr.putBits(1, seg.isTeleporting() ? 1 : 0);
bldr.putBits(14, seg.getNpcId());
bldr.putBits(3, 6); // TODO initial direction this npc is facing
}
/**
* Puts the blocks for the specified segment.
* @Param seg The segment.
* @Param bldr The block builder.
*/
private void putBlocks(SynchronizationSegment seg, GamePacketBuilder bldr) {
SynchronizationBlockSet set = seg.getBlockSet();
if (set.size() > 0) {
int mask = 0;
if (set.contains(HitUpdateBlock.class)) {
mask |= 0x10;
}
if (set.contains(GraphicBlock.class)) {
mask |= 0x2;
}
if (set.contains(TransformBlock.class)) {
mask |= 0x80;
}
if (set.contains(SecondaryHitUpdateBlock.class)) {
mask |= 0x40;
}
if (set.contains(AnimationBlock.class)) {
mask |= 0x20;
}
if (set.contains(TurnToPositionBlock.class)) {
mask |= 0x4;
}
if (set.contains(InteractingMobBlock.class)) {
mask |= 0x8;
}
if (set.contains(ForceChatBlock.class)) {
mask |= 0x1;
}
bldr.put(DataType.BYTE, mask);
if (set.contains(HitUpdateBlock.class)) {
putHitUpdateBlock(set.get(HitUpdateBlock.class), bldr);
}
if (set.contains(GraphicBlock.class)) {
putGraphicBlock(set.get(GraphicBlock.class), bldr);
}
if (set.contains(TransformBlock.class)) {
putTransformBlock(set.get(TransformBlock.class), bldr);
}
if (set.contains(SecondaryHitUpdateBlock.class)) {
putSecondaryHitUpdateBlock(set.get(SecondaryHitUpdateBlock.class), bldr);
}
if (set.contains(AnimationBlock.class)) {
putAnimationBlock(set.get(AnimationBlock.class), bldr);
}
if (set.contains(TurnToPositionBlock.class)) {
putTurnToPositionBlock(set.get(TurnToPositionBlock.class), bldr);
}
if (set.contains(InteractingMobBlock.class)) {
putInteractingMobBlock(set.get(InteractingMobBlock.class), bldr);
}
if (set.contains(ForceChatBlock.class)) {
putForceChatBlock(set.get(ForceChatBlock.class), bldr);
}
}
}
/**
* Puts a movement update for the specified segment.
* @Param seg The segment.
* @Param event The event.
* @Param bldr The builder.
*/
private void putMovementUpdate(SynchronizationSegment seg, NpcSynchronizationEvent event, GamePacketBuilder bldr) {
boolean updateReq = seg.getBlockSet().size() > 0;
if (seg.getType() == SegmentType.RUN) {
Direction[] dirs = ((MovementSegment) seg).getDirections();
bldr.putBits(1, 1);
bldr.putBits(2, 2);
bldr.putBits(3, dirs[0].toInteger());
bldr.putBits(3, dirs[1].toInteger());
bldr.putBits(1, updateReq ? 1 : 0);
} else if (seg.getType() == SegmentType.WALK) {
Direction[] directions = ((MovementSegment) seg).getDirections();
bldr.putBits(1, 1);
bldr.putBits(2, 1);
bldr.putBits(3, directions[0].toInteger());
bldr.putBits(1, updateReq ? 1 : 0);
} else {
if (updateReq) {
bldr.putBits(1, 1);
bldr.putBits(2, 0);
} else {
bldr.putBits(1, 0);
}
}
}
/**
* Puts an interacting mob block into the specified builder.
*
* @Param block The block.
* @Param builder The builder.
*/
private void putInteractingMobBlock(InteractingMobBlock block, GamePacketBuilder builder) {
builder.put(DataType.SHORT, DataTransformation.ADD, block.getInteractingMobIndex());
}
/**
* 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.NEGATE, block.getDamage());
builder.put(DataType.BYTE, block.getType());
builder.put(DataType.SHORT, DataOrder.LITTLE, block.getCurrentHealth());
builder.put(DataType.SHORT, block.getMaximumHealth());
}
private void putSecondaryHitUpdateBlock(SecondaryHitUpdateBlock block, GamePacketBuilder builder) {
builder.put(DataType.BYTE, DataTransformation.NEGATE, block.getDamage());
builder.put(DataType.BYTE, DataTransformation.ADD, block.getType());
builder.put(DataType.SHORT, DataOrder.LITTLE, block.getCurrentHealth());
builder.put(DataType.SHORT, DataOrder.LITTLE, DataTransformation.ADD, block.getMaximumHealth());
}
private void putTransformBlock(TransformBlock block, GamePacketBuilder builder) {
builder.put(DataType.SHORT, DataOrder.LITTLE, block.getId());
}
private void putGraphicBlock(GraphicBlock block, GamePacketBuilder builder) {
Graphic graphic = block.getGraphic();
builder.put(DataType.SHORT, graphic.getId());
builder.put(DataType.INT, DataOrder.LITTLE, graphic.getHeight() << 16 & 0xFFFF0000 | graphic.getDelay() & 0x0000FFFF);
}
private void putAnimationBlock(AnimationBlock block, GamePacketBuilder builder) {
Animation animation = block.getAnimation();
builder.put(DataType.SHORT, DataOrder.LITTLE, DataTransformation.ADD, animation.getId());
builder.put(DataType.BYTE, animation.getDelay());
}
private void putTurnToPositionBlock(TurnToPositionBlock block, GamePacketBuilder builder) {
Position position = block.getPosition();
builder.put(DataType.SHORT, DataTransformation.ADD, position.getX() * 2 + 1);
builder.put(DataType.SHORT, DataOrder.LITTLE, DataTransformation.ADD, position.getY() * 2 + 1);
}
private void putForceChatBlock(ForceChatBlock block, GamePacketBuilder builder) {
builder.putString(block.getMessage());
}
/**
* Puts a terminate npc update.
* @Param bldr The builder.
*/
private void putRemoveNpcUpdate(GamePacketBuilder bldr) {
bldr.putBits(1, 1);
bldr.putBits(2, 3);
}
}