Merge pull request #128 from ryleykimmel/issue84

Fixes issue #84 (Appearance caching)
This commit is contained in:
Gary Tierney
2016-01-23 17:10:29 +00:00
4 changed files with 84 additions and 6 deletions
@@ -6,6 +6,7 @@ import java.util.Deque;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import org.apollo.game.message.impl.ConfigMessage;
import org.apollo.game.message.impl.IdAssignmentMessage;
@@ -19,6 +20,7 @@ import org.apollo.game.message.impl.UpdateRunEnergyMessage;
import org.apollo.game.model.Appearance;
import org.apollo.game.model.Position;
import org.apollo.game.model.World;
import org.apollo.game.model.WorldConstants;
import org.apollo.game.model.entity.attr.Attribute;
import org.apollo.game.model.entity.attr.AttributeDefinition;
import org.apollo.game.model.entity.attr.AttributeMap;
@@ -47,6 +49,7 @@ import org.apollo.game.model.skill.LevelUpSkillListener;
import org.apollo.game.model.skill.SynchronizationSkillListener;
import org.apollo.game.session.GameSession;
import org.apollo.game.sync.block.SynchronizationBlock;
import org.apollo.game.sync.block.SynchronizationBlockSet;
import org.apollo.net.message.Message;
import org.apollo.util.CollectionUtil;
import org.apollo.util.Point;
@@ -71,6 +74,15 @@ public final class Player extends Mob {
AttributeMap.define("run_energy", AttributeDefinition.forInt(100, AttributePersistence.PERSISTENT));
}
/**
* The current amount of appearance tickets.
*/
private static final AtomicInteger appearanceTicketCounter = new AtomicInteger(0);
/**
* This appearance tickets for this Player.
*/
private final int[] appearanceTickets = new int[WorldConstants.MAXIMUM_PLAYERS];
/**
* This player's bank.
@@ -207,6 +219,11 @@ public final class Player extends Mob {
*/
private int worldId = 1;
/**
* This Players appearance ticket.
*/
private int appearanceTicket = nextAppearanceTicket();
/**
* Creates the Player.
*
@@ -641,6 +658,36 @@ public final class Player extends Mob {
localObjects.forEach(object -> object.removeFrom(this));
}
/**
* Generates the next appearance ticket.
*
* @return The next available appearance ticket.
*/
private static int nextAppearanceTicket() {
if (appearanceTicketCounter.incrementAndGet() == 0) {
appearanceTicketCounter.set(1);
}
return appearanceTicketCounter.get();
}
/**
* Gets all of this Players appearance tickets.
*
* @return All of this Players appearance tickets.
*/
public int[] getAppearanceTickets() {
return appearanceTickets;
}
/**
* Gets this Players appearance ticket.
*
* @return This Players appearance ticket.
*/
public int getAppearanceTicket() {
return appearanceTicket;
}
/**
* Indicates whether the message filter is enabled.
*
@@ -735,7 +782,7 @@ public final class Player extends Mob {
* Sends the initial messages.
*/
public void sendInitialMessages() {
blockSet.add(SynchronizationBlock.createAppearanceBlock(this));
updateAppearance();
send(new IdAssignmentMessage(index, members));
sendMessage("Welcome to RuneScape.");
@@ -813,7 +860,7 @@ public final class Player extends Mob {
*/
public void setAppearance(Appearance appearance) {
this.appearance = appearance;
blockSet.add(SynchronizationBlock.createAppearanceBlock(this));
updateAppearance();
}
/**
@@ -1025,4 +1072,12 @@ public final class Player extends Mob {
skillSet.addListener(new LevelUpSkillListener(this));
}
/**
* Updates the appearance for this Player.
*/
public void updateAppearance() {
appearanceTicket = nextAppearanceTicket();
blockSet.add(SynchronizationBlock.createAppearanceBlock(this));
}
}
@@ -39,7 +39,7 @@ public final class AppearanceInventoryListener extends InventoryAdapter {
* Updates the player's appearance.
*/
private void update() {
player.getBlockSet().add(SynchronizationBlock.createAppearanceBlock(player));
player.updateAppearance();
}
}
@@ -32,7 +32,7 @@ public final class SynchronizationSkillListener extends SkillAdapter {
@Override
public void levelledUp(SkillSet set, int id, Skill skill) {
if (Skill.isCombatSkill(id)) {
player.getBlockSet().add(SynchronizationBlock.createAppearanceBlock(player));
player.updateAppearance();
}
}
@@ -53,6 +53,7 @@ public final class PlayerSynchronizationTask extends SynchronizationTask {
public void run() {
Position lastKnownRegion = player.getLastKnownRegion();
boolean regionChanged = player.hasRegionChanged();
int[] appearanceTickets = player.getAppearanceTickets();
SynchronizationBlockSet blockSet = player.getBlockSet();
@@ -101,12 +102,15 @@ public final class PlayerSynchronizationTask extends SynchronizationTask {
added++;
blockSet = other.getBlockSet();
if (!blockSet.contains(AppearanceBlock.class)) { // TODO check if client has cached appearance
int index = other.getIndex();
if (!blockSet.contains(AppearanceBlock.class) && !hasCachedAppearance(appearanceTickets, index - 1, other.getAppearanceTicket())) {
blockSet = blockSet.clone();
blockSet.add(SynchronizationBlock.createAppearanceBlock(other));
}
segments.add(new AddPlayerSegment(blockSet, other.getIndex(), local));
segments.add(new AddPlayerSegment(blockSet, index, local));
}
}
@@ -115,6 +119,25 @@ public final class PlayerSynchronizationTask extends SynchronizationTask {
player.send(message);
}
/**
* Tests whether or not the specified Player has a cached appearance within
* the specified appearance ticket array.
*
* @param appearanceTickets The appearance tickets.
* @param index The index of the Player.
* @param appearanceTicket The current appearance ticket for the Player.
* @return {@code true} if the specified Player has a cached appearance
* otherwise {@code false}.
*/
private boolean hasCachedAppearance(int[] appearanceTickets, int index, int appearanceTicket) {
if (appearanceTickets[index] != appearanceTicket) {
appearanceTickets[index] = appearanceTicket;
return false;
}
return true;
}
/**
* Returns whether or not the specified {@link Player} should be removed.
*