diff --git a/data/login.xml b/data/login.xml
index 27f2d6fa..c7f0371a 100644
--- a/data/login.xml
+++ b/data/login.xml
@@ -1,4 +1,3 @@
- org.apollo.io.player.impl.DummyPlayerLoader
- org.apollo.io.player.impl.DiscardPlayerSaver
+ org.apollo.io.player.DummyPlayerSerializer
\ No newline at end of file
diff --git a/src/org/apollo/io/player/BinaryFileUtils.java b/src/org/apollo/io/player/BinaryFileUtils.java
new file mode 100644
index 00000000..00c747a4
--- /dev/null
+++ b/src/org/apollo/io/player/BinaryFileUtils.java
@@ -0,0 +1,56 @@
+package org.apollo.io.player;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import org.apollo.util.NameUtil;
+
+/**
+ * A utility class with common functionality used by the binary player loader/ savers.
+ *
+ * @author Graham
+ * @author Major
+ */
+public final class BinaryFileUtils {
+
+ /**
+ * The Path to the saved games directory.
+ */
+ private static final Path SAVED_GAMES_DIRECTORY = Paths.get("data/savedGames");
+
+ /**
+ * Creates the saved games directory if it does not exist.
+ */
+ static {
+ try {
+ if (!Files.exists(SAVED_GAMES_DIRECTORY)) {
+ Files.createDirectory(SAVED_GAMES_DIRECTORY);
+ }
+ } catch (IOException e) {
+ throw new UncheckedIOException("Error creating saved games directory.", e);
+ }
+ }
+
+ /**
+ * Gets the save {@link File} for the specified player.
+ *
+ * @param username The username of the player.
+ * @return The file.
+ */
+ public static Path getFile(String username) {
+ String filtered = NameUtil.decodeBase37(NameUtil.encodeBase37(username));
+ return SAVED_GAMES_DIRECTORY.resolve(filtered + ".dat");
+ }
+
+ /**
+ * Sole private constructor to prevent instantiation.
+ */
+ private BinaryFileUtils() {
+
+ }
+
+}
\ No newline at end of file
diff --git a/src/org/apollo/io/player/impl/BinaryPlayerLoader.java b/src/org/apollo/io/player/BinaryPlayerSerializer.java
similarity index 52%
rename from src/org/apollo/io/player/impl/BinaryPlayerLoader.java
rename to src/org/apollo/io/player/BinaryPlayerSerializer.java
index 19d77500..6ae08b98 100644
--- a/src/org/apollo/io/player/impl/BinaryPlayerLoader.java
+++ b/src/org/apollo/io/player/BinaryPlayerSerializer.java
@@ -1,13 +1,20 @@
-package org.apollo.io.player.impl;
+package org.apollo.io.player;
+import java.io.BufferedInputStream;
import java.io.DataInputStream;
+import java.io.DataOutputStream;
import java.io.File;
-import java.io.FileInputStream;
import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
import org.apollo.game.model.Appearance;
import org.apollo.game.model.Item;
@@ -16,6 +23,8 @@ import org.apollo.game.model.entity.Player;
import org.apollo.game.model.entity.Skill;
import org.apollo.game.model.entity.SkillSet;
import org.apollo.game.model.entity.attr.Attribute;
+import org.apollo.game.model.entity.attr.AttributeMap;
+import org.apollo.game.model.entity.attr.AttributePersistence;
import org.apollo.game.model.entity.attr.AttributeType;
import org.apollo.game.model.entity.attr.BooleanAttribute;
import org.apollo.game.model.entity.attr.NumericalAttribute;
@@ -26,8 +35,6 @@ import org.apollo.game.model.entity.setting.PrivacyState;
import org.apollo.game.model.entity.setting.PrivilegeLevel;
import org.apollo.game.model.entity.setting.ScreenBrightness;
import org.apollo.game.model.inv.Inventory;
-import org.apollo.io.player.PlayerLoader;
-import org.apollo.io.player.PlayerLoaderResponse;
import org.apollo.net.codec.login.LoginConstants;
import org.apollo.security.PlayerCredentials;
import org.apollo.util.NameUtil;
@@ -36,28 +43,39 @@ import org.apollo.util.StreamUtil;
import com.lambdaworks.crypto.SCryptUtil;
/**
- * A {@link PlayerLoader} implementation that loads data from a binary file.
+ * A {@link PlayerSerializer} implementation that uses a binary file to store player data.
*
* @author Graham
+ * @author Major
*/
-public final class BinaryPlayerLoader implements PlayerLoader {
+public final class BinaryPlayerSerializer implements PlayerSerializer {
/**
- * The default spawn position.
+ * The Path to the saved games directory.
*/
- private static final Position SPAWN_POSITION = new Position(3093, 3104);
+ private static final Path SAVED_GAMES_DIRECTORY = Paths.get("data/savedGames");
+
+ static {
+ try {
+ if (!Files.exists(SAVED_GAMES_DIRECTORY)) {
+ Files.createDirectory(SAVED_GAMES_DIRECTORY);
+ }
+ } catch (IOException e) {
+ throw new UncheckedIOException("Error creating saved games directory.", e);
+ }
+ }
@Override
public PlayerLoaderResponse loadPlayer(PlayerCredentials credentials) throws IOException {
- File file = BinaryPlayerUtil.getFile(credentials.getUsername());
- if (!file.exists()) {
- Player player = new Player(credentials, SPAWN_POSITION);
- player.getBank().add(995, 25); // 25 coins
+ Path path = getFile(credentials.getUsername());
+ if (!Files.exists(path)) {
+ Player player = new Player(credentials, TUTORIAL_ISLAND_SPAWN);
+
credentials.setPassword(SCryptUtil.scrypt(credentials.getPassword(), 16384, 8, 1));
return new PlayerLoaderResponse(LoginConstants.STATUS_OK, player);
}
- try (DataInputStream in = new DataInputStream(new FileInputStream(file))) {
+ try (DataInputStream in = new DataInputStream(new BufferedInputStream(Files.newInputStream(path)))) {
String name = StreamUtil.readString(in);
String password = StreamUtil.readString(in);
@@ -67,37 +85,35 @@ public final class BinaryPlayerLoader implements PlayerLoader {
credentials.setPassword(password); // Update password to the hashed one.
- PrivilegeLevel privilegeLevel = PrivilegeLevel.valueOf(in.readByte());
+ PrivilegeLevel privilege = PrivilegeLevel.valueOf(in.readByte());
MembershipStatus members = MembershipStatus.valueOf(in.readByte());
PrivacyState chatPrivacy = PrivacyState.valueOf(in.readByte(), true);
PrivacyState friendPrivacy = PrivacyState.valueOf(in.readByte(), false);
PrivacyState tradePrivacy = PrivacyState.valueOf(in.readByte(), false);
- int runEnergy = in.readByte();
ScreenBrightness brightness = ScreenBrightness.valueOf(in.readByte());
int x = in.readUnsignedShort();
int y = in.readUnsignedShort();
int height = in.readUnsignedByte();
- int genderIntValue = in.readUnsignedByte();
- Gender gender = genderIntValue == Gender.MALE.toInteger() ? Gender.MALE : Gender.FEMALE;
+ Gender gender = (in.readUnsignedByte() == Gender.MALE.toInteger()) ? Gender.MALE : Gender.FEMALE;
int[] style = new int[7];
- for (int i = 0; i < style.length; i++) {
- style[i] = in.readUnsignedByte();
+ for (int slot = 0; slot < style.length; slot++) {
+ style[slot] = in.readUnsignedByte();
}
+
int[] colors = new int[5];
- for (int i = 0; i < colors.length; i++) {
- colors[i] = in.readUnsignedByte();
+ for (int slot = 0; slot < colors.length; slot++) {
+ colors[slot] = in.readUnsignedByte();
}
Player player = new Player(credentials, new Position(x, y, height));
- player.setPrivilegeLevel(privilegeLevel);
+ player.setPrivilegeLevel(privilege);
player.setMembers(members);
player.setChatPrivacy(chatPrivacy);
player.setFriendPrivacy(friendPrivacy);
player.setTradePrivacy(tradePrivacy);
- player.setRunEnergy(runEnergy);
player.setScreenBrightness(brightness);
player.setAppearance(new Appearance(gender, style, colors));
@@ -141,6 +157,87 @@ public final class BinaryPlayerLoader implements PlayerLoader {
}
}
+ @Override
+ public void savePlayer(Player player) throws IOException {
+ Path file = getFile(player.getUsername());
+
+ try (DataOutputStream out = new DataOutputStream(Files.newOutputStream(file))) {
+ StreamUtil.writeString(out, player.getUsername());
+ StreamUtil.writeString(out, player.getCredentials().getPassword());
+ out.writeByte(player.getPrivilegeLevel().toInteger());
+ out.writeByte(player.getMembershipStatus().getValue());
+
+ out.writeByte(player.getChatPrivacy().toInteger(true));
+ out.writeByte(player.getFriendPrivacy().toInteger(false));
+ out.writeByte(player.getTradePrivacy().toInteger(false));
+ out.writeByte(player.getScreenBrightness().toInteger());
+
+ Position position = player.getPosition();
+ out.writeShort(position.getX());
+ out.writeShort(position.getY());
+ out.writeByte(position.getHeight());
+
+ Appearance appearance = player.getAppearance();
+ out.writeByte(appearance.getGender().toInteger());
+ int[] style = appearance.getStyle();
+ for (int element : style) {
+ out.writeByte(element);
+ }
+ int[] colors = appearance.getColors();
+ for (int color : colors) {
+ out.writeByte(color);
+ }
+
+ writeInventory(out, player.getInventory());
+ writeInventory(out, player.getEquipment());
+ writeInventory(out, player.getBank());
+
+ SkillSet skills = player.getSkillSet();
+ out.writeByte(skills.size());
+ for (int id = 0; id < skills.size(); id++) {
+ Skill skill = skills.getSkill(id);
+ out.writeByte(skill.getCurrentLevel());
+ out.writeDouble(skill.getExperience());
+ }
+
+ List usernames = player.getFriendUsernames();
+ out.writeByte(usernames.size());
+ for (String username : usernames) {
+ out.writeLong(NameUtil.encodeBase37(username));
+ }
+
+ usernames = player.getIgnoredUsernames();
+ out.writeByte(usernames.size());
+ for (String username : usernames) {
+ out.writeLong(NameUtil.encodeBase37(username));
+ }
+
+ Set>> attributes = player.getAttributes().entrySet();
+ attributes.removeIf(e -> AttributeMap.getDefinition(e.getKey()).getPersistence() != AttributePersistence.PERSISTENT);
+ out.writeInt(attributes.size());
+
+ for (Entry> entry : attributes) {
+ String name = entry.getKey();
+ StreamUtil.writeString(out, name);
+
+ Attribute> attribute = entry.getValue();
+ out.writeByte(attribute.getType().getValue());
+ out.write(attribute.encode());
+ }
+ }
+ }
+
+ /**
+ * Gets the save {@link File} for the specified player.
+ *
+ * @param username The username of the player.
+ * @return The file.
+ */
+ private Path getFile(String username) {
+ String filtered = NameUtil.decodeBase37(NameUtil.encodeBase37(username));
+ return SAVED_GAMES_DIRECTORY.resolve(filtered + ".dat");
+ }
+
/**
* Reads the player's {@link Attribute}s.
*
@@ -148,7 +245,7 @@ public final class BinaryPlayerLoader implements PlayerLoader {
* @return The {@link Map} of attribute names to attributes.
* @throws IOException If there is an error reading from the stream.
*/
- private static Map> readAttributes(DataInputStream in) throws IOException {
+ private Map> readAttributes(DataInputStream in) throws IOException {
int count = in.readInt();
Map> attributes = new HashMap<>(count);
@@ -187,7 +284,7 @@ public final class BinaryPlayerLoader implements PlayerLoader {
* @param inventory The inventory.
* @throws IOException If an I/O error occurs.
*/
- private static void readInventory(DataInputStream in, Inventory inventory) throws IOException {
+ private void readInventory(DataInputStream in, Inventory inventory) throws IOException {
int capacity = in.readUnsignedShort();
inventory.stopFiringEvents();
@@ -206,4 +303,27 @@ public final class BinaryPlayerLoader implements PlayerLoader {
}
}
+ /**
+ * Writes an inventory to the specified output stream.
+ *
+ * @param out The output stream.
+ * @param inventory The inventory.
+ * @throws IOException If an I/O error occurs.
+ */
+ private void writeInventory(DataOutputStream out, Inventory inventory) throws IOException {
+ int capacity = inventory.capacity();
+ out.writeShort(capacity);
+
+ for (int slot = 0; slot < capacity; slot++) {
+ Item item = inventory.get(slot);
+ if (item != null) {
+ out.writeShort(item.getId() + 1);
+ out.writeInt(item.getAmount());
+ } else {
+ out.writeShort(0);
+ out.writeInt(0);
+ }
+ }
+ }
+
}
\ No newline at end of file
diff --git a/src/org/apollo/io/player/impl/DummyPlayerLoader.java b/src/org/apollo/io/player/DummyPlayerSerializer.java
similarity index 52%
rename from src/org/apollo/io/player/impl/DummyPlayerLoader.java
rename to src/org/apollo/io/player/DummyPlayerSerializer.java
index 83b0aedf..5466f385 100644
--- a/src/org/apollo/io/player/impl/DummyPlayerLoader.java
+++ b/src/org/apollo/io/player/DummyPlayerSerializer.java
@@ -1,35 +1,33 @@
-package org.apollo.io.player.impl;
+package org.apollo.io.player;
-import org.apollo.game.model.Position;
import org.apollo.game.model.entity.Player;
import org.apollo.game.model.entity.setting.MembershipStatus;
import org.apollo.game.model.entity.setting.PrivilegeLevel;
-import org.apollo.io.player.PlayerLoader;
-import org.apollo.io.player.PlayerLoaderResponse;
import org.apollo.net.codec.login.LoginConstants;
import org.apollo.security.PlayerCredentials;
/**
- * A dummy {@link PlayerLoader} implementation used for testing purposes.
+ * A {@link PlayerSerializer} that saves no data and returns an administrator member account, ideal for debugging.
*
* @author Graham
+ * @author Major
*/
-public final class DummyPlayerLoader implements PlayerLoader {
-
- /**
- * The default spawn position for players loaded by this loader.
- */
- private static final Position DEFAULT_POSITION = new Position(3093, 3104);
+public final class DummyPlayerSerializer implements PlayerSerializer {
@Override
public PlayerLoaderResponse loadPlayer(PlayerCredentials credentials) {
int status = LoginConstants.STATUS_OK;
- Player player = new Player(credentials, DEFAULT_POSITION);
+ Player player = new Player(credentials, TUTORIAL_ISLAND_SPAWN);
player.setPrivilegeLevel(PrivilegeLevel.ADMINISTRATOR);
player.setMembers(MembershipStatus.PAID);
return new PlayerLoaderResponse(status, player);
}
+ @Override
+ public void savePlayer(Player player) {
+ /* discard player */
+ }
+
}
\ No newline at end of file
diff --git a/src/org/apollo/io/player/JdbcPlayerSerializer.java b/src/org/apollo/io/player/JdbcPlayerSerializer.java
new file mode 100644
index 00000000..c8e48cf0
--- /dev/null
+++ b/src/org/apollo/io/player/JdbcPlayerSerializer.java
@@ -0,0 +1,23 @@
+package org.apollo.io.player;
+
+import org.apollo.game.model.entity.Player;
+import org.apollo.security.PlayerCredentials;
+
+/**
+ * A {@link PlayerSerializer} that utilises {@code JDBC} to communicate with an SQL database containing player data.
+ *
+ * @author Major
+ */
+public final class JdbcPlayerSerializer implements PlayerSerializer {
+
+ @Override
+ public void savePlayer(Player player) throws Exception {
+ throw new UnsupportedOperationException("JDBC saving is not supported at this time.");
+ }
+
+ @Override
+ public PlayerLoaderResponse loadPlayer(PlayerCredentials credentials) throws Exception {
+ throw new UnsupportedOperationException("JDBC loading is not supported at this time.");
+ }
+
+}
\ No newline at end of file
diff --git a/src/org/apollo/io/player/PlayerLoader.java b/src/org/apollo/io/player/PlayerLoader.java
deleted file mode 100644
index ff14e622..00000000
--- a/src/org/apollo/io/player/PlayerLoader.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package org.apollo.io.player;
-
-import org.apollo.security.PlayerCredentials;
-
-/**
- * An interface which may be extended by others which are capable of loading players. For example, implementations might
- * include text-based, binary and SQL loaders.
- *
- * @author Graham
- */
-public interface PlayerLoader {
-
- /**
- * Loads a player.
- *
- * @param credentials The player's credentials.
- * @return The {@link PlayerLoaderResponse}.
- * @throws Exception If an error occurs.
- */
- public PlayerLoaderResponse loadPlayer(PlayerCredentials credentials) throws Exception;
-
-}
\ No newline at end of file
diff --git a/src/org/apollo/io/player/PlayerLoaderResponse.java b/src/org/apollo/io/player/PlayerLoaderResponse.java
index 69e6541b..6f6bc2b6 100644
--- a/src/org/apollo/io/player/PlayerLoaderResponse.java
+++ b/src/org/apollo/io/player/PlayerLoaderResponse.java
@@ -8,9 +8,10 @@ import org.apollo.net.codec.login.LoginConstants;
import com.google.common.base.Preconditions;
/**
- * A response for the {@link PlayerLoader#loadPlayer(org.apollo.security.PlayerCredentials)} call.
+ * A response for the {@link PlayerSerializer#loadPlayer} call.
*
* @author Graham
+ * @author Major
*/
public final class PlayerLoaderResponse {
@@ -32,7 +33,8 @@ public final class PlayerLoaderResponse {
* {@link LoginConstants#STATUS_RECONNECTION_OK}.
*/
public PlayerLoaderResponse(int status) {
- Preconditions.checkArgument(status != LoginConstants.STATUS_OK && status != LoginConstants.STATUS_RECONNECTION_OK, "Player required for this status code.");
+ Preconditions.checkArgument(status != LoginConstants.STATUS_OK && status != LoginConstants.STATUS_RECONNECTION_OK,
+ "Player required for this status code.");
this.status = status;
player = Optional.empty();
}
@@ -46,7 +48,8 @@ public final class PlayerLoaderResponse {
* @throws NullPointerException If the specified player is null.
*/
public PlayerLoaderResponse(int status, Player player) {
- Preconditions.checkArgument(status == LoginConstants.STATUS_OK || status == LoginConstants.STATUS_RECONNECTION_OK, "Player not required for this status code.");
+ Preconditions.checkArgument(status == LoginConstants.STATUS_OK || status == LoginConstants.STATUS_RECONNECTION_OK,
+ "Player not required for this status code.");
this.status = status;
this.player = Optional.of(player);
}
diff --git a/src/org/apollo/io/player/PlayerSaver.java b/src/org/apollo/io/player/PlayerSaver.java
deleted file mode 100644
index 1a2def5d..00000000
--- a/src/org/apollo/io/player/PlayerSaver.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package org.apollo.io.player;
-
-import org.apollo.game.model.entity.Player;
-
-/**
- * An interface which may be implemented by others which are capable of saving players. For example, implementations
- * might include text-based, binary and SQL savers.
- *
- * @author Graham
- */
-public interface PlayerSaver {
-
- /**
- * Saves a player.
- *
- * @param player The player to save.
- * @throws Exception If an error occurs.
- */
- public void savePlayer(Player player) throws Exception;
-
-}
\ No newline at end of file
diff --git a/src/org/apollo/io/player/PlayerSerializer.java b/src/org/apollo/io/player/PlayerSerializer.java
new file mode 100644
index 00000000..4d246a74
--- /dev/null
+++ b/src/org/apollo/io/player/PlayerSerializer.java
@@ -0,0 +1,38 @@
+package org.apollo.io.player;
+
+import org.apollo.game.model.Position;
+import org.apollo.game.model.entity.Player;
+import org.apollo.security.PlayerCredentials;
+
+/**
+ * An interface which may be implemented by others which are capable of serializing and deserializing players. For
+ * example, implementations might include text-based, binary and SQL serializers.
+ *
+ * @author Graham
+ * @author Major
+ */
+public interface PlayerSerializer {
+
+ /**
+ * The spawn point for Players, on Tutorial Island.
+ */
+ Position TUTORIAL_ISLAND_SPAWN = new Position(3093, 3104);
+
+ /**
+ * Loads a {@link Player}.
+ *
+ * @param credentials The {@link PlayerCredentials}.
+ * @return The {@link PlayerLoaderResponse}.
+ * @throws Exception If an error occurs.
+ */
+ public PlayerLoaderResponse loadPlayer(PlayerCredentials credentials) throws Exception;
+
+ /**
+ * Saves a {@link Player}.
+ *
+ * @param player The Player to save.
+ * @throws Exception If an error occurs.
+ */
+ public void savePlayer(Player player) throws Exception;
+
+}
\ No newline at end of file
diff --git a/src/org/apollo/io/player/impl/BinaryPlayerSaver.java b/src/org/apollo/io/player/impl/BinaryPlayerSaver.java
deleted file mode 100644
index 5fca15a2..00000000
--- a/src/org/apollo/io/player/impl/BinaryPlayerSaver.java
+++ /dev/null
@@ -1,126 +0,0 @@
-package org.apollo.io.player.impl;
-
-import java.io.DataOutputStream;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.util.List;
-import java.util.Map.Entry;
-import java.util.Set;
-
-import org.apollo.game.model.Appearance;
-import org.apollo.game.model.Item;
-import org.apollo.game.model.Position;
-import org.apollo.game.model.entity.Player;
-import org.apollo.game.model.entity.Skill;
-import org.apollo.game.model.entity.SkillSet;
-import org.apollo.game.model.entity.attr.Attribute;
-import org.apollo.game.model.entity.attr.AttributeMap;
-import org.apollo.game.model.entity.attr.AttributePersistence;
-import org.apollo.game.model.inv.Inventory;
-import org.apollo.io.player.PlayerSaver;
-import org.apollo.util.NameUtil;
-import org.apollo.util.StreamUtil;
-
-/**
- * A {@link PlayerSaver} implementation that saves player data to a binary file.
- *
- * @author Graham
- */
-public final class BinaryPlayerSaver implements PlayerSaver {
-
- @Override
- public void savePlayer(Player player) throws IOException {
- File file = BinaryPlayerUtil.getFile(player.getUsername());
-
- try (DataOutputStream out = new DataOutputStream(new FileOutputStream(file))) {
- StreamUtil.writeString(out, player.getUsername());
- StreamUtil.writeString(out, player.getCredentials().getPassword());
- out.writeByte(player.getPrivilegeLevel().toInteger());
- out.writeByte(player.getMembershipStatus().getValue());
-
- out.writeByte(player.getChatPrivacy().toInteger(true));
- out.writeByte(player.getFriendPrivacy().toInteger(false));
- out.writeByte(player.getTradePrivacy().toInteger(false));
- out.writeByte(player.getRunEnergy());
- out.writeByte(player.getScreenBrightness().toInteger());
-
- Position position = player.getPosition();
- out.writeShort(position.getX());
- out.writeShort(position.getY());
- out.writeByte(position.getHeight());
-
- Appearance appearance = player.getAppearance();
- out.writeByte(appearance.getGender().toInteger());
- int[] style = appearance.getStyle();
- for (int element : style) {
- out.writeByte(element);
- }
- int[] colors = appearance.getColors();
- for (int color : colors) {
- out.writeByte(color);
- }
-
- writeInventory(out, player.getInventory());
- writeInventory(out, player.getEquipment());
- writeInventory(out, player.getBank());
-
- SkillSet skills = player.getSkillSet();
- out.writeByte(skills.size());
- for (int id = 0; id < skills.size(); id++) {
- Skill skill = skills.getSkill(id);
- out.writeByte(skill.getCurrentLevel());
- out.writeDouble(skill.getExperience());
- }
-
- List usernames = player.getFriendUsernames();
- out.writeByte(usernames.size());
- for (String username : usernames) {
- out.writeLong(NameUtil.encodeBase37(username));
- }
-
- usernames = player.getIgnoredUsernames();
- out.writeByte(usernames.size());
- for (String username : usernames) {
- out.writeLong(NameUtil.encodeBase37(username));
- }
-
- Set>> attributes = player.getAttributes().entrySet();
- attributes.removeIf(e -> AttributeMap.getDefinition(e.getKey()).getPersistence() != AttributePersistence.PERSISTENT);
- out.writeInt(attributes.size());
-
- for (Entry> entry : attributes) {
- String name = entry.getKey();
- StreamUtil.writeString(out, name);
-
- Attribute> attribute = entry.getValue();
- out.writeByte(attribute.getType().getValue());
- out.write(attribute.encode());
- }
- }
- }
-
- /**
- * Writes an inventory to the specified output stream.
- *
- * @param out The output stream.
- * @param inventory The inventory.
- * @throws IOException If an I/O error occurs.
- */
- private static void writeInventory(DataOutputStream out, Inventory inventory) throws IOException {
- int capacity = inventory.capacity();
- out.writeShort(capacity);
-
- for (int slot = 0; slot < capacity; slot++) {
- Item item = inventory.get(slot);
- if (item != null) {
- out.writeShort(item.getId() + 1);
- out.writeInt(item.getAmount());
- } else {
- out.writeShort(0);
- out.writeInt(0);
- }
- }
- }
-
-}
\ No newline at end of file
diff --git a/src/org/apollo/io/player/impl/BinaryPlayerUtil.java b/src/org/apollo/io/player/impl/BinaryPlayerUtil.java
deleted file mode 100644
index 9c4ca633..00000000
--- a/src/org/apollo/io/player/impl/BinaryPlayerUtil.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package org.apollo.io.player.impl;
-
-import java.io.File;
-
-import org.apollo.util.NameUtil;
-
-/**
- * A utility class with common functionality used by the binary player loader/ savers.
- *
- * @author Graham
- */
-public final class BinaryPlayerUtil {
-
- /**
- * The saved games directory.
- */
- private static final File SAVED_GAMES_DIRECTORY = new File("data/savedGames");
-
- /**
- * Creates the saved games directory if it does not exist.
- */
- static {
- if (!SAVED_GAMES_DIRECTORY.exists()) {
- SAVED_GAMES_DIRECTORY.mkdir();
- }
- }
-
- /**
- * Gets the save {@link File} for the specified player.
- *
- * @param username The username of the player.
- * @return The file.
- */
- public static File getFile(String username) {
- String filtered = NameUtil.decodeBase37(NameUtil.encodeBase37(username));
- return new File(SAVED_GAMES_DIRECTORY, filtered + ".dat");
- }
-
- /**
- * Default private constructor to prevent instantiation.
- */
- private BinaryPlayerUtil() {
-
- }
-
-}
\ No newline at end of file
diff --git a/src/org/apollo/io/player/impl/DiscardPlayerSaver.java b/src/org/apollo/io/player/impl/DiscardPlayerSaver.java
deleted file mode 100644
index cc00e839..00000000
--- a/src/org/apollo/io/player/impl/DiscardPlayerSaver.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package org.apollo.io.player.impl;
-
-import org.apollo.game.model.entity.Player;
-import org.apollo.io.player.PlayerSaver;
-
-/**
- * A {@link PlayerSaver} implementation that discards player data.
- *
- * @author Graham
- */
-public final class DiscardPlayerSaver implements PlayerSaver {
-
- @Override
- public void savePlayer(Player player) {
- /* discard player */
- }
-
-}
\ No newline at end of file
diff --git a/src/org/apollo/io/player/impl/JdbcPlayerLoader.java b/src/org/apollo/io/player/impl/JdbcPlayerLoader.java
deleted file mode 100644
index 9be78090..00000000
--- a/src/org/apollo/io/player/impl/JdbcPlayerLoader.java
+++ /dev/null
@@ -1,19 +0,0 @@
-package org.apollo.io.player.impl;
-
-import org.apollo.io.player.PlayerLoader;
-import org.apollo.io.player.PlayerLoaderResponse;
-import org.apollo.security.PlayerCredentials;
-
-/**
- * A {@link PlayerLoader} that utilises {@code JDBC} to load player files.
- *
- * @author Major
- */
-public final class JdbcPlayerLoader implements PlayerLoader {
-
- @Override
- public PlayerLoaderResponse loadPlayer(PlayerCredentials credentials) throws Exception {
- throw new UnsupportedOperationException("JDBC loading is not supported at this time.");
- }
-
-}
\ No newline at end of file
diff --git a/src/org/apollo/io/player/impl/JdbcPlayerSaver.java b/src/org/apollo/io/player/impl/JdbcPlayerSaver.java
deleted file mode 100644
index bbdc7d3d..00000000
--- a/src/org/apollo/io/player/impl/JdbcPlayerSaver.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package org.apollo.io.player.impl;
-
-import org.apollo.game.model.entity.Player;
-import org.apollo.io.player.PlayerSaver;
-
-/**
- * A {@link PlayerSaver} that utilises {@code JDBC} to save the player.
- *
- * @author Major
- */
-public final class JdbcPlayerSaver implements PlayerSaver {
-
- @Override
- public void savePlayer(Player player) throws Exception {
- throw new UnsupportedOperationException("JDBC saving is not supported at this time.");
- }
-
-}
\ No newline at end of file
diff --git a/src/org/apollo/io/player/impl/package-info.java b/src/org/apollo/io/player/impl/package-info.java
deleted file mode 100644
index a56ca9ca..00000000
--- a/src/org/apollo/io/player/impl/package-info.java
+++ /dev/null
@@ -1,4 +0,0 @@
-/**
- * Contains various player loader/saver implementations.
- */
-package org.apollo.io.player.impl;
\ No newline at end of file
diff --git a/src/org/apollo/login/LoginService.java b/src/org/apollo/login/LoginService.java
index fc45797f..d5664526 100644
--- a/src/org/apollo/login/LoginService.java
+++ b/src/org/apollo/login/LoginService.java
@@ -8,9 +8,8 @@ import java.util.concurrent.Executors;
import org.apollo.Service;
import org.apollo.game.model.entity.Player;
-import org.apollo.io.player.PlayerLoader;
import org.apollo.io.player.PlayerLoaderResponse;
-import org.apollo.io.player.PlayerSaver;
+import org.apollo.io.player.PlayerSerializer;
import org.apollo.net.codec.login.LoginConstants;
import org.apollo.net.codec.login.LoginRequest;
import org.apollo.net.release.Release;
@@ -25,6 +24,7 @@ import org.xml.sax.SAXException;
* The {@link LoginService} manages {@link LoginRequest}s.
*
* @author Graham
+ * @author Major
*/
public final class LoginService extends Service {
@@ -34,14 +34,9 @@ public final class LoginService extends Service {
private final ExecutorService executor = Executors.newCachedThreadPool(new NamedThreadFactory("LoginService"));
/**
- * The current {@link PlayerLoader}.
+ * The current {@link PlayerSerializer}.
*/
- private PlayerLoader loader;
-
- /**
- * The current {@link PlayerSaver}.
- */
- private PlayerSaver saver;
+ private PlayerSerializer serializer;
/**
* Creates the login service.
@@ -70,24 +65,16 @@ public final class LoginService extends Service {
}
if (!rootNode.getName().equals("login")) {
- throw new IOException("Unexpected root node name.");
+ throw new IOException("Unexpected root node name, expected 'login'.");
}
- XmlNode loaderNode = rootNode.getChild("loader");
- if (loaderNode == null || !loaderNode.hasValue()) {
- throw new IOException("No loader child node or value.");
+ XmlNode serializer = rootNode.getChild("serializer");
+ if (serializer == null || !serializer.hasValue()) {
+ throw new IOException("No serializer child node or value.");
}
- XmlNode saverNode = rootNode.getChild("saver");
- if (saverNode == null || !saverNode.hasValue()) {
- throw new IOException("No saver child node or value.");
- }
-
- Class> loaderClazz = Class.forName(loaderNode.getValue());
- Class> saverClazz = Class.forName(saverNode.getValue());
-
- loader = (PlayerLoader) loaderClazz.newInstance();
- saver = (PlayerSaver) saverClazz.newInstance();
+ Class> clazz = Class.forName(serializer.getValue());
+ this.serializer = (PlayerSerializer) clazz.newInstance();
}
/**
@@ -95,7 +82,7 @@ public final class LoginService extends Service {
*/
@Override
public void start() {
- /* empty - here for consistency with other services */
+
}
/**
@@ -110,7 +97,7 @@ public final class LoginService extends Service {
// TODO check archive 0 CRCs
session.handlePlayerLoaderResponse(request, new PlayerLoaderResponse(LoginConstants.STATUS_GAME_UPDATED));
} else {
- executor.submit(new PlayerLoaderWorker(loader, session, request));
+ executor.submit(new PlayerLoaderWorker(serializer, session, request));
}
}
@@ -121,7 +108,7 @@ public final class LoginService extends Service {
* @param player The player to save.
*/
public void submitSaveRequest(GameSession session, Player player) {
- executor.submit(new PlayerSaverWorker(saver, session, player));
+ executor.submit(new PlayerSaverWorker(serializer, session, player));
}
}
\ No newline at end of file
diff --git a/src/org/apollo/login/PlayerLoaderWorker.java b/src/org/apollo/login/PlayerLoaderWorker.java
index 9c9bfabe..0553fe77 100644
--- a/src/org/apollo/login/PlayerLoaderWorker.java
+++ b/src/org/apollo/login/PlayerLoaderWorker.java
@@ -3,8 +3,8 @@ package org.apollo.login;
import java.util.logging.Level;
import java.util.logging.Logger;
-import org.apollo.io.player.PlayerLoader;
import org.apollo.io.player.PlayerLoaderResponse;
+import org.apollo.io.player.PlayerSerializer;
import org.apollo.net.codec.login.LoginConstants;
import org.apollo.net.codec.login.LoginRequest;
import org.apollo.net.session.LoginSession;
@@ -22,9 +22,9 @@ public final class PlayerLoaderWorker implements Runnable {
private static final Logger logger = Logger.getLogger(PlayerLoaderWorker.class.getName());
/**
- * The player loader.
+ * The PlayerSerializer.
*/
- private final PlayerLoader loader;
+ private final PlayerSerializer loader;
/**
* The request.
@@ -39,11 +39,11 @@ public final class PlayerLoaderWorker implements Runnable {
/**
* Creates a {@link PlayerLoaderWorker} which will do the work for a single player load request.
*
- * @param loader The current player loader.
+ * @param loader The {@link PlayerSerializer}.
* @param session The {@link LoginSession} which initiated the request.
* @param request The {@link LoginRequest} object.
*/
- public PlayerLoaderWorker(PlayerLoader loader, LoginSession session, LoginRequest request) {
+ public PlayerLoaderWorker(PlayerSerializer loader, LoginSession session, LoginRequest request) {
this.loader = loader;
this.session = session;
this.request = request;
diff --git a/src/org/apollo/login/PlayerSaverWorker.java b/src/org/apollo/login/PlayerSaverWorker.java
index 2a0e369a..6ea2495c 100644
--- a/src/org/apollo/login/PlayerSaverWorker.java
+++ b/src/org/apollo/login/PlayerSaverWorker.java
@@ -4,7 +4,7 @@ import java.util.logging.Level;
import java.util.logging.Logger;
import org.apollo.game.model.entity.Player;
-import org.apollo.io.player.PlayerSaver;
+import org.apollo.io.player.PlayerSerializer;
import org.apollo.net.session.GameSession;
/**
@@ -27,7 +27,7 @@ public final class PlayerSaverWorker implements Runnable {
/**
* The player saver.
*/
- private final PlayerSaver saver;
+ private final PlayerSerializer saver;
/**
* The game session.
@@ -41,7 +41,7 @@ public final class PlayerSaverWorker implements Runnable {
* @param session The game session.
* @param player The player to save.
*/
- public PlayerSaverWorker(PlayerSaver saver, GameSession session, Player player) {
+ public PlayerSaverWorker(PlayerSerializer saver, GameSession session, Player player) {
this.saver = saver;
this.session = session;
this.player = player;