diff --git a/data/plugins/areas/actions.rb b/data/plugins/areas/actions.rb new file mode 100644 index 00000000..5c8872c5 --- /dev/null +++ b/data/plugins/areas/actions.rb @@ -0,0 +1,68 @@ +require 'java' + +java_import 'org.apollo.game.event.impl.DisplayCrossbonesEvent' +java_import 'org.apollo.game.model.entity.Player' + +AREA_ACTIONS = {} + +# An action that is called when a player enters or exits an area. +class AreaAction + + # Sets the block to be called when the player enters the area. + def on_entry(&block) + @on_enter = block + end + + # Sets the block to be called while the player is in the area. + def while_in(&block) + @while_in = block + end + + # Sets the block to be called when the player exits the area. + def on_exit(&block) + @on_exit = block + end + + # Called when the player has entered an area this action is registered to. + def entered(player) + @on_enter.call(player) unless @on_enter == nil + end + + # Called while the player is in area this action is registered to. + def inside(player) + @while_in.call(player) unless @while_in == nil + end + + # Called when the player has exited an area this action is registered to. + def exited(player) + @on_exit.call(player) unless @on_exit == nil + end + +end + +# Registers an area action. +def area_action(name, &block) + AREA_ACTIONS[name] = action = AreaAction.new + action.instance_eval(&block) +end + +# Defines a pvp area action. +area_action :pvp do + on_entry { |player| player.set_attribute("pvp", :boolean, true ) } + on_exit { |player| player.set_attribute("pvp", :boolean, false) } +end + +# Defines a multi-combat area action. +area_action :wilderness do + + on_entry do |player| + player.send(DisplayCrossbonesEvent.new(true)) + player.set_attribute("wilderness", :boolean, true) + end + + on_exit do |player| + player.send(DisplayCrossbonesEvent.new(false)) + player.set_attribute("wilderness", :boolean, false) + end + +end \ No newline at end of file diff --git a/data/plugins/areas/areas.rb b/data/plugins/areas/areas.rb new file mode 100644 index 00000000..a43f1ce4 --- /dev/null +++ b/data/plugins/areas/areas.rb @@ -0,0 +1,44 @@ +require 'java' + +java_import 'org.apollo.game.model.entity.Player' + +# A map of coordinates (as an array) to areas. +AREAS = [] + +# An area of the game world. +class Area + + def initialize(name, coordinates, actions) + @name = name + @coordinates = coordinates + @actions = actions + end + + # Called when the player has entered the area. + def entered(player) + actions.each { |action| action.entered(player) } + end + + # Called whilst the player is inside the area. + def inside(player) + acttions.each { |action| action.inside(player) } + end + + # Called when the player has exited the area. + def exited(player) + actions.each { |action| action.exited(player) } + end + +end + +# Creates a new area and registers it with the supplied coordinates. +def area(hash) + raise "Hash must contain a name, coordinates, and actions pair." unless hash.has_key?(:name) && hash.has_key?(:coordinates) && hash.has_key?(:actions) + name = hash[:name]; coordinates = hash[:coordinates]; actions = hash[:actions] + + AREAS << Area.new(name, coordinates, actions.is_a?(Symbol) ? [actions] : actions) +end + +# Coordinates refer to the bottom-left position (min_x, min_y) and the top-right position (max_x, max_y), followed by the height. +area :name => :wilderness, :coordinates => [ 2944, 3520, 3391, 3967, 0 ], :actions => [ :pvp, :multicombat, :wilderness ] +area :name => :duel_arena, :coordinates => [ 3327, 3200, 3392, 3286, 0 ], :actions => :pvp \ No newline at end of file diff --git a/data/plugins/bootstrap.rb b/data/plugins/bootstrap.rb index fee25fad..26ee1090 100644 --- a/data/plugins/bootstrap.rb +++ b/data/plugins/bootstrap.rb @@ -20,7 +20,7 @@ java_import 'org.apollo.game.login.LoginListener' java_import 'org.apollo.game.login.LogoutListener' java_import 'org.apollo.game.model.World' java_import 'org.apollo.game.model.entity.Player' -java_import 'org.apollo.game.model.settings.PrivilegeLevel' +java_import 'org.apollo.game.model.setting.PrivilegeLevel' java_import 'org.apollo.game.scheduling.ScheduledTask' # Alias the privilege levels. diff --git a/data/plugins/chat-privacy/privacy.rb b/data/plugins/chat-privacy/privacy.rb index 521c2d6e..c6984f33 100644 --- a/data/plugins/chat-privacy/privacy.rb +++ b/data/plugins/chat-privacy/privacy.rb @@ -1,6 +1,6 @@ require 'java' -java_import 'org.apollo.game.model.settings.PrivacyState' +java_import 'org.apollo.game.model.setting.PrivacyState' java_import 'org.apollo.game.event.impl.SendFriendEvent' on :event, :privacy_option do |ctx, player, event| diff --git a/data/plugins/cmd/filter/filter.rb b/data/plugins/cmd/filter/filter.rb index e405f803..951e80ac 100644 --- a/data/plugins/cmd/filter/filter.rb +++ b/data/plugins/cmd/filter/filter.rb @@ -2,7 +2,6 @@ require 'java' java_import 'org.apollo.game.event.impl.ForwardPrivateMessageEvent' java_import 'org.apollo.game.model.World' -java_import 'org.apollo.game.model.settings.PrivacyState' on :command, :filter do |player, command| player.send_message('Your message filter is now ' + (player.toggle_message_filter ? 'enabled.' : 'disabled.')) diff --git a/data/plugins/dialogue/dialogue.rb b/data/plugins/dialogue/dialogue.rb new file mode 100644 index 00000000..e8a09f24 --- /dev/null +++ b/data/plugins/dialogue/dialogue.rb @@ -0,0 +1,16 @@ + +# Intercepts the first npc action event. +on :event, :npc_action do |ctx, player, event| + if (event.option == 1) + # TODO check if player is not in pvp area + + end +end + +def dialogue(name, &block) + +end + +dialogue :banker_introduction do + # +end \ No newline at end of file diff --git a/data/plugins/entity/attributes/attributes.rb b/data/plugins/entity/attributes/attributes.rb index 0f81c6ba..720d8bd8 100644 --- a/data/plugins/entity/attributes/attributes.rb +++ b/data/plugins/entity/attributes/attributes.rb @@ -1,64 +1,78 @@ require 'java' java_import 'org.apollo.game.model.entity.Entity' - -# Maps attribute names (i.e. symbols) to attribute definitions. -ATTRIBUTE_DEFINITIONS = {} +java_import 'org.apollo.game.model.entity.attr.Attribute' +java_import 'org.apollo.game.model.entity.attr.AttributeDefinition' +java_import 'org.apollo.game.model.entity.attr.AttributeMap' +java_import 'org.apollo.game.model.entity.attr.AttributeType' +java_import 'org.apollo.game.model.entity.attr.BooleanAttribute' +java_import 'org.apollo.game.model.entity.attr.NumericalAttribute' +java_import 'org.apollo.game.model.entity.attr.StringAttribute' class Entity - # Overridies method_missing + # Overrides method_missing def method_missing(symbol, *args) name = symbol.to_s.strip if name[-1] == "=" - raise "Error - expected argument count of 1, received #{args.length}" unless args.length == 1 + raise "Expected argument count of 1, received #{args.length}" unless args.length == 1 - name = name[0...-1].strip # Drop the equals and preceeding whitespace - attributes[name] = args[0].is_a?(Symbol) ? args[0].to_s : args[0] - elsif ATTRIBUTE_DEFINITIONS[name] == nil + puts name + name = name[0...-1].strip # Drop the equals + set_attribute(name, to_attribute(args[0])) + elsif AttributeMap::get_definition(name) == nil super(symbol, *args) else - if attributes[name] == nil then return ATTRIBUTE_DEFINITIONS[name].default end - - return ATTRIBUTE_DEFINITIONS[name].type == :symbol ? attributes[name].to_sym : attributes[name] + attribute = get_attribute(name); definition = AttributeMap::get_definition(name) + value = attribute == nil ? definition.default : attribute.value + + return definition.type == AttributeType::SYMBOL ? value.to_sym : value end end - def to_s - return value.to_s - end - -end - -# An attribute belonging to an entity. -class AttributeDefinition - attr_reader :default, :type, :persistence - - def initialize(default, persistence=:transient) - @default = default - @type = get_type - @persistence = persistence - end - - def to_s - return "[AttributeDefinition - default=#{default}, type=#{type}, persistence=#{persistence}]." - end - - private # Gets the type of an attribute from its default value. - def get_type - case @default - when Fixnum, Integer then type = :number - when String then type = :string - when Symbol then type = :symbol - when TrueClass, FalseClass then type = :boolean - else raise "Error - #{value} has an unrecognised attribute type of #{value.class}." + # Gets the appropriate attribute for the specified value. + private + def to_attribute(value) + case value + when String, Symbol then return StringAttribute.new(value.to_s, value.is_a?(Symbol)) + when Integer, Float then return NumericalAttribute.new(value) + when TrueClass, FalseClass then return BooleanAttribute.new(value) + else raise "Undefined attribute type #{value.class}." end end end -# Declares an attribute which can then be assigned. +# Declares an attribute and adds its definition. def declare_attribute(name, default, persistence=:transient) - ATTRIBUTE_DEFINITIONS[name.to_s] = AttributeDefinition.new(default, persistence) + AttributeMap::add_definition(name.to_s, AttributeDefinition.new(default, get_persistence(persistence), get_type(default))) +end + +# Gets the attribute type of the specified value. +private +def get_type(value) + case value + when String then return AttributeType::STRING + when Symbol then return AttributeType::SYMBOL + when Integer then return AttributeType::LONG + when Float then return AttributeType::DOUBLE + when TrueClass, FalseClass then return AttributeType::BOOLEAN + else raise "Undefined attribute type #{value.class}." + end +end + +# Gets the Persistence type of the specified value. +def get_persistence(persistence) + raise "Undefined persistence type #{persistence}." unless persistence == :serialized || persistence == :transient + + return persistence == :serialized ? AttributeDefinition::Persistence::SERIALIZED : AttributeDefinition::Persistence::TRANSIENT +end + +declare_attribute :test, 42, :serialized + +on :command, :test do |player, command| + player.send_message(player.test.to_s) + player.test = 6.5 + player.send_message(player.test.to_s) end \ No newline at end of file diff --git a/data/plugins/entity/spawning/item-spawn.rb b/data/plugins/entity/spawning/item-spawn.rb new file mode 100644 index 00000000..20be250b --- /dev/null +++ b/data/plugins/entity/spawning/item-spawn.rb @@ -0,0 +1,44 @@ +require 'java' + +java_import 'org.apollo.game.model.Position' +java_import 'org.apollo.game.model.World' +java_import 'org.apollo.game.model.area.Sector' +java_import 'org.apollo.game.model.area.SectorCoordinates' +java_import 'org.apollo.game.model.area.SectorRepository' +java_import 'org.apollo.game.model.def.ItemDefinition' + +# :transient :recurrent + +def spawn_npc(hash) + raise 'A name (or id), x coordinate, and y coordinate must be specified to spawn an item' unless (hash.has_key?(:name) || hash.has_key?(:id)) && hash.has_key?(:x) && hash.has_key?(:y) + + z = hash.delete(:z) + position = Position.new(hash.delete(:x), hash.delete(:y), z == nil ? 0 : z) + +end + +def get_item(hash) + id = hash.delete(:id) + + if id == nil + name = hash.delete(:name).to_s.gsub('_', ' ') + if name.include?(' ') + id = name[name.rindex(' ') + 1, name.length - 1].to_i + end + id = locate_entity('item', name, 1).first if id == nil || id == 0 + end + + raise "The item called #{name} could not be identified." if id == nil + + amount = hash.delete(:amount) + return Item.new(id, amount) +end + +class GroundItem + + def initialise(id, amount, x, y, z) + @item = Item.new(id, amount) + @position = Position.new(x, y, z) + end + +end \ No newline at end of file diff --git a/data/plugins/location/al-kharid/npcs.rb b/data/plugins/location/al-kharid/npcs.rb new file mode 100644 index 00000000..cb088d85 --- /dev/null +++ b/data/plugins/location/al-kharid/npcs.rb @@ -0,0 +1,9 @@ + +spawn_npc :name => :gem_trader, :x => 3287, :y => 3210, :face => :south +spawn_npc :name => :al_karid_warrior_18, :x => 3288, :y => 3169 +spawn_npc :name => :al_karid_warrior_18, :x => 3295, :y => 3170 +spawn_npc :name => :al_karid_warrior_18, :x => 3297, :y => 3175 +spawn_npc :name => :al_karid_warrior_18, :x => 3300, :y => 3171 +spawn_npc :name => :al_karid_warrior_18, :x => 3301, :y => 3168 +spawn_npc :name => :al_karid_warrior_18, :x => 3301, :y => 3164 +spawn_npc :name => :al_karid_warrior_18, :x => 3295, :y => 3162 \ No newline at end of file diff --git a/data/plugins/private-messaging/friend.rb b/data/plugins/private-messaging/friend.rb index 57b2ec49..437e2db5 100644 --- a/data/plugins/private-messaging/friend.rb +++ b/data/plugins/private-messaging/friend.rb @@ -3,8 +3,8 @@ require 'java' java_import 'org.apollo.game.event.impl.FriendServerStatusEvent' java_import 'org.apollo.game.event.impl.SendFriendEvent' java_import 'org.apollo.game.model.World' -java_import 'org.apollo.game.model.settings.ServerStatus' -java_import 'org.apollo.game.model.settings.PrivacyState' +java_import 'org.apollo.game.model.setting.ServerStatus' +java_import 'org.apollo.game.model.setting.PrivacyState' java_import 'org.apollo.game.model.entity.Player' diff --git a/data/plugins/private-messaging/messaging.rb b/data/plugins/private-messaging/messaging.rb index 0f730252..e50a2ec6 100644 --- a/data/plugins/private-messaging/messaging.rb +++ b/data/plugins/private-messaging/messaging.rb @@ -2,7 +2,7 @@ require 'java' java_import 'org.apollo.game.event.impl.ForwardPrivateMessageEvent' java_import 'org.apollo.game.model.World' -java_import 'org.apollo.game.model.settings.PrivacyState' +java_import 'org.apollo.game.model.setting.PrivacyState' on :event, :private_message do |ctx, player, event| friend = World.world.get_player(event.username) diff --git a/data/plugins/skill/firemaking/firemaking.rb b/data/plugins/skill/firemaking/firemaking.rb new file mode 100644 index 00000000..e1f11ee2 --- /dev/null +++ b/data/plugins/skill/firemaking/firemaking.rb @@ -0,0 +1,54 @@ +require 'java' + +java_import 'org.apollo.game.action.Action' +java_import 'org.apollo.game.model.entity.Skill' + +FIRE_OBJECT_ID = 2732 + +LOGS = {} + +LIGHTERS = {} + +class Log + attr_reader :id, :level, :experience + + def initialize(id, level, experience) + @id = id + @level = level + @experience = experience + end + +end + +# An action where a player lights a log. +class LogLightingAction < Action + + def initialize(player, log, animation) + super(1, true, player) + @log = log + @time = 1 + end + + def execute + if time == 0 + player.play_animation(animation) + # TODO drop logs, spawn obj + else + time -= 1 + end + end + +end + +# Appends a log to the hash. +def append_log(hash) + raise "Hash must contain an id, level, and experience value." unless hash.has_key?(:id) && hash.has_key?(:level) && hash.has_key?(:experience) + id = hash[:id]; level = hash[:level]; experience = hash[:experience] + + LOGS[id] = Log.new(level, experience) +end + +# Appends a lighter to the hash. +def append_lighter(id, animation_id) + LIGHTERS[id] = animation_id +end \ No newline at end of file diff --git a/src/org/apollo/game/command/CommandListener.java b/src/org/apollo/game/command/CommandListener.java index 97202fa1..57eeffe6 100644 --- a/src/org/apollo/game/command/CommandListener.java +++ b/src/org/apollo/game/command/CommandListener.java @@ -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. diff --git a/src/org/apollo/game/event/handler/impl/PlayerDesignVerificationHandler.java b/src/org/apollo/game/event/handler/impl/PlayerDesignVerificationHandler.java index a7556e2e..3a7c514f 100644 --- a/src/org/apollo/game/event/handler/impl/PlayerDesignVerificationHandler.java +++ b/src/org/apollo/game/event/handler/impl/PlayerDesignVerificationHandler.java @@ -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. diff --git a/src/org/apollo/game/event/impl/ForwardPrivateMessageEvent.java b/src/org/apollo/game/event/impl/ForwardPrivateMessageEvent.java index fcd3d330..4344413b 100644 --- a/src/org/apollo/game/event/impl/ForwardPrivateMessageEvent.java +++ b/src/org/apollo/game/event/impl/ForwardPrivateMessageEvent.java @@ -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. diff --git a/src/org/apollo/game/event/impl/FriendServerStatusEvent.java b/src/org/apollo/game/event/impl/FriendServerStatusEvent.java index b46e348a..ec2c1d3d 100644 --- a/src/org/apollo/game/event/impl/FriendServerStatusEvent.java +++ b/src/org/apollo/game/event/impl/FriendServerStatusEvent.java @@ -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. diff --git a/src/org/apollo/game/event/impl/PrivacyOptionEvent.java b/src/org/apollo/game/event/impl/PrivacyOptionEvent.java index 59741573..7bc6e81e 100644 --- a/src/org/apollo/game/event/impl/PrivacyOptionEvent.java +++ b/src/org/apollo/game/event/impl/PrivacyOptionEvent.java @@ -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 diff --git a/src/org/apollo/game/model/Appearance.java b/src/org/apollo/game/model/Appearance.java index 50fd2d87..4cb3c9ad 100644 --- a/src/org/apollo/game/model/Appearance.java +++ b/src/org/apollo/game/model/Appearance.java @@ -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. diff --git a/src/org/apollo/game/model/entity/Entity.java b/src/org/apollo/game/model/entity/Entity.java index 5e4e3dee..1832e66f 100644 --- a/src/org/apollo/game/model/entity/Entity.java +++ b/src/org/apollo/game/model/entity/Entity.java @@ -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 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> getAttributes() { - return attributes.entrySet(); + public final Map> 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); } } \ No newline at end of file diff --git a/src/org/apollo/game/model/entity/Player.java b/src/org/apollo/game/model/entity/Player.java index 8c67a007..6ef90c81 100644 --- a/src/org/apollo/game/model/entity/Player.java +++ b/src/org/apollo/game/model/entity/Player.java @@ -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; diff --git a/src/org/apollo/game/model/entity/attr/Attribute.java b/src/org/apollo/game/model/entity/attr/Attribute.java new file mode 100644 index 00000000..9fff080f --- /dev/null +++ b/src/org/apollo/game/model/entity/attr/Attribute.java @@ -0,0 +1,52 @@ +package org.apollo.game.model.entity.attr; + +/** + * An attribute belonging to an entity. + * + * @author Major + * + * @param The type of attribute. + */ + +public abstract class Attribute { + + /** + * 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; + } + +} \ No newline at end of file diff --git a/src/org/apollo/game/model/entity/attr/AttributeDefinition.java b/src/org/apollo/game/model/entity/attr/AttributeDefinition.java new file mode 100644 index 00000000..b6cba520 --- /dev/null +++ b/src/org/apollo/game/model/entity/attr/AttributeDefinition.java @@ -0,0 +1,84 @@ +package org.apollo.game.model.entity.attr; + +/** + * A definition for an {@link Attribute}. + * + * @author Major + * + * @param The type of attribute. + */ +public final class AttributeDefinition { + + /** + * 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; + } + +} \ No newline at end of file diff --git a/src/org/apollo/game/model/entity/attr/AttributeMap.java b/src/org/apollo/game/model/entity/attr/AttributeMap.java new file mode 100644 index 00000000..70c4c271 --- /dev/null +++ b/src/org/apollo/game/model/entity/attr/AttributeMap.java @@ -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> 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> getDefinitions() { + return new HashMap<>(definitions); + } + + /** + * The map of attribute names to attributes. + */ + private Map> 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> 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); + } + +} \ No newline at end of file diff --git a/src/org/apollo/game/model/entity/attr/AttributeType.java b/src/org/apollo/game/model/entity/attr/AttributeType.java new file mode 100644 index 00000000..75e4e62e --- /dev/null +++ b/src/org/apollo/game/model/entity/attr/AttributeType.java @@ -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(); + } + +} \ No newline at end of file diff --git a/src/org/apollo/game/model/entity/attr/BooleanAttribute.java b/src/org/apollo/game/model/entity/attr/BooleanAttribute.java new file mode 100644 index 00000000..e5409c66 --- /dev/null +++ b/src/org/apollo/game/model/entity/attr/BooleanAttribute.java @@ -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 { + + /** + * Creates the boolean attribute. + * + * @param value The value. + */ + public BooleanAttribute(Boolean value) { + super(AttributeType.BOOLEAN, value); + } + +} \ No newline at end of file diff --git a/src/org/apollo/game/model/entity/attr/NumericalAttribute.java b/src/org/apollo/game/model/entity/attr/NumericalAttribute.java new file mode 100644 index 00000000..a7f21982 --- /dev/null +++ b/src/org/apollo/game/model/entity/attr/NumericalAttribute.java @@ -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 { + + /** + * 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); + } + +} \ No newline at end of file diff --git a/src/org/apollo/game/model/entity/attr/StringAttribute.java b/src/org/apollo/game/model/entity/attr/StringAttribute.java new file mode 100644 index 00000000..be7c763c --- /dev/null +++ b/src/org/apollo/game/model/entity/attr/StringAttribute.java @@ -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 { + + /** + * 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); + } + +} \ No newline at end of file diff --git a/src/org/apollo/game/model/entity/attr/package-info.java b/src/org/apollo/game/model/entity/attr/package-info.java new file mode 100644 index 00000000..53564181 --- /dev/null +++ b/src/org/apollo/game/model/entity/attr/package-info.java @@ -0,0 +1,4 @@ +/** + * Contains attribute-related files. + */ +package org.apollo.game.model.entity.attr; \ No newline at end of file diff --git a/src/org/apollo/game/model/entity/setting/Gender.java b/src/org/apollo/game/model/setting/Gender.java similarity index 91% rename from src/org/apollo/game/model/entity/setting/Gender.java rename to src/org/apollo/game/model/setting/Gender.java index 9cd43668..1e95bae1 100644 --- a/src/org/apollo/game/model/entity/setting/Gender.java +++ b/src/org/apollo/game/model/setting/Gender.java @@ -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 diff --git a/src/org/apollo/game/model/entity/setting/PrivacyState.java b/src/org/apollo/game/model/setting/PrivacyState.java similarity index 97% rename from src/org/apollo/game/model/entity/setting/PrivacyState.java rename to src/org/apollo/game/model/setting/PrivacyState.java index ed865e0a..f5a5458c 100644 --- a/src/org/apollo/game/model/entity/setting/PrivacyState.java +++ b/src/org/apollo/game/model/setting/PrivacyState.java @@ -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 diff --git a/src/org/apollo/game/model/entity/setting/PrivilegeLevel.java b/src/org/apollo/game/model/setting/PrivilegeLevel.java similarity index 96% rename from src/org/apollo/game/model/entity/setting/PrivilegeLevel.java rename to src/org/apollo/game/model/setting/PrivilegeLevel.java index b77b4c5e..b03a9d0c 100644 --- a/src/org/apollo/game/model/entity/setting/PrivilegeLevel.java +++ b/src/org/apollo/game/model/setting/PrivilegeLevel.java @@ -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 diff --git a/src/org/apollo/game/model/entity/setting/ScreenBrightness.java b/src/org/apollo/game/model/setting/ScreenBrightness.java similarity index 96% rename from src/org/apollo/game/model/entity/setting/ScreenBrightness.java rename to src/org/apollo/game/model/setting/ScreenBrightness.java index 57d3311e..6918bd02 100644 --- a/src/org/apollo/game/model/entity/setting/ScreenBrightness.java +++ b/src/org/apollo/game/model/setting/ScreenBrightness.java @@ -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 diff --git a/src/org/apollo/game/model/entity/setting/ServerStatus.java b/src/org/apollo/game/model/setting/ServerStatus.java similarity index 95% rename from src/org/apollo/game/model/entity/setting/ServerStatus.java rename to src/org/apollo/game/model/setting/ServerStatus.java index 8aceb035..c2761fe6 100644 --- a/src/org/apollo/game/model/entity/setting/ServerStatus.java +++ b/src/org/apollo/game/model/setting/ServerStatus.java @@ -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 diff --git a/src/org/apollo/game/model/entity/setting/package-info.java b/src/org/apollo/game/model/setting/package-info.java similarity index 60% rename from src/org/apollo/game/model/entity/setting/package-info.java rename to src/org/apollo/game/model/setting/package-info.java index db35d20a..5c8ed99e 100644 --- a/src/org/apollo/game/model/entity/setting/package-info.java +++ b/src/org/apollo/game/model/setting/package-info.java @@ -1,4 +1,4 @@ /** * Contains player setting or customisation-related classes. */ -package org.apollo.game.model.entity.setting; \ No newline at end of file +package org.apollo.game.model.setting; \ No newline at end of file diff --git a/src/org/apollo/game/sync/block/ChatBlock.java b/src/org/apollo/game/sync/block/ChatBlock.java index b55b3b43..f10d0344 100644 --- a/src/org/apollo/game/sync/block/ChatBlock.java +++ b/src/org/apollo/game/sync/block/ChatBlock.java @@ -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. diff --git a/src/org/apollo/io/player/impl/BinaryPlayerLoader.java b/src/org/apollo/io/player/impl/BinaryPlayerLoader.java index d4bfbeeb..4b3032dd 100644 --- a/src/org/apollo/io/player/impl/BinaryPlayerLoader.java +++ b/src/org/apollo/io/player/impl/BinaryPlayerLoader.java @@ -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> 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> readAttributes(DataInputStream in) throws IOException { + int count = in.readInt(); + Map> 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. * diff --git a/src/org/apollo/io/player/impl/BinaryPlayerSaver.java b/src/org/apollo/io/player/impl/BinaryPlayerSaver.java index e694bcc6..6e9644c4 100644 --- a/src/org/apollo/io/player/impl/BinaryPlayerSaver.java +++ b/src/org/apollo/io/player/impl/BinaryPlayerSaver.java @@ -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 attribute : player.getAttributes()) { + Map> attributes = player.getAttributes(); + out.writeInt(attributes.size()); + for (Entry> 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 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> 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 + "."); } } diff --git a/src/org/apollo/io/player/impl/DummyPlayerLoader.java b/src/org/apollo/io/player/impl/DummyPlayerLoader.java index 95cd971d..0cc48ed4 100644 --- a/src/org/apollo/io/player/impl/DummyPlayerLoader.java +++ b/src/org/apollo/io/player/impl/DummyPlayerLoader.java @@ -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; diff --git a/src/org/apollo/net/release/r317/PlayerDesignEventDecoder.java b/src/org/apollo/net/release/r317/PlayerDesignEventDecoder.java index d67ef001..c3d2ada5 100644 --- a/src/org/apollo/net/release/r317/PlayerDesignEventDecoder.java +++ b/src/org/apollo/net/release/r317/PlayerDesignEventDecoder.java @@ -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; diff --git a/src/org/apollo/net/release/r317/PlayerSynchronizationEventEncoder.java b/src/org/apollo/net/release/r317/PlayerSynchronizationEventEncoder.java index 524c73c6..97897a69 100644 --- a/src/org/apollo/net/release/r317/PlayerSynchronizationEventEncoder.java +++ b/src/org/apollo/net/release/r317/PlayerSynchronizationEventEncoder.java @@ -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; diff --git a/src/org/apollo/net/release/r377/PlayerDesignEventDecoder.java b/src/org/apollo/net/release/r377/PlayerDesignEventDecoder.java index 421f03d7..052bb904 100644 --- a/src/org/apollo/net/release/r377/PlayerDesignEventDecoder.java +++ b/src/org/apollo/net/release/r377/PlayerDesignEventDecoder.java @@ -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; diff --git a/src/org/apollo/net/release/r377/PlayerSynchronizationEventEncoder.java b/src/org/apollo/net/release/r377/PlayerSynchronizationEventEncoder.java index 0555bf0f..b73aca55 100644 --- a/src/org/apollo/net/release/r377/PlayerSynchronizationEventEncoder.java +++ b/src/org/apollo/net/release/r377/PlayerSynchronizationEventEncoder.java @@ -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;