notesInverse = notes.inverse();
+
+ /**
+ * Gets the total number of item definitions.
+ *
+ * @return The count.
+ */
+ public static int count() {
+ return definitions.length;
+ }
+
+ /**
+ * Gets the array of item definitions.
+ *
+ * @return The definitions.
+ */
+ public static ItemDefinition[] getDefinitions() {
+ return definitions;
+ }
+
+ /**
+ * Initialises the class with the specified set of definitions.
+ *
+ * @param definitions The definitions.
+ * @throws RuntimeException If there is an id mismatch.
+ */
+ public static void init(ItemDefinition[] definitions) {
+ ItemDefinition.definitions = definitions;
+ for (int id = 0; id < definitions.length; id++) {
+ ItemDefinition def = definitions[id];
+ if (def.getId() != id) {
+ throw new RuntimeException("Item definition id mismatch.");
+ }
+ if (def.isNote()) {
+ def.toNote();
+ notes.put(def.getNoteInfoId(), def.getId());
+ }
+ }
+ }
+
+ /**
+ * Converts an item id to a noted id.
+ *
+ * @param id The item id.
+ * @return The noted id.
+ */
+ public static int itemToNote(int id) {
+ Integer entry = notes.get(id);
+ if (entry == null) {
+ return id;
+ }
+ return entry;
+ }
+
+ /**
+ * Gets the item definition for the specified id.
+ *
+ * @param id The id.
+ * @return The definition.
+ * @throws IndexOutOfBoundsException If the id is out of bounds.
+ */
+ public static ItemDefinition lookup(int id) {
+ Preconditions.checkElementIndex(id, definitions.length, "Id out of bounds.");
+ return definitions[id];
+ }
+
+ /**
+ * Converts a noted id to the normal item id.
+ *
+ * @param id The note id.
+ * @return The item id.
+ */
+ public static int noteToItem(int id) {
+ Integer entry = notesInverse.get(id);
+ if (entry == null) {
+ return id;
+ }
+ return entry;
+ }
+
+ /**
+ * The description of the item.
+ */
+ private String description;
+
+ /**
+ * The ground actions array.
+ */
+ private final String[] groundActions = new String[5];
+
+ /**
+ * The item's id.
+ */
+ private final int id;
+
+ /**
+ * The inventory actions array.
+ */
+ private final String[] inventoryActions = new String[5];
+
+ /**
+ * A flag indicating if this item is members only.
+ */
+ private boolean members = false;
+
+ /**
+ * The name of the item.
+ */
+ private String name;
+
+ /**
+ * The id of the item to copy note graphics from.
+ */
+ private int noteGraphicId = -1;
+
+ /**
+ * The id of the item to copy note info from.
+ */
+ private int noteInfoId = -1;
+
+ /**
+ * A flag indicating if this item is stackable.
+ */
+ private boolean stackable = false;
+
+ /**
+ * This item's team.
+ */
+ private int team;
+
+ /**
+ * The item's floor value.
+ */
+ private int value = 1;
+
+ /**
+ * Creates an item definition with the default values.
+ *
+ * @param id The item's id.
+ */
+ public ItemDefinition(int id) {
+ this.id = id;
+ }
+
+ /**
+ * Gets the description of this item.
+ *
+ * @return The item's description.
+ */
+ public String getDescription() {
+ return description;
+ }
+
+ /**
+ * Gets a ground action.
+ *
+ * @param id The id.
+ * @return The action.
+ * @throws IndexOutOfBoundsException If the id is out of bounds.
+ */
+ public String getGroundAction(int id) {
+ Preconditions.checkElementIndex(id, groundActions.length, "Ground action id is out of bounds.");
+ return groundActions[id];
+ }
+
+ /**
+ * Gets this item's id.
+ *
+ * @return The id.
+ */
+ public int getId() {
+ return id;
+ }
+
+ /**
+ * Gets an inventory action.
+ *
+ * @param id The id.
+ * @return The action.
+ * @throws IndexOutOfBoundsException If the id is out of bounds.
+ */
+ public String getInventoryAction(int id) {
+ Preconditions.checkElementIndex(id, inventoryActions.length, "Inventory action id is out of bounds.");
+ return inventoryActions[id];
+ }
+
+ /**
+ * Gets this item's name.
+ *
+ * @return The name.
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Gets this item's note graphic id.
+ *
+ * @return The note graphic id.
+ */
+ public int getNoteGraphicId() {
+ return noteGraphicId;
+ }
+
+ /**
+ * Gets this item's note info id.
+ *
+ * @return The note info id.
+ */
+ public int getNoteInfoId() {
+ return noteInfoId;
+ }
+
+ /**
+ * Gets this item's team.
+ *
+ * @return The team.
+ */
+ public int getTeam() {
+ return team;
+ }
+
+ /**
+ * Gets this item's value.
+ *
+ * @return The value.
+ */
+ public int getValue() {
+ return value;
+ }
+
+ /**
+ * Checks if this item is members only.
+ *
+ * @return {@code true} if so, {@code false} if not.
+ */
+ public boolean isMembersOnly() {
+ return members;
+ }
+
+ /**
+ * Checks if this item is a note.
+ *
+ * @return {@code true} if so, {@code false} otherwise.
+ */
+ public boolean isNote() {
+ return noteGraphicId != -1 && noteInfoId != -1;
+ }
+
+ /**
+ * Checks if the item specified by this definition is stackable.
+ *
+ * @return {@code true} if so, {@code false} if not.
+ */
+ public boolean isStackable() {
+ return stackable;
+ }
+
+ /**
+ * Sets this item's description.
+ *
+ * @param description The description.
+ */
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ /**
+ * Sets a ground action.
+ *
+ * @param id The id.
+ * @param action The action.
+ * @throws IndexOutOfBoundsException If the id is out of bounds.
+ */
+ public void setGroundAction(int id, String action) {
+ Preconditions.checkElementIndex(id, groundActions.length, "Ground action id is out of bounds.");
+ groundActions[id] = action;
+ }
+
+ /**
+ * Sets an inventory action.
+ *
+ * @param id The id.
+ * @param action The action.
+ * @throws IndexOutOfBoundsException If the id is out of bounds.
+ */
+ public void setInventoryAction(int id, String action) {
+ Preconditions.checkElementIndex(id, inventoryActions.length, "Inventory action id is out of bounds.");
+ inventoryActions[id] = action;
+ }
+
+ /**
+ * Sets this item's members only flag.
+ *
+ * @param members The flag.
+ */
+ public void setMembersOnly(boolean members) {
+ this.members = members;
+ }
+
+ /**
+ * Sets this item's name.
+ *
+ * @param name The name.
+ */
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ /**
+ * Sets this item's note graphic id.
+ *
+ * @param noteGraphicId The note graphic id.
+ */
+ public void setNoteGraphicId(int noteGraphicId) {
+ this.noteGraphicId = noteGraphicId;
+ }
+
+ /**
+ * Sets this item's note info id.
+ *
+ * @param noteInfoId The note info id.
+ */
+ public void setNoteInfoId(int noteInfoId) {
+ this.noteInfoId = noteInfoId;
+ }
+
+ /**
+ * Sets this item's stackable flag.
+ *
+ * @param stackable The stackable flag.
+ */
+ public void setStackable(boolean stackable) {
+ this.stackable = stackable;
+ }
+
+ /**
+ * Sets this item's team.
+ *
+ * @param team The team.
+ */
+ public void setTeam(int team) {
+ this.team = team;
+ }
+
+ /**
+ * sets this item's value.
+ *
+ * @param value The value.
+ */
+ public void setValue(int value) {
+ this.value = value;
+ }
+
+ /**
+ * Converts this item to a note, if possible.
+ *
+ * @throws IllegalStateException If {@link ItemDefinition#isNote()} returns {@code false}.
+ */
+ public void toNote() {
+ if (isNote()) {
+ if (description != null && description.startsWith("Swap this note at any bank for ")) {
+ return; // already converted.
+ }
+
+ ItemDefinition infoDef = lookup(noteInfoId);
+ name = infoDef.name;
+ members = infoDef.members;
+
+ String prefix = "a";
+ char firstChar = name == null ? 'n' : name.charAt(0);
+
+ if (firstChar == 'A' || firstChar == 'E' || firstChar == 'I' || firstChar == 'O' || firstChar == 'U') {
+ prefix = "an";
+ }
+
+ description = "Swap this note at any bank for " + prefix + " " + name + ".";
+ value = infoDef.value;
+ stackable = true;
+ } else {
+ throw new IllegalStateException("Item cannot be noted.");
+ }
+ }
+
+}
diff --git a/2006Scape Server/src/main/java/org/apollo/cache/def/NpcDefinition.java b/2006Scape Server/src/main/java/org/apollo/cache/def/NpcDefinition.java
new file mode 100644
index 00000000..0e81396d
--- /dev/null
+++ b/2006Scape Server/src/main/java/org/apollo/cache/def/NpcDefinition.java
@@ -0,0 +1,365 @@
+package org.apollo.cache.def;
+
+import com.google.common.base.Preconditions;
+
+/**
+ * Represents a type of Npc.
+ *
+ * @author Chris Fletcher
+ */
+public final class NpcDefinition {
+
+ /**
+ * The npc definitions.
+ */
+ private static NpcDefinition[] definitions;
+
+ /**
+ * Gets the total number of npc definitions.
+ *
+ * @return The count.
+ */
+ public static int count() {
+ return definitions.length;
+ }
+
+ /**
+ * Gets the array of npc definitions.
+ *
+ * @return The definitions.
+ */
+ public static NpcDefinition[] getDefinitions() {
+ return definitions;
+ }
+
+ /**
+ * Initialises the class with the specified set of definitions.
+ *
+ * @param definitions The definitions.
+ * @throws IllegalStateException If there is an id mismatch.
+ */
+ public static void init(NpcDefinition[] definitions) {
+ NpcDefinition.definitions = definitions;
+ for (int id = 0; id < definitions.length; id++) {
+ NpcDefinition def = definitions[id];
+ if (def.getId() != id) {
+ throw new IllegalStateException("Npc definition id mismatch.");
+ }
+ }
+ }
+
+ /**
+ * Gets the npc definition for the specified id.
+ *
+ * @param id The id.
+ * @return The definition.
+ * @throws IndexOutOfBoundsException If the id is out of bounds.
+ */
+ public static NpcDefinition lookup(int id) {
+ Preconditions.checkElementIndex(id, definitions.length, "Id out of bounds.");
+ return definitions[id];
+ }
+
+ /**
+ * The combat level of the npc.
+ */
+ private int combatLevel = -1;
+
+ /**
+ * The description of the npc.
+ */
+ private String description;
+
+ /**
+ * The npc id.
+ */
+ private final int id;
+
+ /**
+ * An array of interaction options.
+ */
+ private final String[] interactions = new String[5];
+
+ /**
+ * The name of the npc.
+ */
+ private String name;
+
+ /**
+ * The npc's size, in tiles.
+ */
+ private int size = 1;
+
+ /**
+ * The various animation ids.
+ */
+ private int standAnim = -1, walkAnim = -1, walkBackAnim = -1, walkLeftAnim = -1, walkRightAnim = -1;
+
+ /**
+ * Creates a new npc definition.
+ *
+ * @param id The npc id.
+ */
+ public NpcDefinition(int id) {
+ this.id = id;
+ }
+
+ /**
+ * Gets the npc's combat level.
+ *
+ * @return The combat level, or -1 if it doesn't have one.
+ */
+ public int getCombatLevel() {
+ return combatLevel;
+ }
+
+ /**
+ * Gets the description of the npc.
+ *
+ * @return The description.
+ */
+ public String getDescription() {
+ return description;
+ }
+
+ /**
+ * Gets the npc id.
+ *
+ * @return The npc id.
+ */
+ public int getId() {
+ return id;
+ }
+
+ /**
+ * Gets an interaction option.
+ *
+ * @param slot The slot of the option.
+ * @return The option, or {@code null} if there isn't any at the specified slot.
+ * @throws IndexOutOfBoundsException If the slot is out of bounds.
+ */
+ public String getInteraction(int slot) {
+ Preconditions.checkElementIndex(slot, interactions.length, "Npc interaction id is out of bounds.");
+ return interactions[slot];
+ }
+
+ /**
+ * Gets the array of interaction options.
+ *
+ * @return The interaction options.
+ */
+ public String[] getInteractions() {
+ return interactions;
+ }
+
+ /**
+ * Gets the name of the npc.
+ *
+ * @return The name of the npc.
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Gets the npc's size, in tiles.
+ *
+ * @return The size.
+ */
+ public int getSize() {
+ return size;
+ }
+
+ /**
+ * Gets the id of the npc's standing animation.
+ *
+ * @return The stand animation id, or -1 if it doesn't have one.
+ */
+ public int getStandAnimation() {
+ return standAnim;
+ }
+
+ /**
+ * Gets the walking animation of the npc.
+ *
+ * @return The walking animation.
+ */
+ public int getWalkAnimation() {
+ return walkAnim;
+ }
+
+ /**
+ * Gets the walk-back animation of the npc.
+ *
+ * @return The walk-back animation.
+ */
+ public int getWalkBackAnimation() {
+ return walkBackAnim;
+ }
+
+ /**
+ * Gets the walk-left animation of the npc.
+ *
+ * @return The walk-left animation.
+ */
+ public int getWalkLeftAnimation() {
+ return walkLeftAnim;
+ }
+
+ /**
+ * Gets the walk-right animation of the npc.
+ *
+ * @return The walk-right animation.
+ */
+ public int getWalkRightAnimation() {
+ return walkRightAnim;
+ }
+
+ /**
+ * Checks if the npc has a combat level.
+ *
+ * @return {@code true} if so, {@code false} if not.
+ */
+ public boolean hasCombatLevel() {
+ return combatLevel != -1;
+ }
+
+ /**
+ * Checks if there is an interaction option present.
+ *
+ * @param slot The slot to check.
+ * @return {@code true} if so, {@code false} if not.
+ * @throws IndexOutOfBoundsException If the slot is out of bounds.
+ */
+ public boolean hasInteraction(int slot) {
+ Preconditions.checkElementIndex(slot, interactions.length, "Npc interaction id is out of bounds.");
+ return interactions[slot] != null;
+ }
+
+ /**
+ * Checks if the npc has a standing animation id.
+ *
+ * @return {@code true} if so, {@code false} if not.
+ */
+ public boolean hasStandAnimation() {
+ return standAnim != -1;
+ }
+
+ /**
+ * Checks if the npc has a walking animation.
+ *
+ * @return {@code true} if so, {@code false} if not.
+ */
+ public boolean hasWalkAnimation() {
+ return walkAnim != -1;
+ }
+
+ /**
+ * Checks if the npc has a walk-back animation.
+ *
+ * @return {@code true} if so, {@code false} if not.
+ */
+ public boolean hasWalkBackAnimation() {
+ return walkBackAnim != -1;
+ }
+
+ /**
+ * Checks if the npc has a walk-left animation.
+ *
+ * @return {@code true} if so, {@code false} if not.
+ */
+ public boolean hasWalkLeftAnimation() {
+ return walkLeftAnim != -1;
+ }
+
+ /**
+ * Checks if the npc has a walk-right animation.
+ *
+ * @return {@code true} if so, {@code false} if not.
+ */
+ public boolean hasWalkRightAnimation() {
+ return walkRightAnim != -1;
+ }
+
+ /**
+ * Sets the npc's combat level.
+ *
+ * @param combatLevel The combat level.
+ */
+ public void setCombatLevel(int combatLevel) {
+ this.combatLevel = combatLevel;
+ }
+
+ /**
+ * Sets the description of the npc.
+ *
+ * @param description The description.
+ */
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ /**
+ * Sets an interaction option.
+ *
+ * @param slot The slot of the option.
+ * @param interaction The interaction options.
+ * @throws IndexOutOfBoundsException If the slot is out of bounds.
+ */
+ public void setInteraction(int slot, String interaction) {
+ Preconditions.checkElementIndex(slot, interactions.length, "Npc interaction id is out of bounds.");
+ interactions[slot] = interaction;
+ }
+
+ /**
+ * Sets the name of the npc.
+ *
+ * @param name The name.
+ */
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ /**
+ * Sets the size of the npc, in tiles.
+ *
+ * @param size The size.
+ */
+ public void setSize(int size) {
+ this.size = size;
+ }
+
+ /**
+ * Sets the id of the npc's standing animation.
+ *
+ * @param standAnim The stand animation id.
+ */
+ public void setStandAnimation(int standAnim) {
+ this.standAnim = standAnim;
+ }
+
+ /**
+ * Sets the walking animation of the npc.
+ *
+ * @param walkAnim The walking animation.
+ */
+ public void setWalkAnimation(int walkAnim) {
+ this.walkAnim = walkAnim;
+ }
+
+ /**
+ * Sets the various walking animations of the npc.
+ *
+ * @param walkAnim The walking animation.
+ * @param walkBackAnim The walk-back animation.
+ * @param walkLeftAnim The walk-left animation.
+ * @param walkRightAnim The walk-right animation.
+ */
+ public void setWalkAnimations(int walkAnim, int walkBackAnim, int walkLeftAnim, int walkRightAnim) {
+ this.walkAnim = walkAnim;
+ this.walkBackAnim = walkBackAnim;
+ this.walkLeftAnim = walkLeftAnim;
+ this.walkRightAnim = walkRightAnim;
+ }
+
+}
\ No newline at end of file
diff --git a/2006Scape Server/src/main/java/org/apollo/cache/def/ObjectDefinition.java b/2006Scape Server/src/main/java/org/apollo/cache/def/ObjectDefinition.java
new file mode 100644
index 00000000..8f054307
--- /dev/null
+++ b/2006Scape Server/src/main/java/org/apollo/cache/def/ObjectDefinition.java
@@ -0,0 +1,293 @@
+package org.apollo.cache.def;
+
+import com.google.common.base.Preconditions;
+
+/**
+ * Represents a type of GameObject.
+ *
+ * @author Major
+ */
+public final class ObjectDefinition {
+
+ /**
+ * The array of game object definitions.
+ */
+ private static ObjectDefinition[] definitions;
+
+ /**
+ * Gets the total number of object definitions.
+ *
+ * @return The count.
+ */
+ public static int count() {
+ return definitions.length;
+ }
+
+ /**
+ * Gets the array of object definitions.
+ *
+ * @return The definitions.
+ */
+ public static ObjectDefinition[] getDefinitions() {
+ return definitions;
+ }
+
+ /**
+ * Initialises the object definitions.
+ *
+ * @param definitions The decoded definitions.
+ * @throws RuntimeException If there is an id mismatch.
+ */
+ public static void init(ObjectDefinition[] definitions) {
+ ObjectDefinition.definitions = definitions;
+ for (int id = 0; id < definitions.length; id++) {
+ ObjectDefinition def = definitions[id];
+ if (def.getId() != id) {
+ throw new RuntimeException("Item definition id mismatch.");
+ }
+ }
+ }
+
+ /**
+ * Gets the object definition for the specified id.
+ *
+ * @param id The id of the object.
+ * @return The definition.
+ * @throws IndexOutOfBoundsException If the id is out of bounds.
+ */
+ public static ObjectDefinition lookup(int id) {
+ Preconditions.checkElementIndex(id, definitions.length, "Id out of bounds.");
+ return definitions[id];
+ }
+
+ /**
+ * The object's description.
+ */
+ private String description;
+
+ /**
+ * The object's id.
+ */
+ private final int id;
+
+ /**
+ * Denotes whether this object is impenetrable or not.
+ */
+ private boolean impenetrable = true;
+
+ /**
+ * Denotes whether this object has actions associated with it or not.
+ */
+ private boolean interactive;
+
+ /**
+ * Denotes whether or not this object obstructs the ground.
+ */
+ private boolean obstructive;
+
+ /**
+ * This object's length.
+ */
+ private int length = 1;
+
+ /**
+ * The object's menu actions.
+ */
+ private String[] menuActions;
+
+ /**
+ * The object's name.
+ */
+ private String name;
+
+ /**
+ * Denotes whether the object can be walked over or not.
+ */
+ private boolean solid = true;
+
+ /**
+ * This object's width.
+ */
+ private int width = 1;
+
+ /**
+ * Creates a new object definition.
+ *
+ * @param id The id of the object.
+ */
+ public ObjectDefinition(int id) {
+ this.id = id;
+ }
+
+ /**
+ * Gets the description of this object.
+ *
+ * @return The description.
+ */
+ public String getDescription() {
+ return description;
+ }
+
+ /**
+ * Gets the id of this object.
+ *
+ * @return The id.
+ */
+ public int getId() {
+ return id;
+ }
+
+ /**
+ * Gets the length of this object.
+ *
+ * @return The length.
+ */
+ public int getLength() {
+ return length;
+ }
+
+ /**
+ * Gets the menu actions of this object.
+ *
+ * @return The menu actions.
+ */
+ public String[] getMenuActions() {
+ return menuActions;
+ }
+
+ /**
+ * Gets the name of this object.
+ *
+ * @return The name.
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Gets the with of this object.
+ *
+ * @return The width.
+ */
+ public int getWidth() {
+ return width;
+ }
+
+ /**
+ * Indicates the impenetrability of this object.
+ *
+ * @return {@code true} if this object is impenetrable, otherwise {@code false}.
+ */
+ public boolean isImpenetrable() {
+ return impenetrable;
+ }
+
+ /**
+ * Indicates the interactivity of this object.
+ *
+ * @return {@code true} if the object is interactive, otherwise {@code false}.
+ */
+ public boolean isInteractive() {
+ return interactive;
+ }
+
+ /**
+ * Indicates whether or not this object obstructs the ground.
+ *
+ * @return {@code true} if the object obstructs the ground otherwise {@code false}.
+ */
+ public boolean isObstructive() {
+ return obstructive;
+ }
+
+ /**
+ * Indicates the solidity of this object.
+ *
+ * @return {@code true} if this object is solid, otherwise {@code false}.
+ */
+ public boolean isSolid() {
+ return solid;
+ }
+
+ /**
+ * Sets the description of this object.
+ *
+ * @param description The description.
+ */
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ /**
+ * Sets the impenetrability of this object.
+ *
+ * @param impenetrable The impenetrability.
+ */
+ public void setImpenetrable(boolean impenetrable) {
+ this.impenetrable = impenetrable;
+ }
+
+ /**
+ * Sets the interactivity of this object.
+ *
+ * @param interactive The interactivity.
+ */
+ public void setInteractive(boolean interactive) {
+ this.interactive = interactive;
+ }
+
+ /**
+ * Sets the length of this object.
+ *
+ * @param length The length.
+ */
+ public void setLength(int length) {
+ this.length = length;
+ }
+
+ /**
+ * Sets the menu actions of this object.
+ *
+ * @param menuActions The menu actions.
+ */
+ public void setMenuActions(String[] menuActions) {
+ this.menuActions = menuActions;
+ }
+
+ /**
+ * Sets the name of this object.
+ *
+ * @param name The name.
+ */
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ /**
+ * Sets the solidity of this object.
+ *
+ * @param solid The solidity.
+ */
+ public void setSolid(boolean solid) {
+ this.solid = solid;
+ }
+
+ /**
+ * Sets the width of this object.
+ *
+ * @param width The width.
+ */
+ public void setWidth(int width) {
+ this.width = width;
+ }
+
+ /**
+ * Sets whether or not this object is obstructive to the ground.
+ *
+ * @param obstructive Whether or not this object obstructs the ground.
+ */
+ public void setObstructive(boolean obstructive) {
+ this.obstructive = obstructive;
+ }
+
+}
\ No newline at end of file
diff --git a/2006Scape Server/src/main/java/org/apollo/cache/def/package-info.java b/2006Scape Server/src/main/java/org/apollo/cache/def/package-info.java
new file mode 100644
index 00000000..a0298a85
--- /dev/null
+++ b/2006Scape Server/src/main/java/org/apollo/cache/def/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * Contains definition classes which contain information about types of items, NPCs, etc.
+ */
+package org.apollo.cache.def;
\ No newline at end of file
diff --git a/2006Scape Server/src/main/java/org/apollo/cache/map/MapConstants.java b/2006Scape Server/src/main/java/org/apollo/cache/map/MapConstants.java
new file mode 100644
index 00000000..63492978
--- /dev/null
+++ b/2006Scape Server/src/main/java/org/apollo/cache/map/MapConstants.java
@@ -0,0 +1,62 @@
+package org.apollo.cache.map;
+
+/**
+ * Contains {@link MapFile}-related constants.
+ *
+ * @author Major
+ */
+public final class MapConstants {
+
+ /**
+ * The index containing the map files.
+ */
+ public static final int MAP_INDEX = 4;
+
+ /**
+ * The width (and length) of a {@link MapFile} in {@link Tile}s.
+ */
+ public static final int MAP_WIDTH = 64;
+
+ /**
+ * The amount of planes in a MapFile.
+ */
+ public static final int MAP_PLANES = 4;
+
+ /**
+ * The multiplicand for height values.
+ */
+ static final int HEIGHT_MULTIPLICAND = 8;
+
+ /**
+ * The lowest type value that will result in the decoding of a Tile being continued.
+ */
+ static final int LOWEST_CONTINUED_TYPE = 2;
+
+ /**
+ * The minimum type that specifies the Tile attributes.
+ */
+ static final int MINIMUM_ATTRIBUTES_TYPE = 81;
+
+ /**
+ * The minimum type that specifies the Tile underlay id.
+ */
+ static final int MINIMUM_OVERLAY_TYPE = 49;
+
+ /**
+ * The amount of possible overlay orientations.
+ */
+ static final int ORIENTATION_COUNT = 4;
+
+ /**
+ * The height difference between two planes.
+ */
+ static final int PLANE_HEIGHT_DIFFERENCE = 240;
+
+ /**
+ * Sole private constructor to prevent instantiation.
+ */
+ private MapConstants() {
+
+ }
+
+}
\ No newline at end of file
diff --git a/2006Scape Server/src/main/java/org/apollo/cache/map/MapFile.java b/2006Scape Server/src/main/java/org/apollo/cache/map/MapFile.java
new file mode 100644
index 00000000..b1e6d646
--- /dev/null
+++ b/2006Scape Server/src/main/java/org/apollo/cache/map/MapFile.java
@@ -0,0 +1,48 @@
+package org.apollo.cache.map;
+
+import com.google.common.base.Preconditions;
+
+/**
+ * A 3-dimensional 64x64 area of the map.
+ *
+ * @author Major
+ */
+public final class MapFile {
+
+ /**
+ * The array of MapPlanes.
+ */
+ private final MapPlane[] planes;
+
+ /**
+ * Creates the MapFile.
+ *
+ * @param planes The {@link MapPlane}s.
+ */
+ public MapFile(MapPlane[] planes) {
+ this.planes = planes.clone();
+ }
+
+ /**
+ * Gets the {@link MapPlane} with the specified level.
+ *
+ * @param plane The plane.
+ * @return The MapPlane.
+ * @throws ArrayIndexOutOfBoundsException If {@code plane} is out of bounds.
+ */
+ public MapPlane getPlane(int plane) {
+ int length = planes.length;
+ Preconditions.checkElementIndex(plane, length, "Plane index out of bounds, must be [0, " + length + ").");
+ return planes[plane];
+ }
+
+ /**
+ * Gets all of the {@link MapPlane}s in this MapFile.
+ *
+ * @return The MapPlanes.
+ */
+ public MapPlane[] getPlanes() {
+ return planes.clone();
+ }
+
+}
\ No newline at end of file
diff --git a/2006Scape Server/src/main/java/org/apollo/cache/map/MapFileDecoder.java b/2006Scape Server/src/main/java/org/apollo/cache/map/MapFileDecoder.java
new file mode 100644
index 00000000..e85ae5e2
--- /dev/null
+++ b/2006Scape Server/src/main/java/org/apollo/cache/map/MapFileDecoder.java
@@ -0,0 +1,123 @@
+package org.apollo.cache.map;
+
+import org.apollo.cache.IndexedFileSystem;
+import org.apollo.util.CompressionUtil;
+
+import java.nio.ByteBuffer;
+import java.io.IOException;
+
+/**
+ * A decoder for the terrain data stored in {@link MapFile}s.
+ *
+ * @author Major
+ */
+public class MapFileDecoder {
+ /**
+ * Creates a MapFileDecoder for the specified map file.
+ *
+ * @param fs The {@link IndexedFileSystem} to get the file from.
+ * @param index The {@link MapIndex} to get the file index from.
+ * @return The MapFileDecoder.
+ * @throws IOException If there is an error reading or decompressing the file.
+ */
+ public static MapFileDecoder create(IndexedFileSystem fs, MapIndex index) throws IOException {
+ ByteBuffer compressed = fs.getFile(MapConstants.MAP_INDEX, index.getMapFile());
+ ByteBuffer decompressed = ByteBuffer.wrap(CompressionUtil.degzip(compressed));
+
+ return new MapFileDecoder(decompressed);
+ }
+
+ /**
+ * The DataBuffer containing the MapFile data.
+ */
+ private final ByteBuffer buffer;
+
+ /**
+ * Creates the MapIndexDecoder.
+ *
+ * This constructor expects the {@link ByteBuffer} to not be compressed.
+ *
+ * @param buffer The DataBuffer containing the MapFile data.
+ */
+ public MapFileDecoder(ByteBuffer buffer) {
+ this.buffer = buffer.asReadOnlyBuffer();
+ }
+
+ /**
+ * Decodes the data into a {@link MapFile}.
+ *
+ * @return The MapFile.
+ */
+ public MapFile decode() {
+ MapPlane[] planes = new MapPlane[MapConstants.MAP_PLANES];
+
+ for (int level = 0; level < MapConstants.MAP_PLANES; level++) {
+ planes[level] = decodePlane(planes, level);
+ }
+
+ return new MapFile(planes);
+ }
+
+ /**
+ * Decodes a {@link MapPlane} with the specified level.
+ *
+ * @param planes The previously-decoded {@link MapPlane}s, for calculating the height of the tiles.
+ * @param level The level.
+ * @return The MapPlane.
+ */
+ private MapPlane decodePlane(MapPlane[] planes, int level) {
+ Tile[][] tiles = new Tile[MapConstants.MAP_WIDTH][MapConstants.MAP_WIDTH];
+
+ for (int x = 0; x < MapConstants.MAP_WIDTH; x++) {
+ for (int z = 0; z < MapConstants.MAP_WIDTH; z++) {
+ tiles[x][z] = decodeTile(planes, level, x, z);
+ }
+ }
+
+ return new MapPlane(level, tiles);
+ }
+
+ /**
+ * Decodes the data into a {@link Tile}.
+ *
+ * @param planes The previously-decoded {@link MapPlane}s, for calculating the height of the Tile.
+ * @param level The level the Tile is on.
+ * @param x The x coordinate of the Tile.
+ * @param z The z coordinate of the Tile.
+ * @return The MapFile.
+ */
+ private Tile decodeTile(MapPlane[] planes, int level, int x, int z) {
+ Tile.Builder builder = Tile.builder(x, z, level);
+
+ int type;
+ do {
+ type = buffer.get() & 0xFF;
+
+ if (type == 0) {
+ if (level == 0) {
+ builder.setHeight(TileUtils.calculateHeight(x, z));
+ } else {
+ Tile below = planes[level - 1].getTile(x, z);
+ builder.setHeight(below.getHeight() + MapConstants.PLANE_HEIGHT_DIFFERENCE);
+ }
+ } else if (type == 1) {
+ int height = buffer.get();
+ int below = (level == 0) ? 0 : planes[level - 1].getTile(x, z).getHeight();
+
+ builder.setHeight((height == 1 ? 0 : height) * MapConstants.HEIGHT_MULTIPLICAND + below);
+ } else if (type <= MapConstants.MINIMUM_OVERLAY_TYPE) {
+ builder.setOverlay(buffer.get());
+ builder.setOverlayType((type - MapConstants.LOWEST_CONTINUED_TYPE)
+ / MapConstants.ORIENTATION_COUNT);
+ builder.setOverlayOrientation(type - MapConstants.LOWEST_CONTINUED_TYPE
+ % MapConstants.ORIENTATION_COUNT);
+ } else if (type <= MapConstants.MINIMUM_ATTRIBUTES_TYPE) {
+ builder.setAttributes(type - MapConstants.MINIMUM_OVERLAY_TYPE);
+ } else {
+ builder.setUnderlay(type - MapConstants.MINIMUM_ATTRIBUTES_TYPE);
+ }
+ } while (type >= MapConstants.LOWEST_CONTINUED_TYPE);
+
+ return builder.build();
+ }
+}
diff --git a/2006Scape Server/src/main/java/org/apollo/cache/map/MapIndex.java b/2006Scape Server/src/main/java/org/apollo/cache/map/MapIndex.java
new file mode 100644
index 00000000..9b707c85
--- /dev/null
+++ b/2006Scape Server/src/main/java/org/apollo/cache/map/MapIndex.java
@@ -0,0 +1,125 @@
+package org.apollo.cache.map;
+
+import org.apollo.cache.def.ItemDefinition;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * A definition for a map.
+ */
+public final class MapIndex {
+
+ /**
+ * Indicates whether or not this map is members-only.
+ */
+ private final boolean members;
+
+ /**
+ * The object file id.
+ */
+ private final int objects;
+
+ /**
+ * The packed coordinates.
+ */
+ private final int packedCoordinates;
+
+ /**
+ * The terrain file id.
+ */
+ private final int terrain;
+
+ /**
+ * A mapping of region ids to {@link MapIndex}es.
+ */
+ private static Map indices;
+
+ /**
+ * Initialises the class with the specified set of indices.
+ */
+ public static void init(Map indices) {
+ MapIndex.indices = Collections.unmodifiableMap(indices);
+ }
+
+ /**
+ * Gets the {@code Map} of {@link MapIndex} instances.
+ *
+ * @return The map of {@link MapIndex} instances.
+ */
+ public static Map getIndices() {
+ return indices;
+ }
+
+ /**
+ * Creates the {@link MapIndex}.
+ *
+ * @param packedCoordinates The packed coordinates.
+ * @param terrain The terrain file id.
+ * @param objects The object file id.
+ * @param members Indicates whether or not this map is members-only.
+ */
+ public MapIndex(int packedCoordinates, int terrain, int objects, boolean members) {
+ this.packedCoordinates = packedCoordinates;
+ this.terrain = terrain;
+ this.objects = objects;
+ this.members = members;
+ }
+
+ /**
+ * Gets the id of the file containing the object data.
+ *
+ * @return The file id.
+ */
+ public int getObjectFile() {
+ return objects;
+ }
+
+ /**
+ * Gets the packed coordinates.
+ *
+ * @return The packed coordinates.
+ */
+ public int getPackedCoordinates() {
+ return packedCoordinates;
+ }
+
+ /**
+ * Gets the id of the file containing the terrain data.
+ *
+ * @return The file id.
+ */
+ public int getMapFile() {
+ return terrain;
+ }
+
+ /**
+ * Gets the X coordinate of this map.
+ *
+ * @return The X coordinate of this map.
+ */
+ public int getX() {
+ return (packedCoordinates >> 8 & 0xFF) * MapConstants.MAP_WIDTH;
+ }
+
+ /**
+ * Gets the Y coordinate of this map.
+ *
+ * @return The y coordinate of this map.
+ */
+ public int getY() {
+ return (packedCoordinates & 0xFF) * MapConstants.MAP_WIDTH;
+
+ }
+
+ /**
+ * Returns whether or not this MapIndex is for a members-only area of the world.
+ *
+ * @return {@code true} if this MapIndex is for a members-only area, {@code false} if not.
+ */
+ public boolean isMembersOnly() {
+ return members;
+ }
+
+}
diff --git a/2006Scape Server/src/main/java/org/apollo/cache/map/MapIndexDecoder.java b/2006Scape Server/src/main/java/org/apollo/cache/map/MapIndexDecoder.java
new file mode 100644
index 00000000..7bca2add
--- /dev/null
+++ b/2006Scape Server/src/main/java/org/apollo/cache/map/MapIndexDecoder.java
@@ -0,0 +1,70 @@
+package org.apollo.cache.map;
+
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.nio.ByteBuffer;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apollo.cache.IndexedFileSystem;
+import org.apollo.cache.archive.Archive;
+import org.apollo.cache.archive.ArchiveEntry;
+import org.apollo.cache.map.MapIndex;
+
+/**
+ * Decodes {@link MapIndex}s from the {@link IndexedFileSystem}.
+ *
+ * @author Ryley
+ * @author Major
+ */
+public final class MapIndexDecoder implements Runnable {
+
+ /**
+ * The file id of the versions archive.
+ */
+ private static final int VERSIONS_ARCHIVE_FILE_ID = 5;
+
+ /**
+ * The IndexedFileSystem.
+ */
+ private final IndexedFileSystem fs;
+
+ public MapIndexDecoder(IndexedFileSystem fs) {
+ this.fs = fs;
+ }
+
+ /**
+ * Decodes {@link MapIndex}s from the specified {@link IndexedFileSystem}.
+ *
+ * @return A {@link Map} of packed coordinates to their MapDefinitions.
+ * @throws IOException If there is an error reading or decoding the Archive.
+ */
+ public Map decode() throws IOException {
+ Archive archive = fs.getArchive(0, VERSIONS_ARCHIVE_FILE_ID);
+ ArchiveEntry entry = archive.getEntry("map_index");
+ Map definitions = new HashMap<>();
+
+ ByteBuffer buffer = entry.getBuffer();
+ int count = buffer.capacity() / (3 * Short.BYTES + Byte.BYTES);
+
+ for (int times = 0; times < count; times++) {
+ int id = buffer.getShort() & 0xFFFF;
+ int terrain = buffer.getShort() & 0xFFFF;
+ int objects = buffer.getShort() & 0xFFFF;
+ boolean members = buffer.get() == 1;
+
+ definitions.put(id, new MapIndex(id, terrain, objects, members));
+ }
+
+ return definitions;
+ }
+
+ @Override
+ public void run() {
+ try {
+ MapIndex.init(decode());
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+}
\ No newline at end of file
diff --git a/2006Scape Server/src/main/java/org/apollo/cache/map/MapObject.java b/2006Scape Server/src/main/java/org/apollo/cache/map/MapObject.java
new file mode 100644
index 00000000..72980add
--- /dev/null
+++ b/2006Scape Server/src/main/java/org/apollo/cache/map/MapObject.java
@@ -0,0 +1,119 @@
+package org.apollo.cache.map;
+
+/**
+ * Represents a static world object in a map file.
+ */
+public final class MapObject {
+
+ /**
+ * The object definition id of this {@code MapObject}.
+ */
+ private final int id;
+
+ /**
+ * The packed coordinates (local XY and height) for this object.
+ */
+ private int packedCoordinates;
+
+ /**
+ * The type of this object.
+ */
+ private final int type;
+
+ /**
+ * The orientation of this object.
+ */
+ private final int orientation;
+
+ /**
+ * Creates a new {@code MapObject}.
+ *
+ * @param id The object ID of this map object.
+ * @param packedCoordinates A packed integer containing the coordinates of this map object.
+ * @param type The type of object.
+ * @param orientation The object facing direction.
+ */
+ public MapObject(int id, int packedCoordinates, int type, int orientation) {
+ this.id = id;
+ this.packedCoordinates = packedCoordinates;
+ this.type = type;
+ this.orientation = orientation;
+ }
+
+ /**
+ * Create a new {@code MapObject}.
+ *
+ * @param id The object ID of this map object.
+ * @param x The local X coordinate of this object.
+ * @param y The local Y coordinate of this object.
+ * @param height The height level of this object.
+ * @param type The type of this object.
+ * @param orientation The orientation of this object.
+ */
+ public MapObject(int id, int x, int y, int height, int type, int orientation) {
+ this(id, (height & 0x3f) << 12 | (x & 0x3f) << 6 | (y & 0x3f), type, orientation);
+ }
+
+ /**
+ * Get the object ID of this map object.
+ *
+ * @return The object ID for {@link org.apollo.cache.def.ObjectDefinition} lookups.
+ */
+ public int getId() {
+ return id;
+ }
+
+ /**
+ * Get the plane this map object exists on.
+ *
+ * @return The plane this map object is on.
+ */
+ public int getHeight() {
+ return packedCoordinates >> 12 & 0x3;
+ }
+
+ /**
+ * Get the X coordinate of this object relative to the map position.
+ *
+ * @return The local X coordinate.
+ */
+ public int getLocalX() {
+ return packedCoordinates >> 6 & 0x3F;
+ }
+
+ /**
+ * Get the Y coordinate of this object relative to the map position.
+ *
+ * @return The local Y coordinate.
+ */
+ public int getLocalY() {
+ return packedCoordinates & 0x3F;
+ }
+
+ /**
+ * Get the integer representation of this objects orientation (0 indexed, starting West-North-East-South).
+ *
+ * @return The orientation of this object.
+ */
+ public int getOrientation() {
+ return orientation;
+ }
+
+ /**
+ * Get a packed integer containing the x/y coordinates and height for this object.
+ *
+ * @return The packed coordinates.
+ */
+ public int getPackedCoordinates() {
+ return packedCoordinates;
+ }
+
+ /**
+ * Get the type of this object.
+ *
+ * @return The type of this object.
+ */
+ public int getType() {
+ return type;
+ }
+}
diff --git a/2006Scape Server/src/main/java/org/apollo/cache/map/MapObjectsDecoder.java b/2006Scape Server/src/main/java/org/apollo/cache/map/MapObjectsDecoder.java
new file mode 100644
index 00000000..351ea7d7
--- /dev/null
+++ b/2006Scape Server/src/main/java/org/apollo/cache/map/MapObjectsDecoder.java
@@ -0,0 +1,83 @@
+package org.apollo.cache.map;
+
+import org.apollo.cache.IndexedFileSystem;
+import org.apollo.cache.map.MapIndex;
+import org.apollo.cache.map.MapConstants;
+import org.apollo.cache.map.MapObject;
+import org.apollo.util.BufferUtil;
+import org.apollo.util.CompressionUtil;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A decoder for reading the map objects for a given map.
+ *
+ * @author Major
+ */
+public final class MapObjectsDecoder {
+ /**
+ * Creates a MapObjectsDecoder for the specified map file.
+ *
+ * @param fs The {@link IndexedFileSystem} to get the file from.
+ * @param index The map index to decode objects for.
+ * @return The MapObjectsDecoder.
+ * @throws IOException If there is an error reading or decompressing the file.
+ */
+ public static MapObjectsDecoder create(IndexedFileSystem fs, MapIndex index) throws IOException {
+ ByteBuffer compressed = fs.getFile(MapConstants.MAP_INDEX, index.getObjectFile());
+ ByteBuffer decompressed = ByteBuffer.wrap(CompressionUtil.degzip(compressed));
+
+ return new MapObjectsDecoder(decompressed);
+ }
+
+ /**
+ * The buffer to decode {@link MapObject}s from.
+ */
+ private final ByteBuffer buffer;
+
+ /**
+ * Create a new {@link MapObjectsDecoder} from the given buffer and map coordinates.
+ *
+ * @param buffer The decompressed object file buffer.
+ */
+ public MapObjectsDecoder(ByteBuffer buffer) {
+ this.buffer = buffer.asReadOnlyBuffer();
+ }
+
+ /**
+ * Decodes the data in the {@code buffer} to a list of {@link MapObject}s.
+ *
+ * @return A list of decoded {@link MapObject}s.
+ */
+ public List decode() {
+ List objects = new ArrayList<>();
+
+ int id = -1;
+ int idOffset = BufferUtil.readSmart(buffer);
+
+ while (idOffset != 0) {
+ id += idOffset;
+
+ int packed = 0;
+ int positionOffset = BufferUtil.readSmart(buffer);
+
+ while (positionOffset != 0) {
+ packed += positionOffset - 1;
+
+ int attributes = buffer.get() & 0xFF;
+ int type = attributes >> 2;
+ int orientation = attributes & 0x3;
+ objects.add(new MapObject(id, packed, type, orientation));
+
+ positionOffset = BufferUtil.readSmart(buffer);
+ }
+
+ idOffset = BufferUtil.readSmart(buffer);
+ }
+
+ return objects;
+ }
+}
diff --git a/2006Scape Server/src/main/java/org/apollo/cache/map/MapPlane.java b/2006Scape Server/src/main/java/org/apollo/cache/map/MapPlane.java
new file mode 100644
index 00000000..1dfc3a01
--- /dev/null
+++ b/2006Scape Server/src/main/java/org/apollo/cache/map/MapPlane.java
@@ -0,0 +1,90 @@
+package org.apollo.cache.map;
+
+import java.util.Arrays;
+import java.util.stream.Stream;
+
+/**
+ * A plane of a map, which is a distinct height level.
+ *
+ * @author Major
+ */
+public final class MapPlane {
+
+ /**
+ * Returns a shallow copy of the specified 2-dimensional array.
+ *
+ * @param array The array to copy. Must not be {@code null}.
+ * @return The copy.
+ */
+ private static T[][] clone(T[][] array) {
+ T[][] copy = array.clone();
+ for (int index = 0; index < copy.length; index++) {
+ copy[index] = array[index].clone();
+ }
+
+ return copy;
+ }
+
+ /**
+ * The level of this MapPlane.
+ */
+ private final int level;
+
+ /**
+ * The 2-dimensional array of Tiles.
+ */
+ private final Tile[][] tiles;
+
+ /**
+ * Creates the MapPlane.
+ *
+ * @param level The level of the MapPlane.
+ * @param tiles The 2D array of {@link Tile}s. Must not be {@code null}. Must be square.
+ */
+ public MapPlane(int level, Tile[][] tiles) {
+ this.level = level;
+ this.tiles = clone(tiles);
+ }
+
+ /**
+ * Gets the level of this MapPlane.
+ *
+ * @return The level.
+ */
+ public int getLevel() {
+ return level;
+ }
+
+ /**
+ * Gets the amount of tiles in this MapPlane.
+ *
+ * @return The amount of tiles.
+ */
+ public int getSize() {
+ return tiles.length * tiles[0].length;
+ }
+
+ /**
+ * Gets the {@link Tile} at the specified (x, z) coordinate.
+ *
+ * @param x The x coordinate.
+ * @param z The z coordinate.
+ * @return The Tile.
+ */
+ public Tile getTile(int x, int z) {
+ return tiles[x][z];
+ }
+
+ /**
+ * Gets the {@link Tile}s in this MapPlane.
+ *
+ * This method returns the Tiles according on a column-based ordering: for a 2x2 tile set, the order will be
+ * {@code (0, 0), (0, 1), (1, 0), (1, 1)}.
+ *
+ * @return The Tiles.
+ */
+ public Stream getTiles() {
+ return Arrays.stream(tiles).flatMap(Arrays::stream);
+ }
+
+}
\ No newline at end of file
diff --git a/2006Scape Server/src/main/java/org/apollo/cache/map/Tile.java b/2006Scape Server/src/main/java/org/apollo/cache/map/Tile.java
new file mode 100644
index 00000000..e19d8133
--- /dev/null
+++ b/2006Scape Server/src/main/java/org/apollo/cache/map/Tile.java
@@ -0,0 +1,295 @@
+package org.apollo.cache.map;
+
+/**
+ * A single tile on the map.
+ *
+ * @author Major
+ */
+public final class Tile {
+
+ /**
+ * A builder class for a Tile.
+ */
+ public static final class Builder {
+
+ /**
+ * The attributes of the Tile.
+ */
+ private int attributes;
+
+ /**
+ * The height of the Tile.
+ */
+ private int height;
+
+ /**
+ * The overlay id of the Tile.
+ */
+ private int overlay;
+
+ /**
+ * The overlay orientation of the Tile.
+ */
+ private int overlayOrientation;
+
+ /**
+ * The overlay type of the Tile.
+ */
+ private int overlayType;
+
+ /**
+ * The x coordinate of the Tile.
+ */
+ private int x;
+
+ /**
+ * The y coordinate of the Tile.
+ */
+ private int y;
+
+ /**
+ * The underlay id of the Tile.
+ */
+ private int underlay;
+
+ /**
+ * Creates the Builder.
+ *
+ * @param x The x position of the Tile.
+ * @param y The y position of the Tile.
+ * @param height The height level of the Tile.
+ */
+ public Builder(int x, int y, int height) {
+ this.x = x;
+ this.y = y;
+ this.height = height;
+ }
+
+ /**
+ * Builds the contents of this Builder into a Tile.
+ *
+ * @return The Tile.
+ */
+ public Tile build() {
+ return new Tile(x, y, attributes, height, overlay, overlayType, overlayOrientation, underlay);
+ }
+
+ /**
+ * Sets the attributes of the Tile.
+ *
+ * @param attributes The attributes.
+ */
+ public void setAttributes(int attributes) {
+ this.attributes = attributes;
+ }
+
+ /**
+ * Sets the height of the Tile.
+ *
+ * @param height The height.
+ */
+ public void setHeight(int height) {
+ this.height = height;
+ }
+
+ /**
+ * Sets the overlay id of the Tile.
+ *
+ * @param overlay The overlay id.
+ */
+ public void setOverlay(int overlay) {
+ this.overlay = overlay;
+ }
+
+ /**
+ * Sets the overlay orientation of the Tile.
+ *
+ * @param orientation The overlay orientation.
+ */
+ public void setOverlayOrientation(int orientation) {
+ this.overlayOrientation = orientation;
+ }
+
+ /**
+ * Sets the overlay type of the Tile.
+ *
+ * @param type The overlay type.
+ */
+ public void setOverlayType(int type) {
+ this.overlayType = type;
+ }
+
+ /**
+ * Sets the position of the Tile.
+ *
+ * @param x The x coordinate of the Tile.
+ * @param y the y coordinate of the Tile
+ * @param height The height level of the Tile.
+ */
+ public void setPosition(int x, int y, int height) {
+ this.x = x;
+ this.y = y;
+ this.height = height;
+ }
+
+ /**
+ * Sets the underlay id of the Tile.
+ *
+ * @param underlay The underlay.
+ */
+ public void setUnderlay(int underlay) {
+ this.underlay = underlay;
+ }
+
+ }
+
+ /**
+ * Creates a {@link Builder} for a Tile.
+ *
+ * @param x The x coordinate of the Tile.
+ * @param y the y coordinate of the Tile.
+ * @param height The height level of the Tile.
+ * @return The Builder.
+ */
+ public static Builder builder(int x, int y, int height) {
+ return new Builder(x, y, height);
+ }
+
+ /**
+ * The attributes of this Tile.
+ */
+ private final int attributes;
+
+ /**
+ * The height of this Tile.
+ */
+ private final int height;
+
+ /**
+ * The overlay id of this Tile.
+ */
+ private final int overlay;
+
+ /**
+ * The overlay orientation of this Tile.
+ */
+ private final int overlayOrientation;
+
+ /**
+ * The overlay type of this Tile.
+ */
+ private final int overlayType;
+
+ /**
+ * The x coordinate of this Tile.
+ */
+ private final int x;
+
+ /**
+ * The y coordinate of this Tile.
+ */
+ private final int y;
+
+ /**
+ * The underlay id of this Tile.
+ */
+ private final int underlay;
+
+ /**
+ * Creates the Tile.
+ *
+ * @param x The x coordinate of the Tile.
+ * @param y The y coordinate of the Tile.
+ * @param attributes The attributes.
+ * @param height The height.
+ * @param overlay The overlay id.
+ * @param overlayType The overlay type.
+ * @param overlayOrientation The overlay orientation.
+ * @param underlay The underlay id.
+ */
+ public Tile(int x, int y, int attributes, int height, int overlay, int overlayType, int overlayOrientation,
+ int underlay) {
+ this.x = x;
+ this.y = y;
+ this.attributes = attributes;
+ this.height = height;
+ this.overlay = overlay;
+ this.overlayType = overlayType;
+ this.overlayOrientation = overlayOrientation;
+ this.underlay = underlay;
+ }
+
+ /**
+ * Gets the attributes of this Tile.
+ *
+ * @return The attributes.
+ */
+ public int getAttributes() {
+ return attributes;
+ }
+
+ /**
+ * Gets the height of this Tile.
+ *
+ * @return The height.
+ */
+ public int getHeight() {
+ return height;
+ }
+
+ /**
+ * Gets the overlay id of this Tile.
+ *
+ * @return The overlay id.
+ */
+ public int getOverlay() {
+ return overlay;
+ }
+
+ /**
+ * Gets the overlay orientation of this Tile.
+ *
+ * @return The overlay orientation.
+ */
+ public int getOverlayOrientation() {
+ return overlayOrientation;
+ }
+
+ /**
+ * Gets the overlay type of this Tile.
+ *
+ * @return The overlay types.
+ */
+ public int getOverlayType() {
+ return overlayType;
+ }
+
+ /**
+ * Gets the underlay id of this Tile.
+ *
+ * @return The underlay id.
+ */
+ public int getUnderlay() {
+ return underlay;
+ }
+
+
+ /**
+ * Gets the x coordinate of this Tile.
+ *
+ * @return The x coordinate.
+ */
+ public int getX() {
+ return x;
+ }
+
+ /**
+ * Gets the y coordinate of this Tile.
+ *
+ * @return The y coordinate.
+ */
+ public int getY() {
+ return y;
+ }
+
+}
diff --git a/2006Scape Server/src/main/java/org/apollo/cache/map/TileUtils.java b/2006Scape Server/src/main/java/org/apollo/cache/map/TileUtils.java
new file mode 100644
index 00000000..977e9562
--- /dev/null
+++ b/2006Scape Server/src/main/java/org/apollo/cache/map/TileUtils.java
@@ -0,0 +1,161 @@
+package org.apollo.cache.map;
+
+/*
+ * Copyright (c) 2012-2013 Jonathan Edgecombe
+ * Copyright (c) 2015 Major
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/**
+ * Contains tile-related utility methods.
+ *
+ * @author Johnny
+ * @author Major
+ */
+public final class TileUtils {
+
+ /**
+ * The x coordinate offset, used for computing the Tile height.
+ */
+ static final int TILE_HEIGHT_X_OFFSET = 0xe3b7b;
+
+ /**
+ * The z coordinate offset, used for computing the Tile height.
+ */
+ static final int TILE_HEIGHT_Z_OFFSET = 0x87cce;
+
+ /**
+ * The cosine table used for interpolation.
+ */
+ private static final int[] COSINE = new int[2048];
+
+ static {
+ for (int index = 0; index < COSINE.length; index++) {
+ COSINE[index] = (int) (65536 * Math.cos(2 * Math.PI * index / COSINE.length));
+ }
+ }
+
+ /**
+ * Calculates the height offset for the specified coordinate pair.
+ *
+ * @param x The x coordinate of the Tile.
+ * @param z The z coordinate of the Tile.
+ * @return The height offset.
+ */
+ public static int calculateHeight(int x, int z) {
+ int regionSize = 8;
+ int regionOffset = 6;
+ int offset = regionOffset * regionSize;
+
+ int baseX = x - offset;
+ int baseZ = z - offset;
+
+ return computeHeight(x + TILE_HEIGHT_X_OFFSET - baseX, z + TILE_HEIGHT_Z_OFFSET - baseZ)
+ * MapConstants.HEIGHT_MULTIPLICAND;
+ }
+
+ /**
+ * Gets the height offset for the specified coordinate pair.
+ *
+ * @param x The offset-x coordinate of the tile.
+ * @param z The offset-z coordinate of the tile.
+ * @return The tile height offset.
+ */
+ private static int computeHeight(int x, int z) {
+ int total = interpolatedNoise(x + 45365, z + 91923, 4) - 128;
+
+ total += (interpolatedNoise(x + 10294, z + 37821, 2) - 128) / 2;
+ total += (interpolatedNoise(x, z, 1) - 128) / 4;
+
+ total = (int) Math.max(total * 0.3 + 35, 10);
+ return Math.min(total, 60);
+ }
+
+ /**
+ * Interpolates two smooth noise values.
+ *
+ * @param a The first smooth noise value.
+ * @param b The second smooth noise value.
+ * @param theta The angle.
+ * @param reciprocal The frequency reciprocal.
+ * @return The interpolated value.
+ */
+ private static int interpolate(int a, int b, int theta, int reciprocal) {
+ int cosine = 65536 - COSINE[theta * COSINE.length / (2 * reciprocal)] / 2;
+ return (a * (65536 - cosine)) / 65536 + (b * cosine) / 65536;
+ }
+
+ /**
+ * Gets interpolated noise for the specified coordinate pair, using the specified frequency reciprocal.
+ *
+ * @param x The x coordinate.
+ * @param z The z coordinate.
+ * @param reciprocal The frequency reciprocal.
+ * @return The interpolated noise.
+ */
+ private static int interpolatedNoise(int x, int z, int reciprocal) {
+ int xt = x % reciprocal;
+ int zt = z % reciprocal;
+
+ x /= reciprocal;
+ z /= reciprocal;
+
+ int c = smoothNoise(x, z);
+ int e = smoothNoise(x + 1, z);
+ int ce = interpolate(c, e, xt, reciprocal);
+
+ int n = smoothNoise(x, z + 1);
+ int ne = smoothNoise(x + 1, z + 1);
+ int u = interpolate(n, ne, xt, reciprocal);
+
+ return interpolate(ce, u, zt, reciprocal);
+ }
+
+ /**
+ * Computes noise for the specified coordinate pair.
+ *
+ * @param x The x coordinate.
+ * @param z The z coordinate.
+ * @return The noise.
+ */
+ private static int noise(int x, int z) {
+ int n = x + z * 57;
+ n = (n << 13) ^ n;
+ n = (n * (n * n * 15731 + 789221) + 1376312589) & Integer.MAX_VALUE;
+ return (n >> 19) & 0xff;
+ }
+
+ /**
+ * Computes smooth noise for the specified coordinate pair.
+ *
+ * @param x The x coordinate.
+ * @param z The z coordinate.
+ * @return The smooth noise.
+ */
+ private static int smoothNoise(int x, int z) {
+ int corners = noise(x - 1, z - 1) + noise(x + 1, z - 1) + noise(x - 1, z + 1) + noise(x + 1, z + 1);
+ int sides = noise(x - 1, z) + noise(x + 1, z) + noise(x, z - 1) + noise(x, z + 1);
+ int center = noise(x, z);
+
+ return corners / 16 + sides / 8 + center / 4;
+ }
+
+ /**
+ * Sole private constructor to prevent instantiation.
+ */
+ private TileUtils() {
+
+ }
+
+}
\ No newline at end of file
diff --git a/2006Scape Server/src/main/java/org/apollo/cache/package-info.java b/2006Scape Server/src/main/java/org/apollo/cache/package-info.java
new file mode 100644
index 00000000..73873276
--- /dev/null
+++ b/2006Scape Server/src/main/java/org/apollo/cache/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * Contains classes which deal with the file system that the client uses to store game data files.
+ */
+package org.apollo.cache;
\ No newline at end of file
diff --git a/2006Scape Server/src/main/java/org/apollo/cache/tools/EquipmentUpdater.java b/2006Scape Server/src/main/java/org/apollo/cache/tools/EquipmentUpdater.java
new file mode 100644
index 00000000..7345704c
--- /dev/null
+++ b/2006Scape Server/src/main/java/org/apollo/cache/tools/EquipmentUpdater.java
@@ -0,0 +1,964 @@
+package org.apollo.cache.tools;
+
+import java.io.BufferedOutputStream;
+import java.io.DataOutputStream;
+import java.io.FileOutputStream;
+import java.nio.file.Paths;
+
+import org.apollo.cache.IndexedFileSystem;
+import org.apollo.cache.decoder.ItemDefinitionDecoder;
+import org.apollo.cache.def.ItemDefinition;
+import org.apollo.util.tools.EquipmentConstants;
+
+import com.google.common.base.Preconditions;
+
+/**
+ * A tool for updating the equipment data.
+ *
+ * @author Graham
+ * @author Palidino76
+ */
+public final class EquipmentUpdater {
+
+ /**
+ * The entry point of the application.
+ *
+ * @param args The command line arguments.
+ * @throws Exception If an error occurs.
+ */
+ public static void main(String[] args) throws Exception {
+ Preconditions.checkArgument(args.length == 1, "Usage:\njava -cp ... org.apollo.tools.EquipmentUpdater [release].");
+ String release = args[0];
+
+ try (DataOutputStream os = new DataOutputStream(new BufferedOutputStream(new FileOutputStream("data/equipment-" + release + ".dat")));
+ IndexedFileSystem fs = new IndexedFileSystem(Paths.get("data/fs/", release), true)) {
+ ItemDefinitionDecoder decoder = new ItemDefinitionDecoder(fs);
+ decoder.run();
+
+ int count = ItemDefinition.count();
+ os.writeShort(count);
+
+ for (int id = 0; id < count; id++) {
+ ItemDefinition definition = ItemDefinition.lookup(id);
+ int type = getWeaponType(definition);
+ os.writeByte(type);
+
+ if (type != -1) {
+ os.writeBoolean(isTwoHanded(definition));
+ os.writeBoolean(isFullBody(definition));
+ os.writeBoolean(isFullHat(definition));
+ os.writeBoolean(isFullMask(definition));
+ os.writeByte(getAttackRequirement(definition));
+ os.writeByte(getStrengthRequirement(definition));
+ os.writeByte(getDefenceRequirement(definition));
+ os.writeByte(getRangedRequirement(definition));
+ os.writeByte(getPrayerRequirement(definition));
+ os.writeByte(getMagicRequirement(definition));
+ }
+ }
+ }
+ }
+
+ /**
+ * Gets the attack requirement.
+ *
+ * @param definition The item definition.
+ * @return The required level.
+ */
+ private static int getAttackRequirement(ItemDefinition definition) {
+ String name = definition.getName();
+ if (name == null) {
+ name = "null";
+ }
+
+ if (name.equals("Black sword")) {
+ return 10;
+ } else if (name.equals("Black dagger")) {
+ return 10;
+ } else if (name.equals("Black spear")) {
+ return 10;
+ } else if (name.equals("Black longsword")) {
+ return 10;
+ } else if (name.equals("Black scimitar")) {
+ return 10;
+ } else if (name.equals("Black axe")) {
+ return 10;
+ } else if (name.equals("Black battleaxe")) {
+ return 10;
+ } else if (name.equals("Black mace")) {
+ return 10;
+ } else if (name.equals("Black halberd")) {
+ return 10;
+ } else if (name.equals("Mithril sword")) {
+ return 20;
+ } else if (name.equals("Mithril dagger")) {
+ return 20;
+ } else if (name.equals("Mithril spear")) {
+ return 20;
+ } else if (name.equals("Mihril longsword")) {
+ return 20;
+ } else if (name.equals("Mithril scimitar")) {
+ return 20;
+ } else if (name.equals("Mithril axe")) {
+ return 20;
+ } else if (name.equals("Mithril battleaxe")) {
+ return 20;
+ } else if (name.equals("Mithril mace")) {
+ return 20;
+ } else if (name.equals("Mithril halberd")) {
+ return 20;
+ } else if (name.equals("Adamant sword")) {
+ return 30;
+ } else if (name.equals("Adamant dagger")) {
+ return 30;
+ } else if (name.equals("Adamant spear")) {
+ return 30;
+ } else if (name.equals("Adamant longsword")) {
+ return 30;
+ } else if (name.equals("Adamant scimitar")) {
+ return 30;
+ } else if (name.equals("Adamant axe")) {
+ return 30;
+ } else if (name.equals("Adamant battleaxe")) {
+ return 30;
+ } else if (name.equals("Adamant mace")) {
+ return 30;
+ } else if (name.equals("Adamant halberd")) {
+ return 30;
+ } else if (name.equals("Rune sword")) {
+ return 40;
+ } else if (name.equals("Rune dagger")) {
+ return 40;
+ } else if (name.equals("Rune spear")) {
+ return 40;
+ } else if (name.equals("Rune longsword")) {
+ return 40;
+ } else if (name.equals("Rune scimitar")) {
+ return 40;
+ } else if (name.equals("Rune axe")) {
+ return 40;
+ } else if (name.equals("Rune battleaxe")) {
+ return 40;
+ } else if (name.equals("Rune mace")) {
+ return 40;
+ } else if (name.equals("Rune halberd")) {
+ return 40;
+ } else if (name.equals("Dragon sword")) {
+ return 60;
+ } else if (name.equals("Dragon dagger(s)")) {
+ return 60;
+ } else if (name.equals("Dragon dagger")) {
+ return 60;
+ } else if (name.startsWith("Dragon spear")) {
+ return 60;
+ } else if (name.equals("Dragon longsword")) {
+ return 60;
+ } else if (name.equals("Dragon scimitar")) {
+ return 60;
+ } else if (name.equals("Dragon axe")) {
+ return 60;
+ } else if (name.equals("Dragon battleaxe")) {
+ return 60;
+ } else if (name.equals("Dragon mace")) {
+ return 60;
+ } else if (name.equals("Dragon halberd")) {
+ return 60;
+ } else if (name.equals("Abyssal whip")) {
+ return 70;
+ } else if (name.equals("Veracs flail")) {
+ return 70;
+ } else if (name.equals("Torags hammers")) {
+ return 70;
+ } else if (name.equals("Dharoks greataxe")) {
+ return 70;
+ } else if (name.equals("Guthans warspear")) {
+ return 70;
+ } else if (name.equals("Ahrims staff")) {
+ return 70;
+ } else if (name.equals("Granite maul")) {
+ return 50;
+ } else if (name.equals("Toktz-xil-ak")) {
+ return 60;
+ } else if (name.equals("Tzhaar-ket-em")) {
+ return 60;
+ } else if (name.equals("Toktz-xil-ek")) {
+ return 60;
+ } else if (name.equals("Granite legs")) {
+ return 99;
+ } else if (name.equals("Mud staff")) {
+ return 30;
+ } else if (name.equals("Armadyl godsword")) {
+ return 75;
+ } else if (name.equals("Bandos godsword")) {
+ return 75;
+ } else if (name.equals("Saradomin godsword")) {
+ return 75;
+ } else if (name.equals("Zamorak godsword")) {
+ return 75;
+ } else if (name.equals("Lava battlestaff")) {
+ return 30;
+ } else if (name.equals("Toktz-mej-tal")) {
+ return 60;
+ } else if (name.equals("Ancient staff")) {
+ return 50;
+ }
+
+ return 1;
+ }
+
+ /**
+ * Gets the defence requirement.
+ *
+ * @param definition The item definition.
+ * @return The required level.
+ */
+ private static int getDefenceRequirement(ItemDefinition definition) {
+ int id = definition.getId();
+ String name = definition.getName();
+ if (name == null) {
+ name = "null";
+ }
+
+ if (name.equals("Rune boots")) {
+ return 40;
+ } else if (id == 2499) {
+ return 40;
+ } else if (id == 4123) {
+ return 5;
+ } else if (id == 4125) {
+ return 10;
+ } else if (id == 4127) {
+ return 20;
+ } else if (id == 4129) {
+ return 30;
+ } else if (id == 7990) {
+ return 60;
+ } else if (id == 2501) {
+ return 40;
+ } else if (id == 1131) {
+ return 10;
+ } else if (id == 2503) {
+ return 40;
+ } else if (id == 1135) {
+ return 40;
+ } else if (id == 7462) {
+ return 42;
+ } else if (id == 7461) {
+ return 42;
+ } else if (id == 7460) {
+ return 42;
+ } else if (id == 7459) {
+ return 20;
+ } else if (id == 7458) {
+ return 1;
+ } else if (id == 7457) {
+ return 1;
+ } else if (id == 7456) {
+ return 1;
+ } else if (id == 2661) {
+ return 40;
+ } else if (id == 2667) {
+ return 40;
+ } else if (id == 3479) {
+ return 40;
+ } else if (name.equals("White med helm")) {
+ return 10;
+ } else if (name.equals("White chainbody")) {
+ return 10;
+ } else if (name.startsWith("White full helm")) {
+ return 10;
+ } else if (name.startsWith("White platebody")) {
+ return 10;
+ } else if (name.startsWith("White plateskirt")) {
+ return 10;
+ } else if (name.startsWith("White platelegs")) {
+ return 10;
+ } else if (name.startsWith("White kiteshield")) {
+ return 10;
+ } else if (name.startsWith("White sq shield")) {
+ return 10;
+ } else if (name.startsWith("Studded chaps")) {
+ return 1;
+ } else if (name.startsWith("Studded")) {
+ return 20;
+ } else if (name.startsWith("Black kiteshield(h)")) {
+ return 10;
+ } else if (name.startsWith("Rune kiteshield(h)")) {
+ return 40;
+ } else if (name.equals("Black med helm")) {
+ return 10;
+ } else if (name.equals("Black chainbody")) {
+ return 10;
+ } else if (name.startsWith("Black full helm")) {
+ return 10;
+ } else if (name.startsWith("Black platebody")) {
+ return 10;
+ } else if (name.startsWith("Black plateskirt")) {
+ return 10;
+ } else if (name.startsWith("Black platelegs")) {
+ return 10;
+ } else if (name.startsWith("Black kiteshield")) {
+ return 10;
+ } else if (name.startsWith("Black sq shield")) {
+ return 10;
+ } else if (name.equals("Mithril med helm")) {
+ return 20;
+ } else if (name.equals("Mithril chainbody")) {
+ return 20;
+ } else if (name.startsWith("Mithril full helm")) {
+ return 20;
+ } else if (name.startsWith("Mithril platebody")) {
+ return 20;
+ } else if (name.startsWith("Mithril plateskirt")) {
+ return 20;
+ } else if (name.startsWith("Mithril platelegs")) {
+ return 20;
+ } else if (name.startsWith("Mithril kiteshield")) {
+ return 20;
+ } else if (name.startsWith("Mithril sq shield")) {
+ return 20;
+ } else if (name.equals("Adamant med helm")) {
+ return 30;
+ } else if (name.equals("Adamant chainbody")) {
+ return 30;
+ } else if (name.startsWith("Adamant full helm")) {
+ return 30;
+ } else if (name.startsWith("Adamant platebody")) {
+ return 30;
+ } else if (name.startsWith("Adamant plateskirt")) {
+ return 30;
+ } else if (name.startsWith("Adamant platelegs")) {
+ return 30;
+ } else if (name.startsWith("Adamant kiteshield")) {
+ return 30;
+ } else if (name.startsWith("Adamant sq shield")) {
+ return 30;
+ } else if (name.startsWith("Adam full helm")) {
+ return 30;
+ } else if (name.startsWith("Adam platebody")) {
+ return 30;
+ } else if (name.startsWith("Adam plateskirt")) {
+ return 30;
+ } else if (name.startsWith("Adam platelegs")) {
+ return 30;
+ } else if (name.startsWith("Adam kiteshield")) {
+ return 30;
+ } else if (name.startsWith("Adam kiteshield(h)")) {
+ return 30;
+ } else if (name.startsWith("D-hide body(g)")) {
+ return 40;
+ } else if (name.startsWith("D-hide body(t)")) {
+ return 40;
+ } else if (name.equals("Dragon sq shield")) {
+ return 60;
+ } else if (name.equals("Dragon med helm")) {
+ return 60;
+ } else if (name.equals("Dragon chainbody")) {
+ return 60;
+ } else if (name.equals("Dragon plateskirt")) {
+ return 60;
+ } else if (name.equals("Dragon platelegs")) {
+ return 60;
+ } else if (name.equals("Dragon sq shield")) {
+ return 60;
+ } else if (name.equals("Rune med helm")) {
+ return 40;
+ } else if (name.equals("Rune chainbody")) {
+ return 40;
+ } else if (name.startsWith("Rune full helm")) {
+ return 40;
+ } else if (name.startsWith("Rune platebody")) {
+ return 40;
+ } else if (name.startsWith("Rune plateskirt")) {
+ return 40;
+ } else if (name.startsWith("Rune platelegs")) {
+ return 40;
+ } else if (name.startsWith("Rune kiteshield")) {
+ return 40;
+ } else if (name.startsWith("Zamorak full helm")) {
+ return 40;
+ } else if (name.startsWith("Zamorak platebody")) {
+ return 40;
+ } else if (name.startsWith("Zamorak plateskirt")) {
+ return 40;
+ } else if (name.startsWith("Zamorak platelegs")) {
+ return 40;
+ } else if (name.startsWith("Zamorak kiteshield")) {
+ return 40;
+ } else if (name.startsWith("Guthix full helm")) {
+ return 40;
+ } else if (name.startsWith("Guthix platebody")) {
+ return 40;
+ } else if (name.startsWith("Guthix plateskirt")) {
+ return 40;
+ } else if (name.startsWith("Guthix platelegs")) {
+ return 40;
+ } else if (name.startsWith("Guthix kiteshield")) {
+ return 40;
+ } else if (name.startsWith("Saradomin full")) {
+ return 40;
+ } else if (name.startsWith("Saradomrangedin plate")) {
+ return 40;
+ } else if (name.startsWith("Saradomin plateskirt")) {
+ return 40;
+ } else if (name.startsWith("Saradomin legs")) {
+ return 40;
+ } else if (name.startsWith("Zamorak kiteshield")) {
+ return 40;
+ } else if (name.startsWith("Rune sq shield")) {
+ return 40;
+ } else if (name.equals("Gilded full helm")) {
+ return 40;
+ } else if (name.equals("Gilded platebody")) {
+ return 40;
+ } else if (name.equals("Gilded plateskirt")) {
+ return 40;
+ } else if (name.equals("Gilded platelegs")) {
+ return 40;
+ } else if (name.equals("Gilded kiteshield")) {
+ return 40;
+ } else if (name.equals("Fighter torso")) {
+ return 40;
+ } else if (name.equals("Granite legs")) {
+ return 99;
+ } else if (name.equals("Toktz-ket-xil")) {
+ return 60;
+ } else if (name.equals("Dharoks helm")) {
+ return 70;
+ } else if (name.equals("Dharoks platebody")) {
+ return 70;
+ } else if (name.equals("Dharoks platelegs")) {
+ return 70;
+ } else if (name.equals("Guthans helm")) {
+ return 70;
+ } else if (name.equals("Guthans platebody")) {
+ return 70;
+ } else if (name.equals("Guthans chainskirt")) {
+ return 70;
+ } else if (name.equals("Torags helm")) {
+ return 70;
+ } else if (name.equals("Torags platebody")) {
+ return 70;
+ } else if (name.equals("Torags platelegs")) {
+ return 70;
+ } else if (name.equals("Veracs helm")) {
+ return 70;
+ } else if (name.equals("Veracs brassard")) {
+ return 70;
+ } else if (name.equals("Veracs plateskirt")) {
+ return 70;
+ } else if (name.equals("Ahrims hood")) {
+ return 70;
+ } else if (name.equals("Ahrims robetop")) {
+ return 70;
+ } else if (name.equals("Ahrims robeskirt")) {
+ return 70;
+ } else if (name.equals("Karils coif")) {
+ return 70;
+ } else if (name.equals("Karils leathertop")) {
+ return 70;
+ } else if (name.equals("Karils leatherskirt")) {
+ return 70;
+ } else if (name.equals("Granite shield")) {
+ return 50;
+ } else if (name.equals("New crystal shield")) {
+ return 70;
+ } else if (name.equals("Archer helm")) {
+ return 45;
+ } else if (name.equals("Berserker helm")) {
+ return 45;
+ } else if (name.equals("Warrior helm")) {
+ return 45;
+ } else if (name.equals("Farseer helm")) {
+ return 45;
+ } else if (name.equals("Initiate helm")) {
+ return 20;
+ } else if (name.equals("Initiate platemail")) {
+ return 20;
+ } else if (name.equals("Initiate platelegs")) {
+ return 20;
+ } else if (name.equals("Dragonhide body")) {
+ return 40;
+ } else if (name.equals("Mystic hat")) {
+ return 20;
+ } else if (name.equals("Mystic robe top")) {
+ return 20;
+ } else if (name.equals("Mystic robe bottom")) {
+ return 20;
+ } else if (name.equals("Mystic gloves")) {
+ return 20;
+ } else if (name.equals("Mystic boots")) {
+ return 20;
+ } else if (name.equals("Enchanted hat")) {
+ return 20;
+ } else if (name.equals("Enchanted top")) {
+ return 20;
+ } else if (name.equals("Enchanted robe")) {
+ return 20;
+ } else if (name.equals("Splitbark helm")) {
+ return 40;
+ } else if (name.equals("Splitbark body")) {
+ return 40;
+ } else if (name.equals("Splitbark gauntlets")) {
+ return 40;
+ } else if (name.equals("Splitbark legs")) {
+ return 40;
+ } else if (name.equals("Splitbark greaves")) {
+ return 40;
+ } else if (name.equals("Infinity gloves")) {
+ return 25;
+ } else if (name.equals("Infinity hat")) {
+ return 25;
+ } else if (name.equals("Infinity top")) {
+ return 25;
+ } else if (name.equals("Infinity bottoms")) {
+ return 25;
+ } else if (name.equals("Infinity boots")) {
+ return 25;
+ }
+
+ return 1;
+ }
+
+ /**
+ * Gets the magic requirement.
+ *
+ * @param definition The item definition.
+ * @return The required level.
+ */
+ private static int getMagicRequirement(ItemDefinition definition) {
+ String name = definition.getName();
+ if (name == null) {
+ name = "null";
+ }
+
+ if (name.equals("Mystic hat")) {
+ return 40;
+ } else if (name.equals("Mystic robe top")) {
+ return 40;
+ } else if (name.equals("Mystic robe bottom")) {
+ return 40;
+ } else if (name.equals("Mystic gloves")) {
+ return 40;
+ } else if (name.equals("Mystic boots")) {
+ return 40;
+ } else if (name.equals("Slayer's staff")) {
+ return 50;
+ } else if (name.equals("Enchanted hat")) {
+ return 40;
+ } else if (name.equals("Enchanted top")) {
+ return 40;
+ } else if (name.equals("Enchanted robe")) {
+ return 40;
+ } else if (name.equals("Splitbark helm")) {
+ return 40;
+ } else if (name.equals("Splitbark body")) {
+ return 40;
+ } else if (name.equals("Splitbark gauntlets")) {
+ return 40;
+ } else if (name.equals("Splitbark legs")) {
+ return 40;
+ } else if (name.equals("Splitbark greaves")) {
+ return 40;
+ } else if (name.equals("Infinity gloves")) {
+ return 50;
+ } else if (name.equals("Infinity hat")) {
+ return 50;
+ } else if (name.equals("Infinity top")) {
+ return 50;
+ } else if (name.equals("Infinity bottoms")) {
+ return 50;
+ } else if (name.equals("Infinity boots")) {
+ return 50;
+ } else if (name.equals("Ahrims hood")) {
+ return 70;
+ } else if (name.equals("Ahrims robetop")) {
+ return 70;
+ } else if (name.equals("Ahrims robeskirt")) {
+ return 70;
+ } else if (name.equals("Ahrims staff")) {
+ return 70;
+ } else if (name.equals("Saradomin cape")) {
+ return 60;
+ } else if (name.equals("Saradomin staff")) {
+ return 60;
+ } else if (name.equals("Zamorak cape")) {
+ return 60;
+ } else if (name.equals("Zamorak staff")) {
+ return 60;
+ } else if (name.equals("Guthix cape")) {
+ return 60;
+ } else if (name.equals("Guthix staff")) {
+ return 60;
+ } else if (name.equals("mud staff")) {
+ return 30;
+ } else if (name.equals("Fire battlestaff")) {
+ return 30;
+ } else if (name.equals("Toktz-mej-tal")) {
+ return 60;
+ }
+ return 1;
+ }
+
+ /**
+ * Gets the prayer requirement.
+ *
+ * @param definition the item.
+ * @return The required level.
+ */
+ private static int getPrayerRequirement(ItemDefinition definition) {
+ String name = definition.getName();
+ if (name == null) {
+ name = "null";
+ }
+ if (name.contains("Initiate")) {
+ return 10;
+ }
+ if (name.contains("Proselyte")) {
+ return 20;
+ }
+ return 1;
+ }
+
+ /**
+ * Gets the ranged requirement.
+ *
+ * @param definition The item.
+ * @return The required level.
+ */
+ private static int getRangedRequirement(ItemDefinition definition) {
+ int id = definition.getId();
+ String name = definition.getName();
+ if (name == null) {
+ name = "null";
+ }
+
+ if (id == 2499) {
+ return 50;
+ } else if (id == 1135) {
+ return 40;
+ } else if (id == 1099) {
+ return 40;
+ } else if (id == 1065) {
+ return 40;
+ } else if (id == 2501) {
+ return 60;
+ } else if (id == 2503) {
+ return 70;
+ } else if (id == 2487) {
+ return 50;
+ } else if (id == 2489) {
+ return 60;
+ } else if (id == 2495) {
+ return 60;
+ } else if (id == 2491) {
+ return 70;
+ } else if (id == 2493) {
+ return 50;
+ } else if (id == 2505) {
+ return 60;
+ } else if (id == 2507) {
+ return 70;
+ } else if (id == 859) {
+ return 40;
+ } else if (id == 861) {
+ return 40;
+ } else if (id == 7370) {
+ return 40;
+ } else if (id == 7372) {
+ return 40;
+ } else if (id == 7378) {
+ return 40;
+ } else if (id == 7380) {
+ return 40;
+ } else if (id == 7374) {
+ return 50;
+ } else if (id == 7376) {
+ return 50;
+ } else if (id == 7382) {
+ return 50;
+ } else if (id == 7384) {
+ return 50;
+ } else if (name.equals("Coif")) {
+ return 20;
+ } else if (name.startsWith("Studded chaps")) {
+ return 20;
+ } else if (name.startsWith("Studded")) {
+ return 20;
+ } else if (name.equals("Karils coif")) {
+ return 70;
+ } else if (name.equals("Karils leathertop")) {
+ return 70;
+ } else if (name.equals("Karils leatherskirt")) {
+ return 70;
+ } else if (name.equals("Robin hood hat")) {
+ return 40;
+ } else if (name.equals("Ranger boots")) {
+ return 40;
+ } else if (name.equals("Crystal bow full")) {
+ return 70;
+ } else if (name.equals("New crystal bow")) {
+ return 70;
+ } else if (name.equals("Karils crossbow")) {
+ return 70;
+ } else if (id == 2497) {
+ return 70;
+ } else if (name.equals("Rune thrownaxe")) {
+ return 40;
+ } else if (name.equals("Rune dart")) {
+ return 40;
+ } else if (name.equals("Rune javelin")) {
+ return 40;
+ } else if (name.equals("Rune knife")) {
+ return 40;
+ } else if (name.equals("Adamant thrownaxe")) {
+ return 30;
+ } else if (name.equals("Adamant dart")) {
+ return 30;
+ } else if (name.equals("Adamant javelin")) {
+ return 30;
+ } else if (name.equals("Adamant knife")) {
+ return 30;
+ } else if (name.equals("Toktz-xil-ul")) {
+ return 60;
+ } else if (name.equals("Seercull")) {
+ return 50;
+ } else if (name.equals("Bolt rack")) {
+ return 70;
+ } else if (name.equals("Rune arrow")) {
+ return 40;
+ } else if (name.equals("Adamant arrow")) {
+ return 30;
+ } else if (name.equals("Mithril arrow")) {
+ return 1;
+ }
+
+ return 1;
+ }
+
+ /**
+ * Gets the strength requirement.
+ *
+ * @param def The item.
+ * @return The required level.
+ */
+ private static int getStrengthRequirement(ItemDefinition def) {
+ String name = def.getName();
+ if (name == null) {
+ name = "null";
+ }
+
+ if (name.equals("Torags hammers")) {
+ return 70;
+ } else if (name.equals("Dharoks greataxe")) {
+ return 70;
+ } else if (name.equals("Granite maul")) {
+ return 50;
+ } else if (name.equals("Granite legs")) {
+ return 99;
+ } else if (name.equals("Tzhaar-ket-om")) {
+ return 60;
+ } else if (name.equals("Granite shield")) {
+ return 50;
+ }
+
+ return 1;
+ }
+
+ /**
+ * Gets the weapon type.
+ *
+ * @param definition The item.
+ * @return The weapon type, or {@code -1} if it is not a weapon.
+ */
+ private static int getWeaponType(ItemDefinition definition) {
+ String name = definition.getName();
+ if (name == null) {
+ name = "null";
+ }
+ for (String element : EquipmentConstants.CAPES) {
+ if (name.contains(element)) {
+ return 1;
+ }
+ }
+ for (String element : EquipmentConstants.HATS) {
+ if (name.contains(element)) {
+ return 0;
+ }
+ }
+ for (String element : EquipmentConstants.BOOTS) {
+ if (name.endsWith(element) || name.startsWith(element)) {
+ return 10;
+ }
+ }
+ for (String element : EquipmentConstants.GLOVES) {
+ if (name.endsWith(element) || name.startsWith(element)) {
+ return 9;
+ }
+ }
+ for (String element : EquipmentConstants.SHIELDS) {
+ if (name.contains(element)) {
+ return 5;
+ }
+ }
+ for (String element : EquipmentConstants.AMULETS) {
+ if (name.endsWith(element) || name.startsWith(element)) {
+ return 2;
+ }
+ }
+ for (String element : EquipmentConstants.ARROWS) {
+ if (name.endsWith(element) || name.startsWith(element)) {
+ return 13;
+ }
+ }
+ for (String element : EquipmentConstants.RINGS) {
+ if (name.endsWith(element) || name.startsWith(element)) {
+ return 12;
+ }
+ }
+ for (String element : EquipmentConstants.BODY) {
+ if (name.contains(element)) {
+ return 4;
+ }
+ }
+ for (String element : EquipmentConstants.LEGS) {
+ if (name.contains(element)) {
+ return 7;
+ }
+ }
+ for (String element : EquipmentConstants.WEAPONS) {
+ if (name.endsWith(element) || name.startsWith(element)) {
+ return 3;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Checks if the item is a full body item.
+ *
+ * @param definition The item.
+ * @return {@code true} if so, {@code false} otherwise.
+ */
+ private static boolean isFullBody(ItemDefinition definition) {
+ String name = definition.getName();
+ if (name == null) {
+ name = "null";
+ }
+
+ for (String element : EquipmentConstants.FULL_BODIES) {
+ if (name.contains(element)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Checks if the item is a full hat item.
+ *
+ * @param definition The item.
+ * @return {@code true} if so, {@code false} otherwise.
+ */
+ private static boolean isFullHat(ItemDefinition definition) {
+ String name = definition.getName();
+ if (name == null) {
+ name = "null";
+ }
+
+ for (String element : EquipmentConstants.FULL_HATS) {
+ if (name.endsWith(element)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Checks if the item is a full mask item.
+ *
+ * @param definition The item.
+ * @return {@code true} if so, {@code false} otherwise.
+ */
+ private static boolean isFullMask(ItemDefinition definition) {
+ String name = definition.getName();
+ if (name == null) {
+ name = "null";
+ }
+
+ for (String element : EquipmentConstants.FULL_MASKS) {
+ if (name.endsWith(element)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Checks if the item is two handed.
+ *
+ * @param definition The item.
+ * @return {@code true} if so, {@code false} otherwise.
+ */
+ private static boolean isTwoHanded(ItemDefinition definition) {
+ int id = definition.getId();
+ String name = definition.getName();
+ if (name == null) {
+ name = "null";
+ }
+
+ if (id == 4212) {
+ return true;
+ } else if (id == 4214) {
+ return true;
+ } else if (id == 6526) {
+ return true;
+ } else if (name.endsWith("2h sword")) {
+ return true;
+ } else if (name.endsWith("longbow")) {
+ return true;
+ } else if (name.equals("Seercull")) {
+ return true;
+ } else if (name.endsWith("shortbow")) {
+ return true;
+ } else if (name.endsWith("Longbow")) {
+ return true;
+ } else if (name.endsWith("Shortbow")) {
+ return true;
+ } else if (name.endsWith("bow full")) {
+ return true;
+ } else if (name.endsWith("halberd")) {
+ return true;
+ } else if (name.equals("Granite maul")) {
+ return true;
+ } else if (name.equals("Karils crossbow")) {
+ return true;
+ } else if (name.equals("Torags hammers")) {
+ return true;
+ } else if (name.equals("Veracs flail")) {
+ return true;
+ } else if (name.equals("Dharoks greataxe")) {
+ return true;
+ } else if (name.equals("Guthans warspear")) {
+ return true;
+ } else if (name.equals("Tzhaar-ket-om")) {
+ return true;
+ } else if (name.endsWith("godsword")) {
+ return true;
+ } else if (name.equals("Saradomin sword")) {
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Default private constructor to prevent instantiation.
+ */
+ private EquipmentUpdater() {
+ }
+
+}
\ No newline at end of file
diff --git a/2006Scape Server/src/main/java/org/apollo/cache/tools/package-info.java b/2006Scape Server/src/main/java/org/apollo/cache/tools/package-info.java
new file mode 100644
index 00000000..c885d57d
--- /dev/null
+++ b/2006Scape Server/src/main/java/org/apollo/cache/tools/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * Contains cache-related tools.
+ */
+package org.apollo.cache.tools;
\ No newline at end of file
diff --git a/2006Scape Server/src/main/java/org/apollo/game/session/ApolloHandler.java b/2006Scape Server/src/main/java/org/apollo/game/session/ApolloHandler.java
new file mode 100644
index 00000000..9a04936f
--- /dev/null
+++ b/2006Scape Server/src/main/java/org/apollo/game/session/ApolloHandler.java
@@ -0,0 +1,106 @@
+package org.apollo.game.session;
+
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelHandler.Sharable;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.ChannelInboundHandlerAdapter;
+import io.netty.handler.codec.http.HttpRequest;
+import io.netty.util.Attribute;
+import io.netty.util.AttributeKey;
+import io.netty.util.ReferenceCountUtil;
+
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.apollo.net.codec.handshake.HandshakeConstants;
+import org.apollo.net.codec.handshake.HandshakeMessage;
+import org.apollo.net.codec.jaggrab.JagGrabRequest;
+
+import com.rs2.GameConstants;
+
+/**
+ * An implementation of {@link ChannelInboundHandlerAdapter} which handles incoming upstream events from Netty.
+ *
+ * @author Graham
+ */
+@Sharable
+public final class ApolloHandler extends ChannelInboundHandlerAdapter {
+
+ /**
+ * The logger for this class.
+ */
+ private static final Logger logger = Logger.getLogger(ApolloHandler.class.getName());
+
+ /**
+ * The {@link Session} {@link AttributeKey}.
+ */
+ public static final AttributeKey SESSION_KEY = AttributeKey.valueOf("session");
+
+ /**
+ * Creates the Apollo event handler.
+ *
+ * @param context The server context.
+ */
+ public ApolloHandler() {
+ }
+
+ @Override
+ public void channelInactive(ChannelHandlerContext ctx) {
+ Channel channel = ctx.channel();
+ Session session = channel.attr(ApolloHandler.SESSION_KEY).getAndRemove();
+ if (session != null) {
+ session.destroy();
+ }
+ logger.fine("Channel disconnected: " + channel);
+ channel.close();
+ }
+
+ @Override
+ public void exceptionCaught(ChannelHandlerContext ctx, Throwable e) {
+ if (!e.getMessage().contains("An existing connection was forcibly closed by the remote host")) {
+ logger.log(Level.WARNING, "Exception occured for channel: " + ctx.channel() + ", closing...", e);
+ }
+ ctx.channel().close();
+ }
+
+ @Override
+ public void channelRead(ChannelHandlerContext ctx, Object message) throws Exception {
+ Channel channel = ctx.channel();
+ Attribute attribute = channel.attr(ApolloHandler.SESSION_KEY);
+ Session session = attribute.get();
+
+ if (message instanceof HttpRequest || message instanceof JagGrabRequest) {
+ session = new UpdateSession(channel);
+ }
+
+ if (session != null) {
+ session.messageReceived(message);
+ return;
+ }
+
+ // TODO: Perhaps let HandshakeMessage implement Message to remove this explicit check
+ if (message instanceof HandshakeMessage) {
+ HandshakeMessage handshakeMessage = (HandshakeMessage) message;
+
+ switch (handshakeMessage.getServiceId()) {
+ case HandshakeConstants.SERVICE_GAME:
+ attribute.set(new LoginSession(channel));
+ break;
+
+ case HandshakeConstants.SERVICE_UPDATE:
+ if(!GameConstants.FILE_SERVER) {
+ ctx.close();
+ return;
+ }
+ attribute.set(new UpdateSession(channel));
+ break;
+ }
+ }
+ }
+
+ @Override
+ public void channelReadComplete(ChannelHandlerContext ctx) {
+ ctx.flush();
+ }
+
+}
\ No newline at end of file
diff --git a/2006Scape Server/src/main/java/org/apollo/game/session/GameSession.java b/2006Scape Server/src/main/java/org/apollo/game/session/GameSession.java
new file mode 100644
index 00000000..eb43f74b
--- /dev/null
+++ b/2006Scape Server/src/main/java/org/apollo/game/session/GameSession.java
@@ -0,0 +1,66 @@
+package org.apollo.game.session;
+
+import io.netty.buffer.ByteBuf;
+import io.netty.channel.Channel;
+
+import java.net.SocketAddress;
+
+import com.rs2.game.players.Player;
+import com.rs2.net.Packet;
+
+/**
+ * Temporary quick and tear integration with apollo netcode. This needs redone when the the packets are fully redone.
+ * @author Advocatus
+ *
+ */
+public final class GameSession extends Session {
+
+ private Player player;
+
+ public void setPlayer(Player player) {
+ this.player = player;
+ }
+
+ private final boolean reconnecting;
+
+ public GameSession(Channel channel, Player player, boolean reconnecting) {
+ super(channel);
+ this.player = player;
+ this.reconnecting = reconnecting;
+ }
+
+ @Override
+ public void destroy() {
+ player.disconnected = true;
+ }
+
+ public boolean isReconnecting() {
+ return reconnecting;
+ }
+
+ @Override
+ public void messageReceived(Object message) {
+ player.queueMessage((Packet) message);
+ }
+
+ public SocketAddress getRemoteAddress() {
+ return channel.remoteAddress();
+ }
+
+ public void close() {
+ channel.close();
+ }
+
+ public boolean isActive() {
+ return channel.isActive();
+ }
+
+// public void write(Packet packet) {
+// channel.write(packet);
+// }
+
+ public void write(ByteBuf buf) {
+ channel.writeAndFlush(buf);
+ }
+
+}
\ No newline at end of file
diff --git a/2006Scape Server/src/main/java/org/apollo/game/session/LoginSession.java b/2006Scape Server/src/main/java/org/apollo/game/session/LoginSession.java
new file mode 100644
index 00000000..1c6649fb
--- /dev/null
+++ b/2006Scape Server/src/main/java/org/apollo/game/session/LoginSession.java
@@ -0,0 +1,171 @@
+package org.apollo.game.session;
+
+import io.netty.buffer.ByteBuf;
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelFuture;
+import io.netty.channel.ChannelFutureListener;
+import io.netty.channel.ChannelHandlerContext;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.util.Optional;
+
+import org.apollo.net.codec.login.LoginConstants;
+import org.apollo.net.codec.login.LoginRequest;
+import org.apollo.net.codec.login.LoginResponse;
+import org.apollo.util.security.IsaacRandom;
+import org.apollo.util.security.IsaacRandomPair;
+import org.apollo.util.security.PlayerCredentials;
+
+import com.rs2.Connection;
+import com.rs2.GameConstants;
+import com.rs2.GameEngine;
+import com.rs2.game.players.Client;
+import com.rs2.game.players.PlayerHandler;
+import com.rs2.game.players.PlayerSave;
+import com.rs2.net.RS2ProtocolDecoder;
+import com.rs2.util.HostBlacklist;
+
+/**
+ * Temporary quick and tear integration with apollo netcode. This needs redone when the Apollo Service system is added.
+ * @author Advocatus
+ *
+ */
+public final class LoginSession extends Session {
+
+ public LoginSession(Channel channel) {
+ super(channel);
+ }
+
+ @Override
+ public void destroy() {
+
+ }
+
+ @Override
+ public void messageReceived(Object message) throws Exception {
+ if (message.getClass() == LoginRequest.class) {
+ handleLoginRequest((LoginRequest) message);
+ }
+ }
+
+ public static void load(Channel channel,
+ PlayerCredentials credentials, IsaacRandomPair randomPair, boolean reconnecting) {
+
+ int returnCode = 2;
+
+ String username = credentials.getUsername().trim();
+ String password = credentials.getPassword().trim();
+ username = username.toLowerCase();
+ // pass = pass.toLowerCase();
+
+ String hostName = ((InetSocketAddress) channel.remoteAddress())
+ .getAddress().getHostName();
+
+// if (uid != 314268572) {
+// channel.close();
+// return;
+// }
+// if (version != 1) {
+// returnCode = 31;
+// }
+
+ if (HostBlacklist.isBlocked(hostName)) {
+ returnCode = 11;
+ }
+
+ if (!username.matches("[A-Za-z0-9 ]+")) {
+ returnCode = 4;
+ }
+ if (username.length() > 12) {
+ returnCode = 8;
+ }
+
+ if (password.length() == 0) {
+ returnCode = 4;
+ }
+ GameSession session = new GameSession(channel, null, reconnecting);
+ Client cl = new Client(session, -1);
+ session.setPlayer(cl);
+ cl.playerName = username;
+ cl.playerName2 = cl.playerName;
+ cl.playerPass = password;
+ cl.outStream.packetEncryption = randomPair.getEncodingRandom();
+ cl.saveCharacter = false;
+ char first = username.charAt(0);
+ cl.properName = Character.toUpperCase(first)
+ + username.substring(1, username.length());
+ if (Connection.isNamedBanned(cl.playerName)) {
+ returnCode = 4;
+ }
+
+ if (PlayerHandler.isPlayerOn(username)) {
+ returnCode = 5;
+ }
+
+ if (PlayerHandler.getPlayerCount() >= GameConstants.MAX_PLAYERS) {
+ returnCode = 7;
+ }
+
+ if (GameEngine.updateServer) {
+ returnCode = 14;
+ }
+
+ if (returnCode == 2) {
+ int load = PlayerSave.loadGame(cl, cl.playerName, cl.playerPass);
+ if (load == 0)
+ cl.addStarter = true;
+ if (load == 3) {
+ returnCode = 3;
+ cl.saveFile = false;
+ } else {
+ for (int i = 0; i < cl.playerEquipment.length; i++) {
+ if (cl.playerEquipment[i] == 0) {
+ cl.playerEquipment[i] = -1;
+ cl.playerEquipmentN[i] = 0;
+ }
+ }
+ if (!GameEngine.playerHandler.newPlayerClient(cl)) {
+ returnCode = 7;
+ cl.saveFile = false;
+ } else {
+ cl.saveFile = true;
+ }
+ }
+ }
+ if (returnCode == 2) {
+ cl.saveCharacter = true;
+ ByteBuf response = channel.alloc().buffer(3);
+ response.writeByte((byte) 2);
+ if (cl.playerRights == 3) {
+ response.writeByte((byte) 2);
+ } else {
+ response.writeByte((byte) cl.playerRights);
+ }
+ response.writeByte((byte) 0);
+ channel.write(response);
+ } else {
+ System.out.println("returncode:" + returnCode);
+ ByteBuf buffer = channel.alloc().buffer(1);
+ buffer.writeByte(returnCode);
+ channel.writeAndFlush(buffer).addListener(ChannelFutureListener.CLOSE);
+ return;
+ }
+ cl.isActive = true;
+ channel.attr(ApolloHandler.SESSION_KEY).set(session);
+
+ channel.pipeline().addBefore("handler", "gameDecoder", new RS2ProtocolDecoder(randomPair.getDecodingRandom()));
+ channel.pipeline().remove("loginDecoder");
+ channel.pipeline().remove("loginEncoder");
+ }
+
+ /**
+ * Handles a login request.
+ *
+ * @param request The login request.
+ * @throws IOException If some I/O exception occurs.
+ */
+ private void handleLoginRequest(LoginRequest request) throws IOException {
+ load(channel, request.getCredentials(), request.getRandomPair(), request.isReconnecting());
+ }
+}
\ No newline at end of file
diff --git a/2006Scape Server/src/main/java/org/apollo/game/session/Session.java b/2006Scape Server/src/main/java/org/apollo/game/session/Session.java
new file mode 100644
index 00000000..9fa0233f
--- /dev/null
+++ b/2006Scape Server/src/main/java/org/apollo/game/session/Session.java
@@ -0,0 +1,49 @@
+package org.apollo.game.session;
+
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelHandlerContext;
+
+/**
+ * A session which is used as an attribute of a {@link ChannelHandlerContext} in Netty.
+ *
+ * @author Graham
+ */
+public abstract class Session {
+
+ /**
+ * The channel.
+ */
+ protected final Channel channel;
+
+ /**
+ * Creates a session for the specified channel.
+ *
+ * @param channel The channel.
+ */
+ public Session(Channel channel) {
+ this.channel = channel;
+ }
+
+ /**
+ * Destroys this session.
+ */
+ public abstract void destroy();
+
+ /**
+ * Processes a message received from the channel.
+ *
+ * @param message The message.
+ * @throws Exception If some error occurs.
+ */
+ public abstract void messageReceived(Object message) throws Exception;
+
+ /**
+ * Gets the channel.
+ *
+ * @return The channel.
+ */
+ protected final Channel getChannel() {
+ return channel;
+ }
+
+}
\ No newline at end of file
diff --git a/2006Scape Server/src/main/java/org/apollo/game/session/UpdateSession.java b/2006Scape Server/src/main/java/org/apollo/game/session/UpdateSession.java
new file mode 100644
index 00000000..0435b473
--- /dev/null
+++ b/2006Scape Server/src/main/java/org/apollo/game/session/UpdateSession.java
@@ -0,0 +1,48 @@
+package org.apollo.game.session;
+
+import io.netty.channel.Channel;
+import io.netty.handler.codec.http.HttpRequest;
+
+import org.apollo.jagcached.RequestWorkerPool;
+import org.apollo.net.codec.jaggrab.JagGrabRequest;
+import org.apollo.net.codec.update.OnDemandRequest;
+import org.apollo.net.update.UpdateDispatcher;
+
+/**
+ * An update session.
+ *
+ * @author Graham
+ */
+public final class UpdateSession extends Session {
+
+ /**
+ * Creates an update session for the specified channel.
+ *
+ * @param channel The channel.
+ * @param context The server context.
+ */
+ public UpdateSession(Channel channel) {
+ super(channel);
+ }
+
+ @Override
+ public void destroy() {
+ channel.close();
+ }
+
+ @Override
+ public void messageReceived(Object message) {
+ UpdateDispatcher dispatcher = RequestWorkerPool.getDispatcher();
+
+ if (message instanceof OnDemandRequest) {
+ dispatcher.dispatch(getChannel(), (OnDemandRequest) message);
+ } else if (message instanceof JagGrabRequest) {
+ dispatcher.dispatch(getChannel(), (JagGrabRequest) message);
+ } else if (message instanceof HttpRequest) {
+ dispatcher.dispatch(getChannel(), (HttpRequest) message);
+ } else {
+ throw new IllegalArgumentException("Unknown message type.");
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/2006Scape Server/src/main/java/org/apollo/game/session/package-info.java b/2006Scape Server/src/main/java/org/apollo/game/session/package-info.java
new file mode 100644
index 00000000..1d20a30a
--- /dev/null
+++ b/2006Scape Server/src/main/java/org/apollo/game/session/package-info.java
@@ -0,0 +1,6 @@
+/**
+ * Contains {@link org.apollo.game.session.Session} classes which are the equivalent of Netty's
+ * {@link io.netty.channel.Channel}s but are designed for Apollo to use itself - unlike Netty's which are purely
+ * designed for networking.
+ */
+package org.apollo.game.session;
\ No newline at end of file
diff --git a/2006Scape Server/src/main/java/org/apollo/jagcached/FileServer.java b/2006Scape Server/src/main/java/org/apollo/jagcached/FileServer.java
index df330ff4..77ef6685 100644
--- a/2006Scape Server/src/main/java/org/apollo/jagcached/FileServer.java
+++ b/2006Scape Server/src/main/java/org/apollo/jagcached/FileServer.java
@@ -1,25 +1,33 @@
package org.apollo.jagcached;
import java.io.File;
+import java.io.IOException;
+import java.net.BindException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
+import java.nio.file.Paths;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.logging.Level;
import java.util.logging.Logger;
+import org.apollo.cache.IndexedFileSystem;
+import org.apollo.game.session.ApolloHandler;
+import org.apollo.net.HttpChannelInitializer;
+import org.apollo.net.JagGrabChannelInitializer;
+import org.apollo.net.NetworkConstants;
+import org.apollo.net.ServiceChannelInitializer;
-import org.apollo.jagcached.dispatch.RequestWorkerPool;
-import org.apollo.jagcached.net.FileServerHandler;
-import org.apollo.jagcached.net.HttpPipelineFactory;
-import org.apollo.jagcached.net.JagGrabPipelineFactory;
-import org.apollo.jagcached.net.NetworkConstants;
-import org.apollo.jagcached.net.OnDemandPipelineFactory;
-import org.jboss.netty.bootstrap.ServerBootstrap;
-import org.jboss.netty.channel.ChannelPipelineFactory;
-import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
-import org.jboss.netty.util.HashedWheelTimer;
-import org.jboss.netty.util.Timer;
+import com.rs2.GameConstants;
+
+import io.netty.bootstrap.ServerBootstrap;
+import io.netty.channel.ChannelInitializer;
+import io.netty.channel.EventLoopGroup;
+import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.channel.socket.SocketChannel;
+import io.netty.channel.socket.nio.NioServerSocketChannel;
+import io.netty.util.HashedWheelTimer;
+import io.netty.util.Timer;
/**
* The core class of the file server.
@@ -27,47 +35,45 @@ import org.jboss.netty.util.Timer;
*/
public final class FileServer {
+ /**
+ * The {@link ServerBootstrap} for the HTTP listener.
+ */
+ private ServerBootstrap httpBootstrap;
+
+ /**
+ * The {@link ServerBootstrap} for the JAGGRAB listener.
+ */
+ private ServerBootstrap jaggrabBootstrap;
+
+ /**
+ * The event loop group.
+ */
+ private final EventLoopGroup loopGroup = new NioEventLoopGroup();
+
+ /**
+ * The {@link ServerBootstrap} for the service listener.
+ */
+ private final ServerBootstrap serviceBootstrap = new ServerBootstrap();
+
+
/**
* The logger for this class.
*/
private static final Logger logger = Logger.getLogger(FileServer.class.getName());
- /**
- * The entry point of the application.
- * @param args The command-line arguments.
- */
- public static void main(String[] args) {
- try {
- new FileServer().start();
- } catch (Throwable t) {
- logger.log(Level.SEVERE, "Error starting server.", t);
- }
- }
-
- /**
- * The executor service.
- */
- private final ExecutorService service = Executors.newCachedThreadPool();
/**
* The request worker pool.
*/
- private final RequestWorkerPool pool = new RequestWorkerPool();
-
- /**
- * The file server event handler.
- */
- private final FileServerHandler handler = new FileServerHandler();
-
- /**
- * The timer used for idle checking.
- */
- private final Timer timer = new HashedWheelTimer();
-
+ private RequestWorkerPool pool;
+
+
/**
* Starts the file server.
* @throws Exception if an error occurs.
*/
+ public SocketAddress service = new InetSocketAddress((GameConstants.WORLD == 1) ? 43594 : 43596 + GameConstants.WORLD);
+
public void start() throws Exception {
if (!new File(Constants.FILE_SYSTEM_DIR).exists())
{
@@ -84,37 +90,92 @@ public final class FileServer {
System.exit(1);
}
- logger.info("Starting workers...");
- pool.start();
-
- logger.info("Starting services...");
- try {
- start("HTTP", new HttpPipelineFactory(handler, timer), NetworkConstants.HTTP_PORT);
- } catch (Throwable t) {
- logger.log(Level.SEVERE, "Failed to start HTTP service.", t);
- logger.warning("HTTP will be unavailable. JAGGRAB will be used as a fallback by clients but this isn't reccomended!");
+ if(GameConstants.FILE_SERVER) {
+ httpBootstrap = new ServerBootstrap();
+ jaggrabBootstrap = new ServerBootstrap();
+ pool = new RequestWorkerPool();
+ logger.info("Starting workers...");
+ pool.start();
}
- start("JAGGRAB", new JagGrabPipelineFactory(handler, timer), NetworkConstants.JAGGRAB_PORT);
- start("ondemand", new OnDemandPipelineFactory(handler, timer), NetworkConstants.SERVICE_PORT);
+ logger.info("Starting services...");
+
+ init();
+ SocketAddress http = new InetSocketAddress(NetworkConstants.HTTP_PORT);
+ SocketAddress jaggrab = new InetSocketAddress(NetworkConstants.JAGGRAB_PORT);
+
+ bind(service, http, jaggrab);
logger.info("Ready for connections.");
}
/**
- * Starts the specified service.
- * @param name The name of the service.
- * @param pipelineFactory The pipeline factory.
- * @param port The port.
+ * Initialises the server.
+ *
+ * @param releaseName The class name of the current active {@link Release}.
+ * @throws Exception If an error occurs.
*/
- private void start(String name, ChannelPipelineFactory pipelineFactory, int port) {
- SocketAddress address = new InetSocketAddress(port);
+ public void init() throws Exception {
- logger.info("Binding " + name + " service to " + address + "...");
-
- ServerBootstrap bootstrap = new ServerBootstrap();
- bootstrap.setFactory(new NioServerSocketChannelFactory(service, service));
- bootstrap.setPipelineFactory(pipelineFactory);
- bootstrap.bind(address);
- }
+ serviceBootstrap.group(loopGroup);
+ if(GameConstants.FILE_SERVER) {
+ httpBootstrap.group(loopGroup);
+ jaggrabBootstrap.group(loopGroup);
+ }
+ ApolloHandler handler = new ApolloHandler();
+ ChannelInitializer service = new ServiceChannelInitializer(handler);
+ serviceBootstrap.channel(NioServerSocketChannel.class);
+ serviceBootstrap.childHandler(service);
+
+ if(!GameConstants.FILE_SERVER)
+ return;
+ ChannelInitializer http = new HttpChannelInitializer(handler);
+ httpBootstrap.channel(NioServerSocketChannel.class);
+ httpBootstrap.childHandler(http);
+
+ ChannelInitializer jaggrab = new JagGrabChannelInitializer(handler);
+ jaggrabBootstrap.channel(NioServerSocketChannel.class);
+ jaggrabBootstrap.childHandler(jaggrab);
+ }
+
+ /**
+ * Binds the server to the specified address.
+ *
+ * @param service The service address to bind to.
+ * @param http The HTTP address to bind to.
+ * @param jaggrab The JAGGRAB address to bind to.
+ * @throws BindException If the ServerBootstrap fails to bind to the SocketAddress.
+ */
+ public void bind(SocketAddress service, SocketAddress http, SocketAddress jaggrab) throws IOException {
+ logger.fine("Binding service listener to address: " + service + "...");
+ bind(serviceBootstrap, service);
+ if (GameConstants.FILE_SERVER) {
+ try {
+ logger.fine("Binding HTTP listener to address: " + http + "...");
+ bind(httpBootstrap, http);
+ } catch (IOException cause) {
+ logger.log(Level.WARNING, "Unable to bind to HTTP - JAGGRAB will be used as a fallback.", cause);
+ }
+
+ logger.fine("Binding JAGGRAB listener to address: " + jaggrab + "...");
+ bind(jaggrabBootstrap, jaggrab);
+ }
+ logger.info("Ready for connections.");
+ }
+
+ /**
+ * Attempts to bind the specified ServerBootstrap to the specified SocketAddress.
+ *
+ * @param bootstrap The ServerBootstrap.
+ * @param address The SocketAddress.
+ * @throws IOException If the ServerBootstrap fails to bind to the SocketAddress.
+ */
+ private void bind(ServerBootstrap bootstrap, SocketAddress address) throws IOException {
+ try {
+ bootstrap.bind(address).sync();
+ } catch (Exception cause) {
+ throw new IOException("Failed to bind to " + address, cause);
+ }
+ }
+
}
diff --git a/2006Scape Server/src/main/java/org/apollo/jagcached/dispatch/RequestWorkerPool.java b/2006Scape Server/src/main/java/org/apollo/jagcached/RequestWorkerPool.java
similarity index 60%
rename from 2006Scape Server/src/main/java/org/apollo/jagcached/dispatch/RequestWorkerPool.java
rename to 2006Scape Server/src/main/java/org/apollo/jagcached/RequestWorkerPool.java
index da3856df..87805a95 100644
--- a/2006Scape Server/src/main/java/org/apollo/jagcached/dispatch/RequestWorkerPool.java
+++ b/2006Scape Server/src/main/java/org/apollo/jagcached/RequestWorkerPool.java
@@ -1,13 +1,18 @@
-package org.apollo.jagcached.dispatch;
+package org.apollo.jagcached;
-import java.io.File;
+import java.nio.file.Path;
+import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
-import org.apollo.jagcached.Constants;
-import org.apollo.jagcached.fs.IndexedFileSystem;
+import org.apollo.cache.IndexedFileSystem;
+import org.apollo.net.update.HttpRequestWorker;
+import org.apollo.net.update.JagGrabRequestWorker;
+import org.apollo.net.update.OnDemandRequestWorker;
+import org.apollo.net.update.RequestWorker;
+import org.apollo.net.update.UpdateDispatcher;
/**
* A class which manages the pool of request workers.
@@ -36,6 +41,15 @@ public final class RequestWorkerPool {
*/
private final List> workers = new ArrayList>();
+ /**
+ * Gets the update dispatcher.
+ *
+ * @return The update dispatcher.
+ */
+ public static UpdateDispatcher getDispatcher() {
+ return dispatcher;
+ }
+
/**
* The request worker pool.
*/
@@ -43,17 +57,18 @@ public final class RequestWorkerPool {
int totalThreads = REQUEST_TYPES * THREADS_PER_REQUEST_TYPE;
service = Executors.newFixedThreadPool(totalThreads);
}
+ private static final UpdateDispatcher dispatcher = new UpdateDispatcher();
/**
* Starts the threads in the pool.
* @throws Exception if the file system cannot be created.
*/
public void start() throws Exception {
- File base = new File(Constants.FILE_SYSTEM_DIR);
+ Path base = Paths.get(Constants.FILE_SYSTEM_DIR);
for (int i = 0; i < THREADS_PER_REQUEST_TYPE; i++) {
- workers.add(new JagGrabRequestWorker(new IndexedFileSystem(base, true)));
- workers.add(new OnDemandRequestWorker(new IndexedFileSystem(base, true)));
- workers.add(new HttpRequestWorker(new IndexedFileSystem(base, true)));
+ workers.add(new JagGrabRequestWorker(dispatcher, new IndexedFileSystem(base, true)));
+ workers.add(new OnDemandRequestWorker(dispatcher, new IndexedFileSystem(base, true)));
+ workers.add(new HttpRequestWorker(dispatcher, new IndexedFileSystem(base, true)));
}
for (RequestWorker, ?> worker : workers) {
diff --git a/2006Scape Server/src/main/java/org/apollo/jagcached/dispatch/HttpRequestWorker.java b/2006Scape Server/src/main/java/org/apollo/jagcached/dispatch/HttpRequestWorker.java
deleted file mode 100644
index e3770f8d..00000000
--- a/2006Scape Server/src/main/java/org/apollo/jagcached/dispatch/HttpRequestWorker.java
+++ /dev/null
@@ -1,139 +0,0 @@
-package org.apollo.jagcached.dispatch;
-
-import java.io.File;
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.nio.charset.Charset;
-import java.util.Date;
-
-import org.apollo.jagcached.fs.IndexedFileSystem;
-import org.apollo.jagcached.resource.CombinedResourceProvider;
-import org.apollo.jagcached.resource.HypertextResourceProvider;
-import org.apollo.jagcached.resource.ResourceProvider;
-import org.apollo.jagcached.resource.VirtualResourceProvider;
-import org.jboss.netty.buffer.ChannelBuffer;
-import org.jboss.netty.buffer.ChannelBuffers;
-import org.jboss.netty.channel.Channel;
-import org.jboss.netty.channel.ChannelFutureListener;
-import org.jboss.netty.handler.codec.http.DefaultHttpResponse;
-import org.jboss.netty.handler.codec.http.HttpRequest;
-import org.jboss.netty.handler.codec.http.HttpResponse;
-import org.jboss.netty.handler.codec.http.HttpResponseStatus;
-
-/**
- * A worker which services HTTP requests.
- * @author Graham
- */
-public final class HttpRequestWorker extends RequestWorker {
-
- /**
- * The value of the server header.
- */
- private static final String SERVER_IDENTIFIER = "JAGeX/3.1";
-
- /**
- * The directory with web files.
- */
- private static final File WWW_DIRECTORY = new File("./data/www/");
-
- /**
- * The default character set.
- */
- private static final Charset CHARACTER_SET = Charset.forName("ISO-8859-1");
-
- /**
- * Creates the HTTP request worker.
- * @param fs The file system.
- */
- public HttpRequestWorker(IndexedFileSystem fs) {
- super(new CombinedResourceProvider(new VirtualResourceProvider(fs), new HypertextResourceProvider(WWW_DIRECTORY)));
- }
-
- @Override
- protected ChannelRequest nextRequest() throws InterruptedException {
- return RequestDispatcher.nextHttpRequest();
- }
-
- @Override
- protected void service(ResourceProvider provider, Channel channel, HttpRequest request) throws IOException {
- String path = request.getUri();
- ByteBuffer buf = provider.get(path);
-
- ChannelBuffer wrappedBuf;
- HttpResponseStatus status = HttpResponseStatus.OK;
-
- String mimeType = getMimeType(request.getUri());
-
- if (buf == null) {
- status = HttpResponseStatus.NOT_FOUND;
- wrappedBuf = createErrorPage(status, "The page you requested could not be found.");
- mimeType = "text/html";
- } else {
- wrappedBuf = ChannelBuffers.wrappedBuffer(buf);
- }
-
- HttpResponse resp = new DefaultHttpResponse(request.getProtocolVersion(), status);
-
- resp.setHeader("Date", new Date());
- resp.setHeader("Server", SERVER_IDENTIFIER);
- resp.setHeader("Content-type", mimeType + ", charset=" + CHARACTER_SET.name());
- resp.setHeader("Cache-control", "no-cache");
- resp.setHeader("Pragma", "no-cache");
- resp.setHeader("Expires", new Date(0));
- resp.setHeader("Connection", "close");
- resp.setHeader("Content-length", wrappedBuf.readableBytes());
- resp.setChunked(false);
- resp.setContent(wrappedBuf);
-
- channel.write(resp).addListener(ChannelFutureListener.CLOSE);
- }
-
- /**
- * Gets the MIME type of a file by its name.
- * @param name The file name.
- * @return The MIME type.
- */
- private String getMimeType(String name) {
- if (name.endsWith(".htm") || name.endsWith(".html")) {
- return "text/html";
- } else if (name.endsWith(".css")) {
- return "text/css";
- } else if (name.endsWith(".js")) {
- return "text/javascript";
- } else if (name.endsWith(".jpg") || name.endsWith(".jpeg")) {
- return "image/jpeg";
- } else if (name.endsWith(".gif")) {
- return "image/gif";
- } else if (name.endsWith(".png")) {
- return "image/png";
- } else if (name.endsWith(".txt")) {
- return "text/plain";
- }
- return "application/octect-stream";
- }
-
- /**
- * Creates an error page.
- * @param status The HTTP status.
- * @param description The error description.
- * @return The error page as a buffer.
- */
- private ChannelBuffer createErrorPage(HttpResponseStatus status, String description) {
- String title = status.getCode() + " " + status.getReasonPhrase();
-
- StringBuilder bldr = new StringBuilder();
-
- bldr.append("");
- bldr.append(title);
- bldr.append("");
- bldr.append(title);
- bldr.append("
");
- bldr.append(description);
- bldr.append("
");
- bldr.append(SERVER_IDENTIFIER);
- bldr.append(" Server");
-
- return ChannelBuffers.copiedBuffer(bldr.toString(), Charset.defaultCharset());
- }
-
-}
diff --git a/2006Scape Server/src/main/java/org/apollo/jagcached/dispatch/JagGrabRequestWorker.java b/2006Scape Server/src/main/java/org/apollo/jagcached/dispatch/JagGrabRequestWorker.java
deleted file mode 100644
index b2222a79..00000000
--- a/2006Scape Server/src/main/java/org/apollo/jagcached/dispatch/JagGrabRequestWorker.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package org.apollo.jagcached.dispatch;
-
-import java.io.IOException;
-import java.nio.ByteBuffer;
-
-import org.apollo.jagcached.fs.IndexedFileSystem;
-import org.apollo.jagcached.net.jaggrab.JagGrabRequest;
-import org.apollo.jagcached.net.jaggrab.JagGrabResponse;
-import org.apollo.jagcached.resource.ResourceProvider;
-import org.apollo.jagcached.resource.VirtualResourceProvider;
-import org.jboss.netty.buffer.ChannelBuffer;
-import org.jboss.netty.buffer.ChannelBuffers;
-import org.jboss.netty.channel.Channel;
-import org.jboss.netty.channel.ChannelFutureListener;
-
-/**
- * A worker which services JAGGRAB requests.
- * @author Graham
- */
-public final class JagGrabRequestWorker extends RequestWorker {
-
- /**
- * Creates the JAGGRAB request worker.
- * @param fs The file system.
- */
- public JagGrabRequestWorker(IndexedFileSystem fs) {
- super(new VirtualResourceProvider(fs));
- }
-
- @Override
- protected ChannelRequest nextRequest() throws InterruptedException {
- return RequestDispatcher.nextJagGrabRequest();
- }
-
- @Override
- protected void service(ResourceProvider provider, Channel channel, JagGrabRequest request) throws IOException {
- ByteBuffer buf = provider.get(request.getFilePath());
- if (buf == null) {
- channel.close();
- } else {
- ChannelBuffer wrapped = ChannelBuffers.wrappedBuffer(buf);
- channel.write(new JagGrabResponse(wrapped)).addListener(ChannelFutureListener.CLOSE);
- }
- }
-
-}
diff --git a/2006Scape Server/src/main/java/org/apollo/jagcached/dispatch/OnDemandRequestWorker.java b/2006Scape Server/src/main/java/org/apollo/jagcached/dispatch/OnDemandRequestWorker.java
deleted file mode 100644
index 98d4a421..00000000
--- a/2006Scape Server/src/main/java/org/apollo/jagcached/dispatch/OnDemandRequestWorker.java
+++ /dev/null
@@ -1,61 +0,0 @@
-package org.apollo.jagcached.dispatch;
-
-import java.io.IOException;
-import java.nio.ByteBuffer;
-
-
-import org.apollo.jagcached.fs.FileDescriptor;
-import org.apollo.jagcached.fs.IndexedFileSystem;
-import org.apollo.jagcached.net.ondemand.OnDemandRequest;
-import org.apollo.jagcached.net.ondemand.OnDemandResponse;
-import org.jboss.netty.buffer.ChannelBuffer;
-import org.jboss.netty.buffer.ChannelBuffers;
-import org.jboss.netty.channel.Channel;
-
-/**
- * A worker which services 'on-demand' requests.
- * @author Graham
- */
-public final class OnDemandRequestWorker extends RequestWorker {
-
- /**
- * The maximum length of a chunk, in bytes.
- */
- private static final int CHUNK_LENGTH = 500;
-
- /**
- * Creates the 'on-demand' request worker.
- * @param fs The file system.
- */
- public OnDemandRequestWorker(IndexedFileSystem fs) {
- super(fs);
- }
-
- @Override
- protected ChannelRequest nextRequest() throws InterruptedException {
- return RequestDispatcher.nextOnDemandRequest();
- }
-
- @Override
- protected void service(IndexedFileSystem fs, Channel channel, OnDemandRequest request) throws IOException {
- FileDescriptor desc = request.getFileDescriptor();
-
- ByteBuffer buf = fs.getFile(desc);
- int length = buf.remaining();
-
- for (int chunk = 0; buf.remaining() > 0; chunk++) {
- int chunkSize = buf.remaining();
- if (chunkSize > CHUNK_LENGTH) {
- chunkSize = CHUNK_LENGTH;
- }
-
- byte[] tmp = new byte[chunkSize];
- buf.get(tmp, 0, tmp.length);
- ChannelBuffer chunkData = ChannelBuffers.wrappedBuffer(tmp, 0, chunkSize);
-
- OnDemandResponse response = new OnDemandResponse(desc, length, chunk, chunkData);
- channel.write(response);
- }
- }
-
-}
diff --git a/2006Scape Server/src/main/java/org/apollo/jagcached/dispatch/RequestDispatcher.java b/2006Scape Server/src/main/java/org/apollo/jagcached/dispatch/RequestDispatcher.java
deleted file mode 100644
index da6af96d..00000000
--- a/2006Scape Server/src/main/java/org/apollo/jagcached/dispatch/RequestDispatcher.java
+++ /dev/null
@@ -1,112 +0,0 @@
-package org.apollo.jagcached.dispatch;
-
-import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.PriorityBlockingQueue;
-
-
-import org.apollo.jagcached.net.jaggrab.JagGrabRequest;
-import org.apollo.jagcached.net.ondemand.OnDemandRequest;
-import org.jboss.netty.channel.Channel;
-import org.jboss.netty.handler.codec.http.HttpRequest;
-
-/**
- * A class which dispatches requests to worker threads.
- * @author Graham
- */
-public final class RequestDispatcher {
-
- /**
- * The maximum size of a queue before requests are rejected.
- */
- private static final int MAXIMUM_QUEUE_SIZE = 1024;
-
- /**
- * A queue for pending 'on-demand' requests.
- */
- private static final BlockingQueue> onDemandQueue = new PriorityBlockingQueue>();
-
- /**
- * A queue for pending JAGGRAB requests.
- */
- private static final BlockingQueue> jagGrabQueue = new LinkedBlockingQueue>();
-
- /**
- * A queue for pending HTTP requests.
- */
- private static final BlockingQueue> httpQueue = new LinkedBlockingQueue>();
-
- /**
- * Gets the next 'on-demand' request from the queue, blocking if none are
- * available.
- * @return The 'on-demand' request.
- * @throws InterruptedException if the thread is interrupted.
- */
- static ChannelRequest nextOnDemandRequest() throws InterruptedException {
- return onDemandQueue.take();
- }
-
- /**
- * Gets the next JAGGRAB request from the queue, blocking if none are
- * available.
- * @return The JAGGRAB request.
- * @throws InterruptedException if the thread is interrupted.
- */
- static ChannelRequest nextJagGrabRequest() throws InterruptedException {
- return jagGrabQueue.take();
- }
-
- /**
- * Gets the next HTTP request from the queue, blocking if none are
- * available.
- * @return The HTTP request.
- * @throws InterruptedException if the thread is interrupted.
- */
- static ChannelRequest nextHttpRequest() throws InterruptedException {
- return httpQueue.take();
- }
-
- /**
- * Dispatches an 'on-demand' request.
- * @param channel The channel.
- * @param request The request.
- */
- public static void dispatch(Channel channel, OnDemandRequest request) {
- if (onDemandQueue.size() >= MAXIMUM_QUEUE_SIZE) {
- channel.close();
- }
- onDemandQueue.add(new ChannelRequest(channel, request));
- }
-
- /**
- * Dispatches a JAGGRAB request.
- * @param channel The channel.
- * @param request The request.
- */
- public static void dispatch(Channel channel, JagGrabRequest request) {
- if (jagGrabQueue.size() >= MAXIMUM_QUEUE_SIZE) {
- channel.close();
- }
- jagGrabQueue.add(new ChannelRequest(channel, request));
- }
-
- /**
- * Dispatches a HTTP request.
- * @param channel The channel.
- * @param request The request.
- */
- public static void dispatch(Channel channel, HttpRequest request) {
- if (httpQueue.size() >= MAXIMUM_QUEUE_SIZE) {
- channel.close();
- }
- httpQueue.add(new ChannelRequest(channel, request));
- }
-
- /**
- * Default private constructor to prevent instantiation.
- */
- private RequestDispatcher() {
-
- }
-
-}
diff --git a/2006Scape Server/src/main/java/org/apollo/jagcached/fs/IndexedFileSystem.java b/2006Scape Server/src/main/java/org/apollo/jagcached/fs/IndexedFileSystem.java
deleted file mode 100644
index 2e53372b..00000000
--- a/2006Scape Server/src/main/java/org/apollo/jagcached/fs/IndexedFileSystem.java
+++ /dev/null
@@ -1,361 +0,0 @@
-package org.apollo.jagcached.fs;
-
-import java.io.Closeable;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.RandomAccessFile;
-import java.nio.ByteBuffer;
-import java.util.zip.CRC32;
-
-/**
- * A file system based on top of the operating system's file system. It
- * consists of a data file and index files. Index files point to blocks in the
- * data file, which contains the actual data.
- * @author Graham
- * @author Ryley Kimmel
- */
-public final class IndexedFileSystem implements Closeable {
-
- /**
- * Read only flag.
- */
- private final boolean readOnly;
-
- /**
- * The index files.
- */
- private RandomAccessFile[] indices = new RandomAccessFile[256];
-
- /**
- * The data file.
- */
- private RandomAccessFile data;
-
- /**
- * The cached CRC table.
- */
- private ByteBuffer crcTable;
-
- /**
- * Creates the file system with the specified base directory.
- * @param base The base directory.
- * @param readOnly A flag indicating if the file system will be read only.
- * @throws Exception if the file system is invalid.
- */
- public IndexedFileSystem(File base, boolean readOnly) throws Exception {
- this.readOnly = readOnly;
- detectLayout(base);
- }
-
- /**
- * Checks if this {@link IndexedFileSystem} is read only.
- * @return {@code true} if so, {@code false} if not.
- */
- public boolean isReadOnly() {
- return readOnly;
- }
-
- /**
- * Automatically detect the layout of the specified directory.
- * @param base The base directory.
- * @throws Exception if the file system is invalid.
- */
- private void detectLayout(File base) throws Exception {
- int indexCount = 0;
- for (int index = 0; index < indices.length; index++) {
- File f = new File(base.getAbsolutePath() + "/main_file_cache.idx" + index);
- if (f.exists() && !f.isDirectory()) {
- indexCount++;
- indices[index] = new RandomAccessFile(f, readOnly ? "r" : "rw");
- }
- }
- if (indexCount <= 0) {
- throw new Exception("No index file(s) present");
- }
-
- File dataFile = new File(base.getAbsolutePath() + "/main_file_cache.dat");
- if (dataFile.exists() && !dataFile.isDirectory()) {
- data = new RandomAccessFile(dataFile, readOnly ? "r" : "rw");
- } else {
- throw new Exception("No data file present");
- }
- }
-
- /**
- * Gets the index of a file.
- * @param fd The {@link FileDescriptor} which points to the file.
- * @return The {@link Index}.
- * @throws IOException if an I/O error occurs.
- */
- private Index getIndex(FileDescriptor fd) throws IOException {
- int index = fd.getType();
- if (index < 0 || index >= indices.length) {
- throw new IndexOutOfBoundsException();
- }
-
- byte[] buffer = new byte[FileSystemConstants.INDEX_SIZE];
- RandomAccessFile indexFile = indices[index];
- synchronized (indexFile) {
- long ptr = (long) fd.getFile() * (long) FileSystemConstants.INDEX_SIZE;
- if (ptr >= 0 && indexFile.length() >= (ptr + FileSystemConstants.INDEX_SIZE)) {
- indexFile.seek(ptr);
- indexFile.readFully(buffer);
- } else {
- throw new FileNotFoundException();
- }
- }
-
- return Index.decode(buffer);
- }
-
- /**
- * Gets the number of files with the specified type.
- * @param type The type.
- * @return The number of files.
- * @throws IOException if an I/O error occurs.
- */
- private int getFileCount(int type) throws IOException {
- if (type < 0 || type >= indices.length) {
- throw new IndexOutOfBoundsException();
- }
-
- RandomAccessFile indexFile = indices[type];
- synchronized (indexFile) {
- return (int) (indexFile.length() / FileSystemConstants.INDEX_SIZE);
- }
- }
-
- /**
- * Gets the CRC table.
- * @return The CRC table.
- * @throws IOException if an I/O erorr occurs.
- */
- public ByteBuffer getCrcTable() throws IOException {
- if (readOnly) {
- synchronized (this) {
- if (crcTable != null) {
- return crcTable.slice();
- }
- }
-
- // the number of archives
- int archives = getFileCount(0);
-
- // the hash
- int hash = 1234;
-
- // the CRCs
- int[] crcs = new int[archives];
-
- // calculate the CRCs
- CRC32 crc32 = new CRC32();
- for (int i = 1; i < crcs.length; i++) {
- crc32.reset();
-
- ByteBuffer bb = getFile(0, i);
- byte[] bytes = new byte[bb.remaining()];
- bb.get(bytes, 0, bytes.length);
- crc32.update(bytes, 0, bytes.length);
-
- crcs[i] = (int) crc32.getValue();
- }
-
- // hash the CRCs and place them in the buffer
- ByteBuffer buf = ByteBuffer.allocate(crcs.length * 4 + 4);
- for (int i = 0; i < crcs.length; i++) {
- hash = (hash << 1) + crcs[i];
- buf.putInt(crcs[i]);
- }
-
- // place the hash into the buffer
- buf.putInt(hash);
- buf.flip();
-
- synchronized (this) {
- crcTable = buf;
- return crcTable.slice();
- }
- } else {
- throw new IOException("cannot get CRC table from a writable file system");
- }
- }
-
- /**
- * Gets a file.
- * @param type The file type.
- * @param file The file id.
- * @return A {@link ByteBuffer} which contains the contents of the file.
- * @throws IOException if an I/O error occurs.
- */
- public ByteBuffer getFile(int type, int file) throws IOException {
- return getFile(new FileDescriptor(type, file));
- }
-
- /**
- * Gets a file.
- * @param fd The {@link FileDescriptor} which points to the file.
- * @return A {@link ByteBuffer} which contains the contents of the file.
- * @throws IOException if an I/O error occurs.
- */
- public ByteBuffer getFile(FileDescriptor fd) throws IOException {
- Index index = getIndex(fd);
- ByteBuffer buffer = ByteBuffer.allocate(index.getSize());
-
- // calculate some initial values
- long ptr = (long) index.getBlock() * (long) FileSystemConstants.BLOCK_SIZE;
- int read = 0;
- int size = index.getSize();
- int blocks = size / FileSystemConstants.CHUNK_SIZE;
- if (size % FileSystemConstants.CHUNK_SIZE != 0) {
- blocks++;
- }
-
- for (int i = 0; i < blocks; i++) {
-
- // read header
- byte[] header = new byte[FileSystemConstants.HEADER_SIZE];
- synchronized (data) {
- data.seek(ptr);
- data.readFully(header);
- }
-
- // increment pointers
- ptr += FileSystemConstants.HEADER_SIZE;
-
- // parse header
- int nextFile = ((header[0] & 0xFF) << 8) | (header[1] & 0xFF);
- int curChunk = ((header[2] & 0xFF) << 8) | (header[3] & 0xFF);
- int nextBlock = ((header[4] & 0xFF) << 16) | ((header[5] & 0xFF) << 8) | (header[6] & 0xFF);
- int nextType = header[7] & 0xFF;
-
- // check expected chunk id is correct
- if (i != curChunk) {
- throw new IOException("Chunk id mismatch.");
- }
-
- // calculate how much we can read
- int chunkSize = size - read;
- if (chunkSize > FileSystemConstants.CHUNK_SIZE) {
- chunkSize = FileSystemConstants.CHUNK_SIZE;
- }
-
- // read the next chunk and put it in the buffer
- byte[] chunk = new byte[chunkSize];
- synchronized (data) {
- data.seek(ptr);
- data.readFully(chunk);
- }
- buffer.put(chunk);
-
- // increment pointers
- read += chunkSize;
- ptr = (long) nextBlock * (long) FileSystemConstants.BLOCK_SIZE;
-
- // if we still have more data to read, check the validity of the
- // header
- if (size > read) {
- if (nextType != (fd.getType() + 1)) {
- throw new IOException("File type mismatch.");
- }
-
- if (nextFile != fd.getFile()) {
- throw new IOException("File id mismatch.");
- }
- }
- }
-
- buffer.flip();
- return buffer;
- }
-
- public byte[] getFileBytes(int type, int file) throws IOException {
- return getFileBytes(new FileDescriptor(type, file));
- }
-
- public byte[] getFileBytes(FileDescriptor fd) throws IOException {
- Index index = getIndex(fd);
- byte[] decompressed = new byte[index.getSize()];
-
- // calculate some initial values
- long ptr = (long) index.getBlock() * (long) FileSystemConstants.BLOCK_SIZE;
- int read = 0;
- int size = index.getSize();
- int blocks = size / FileSystemConstants.CHUNK_SIZE;
- if (size % FileSystemConstants.CHUNK_SIZE != 0) {
- blocks++;
- }
-
- for (int i = 0; i < blocks; i++) {
-
- // read header
- byte[] header = new byte[FileSystemConstants.HEADER_SIZE];
- synchronized (data) {
- data.seek(ptr);
- data.readFully(header);
- }
-
- // increment pointers
- ptr += FileSystemConstants.HEADER_SIZE;
-
- // parse header
- int nextFile = ((header[0] & 0xFF) << 8) | (header[1] & 0xFF);
- int curChunk = ((header[2] & 0xFF) << 8) | (header[3] & 0xFF);
- int nextBlock = ((header[4] & 0xFF) << 16) | ((header[5] & 0xFF) << 8) | (header[6] & 0xFF);
- int nextType = header[7] & 0xFF;
-
- // check expected chunk id is correct
- if (i != curChunk) {
- throw new IOException("Chunk id mismatch.");
- }
-
- // calculate how much we can read
- int chunkSize = size - read;
- if (chunkSize > FileSystemConstants.CHUNK_SIZE) {
- chunkSize = FileSystemConstants.CHUNK_SIZE;
- }
-
- // read the next chunk and put it in the buffer
- synchronized (data) {
- data.seek(ptr);
- data.readFully(decompressed, read, chunkSize);
- }
-
- // increment pointers
- read += chunkSize;
- ptr = (long) nextBlock * (long) FileSystemConstants.BLOCK_SIZE;
-
- // if we still have more data to read, check the validity of the
- // header
- if (size > read) {
- if (nextType != (fd.getType() + 1)) {
- throw new IOException("File type mismatch.");
- }
-
- if (nextFile != fd.getFile()) {
- throw new IOException("File id mismatch.");
- }
- }
- }
-
- return decompressed;
- }
-
- @Override
- public void close() throws IOException {
- if (data != null) {
- synchronized (data) {
- data.close();
- }
- }
-
- for (RandomAccessFile index : indices) {
- if (index != null) {
- synchronized (index) {
- index.close();
- }
- }
- }
- }
-
-}
diff --git a/2006Scape Server/src/main/java/org/apollo/jagcached/net/FileServerHandler.java b/2006Scape Server/src/main/java/org/apollo/jagcached/net/FileServerHandler.java
deleted file mode 100644
index 4383724d..00000000
--- a/2006Scape Server/src/main/java/org/apollo/jagcached/net/FileServerHandler.java
+++ /dev/null
@@ -1,63 +0,0 @@
-package org.apollo.jagcached.net;
-
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-
-import org.apollo.jagcached.FileServer;
-import org.apollo.jagcached.dispatch.RequestDispatcher;
-import org.apollo.jagcached.net.jaggrab.JagGrabRequest;
-import org.apollo.jagcached.net.ondemand.OnDemandRequest;
-import org.apollo.jagcached.net.service.ServiceRequest;
-import org.apollo.jagcached.net.service.ServiceResponse;
-import org.jboss.netty.channel.ChannelHandlerContext;
-import org.jboss.netty.channel.ExceptionEvent;
-import org.jboss.netty.channel.MessageEvent;
-import org.jboss.netty.handler.codec.http.HttpRequest;
-import org.jboss.netty.handler.timeout.IdleStateAwareChannelUpstreamHandler;
-import org.jboss.netty.handler.timeout.IdleStateEvent;
-
-/**
- * An {@link IdleStateAwareChannelUpstreamHandler} for the {@link FileServer}.
- * @author Graham
- */
-public final class FileServerHandler extends IdleStateAwareChannelUpstreamHandler {
-
- /**
- * The logger for this class.
- */
- private static final Logger logger = Logger.getLogger(FileServerHandler.class.getName());
-
- @Override
- public void channelIdle(ChannelHandlerContext ctx, IdleStateEvent e) throws Exception {
- e.getChannel().close();
- }
-
- @Override
- public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
- Object msg = e.getMessage();
- if (msg instanceof ServiceRequest) {
- ServiceRequest request = (ServiceRequest) msg;
- if (request.getId() != ServiceRequest.SERVICE_ONDEMAND) {
- e.getChannel().close();
- } else {
- e.getChannel().write(new ServiceResponse());
- }
- } else if (msg instanceof OnDemandRequest) {
- RequestDispatcher.dispatch(e.getChannel(), (OnDemandRequest) msg);
- } else if (msg instanceof JagGrabRequest) {
- RequestDispatcher.dispatch(e.getChannel(), (JagGrabRequest) msg);
- } else if (msg instanceof HttpRequest) {
- RequestDispatcher.dispatch(e.getChannel(), (HttpRequest) msg);
- } else {
- throw new Exception("unknown message type");
- }
- }
-
- @Override
- public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception {
- logger.log(Level.SEVERE, "Exception occured, closing channel...", e.getCause());
- e.getChannel().close();
- }
-
-}
diff --git a/2006Scape Server/src/main/java/org/apollo/jagcached/net/HttpPipelineFactory.java b/2006Scape Server/src/main/java/org/apollo/jagcached/net/HttpPipelineFactory.java
deleted file mode 100644
index 66df879d..00000000
--- a/2006Scape Server/src/main/java/org/apollo/jagcached/net/HttpPipelineFactory.java
+++ /dev/null
@@ -1,61 +0,0 @@
-package org.apollo.jagcached.net;
-
-import org.jboss.netty.channel.ChannelPipeline;
-import org.jboss.netty.channel.ChannelPipelineFactory;
-import org.jboss.netty.channel.Channels;
-import org.jboss.netty.handler.codec.http.HttpChunkAggregator;
-import org.jboss.netty.handler.codec.http.HttpRequestDecoder;
-import org.jboss.netty.handler.codec.http.HttpResponseEncoder;
-import org.jboss.netty.handler.timeout.IdleStateHandler;
-import org.jboss.netty.util.Timer;
-
-/**
- * A {@link ChannelPipelineFactory} for the HTTP protocol.
- * @author Graham
- */
-public final class HttpPipelineFactory implements ChannelPipelineFactory {
-
- /**
- * The maximum length of a request, in bytes.
- */
- private static final int MAX_REQUEST_LENGTH = 8192;
-
- /**
- * The file server event handler.
- */
- private final FileServerHandler handler;
-
- /**
- * The timer used for idle checking.
- */
- private final Timer timer;
-
- /**
- * Creates the HTTP pipeline factory.
- * @param handler The file server event handler.
- * @param timer The timer used for idle checking.
- */
- public HttpPipelineFactory(FileServerHandler handler, Timer timer) {
- this.handler = handler;
- this.timer = timer;
- }
-
- @Override
- public ChannelPipeline getPipeline() throws Exception {
- ChannelPipeline pipeline = Channels.pipeline();
-
- // decoders
- pipeline.addLast("decoder", new HttpRequestDecoder());
- pipeline.addLast("chunker", new HttpChunkAggregator(MAX_REQUEST_LENGTH));
-
- // encoders
- pipeline.addLast("encoder", new HttpResponseEncoder());
-
- // handler
- pipeline.addLast("timeout", new IdleStateHandler(timer, NetworkConstants.IDLE_TIME, 0, 0));
- pipeline.addLast("handler", handler);
-
- return pipeline;
- }
-
-}
diff --git a/2006Scape Server/src/main/java/org/apollo/jagcached/net/JagGrabPipelineFactory.java b/2006Scape Server/src/main/java/org/apollo/jagcached/net/JagGrabPipelineFactory.java
deleted file mode 100644
index 5c0f7250..00000000
--- a/2006Scape Server/src/main/java/org/apollo/jagcached/net/JagGrabPipelineFactory.java
+++ /dev/null
@@ -1,86 +0,0 @@
-package org.apollo.jagcached.net;
-
-import java.nio.charset.Charset;
-
-
-import org.apollo.jagcached.net.jaggrab.JagGrabRequestDecoder;
-import org.apollo.jagcached.net.jaggrab.JagGrabResponseEncoder;
-import org.jboss.netty.buffer.ChannelBuffer;
-import org.jboss.netty.buffer.ChannelBuffers;
-import org.jboss.netty.channel.ChannelPipeline;
-import org.jboss.netty.channel.ChannelPipelineFactory;
-import org.jboss.netty.channel.Channels;
-import org.jboss.netty.handler.codec.frame.DelimiterBasedFrameDecoder;
-import org.jboss.netty.handler.codec.string.StringDecoder;
-import org.jboss.netty.handler.timeout.IdleStateHandler;
-import org.jboss.netty.util.Timer;
-
-/**
- * A {@link ChannelPipelineFactory} for the JAGGRAB protocol.
- * @author Graham
- */
-public final class JagGrabPipelineFactory implements ChannelPipelineFactory {
-
- /**
- * The maximum length of a request, in bytes.
- */
- private static final int MAX_REQUEST_LENGTH = 8192;
-
- /**
- * The character set used in the request.
- */
- private static final Charset JAGGRAB_CHARSET = Charset.forName("US-ASCII");
-
- /**
- * A buffer with two line feed (LF) characters in it.
- */
- private static final ChannelBuffer DOUBLE_LINE_FEED_DELIMITER = ChannelBuffers.buffer(2);
-
- /**
- * Populates the double line feed buffer.
- */
- static {
- DOUBLE_LINE_FEED_DELIMITER.writeByte(10);
- DOUBLE_LINE_FEED_DELIMITER.writeByte(10);
- }
-
- /**
- * The file server event handler.
- */
- private final FileServerHandler handler;
-
- /**
- * The timer used for idle checking.
- */
- private final Timer timer;
-
- /**
- * Creates a {@code JAGGRAB} pipeline factory.
- * @param handler The file server event handler.
- * @param timer The timer used for idle checking.
- */
- public JagGrabPipelineFactory(FileServerHandler handler, Timer timer) {
- this.handler = handler;
- this.timer = timer;
- }
-
- @Override
- public ChannelPipeline getPipeline() throws Exception {
- ChannelPipeline pipeline = Channels.pipeline();
-
- // decoders
- pipeline.addLast("framer", new DelimiterBasedFrameDecoder(MAX_REQUEST_LENGTH, DOUBLE_LINE_FEED_DELIMITER));
- pipeline.addLast("string-decoder", new StringDecoder(JAGGRAB_CHARSET));
- pipeline.addLast("jaggrab-decoder", new JagGrabRequestDecoder());
-
- // encoders
- pipeline.addLast("jaggrab-encoder", new JagGrabResponseEncoder());
-
- // handler
- pipeline.addLast("timeout", new IdleStateHandler(timer, NetworkConstants.IDLE_TIME, 0, 0));
- pipeline.addLast("handler", handler);
-
- return pipeline;
- }
-
-}
diff --git a/2006Scape Server/src/main/java/org/apollo/jagcached/net/NetworkConstants.java b/2006Scape Server/src/main/java/org/apollo/jagcached/net/NetworkConstants.java
deleted file mode 100644
index 04c2bf76..00000000
--- a/2006Scape Server/src/main/java/org/apollo/jagcached/net/NetworkConstants.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package org.apollo.jagcached.net;
-
-/**
- * A class which holds network-related constants.
- * @author Graham
- */
-public final class NetworkConstants {
-
- /**
- * The HTTP port.
- */
- public static final int HTTP_PORT = 8080;
-
- /**
- * The JAGGRAB port.
- */
- public static final int JAGGRAB_PORT = 43595;
-
- /**
- * The service port (which is also used for the 'on-demand' protocol).
- */
- public static final int SERVICE_PORT = 43596;
-
- /**
- * The number of seconds a channel can be idle before being closed
- * automatically.
- */
- public static final int IDLE_TIME = 15;
-
- /**
- * Default private constructor to prevent instantiaton.
- */
- private NetworkConstants() {
-
- }
-
-}
diff --git a/2006Scape Server/src/main/java/org/apollo/jagcached/net/OnDemandPipelineFactory.java b/2006Scape Server/src/main/java/org/apollo/jagcached/net/OnDemandPipelineFactory.java
deleted file mode 100644
index 7dcad1e2..00000000
--- a/2006Scape Server/src/main/java/org/apollo/jagcached/net/OnDemandPipelineFactory.java
+++ /dev/null
@@ -1,59 +0,0 @@
-package org.apollo.jagcached.net;
-
-
-import org.apollo.jagcached.net.ondemand.OnDemandRequestDecoder;
-import org.apollo.jagcached.net.ondemand.OnDemandResponseEncoder;
-import org.apollo.jagcached.net.service.ServiceRequestDecoder;
-import org.apollo.jagcached.net.service.ServiceResponseEncoder;
-import org.jboss.netty.channel.ChannelPipeline;
-import org.jboss.netty.channel.ChannelPipelineFactory;
-import org.jboss.netty.channel.Channels;
-import org.jboss.netty.handler.timeout.IdleStateHandler;
-import org.jboss.netty.util.Timer;
-
-/**
- * A {@link ChannelPipelineFactory} for the 'on-demand' protocol.
- * @author Graham
- */
-public final class OnDemandPipelineFactory implements ChannelPipelineFactory {
-
- /**
- * The file server event handler.
- */
- private final FileServerHandler handler;
-
- /**
- * The timer used for idle checking.
- */
- private final Timer timer;
-
- /**
- * Creates an 'on-demand' pipeline factory.
- * @param handler The file server event handler.
- * @param timer The timer used for idle checking.
- */
- public OnDemandPipelineFactory(FileServerHandler handler, Timer timer) {
- this.handler = handler;
- this.timer = timer;
- }
-
- @Override
- public ChannelPipeline getPipeline() throws Exception {
- ChannelPipeline pipeline = Channels.pipeline();
-
- // decoders
- pipeline.addLast("serviceDecoder", new ServiceRequestDecoder());
- pipeline.addLast("decoder", new OnDemandRequestDecoder());
-
- // encoders
- pipeline.addLast("serviceEncoder", new ServiceResponseEncoder());
- pipeline.addLast("encoder", new OnDemandResponseEncoder());
-
- // handler
- pipeline.addLast("timeout", new IdleStateHandler(timer, NetworkConstants.IDLE_TIME, 0, 0));
- pipeline.addLast("handler", handler);
-
- return pipeline;
- }
-
-}
diff --git a/2006Scape Server/src/main/java/org/apollo/jagcached/net/jaggrab/JagGrabRequestDecoder.java b/2006Scape Server/src/main/java/org/apollo/jagcached/net/jaggrab/JagGrabRequestDecoder.java
deleted file mode 100644
index 924d5bac..00000000
--- a/2006Scape Server/src/main/java/org/apollo/jagcached/net/jaggrab/JagGrabRequestDecoder.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package org.apollo.jagcached.net.jaggrab;
-
-import org.jboss.netty.channel.Channel;
-import org.jboss.netty.channel.ChannelHandlerContext;
-import org.jboss.netty.handler.codec.oneone.OneToOneDecoder;
-
-/**
- * A {@link OneToOneDecoder} for the JAGGRAB protocol.
- * @author Graham
- */
-public final class JagGrabRequestDecoder extends OneToOneDecoder {
-
- @Override
- protected Object decode(ChannelHandlerContext ctx, Channel c, Object msg) throws Exception {
- if (msg instanceof String) {
- String str = ((String) msg);
- if (str.startsWith("JAGGRAB /")) {
- String filePath = str.substring(8).trim();
- return new JagGrabRequest(filePath);
- } else {
- throw new Exception("corrupted request line");
- }
- }
- return msg;
- }
-
-}
diff --git a/2006Scape Server/src/main/java/org/apollo/jagcached/net/jaggrab/JagGrabResponseEncoder.java b/2006Scape Server/src/main/java/org/apollo/jagcached/net/jaggrab/JagGrabResponseEncoder.java
deleted file mode 100644
index c24e1066..00000000
--- a/2006Scape Server/src/main/java/org/apollo/jagcached/net/jaggrab/JagGrabResponseEncoder.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package org.apollo.jagcached.net.jaggrab;
-
-import org.jboss.netty.channel.Channel;
-import org.jboss.netty.channel.ChannelHandlerContext;
-import org.jboss.netty.handler.codec.oneone.OneToOneEncoder;
-
-/**
- * A {@link OneToOneEncoder} for the JAGGRAB protocol.
- * @author Graham
- */
-public final class JagGrabResponseEncoder extends OneToOneEncoder {
-
- @Override
- protected Object encode(ChannelHandlerContext ctx, Channel c, Object msg) throws Exception {
- if (msg instanceof JagGrabResponse) {
- JagGrabResponse resp = (JagGrabResponse) msg;
- return resp.getFileData();
- }
- return msg;
- }
-
-}
diff --git a/2006Scape Server/src/main/java/org/apollo/jagcached/net/ondemand/OnDemandRequest.java b/2006Scape Server/src/main/java/org/apollo/jagcached/net/ondemand/OnDemandRequest.java
deleted file mode 100644
index 0eac7c3f..00000000
--- a/2006Scape Server/src/main/java/org/apollo/jagcached/net/ondemand/OnDemandRequest.java
+++ /dev/null
@@ -1,109 +0,0 @@
-package org.apollo.jagcached.net.ondemand;
-
-import org.apollo.jagcached.fs.FileDescriptor;
-
-/**
- * Represents a single 'on-demand' request.
- * @author Graham
- * @author Ryley Kimmel
- */
-public final class OnDemandRequest implements Comparable {
-
- /**
- * An enumeration containing the different request priorities.
- * @author Graham
- */
- public enum Priority {
-
- /**
- * High priority - used in-game when data is required immediately but
- * has not yet been received.
- */
- HIGH,
-
- /**
- * Medium priority - used while loading the 'bare minimum' required to
- * run the game.
- */
- MEDIUM,
-
- /**
- * Low priority - used when a file is not required urgently. The client
- * login screen says "loading extra files.." when low priority loading
- * is being performed.
- */
- LOW;
-
- /**
- * Converts the integer value to a priority.
- * @param v The integer value.
- * @return The priority.
- * @throws IllegalArgumentException if the value is outside of the
- * range 1-3 inclusive.
- */
- public static Priority valueOf(int v) {
- switch (v) {
- case 0:
- return HIGH;
- case 1:
- return MEDIUM;
- case 2:
- return LOW;
- default:
- throw new IllegalArgumentException("priority out of range");
- }
- }
-
- }
-
- /**
- * The file descriptor.
- */
- private final FileDescriptor fileDescriptor;
-
- /**
- * The request priority.
- */
- private final Priority priority;
-
- /**
- * Creates the 'on-demand' request.
- * @param fileDescriptor The file descriptor.
- * @param priority The priority.
- */
- public OnDemandRequest(FileDescriptor fileDescriptor, Priority priority) {
- this.fileDescriptor = fileDescriptor;
- this.priority = priority;
- }
-
- /**
- * Gets the file descriptor.
- * @return The file descriptor.
- */
- public FileDescriptor getFileDescriptor() {
- return fileDescriptor;
- }
-
- /**
- * Gets the priority.
- * @return The priority.
- */
- public Priority getPriority() {
- return priority;
- }
-
- @Override
- public int compareTo(OnDemandRequest o) {
- int thisPriority = priority.ordinal();
- int otherPriority = o.priority.ordinal();
-
- if (thisPriority < otherPriority) {
- return 1;
- } else if (thisPriority == otherPriority) {
- return 0;
- } else {
- return -1;
- }
- }
-
-}
diff --git a/2006Scape Server/src/main/java/org/apollo/jagcached/net/ondemand/OnDemandRequestDecoder.java b/2006Scape Server/src/main/java/org/apollo/jagcached/net/ondemand/OnDemandRequestDecoder.java
deleted file mode 100644
index 130de142..00000000
--- a/2006Scape Server/src/main/java/org/apollo/jagcached/net/ondemand/OnDemandRequestDecoder.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package org.apollo.jagcached.net.ondemand;
-
-
-import org.apollo.jagcached.fs.FileDescriptor;
-import org.apollo.jagcached.net.ondemand.OnDemandRequest.Priority;
-import org.jboss.netty.buffer.ChannelBuffer;
-import org.jboss.netty.channel.Channel;
-import org.jboss.netty.channel.ChannelHandlerContext;
-import org.jboss.netty.handler.codec.frame.FrameDecoder;
-
-/**
- * A {@link FrameDecoder} for the 'on-demand' protocol.
- * @author Graham
- */
-public final class OnDemandRequestDecoder extends FrameDecoder {
-
- @Override
- protected Object decode(ChannelHandlerContext ctx, Channel c, ChannelBuffer buf) throws Exception {
- if (buf.readableBytes() >= 4) {
- int type = buf.readUnsignedByte() + 1;
- int file = buf.readUnsignedShort();
- int priority = buf.readUnsignedByte();
-
- FileDescriptor desc = new FileDescriptor(type, file);
- Priority p = Priority.valueOf(priority);
-
- return new OnDemandRequest(desc, p);
- }
- return null;
- }
-
-}
diff --git a/2006Scape Server/src/main/java/org/apollo/jagcached/net/ondemand/OnDemandResponseEncoder.java b/2006Scape Server/src/main/java/org/apollo/jagcached/net/ondemand/OnDemandResponseEncoder.java
deleted file mode 100644
index 965a24ba..00000000
--- a/2006Scape Server/src/main/java/org/apollo/jagcached/net/ondemand/OnDemandResponseEncoder.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package org.apollo.jagcached.net.ondemand;
-
-
-import org.apollo.jagcached.fs.FileDescriptor;
-import org.jboss.netty.buffer.ChannelBuffer;
-import org.jboss.netty.buffer.ChannelBuffers;
-import org.jboss.netty.channel.Channel;
-import org.jboss.netty.channel.ChannelHandlerContext;
-import org.jboss.netty.handler.codec.oneone.OneToOneEncoder;
-
-/**
- * A {@link OneToOneEncoder} for the 'on-demand' protocol.
- * @author Graham
- */
-public final class OnDemandResponseEncoder extends OneToOneEncoder {
-
- @Override
- protected Object encode(ChannelHandlerContext ctx, Channel c, Object msg) throws Exception {
- if (msg instanceof OnDemandResponse) {
- OnDemandResponse resp = (OnDemandResponse) msg;
-
- FileDescriptor fileDescriptor = resp.getFileDescriptor();
- int fileSize = resp.getFileSize();
- int chunkId = resp.getChunkId();
- ChannelBuffer chunkData = resp.getChunkData();
-
- ChannelBuffer buf = ChannelBuffers.buffer(6 + chunkData.readableBytes());
- buf.writeByte(fileDescriptor.getType() - 1);
- buf.writeShort(fileDescriptor.getFile());
- buf.writeShort(fileSize);
- buf.writeByte(chunkId);
- buf.writeBytes(chunkData);
-
- return buf;
- }
- return msg;
- }
-
-}
diff --git a/2006Scape Server/src/main/java/org/apollo/jagcached/net/service/ServiceRequest.java b/2006Scape Server/src/main/java/org/apollo/jagcached/net/service/ServiceRequest.java
deleted file mode 100644
index 36833128..00000000
--- a/2006Scape Server/src/main/java/org/apollo/jagcached/net/service/ServiceRequest.java
+++ /dev/null
@@ -1,40 +0,0 @@
-package org.apollo.jagcached.net.service;
-
-/**
- * Represents a service request message.
- * @author Graham
- */
-public final class ServiceRequest {
-
- /**
- * The game service id.
- */
- public static final int SERVICE_GAME = 14;
-
- /**
- * The 'on-demand' service id.
- */
- public static final int SERVICE_ONDEMAND = 15;
-
- /**
- * The service id.
- */
- private final int id;
-
- /**
- * Creates a service request.
- * @param id The service id.
- */
- public ServiceRequest(int id) {
- this.id = id;
- }
-
- /**
- * Gets the service id.
- * @return The service id.
- */
- public int getId() {
- return id;
- }
-
-}
diff --git a/2006Scape Server/src/main/java/org/apollo/jagcached/net/service/ServiceRequestDecoder.java b/2006Scape Server/src/main/java/org/apollo/jagcached/net/service/ServiceRequestDecoder.java
deleted file mode 100644
index 4128c83f..00000000
--- a/2006Scape Server/src/main/java/org/apollo/jagcached/net/service/ServiceRequestDecoder.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package org.apollo.jagcached.net.service;
-
-import org.jboss.netty.buffer.ChannelBuffer;
-import org.jboss.netty.channel.Channel;
-import org.jboss.netty.channel.ChannelHandlerContext;
-import org.jboss.netty.channel.ChannelPipeline;
-import org.jboss.netty.handler.codec.frame.FrameDecoder;
-
-/**
- * A {@link FrameDecoder} which decodes {@link ServiceRequest} messages.
- * @author Graham
- */
-public final class ServiceRequestDecoder extends FrameDecoder {
-
- /**
- * Creates the decoder, enabling the 'unfold' mechanism.
- */
- public ServiceRequestDecoder() {
- super(true);
- }
-
- @Override
- protected Object decode(ChannelHandlerContext ctx, Channel c, ChannelBuffer buf) throws Exception {
- if (buf.readable()) {
- ServiceRequest request = new ServiceRequest(buf.readUnsignedByte());
-
- ChannelPipeline pipeline = ctx.getPipeline();
- pipeline.remove(this);
-
- if (buf.readable()) {
- return new Object[] { request, buf.readBytes(buf.readableBytes()) };
- } else {
- return request;
- }
- }
- return null;
- }
-
-}
diff --git a/2006Scape Server/src/main/java/org/apollo/jagcached/net/service/ServiceResponse.java b/2006Scape Server/src/main/java/org/apollo/jagcached/net/service/ServiceResponse.java
deleted file mode 100644
index 9648d01e..00000000
--- a/2006Scape Server/src/main/java/org/apollo/jagcached/net/service/ServiceResponse.java
+++ /dev/null
@@ -1,9 +0,0 @@
-package org.apollo.jagcached.net.service;
-
-/**
- * Represents a response to a service request.
- * @author Graham
- */
-public final class ServiceResponse {
-
-}
diff --git a/2006Scape Server/src/main/java/org/apollo/jagcached/net/service/ServiceResponseEncoder.java b/2006Scape Server/src/main/java/org/apollo/jagcached/net/service/ServiceResponseEncoder.java
deleted file mode 100644
index af580379..00000000
--- a/2006Scape Server/src/main/java/org/apollo/jagcached/net/service/ServiceResponseEncoder.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package org.apollo.jagcached.net.service;
-
-import org.jboss.netty.buffer.ChannelBuffer;
-import org.jboss.netty.buffer.ChannelBuffers;
-import org.jboss.netty.channel.Channel;
-import org.jboss.netty.channel.ChannelHandlerContext;
-import org.jboss.netty.handler.codec.oneone.OneToOneEncoder;
-
-/**
- * A {@link OneToOneEncoder} which encodes {@link ServiceResponse} messages.
- * @author Graham
- */
-public final class ServiceResponseEncoder extends OneToOneEncoder {
-
- @Override
- protected Object encode(ChannelHandlerContext ctx, Channel c, Object msg) throws Exception {
- if (msg instanceof ServiceResponse) {
- ChannelBuffer buf = ChannelBuffers.buffer(8);
- buf.writeLong(0);
- return buf;
- }
- return msg;
- }
-
-}
diff --git a/2006Scape Server/src/main/java/org/apollo/jagcached/resource/HypertextResourceProvider.java b/2006Scape Server/src/main/java/org/apollo/jagcached/resource/HypertextResourceProvider.java
deleted file mode 100644
index bbddd593..00000000
--- a/2006Scape Server/src/main/java/org/apollo/jagcached/resource/HypertextResourceProvider.java
+++ /dev/null
@@ -1,64 +0,0 @@
-package org.apollo.jagcached.resource;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.RandomAccessFile;
-import java.net.URI;
-import java.nio.ByteBuffer;
-import java.nio.channels.FileChannel.MapMode;
-
-/**
- * A {@link ResourceProvider} which provides additional hypertext resources.
- * @author Graham Edgecombe
- */
-public final class HypertextResourceProvider extends ResourceProvider {
-
- /**
- * The base directory from which documents are served.
- */
- private final File base;
-
- /**
- * Creates a new hypertext resource provider with the specified base
- * directory.
- * @param base The base directory.
- */
- public HypertextResourceProvider(File base) {
- this.base = base;
- }
-
- @Override
- public boolean accept(String path) throws IOException {
- File f = new File(base, path);
- URI target = f.toURI().normalize();
- if (target.toASCIIString().startsWith(base.toURI().normalize().toASCIIString())) {
- if (f.isDirectory()) {
- f = new File(f, "index.html");
- }
- return f.exists();
- }
- return false;
- }
-
- @Override
- public ByteBuffer get(String path) throws IOException {
- File f = new File(base, path);
- if (f.isDirectory()) {
- f = new File(f, "index.html");
- }
- if (!f.exists()) {
- return null;
- }
-
- RandomAccessFile raf = new RandomAccessFile(f, "r");
- ByteBuffer buf;
- try {
- buf = raf.getChannel().map(MapMode.READ_ONLY, 0, raf.length());
- } finally {
- raf.close();
- }
-
- return buf;
- }
-
-}
diff --git a/2006Scape Server/src/main/java/org/apollo/jagcached/resource/ResourceProvider.java b/2006Scape Server/src/main/java/org/apollo/jagcached/resource/ResourceProvider.java
deleted file mode 100644
index 2a38d407..00000000
--- a/2006Scape Server/src/main/java/org/apollo/jagcached/resource/ResourceProvider.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package org.apollo.jagcached.resource;
-
-import java.io.IOException;
-import java.nio.ByteBuffer;
-
-/**
- * A class which provides resources.
- * @author Graham Edgecombe
- */
-public abstract class ResourceProvider {
-
- /**
- * Checks that this provider can fulfil a request to the specified
- * resource.
- * @param path The path to the resource, e.g. {@code /crc}.
- * @return {@code true} if the provider can fulfil a request to the
- * resource, {@code false} otherwise.
- * @throws IOException if an I/O error occurs.
- */
- public abstract boolean accept(String path) throws IOException;
-
- /**
- * Gets a resource by its path.
- * @param path The path.
- * @return The resource, or {@code null} if it doesn't exist.
- * @throws IOException if an I/O error occurs.
- */
- public abstract ByteBuffer get(String path) throws IOException;
-
-}
diff --git a/2006Scape Server/src/main/java/org/apollo/jagcached/resource/VirtualResourceProvider.java b/2006Scape Server/src/main/java/org/apollo/jagcached/resource/VirtualResourceProvider.java
deleted file mode 100644
index f474adf1..00000000
--- a/2006Scape Server/src/main/java/org/apollo/jagcached/resource/VirtualResourceProvider.java
+++ /dev/null
@@ -1,70 +0,0 @@
-package org.apollo.jagcached.resource;
-
-import java.io.IOException;
-import java.nio.ByteBuffer;
-
-import org.apollo.jagcached.fs.IndexedFileSystem;
-
-/**
- * A {@link ResourceProvider} which maps virtual resources (such as
- * {@code /media}) to files in an {@link IndexedFileSystem}.
- * @author Graham Edgecombe
- */
-public final class VirtualResourceProvider extends ResourceProvider {
-
- /**
- * An array of valid prefixes.
- */
- private static final String[] VALID_PREFIXES = {
- "crc", "title", "config", "interface", "media", "versionlist",
- "textures", "wordenc", "sounds"
- };
-
- /**
- * The file system.
- */
- private final IndexedFileSystem fs;
-
- /**
- * Creates a new virtual resource provider with the specified file system.
- * @param fs The file system.
- */
- public VirtualResourceProvider(IndexedFileSystem fs) {
- this.fs = fs;
- }
-
- @Override
- public boolean accept(String path) throws IOException {
- for (String prefix : VALID_PREFIXES) {
- if (path.startsWith("/" + prefix)) {
- return true;
- }
- }
- return false;
- }
-
- @Override
- public ByteBuffer get(String path) throws IOException {
- if (path.startsWith("/crc")) {
- return fs.getCrcTable();
- } else if (path.startsWith("/title")) {
- return fs.getFile(0, 1);
- } else if (path.startsWith("/config")) {
- return fs.getFile(0, 2);
- } else if (path.startsWith("/interface")) {
- return fs.getFile(0, 3);
- } else if (path.startsWith("/media")) {
- return fs.getFile(0, 4);
- } else if (path.startsWith("/versionlist")) {
- return fs.getFile(0, 5);
- } else if (path.startsWith("/textures")) {
- return fs.getFile(0, 6);
- } else if (path.startsWith("/wordenc")) {
- return fs.getFile(0, 7);
- } else if (path.startsWith("/sounds")) {
- return fs.getFile(0, 8);
- }
- return null;
- }
-
-}
diff --git a/2006Scape Server/src/main/java/org/apollo/net/HttpChannelInitializer.java b/2006Scape Server/src/main/java/org/apollo/net/HttpChannelInitializer.java
new file mode 100644
index 00000000..5aa29a13
--- /dev/null
+++ b/2006Scape Server/src/main/java/org/apollo/net/HttpChannelInitializer.java
@@ -0,0 +1,51 @@
+package org.apollo.net;
+
+import io.netty.channel.ChannelInboundHandlerAdapter;
+import io.netty.channel.ChannelInitializer;
+import io.netty.channel.ChannelPipeline;
+import io.netty.channel.socket.SocketChannel;
+import io.netty.handler.codec.http.HttpObjectAggregator;
+import io.netty.handler.codec.http.HttpRequestDecoder;
+import io.netty.handler.codec.http.HttpResponseEncoder;
+import io.netty.handler.timeout.IdleStateHandler;
+
+/**
+ * A {@link ChannelInitializer} for the HTTP protocol.
+ *
+ * @author Graham
+ */
+public final class HttpChannelInitializer extends ChannelInitializer {
+
+ /**
+ * The maximum length of a request, in bytes.
+ */
+ private static final int MAX_REQUEST_LENGTH = 8192;
+
+ /**
+ * The server event handler.
+ */
+ private final ChannelInboundHandlerAdapter handler;
+
+ /**
+ * Creates the HTTP pipeline factory.
+ *
+ * @param handler The file server event handler.
+ */
+ public HttpChannelInitializer(ChannelInboundHandlerAdapter handler) {
+ this.handler = handler;
+ }
+
+ @Override
+ protected void initChannel(SocketChannel ch) throws Exception {
+ ChannelPipeline pipeline = ch.pipeline();
+
+ pipeline.addLast("decoder", new HttpRequestDecoder());
+ pipeline.addLast("chunker", new HttpObjectAggregator(MAX_REQUEST_LENGTH));
+
+ pipeline.addLast("encoder", new HttpResponseEncoder());
+
+ pipeline.addLast("timeout", new IdleStateHandler(NetworkConstants.IDLE_TIME, 0, 0));
+ pipeline.addLast("handler", handler);
+ }
+
+}
\ No newline at end of file
diff --git a/2006Scape Server/src/main/java/org/apollo/net/JagGrabChannelInitializer.java b/2006Scape Server/src/main/java/org/apollo/net/JagGrabChannelInitializer.java
new file mode 100644
index 00000000..a882f494
--- /dev/null
+++ b/2006Scape Server/src/main/java/org/apollo/net/JagGrabChannelInitializer.java
@@ -0,0 +1,77 @@
+package org.apollo.net;
+
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
+import io.netty.channel.ChannelInboundHandlerAdapter;
+import io.netty.channel.ChannelInitializer;
+import io.netty.channel.ChannelPipeline;
+import io.netty.channel.socket.SocketChannel;
+import io.netty.handler.codec.DelimiterBasedFrameDecoder;
+import io.netty.handler.codec.string.StringDecoder;
+import io.netty.handler.timeout.IdleStateHandler;
+
+import java.nio.charset.Charset;
+
+import org.apollo.net.codec.jaggrab.JagGrabRequestDecoder;
+import org.apollo.net.codec.jaggrab.JagGrabResponseEncoder;
+
+import com.google.common.base.Charsets;
+
+/**
+ * A {@link ChannelInitializer} for the JAGGRAB protocol.
+ *
+ * @author Graham
+ */
+public final class JagGrabChannelInitializer extends ChannelInitializer {
+
+ /**
+ * A buffer with two line feed (LF) characters in it.
+ */
+ private static final ByteBuf DOUBLE_LINE_FEED_DELIMITER = Unpooled.buffer(2);
+
+ /**
+ * The character set used in the request.
+ */
+ private static final Charset JAGGRAB_CHARSET = Charsets.US_ASCII;
+
+ /**
+ * The maximum length of a request, in bytes.
+ */
+ private static final int MAX_REQUEST_LENGTH = 8192;
+
+ /**
+ * Populates the double line feed buffer.
+ */
+ static {
+ DOUBLE_LINE_FEED_DELIMITER.writeByte(10).writeByte(10);
+ }
+
+ /**
+ * The file server event handler.
+ */
+ private final ChannelInboundHandlerAdapter handler;
+
+ /**
+ * Creates a {@code JAGGRAB} pipeline factory.
+ *
+ * @param handler The file server event handler.
+ */
+ public JagGrabChannelInitializer(ChannelInboundHandlerAdapter handler) {
+ this.handler = handler;
+ }
+
+ @Override
+ public void initChannel(SocketChannel ch) throws Exception {
+ ChannelPipeline pipeline = ch.pipeline();
+
+ pipeline.addLast("framer", new DelimiterBasedFrameDecoder(MAX_REQUEST_LENGTH, DOUBLE_LINE_FEED_DELIMITER));
+ pipeline.addLast("string-decoder", new StringDecoder(JAGGRAB_CHARSET));
+ pipeline.addLast("jaggrab-decoder", new JagGrabRequestDecoder());
+
+ pipeline.addLast("jaggrab-encoder", new JagGrabResponseEncoder());
+
+ pipeline.addLast("timeout", new IdleStateHandler(NetworkConstants.IDLE_TIME, 0, 0));
+ pipeline.addLast("handler", handler);
+ }
+
+}
\ No newline at end of file
diff --git a/2006Scape Server/src/main/java/org/apollo/net/NetworkConstants.java b/2006Scape Server/src/main/java/org/apollo/net/NetworkConstants.java
new file mode 100644
index 00000000..4aa69447
--- /dev/null
+++ b/2006Scape Server/src/main/java/org/apollo/net/NetworkConstants.java
@@ -0,0 +1,81 @@
+package org.apollo.net;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.math.BigInteger;
+
+import com.google.common.base.Preconditions;
+import org.apollo.util.xml.XmlNode;
+import org.apollo.util.xml.XmlParser;
+
+/**
+ * Holds various network-related constants such as port numbers.
+ *
+ * @author Graham
+ * @author Major
+ */
+public final class NetworkConstants {
+
+ /**
+ * The HTTP port.
+ */
+ public static final int HTTP_PORT;
+
+ /**
+ * The number of seconds before a connection becomes idle.
+ */
+ public static final int IDLE_TIME = 15;
+
+ /**
+ * The JAGGRAB port.
+ */
+ public static final int JAGGRAB_PORT;
+
+ /**
+ * The exponent used when decrypting the RSA block.
+ */
+ public static final BigInteger RSA_EXPONENT;
+
+ /**
+ * The modulus used when decrypting the RSA block.
+ */
+ public static final BigInteger RSA_MODULUS;
+
+ static {
+ try (InputStream is = new FileInputStream("data/net.xml")) {
+ XmlNode net = new XmlParser().parse(is);
+ if (!net.getName().equals("net")) {
+ throw new IOException("Root node name is not 'net'.");
+ }
+
+ XmlNode rsa = net.getChild("rsa");
+ Preconditions.checkState(rsa != null, "Root node must have a child named 'rsa'.");
+
+ XmlNode modulus = rsa.getChild("modulus"), exponent = rsa.getChild("private-exponent");
+ Preconditions.checkState(modulus != null && exponent != null, "Rsa node must have two children: 'modulus' and 'private-exponent'.");
+
+ RSA_MODULUS = new BigInteger(modulus.getValue());
+ RSA_EXPONENT = new BigInteger(exponent.getValue());
+
+ XmlNode ports = net.getChild("ports");
+ Preconditions.checkState(ports != null, "Root node must have a child named 'ports'.");
+
+ XmlNode http = ports.getChild("http"), jaggrab = ports.getChild("jaggrab");
+ Preconditions.checkState(http != null && jaggrab != null, "Ports node must have two children: 'http', and 'jaggrab'.");
+
+ HTTP_PORT = Integer.parseInt(http.getValue());
+ JAGGRAB_PORT = Integer.parseInt(jaggrab.getValue());
+ } catch (Exception exception) {
+ throw new ExceptionInInitializerError(new IOException("Error parsing net.xml.", exception));
+ }
+ }
+
+ /**
+ * Sole private constructor to prevent instantiation.
+ */
+ private NetworkConstants() {
+
+ }
+
+}
\ No newline at end of file
diff --git a/2006Scape Server/src/main/java/org/apollo/net/ServiceChannelInitializer.java b/2006Scape Server/src/main/java/org/apollo/net/ServiceChannelInitializer.java
new file mode 100644
index 00000000..9e4419e8
--- /dev/null
+++ b/2006Scape Server/src/main/java/org/apollo/net/ServiceChannelInitializer.java
@@ -0,0 +1,40 @@
+package org.apollo.net;
+
+import io.netty.channel.ChannelInboundHandlerAdapter;
+import io.netty.channel.ChannelInitializer;
+import io.netty.channel.ChannelPipeline;
+import io.netty.channel.socket.SocketChannel;
+import io.netty.handler.timeout.IdleStateHandler;
+
+import org.apollo.net.codec.handshake.HandshakeDecoder;
+
+/**
+ * A {@link ChannelInitializer} for the service pipeline.
+ *
+ * @author Graham
+ */
+public final class ServiceChannelInitializer extends ChannelInitializer {
+
+ /**
+ * The network event handler.
+ */
+ private final ChannelInboundHandlerAdapter handler;
+
+ /**
+ * Creates the service pipeline factory.
+ *
+ * @param handler The networking event handler.
+ */
+ public ServiceChannelInitializer(ChannelInboundHandlerAdapter handler) {
+ this.handler = handler;
+ }
+
+ @Override
+ protected void initChannel(SocketChannel ch) throws Exception {
+ ChannelPipeline pipeline = ch.pipeline();
+ pipeline.addLast("handshakeDecoder", new HandshakeDecoder());
+ pipeline.addLast("timeout", new IdleStateHandler(NetworkConstants.IDLE_TIME, 0, 0));
+ pipeline.addLast("handler", handler);
+ }
+
+}
\ No newline at end of file
diff --git a/2006Scape Server/src/main/java/org/apollo/net/codec/handshake/HandshakeConstants.java b/2006Scape Server/src/main/java/org/apollo/net/codec/handshake/HandshakeConstants.java
new file mode 100644
index 00000000..94861b7b
--- /dev/null
+++ b/2006Scape Server/src/main/java/org/apollo/net/codec/handshake/HandshakeConstants.java
@@ -0,0 +1,27 @@
+package org.apollo.net.codec.handshake;
+
+/**
+ * Holds handshake-related constants.
+ *
+ * @author Graham
+ */
+public final class HandshakeConstants {
+
+ /**
+ * The id of the game service.
+ */
+ public static final int SERVICE_GAME = 14;
+
+ /**
+ * The id of the update service.
+ */
+ public static final int SERVICE_UPDATE = 15;
+
+ /**
+ * Default private constructor to prevent instantiation by other classes.
+ */
+ private HandshakeConstants() {
+
+ }
+
+}
\ No newline at end of file
diff --git a/2006Scape Server/src/main/java/org/apollo/net/codec/handshake/HandshakeDecoder.java b/2006Scape Server/src/main/java/org/apollo/net/codec/handshake/HandshakeDecoder.java
new file mode 100644
index 00000000..aa768ae8
--- /dev/null
+++ b/2006Scape Server/src/main/java/org/apollo/net/codec/handshake/HandshakeDecoder.java
@@ -0,0 +1,60 @@
+package org.apollo.net.codec.handshake;
+
+import io.netty.buffer.ByteBuf;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.handler.codec.ByteToMessageDecoder;
+
+import java.util.List;
+import java.util.logging.Logger;
+
+import org.apollo.net.codec.login.LoginDecoder;
+import org.apollo.net.codec.login.LoginEncoder;
+import org.apollo.net.codec.update.UpdateDecoder;
+import org.apollo.net.codec.update.UpdateEncoder;
+
+/**
+ * A {@link ByteToMessageDecoder} which decodes the handshake and makes changes to the pipeline as appropriate for the
+ * selected service.
+ *
+ * @author Graham
+ */
+public final class HandshakeDecoder extends ByteToMessageDecoder {
+
+ /**
+ * The logger for this class.
+ */
+ private static final Logger logger = Logger.getLogger(HandshakeDecoder.class.getName());
+
+ @Override
+ protected void decode(ChannelHandlerContext ctx, ByteBuf buffer, List