Redo attributes system, add support for saving and loading, move settings classes around.

This commit is contained in:
Major-
2014-07-19 04:15:06 +01:00
parent 9d465e4885
commit 13ca51809c
42 changed files with 762 additions and 103 deletions
@@ -1,7 +1,7 @@
package org.apollo.game.command;
import org.apollo.game.model.entity.Player;
import org.apollo.game.model.entity.setting.PrivilegeLevel;
import org.apollo.game.model.setting.PrivilegeLevel;
/**
* An interface which should be implemented to listen to {@link Command}s.
@@ -5,7 +5,7 @@ import org.apollo.game.event.handler.EventHandlerContext;
import org.apollo.game.event.impl.PlayerDesignEvent;
import org.apollo.game.model.Appearance;
import org.apollo.game.model.entity.Player;
import org.apollo.game.model.entity.setting.Gender;
import org.apollo.game.model.setting.Gender;
/**
* An {@link EventHandler} that verifies {@link PlayerDesignEvent}s.
@@ -1,7 +1,7 @@
package org.apollo.game.event.impl;
import org.apollo.game.event.Event;
import org.apollo.game.model.entity.setting.PrivilegeLevel;
import org.apollo.game.model.setting.PrivilegeLevel;
/**
* An {@link Event} sent to the client that forwards a private message.
@@ -1,7 +1,7 @@
package org.apollo.game.event.impl;
import org.apollo.game.event.Event;
import org.apollo.game.model.entity.setting.ServerStatus;
import org.apollo.game.model.setting.ServerStatus;
/**
* An {@link Event} sent to the client to update the friend server status.
@@ -1,7 +1,7 @@
package org.apollo.game.event.impl;
import org.apollo.game.event.Event;
import org.apollo.game.model.entity.setting.PrivacyState;
import org.apollo.game.model.setting.PrivacyState;
/**
* An {@link Event} sent both by and to the client to update the public chat, private (friend) chat, and trade chat
+1 -1
View File
@@ -1,6 +1,6 @@
package org.apollo.game.model;
import org.apollo.game.model.entity.setting.Gender;
import org.apollo.game.model.setting.Gender;
/**
* Represents the appearance of a player.
+13 -14
View File
@@ -1,11 +1,10 @@
package org.apollo.game.model.entity;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.apollo.game.model.Position;
import org.apollo.game.model.entity.attr.Attribute;
import org.apollo.game.model.entity.attr.AttributeMap;
/**
* Represents an in-game entity, such as a mob, object, projectile etc.
@@ -49,9 +48,9 @@ public abstract class Entity {
}
/**
* A map of attribute names to attributes.
* The attribute map of this entity.
*/
protected final Map<String, Object> attributes = new HashMap<>(5);
protected final AttributeMap attributes = new AttributeMap();
/**
* The position of this entity.
@@ -73,17 +72,17 @@ public abstract class Entity {
* @param name The name of the attribute.
* @return The value of the attribute.
*/
public final Object getAttribute(String name) {
return attributes.get(name);
public final Attribute<?> getAttribute(String name) {
return attributes.getAttribute(name);
}
/**
* Gets all of the attributes of this entity, as a {@link Set} of {@link Entry} objects.
* Gets a shallow copy of the attributes of this entity, as a {@link Map}.
*
* @return The set of attributes.
* @return The map of attributes.
*/
public final Set<Entry<String, Object>> getAttributes() {
return attributes.entrySet();
public final Map<String, Attribute<?>> getAttributes() {
return attributes.getAttributes();
}
/**
@@ -106,10 +105,10 @@ public abstract class Entity {
* Sets the value of the attribute with the specified name.
*
* @param name The name of the attribute.
* @param value The value of the attribute.
* @param value The attribute.
*/
public final void setAttribute(String name, Object value) {
attributes.put(name, value);
public final void setAttribute(String name, Attribute<?> value) {
attributes.setAttribute(name, value);
}
}
+3 -3
View File
@@ -18,9 +18,6 @@ import org.apollo.game.event.impl.UpdateRunEnergyEvent;
import org.apollo.game.model.Appearance;
import org.apollo.game.model.Position;
import org.apollo.game.model.World;
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.inter.InterfaceConstants;
import org.apollo.game.model.inter.InterfaceListener;
import org.apollo.game.model.inter.InterfaceSet;
@@ -33,6 +30,9 @@ import org.apollo.game.model.inv.InventoryConstants;
import org.apollo.game.model.inv.InventoryListener;
import org.apollo.game.model.inv.SynchronizationInventoryListener;
import org.apollo.game.model.inv.Inventory.StackMode;
import org.apollo.game.model.setting.PrivacyState;
import org.apollo.game.model.setting.PrivilegeLevel;
import org.apollo.game.model.setting.ScreenBrightness;
import org.apollo.game.model.skill.LevelUpSkillListener;
import org.apollo.game.model.skill.SynchronizationSkillListener;
import org.apollo.game.sync.block.SynchronizationBlock;
@@ -0,0 +1,52 @@
package org.apollo.game.model.entity.attr;
/**
* An attribute belonging to an entity.
*
* @author Major
*
* @param <T> The type of attribute.
*/
public abstract class Attribute<T> {
/**
* The type of this attribute.
*/
private final AttributeType type;
/**
* The value of this attribute.
*/
protected T value;
/**
* Creates the attribute with the specified {@link AttributeType} and value.
*
* @param type The type.
* @param value The value.
*/
protected Attribute(AttributeType type, T value) {
this.type = type;
this.value = value;
}
/**
* Gets the type of this attribute.
*
* @return The type.
*/
public AttributeType getType() {
return type;
}
/**
* Gets the value of this attribute.
*
* @return The value.
*/
public T getValue() {
return value;
}
}
@@ -0,0 +1,84 @@
package org.apollo.game.model.entity.attr;
/**
* A definition for an {@link Attribute}.
*
* @author Major
*
* @param <T> The type of attribute.
*/
public final class AttributeDefinition<T> {
/**
* The persistence state of an attribute - either {@code PERSISTENT} (saved) or {@code TRANSIENT} (not saved).
*/
public enum Persistence {
/**
* The serialized persistence type, indicating that the attribute will be saved.
*/
SERIALIZED,
/**
* The transient persistence type, indicating that the attribute will not be saved.
*/
TRANSIENT;
}
/**
* The default value of this definition.
*/
private final T defaultValue;
/**
* The persistence state of this definition.
*/
private final Persistence persistence;
/**
* The type of this definition.
*/
private final AttributeType type;
/**
* Creates the attribute definition.
*
* @param defaultValue The default value.
* @param persistence The {@link Persistence} state.
* @param type The {@link AttributeType}.
*/
public AttributeDefinition(T defaultValue, Persistence persistence, AttributeType type) {
this.defaultValue = defaultValue;
this.persistence = persistence;
this.type = type;
}
/**
* Gets the default value of this attribute definition.
*
* @return The default value.
*/
public T getDefault() {
return defaultValue;
}
/**
* Gets the persistence state of this attribute definition.
*
* @return The persistence.
*/
public Persistence getPersistence() {
return persistence;
}
/**
* Gets the {@link AttributeType} of this definition.
*
* @return The attribute type.
*/
public AttributeType getType() {
return type;
}
}
@@ -0,0 +1,79 @@
package org.apollo.game.model.entity.attr;
import java.util.HashMap;
import java.util.Map;
public final class AttributeMap {
/**
* The map of attribute names to definitions.
*/
private static Map<String, AttributeDefinition<?>> definitions = new HashMap<>(50);
/**
* Registers an {@link AttributeDefinition}.
*
* @param name The name of the attribute.
* @param definition The definition.
*/
public static void addDefinition(String name, AttributeDefinition<?> definition) {
definitions.put(name, definition);
}
/**
* Gets the {@link AttributeDefinition} with the specified name, or {@code null} if it is not defined.
*
* @param name The name of the attribute.
* @return The attribute definition.
*/
public static AttributeDefinition<?> getDefinition(String name) {
return definitions.get(name);
}
/**
* Gets the {@link AttributeDefinitions}, as a {@link Map}.
*
* @return The map of attribute names to definitions.
*/
public static Map<String, AttributeDefinition<?>> getDefinitions() {
return new HashMap<>(definitions);
}
/**
* The map of attribute names to attributes.
*/
private Map<String, Attribute<?>> attributes = new HashMap<>();
/**
* Gets the {@link Attribute} with the specified name.
*
* @param name The name of the attribute.
* @return The attribute.
*/
public Attribute<?> getAttribute(String name) {
return attributes.get(name);
}
/**
* Gets a shallow copy of the map of attributes.
*
* @return The attributes.
*/
public Map<String, Attribute<?>> getAttributes() {
return new HashMap<>(attributes);
}
/**
* Sets the value of the {@link Attribute} with the specified name.
*
* @param name The name of the attribute.
* @param attribute The attribute.
*/
public void setAttribute(String name, Attribute<?> attribute) {
if (getDefinition(name) == null) {
throw new IllegalArgumentException("Attributes must be defined before their value can be set.");
}
attributes.put(name, attribute);
}
}
@@ -0,0 +1,55 @@
package org.apollo.game.model.entity.attr;
/**
* The type of attribute. The functionality of this enum (and other classes) is dependent on the ordering of the values
* - the expected order is {@link #BOOLEAN}, {@link#DOUBLE}, {@link #LONG}, {@link #STRING}, {@link #SYMBOL}.
*
* @author Major
*/
public enum AttributeType {
/**
* The boolean attribute type.
*/
BOOLEAN,
/**
* The double attribute type.
*/
DOUBLE,
/**
* The long attribute type.
*/
LONG,
/**
* The string attribute type.
*/
STRING,
/**
* The symbol attribute type.
*/
SYMBOL;
/**
* Gets the type with the specified ordinal.
*
* @param ordinal The ordinal.
* @return The type.
*/
public static AttributeType valueOf(int ordinal) {
return values()[ordinal];
}
/**
* Gets the value of this attribute type.
*
* @return The value.
*/
public int getValue() {
return ordinal();
}
}
@@ -0,0 +1,19 @@
package org.apollo.game.model.entity.attr;
/**
* An {@link Attribute} with a boolean value.
*
* @author Major
*/
public final class BooleanAttribute extends Attribute<Boolean> {
/**
* Creates the boolean attribute.
*
* @param value The value.
*/
public BooleanAttribute(Boolean value) {
super(AttributeType.BOOLEAN, value);
}
}
@@ -0,0 +1,29 @@
package org.apollo.game.model.entity.attr;
/**
* An {@link Attribute} with a numerical value.
*
* @author Major
*/
public final class NumericalAttribute extends Attribute<Number> {
/**
* Gets the {@link AttributeType} of number this attribute is.
*
* @param value The value of this attribute.
* @return The type.
*/
private static final AttributeType typeOf(Number value) {
return value instanceof Double ? AttributeType.DOUBLE : AttributeType.LONG;
}
/**
* Creates the number attribute.
*
* @param value The value of this attribute.
*/
public NumericalAttribute(Number value) {
super(typeOf(value), value);
}
}
@@ -0,0 +1,29 @@
package org.apollo.game.model.entity.attr;
/**
* An {@link Attribute} with a string value.
*
* @author Major
*/
public final class StringAttribute extends Attribute<String> {
/**
* Creates the string attribute.
*
* @param value The value.
*/
public StringAttribute(String value) {
this(value, false);
}
/**
* Creates the string attribute.
*
* @param value The value.
* @param symbol Whether or not the attribute is a symbol.
*/
public StringAttribute(String value, boolean symbol) {
super(symbol ? AttributeType.SYMBOL : AttributeType.STRING, value);
}
}
@@ -0,0 +1,4 @@
/**
* Contains attribute-related files.
*/
package org.apollo.game.model.entity.attr;
@@ -1,4 +1,4 @@
package org.apollo.game.model.entity.setting;
package org.apollo.game.model.setting;
/**
* An enumeration containing the two genders (male and female). This enumeration relies on the ordering of the elements
@@ -1,4 +1,4 @@
package org.apollo.game.model.entity.setting;
package org.apollo.game.model.setting;
/**
* An enumeration representing the different privacy states for public, private and trade chat. This enumeration relies
@@ -1,4 +1,4 @@
package org.apollo.game.model.entity.setting;
package org.apollo.game.model.setting;
/**
* An enumeration with the different privilege levels a player can have. This enumeration relies on the ordering of the
@@ -1,4 +1,4 @@
package org.apollo.game.model.entity.setting;
package org.apollo.game.model.setting;
/**
* An enumeration representing the brightness of a player's screen. This enumeration relies on the ordering of the
@@ -1,4 +1,4 @@
package org.apollo.game.model.entity.setting;
package org.apollo.game.model.setting;
/**
* Represents the status of the friend server. This enumeration relies on the ordering of the elements within, which
@@ -1,4 +1,4 @@
/**
* Contains player setting or customisation-related classes.
*/
package org.apollo.game.model.entity.setting;
package org.apollo.game.model.setting;
@@ -1,7 +1,7 @@
package org.apollo.game.sync.block;
import org.apollo.game.event.impl.ChatEvent;
import org.apollo.game.model.entity.setting.PrivilegeLevel;
import org.apollo.game.model.setting.PrivilegeLevel;
/**
* The chat {@link SynchronizationBlock}. Only players can utilise this block.
@@ -5,7 +5,9 @@ import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apollo.game.model.Appearance;
import org.apollo.game.model.Item;
@@ -13,11 +15,16 @@ 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.setting.Gender;
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.entity.attr.Attribute;
import org.apollo.game.model.entity.attr.AttributeType;
import org.apollo.game.model.entity.attr.BooleanAttribute;
import org.apollo.game.model.entity.attr.NumericalAttribute;
import org.apollo.game.model.entity.attr.StringAttribute;
import org.apollo.game.model.inv.Inventory;
import org.apollo.game.model.setting.Gender;
import org.apollo.game.model.setting.PrivacyState;
import org.apollo.game.model.setting.PrivilegeLevel;
import org.apollo.game.model.setting.ScreenBrightness;
import org.apollo.io.player.PlayerLoader;
import org.apollo.io.player.PlayerLoaderResponse;
import org.apollo.net.codec.login.LoginConstants;
@@ -135,10 +142,51 @@ public final class BinaryPlayerLoader implements PlayerLoader {
}
player.setIgnoredUsernames(ignores);
Map<String, Attribute<?>> attributes = readAttributes(in);
attributes.forEach(player::setAttribute);
return new PlayerLoaderResponse(LoginConstants.STATUS_OK, player);
}
}
/**
* Reads the player's {@link Attribute}s.
*
* @param in The input stream.
* @return The {@link Map} of attribute names to attributes.
* @throws IOException If there is an error reading from the stream.
*/
private Map<String, Attribute<?>> readAttributes(DataInputStream in) throws IOException {
int count = in.readInt();
Map<String, Attribute<?>> attributes = new HashMap<>(count);
Attribute<?> attribute;
for (int i = 0; i < count; i++) {
String name = StreamUtil.readString(in);
AttributeType type = AttributeType.valueOf(in.read());
switch (type) {
case BOOLEAN:
attribute = new BooleanAttribute(in.read() == 1);
break;
case DOUBLE:
attribute = new NumericalAttribute(in.readDouble());
break;
case LONG:
attribute = new NumericalAttribute(in.readLong());
break;
case STRING:
case SYMBOL:
attribute = new StringAttribute(StreamUtil.readString(in), type == AttributeType.SYMBOL);
break;
default:
throw new IllegalArgumentException("Undefined attribute type: " + type + ".");
}
attributes.put(name, attribute);
}
return attributes;
}
/**
* Reads an inventory from the input stream.
*
@@ -5,6 +5,7 @@ import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.apollo.game.model.Appearance;
@@ -13,6 +14,8 @@ 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.AttributeType;
import org.apollo.game.model.inv.Inventory;
import org.apollo.io.player.PlayerSaver;
import org.apollo.util.NameUtil;
@@ -89,33 +92,43 @@ public final class BinaryPlayerSaver implements PlayerSaver {
out.writeLong(NameUtil.encodeBase37(username));
}
for (Entry<String, Object> attribute : player.getAttributes()) {
Map<String, Attribute<?>> attributes = player.getAttributes();
out.writeInt(attributes.size());
for (Entry<String, Attribute<?>> attribute : player.getAttributes().entrySet()) {
saveAttribute(out, attribute);
}
}
}
/**
* Writes an attribute to the specified output stream.
* Writes an attribute map entry to the specified output stream.
*
* @param out The output stream.
* @param attribute The attribute.
* @param entry The map entry.
* @throws IOException If an I/O error occurs.
*/
private void saveAttribute(DataOutputStream out, Entry<String, Object> attribute) throws IOException {
StreamUtil.writeString(out, attribute.getKey());
Object value = attribute.getValue();
if (value instanceof String) {
out.writeByte(0);
StreamUtil.writeString(out, (String) value);
} else if (value instanceof Integer) {
out.writeByte(1);
out.writeInt((Integer) value);
} else if (value instanceof Boolean) {
out.writeByte(2);
out.writeByte(((Boolean) value) ? 1 : 0);
} else {
throw new IllegalArgumentException("Undefined attribute type " + value + ".");
private void saveAttribute(DataOutputStream out, Entry<String, Attribute<?>> entry) throws IOException {
StreamUtil.writeString(out, entry.getKey());
Attribute<?> attribute = entry.getValue();
AttributeType type = attribute.getType();
out.writeByte(type.getValue());
switch (type) {
case BOOLEAN:
out.writeByte((boolean) attribute.getValue() ? 1 : 0);
break;
case DOUBLE:
out.writeDouble((double) attribute.getValue());
break;
case LONG:
out.writeLong((long) attribute.getValue());
break;
case STRING:
case SYMBOL:
StreamUtil.writeString(out, (String) attribute.getValue());
break;
default:
throw new IllegalArgumentException("Undefined attribute type " + type + ".");
}
}
@@ -2,7 +2,7 @@ package org.apollo.io.player.impl;
import org.apollo.game.model.Position;
import org.apollo.game.model.entity.Player;
import org.apollo.game.model.entity.setting.PrivilegeLevel;
import org.apollo.game.model.setting.PrivilegeLevel;
import org.apollo.io.player.PlayerLoader;
import org.apollo.io.player.PlayerLoaderResponse;
import org.apollo.net.codec.login.LoginConstants;
@@ -2,7 +2,7 @@ package org.apollo.net.release.r317;
import org.apollo.game.event.impl.PlayerDesignEvent;
import org.apollo.game.model.Appearance;
import org.apollo.game.model.entity.setting.Gender;
import org.apollo.game.model.setting.Gender;
import org.apollo.net.codec.game.DataType;
import org.apollo.net.codec.game.GamePacket;
import org.apollo.net.codec.game.GamePacketReader;
@@ -9,8 +9,8 @@ import org.apollo.game.model.Item;
import org.apollo.game.model.Position;
import org.apollo.game.model.def.EquipmentDefinition;
import org.apollo.game.model.entity.EquipmentConstants;
import org.apollo.game.model.entity.setting.Gender;
import org.apollo.game.model.inv.Inventory;
import org.apollo.game.model.setting.Gender;
import org.apollo.game.sync.block.AnimationBlock;
import org.apollo.game.sync.block.AppearanceBlock;
import org.apollo.game.sync.block.ChatBlock;
@@ -2,7 +2,7 @@ package org.apollo.net.release.r377;
import org.apollo.game.event.impl.PlayerDesignEvent;
import org.apollo.game.model.Appearance;
import org.apollo.game.model.entity.setting.Gender;
import org.apollo.game.model.setting.Gender;
import org.apollo.net.codec.game.DataType;
import org.apollo.net.codec.game.GamePacket;
import org.apollo.net.codec.game.GamePacketReader;
@@ -9,8 +9,8 @@ import org.apollo.game.model.Item;
import org.apollo.game.model.Position;
import org.apollo.game.model.def.EquipmentDefinition;
import org.apollo.game.model.entity.EquipmentConstants;
import org.apollo.game.model.entity.setting.Gender;
import org.apollo.game.model.inv.Inventory;
import org.apollo.game.model.setting.Gender;
import org.apollo.game.sync.block.AnimationBlock;
import org.apollo.game.sync.block.AppearanceBlock;
import org.apollo.game.sync.block.ChatBlock;