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.HashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import org.apollo.game.message.impl.ConfigMessage; import org.apollo.game.message.impl.ConfigMessage;
import org.apollo.game.message.impl.IdAssignmentMessage; 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.Appearance;
import org.apollo.game.model.Position; import org.apollo.game.model.Position;
import org.apollo.game.model.World; 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.Attribute;
import org.apollo.game.model.entity.attr.AttributeDefinition; import org.apollo.game.model.entity.attr.AttributeDefinition;
import org.apollo.game.model.entity.attr.AttributeMap; 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.model.skill.SynchronizationSkillListener;
import org.apollo.game.session.GameSession; import org.apollo.game.session.GameSession;
import org.apollo.game.sync.block.SynchronizationBlock; import org.apollo.game.sync.block.SynchronizationBlock;
import org.apollo.game.sync.block.SynchronizationBlockSet;
import org.apollo.net.message.Message; import org.apollo.net.message.Message;
import org.apollo.util.CollectionUtil; import org.apollo.util.CollectionUtil;
import org.apollo.util.Point; import org.apollo.util.Point;
@@ -71,6 +74,15 @@ public final class Player extends Mob {
AttributeMap.define("run_energy", AttributeDefinition.forInt(100, AttributePersistence.PERSISTENT)); 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. * This player's bank.
@@ -207,6 +219,11 @@ public final class Player extends Mob {
*/ */
private int worldId = 1; private int worldId = 1;
/**
* This Players appearance ticket.
*/
private int appearanceTicket = nextAppearanceTicket();
/** /**
* Creates the Player. * Creates the Player.
* *
@@ -641,6 +658,36 @@ public final class Player extends Mob {
localObjects.forEach(object -> object.removeFrom(this)); 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. * Indicates whether the message filter is enabled.
* *
@@ -735,7 +782,7 @@ public final class Player extends Mob {
* Sends the initial messages. * Sends the initial messages.
*/ */
public void sendInitialMessages() { public void sendInitialMessages() {
blockSet.add(SynchronizationBlock.createAppearanceBlock(this)); updateAppearance();
send(new IdAssignmentMessage(index, members)); send(new IdAssignmentMessage(index, members));
sendMessage("Welcome to RuneScape."); sendMessage("Welcome to RuneScape.");
@@ -813,7 +860,7 @@ public final class Player extends Mob {
*/ */
public void setAppearance(Appearance appearance) { public void setAppearance(Appearance appearance) {
this.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)); 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. * Updates the player's appearance.
*/ */
private void update() { private void update() {
player.getBlockSet().add(SynchronizationBlock.createAppearanceBlock(player)); player.updateAppearance();
} }
} }
@@ -32,7 +32,7 @@ public final class SynchronizationSkillListener extends SkillAdapter {
@Override @Override
public void levelledUp(SkillSet set, int id, Skill skill) { public void levelledUp(SkillSet set, int id, Skill skill) {
if (Skill.isCombatSkill(id)) { 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() { public void run() {
Position lastKnownRegion = player.getLastKnownRegion(); Position lastKnownRegion = player.getLastKnownRegion();
boolean regionChanged = player.hasRegionChanged(); boolean regionChanged = player.hasRegionChanged();
int[] appearanceTickets = player.getAppearanceTickets();
SynchronizationBlockSet blockSet = player.getBlockSet(); SynchronizationBlockSet blockSet = player.getBlockSet();
@@ -101,12 +102,15 @@ public final class PlayerSynchronizationTask extends SynchronizationTask {
added++; added++;
blockSet = other.getBlockSet(); 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 = blockSet.clone();
blockSet.add(SynchronizationBlock.createAppearanceBlock(other)); 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); 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. * Returns whether or not the specified {@link Player} should be removed.
* *