Merge PlayerSaver and PlayerLoader into PlayerSerializer.

This commit is contained in:
Major-
2015-03-03 07:25:20 +00:00
parent 1859276a22
commit 65ecd1b5fc
18 changed files with 300 additions and 350 deletions
+1 -2
View File
@@ -1,4 +1,3 @@
<login> <login>
<loader>org.apollo.io.player.impl.DummyPlayerLoader</loader> <serializer>org.apollo.io.player.DummyPlayerSerializer</serializer>
<saver>org.apollo.io.player.impl.DiscardPlayerSaver</saver>
</login> </login>
@@ -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() {
}
}
@@ -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.DataInputStream;
import java.io.DataOutputStream;
import java.io.File; import java.io.File;
import java.io.FileInputStream;
import java.io.IOException; 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.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.apollo.game.model.Appearance; import org.apollo.game.model.Appearance;
import org.apollo.game.model.Item; 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.Skill;
import org.apollo.game.model.entity.SkillSet; import org.apollo.game.model.entity.SkillSet;
import org.apollo.game.model.entity.attr.Attribute; 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.AttributeType;
import org.apollo.game.model.entity.attr.BooleanAttribute; import org.apollo.game.model.entity.attr.BooleanAttribute;
import org.apollo.game.model.entity.attr.NumericalAttribute; 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.PrivilegeLevel;
import org.apollo.game.model.entity.setting.ScreenBrightness; import org.apollo.game.model.entity.setting.ScreenBrightness;
import org.apollo.game.model.inv.Inventory; 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.net.codec.login.LoginConstants;
import org.apollo.security.PlayerCredentials; import org.apollo.security.PlayerCredentials;
import org.apollo.util.NameUtil; import org.apollo.util.NameUtil;
@@ -36,28 +43,39 @@ import org.apollo.util.StreamUtil;
import com.lambdaworks.crypto.SCryptUtil; 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 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 @Override
public PlayerLoaderResponse loadPlayer(PlayerCredentials credentials) throws IOException { public PlayerLoaderResponse loadPlayer(PlayerCredentials credentials) throws IOException {
File file = BinaryPlayerUtil.getFile(credentials.getUsername()); Path path = getFile(credentials.getUsername());
if (!file.exists()) { if (!Files.exists(path)) {
Player player = new Player(credentials, SPAWN_POSITION); Player player = new Player(credentials, TUTORIAL_ISLAND_SPAWN);
player.getBank().add(995, 25); // 25 coins
credentials.setPassword(SCryptUtil.scrypt(credentials.getPassword(), 16384, 8, 1)); credentials.setPassword(SCryptUtil.scrypt(credentials.getPassword(), 16384, 8, 1));
return new PlayerLoaderResponse(LoginConstants.STATUS_OK, player); 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 name = StreamUtil.readString(in);
String password = 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. 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()); MembershipStatus members = MembershipStatus.valueOf(in.readByte());
PrivacyState chatPrivacy = PrivacyState.valueOf(in.readByte(), true); PrivacyState chatPrivacy = PrivacyState.valueOf(in.readByte(), true);
PrivacyState friendPrivacy = PrivacyState.valueOf(in.readByte(), false); PrivacyState friendPrivacy = PrivacyState.valueOf(in.readByte(), false);
PrivacyState tradePrivacy = PrivacyState.valueOf(in.readByte(), false); PrivacyState tradePrivacy = PrivacyState.valueOf(in.readByte(), false);
int runEnergy = in.readByte();
ScreenBrightness brightness = ScreenBrightness.valueOf(in.readByte()); ScreenBrightness brightness = ScreenBrightness.valueOf(in.readByte());
int x = in.readUnsignedShort(); int x = in.readUnsignedShort();
int y = in.readUnsignedShort(); int y = in.readUnsignedShort();
int height = in.readUnsignedByte(); int height = in.readUnsignedByte();
int genderIntValue = in.readUnsignedByte(); Gender gender = (in.readUnsignedByte() == Gender.MALE.toInteger()) ? Gender.MALE : Gender.FEMALE;
Gender gender = genderIntValue == Gender.MALE.toInteger() ? Gender.MALE : Gender.FEMALE;
int[] style = new int[7]; int[] style = new int[7];
for (int i = 0; i < style.length; i++) { for (int slot = 0; slot < style.length; slot++) {
style[i] = in.readUnsignedByte(); style[slot] = in.readUnsignedByte();
} }
int[] colors = new int[5]; int[] colors = new int[5];
for (int i = 0; i < colors.length; i++) { for (int slot = 0; slot < colors.length; slot++) {
colors[i] = in.readUnsignedByte(); colors[slot] = in.readUnsignedByte();
} }
Player player = new Player(credentials, new Position(x, y, height)); Player player = new Player(credentials, new Position(x, y, height));
player.setPrivilegeLevel(privilegeLevel); player.setPrivilegeLevel(privilege);
player.setMembers(members); player.setMembers(members);
player.setChatPrivacy(chatPrivacy); player.setChatPrivacy(chatPrivacy);
player.setFriendPrivacy(friendPrivacy); player.setFriendPrivacy(friendPrivacy);
player.setTradePrivacy(tradePrivacy); player.setTradePrivacy(tradePrivacy);
player.setRunEnergy(runEnergy);
player.setScreenBrightness(brightness); player.setScreenBrightness(brightness);
player.setAppearance(new Appearance(gender, style, colors)); 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<String> 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<Entry<String, Attribute<?>>> attributes = player.getAttributes().entrySet();
attributes.removeIf(e -> AttributeMap.getDefinition(e.getKey()).getPersistence() != AttributePersistence.PERSISTENT);
out.writeInt(attributes.size());
for (Entry<String, Attribute<?>> 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. * 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. * @return The {@link Map} of attribute names to attributes.
* @throws IOException If there is an error reading from the stream. * @throws IOException If there is an error reading from the stream.
*/ */
private static Map<String, Attribute<?>> readAttributes(DataInputStream in) throws IOException { private Map<String, Attribute<?>> readAttributes(DataInputStream in) throws IOException {
int count = in.readInt(); int count = in.readInt();
Map<String, Attribute<?>> attributes = new HashMap<>(count); Map<String, Attribute<?>> attributes = new HashMap<>(count);
@@ -187,7 +284,7 @@ public final class BinaryPlayerLoader implements PlayerLoader {
* @param inventory The inventory. * @param inventory The inventory.
* @throws IOException If an I/O error occurs. * @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(); int capacity = in.readUnsignedShort();
inventory.stopFiringEvents(); 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);
}
}
}
} }
@@ -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.Player;
import org.apollo.game.model.entity.setting.MembershipStatus; import org.apollo.game.model.entity.setting.MembershipStatus;
import org.apollo.game.model.entity.setting.PrivilegeLevel; 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.net.codec.login.LoginConstants;
import org.apollo.security.PlayerCredentials; 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 Graham
* @author Major
*/ */
public final class DummyPlayerLoader implements PlayerLoader { public final class DummyPlayerSerializer implements PlayerSerializer {
/**
* The default spawn position for players loaded by this loader.
*/
private static final Position DEFAULT_POSITION = new Position(3093, 3104);
@Override @Override
public PlayerLoaderResponse loadPlayer(PlayerCredentials credentials) { public PlayerLoaderResponse loadPlayer(PlayerCredentials credentials) {
int status = LoginConstants.STATUS_OK; 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.setPrivilegeLevel(PrivilegeLevel.ADMINISTRATOR);
player.setMembers(MembershipStatus.PAID); player.setMembers(MembershipStatus.PAID);
return new PlayerLoaderResponse(status, player); return new PlayerLoaderResponse(status, player);
} }
@Override
public void savePlayer(Player player) {
/* discard player */
}
} }
@@ -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.");
}
}
@@ -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;
}
@@ -8,9 +8,10 @@ import org.apollo.net.codec.login.LoginConstants;
import com.google.common.base.Preconditions; 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 Graham
* @author Major
*/ */
public final class PlayerLoaderResponse { public final class PlayerLoaderResponse {
@@ -32,7 +33,8 @@ public final class PlayerLoaderResponse {
* {@link LoginConstants#STATUS_RECONNECTION_OK}. * {@link LoginConstants#STATUS_RECONNECTION_OK}.
*/ */
public PlayerLoaderResponse(int status) { 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; this.status = status;
player = Optional.empty(); player = Optional.empty();
} }
@@ -46,7 +48,8 @@ public final class PlayerLoaderResponse {
* @throws NullPointerException If the specified player is null. * @throws NullPointerException If the specified player is null.
*/ */
public PlayerLoaderResponse(int status, Player player) { 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.status = status;
this.player = Optional.of(player); this.player = Optional.of(player);
} }
-21
View File
@@ -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;
}
@@ -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;
}
@@ -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<String> 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<Entry<String, Attribute<?>>> attributes = player.getAttributes().entrySet();
attributes.removeIf(e -> AttributeMap.getDefinition(e.getKey()).getPersistence() != AttributePersistence.PERSISTENT);
out.writeInt(attributes.size());
for (Entry<String, Attribute<?>> 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);
}
}
}
}
@@ -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() {
}
}
@@ -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 */
}
}
@@ -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.");
}
}
@@ -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.");
}
}
@@ -1,4 +0,0 @@
/**
* Contains various player loader/saver implementations.
*/
package org.apollo.io.player.impl;
+13 -26
View File
@@ -8,9 +8,8 @@ import java.util.concurrent.Executors;
import org.apollo.Service; import org.apollo.Service;
import org.apollo.game.model.entity.Player; import org.apollo.game.model.entity.Player;
import org.apollo.io.player.PlayerLoader;
import org.apollo.io.player.PlayerLoaderResponse; 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.LoginConstants;
import org.apollo.net.codec.login.LoginRequest; import org.apollo.net.codec.login.LoginRequest;
import org.apollo.net.release.Release; import org.apollo.net.release.Release;
@@ -25,6 +24,7 @@ import org.xml.sax.SAXException;
* The {@link LoginService} manages {@link LoginRequest}s. * The {@link LoginService} manages {@link LoginRequest}s.
* *
* @author Graham * @author Graham
* @author Major
*/ */
public final class LoginService extends Service { 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")); private final ExecutorService executor = Executors.newCachedThreadPool(new NamedThreadFactory("LoginService"));
/** /**
* The current {@link PlayerLoader}. * The current {@link PlayerSerializer}.
*/ */
private PlayerLoader loader; private PlayerSerializer serializer;
/**
* The current {@link PlayerSaver}.
*/
private PlayerSaver saver;
/** /**
* Creates the login service. * Creates the login service.
@@ -70,24 +65,16 @@ public final class LoginService extends Service {
} }
if (!rootNode.getName().equals("login")) { 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"); XmlNode serializer = rootNode.getChild("serializer");
if (loaderNode == null || !loaderNode.hasValue()) { if (serializer == null || !serializer.hasValue()) {
throw new IOException("No loader child node or value."); throw new IOException("No serializer child node or value.");
} }
XmlNode saverNode = rootNode.getChild("saver"); Class<?> clazz = Class.forName(serializer.getValue());
if (saverNode == null || !saverNode.hasValue()) { this.serializer = (PlayerSerializer) clazz.newInstance();
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();
} }
/** /**
@@ -95,7 +82,7 @@ public final class LoginService extends Service {
*/ */
@Override @Override
public void start() { 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 // TODO check archive 0 CRCs
session.handlePlayerLoaderResponse(request, new PlayerLoaderResponse(LoginConstants.STATUS_GAME_UPDATED)); session.handlePlayerLoaderResponse(request, new PlayerLoaderResponse(LoginConstants.STATUS_GAME_UPDATED));
} else { } 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. * @param player The player to save.
*/ */
public void submitSaveRequest(GameSession session, Player player) { public void submitSaveRequest(GameSession session, Player player) {
executor.submit(new PlayerSaverWorker(saver, session, player)); executor.submit(new PlayerSaverWorker(serializer, session, player));
} }
} }
+5 -5
View File
@@ -3,8 +3,8 @@ package org.apollo.login;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import org.apollo.io.player.PlayerLoader;
import org.apollo.io.player.PlayerLoaderResponse; 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.LoginConstants;
import org.apollo.net.codec.login.LoginRequest; import org.apollo.net.codec.login.LoginRequest;
import org.apollo.net.session.LoginSession; 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()); 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. * 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. * 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 session The {@link LoginSession} which initiated the request.
* @param request The {@link LoginRequest} object. * @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.loader = loader;
this.session = session; this.session = session;
this.request = request; this.request = request;
+3 -3
View File
@@ -4,7 +4,7 @@ import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import org.apollo.game.model.entity.Player; 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; import org.apollo.net.session.GameSession;
/** /**
@@ -27,7 +27,7 @@ public final class PlayerSaverWorker implements Runnable {
/** /**
* The player saver. * The player saver.
*/ */
private final PlayerSaver saver; private final PlayerSerializer saver;
/** /**
* The game session. * The game session.
@@ -41,7 +41,7 @@ public final class PlayerSaverWorker implements Runnable {
* @param session The game session. * @param session The game session.
* @param player The player to save. * @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.saver = saver;
this.session = session; this.session = session;
this.player = player; this.player = player;