diff --git a/data/login.xml b/data/login.xml index 27f2d6fa..c7f0371a 100644 --- a/data/login.xml +++ b/data/login.xml @@ -1,4 +1,3 @@ - org.apollo.io.player.impl.DummyPlayerLoader - org.apollo.io.player.impl.DiscardPlayerSaver + org.apollo.io.player.DummyPlayerSerializer \ No newline at end of file diff --git a/data/plugins/areas/plugin.xml b/data/plugins/areas/plugin.xml index 2c18bb32..0e9c4b1b 100644 --- a/data/plugins/areas/plugin.xml +++ b/data/plugins/areas/plugin.xml @@ -10,6 +10,7 @@ + diff --git a/data/plugins/areas/wilderness.rb b/data/plugins/areas/wilderness.rb new file mode 100644 index 00000000..27fcbd54 --- /dev/null +++ b/data/plugins/areas/wilderness.rb @@ -0,0 +1,52 @@ +require 'java' + +java_import 'org.apollo.game.model.entity.Player' +java_import 'org.apollo.game.message.impl.OpenOverlayMessage' +java_import 'org.apollo.game.message.impl.SetWidgetTextMessage' + + + +private + +MIN_X = 2945 +MIN_Y = 3522 +MAX_X = 3390 +MAX_Y = 3972 + +OVERLAY_INTERFACE_ID = 197 +LEVEL_STRING_ID = 199 + +declare_attribute(:wilderness_level, 0, :transient) + +# Determines the wilderness level for the specified player's position +def wilderness_level(player) + return (player.position.y - (MIN_Y - 1) / 8).ceil +end + +area_action :wilderness_level do + + on_entry do |player| + player.wilderness_level = wilderness_level(player) + player.interface_set.open_overlay(OVERLAY_INTERFACE_ID) + player.send(SetWidgetTextMessage.new(LEVEL_STRING_ID, "Level: #{player.wilderness_level}")) + show_action(ATTACK_ACTION) + end + + while_in do |player| + current = player.wilderness_level + updated = wilderness_level(player) + if (current != updated) + player.wilderness_level = updated + player.send(SetWidgetTextMessage.new(LEVEL_STRING_ID, "Level: #{player.wilderness_level}")) + end + end + + on_exit do |player| + player.wilderness_level = 0 + player.interface_set.close() # TODO: Will this cause issues with other potentially open interfaces? + hide_action(ATTACK_ACTION) + end + +end + +area :name => :wilderness, :coordinates => MIN_X, MIN_Y, MAX_X, MAX_Y, 0, => :actions => :wilderness_level \ No newline at end of file diff --git a/data/plugins/dialogue/dialogue.rb b/data/plugins/dialogue/dialogue.rb index ffe51c9a..523424ad 100644 --- a/data/plugins/dialogue/dialogue.rb +++ b/data/plugins/dialogue/dialogue.rb @@ -6,6 +6,7 @@ java_import 'org.apollo.game.message.impl.SetWidgetItemModelMessage' java_import 'org.apollo.game.message.impl.SetWidgetNpcModelMessage' java_import 'org.apollo.game.message.impl.SetWidgetPlayerModelMessage' java_import 'org.apollo.game.message.impl.SetWidgetTextMessage' +java_import 'org.apollo.game.action.DistancedAction' # The map of conversation names to Conversations. CONVERSATIONS = {} @@ -20,6 +21,30 @@ def conversation(name, &block) CONVERSATIONS[name] = conversation end +# A distanced action which opens the dialogue when getting into interaction distance of the given npc +class OpenDialogueAction < DistancedAction + attr_reader :player, :npc, :dialogue + + def initialize(player, npc, dialogue) + super(0, true, player, npc.position, 1) + + @player = player + @npc = npc + @dialogue = dialogue + end + + def executeAction + @player.set_interacting_mob(@npc) + send_dialogue(@player, @dialogue) + stop + end + + def equals(other) + return (@npc == other.npc && @dialogue == other.dialogue) + end + +end + # A conversation held between two entities. class Conversation @@ -42,15 +67,16 @@ class Conversation @dialogues[name] = dialogue if ((@dialogues.empty? || dialogue.has_precondition?) && dialogue.type == :npc_speech) - npc = dialogue.npc - raise 'Npc cannot be null when opening a dialogue.' if npc.nil? + npc_index = dialogue.npc + raise 'Npc cannot be null when opening a dialogue.' if npc_index.nil? @starters << dialogue on :message, :first_npc_action do |ctx, player, event| - if npc == $world.npc_repository.get(event.index).id + npc = $world.npc_repository.get(event.index) + if npc_index == npc.id @starters.each do |start| if dialogue.precondition(player) - send_dialogue(player, dialogue) + player.start_action(OpenDialogueAction.new(player, npc, dialogue)) ctx.break_handler_chain() break end @@ -74,6 +100,12 @@ def declare_emote(name, id) end +# Sends the dialogue from the specified Conversation with the specified name. +def get_dialogue(conversation, name) + CONVERSATIONS[conversation].part(name) +end + + # Sends the specified dialogue. def send_dialogue(player, dialogue) type = dialogue.type @@ -144,17 +176,6 @@ class Dialogue @options << ->(player) { action.call(player) unless type.nil?; block.call(player) unless block.nil? } end - # Copies the value of every variable from the specified Dialogue, optionally updating the text array. - def copy_from(dialogue, text=nil) - @emote = dialogue.emote - @item = dialogue.item - @model = dialogue.model - @npc = dialogue.npc - @options = dialogue.options - @text = if text.nil? then dialogue.text.dup else text.dup end - @type = dialogue.type - end - # Sets the emote performed by the dialogue head. def emote(emote=nil) unless emote.nil? @@ -186,16 +207,21 @@ class Dialogue end # Sets the id of the item displayed. - def item(item=nil, scale=nil) + def item(item=nil, scale=100) unless item.nil? raise 'Can only display an item on :message_with_item dialogues.' unless @type == :message_with_item - @item = item + @item = lookup_item(item) @item_scale = scale end @item end + # Gets the scale of the item. + def item_scale + @item_scale + end + # Sets the id of the model displayed. def model(model=nil) unless model.nil? @@ -228,7 +254,7 @@ class Dialogue def options @options.dup end - + # Sets the precondition of this dialogue. def precondition(player=nil, &block) @precondition = block unless block.nil? @@ -296,6 +322,19 @@ class Dialogue @text = lines end + protected + + # Copies the value of every variable from the specified Dialogue, optionally updating the text array. + def copy_from(dialogue, text=nil) + @emote = dialogue.emote + @item = dialogue.item + @model = dialogue.model + @npc = dialogue.npc + @options = dialogue.options + @text = if text.nil? then dialogue.text.dup else text.dup end + @type = dialogue.type + end + private # Inserts a copy of this Dialogue into the chain, but with different text. @@ -350,6 +389,17 @@ OPTIONS_DIALOGUE_IDS = [ 2459, 2469, 2480, 2492 ] ## TODO separate this into different Dialogue types ## +# Sends a dialogue displaying an item model and text. +def send_item_dialogue(player, dialogue) + text = dialogue.text + dialogue_id = ITEM_DIALOGUE_IDS[text.size - 1] + player.send(SetWidgetItemModelMessage.new(dialogue_id + 1, dialogue.item, dialogue.item_scale)) + + indices = [ dialogue_id + 1 + 2, dialogue_id + 1 + 1, dialogue_id + 1 + 4, dialogue_id + 1 + 5 ] + + text.each_with_index { |line, index| set_text(player, indices[index], line) } + player.interface_set.open_dialogue(ContinueDialogueAdapter.new(player, dialogue.options[0]), dialogue_id) +end # Sends a dialogue displaying only text, with no 'Click here to continue...' button. def send_statement_dialogue(player, dialogue) diff --git a/data/plugins/entity/spawning/npc-spawn.rb b/data/plugins/entity/spawning/npc-spawn.rb index f5e86397..65aeeec3 100644 --- a/data/plugins/entity/spawning/npc-spawn.rb +++ b/data/plugins/entity/spawning/npc-spawn.rb @@ -16,7 +16,7 @@ java_import 'org.apollo.game.model.entity.Npc' # :y - the y coordinate where the npc will spawn. # Optional arguments are as follows: # :face - the direction the npc should face when it spawns. Supported options are :north, :north_east, :east, :south_east, :south, :south_west, :west, and :north_west -# :bounds - the rectangular bound that the npc can wander about in. Order is [top-left x-coordinate, top-left y-coordinate, bottom-right x-coordinate, bottom-right y-coordinate] +# :bounds - the rectangular bound that the npc can wander about in. Order is [bottom-left x-coordinate, bottom-left y-coordinate, top-right x-coordinate, top-right y-coordinate] # :delta_bounds - the rectangular bound that the npc can wander about in, as a difference from the spawn point. Order is [x-delta, y-delta]. Should not be used with :bounds. # :spawn_animation - the animation that will be played when the npc spawns. # :spawn_graphic - the graphic that will be played when the npc spawns. @@ -33,11 +33,12 @@ end # Spawns the specified npc and applies the properties in the hash. def spawn(npc, hash) - $world.register(npc) unless hash.empty? - hash = decode_hash(npc.position, hash) # Use npc.position here because sector registry events (called by World.register) can be hooked - apply_decoded_hash(npc, hash) # into and someone might do something daft like move the npc immediately after it gets spawned. + hash = decode_hash(npc.position, hash) + apply_decoded_hash(npc, hash) end + + $world.register(npc) end # Returns an npc with the id and position specified by the hash. @@ -54,7 +55,7 @@ def apply_decoded_hash(npc, hash) hash.each do |key, value| case key when :face then npc.turn_to(value) - when :boundary then npc.boundary = value + when :boundary then npc.boundaries = value when :spawn_animation then npc.play_animation(Animation.new(value)) when :spawn_graphic then npc.play_graphic(Graphic.new(value)) else raise "Unrecognised key #{key} - value #{value}." @@ -71,11 +72,16 @@ def decode_hash(position, hash) when :face decoded[:face] = direction_to_position(value, position) when :delta_bounds + raise ':delta_bounds must have two values.' unless value.length == 2 dx, dy, x, y, z = value[0], value[1], position.x, position.y, position.height raise 'Delta values cannot be less than 0.' if (dx < 0 || dy < 0) - decoded[:boundary] = [ Position.new(x + dx, y, z), Position.new(x, y + dy, z), Position.new(x - dx, y, z), Position.new(x, y - dy, z) ] - when :bounds then decoded[:boundary] = value + decoded[:boundary] = [ Position.new(x - dx, y - dy, z), Position.new(x + dx, y + dy, z) ] + when :bounds + raise ':bounds must have four values.' unless value.length == 4 + min_x, min_y, max_x, max_y = value[0], value[1], value[2], value[3] + + decoded[:boundary] = [ Position.new(min_x, min_y), Position.new(max_x, max_y) ] when :spawn_animation then decoded[:spawn_animation] = Animation.new(value) when :spawn_graphic then decoded[:spawn_graphic ] = Graphic.new(value) else raise "Unrecognised key #{key} - value #{value}." diff --git a/data/plugins/location/al-kharid/npcs.rb b/data/plugins/location/al-kharid/npcs.rb index d61324ae..f5d48346 100644 --- a/data/plugins/location/al-kharid/npcs.rb +++ b/data/plugins/location/al-kharid/npcs.rb @@ -6,7 +6,7 @@ # :y - the y coordinate where the npc will spawn. # Optional arguments are as follows: # :face - the direction the npc should face when it spawns. Supported options are :north, :north_east, :east, :south_east, :south, :south_west, :west, and :north_west -# :bounds - the rectangular bound that the npc can wander about in. Order is [top-left x-coordinate, top-left y-coordinate, bottom-right x-coordinate, bottom-right y-coordinate] +# :bounds - the rectangular bound that the npc can wander about in. Order is [bottom-left x-coordinate, bottom-left y-coordinate, top-right x-coordinate, top-right y-coordinate] # :delta_bounds - the rectangular bound that the npc can wander about in, as a difference from the spawn point. Order is [x-delta, y-delta]. Should not be used with :bounds. # :spawn_animation - the animation that will be played when the npc spawns. # :spawn_graphic - the graphic that will be played when the npc spawns. diff --git a/data/plugins/location/edgeville/npcs.rb b/data/plugins/location/edgeville/npcs.rb index 36cb4eb0..f8dbd14c 100644 --- a/data/plugins/location/edgeville/npcs.rb +++ b/data/plugins/location/edgeville/npcs.rb @@ -6,7 +6,7 @@ # :y - the y coordinate where the npc will spawn. # Optional arguments are as follows: # :face - the direction the npc should face when it spawns. Supported options are :north, :north_east, :east, :south_east, :south, :south_west, :west, and :north_west -# :bounds - the rectangular bound that the npc can wander about in. Order is [top-left x-coordinate, top-left y-coordinate, bottom-right x-coordinate, bottom-right y-coordinate] +# :bounds - the rectangular bound that the npc can wander about in. Order is [bottom-left x-coordinate, bottom-left y-coordinate, top-right x-coordinate, top-right y-coordinate] # :delta_bounds - the rectangular bound that the npc can wander about in, as a difference from the spawn point. Order is [x-delta, y-delta]. Should not be used with :bounds. # :spawn_animation - the animation that will be played when the npc spawns. # :spawn_graphic - the graphic that will be played when the npc spawns. diff --git a/data/plugins/location/lumbridge/npcs.rb b/data/plugins/location/lumbridge/npcs.rb index 12dfc1d0..73f15689 100644 --- a/data/plugins/location/lumbridge/npcs.rb +++ b/data/plugins/location/lumbridge/npcs.rb @@ -6,7 +6,7 @@ # :y - the y coordinate where the npc will spawn. # Optional arguments are as follows: # :face - the direction the npc should face when it spawns. Supported options are :north, :north_east, :east, :south_east, :south, :south_west, :west, and :north_west -# :bounds - the rectangular bound that the npc can wander about in. Order is [top-left x-coordinate, top-left y-coordinate, bottom-right x-coordinate, bottom-right y-coordinate] +# :bounds - the rectangular bound that the npc can wander about in. Order is [bottom-left x-coordinate, bottom-left y-coordinate, top-right x-coordinate, top-right y-coordinate] # :delta_bounds - the rectangular bound that the npc can wander about in, as a difference from the spawn point. Order is [x-delta, y-delta]. Should not be used with :bounds. # :spawn_animation - the animation that will be played when the npc spawns. # :spawn_graphic - the graphic that will be played when the npc spawns. diff --git a/data/plugins/location/tutorial-island/guide.rb b/data/plugins/location/tutorial-island/guide.rb new file mode 100644 index 00000000..16abb698 --- /dev/null +++ b/data/plugins/location/tutorial-island/guide.rb @@ -0,0 +1,119 @@ +require 'java' + +java_import 'org.apollo.game.message.impl.HintIconMessage' +java_import 'org.apollo.game.message.impl.SwitchTabInterfaceMessage' + + +private + +# The ids of tabs that are displayed when the player has yet to start the tutorial. +INITIAL_TABS = [ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 2449, 904, -1, -1 ] + +# The character design interface id. +CHARACTER_DESIGN = 3559 + +# The Runescape guide Npc +@runescape_guide = spawn_npc :name => :runescape_guide, :x => 3093, :y => 3107 + +# Sends the appropriate data to the client when the player logs in to the game. +on :login do |event, player| + if player.in_tutorial_island + TutorialInstructions::show_instruction(player) + # INITIAL_TABS.each_with_index { |tab, index| player.send(SwitchTabInterfaceMessage.new(index, tab)) } # This is commented so the lame hack works + + if (player.tutorial_island_progress == :not_started) + show_hint_icon(player) + player.interface_set.open_window(CHARACTER_DESIGN) + end + end +end + +## TODO lame hack to get round the lack of door support - must remove + + +on :message, :fifth_item_option do |ctx, player, message| + player.teleport(Position.new(3100, 3107)) if message.id == 1 + player.tutorial_island_progress = :moving_around + player.interface_set.open_dialogue_overlay(-1) +end + +on :login do |event, player| + player.inventory.add(1) +end + +## END lame hack + + +# The conversation with the Runescape Guide, when on tutorial island. +conversation :tutorial_runescape_guide do + + # The first dialogue of the Runescape Guide, greeting the Player. + dialogue :greetings do + type :npc_speech + npc :runescape_guide + + precondition { |player| player.tutorial_island_progress == :not_started } + + text "Greetings! I see you are a new arrival to this land. My job is to welcome all new visitors. So welcome!" + + continue :dialogue => :go_through_door do |player| + player.tutorial_island_progress = :talk_to_people + end + end + + + # The Guide welcomes back the Player if they speak to him after they have already gone through the conversation once. + dialogue :welcome_back do + type :npc_speech + npc :runescape_guide + + precondition { |player| player.tutorial_island_progress != :not_started } + + text "Welcome back." + + continue :dialogue => :talk_to_people + end + + + # The Guide tells Players to speak to people in order to succeed. + dialogue :talk_to_people do + type :npc_speech + npc :runescape_guide + + text "You have already learned the first thing you need to succeed in this world: talking to people!", + "You will find many inhabitants of this world have useful things to say to you. By clicking on them with your mouse you can talk to them.", + "I would also suggest reading through some of the supporting information on the website. There you can find maps, a bestiary, and much more." + + continue :dialogue => :go_through_door + end + + # The Guide tells Players to go through the door, advancing the tutorial progress if this is the first time the Player has heard this. + dialogue :go_through_door do + type :npc_speech + npc :runescape_guide + + text "To continue the tutorial go through that door over there, and speak to your first instructor." + + continue :close => true do |player| + if (player.tutorial_island_progress < :runescape_guide_finished) + reset_hint_icon(player) + # TODO door hint icon + player.tutorial_island_progress = :runescape_guide_finished + end + + TutorialInstructions.show_instruction(player) + end + end + +end + + +# Enables the hint icon above the Runescape guide. +def show_hint_icon(player) + player.send(HintIconMessage.for_npc(@runescape_guide.index)) +end + +# Resets the hint icon. +def reset_hint_icon(player) + player.send(HintIconMessage.reset_npc()) +end \ No newline at end of file diff --git a/data/plugins/location/tutorial-island/instructions.rb b/data/plugins/location/tutorial-island/instructions.rb new file mode 100644 index 00000000..26c223c5 --- /dev/null +++ b/data/plugins/location/tutorial-island/instructions.rb @@ -0,0 +1,121 @@ + +# TODO update the status to :moving_around when the door is opened + +# Contains members related to the instructions issues during tutorial island. +module TutorialInstructions + + # Sends the appropriate instruction to the player. + def self.show_instruction(player) + instructions = CONVERSATIONS[:tutorial_island_instructions] + progress = player.tutorial_island_progress.name + name = case progress + # The Runescape Guide instructions. + when :not_started then :getting_started + when :runescape_guide_finished then :scenery + when :moving_around then :moving_around + + # The Survival Guide instructions. + when :given_axe then :viewing_items + when :cut_tree then :cut_tree + when :cutting_tree then :please_wait + else raise "No dialogue for current stage #{progress} exists." + end + + dialogue = instructions.part(name) + send_dialogue(player, dialogue) + end + + + # The one-sided 'conversation' of instruction instructions. + conversation :tutorial_island_instructions do + + # The initial instruction displayed when the player logs in, before they have spoken to the guide. + dialogue :getting_started do + type :text + + title "Getting started" + text "To start the tutorial, use your left mouse button to click on the Runescape Guide in this room. He is indicated by "\ + "a flashing yellow arrow above his head. If you can't see him, use your keyboard's arrow keys to rotate the view." + end + + # The instruction displayed after the player has spoken to the Runescape Guide. + dialogue :scenery do + type :text + + title "Interacting with scenery" + text "You can interact with many items of the scenery by simply clicking on them. Right clicking will also give more options. "\ + "Click on the door indicated with the yellow arrow to go through to the next area and speak with your next instructor." + end + + ## TODO !! When we have door support, the player's tutorial island progress needs to be set to :moving_around when they walk through the door !! + + # The instruction displayed after the player has left the initial building. + dialogue :moving_around do + type :text + + title "Moving around" + text "Follow the path to find the next instructor. Clicking on the ground will walk you to that point. Talk to the survival expert "\ + "by the pond to continue the tutorial. Remember you can rotate the view by pressing the arrow keys." + end + + # The instruction displayed after the player has been given the tinderbox and bronze axe by the Survival Guide. + dialogue :viewing_items do + type :text + + title "Viewing the items you were given" + text "Click on the flashing backpack icon to the right side of the main window to view your inventory. Your inventory is a list of "\ + "everything you have in your backpack." + end + + # The instruction displayed before the player has begun to cut the tree. + dialogue :cut_tree do + type :text + + title "Cut down a tree" + text "You can click on the backpack icon at any time to view the items that you currently have in your inventory. You will see that you "\ + "now have an axe in your inventory. Use this to get some logs by clicking on the indicated tree." + end + + # The instruction displayed when the player begins to cut the tree. + dialogue :please_wait do + type :text + + title "Please wait..." + text "Your character is now attempting to cut down the tree. Sit back for a moment whilst he does all the hard work." # TODO she instead of he if applicable + end + + # The instruction displayed after the player has successfully cut logs from the tree. + dialogue :make_a_fire do + type :text + + title "Making a fire" + text "Well done! You managed to cut some logs from the tree! Next, use the tinderbox in your inventory to light the logs. First click on the "\ + "tinderbox to 'use' it. Then click on the logs in your inventory to light them." + end + + # The instruction displayed when the player begins to light the fire. + dialogue :lighting_fire do + type :text + + title "Please wait..." + text "Your character is now attempting to light the logs. Sit back for a moment whilst he does all the hard work." # TODO she instead of he if applicable + end + + # The instruction displayed when the has lit the logs. + dialogue :gained_experience do + type :text + + text "You gained some experience."\ + "Click on the flashing bar graph icon near the inventory button to see your skill stats." + end + + # The dialogue displayed when the Player has clicked the flashing skill tab icon. + dialogue :skill_stats do + type :text + + title "Your skill stats." + text "" # TODO !! + end + end + +end \ No newline at end of file diff --git a/data/plugins/location/tutorial-island/npcs.rb b/data/plugins/location/tutorial-island/npcs.rb index 2ce4f67d..ee49851d 100644 --- a/data/plugins/location/tutorial-island/npcs.rb +++ b/data/plugins/location/tutorial-island/npcs.rb @@ -6,7 +6,7 @@ # :y - the y coordinate where the npc will spawn. # Optional arguments are as follows: # :face - the direction the npc should face when it spawns. Supported options are :north, :north_east, :east, :south_east, :south, :south_west, :west, and :north_west -# :bounds - the rectangular bound that the npc can wander about in. Order is [top-left x-coordinate, top-left y-coordinate, bottom-right x-coordinate, bottom-right y-coordinate] +# :bounds - the rectangular bound that the npc can wander about in. Order is [bottom-left x-coordinate, bottom-left y-coordinate, top-right x-coordinate, top-right y-coordinate] # :delta_bounds - the rectangular bound that the npc can wander about in, as a difference from the spawn point. Order is [x-delta, y-delta]. Should not be used with :bounds. # :spawn_animation - the animation that will be played when the npc spawns. # :spawn_graphic - the graphic that will be played when the npc spawns. @@ -16,8 +16,6 @@ # 'Above-ground' npcs -spawn_npc :name => :runescape_guide, :x => 3093, :y => 3107 -spawn_npc :name => :survival_expert, :x => 3104, :y => 3095, :face => :north spawn_npc :name => :master_chef, :x => 3076, :y => 3085 spawn_npc :name => :quest_guide, :x => 3086, :y => 3122, :face => :north spawn_npc :name => :financial_advisor, :x => 3127, :y => 3124, :face => :west diff --git a/data/plugins/location/tutorial-island/plugin.xml b/data/plugins/location/tutorial-island/plugin.xml index bf9bf322..2306c8ec 100644 --- a/data/plugins/location/tutorial-island/plugin.xml +++ b/data/plugins/location/tutorial-island/plugin.xml @@ -3,14 +3,21 @@ location-tutorial-island 0.1 Tutorial Island - Adds funtionality to Tutorial island. + Adds functionality to Tutorial island. Major + + + + + + dialogue entity-spawning + quest \ No newline at end of file diff --git a/data/plugins/location/tutorial-island/stages.rb b/data/plugins/location/tutorial-island/stages.rb new file mode 100644 index 00000000..453efb4b --- /dev/null +++ b/data/plugins/location/tutorial-island/stages.rb @@ -0,0 +1,15 @@ + +private + +# The array of stages in tutorial island. +STAGES = [] + +# The stages that are used when interacting with the Runescape Guide. +RUNESCAPE_GUIDE = [ :not_started, :talk_to_people, :go_through_door, :runescape_guide_finished, :moving_around ] +STAGES.concat(RUNESCAPE_GUIDE) + +# The stages that are used when interacting with the Survival Expert. +SURVIVAL_EXPERT = [ :given_axe, :cut_tree, :cutting_tree, ] +STAGES.concat(SURVIVAL_EXPERT) + +quest :tutorial_island, STAGES \ No newline at end of file diff --git a/data/plugins/location/tutorial-island/survival.rb b/data/plugins/location/tutorial-island/survival.rb new file mode 100644 index 00000000..cbe12b30 --- /dev/null +++ b/data/plugins/location/tutorial-island/survival.rb @@ -0,0 +1,108 @@ +require 'java' + +java_import 'org.apollo.game.message.impl.FlashTabInterfaceMessage' +java_import 'org.apollo.game.message.impl.FlashingTabClickedMessage' +java_import 'org.apollo.game.message.impl.SwitchTabInterfaceMessage' + +private + +# The Survival Expert Npc. +@survival_expert = spawn_npc :name => :survival_expert, :x => 3104, :y => 3095, :face => :north + +# The inventory tab index. +INVENTORY_TAB_INDEX = 3 + +# The inventory tab id. +INVENTORY_TAB_ID = 3213 + +# The id of the tree the Player will cut down. +TREE_ID = 3033 + +# TODO prevent axe equipping + +# The conversation with the Survival Expert, when on tutorial island. +conversation :tutorial_surivival_expert do + + dialogue :introduction do + type :npc_speech + npc :survival_expert + + precondition { |player| player.tutorial_island_progress == :moving_around } + + text "Hello there, newcomer. My name is Brynna. My job is to teach you a few survival tips and tricks. First off we're "\ + "going to start with the most basic survival skill of all: making a fire." + + continue :dialogue => :items + end + + + dialogue :hello_again do + type :npc_speech + npc :survival_expert + + precondition { |player| player.tutorial_island_progress == :moving_around } + + text "Hello again. I'm here to teach you a few survival tips and tricks. First off we're going to start with the most "\ + "basic survival skill of all: making a fire." + + continue :close => true, &:add_survival_items + end + + # The dialogue displayed when the Survival Guide hands both a bronze axe and a tinderbox to the player. + dialogue :items do + type :message_with_item + item :bronze_axe, 200 # TODO the tinderbox is also displayed - find this dialogue id. Scale looks like the default http://i.imgur.com/i1abN5X.png + + text "The Survival Guide gives you a tinderbox and a bronze axe!" + + continue :close => true do |player| + if (player.tutorial_island_progress != :given_axe) + player.tutorial_island_progress = :given_axe + player.send(SwitchTabInterfaceMessage.new(INVENTORY_TAB_INDEX, INVENTORY_TAB_ID)) + player.send(FlashTabInterfaceMessage.new(INVENTORY_TAB_INDEX)) + end + + add_survival_items(player) + end + end + + # The dialogue displayed when the player has succesfully cut down a tree. + dialogue :get_logs do + type :message_with_item + item :logs + + text "You get some logs." + continue :close => true do |player| + TutorialInstructions.show_instruction(player) + end + end + +end + +# The id of the bronze axe. +BRONZE_AXE = lookup_item(:bronze_axe) + +# The id of the tinderbox. +TINDERBOX = lookup_item(:tinderbox) + +# Add the survival items (bronze axe and tinderbox) to the inventory of the player, if they do not already have them. +def add_survival_items(player) + inventory = player.inventory + [ BRONZE_AXE, TINDERBOX ].each { |item| inventory.add(item) unless inventory.contains(item) } + TutorialInstructions.show_instruction(player) +end + +on :message, :first_object_action do |ctx, player, message| + # TODO display "You cannot cut down this tree; you must first follow the guide's instructions." if the player has yet to get the axe + if (player.in_tutorial_island && player.tutorial_island_progress == :cut_tree && message.id == TREE_ID) + player.tutorial_island_progress = :cutting_tree # Don't break the chain, so that the Woodcutting event actually happens. + end +end + +# Intercept the FlashingTabClickedMessage to update the player's progress, if applicable. +on :message, :flashing_tab_clicked do |ctx, player, message| + if (player.in_tutorial_island && message.tab == INVENTORY_TAB_INDEX) + player.tutorial_island_progress = :cut_tree + ctx.break_handler_chain() + end +end \ No newline at end of file diff --git a/data/plugins/location/tutorial-island/utils.rb b/data/plugins/location/tutorial-island/utils.rb new file mode 100644 index 00000000..00250f6c --- /dev/null +++ b/data/plugins/location/tutorial-island/utils.rb @@ -0,0 +1,34 @@ +require 'java' + +java_import 'org.apollo.game.model.entity.Player' + +# Declare the tutorial island progress attribute. +declare_attribute(:tutorial_island_progress, :not_started, :persistent) + + +# The existing player class. +class Player + + # Returns whether or not this Player is currently on tutorial island. + def in_tutorial_island + x, y = self.position.x, self.position.y + + return above_ground(x, y) || below_ground(x, y) + end + +end + + +private + + +# Returns whether or not the specified coordinate pair is above ground on tutorial island. +def above_ground(x, y) + return (x >= 3053 && x <= 3156 && y >= 3056 && y <= 3136) +end + + +# Returns whether or not the specified coordinate pair is 'below' ground on tutorial island. +def below_ground(x, y) + return (x >= 3072 && x <= 3118 && y >= 9492 && y <= 9535) +end \ No newline at end of file diff --git a/data/plugins/quest/plugin.xml b/data/plugins/quest/plugin.xml new file mode 100644 index 00000000..b92ef5b3 --- /dev/null +++ b/data/plugins/quest/plugin.xml @@ -0,0 +1,16 @@ + + + quest + 0.9 + Quest + Adds + + Major + + + + + + attributes + + \ No newline at end of file diff --git a/data/plugins/quest/repository.rb b/data/plugins/quest/repository.rb new file mode 100644 index 00000000..ca827367 --- /dev/null +++ b/data/plugins/quest/repository.rb @@ -0,0 +1,133 @@ + +# Defines a quest with the specified name. +def quest(name, stage_names) + stages = { } + stage_names.each_with_index { |stage, index| stages[stage] = QuestStage.new(stage, index, name) } + + QUESTS[name] = Quest.new(name, stages) +end + +private + +# The repository of quests. +QUESTS = {} + +# An ingame Quest. +class Quest + attr_reader :name + + # Creates the Quest. + def initialize(name, stages) + raise "Quest name must be a symbol, received '#{name}'." unless name.kind_of?(Symbol) + @name = name + @stages = stages + end + + # Gets the finishing quest stage (i.e. the stage that indicates the Player has completed the quest). + def final_stage() + @stages.last + end + + # Gets the starting quest stage. + def initial_stage() + @stages.first + end + + # Gets the QuestStage with the specified name. + def stage(name) + stage = @stages[name] + raise "No stage named #{name} exists in #{@name}." if stage.nil? + stage + end + +end + +# A stage in a quest, indicating the progress of a Player. +class QuestStage + attr_reader :name, :index + + # Creates the QuestProgress. + def initialize(name, index, quest, log_text=nil) + @name = name + @index = index + @quest = quest + @log_text = log_text + end + + # Returns whether or no this quest stage should be logged. + def logged + !@log_text.nil? + end + + # Gets the log text for this stage. + def log_text + raise "Cannot get the log text from an unlogged quest stage." unless logged + @log_text + end + + # Defines the equality operator. + def ==(name) + @index == index_of(name) + end + + # Defines the not equal operator. + def !=(name) + @index != index_of(name) + end + + # Defines the greater than or equal to operator. + def >=(name) + @index >= index_of(name) + end + + # Defines the greater than operator. + def >(name) + @index > index_of(name) + end + + # Defines the less than operator. + def <(name) + @index < index_of(name) + end + + # Defines the less than or equal to operator. + def <=(name) + @index <= index_of(name) + end + + + private + + # Gets the index of the QuestStage with the specified name. + def index_of(name) + QUESTS[@quest].stage(name).index + end + +end + + +# Define method_missing for player +class Player + + # Override method_missing to return a QuestStage if the method name indicates quest. + def method_missing(symbol, *args) + unless args.nil? + arg = args[0] + args[0] = arg.name if arg.kind_of?(QuestStage) + end + + result = super(symbol, *args) + string = symbol.to_s + + if (string.end_with?('_progress')) + name = string[0..-10] # Cut the '_progress' from the end + quest = QUESTS[name.to_sym] + raise "No Quest with the name '#{name}' exists." if quest.nil? + + result = quest.stage(result) + end + + result + end + +end \ No newline at end of file diff --git a/pom.xml b/pom.xml index 65b141e2..a4b88906 100644 --- a/pom.xml +++ b/pom.xml @@ -25,12 +25,12 @@ org.apache.commons commons-compress - 1.8.1 + 1.9 org.jruby jruby-complete - 1.7.15 + 1.7.19 com.google.guava @@ -40,7 +40,7 @@ io.netty netty-all - 4.0.23.Final + 4.0.25.Final compile diff --git a/src/org/apollo/fs/FileSystemConstants.java b/src/org/apollo/fs/FileSystemConstants.java index 4a1d2b5b..630b5fd4 100644 --- a/src/org/apollo/fs/FileSystemConstants.java +++ b/src/org/apollo/fs/FileSystemConstants.java @@ -27,11 +27,6 @@ public final class FileSystemConstants { */ public static final int BLOCK_SIZE = HEADER_SIZE + CHUNK_SIZE; - /** - * The number of caches. - */ - public static final int CACHE_COUNT = 5; - /** * The size of an index. */ diff --git a/src/org/apollo/fs/decoder/NpcDefinitionDecoder.java b/src/org/apollo/fs/decoder/NpcDefinitionDecoder.java index 6e95b63f..743a2342 100644 --- a/src/org/apollo/fs/decoder/NpcDefinitionDecoder.java +++ b/src/org/apollo/fs/decoder/NpcDefinitionDecoder.java @@ -122,13 +122,13 @@ public final class NpcDefinitionDecoder { buffer.getShort(); } else if (opcode == 106) { @SuppressWarnings("unused") - int morphVariableBitsIndex = wrapMorphism(buffer.getShort()); + int morphVariableBitsIndex = wrap(buffer.getShort()); @SuppressWarnings("unused") - int morphismCount = wrapMorphism(buffer.getShort()); + int morphismCount = wrap(buffer.getShort()); int count = buffer.get() & 0xFF; int[] morphisms = new int[count + 1]; - Arrays.setAll(morphisms, index -> wrapMorphism(buffer.getShort())); + Arrays.setAll(morphisms, index -> wrap(buffer.getShort())); } else if (opcode == 107) { @SuppressWarnings("unused") boolean clickable = false; @@ -137,12 +137,12 @@ public final class NpcDefinitionDecoder { } /** - * Wraps a morphism value around, returning -1 if the specified value is 65,535. TODO name + * Wraps a morphism value around, returning -1 if the specified value is 65,535. * * @param value The value. * @return -1 if {@code value} is 65,535, otherwise {@code value}. */ - private static int wrapMorphism(int value) { + private static int wrap(int value) { return value == 65_535 ? -1 : value; } diff --git a/src/org/apollo/fs/package-info.java b/src/org/apollo/fs/package-info.java index 1ddba019..6353ab6e 100644 --- a/src/org/apollo/fs/package-info.java +++ b/src/org/apollo/fs/package-info.java @@ -1,5 +1,4 @@ /** - * Contains classes which deal with the file system that the client uses to - * store game data files. + * Contains classes which deal with the file system that the client uses to store game data files. */ package org.apollo.fs; \ No newline at end of file diff --git a/src/org/apollo/game/GameService.java b/src/org/apollo/game/GameService.java index efdbab2a..bb5d39b1 100644 --- a/src/org/apollo/game/GameService.java +++ b/src/org/apollo/game/GameService.java @@ -49,8 +49,7 @@ public final class GameService extends Service { /** * The scheduled executor service. */ - private final ScheduledExecutorService scheduledExecutor = Executors.newSingleThreadScheduledExecutor(new NamedThreadFactory( - "GameService")); + private final ScheduledExecutorService scheduledExecutor = Executors.newSingleThreadScheduledExecutor(new NamedThreadFactory("GameService")); /** * The {@link ClientSynchronizer}. @@ -170,8 +169,7 @@ public final class GameService extends Service { */ @Override public void start() { - scheduledExecutor.scheduleAtFixedRate(new GamePulseHandler(this), GameConstants.PULSE_DELAY, GameConstants.PULSE_DELAY, - TimeUnit.MILLISECONDS); + scheduledExecutor.scheduleAtFixedRate(new GamePulseHandler(this), GameConstants.PULSE_DELAY, GameConstants.PULSE_DELAY, TimeUnit.MILLISECONDS); } /** diff --git a/src/org/apollo/game/action/package-info.java b/src/org/apollo/game/action/package-info.java index ab52281b..a89acf1d 100644 --- a/src/org/apollo/game/action/package-info.java +++ b/src/org/apollo/game/action/package-info.java @@ -1,5 +1,4 @@ /** - * Contains classes related to actions, specialised scheduled tasks which - * mobs perform. + * Contains classes related to actions, specialised scheduled tasks which mobs perform. */ package org.apollo.game.action; \ No newline at end of file diff --git a/src/org/apollo/game/message/handler/MessageHandlerChain.java b/src/org/apollo/game/message/handler/MessageHandlerChain.java index 96e20db5..7954d7ef 100644 --- a/src/org/apollo/game/message/handler/MessageHandlerChain.java +++ b/src/org/apollo/game/message/handler/MessageHandlerChain.java @@ -41,8 +41,8 @@ public final class MessageHandlerChain { } /** - * Handles the message, passing it down the chain until the chain is broken - * or the message reaches the end of the chain. + * Handles the message, passing it down the chain until the chain is broken or the message reaches the end of the + * chain. * * @param player The player. * @param message The message. diff --git a/src/org/apollo/game/message/handler/MessageHandlerContext.java b/src/org/apollo/game/message/handler/MessageHandlerContext.java index 6660d1e2..4fda61db 100644 --- a/src/org/apollo/game/message/handler/MessageHandlerContext.java +++ b/src/org/apollo/game/message/handler/MessageHandlerContext.java @@ -1,8 +1,7 @@ package org.apollo.game.message.handler; /** - * Provides operations specific to a {@link MessageHandler} in a - * {@link MessageHandlerChain}. + * Provides operations specific to a {@link MessageHandler} in a {@link MessageHandlerChain}. * * @author Graham * @author Ryley @@ -24,8 +23,7 @@ public final class MessageHandlerContext { /** * Returns whether or not this handler chain is broken. * - * @return {@code true} if this handler chain is broken, otherwise - * {@code false}. + * @return {@code true} if this handler chain is broken, otherwise {@code false}. */ public boolean isBroken() { return broken; diff --git a/src/org/apollo/game/message/handler/impl/BankMessageHandler.java b/src/org/apollo/game/message/handler/impl/BankMessageHandler.java index 8e5c5925..02df5c4c 100644 --- a/src/org/apollo/game/message/handler/impl/BankMessageHandler.java +++ b/src/org/apollo/game/message/handler/impl/BankMessageHandler.java @@ -25,16 +25,16 @@ public final class BankMessageHandler extends MessageHandler */ private static final int optionToAmount(int option) { switch (option) { - case 1: - return 1; - case 2: - return 5; - case 3: - return 10; - case 4: - return Integer.MAX_VALUE; - case 5: - return -1; + case 1: + return 1; + case 2: + return 5; + case 3: + return 10; + case 4: + return Integer.MAX_VALUE; + case 5: + return -1; } throw new IllegalArgumentException("Invalid option supplied."); diff --git a/src/org/apollo/game/message/handler/impl/ItemOnItemVerificationHandler.java b/src/org/apollo/game/message/handler/impl/ItemOnItemVerificationHandler.java index f01221a2..e40a3350 100644 --- a/src/org/apollo/game/message/handler/impl/ItemOnItemVerificationHandler.java +++ b/src/org/apollo/game/message/handler/impl/ItemOnItemVerificationHandler.java @@ -21,19 +21,19 @@ public final class ItemOnItemVerificationHandler extends MessageHandler= 0 && message.getNewSlot() >= 0 && message.getOldSlot() < inventory.capacity() - && message.getNewSlot() < inventory.capacity()) { + if (message.getOldSlot() >= 0 && message.getNewSlot() >= 0 && message.getOldSlot() < inventory.capacity() && message.getNewSlot() < inventory.capacity()) { // events must be fired for it to work if a sidebar inventory overlay is used inventory.swap(insertPermitted && message.isInserting(), message.getOldSlot(), message.getNewSlot()); } diff --git a/src/org/apollo/game/message/handler/impl/WalkMessageHandler.java b/src/org/apollo/game/message/handler/impl/WalkMessageHandler.java index 003a9cee..d36728aa 100644 --- a/src/org/apollo/game/message/handler/impl/WalkMessageHandler.java +++ b/src/org/apollo/game/message/handler/impl/WalkMessageHandler.java @@ -36,6 +36,11 @@ public final class WalkMessageHandler extends MessageHandler { player.stopAction(); } player.getInterfaceSet().close(); + + if (player.getInteractingMob() != null) { + player.resetInteractingMob(); + } + } } \ No newline at end of file diff --git a/src/org/apollo/game/message/impl/PlayerSynchronizationMessage.java b/src/org/apollo/game/message/impl/PlayerSynchronizationMessage.java index 8435f6b0..88f8bfde 100644 --- a/src/org/apollo/game/message/impl/PlayerSynchronizationMessage.java +++ b/src/org/apollo/game/message/impl/PlayerSynchronizationMessage.java @@ -53,8 +53,7 @@ public final class PlayerSynchronizationMessage extends Message { * @param localPlayers The number of local players. * @param segments A list of segments. */ - public PlayerSynchronizationMessage(Position lastKnownSector, Position position, boolean sectorChanged, - SynchronizationSegment segment, int localPlayers, List segments) { + public PlayerSynchronizationMessage(Position lastKnownSector, Position position, boolean sectorChanged, SynchronizationSegment segment, int localPlayers, List segments) { this.lastKnownSector = lastKnownSector; this.position = position; this.sectorChanged = sectorChanged; diff --git a/src/org/apollo/game/model/Appearance.java b/src/org/apollo/game/model/Appearance.java index 4ece0496..6bb6a961 100644 --- a/src/org/apollo/game/model/Appearance.java +++ b/src/org/apollo/game/model/Appearance.java @@ -14,8 +14,8 @@ public final class Appearance { /** * The default appearance. */ - public static final Appearance DEFAULT_APPEARANCE = new Appearance(Gender.MALE, new int[] { 0, 10, 18, 26, 33, 36, 42 }, - new int[5]); + public static final Appearance DEFAULT_APPEARANCE = new Appearance(Gender.MALE, new int[] { 0, 10, 18, 26, 33, 36, + 42 }, new int[5]); /** * The array of clothing/skin colors. diff --git a/src/org/apollo/game/model/Direction.java b/src/org/apollo/game/model/Direction.java index 41f3ae6c..61015ca3 100644 --- a/src/org/apollo/game/model/Direction.java +++ b/src/org/apollo/game/model/Direction.java @@ -1,9 +1,5 @@ package org.apollo.game.model; - - - - /** * Represents a single movement direction. * @@ -90,7 +86,7 @@ public enum Direction { return Direction.WEST; } } - + return Direction.NONE; } diff --git a/src/org/apollo/game/model/Position.java b/src/org/apollo/game/model/Position.java index 24c1e3de..ac42c9b7 100644 --- a/src/org/apollo/game/model/Position.java +++ b/src/org/apollo/game/model/Position.java @@ -221,13 +221,12 @@ public final class Position { public boolean isWithinDistance(Position other, int distance) { int deltaX = Math.abs(getX() - other.getX()); int deltaY = Math.abs(getY() - other.getY()); - return deltaX <= distance && deltaY <= distance; + return deltaX <= distance && deltaY <= distance && getHeight() == other.getHeight(); } @Override public String toString() { - return MoreObjects.toStringHelper(this).add("x", getX()).add("y", getY()).add("height", getHeight()) - .add("sector", getSectorCoordinates()).toString(); + return MoreObjects.toStringHelper(this).add("x", getX()).add("y", getY()).add("height", getHeight()).add("sector", getSectorCoordinates()).toString(); } } \ No newline at end of file diff --git a/src/org/apollo/game/model/World.java b/src/org/apollo/game/model/World.java index 29bd4e36..98335a0b 100644 --- a/src/org/apollo/game/model/World.java +++ b/src/org/apollo/game/model/World.java @@ -30,6 +30,7 @@ import org.apollo.game.model.event.EventListener; import org.apollo.game.model.event.EventListenerChainSet; import org.apollo.game.scheduling.ScheduledTask; import org.apollo.game.scheduling.Scheduler; +import org.apollo.game.scheduling.impl.NpcMovementTask; import org.apollo.io.EquipmentDefinitionParser; import org.apollo.util.MobRepository; import org.apollo.util.NameUtil; @@ -97,6 +98,11 @@ public final class World { */ private final EventListenerChainSet events = new EventListenerChainSet(); + /** + * The ScheduledTask that moves Npcs. + */ + private NpcMovementTask npcMovement; + /** * The {@link MobRepository} of {@link Npc}s. */ @@ -113,7 +119,7 @@ public final class World { private final Map players = new HashMap<>(); /** - * The {@link PluginManager}. TODO: better place than here!! + * The {@link PluginManager}. */ private PluginManager pluginManager; @@ -178,7 +184,7 @@ public final class World { } /** - * Gets the plugin manager. TODO should this be here? + * Gets the plugin manager. * * @return The plugin manager. */ @@ -242,8 +248,11 @@ public final class World { placeEntities(objects); logger.fine("Loaded " + objects.length + " static objects."); + npcMovement = new NpcMovementTask(); // Must be exactly here because of ordering issues. + scheduler.schedule(npcMovement); + manager.start(); - pluginManager = manager; // TODO move!! + pluginManager = manager; } /** @@ -285,6 +294,10 @@ public final class World { if (success) { Sector sector = sectors.fromPosition(npc.getPosition()); sector.addEntity(npc); + + if (npc.hasBoundaries()) { + npcMovement.addNpc(npc); + } } else { logger.warning("Failed to register npc, repository capacity reached: [count=" + npcRepository.size() + "]"); } diff --git a/src/org/apollo/game/model/area/Sector.java b/src/org/apollo/game/model/area/Sector.java index 3f9dfcd9..bc03933f 100644 --- a/src/org/apollo/game/model/area/Sector.java +++ b/src/org/apollo/game/model/area/Sector.java @@ -14,6 +14,7 @@ import org.apollo.game.model.area.collision.CollisionMatrix; import org.apollo.game.model.entity.Entity; import org.apollo.game.model.entity.Entity.EntityType; +import com.google.common.base.MoreObjects; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableSet; @@ -174,13 +175,14 @@ public final class Sector { Set local = entities.get(old); - Preconditions.checkArgument(local != null && local.remove(entity), "Entity belongs in this sector but does not exist."); + if (local == null || !local.remove(entity)) { + throw new IllegalArgumentException("Entity belongs in this sector (" + this + ") but does not exist."); + } local = entities.computeIfAbsent(position, key -> new HashSet<>(DEFAULT_SET_SIZE)); local.add(entity); notifyListeners(entity, SectorOperation.MOVE); - } /** @@ -205,7 +207,9 @@ public final class Sector { Set local = entities.get(position); - Preconditions.checkArgument(local != null && local.remove(entity), "Entity belongs in this sector but does not exist."); + if (local == null || !local.remove(entity)) { + throw new IllegalArgumentException("Entity belongs in this sector (" + this + ") but does not exist."); + } notifyListeners(entity, SectorOperation.REMOVE); } @@ -221,9 +225,14 @@ public final class Sector { */ public boolean traversable(Position position, EntityType entity, Direction direction) { CollisionMatrix matrix = matrices[position.getHeight()]; - int x = position.getLocalX(), y = position.getLocalY(); + int x = position.getX(), y = position.getY(); - return matrix.traversable(x, y, entity, direction); + return !matrix.untraversable(x % SECTOR_SIZE, y % SECTOR_SIZE, entity, direction); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this).add("coordinates", coordinates).toString(); } /** @@ -233,8 +242,7 @@ public final class Sector { * @throws IllegalArgumentException If the specified position is not included in this sector. */ private void checkPosition(Position position) { - Preconditions.checkArgument(coordinates.equals(SectorCoordinates.fromPosition(position)), - "Position is not included in this sector."); + Preconditions.checkArgument(coordinates.equals(SectorCoordinates.fromPosition(position)), "Position is not included in this sector."); } } \ No newline at end of file diff --git a/src/org/apollo/game/model/area/collision/CollisionFlag.java b/src/org/apollo/game/model/area/collision/CollisionFlag.java index 20554176..f680013c 100644 --- a/src/org/apollo/game/model/area/collision/CollisionFlag.java +++ b/src/org/apollo/game/model/area/collision/CollisionFlag.java @@ -9,16 +9,16 @@ import org.apollo.game.model.entity.Entity.EntityType; */ public enum CollisionFlag { - /** - * The walk east flag. - */ - MOB_EAST(1), - /** * The walk north flag. */ MOB_NORTH(0), + /** + * The walk east flag. + */ + MOB_EAST(1), + /** * The walk south flag. */ @@ -29,16 +29,16 @@ public enum CollisionFlag { */ MOB_WEST(3), - /** - * The projectile east flag. - */ - PROJECTILE_EAST(5), - /** * The projectile north flag. */ PROJECTILE_NORTH(4), + /** + * The projectile east flag. + */ + PROJECTILE_EAST(5), + /** * The projectile south flag. */ diff --git a/src/org/apollo/game/model/area/collision/CollisionMatrix.java b/src/org/apollo/game/model/area/collision/CollisionMatrix.java index 9630ad45..8a97aa3c 100644 --- a/src/org/apollo/game/model/area/collision/CollisionMatrix.java +++ b/src/org/apollo/game/model/area/collision/CollisionMatrix.java @@ -15,6 +15,16 @@ import com.google.common.base.Preconditions; */ public final class CollisionMatrix { + /** + * Indicates that all types of traversal are allowed. + */ + private static final byte ALL_ALLOWED = 0b0000_0000; + + /** + * Indicates that no types of traversal are allowed. + */ + private static final byte ALL_BLOCKED = (byte) 0b1111_1111; + /** * Creates an array of CollisionMatrix objects, all of the specified width and length. * @@ -29,16 +39,6 @@ public final class CollisionMatrix { return matrices; } - /** - * Indicates that all types of traversal are allowed. - */ - private static final byte ALL_ALLOWED = 0b0000_0000; - - /** - * Indicates that no types of traversal are allowed. - */ - private static final byte ALL_BLOCKED = (byte) 0b1111_1111; - /** * The length of the matrix. */ @@ -76,13 +76,7 @@ public final class CollisionMatrix { * @return {@code true} if all of the CollisionFlags are set, otherwise {@code false}. */ public boolean all(int x, int y, CollisionFlag... flags) { - for (CollisionFlag flag : flags) { - if ((get(x, y) & flag.asByte()) == 0) { - return false; - } - } - - return true; + return Arrays.stream(flags).allMatch(flag -> (get(x, y) & flag.asByte()) != 0); } /** @@ -95,13 +89,7 @@ public final class CollisionMatrix { * @return {@code true} if any of the CollisionFlags are set, otherwise {@code false}. */ public boolean any(int x, int y, CollisionFlag... flags) { - for (CollisionFlag flag : flags) { - if ((get(x, y) & flag.asByte()) != 0) { - return true; - } - } - - return false; + return Arrays.stream(flags).anyMatch(flag -> (get(x, y) & flag.asByte()) != 0); } /** @@ -173,21 +161,20 @@ public final class CollisionMatrix { @Override public String toString() { - return MoreObjects.toStringHelper(this).add("width", width).add("length", length).add("matrix", Arrays.toString(matrix)) - .toString(); + return MoreObjects.toStringHelper(this).add("width", width).add("length", length).add("matrix", Arrays.toString(matrix)).toString(); } /** - * Returns whether or not an Entity of the specified {@link EntityType type} can traverse the tile at the specified - * coordinate pair. + * Returns whether or not an Entity of the specified {@link EntityType type} cannot traverse the tile at the + * specified coordinate pair. * * @param x The x coordinate. * @param y The y coordinate. * @param entity The {@link EntityType}. * @param direction The {@link Direction} the Entity is approaching from. - * @return {@code true} if the tile at the specified coordinate pair is traversable, {@code false} if not. + * @return {@code true} if the tile at the specified coordinate pair is not traversable, {@code false} if not. */ - public boolean traversable(int x, int y, EntityType entity, Direction direction) { + public boolean untraversable(int x, int y, EntityType entity, Direction direction) { CollisionFlag[] flags = CollisionFlag.forType(entity); int north = 0, east = 1, south = 2, west = 3; diff --git a/src/org/apollo/game/model/area/package-info.java b/src/org/apollo/game/model/area/package-info.java index a39c9f88..8a1f2a6b 100644 --- a/src/org/apollo/game/model/area/package-info.java +++ b/src/org/apollo/game/model/area/package-info.java @@ -1,5 +1,5 @@ /** - * Contains classes which represent in-game sectors - blocks of 8x8 tiles used to store ground items, temporary objects, etc. - * efficiently. + * Contains classes which represent in-game sectors - blocks of 8x8 tiles used to store ground items, temporary objects, + * etc. efficiently. */ package org.apollo.game.model.area; \ No newline at end of file diff --git a/src/org/apollo/game/model/def/ItemDefinition.java b/src/org/apollo/game/model/def/ItemDefinition.java index 7e175a25..bbbad0c2 100644 --- a/src/org/apollo/game/model/def/ItemDefinition.java +++ b/src/org/apollo/game/model/def/ItemDefinition.java @@ -388,7 +388,7 @@ public final class ItemDefinition { public void toNote() { if (isNote()) { if (description != null && description.startsWith("Swap this note at any bank for ")) { - return; // already converted TODO better way of checking? + return; // already converted. } ItemDefinition infoDef = lookup(noteInfoId); diff --git a/src/org/apollo/game/model/def/ObjectDefinition.java b/src/org/apollo/game/model/def/ObjectDefinition.java index a890b4cc..de1af1c9 100644 --- a/src/org/apollo/game/model/def/ObjectDefinition.java +++ b/src/org/apollo/game/model/def/ObjectDefinition.java @@ -178,8 +178,7 @@ public final class ObjectDefinition { /** * Indicates the impenetrability of this object. * - * @return {@code true} if this object is impenetrable, otherwise - * {@code false}. + * @return {@code true} if this object is impenetrable, otherwise {@code false}. */ public boolean isImpenetrable() { return impenetrable; @@ -188,8 +187,7 @@ public final class ObjectDefinition { /** * Indicates the interactivity of this object. * - * @return {@code true} if the object is interactive, otherwise - * {@code false}. + * @return {@code true} if the object is interactive, otherwise {@code false}. */ public boolean isInteractive() { return interactive; @@ -198,8 +196,7 @@ public final class ObjectDefinition { /** * Indicates whether or not this object obstructs the ground. * - * @return {@code true} if the object obstructs the ground otherwise - * {@code false}. + * @return {@code true} if the object obstructs the ground otherwise {@code false}. */ public boolean isObstructive() { return obstructive; diff --git a/src/org/apollo/game/model/def/package-info.java b/src/org/apollo/game/model/def/package-info.java index c214a056..56c13bf9 100644 --- a/src/org/apollo/game/model/def/package-info.java +++ b/src/org/apollo/game/model/def/package-info.java @@ -1,5 +1,4 @@ /** - * Contains definition classes which contain information about types of items, - * NPCs, etc. + * Contains definition classes which contain information about types of items, NPCs, etc. */ package org.apollo.game.model.def; \ No newline at end of file diff --git a/src/org/apollo/game/model/entity/GameObject.java b/src/org/apollo/game/model/entity/GameObject.java index 36b596a2..8592c7a1 100644 --- a/src/org/apollo/game/model/entity/GameObject.java +++ b/src/org/apollo/game/model/entity/GameObject.java @@ -89,8 +89,7 @@ public final class GameObject extends Entity { @Override public String toString() { - return MoreObjects.toStringHelper(this).add("id", getId()).add("type", getType()).add("rotation", getRotation()) - .toString(); + return MoreObjects.toStringHelper(this).add("id", getId()).add("type", getType()).add("rotation", getRotation()).toString(); } } \ No newline at end of file diff --git a/src/org/apollo/game/model/entity/Mob.java b/src/org/apollo/game/model/entity/Mob.java index 022e0692..e5a8cf33 100644 --- a/src/org/apollo/game/model/entity/Mob.java +++ b/src/org/apollo/game/model/entity/Mob.java @@ -194,8 +194,8 @@ public abstract class Mob extends Entity { */ public final Direction[] getDirections() { if (firstDirection != Direction.NONE) { - return secondDirection == Direction.NONE ? new Direction[] { firstDirection } : new Direction[] { firstDirection, - secondDirection }; + return secondDirection == Direction.NONE ? new Direction[] { firstDirection } : new Direction[] { + firstDirection, secondDirection }; } return Direction.EMPTY_DIRECTION_ARRAY; diff --git a/src/org/apollo/game/model/entity/Npc.java b/src/org/apollo/game/model/entity/Npc.java index 66532a96..12ccc2a9 100644 --- a/src/org/apollo/game/model/entity/Npc.java +++ b/src/org/apollo/game/model/entity/Npc.java @@ -1,6 +1,5 @@ package org.apollo.game.model.entity; -import java.util.Arrays; import java.util.Optional; import org.apollo.game.model.Position; @@ -20,9 +19,9 @@ import com.google.common.base.Preconditions; public final class Npc extends Mob { /** - * The positions representing the bounds (i.e. walking limits) of this Npc. + * The Positions representing the boundaries (i.e. walking limits) of this Npc. */ - private Position[] boundary; + private Optional boundaries; /** * Creates a new Npc with the specified id and {@link Position}. @@ -31,18 +30,20 @@ public final class Npc extends Mob { * @param position The position. */ public Npc(int id, Position position) { - this(position, NpcDefinition.lookup(id)); + this(position, NpcDefinition.lookup(id), null); } /** * Creates a new Npc with the specified {@link NpcDefinition} and {@link Position}. * - * @param position The position. - * @param definition The definition. + * @param position The Position. + * @param definition The NpcDefinition. + * @param boundaries The boundary Positions. */ - public Npc(Position position, NpcDefinition definition) { + public Npc(Position position, NpcDefinition definition, Position[] boundaries) { super(position, definition); + this.boundaries = Optional.ofNullable(boundaries); init(); } @@ -50,19 +51,19 @@ public final class Npc extends Mob { public boolean equals(Object obj) { if (obj instanceof Npc) { Npc other = (Npc) obj; - return position.equals(other.position) && Arrays.equals(boundary, other.boundary) && getId() == other.getId(); + return index == other.index && getId() == other.getId(); } return false; } /** - * Gets the boundary of this Npc. + * Gets the boundaries of this Npc. * - * @return The boundary. + * @return The boundaries. */ - public Position[] getBoundary() { - return boundary.clone(); + public Optional getBoundaries() { + return boundaries.isPresent() ? Optional.of(boundaries.get().clone()) : Optional.empty(); } @Override @@ -79,30 +80,29 @@ public final class Npc extends Mob { return definition.get().getId(); } + /** + * Returns whether or not this Npc has boundaries. + * + * @return {@code true} if this Npc has boundaries, {@code false} if not. + */ + public boolean hasBoundaries() { + return boundaries.isPresent(); + } + @Override public int hashCode() { final int prime = 31; - int result = prime * position.hashCode() + Arrays.hashCode(boundary); - return prime * result + getId(); + return prime * index + getId(); } /** - * Indicates whether or not this Npc is bound to a specific set of coordinates. + * Sets the boundaries of this Npc. * - * @return {@code true} if the Npc is bound, otherwise {@code false}. + * @param boundaries The boundaries. */ - public boolean isBound() { - return boundary == null; - } - - /** - * Sets the boundary of this Npc. - * - * @param boundary The boundary. - */ - public void setBoundary(Position[] boundary) { - Preconditions.checkArgument(boundary.length == 4, "Boundary count must be 4."); - this.boundary = boundary.clone(); + public void setBoundaries(Position[] boundaries) { + Preconditions.checkArgument(boundaries.length == 2, "Boundary count must be 2."); + this.boundaries = Optional.of(boundaries.clone()); } @Override diff --git a/src/org/apollo/game/model/entity/Player.java b/src/org/apollo/game/model/entity/Player.java index 79f9efc1..9c7e8552 100644 --- a/src/org/apollo/game/model/entity/Player.java +++ b/src/org/apollo/game/model/entity/Player.java @@ -686,7 +686,7 @@ public final class Player extends Mob { */ public void sendInitialMessages() { blockSet.add(SynchronizationBlock.createAppearanceBlock(this)); - send(new IdAssignmentMessage(index, members)); // TODO should this be sent when we reconnect? + send(new IdAssignmentMessage(index, members)); sendMessage("Welcome to RuneScape."); int[] tabs = InterfaceConstants.DEFAULT_INVENTORY_TABS; @@ -943,8 +943,7 @@ public final class Player extends Mob { @Override public String toString() { - return MoreObjects.toStringHelper(this).add("username", getUsername()).add("privilege", privilegeLevel) - .add("client version", getClientVersion()).toString(); + return MoreObjects.toStringHelper(this).add("username", getUsername()).add("privilege", privilegeLevel).add("client version", getClientVersion()).toString(); } /** @@ -968,11 +967,9 @@ public final class Player extends Mob { InventoryListener fullBankListener = new FullInventoryListener(this, FullInventoryListener.FULL_BANK_MESSAGE); InventoryListener appearanceListener = new AppearanceInventoryListener(this); - InventoryListener syncInventoryListener = new SynchronizationInventoryListener(this, - SynchronizationInventoryListener.INVENTORY_ID); + InventoryListener syncInventoryListener = new SynchronizationInventoryListener(this, SynchronizationInventoryListener.INVENTORY_ID); InventoryListener syncBankListener = new SynchronizationInventoryListener(this, BankConstants.BANK_INVENTORY_ID); - InventoryListener syncEquipmentListener = new SynchronizationInventoryListener(this, - SynchronizationInventoryListener.EQUIPMENT_ID); + InventoryListener syncEquipmentListener = new SynchronizationInventoryListener(this, SynchronizationInventoryListener.EQUIPMENT_ID); inventory.addListener(syncInventoryListener); inventory.addListener(fullInventoryListener); diff --git a/src/org/apollo/game/model/entity/Skill.java b/src/org/apollo/game/model/entity/Skill.java index f9f9c54b..5db56e22 100644 --- a/src/org/apollo/game/model/entity/Skill.java +++ b/src/org/apollo/game/model/entity/Skill.java @@ -115,9 +115,9 @@ public final class Skill { /** * The skill names. */ - private static final String[] SKILL_NAMES = { "Attack", "Defence", "Strength", "Hitpoints", "Ranged", "Prayer", "Magic", - "Cooking", "Woodcutting", "Fletching", "Fishing", "Firemaking", "Crafting", "Smithing", "Mining", "Herblore", - "Agility", "Thieving", "Slayer", "Farming", "Runecraft" }; + private static final String[] SKILL_NAMES = { "Attack", "Defence", "Strength", "Hitpoints", "Ranged", "Prayer", + "Magic", "Cooking", "Woodcutting", "Fletching", "Fishing", "Firemaking", "Crafting", "Smithing", "Mining", + "Herblore", "Agility", "Thieving", "Slayer", "Farming", "Runecraft" }; /** * Gets the name of a skill. diff --git a/src/org/apollo/game/model/entity/SkillSet.java b/src/org/apollo/game/model/entity/SkillSet.java index 9cfbf2aa..c3b61223 100644 --- a/src/org/apollo/game/model/entity/SkillSet.java +++ b/src/org/apollo/game/model/entity/SkillSet.java @@ -57,8 +57,7 @@ public final class SkillSet { * @return The minimum level. */ public static int getLevelForExperience(double experience) { - Preconditions.checkArgument(experience >= 0 && experience <= MAXIMUM_EXP, "Experience must be between 0 and " - + MAXIMUM_EXP + ", inclusive."); + Preconditions.checkArgument(experience >= 0 && experience <= MAXIMUM_EXP, "Experience must be between 0 and " + MAXIMUM_EXP + ", inclusive."); for (int level = 1; level <= 98; level++) { if (experience < EXPERIENCE_FOR_LEVEL[level + 1]) { diff --git a/src/org/apollo/game/model/entity/attr/AttributeMap.java b/src/org/apollo/game/model/entity/attr/AttributeMap.java index e1f0ce9b..a4410c8a 100644 --- a/src/org/apollo/game/model/entity/attr/AttributeMap.java +++ b/src/org/apollo/game/model/entity/attr/AttributeMap.java @@ -80,8 +80,7 @@ public final class AttributeMap { AttributeDefinition definition = getDefinition(name); Preconditions.checkNotNull(definition, "Attributes must be defined before their value can be retreived."); - return (Attribute) attributes.computeIfAbsent(name, - key -> createAttribute(definition.getDefault(), definition.getType())); + return (Attribute) attributes.computeIfAbsent(name, key -> createAttribute(definition.getDefault(), definition.getType())); } /** diff --git a/src/org/apollo/game/model/entity/path/AStarPathfindingAlgorithm.java b/src/org/apollo/game/model/entity/path/AStarPathfindingAlgorithm.java index eb06d263..6c10ed58 100644 --- a/src/org/apollo/game/model/entity/path/AStarPathfindingAlgorithm.java +++ b/src/org/apollo/game/model/entity/path/AStarPathfindingAlgorithm.java @@ -23,7 +23,7 @@ import org.apollo.game.model.Position; * * @author Major */ -final class AStarPathfindingAlgorithm extends PathfindingAlgorithm { +public final class AStarPathfindingAlgorithm extends PathfindingAlgorithm { /** * The heuristic. diff --git a/src/org/apollo/game/model/entity/path/PathfindingAlgorithm.java b/src/org/apollo/game/model/entity/path/PathfindingAlgorithm.java index 104e67aa..eaea81db 100644 --- a/src/org/apollo/game/model/entity/path/PathfindingAlgorithm.java +++ b/src/org/apollo/game/model/entity/path/PathfindingAlgorithm.java @@ -1,7 +1,7 @@ package org.apollo.game.model.entity.path; import java.util.Deque; -import java.util.Set; +import java.util.Optional; import org.apollo.game.model.Direction; import org.apollo.game.model.Position; @@ -9,7 +9,8 @@ import org.apollo.game.model.World; import org.apollo.game.model.area.Sector; import org.apollo.game.model.area.SectorRepository; import org.apollo.game.model.entity.Entity.EntityType; -import org.apollo.game.model.entity.GameObject; + +import com.google.common.base.Preconditions; /** * An algorithm used to find a path between two {@link Position}s. @@ -19,46 +20,48 @@ import org.apollo.game.model.entity.GameObject; abstract class PathfindingAlgorithm { /** - * The repository of sectors. + * The repository of Sectors. */ - private static final SectorRepository repository = World.getWorld().getSectorRepository(); + private static final SectorRepository REPOSITORY = World.getWorld().getSectorRepository(); /** * Finds a valid path from the origin {@link Position} to the target one. * - * @param origin The origin position. - * @param target The target position. - * @return The {@link Deque} containing the positions to go through. + * @param origin The origin Position. + * @param target The target Position. + * @return The {@link Deque} containing the Positions to go through. */ public abstract Deque find(Position origin, Position target); /** - * Returns whether or not the tile at the specified position is walkable. FIXME do this properly w/tile collision - * data! - * - * @param position The {@link Position}. - * @return {@code true} if the tile is walkable, otherwise {@code false}. + * Returns whether or not a {@link Position} walking one step in any of the specified {@link Direction}s would lead + * to is traversable. + * + * @param current The current Position. + * @param directions The Directions that should be checked. + * @return {@code true} if any of the Directions lead to a traversable tile, otherwise {@code false}. */ - protected boolean traversable(Position position) { - Sector sector = repository.get(position.getSectorCoordinates()); - Set objects = sector.getEntities(position, EntityType.GAME_OBJECT); - - return objects.stream().anyMatch(object -> object.getDefinition().isSolid()); + protected boolean traversable(Position current, Direction... directions) { + return traversable(current, Optional.empty(), directions); } /** - * Returns whether or not the {@link Position}s walking one step in a specified {@link Direction} would lead to is - * traversable. + * Returns whether or not a {@link Position} walking one step in any of the specified {@link Direction}s would lead + * to is traversable. * - * @param position The starting position. - * @param directions The directions that should be checked. - * @return {@code true} if any of the directions lead to a traversable tile, otherwise {@code false}. + * @param current The current Position. + * @param boundaries The {@link Optional} containing the Position boundaries. + * @param directions The Directions that should be checked. + * @return {@code true} if any of the Directions lead to a traversable tile, otherwise {@code false}. */ - protected boolean traversable(Position position, Direction... directions) { - int height = position.getHeight(); + protected boolean traversable(Position current, Optional boundaries, Direction... directions) { + Preconditions.checkArgument(directions != null && directions.length > 0, "Directions array cannot be null."); + int height = current.getHeight(); + + Position[] positions = boundaries.isPresent() ? boundaries.get() : new Position[0]; for (Direction direction : directions) { - int x = position.getX(), y = position.getY(); + int x = current.getX(), y = current.getY(); int value = direction.toInteger(); if (value >= Direction.NORTH_WEST.toInteger() && value <= Direction.NORTH_EAST.toInteger()) { @@ -73,7 +76,9 @@ abstract class PathfindingAlgorithm { x--; } - if (traversable(new Position(x, y, height))) { + Position next = new Position(x, y, height); + Sector sector = REPOSITORY.get(next.getSectorCoordinates()); + if (sector.traversable(next, EntityType.NPC, direction) && (positions.length == 0 || inside(next, positions))) { return true; } } @@ -81,4 +86,18 @@ abstract class PathfindingAlgorithm { return false; } + /** + * Returns whether or not the specified {@link Position} is inside the specified {@code boundary}. + * + * @param position The Position. + * @param boundary The boundary Positions. + * @return {@code true} if the specified Position is inside the boundary, {@code false} if not. + */ + private boolean inside(Position position, Position[] boundary) { + int x = position.getX(), y = position.getY(); + Position min = boundary[0], max = boundary[1]; + + return x >= min.getX() && y >= min.getY() && x <= max.getX() && y <= max.getY(); + } + } \ No newline at end of file diff --git a/src/org/apollo/game/model/entity/path/SimplePathfindingAlgorithm.java b/src/org/apollo/game/model/entity/path/SimplePathfindingAlgorithm.java index 0ef4b77d..8789eb38 100644 --- a/src/org/apollo/game/model/entity/path/SimplePathfindingAlgorithm.java +++ b/src/org/apollo/game/model/entity/path/SimplePathfindingAlgorithm.java @@ -2,6 +2,7 @@ package org.apollo.game.model.entity.path; import java.util.ArrayDeque; import java.util.Deque; +import java.util.Optional; import org.apollo.game.model.Direction; import org.apollo.game.model.Position; @@ -12,7 +13,12 @@ import org.apollo.game.model.Position; * * @author Major */ -final class SimplePathfindingAlgorithm extends PathfindingAlgorithm { +public final class SimplePathfindingAlgorithm extends PathfindingAlgorithm { + + /** + * The Optional containing the boundary Positions. + */ + private Optional boundaries = Optional.empty(); @Override public Deque find(Position origin, Position target) { @@ -22,6 +28,19 @@ final class SimplePathfindingAlgorithm extends PathfindingAlgorithm { return addHorizontal(origin, target, positions); } + /** + * Finds a valid path from the origin {@link Position} to the target one. + * + * @param origin The origin Position. + * @param target The target Position. + * @param boundaries The boundary Positions, which are marking as untraversable. + * @return The {@link Deque} containing the Positions to go through. + */ + public Deque find(Position origin, Position target, Position[] boundaries) { + this.boundaries = Optional.of(boundaries); + return find(origin, target); + } + /** * Adds the necessary and possible horizontal {@link Position}s to the existing {@link Deque}. *

@@ -33,33 +52,33 @@ final class SimplePathfindingAlgorithm extends PathfindingAlgorithm { * if so, we traverse horizontally (see {@link #addHorizontal}); if not, return the current path. * * - * @param current The current position. + * @param start The current position. * @param target The target position. * @param positions The deque of positions. * @return The deque of positions containing the path. */ - private Deque addHorizontal(Position current, Position target, Deque positions) { - int x = current.getX(), y = current.getY(), height = current.getHeight(); - int dx = x - target.getX(); + private Deque addHorizontal(Position start, Position target, Deque positions) { + int x = start.getX(), y = start.getY(), height = start.getHeight(); + int dx = x - target.getX(), dy = y - target.getY(); if (dx > 0) { - Position west = new Position(x - 1, y, height); + Position current = start; - while (traversable(west) && dx-- > 0) { - west = new Position(--x, y, height); - positions.addLast(west); + while (traversable(current, boundaries, Direction.WEST) && dx-- > 0) { + current = new Position(--x, y, height); + positions.addLast(current); } } else if (dx < 0) { - Position east = new Position(x + 1, y, height); + Position current = start; - while (traversable(east) && dx++ < 0) { - east = new Position(++x, y, height); - positions.addLast(east); + while (traversable(current, boundaries, Direction.EAST) && dx++ < 0) { + current = new Position(++x, y, height); + positions.addLast(current); } } Position last = new Position(x, y, height); - if (!current.equals(last) && traversable(last, Direction.NORTH, Direction.SOUTH)) { + if (!start.equals(last) && dy != 0 && traversable(last, boundaries, (dy > 0) ? Direction.SOUTH : Direction.NORTH)) { return addVertical(last, target, positions); } @@ -77,33 +96,33 @@ final class SimplePathfindingAlgorithm extends PathfindingAlgorithm { * if so, we traverse horizontally (see {@link #addHorizontal}); if not, return the current path. * * - * @param current The current position. + * @param start The current position. * @param target The target position. * @param positions The deque of positions. * @return The deque of positions containing the path. */ - private Deque addVertical(Position current, Position target, Deque positions) { - int x = current.getX(), y = current.getY(), height = current.getHeight(); - int dy = y - target.getY(); + private Deque addVertical(Position start, Position target, Deque positions) { + int x = start.getX(), y = start.getY(), height = start.getHeight(); + int dy = y - target.getY(), dx = x - target.getX(); if (dy > 0) { - Position south = new Position(x, y - 1, height); + Position current = start; - while (traversable(south) && dy-- > 0) { - south = new Position(x, --y, height); - positions.addLast(south); + while (traversable(current, boundaries, Direction.SOUTH) && dy-- > 0) { + current = new Position(x, --y, height); + positions.addLast(current); } } else if (dy < 0) { - Position north = new Position(x, y + 1, height); + Position current = start; - while (traversable(north) && dy++ < 0) { - north = new Position(x, ++y, height); - positions.addLast(north); + while (traversable(current, boundaries, Direction.NORTH) && dy++ < 0) { + current = new Position(x, ++y, height); + positions.addLast(current); } } Position last = new Position(x, y, height); - if (!last.equals(target) && traversable(last, Direction.EAST, Direction.WEST)) { + if (!last.equals(target) && dx != 0 && traversable(last, boundaries, (dx > 0) ? Direction.WEST : Direction.EAST)) { return addHorizontal(last, target, positions); } diff --git a/src/org/apollo/game/model/event/Event.java b/src/org/apollo/game/model/event/Event.java index 8d71d84e..fbb225b0 100644 --- a/src/org/apollo/game/model/event/Event.java +++ b/src/org/apollo/game/model/event/Event.java @@ -6,7 +6,7 @@ package org.apollo.game.model.event; * @author Major */ public abstract class Event { - + /** * Indicates whether or not the Event chain has been terminated. */ @@ -27,5 +27,5 @@ public abstract class Event { public final boolean terminated() { return terminated; } - + } \ No newline at end of file diff --git a/src/org/apollo/game/model/inter/InterfaceConstants.java b/src/org/apollo/game/model/inter/InterfaceConstants.java index d0e44330..b356f590 100644 --- a/src/org/apollo/game/model/inter/InterfaceConstants.java +++ b/src/org/apollo/game/model/inter/InterfaceConstants.java @@ -10,8 +10,8 @@ public class InterfaceConstants { /** * The default inventory tab ids. */ - public static final int[] DEFAULT_INVENTORY_TABS = { 2423, 3917, 638, 3213, 1644, 5608, 1151, -1, 5065, 5715, 2449, 904, 147, - 962, }; + public static final int[] DEFAULT_INVENTORY_TABS = { 2423, 3917, 638, 3213, 1644, 5608, 1151, -1, 5065, 5715, 2449, + 904, 147, 962, }; // 6299 = music tab, music disabled // 4445 = settings tab, music disabled // 12855 = ancients magic @@ -19,8 +19,8 @@ public class InterfaceConstants { /** * The level-up dialogue interface ids. */ - public static final int[] LEVEL_UP_INTERFACES = { 6247, 6253, 6206, 6216, 4443, 6242, 6211, 6226, 4272, 6231, 6258, 4282, - 6263, 6221, 4416, 6237, 4277, 4261, 12122, 4887, 4267 }; + public static final int[] LEVEL_UP_INTERFACES = { 6247, 6253, 6206, 6216, 4443, 6242, 6211, 6226, 4272, 6231, 6258, + 4282, 6263, 6221, 4416, 6237, 4277, 4261, 12122, 4887, 4267 }; /** * The quest interface id. @@ -35,12 +35,13 @@ public class InterfaceConstants { /** * The array of widgets that display the text. */ - public static final int[] QUEST_TEXT = { 8144, 8145, 8147, 8148, 8149, 8150, 8151, 8152, 8153, 8154, 8155, 8156, 8157, 8158, - 8159, 8160, 8161, 8162, 8163, 8164, 8165, 8166, 8167, 8168, 8169, 8170, 8171, 8172, 8173, 8174, 8175, 8176, 8177, - 8178, 8179, 8180, 8181, 8182, 8183, 8184, 8185, 8186, 8187, 8188, 8189, 8190, 8191, 8192, 8193, 8194, 8195, 12174, - 12175, 12176, 12177, 12178, 12179, 12180, 12181, 12182, 12183, 12184, 12185, 12186, 12187, 12188, 12189, 12190, - 12191, 12192, 12193, 12194, 12195, 12196, 12197, 12198, 12199, 12200, 12201, 12202, 12203, 12204, 12205, 12206, - 12207, 12208, 12209, 12210, 12211, 12212, 12213, 12214, 12215, 12216, 12217, 12218, 12219, 12220, 12221, 12222, 12223 }; + public static final int[] QUEST_TEXT = { 8144, 8145, 8147, 8148, 8149, 8150, 8151, 8152, 8153, 8154, 8155, 8156, + 8157, 8158, 8159, 8160, 8161, 8162, 8163, 8164, 8165, 8166, 8167, 8168, 8169, 8170, 8171, 8172, 8173, 8174, + 8175, 8176, 8177, 8178, 8179, 8180, 8181, 8182, 8183, 8184, 8185, 8186, 8187, 8188, 8189, 8190, 8191, 8192, + 8193, 8194, 8195, 12174, 12175, 12176, 12177, 12178, 12179, 12180, 12181, 12182, 12183, 12184, 12185, + 12186, 12187, 12188, 12189, 12190, 12191, 12192, 12193, 12194, 12195, 12196, 12197, 12198, 12199, 12200, + 12201, 12202, 12203, 12204, 12205, 12206, 12207, 12208, 12209, 12210, 12211, 12212, 12213, 12214, 12215, + 12216, 12217, 12218, 12219, 12220, 12221, 12222, 12223 }; /** * The quest title widget id. diff --git a/src/org/apollo/game/model/inv/Inventory.java b/src/org/apollo/game/model/inv/Inventory.java index 5e9fd664..ac6abbe1 100644 --- a/src/org/apollo/game/model/inv/Inventory.java +++ b/src/org/apollo/game/model/inv/Inventory.java @@ -51,7 +51,7 @@ public final class Inventory { /** * A flag indicating if events are being fired. */ - private boolean firingEvents = true; // TODO: make this reentrant + private boolean firingEvents = true; /** * The items in this inventory. diff --git a/src/org/apollo/game/model/package-info.java b/src/org/apollo/game/model/package-info.java index 109e9321..d0bcf043 100644 --- a/src/org/apollo/game/model/package-info.java +++ b/src/org/apollo/game/model/package-info.java @@ -1,5 +1,4 @@ /** - * Contains classes which represent things in the in-game world such as items, - * players and NPCs. + * Contains classes which represent things in the in-game world such as items, players and NPCs. */ package org.apollo.game.model; \ No newline at end of file diff --git a/src/org/apollo/game/model/skill/LevelUpSkillListener.java b/src/org/apollo/game/model/skill/LevelUpSkillListener.java index 953706f8..3539fb67 100644 --- a/src/org/apollo/game/model/skill/LevelUpSkillListener.java +++ b/src/org/apollo/game/model/skill/LevelUpSkillListener.java @@ -31,8 +31,7 @@ public final class LevelUpSkillListener extends SkillAdapter { // TODO show the interface String name = Skill.getName(id); String article = LanguageUtil.getIndefiniteArticle(name); - player.sendMessage("You've just advanced " + article + " " + name + " level! You have reached level " - + skill.getMaximumLevel() + "."); + player.sendMessage("You've just advanced " + article + " " + name + " level! You have reached level " + skill.getMaximumLevel() + "."); if (Skill.isCombatSkill(id)) { player.getSkillSet().calculateCombatLevel(); diff --git a/src/org/apollo/game/scheduling/impl/NpcMovementTask.java b/src/org/apollo/game/scheduling/impl/NpcMovementTask.java new file mode 100644 index 00000000..9a87a94a --- /dev/null +++ b/src/org/apollo/game/scheduling/impl/NpcMovementTask.java @@ -0,0 +1,100 @@ +package org.apollo.game.scheduling.impl; + +import java.util.Comparator; +import java.util.Deque; +import java.util.PriorityQueue; +import java.util.Queue; +import java.util.Random; + +import org.apollo.game.model.Position; +import org.apollo.game.model.entity.Npc; +import org.apollo.game.model.entity.WalkingQueue; +import org.apollo.game.model.entity.path.SimplePathfindingAlgorithm; +import org.apollo.game.scheduling.ScheduledTask; + +import com.google.common.base.Preconditions; + +/** + * A {@link ScheduledTask} that causes {@link Npc}s to randomly walk around in their boundary. + * + * @author Major + */ +public final class NpcMovementTask extends ScheduledTask { + + /** + * The delay between executions of this task, in pulses. + */ + private static final int DELAY = 5; + + /** + * The random number generator used to calculate how many Npcs should be moved per execution. + */ + private static final Random RANDOM = new Random(); + + /** + * The comparator used to sort the Npcs in the PriorityQueue. + */ + private static final Comparator RANDOM_COMPARATOR = (first, second) -> RANDOM.nextInt(2) - 1; + + /** + * The PathfindingAlgorithm used by this Task. + */ + private final SimplePathfindingAlgorithm algorithm = new SimplePathfindingAlgorithm(); + + /** + * The Queue of Npcs. + */ + private final Queue npcs = new PriorityQueue<>(RANDOM_COMPARATOR); + + /** + * Creates the NpcMovementTask. + */ + public NpcMovementTask() { + super(DELAY, false); + } + + /** + * Adds the {@link Npc} to this {@link ScheduledTask}. + * + * @param npc The Npc to add. + */ + public void addNpc(Npc npc) { + Preconditions.checkArgument(npc.hasBoundaries(), "Cannot add an npc with no boundaries to the NpcMovementTask."); + npcs.offer(npc); + } + + @Override + public void execute() { + int count = RANDOM.nextInt(npcs.size() / 50 + 5); + for (int iterations = 0; iterations < count; iterations++) { + Npc npc = npcs.poll(); + if (npc == null) { + break; + } + + Position[] boundary = npc.getBoundaries().get(); + Position current = npc.getPosition(); + Position min = boundary[0], max = boundary[1]; + int currentX = current.getX(), currentY = current.getY(); + + boolean negativeX = RANDOM.nextBoolean(), negativeY = RANDOM.nextBoolean(); + int x = RANDOM.nextInt(negativeX ? (currentX - min.getX()) : (max.getX() - currentX)); + int y = RANDOM.nextInt(negativeY ? (currentY - min.getY()) : (max.getY() - currentY)); + + int dx = negativeX ? -x : x; + int dy = negativeY ? -y : y; + Position next = new Position(currentX + dx, currentY + dy); + + Deque positions = algorithm.find(current, next, boundary); + WalkingQueue queue = npc.getWalkingQueue(); + + Position first = positions.pollFirst(); + if (first != null && queue.addFirstStep(first)) { + positions.forEach(npc.getWalkingQueue()::addStep); + } + + npcs.offer(npc); + } + } + +} \ No newline at end of file diff --git a/src/org/apollo/game/scheduling/package-info.java b/src/org/apollo/game/scheduling/package-info.java index 6fe54d13..2362c0e3 100644 --- a/src/org/apollo/game/scheduling/package-info.java +++ b/src/org/apollo/game/scheduling/package-info.java @@ -1,5 +1,4 @@ /** - * Contains classes related to scheduling which allow tasks to be executed in - * future pulses periodically. + * Contains classes related to scheduling which allow tasks to be executed in future pulses periodically. */ package org.apollo.game.scheduling; \ No newline at end of file diff --git a/src/org/apollo/game/sync/block/AppearanceBlock.java b/src/org/apollo/game/sync/block/AppearanceBlock.java index c37e8cb8..db91ea42 100644 --- a/src/org/apollo/game/sync/block/AppearanceBlock.java +++ b/src/org/apollo/game/sync/block/AppearanceBlock.java @@ -77,8 +77,7 @@ public final class AppearanceBlock extends SynchronizationBlock { * @param isSkulled Whether or not the player is skulled. * @param npcId The npc id of the player, if they are appearing as an npc, (otherwise {@code -1}). */ - AppearanceBlock(long name, Appearance appearance, int combat, int skill, Inventory equipment, int headIcon, - boolean isSkulled, int npcId) { + AppearanceBlock(long name, Appearance appearance, int combat, int skill, Inventory equipment, int headIcon, boolean isSkulled, int npcId) { this.name = name; this.appearance = appearance; this.combat = combat; diff --git a/src/org/apollo/game/sync/block/ForceMovementBlock.java b/src/org/apollo/game/sync/block/ForceMovementBlock.java index b213492a..4b22f050 100644 --- a/src/org/apollo/game/sync/block/ForceMovementBlock.java +++ b/src/org/apollo/game/sync/block/ForceMovementBlock.java @@ -48,8 +48,7 @@ public final class ForceMovementBlock extends SynchronizationBlock { * @param travelDurationY The length of time (in game pulses) the player's movement along the Y-axis will last. * @param direction The direction the player should move. */ - ForceMovementBlock(Position initialPosition, Position finalPosition, int travelDurationX, int travelDurationY, - Direction direction) { + ForceMovementBlock(Position initialPosition, Position finalPosition, int travelDurationX, int travelDurationY, Direction direction) { this.initialPosition = initialPosition; this.finalPosition = finalPosition; this.travelDurationX = travelDurationX; diff --git a/src/org/apollo/game/sync/block/SynchronizationBlock.java b/src/org/apollo/game/sync/block/SynchronizationBlock.java index e40d8a1e..b6817c8c 100644 --- a/src/org/apollo/game/sync/block/SynchronizationBlock.java +++ b/src/org/apollo/game/sync/block/SynchronizationBlock.java @@ -37,8 +37,7 @@ public abstract class SynchronizationBlock { int combat = player.getSkillSet().getCombatLevel(); int id = player.hasNpcDefinition() ? player.getDefinition().getId() : -1; - return new AppearanceBlock(player.getEncodedName(), player.getAppearance(), combat, 0, player.getEquipment(), - player.getPrayerIcon(), player.isSkulled(), id); + return new AppearanceBlock(player.getEncodedName(), player.getAppearance(), combat, 0, player.getEquipment(), player.getPrayerIcon(), player.isSkulled(), id); } /** @@ -72,8 +71,7 @@ public abstract class SynchronizationBlock { * @param direction The {@link Direction} the player should move. * @return The force movement block. */ - public static SynchronizationBlock createForceMovementBlock(Position initialPosition, Position finalPosition, - int travelDurationX, int travelDurationY, Direction direction) { + public static SynchronizationBlock createForceMovementBlock(Position initialPosition, Position finalPosition, int travelDurationX, int travelDurationY, Direction direction) { return new ForceMovementBlock(initialPosition, finalPosition, travelDurationX, travelDurationY, direction); } @@ -98,10 +96,8 @@ public abstract class SynchronizationBlock { * @param secondary If the block is a secondary hit or not. * @return The hit update block. */ - public static SynchronizationBlock createHitUpdateBlock(int damage, int type, int currentHealth, int maximumHealth, - boolean secondary) { - return secondary ? new SecondaryHitUpdateBlock(damage, type, currentHealth, maximumHealth) : new HitUpdateBlock(damage, - type, currentHealth, maximumHealth); + public static SynchronizationBlock createHitUpdateBlock(int damage, int type, int currentHealth, int maximumHealth, boolean secondary) { + return secondary ? new SecondaryHitUpdateBlock(damage, type, currentHealth, maximumHealth) : new HitUpdateBlock(damage, type, currentHealth, maximumHealth); } /** diff --git a/src/org/apollo/game/sync/package-info.java b/src/org/apollo/game/sync/package-info.java index d2a5a620..6aaee3d8 100644 --- a/src/org/apollo/game/sync/package-info.java +++ b/src/org/apollo/game/sync/package-info.java @@ -1,5 +1,5 @@ /** - * Contains classes related to client synchronization - the process where the - * client's state is updated by the server so it matches the server's state. + * Contains classes related to client synchronization - the process where the client's state is updated by the server so + * it matches the server's state. */ package org.apollo.game.sync; \ No newline at end of file diff --git a/src/org/apollo/game/sync/seg/MovementSegment.java b/src/org/apollo/game/sync/seg/MovementSegment.java index cbbaadf0..97376791 100644 --- a/src/org/apollo/game/sync/seg/MovementSegment.java +++ b/src/org/apollo/game/sync/seg/MovementSegment.java @@ -26,8 +26,7 @@ public final class MovementSegment extends SynchronizationSegment { */ public MovementSegment(SynchronizationBlockSet blockSet, Direction[] directions) { super(blockSet); - Preconditions.checkArgument(directions.length >= 0 && directions.length < 3, - "Directions length must be between 0 and 2 inclusive."); + Preconditions.checkArgument(directions.length >= 0 && directions.length < 3, "Directions length must be between 0 and 2 inclusive."); this.directions = directions; } @@ -43,14 +42,14 @@ public final class MovementSegment extends SynchronizationSegment { @Override public SegmentType getType() { switch (directions.length) { - case 0: - return SegmentType.NO_MOVEMENT; - case 1: - return SegmentType.WALK; - case 2: - return SegmentType.RUN; - default: - throw new IllegalStateException("Direction type unsupported."); + case 0: + return SegmentType.NO_MOVEMENT; + case 1: + return SegmentType.WALK; + case 2: + return SegmentType.RUN; + default: + throw new IllegalStateException("Direction type unsupported."); } } diff --git a/src/org/apollo/game/sync/seg/package-info.java b/src/org/apollo/game/sync/seg/package-info.java index 41052407..eb33ad96 100644 --- a/src/org/apollo/game/sync/seg/package-info.java +++ b/src/org/apollo/game/sync/seg/package-info.java @@ -1,6 +1,5 @@ /** - * Contains classes related to synchronization segments. Each segment contains - * multiple blocks and can be used to add, remove, teleport or move a - * mob. + * Contains classes related to synchronization segments. Each segment contains multiple blocks and can be used to add, + * remove, teleport or move a mob. */ package org.apollo.game.sync.seg; \ No newline at end of file diff --git a/src/org/apollo/game/sync/task/NpcSynchronizationTask.java b/src/org/apollo/game/sync/task/NpcSynchronizationTask.java index 0f9255d3..b8d63221 100644 --- a/src/org/apollo/game/sync/task/NpcSynchronizationTask.java +++ b/src/org/apollo/game/sync/task/NpcSynchronizationTask.java @@ -50,8 +50,7 @@ public final class NpcSynchronizationTask extends SynchronizationTask { for (Iterator it = localNpcs.iterator(); it.hasNext();) { Npc npc = it.next(); - if (!npc.isActive() || npc.isTeleporting() - || npc.getPosition().getLongestDelta(playerPosition) > player.getViewingDistance()) { + if (!npc.isActive() || npc.isTeleporting() || npc.getPosition().getLongestDelta(playerPosition) > player.getViewingDistance()) { it.remove(); segments.add(new RemoveMobSegment()); } else { @@ -70,8 +69,7 @@ public final class NpcSynchronizationTask extends SynchronizationTask { } Position npcPosition = npc.getPosition(); - if (npcPosition.isWithinDistance(playerPosition, player.getViewingDistance()) && !localNpcs.contains(npc) - && npcPosition.getHeight() == playerPosition.getHeight()) { + if (npcPosition.isWithinDistance(playerPosition, player.getViewingDistance()) && !localNpcs.contains(npc) && npcPosition.getHeight() == playerPosition.getHeight()) { localNpcs.add(npc); added++; npc.turnTo(npc.getFacingPosition()); diff --git a/src/org/apollo/game/sync/task/PhasedSynchronizationTask.java b/src/org/apollo/game/sync/task/PhasedSynchronizationTask.java index 020ea7c8..c6b39da0 100644 --- a/src/org/apollo/game/sync/task/PhasedSynchronizationTask.java +++ b/src/org/apollo/game/sync/task/PhasedSynchronizationTask.java @@ -38,7 +38,7 @@ public final class PhasedSynchronizationTask extends SynchronizationTask { public void run() { try { task.run(); - } catch (Exception e) { // TODO better solution... + } catch (Exception e) { e.printStackTrace(); // The executor suppresses any exceptions thrown as part of the task, so we catch and print here as // rethrowing them does nothing. diff --git a/src/org/apollo/game/sync/task/PlayerSynchronizationTask.java b/src/org/apollo/game/sync/task/PlayerSynchronizationTask.java index e3155924..5ffd93f2 100644 --- a/src/org/apollo/game/sync/task/PlayerSynchronizationTask.java +++ b/src/org/apollo/game/sync/task/PlayerSynchronizationTask.java @@ -70,8 +70,7 @@ public final class PlayerSynchronizationTask extends SynchronizationTask { for (Iterator it = localPlayers.iterator(); it.hasNext();) { Player other = it.next(); - if (!other.isActive() || other.isTeleporting() - || other.getPosition().getLongestDelta(player.getPosition()) > player.getViewingDistance()) { + if (!other.isActive() || other.isTeleporting() || other.getPosition().getLongestDelta(player.getPosition()) > player.getViewingDistance()) { it.remove(); segments.add(new RemoveMobSegment()); } else { @@ -91,8 +90,7 @@ public final class PlayerSynchronizationTask extends SynchronizationTask { break; } - if (other != player && other.getPosition().isWithinDistance(player.getPosition(), player.getViewingDistance()) - && !localPlayers.contains(other)) { + if (other != player && other.getPosition().isWithinDistance(player.getPosition(), player.getViewingDistance()) && !localPlayers.contains(other)) { localPlayers.add(other); added++; @@ -107,8 +105,7 @@ public final class PlayerSynchronizationTask extends SynchronizationTask { } } - PlayerSynchronizationMessage message = new PlayerSynchronizationMessage(lastKnownSector, player.getPosition(), - sectorChanged, segment, oldLocalPlayers, segments); + PlayerSynchronizationMessage message = new PlayerSynchronizationMessage(lastKnownSector, player.getPosition(), sectorChanged, segment, oldLocalPlayers, segments); player.send(message); } diff --git a/src/org/apollo/game/sync/task/package-info.java b/src/org/apollo/game/sync/task/package-info.java index b45ff20d..bca00016 100644 --- a/src/org/apollo/game/sync/task/package-info.java +++ b/src/org/apollo/game/sync/task/package-info.java @@ -1,6 +1,5 @@ /** - * Contains classes related to - * {@link org.apollo.game.sync.task.SynchronizationTask}s, small chunks of work - * executed during the client synchronization process. + * Contains classes related to {@link org.apollo.game.sync.task.SynchronizationTask}s, small chunks of work executed + * during the client synchronization process. */ package org.apollo.game.sync.task; \ No newline at end of file diff --git a/src/org/apollo/io/MessageHandlerChainParser.java b/src/org/apollo/io/MessageHandlerChainParser.java index 96aa7b8c..27208725 100644 --- a/src/org/apollo/io/MessageHandlerChainParser.java +++ b/src/org/apollo/io/MessageHandlerChainParser.java @@ -53,8 +53,7 @@ public final class MessageHandlerChainParser { * @return A {@link MessageHandlerChainGroup}. */ @SuppressWarnings("unchecked") - public MessageHandlerChainGroup parse() throws IOException, SAXException, ClassNotFoundException, InstantiationException, - IllegalAccessException { + public MessageHandlerChainGroup parse() throws IOException, SAXException, ClassNotFoundException, InstantiationException, IllegalAccessException { XmlNode messages = parser.parse(is); if (!messages.getName().equals("messages")) { throw new IOException("Root node name is not 'messages'."); @@ -94,8 +93,7 @@ public final class MessageHandlerChainParser { throw new IOException("Handler node must have a value."); } - Class> handlerClass = (Class>) Class - .forName(handlerClassName); + Class> handlerClass = (Class>) Class.forName(handlerClassName); MessageHandler handler = handlerClass.newInstance(); handlers.add(handler); } diff --git a/src/org/apollo/io/player/BinaryFileUtils.java b/src/org/apollo/io/player/BinaryFileUtils.java new file mode 100644 index 00000000..00c747a4 --- /dev/null +++ b/src/org/apollo/io/player/BinaryFileUtils.java @@ -0,0 +1,56 @@ +package org.apollo.io.player; + +import java.io.File; +import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +import org.apollo.util.NameUtil; + +/** + * A utility class with common functionality used by the binary player loader/ savers. + * + * @author Graham + * @author Major + */ +public final class BinaryFileUtils { + + /** + * The Path to the saved games directory. + */ + private static final Path SAVED_GAMES_DIRECTORY = Paths.get("data/savedGames"); + + /** + * Creates the saved games directory if it does not exist. + */ + static { + try { + if (!Files.exists(SAVED_GAMES_DIRECTORY)) { + Files.createDirectory(SAVED_GAMES_DIRECTORY); + } + } catch (IOException e) { + throw new UncheckedIOException("Error creating saved games directory.", e); + } + } + + /** + * Gets the save {@link File} for the specified player. + * + * @param username The username of the player. + * @return The file. + */ + public static Path getFile(String username) { + String filtered = NameUtil.decodeBase37(NameUtil.encodeBase37(username)); + return SAVED_GAMES_DIRECTORY.resolve(filtered + ".dat"); + } + + /** + * Sole private constructor to prevent instantiation. + */ + private BinaryFileUtils() { + + } + +} \ No newline at end of file diff --git a/src/org/apollo/io/player/impl/BinaryPlayerLoader.java b/src/org/apollo/io/player/BinaryPlayerSerializer.java similarity index 52% rename from src/org/apollo/io/player/impl/BinaryPlayerLoader.java rename to src/org/apollo/io/player/BinaryPlayerSerializer.java index 19d77500..6ae08b98 100644 --- a/src/org/apollo/io/player/impl/BinaryPlayerLoader.java +++ b/src/org/apollo/io/player/BinaryPlayerSerializer.java @@ -1,13 +1,20 @@ -package org.apollo.io.player.impl; +package org.apollo.io.player; +import java.io.BufferedInputStream; import java.io.DataInputStream; +import java.io.DataOutputStream; import java.io.File; -import java.io.FileInputStream; import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; import org.apollo.game.model.Appearance; import org.apollo.game.model.Item; @@ -16,6 +23,8 @@ import org.apollo.game.model.entity.Player; import org.apollo.game.model.entity.Skill; import org.apollo.game.model.entity.SkillSet; import org.apollo.game.model.entity.attr.Attribute; +import org.apollo.game.model.entity.attr.AttributeMap; +import org.apollo.game.model.entity.attr.AttributePersistence; import org.apollo.game.model.entity.attr.AttributeType; import org.apollo.game.model.entity.attr.BooleanAttribute; import org.apollo.game.model.entity.attr.NumericalAttribute; @@ -26,8 +35,6 @@ import org.apollo.game.model.entity.setting.PrivacyState; import org.apollo.game.model.entity.setting.PrivilegeLevel; import org.apollo.game.model.entity.setting.ScreenBrightness; import org.apollo.game.model.inv.Inventory; -import org.apollo.io.player.PlayerLoader; -import org.apollo.io.player.PlayerLoaderResponse; import org.apollo.net.codec.login.LoginConstants; import org.apollo.security.PlayerCredentials; import org.apollo.util.NameUtil; @@ -36,28 +43,39 @@ import org.apollo.util.StreamUtil; import com.lambdaworks.crypto.SCryptUtil; /** - * A {@link PlayerLoader} implementation that loads data from a binary file. + * A {@link PlayerSerializer} implementation that uses a binary file to store player data. * * @author Graham + * @author Major */ -public final class BinaryPlayerLoader implements PlayerLoader { +public final class BinaryPlayerSerializer implements PlayerSerializer { /** - * The default spawn position. + * The Path to the saved games directory. */ - private static final Position SPAWN_POSITION = new Position(3093, 3104); + private static final Path SAVED_GAMES_DIRECTORY = Paths.get("data/savedGames"); + + static { + try { + if (!Files.exists(SAVED_GAMES_DIRECTORY)) { + Files.createDirectory(SAVED_GAMES_DIRECTORY); + } + } catch (IOException e) { + throw new UncheckedIOException("Error creating saved games directory.", e); + } + } @Override public PlayerLoaderResponse loadPlayer(PlayerCredentials credentials) throws IOException { - File file = BinaryPlayerUtil.getFile(credentials.getUsername()); - if (!file.exists()) { - Player player = new Player(credentials, SPAWN_POSITION); - player.getBank().add(995, 25); // 25 coins + Path path = getFile(credentials.getUsername()); + if (!Files.exists(path)) { + Player player = new Player(credentials, TUTORIAL_ISLAND_SPAWN); + credentials.setPassword(SCryptUtil.scrypt(credentials.getPassword(), 16384, 8, 1)); return new PlayerLoaderResponse(LoginConstants.STATUS_OK, player); } - try (DataInputStream in = new DataInputStream(new FileInputStream(file))) { + try (DataInputStream in = new DataInputStream(new BufferedInputStream(Files.newInputStream(path)))) { String name = StreamUtil.readString(in); String password = StreamUtil.readString(in); @@ -67,37 +85,35 @@ public final class BinaryPlayerLoader implements PlayerLoader { credentials.setPassword(password); // Update password to the hashed one. - PrivilegeLevel privilegeLevel = PrivilegeLevel.valueOf(in.readByte()); + PrivilegeLevel privilege = PrivilegeLevel.valueOf(in.readByte()); MembershipStatus members = MembershipStatus.valueOf(in.readByte()); PrivacyState chatPrivacy = PrivacyState.valueOf(in.readByte(), true); PrivacyState friendPrivacy = PrivacyState.valueOf(in.readByte(), false); PrivacyState tradePrivacy = PrivacyState.valueOf(in.readByte(), false); - int runEnergy = in.readByte(); ScreenBrightness brightness = ScreenBrightness.valueOf(in.readByte()); int x = in.readUnsignedShort(); int y = in.readUnsignedShort(); int height = in.readUnsignedByte(); - int genderIntValue = in.readUnsignedByte(); - Gender gender = genderIntValue == Gender.MALE.toInteger() ? Gender.MALE : Gender.FEMALE; + Gender gender = (in.readUnsignedByte() == Gender.MALE.toInteger()) ? Gender.MALE : Gender.FEMALE; int[] style = new int[7]; - for (int i = 0; i < style.length; i++) { - style[i] = in.readUnsignedByte(); + for (int slot = 0; slot < style.length; slot++) { + style[slot] = in.readUnsignedByte(); } + int[] colors = new int[5]; - for (int i = 0; i < colors.length; i++) { - colors[i] = in.readUnsignedByte(); + for (int slot = 0; slot < colors.length; slot++) { + colors[slot] = in.readUnsignedByte(); } Player player = new Player(credentials, new Position(x, y, height)); - player.setPrivilegeLevel(privilegeLevel); + player.setPrivilegeLevel(privilege); player.setMembers(members); player.setChatPrivacy(chatPrivacy); player.setFriendPrivacy(friendPrivacy); player.setTradePrivacy(tradePrivacy); - player.setRunEnergy(runEnergy); player.setScreenBrightness(brightness); player.setAppearance(new Appearance(gender, style, colors)); @@ -141,6 +157,87 @@ public final class BinaryPlayerLoader implements PlayerLoader { } } + @Override + public void savePlayer(Player player) throws IOException { + Path file = getFile(player.getUsername()); + + try (DataOutputStream out = new DataOutputStream(Files.newOutputStream(file))) { + StreamUtil.writeString(out, player.getUsername()); + StreamUtil.writeString(out, player.getCredentials().getPassword()); + out.writeByte(player.getPrivilegeLevel().toInteger()); + out.writeByte(player.getMembershipStatus().getValue()); + + out.writeByte(player.getChatPrivacy().toInteger(true)); + out.writeByte(player.getFriendPrivacy().toInteger(false)); + out.writeByte(player.getTradePrivacy().toInteger(false)); + out.writeByte(player.getScreenBrightness().toInteger()); + + Position position = player.getPosition(); + out.writeShort(position.getX()); + out.writeShort(position.getY()); + out.writeByte(position.getHeight()); + + Appearance appearance = player.getAppearance(); + out.writeByte(appearance.getGender().toInteger()); + int[] style = appearance.getStyle(); + for (int element : style) { + out.writeByte(element); + } + int[] colors = appearance.getColors(); + for (int color : colors) { + out.writeByte(color); + } + + writeInventory(out, player.getInventory()); + writeInventory(out, player.getEquipment()); + writeInventory(out, player.getBank()); + + SkillSet skills = player.getSkillSet(); + out.writeByte(skills.size()); + for (int id = 0; id < skills.size(); id++) { + Skill skill = skills.getSkill(id); + out.writeByte(skill.getCurrentLevel()); + out.writeDouble(skill.getExperience()); + } + + List usernames = player.getFriendUsernames(); + out.writeByte(usernames.size()); + for (String username : usernames) { + out.writeLong(NameUtil.encodeBase37(username)); + } + + usernames = player.getIgnoredUsernames(); + out.writeByte(usernames.size()); + for (String username : usernames) { + out.writeLong(NameUtil.encodeBase37(username)); + } + + Set>> attributes = player.getAttributes().entrySet(); + attributes.removeIf(e -> AttributeMap.getDefinition(e.getKey()).getPersistence() != AttributePersistence.PERSISTENT); + out.writeInt(attributes.size()); + + for (Entry> entry : attributes) { + String name = entry.getKey(); + StreamUtil.writeString(out, name); + + Attribute attribute = entry.getValue(); + out.writeByte(attribute.getType().getValue()); + out.write(attribute.encode()); + } + } + } + + /** + * Gets the save {@link File} for the specified player. + * + * @param username The username of the player. + * @return The file. + */ + private Path getFile(String username) { + String filtered = NameUtil.decodeBase37(NameUtil.encodeBase37(username)); + return SAVED_GAMES_DIRECTORY.resolve(filtered + ".dat"); + } + /** * Reads the player's {@link Attribute}s. * @@ -148,7 +245,7 @@ public final class BinaryPlayerLoader implements PlayerLoader { * @return The {@link Map} of attribute names to attributes. * @throws IOException If there is an error reading from the stream. */ - private static Map> readAttributes(DataInputStream in) throws IOException { + private Map> readAttributes(DataInputStream in) throws IOException { int count = in.readInt(); Map> attributes = new HashMap<>(count); @@ -187,7 +284,7 @@ public final class BinaryPlayerLoader implements PlayerLoader { * @param inventory The inventory. * @throws IOException If an I/O error occurs. */ - private static void readInventory(DataInputStream in, Inventory inventory) throws IOException { + private void readInventory(DataInputStream in, Inventory inventory) throws IOException { int capacity = in.readUnsignedShort(); inventory.stopFiringEvents(); @@ -206,4 +303,27 @@ public final class BinaryPlayerLoader implements PlayerLoader { } } + /** + * Writes an inventory to the specified output stream. + * + * @param out The output stream. + * @param inventory The inventory. + * @throws IOException If an I/O error occurs. + */ + private void writeInventory(DataOutputStream out, Inventory inventory) throws IOException { + int capacity = inventory.capacity(); + out.writeShort(capacity); + + for (int slot = 0; slot < capacity; slot++) { + Item item = inventory.get(slot); + if (item != null) { + out.writeShort(item.getId() + 1); + out.writeInt(item.getAmount()); + } else { + out.writeShort(0); + out.writeInt(0); + } + } + } + } \ No newline at end of file diff --git a/src/org/apollo/io/player/impl/DummyPlayerLoader.java b/src/org/apollo/io/player/DummyPlayerSerializer.java similarity index 52% rename from src/org/apollo/io/player/impl/DummyPlayerLoader.java rename to src/org/apollo/io/player/DummyPlayerSerializer.java index 83b0aedf..5466f385 100644 --- a/src/org/apollo/io/player/impl/DummyPlayerLoader.java +++ b/src/org/apollo/io/player/DummyPlayerSerializer.java @@ -1,35 +1,33 @@ -package org.apollo.io.player.impl; +package org.apollo.io.player; -import org.apollo.game.model.Position; import org.apollo.game.model.entity.Player; import org.apollo.game.model.entity.setting.MembershipStatus; import org.apollo.game.model.entity.setting.PrivilegeLevel; -import org.apollo.io.player.PlayerLoader; -import org.apollo.io.player.PlayerLoaderResponse; import org.apollo.net.codec.login.LoginConstants; import org.apollo.security.PlayerCredentials; /** - * A dummy {@link PlayerLoader} implementation used for testing purposes. + * A {@link PlayerSerializer} that saves no data and returns an administrator member account, ideal for debugging. * * @author Graham + * @author Major */ -public final class DummyPlayerLoader implements PlayerLoader { - - /** - * The default spawn position for players loaded by this loader. - */ - private static final Position DEFAULT_POSITION = new Position(3093, 3104); +public final class DummyPlayerSerializer implements PlayerSerializer { @Override public PlayerLoaderResponse loadPlayer(PlayerCredentials credentials) { int status = LoginConstants.STATUS_OK; - Player player = new Player(credentials, DEFAULT_POSITION); + Player player = new Player(credentials, TUTORIAL_ISLAND_SPAWN); player.setPrivilegeLevel(PrivilegeLevel.ADMINISTRATOR); player.setMembers(MembershipStatus.PAID); return new PlayerLoaderResponse(status, player); } + @Override + public void savePlayer(Player player) { + /* discard player */ + } + } \ No newline at end of file diff --git a/src/org/apollo/io/player/JdbcPlayerSerializer.java b/src/org/apollo/io/player/JdbcPlayerSerializer.java new file mode 100644 index 00000000..c8e48cf0 --- /dev/null +++ b/src/org/apollo/io/player/JdbcPlayerSerializer.java @@ -0,0 +1,23 @@ +package org.apollo.io.player; + +import org.apollo.game.model.entity.Player; +import org.apollo.security.PlayerCredentials; + +/** + * A {@link PlayerSerializer} that utilises {@code JDBC} to communicate with an SQL database containing player data. + * + * @author Major + */ +public final class JdbcPlayerSerializer implements PlayerSerializer { + + @Override + public void savePlayer(Player player) throws Exception { + throw new UnsupportedOperationException("JDBC saving is not supported at this time."); + } + + @Override + public PlayerLoaderResponse loadPlayer(PlayerCredentials credentials) throws Exception { + throw new UnsupportedOperationException("JDBC loading is not supported at this time."); + } + +} \ No newline at end of file diff --git a/src/org/apollo/io/player/PlayerLoader.java b/src/org/apollo/io/player/PlayerLoader.java deleted file mode 100644 index ff14e622..00000000 --- a/src/org/apollo/io/player/PlayerLoader.java +++ /dev/null @@ -1,22 +0,0 @@ -package org.apollo.io.player; - -import org.apollo.security.PlayerCredentials; - -/** - * An interface which may be extended by others which are capable of loading players. For example, implementations might - * include text-based, binary and SQL loaders. - * - * @author Graham - */ -public interface PlayerLoader { - - /** - * Loads a player. - * - * @param credentials The player's credentials. - * @return The {@link PlayerLoaderResponse}. - * @throws Exception If an error occurs. - */ - public PlayerLoaderResponse loadPlayer(PlayerCredentials credentials) throws Exception; - -} \ No newline at end of file diff --git a/src/org/apollo/io/player/PlayerLoaderResponse.java b/src/org/apollo/io/player/PlayerLoaderResponse.java index 47527d11..6f6bc2b6 100644 --- a/src/org/apollo/io/player/PlayerLoaderResponse.java +++ b/src/org/apollo/io/player/PlayerLoaderResponse.java @@ -8,9 +8,10 @@ import org.apollo.net.codec.login.LoginConstants; import com.google.common.base.Preconditions; /** - * A response for the {@link PlayerLoader#loadPlayer(org.apollo.security.PlayerCredentials)} call. + * A response for the {@link PlayerSerializer#loadPlayer} call. * * @author Graham + * @author Major */ public final class PlayerLoaderResponse { diff --git a/src/org/apollo/io/player/PlayerSaver.java b/src/org/apollo/io/player/PlayerSaver.java deleted file mode 100644 index 1a2def5d..00000000 --- a/src/org/apollo/io/player/PlayerSaver.java +++ /dev/null @@ -1,21 +0,0 @@ -package org.apollo.io.player; - -import org.apollo.game.model.entity.Player; - -/** - * An interface which may be implemented by others which are capable of saving players. For example, implementations - * might include text-based, binary and SQL savers. - * - * @author Graham - */ -public interface PlayerSaver { - - /** - * Saves a player. - * - * @param player The player to save. - * @throws Exception If an error occurs. - */ - public void savePlayer(Player player) throws Exception; - -} \ No newline at end of file diff --git a/src/org/apollo/io/player/PlayerSerializer.java b/src/org/apollo/io/player/PlayerSerializer.java new file mode 100644 index 00000000..4d246a74 --- /dev/null +++ b/src/org/apollo/io/player/PlayerSerializer.java @@ -0,0 +1,38 @@ +package org.apollo.io.player; + +import org.apollo.game.model.Position; +import org.apollo.game.model.entity.Player; +import org.apollo.security.PlayerCredentials; + +/** + * An interface which may be implemented by others which are capable of serializing and deserializing players. For + * example, implementations might include text-based, binary and SQL serializers. + * + * @author Graham + * @author Major + */ +public interface PlayerSerializer { + + /** + * The spawn point for Players, on Tutorial Island. + */ + Position TUTORIAL_ISLAND_SPAWN = new Position(3093, 3104); + + /** + * Loads a {@link Player}. + * + * @param credentials The {@link PlayerCredentials}. + * @return The {@link PlayerLoaderResponse}. + * @throws Exception If an error occurs. + */ + public PlayerLoaderResponse loadPlayer(PlayerCredentials credentials) throws Exception; + + /** + * Saves a {@link Player}. + * + * @param player The Player to save. + * @throws Exception If an error occurs. + */ + public void savePlayer(Player player) throws Exception; + +} \ No newline at end of file diff --git a/src/org/apollo/io/player/impl/BinaryPlayerSaver.java b/src/org/apollo/io/player/impl/BinaryPlayerSaver.java deleted file mode 100644 index 5fca15a2..00000000 --- a/src/org/apollo/io/player/impl/BinaryPlayerSaver.java +++ /dev/null @@ -1,126 +0,0 @@ -package org.apollo.io.player.impl; - -import java.io.DataOutputStream; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.util.List; -import java.util.Map.Entry; -import java.util.Set; - -import org.apollo.game.model.Appearance; -import org.apollo.game.model.Item; -import org.apollo.game.model.Position; -import org.apollo.game.model.entity.Player; -import org.apollo.game.model.entity.Skill; -import org.apollo.game.model.entity.SkillSet; -import org.apollo.game.model.entity.attr.Attribute; -import org.apollo.game.model.entity.attr.AttributeMap; -import org.apollo.game.model.entity.attr.AttributePersistence; -import org.apollo.game.model.inv.Inventory; -import org.apollo.io.player.PlayerSaver; -import org.apollo.util.NameUtil; -import org.apollo.util.StreamUtil; - -/** - * A {@link PlayerSaver} implementation that saves player data to a binary file. - * - * @author Graham - */ -public final class BinaryPlayerSaver implements PlayerSaver { - - @Override - public void savePlayer(Player player) throws IOException { - File file = BinaryPlayerUtil.getFile(player.getUsername()); - - try (DataOutputStream out = new DataOutputStream(new FileOutputStream(file))) { - StreamUtil.writeString(out, player.getUsername()); - StreamUtil.writeString(out, player.getCredentials().getPassword()); - out.writeByte(player.getPrivilegeLevel().toInteger()); - out.writeByte(player.getMembershipStatus().getValue()); - - out.writeByte(player.getChatPrivacy().toInteger(true)); - out.writeByte(player.getFriendPrivacy().toInteger(false)); - out.writeByte(player.getTradePrivacy().toInteger(false)); - out.writeByte(player.getRunEnergy()); - out.writeByte(player.getScreenBrightness().toInteger()); - - Position position = player.getPosition(); - out.writeShort(position.getX()); - out.writeShort(position.getY()); - out.writeByte(position.getHeight()); - - Appearance appearance = player.getAppearance(); - out.writeByte(appearance.getGender().toInteger()); - int[] style = appearance.getStyle(); - for (int element : style) { - out.writeByte(element); - } - int[] colors = appearance.getColors(); - for (int color : colors) { - out.writeByte(color); - } - - writeInventory(out, player.getInventory()); - writeInventory(out, player.getEquipment()); - writeInventory(out, player.getBank()); - - SkillSet skills = player.getSkillSet(); - out.writeByte(skills.size()); - for (int id = 0; id < skills.size(); id++) { - Skill skill = skills.getSkill(id); - out.writeByte(skill.getCurrentLevel()); - out.writeDouble(skill.getExperience()); - } - - List usernames = player.getFriendUsernames(); - out.writeByte(usernames.size()); - for (String username : usernames) { - out.writeLong(NameUtil.encodeBase37(username)); - } - - usernames = player.getIgnoredUsernames(); - out.writeByte(usernames.size()); - for (String username : usernames) { - out.writeLong(NameUtil.encodeBase37(username)); - } - - Set>> attributes = player.getAttributes().entrySet(); - attributes.removeIf(e -> AttributeMap.getDefinition(e.getKey()).getPersistence() != AttributePersistence.PERSISTENT); - out.writeInt(attributes.size()); - - for (Entry> entry : attributes) { - String name = entry.getKey(); - StreamUtil.writeString(out, name); - - Attribute attribute = entry.getValue(); - out.writeByte(attribute.getType().getValue()); - out.write(attribute.encode()); - } - } - } - - /** - * Writes an inventory to the specified output stream. - * - * @param out The output stream. - * @param inventory The inventory. - * @throws IOException If an I/O error occurs. - */ - private static void writeInventory(DataOutputStream out, Inventory inventory) throws IOException { - int capacity = inventory.capacity(); - out.writeShort(capacity); - - for (int slot = 0; slot < capacity; slot++) { - Item item = inventory.get(slot); - if (item != null) { - out.writeShort(item.getId() + 1); - out.writeInt(item.getAmount()); - } else { - out.writeShort(0); - out.writeInt(0); - } - } - } - -} \ No newline at end of file diff --git a/src/org/apollo/io/player/impl/BinaryPlayerUtil.java b/src/org/apollo/io/player/impl/BinaryPlayerUtil.java deleted file mode 100644 index 9c4ca633..00000000 --- a/src/org/apollo/io/player/impl/BinaryPlayerUtil.java +++ /dev/null @@ -1,46 +0,0 @@ -package org.apollo.io.player.impl; - -import java.io.File; - -import org.apollo.util.NameUtil; - -/** - * A utility class with common functionality used by the binary player loader/ savers. - * - * @author Graham - */ -public final class BinaryPlayerUtil { - - /** - * The saved games directory. - */ - private static final File SAVED_GAMES_DIRECTORY = new File("data/savedGames"); - - /** - * Creates the saved games directory if it does not exist. - */ - static { - if (!SAVED_GAMES_DIRECTORY.exists()) { - SAVED_GAMES_DIRECTORY.mkdir(); - } - } - - /** - * Gets the save {@link File} for the specified player. - * - * @param username The username of the player. - * @return The file. - */ - public static File getFile(String username) { - String filtered = NameUtil.decodeBase37(NameUtil.encodeBase37(username)); - return new File(SAVED_GAMES_DIRECTORY, filtered + ".dat"); - } - - /** - * Default private constructor to prevent instantiation. - */ - private BinaryPlayerUtil() { - - } - -} \ No newline at end of file diff --git a/src/org/apollo/io/player/impl/DiscardPlayerSaver.java b/src/org/apollo/io/player/impl/DiscardPlayerSaver.java deleted file mode 100644 index cc00e839..00000000 --- a/src/org/apollo/io/player/impl/DiscardPlayerSaver.java +++ /dev/null @@ -1,18 +0,0 @@ -package org.apollo.io.player.impl; - -import org.apollo.game.model.entity.Player; -import org.apollo.io.player.PlayerSaver; - -/** - * A {@link PlayerSaver} implementation that discards player data. - * - * @author Graham - */ -public final class DiscardPlayerSaver implements PlayerSaver { - - @Override - public void savePlayer(Player player) { - /* discard player */ - } - -} \ No newline at end of file diff --git a/src/org/apollo/io/player/impl/JdbcPlayerLoader.java b/src/org/apollo/io/player/impl/JdbcPlayerLoader.java deleted file mode 100644 index 9be78090..00000000 --- a/src/org/apollo/io/player/impl/JdbcPlayerLoader.java +++ /dev/null @@ -1,19 +0,0 @@ -package org.apollo.io.player.impl; - -import org.apollo.io.player.PlayerLoader; -import org.apollo.io.player.PlayerLoaderResponse; -import org.apollo.security.PlayerCredentials; - -/** - * A {@link PlayerLoader} that utilises {@code JDBC} to load player files. - * - * @author Major - */ -public final class JdbcPlayerLoader implements PlayerLoader { - - @Override - public PlayerLoaderResponse loadPlayer(PlayerCredentials credentials) throws Exception { - throw new UnsupportedOperationException("JDBC loading is not supported at this time."); - } - -} \ No newline at end of file diff --git a/src/org/apollo/io/player/impl/JdbcPlayerSaver.java b/src/org/apollo/io/player/impl/JdbcPlayerSaver.java deleted file mode 100644 index bbdc7d3d..00000000 --- a/src/org/apollo/io/player/impl/JdbcPlayerSaver.java +++ /dev/null @@ -1,18 +0,0 @@ -package org.apollo.io.player.impl; - -import org.apollo.game.model.entity.Player; -import org.apollo.io.player.PlayerSaver; - -/** - * A {@link PlayerSaver} that utilises {@code JDBC} to save the player. - * - * @author Major - */ -public final class JdbcPlayerSaver implements PlayerSaver { - - @Override - public void savePlayer(Player player) throws Exception { - throw new UnsupportedOperationException("JDBC saving is not supported at this time."); - } - -} \ No newline at end of file diff --git a/src/org/apollo/io/player/impl/package-info.java b/src/org/apollo/io/player/impl/package-info.java deleted file mode 100644 index a56ca9ca..00000000 --- a/src/org/apollo/io/player/impl/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -/** - * Contains various player loader/saver implementations. - */ -package org.apollo.io.player.impl; \ No newline at end of file diff --git a/src/org/apollo/login/LoginService.java b/src/org/apollo/login/LoginService.java index fc45797f..d5664526 100644 --- a/src/org/apollo/login/LoginService.java +++ b/src/org/apollo/login/LoginService.java @@ -8,9 +8,8 @@ import java.util.concurrent.Executors; import org.apollo.Service; import org.apollo.game.model.entity.Player; -import org.apollo.io.player.PlayerLoader; import org.apollo.io.player.PlayerLoaderResponse; -import org.apollo.io.player.PlayerSaver; +import org.apollo.io.player.PlayerSerializer; import org.apollo.net.codec.login.LoginConstants; import org.apollo.net.codec.login.LoginRequest; import org.apollo.net.release.Release; @@ -25,6 +24,7 @@ import org.xml.sax.SAXException; * The {@link LoginService} manages {@link LoginRequest}s. * * @author Graham + * @author Major */ public final class LoginService extends Service { @@ -34,14 +34,9 @@ public final class LoginService extends Service { private final ExecutorService executor = Executors.newCachedThreadPool(new NamedThreadFactory("LoginService")); /** - * The current {@link PlayerLoader}. + * The current {@link PlayerSerializer}. */ - private PlayerLoader loader; - - /** - * The current {@link PlayerSaver}. - */ - private PlayerSaver saver; + private PlayerSerializer serializer; /** * Creates the login service. @@ -70,24 +65,16 @@ public final class LoginService extends Service { } if (!rootNode.getName().equals("login")) { - throw new IOException("Unexpected root node name."); + throw new IOException("Unexpected root node name, expected 'login'."); } - XmlNode loaderNode = rootNode.getChild("loader"); - if (loaderNode == null || !loaderNode.hasValue()) { - throw new IOException("No loader child node or value."); + XmlNode serializer = rootNode.getChild("serializer"); + if (serializer == null || !serializer.hasValue()) { + throw new IOException("No serializer child node or value."); } - XmlNode saverNode = rootNode.getChild("saver"); - if (saverNode == null || !saverNode.hasValue()) { - throw new IOException("No saver child node or value."); - } - - Class loaderClazz = Class.forName(loaderNode.getValue()); - Class saverClazz = Class.forName(saverNode.getValue()); - - loader = (PlayerLoader) loaderClazz.newInstance(); - saver = (PlayerSaver) saverClazz.newInstance(); + Class clazz = Class.forName(serializer.getValue()); + this.serializer = (PlayerSerializer) clazz.newInstance(); } /** @@ -95,7 +82,7 @@ public final class LoginService extends Service { */ @Override public void start() { - /* empty - here for consistency with other services */ + } /** @@ -110,7 +97,7 @@ public final class LoginService extends Service { // TODO check archive 0 CRCs session.handlePlayerLoaderResponse(request, new PlayerLoaderResponse(LoginConstants.STATUS_GAME_UPDATED)); } else { - executor.submit(new PlayerLoaderWorker(loader, session, request)); + executor.submit(new PlayerLoaderWorker(serializer, session, request)); } } @@ -121,7 +108,7 @@ public final class LoginService extends Service { * @param player The player to save. */ public void submitSaveRequest(GameSession session, Player player) { - executor.submit(new PlayerSaverWorker(saver, session, player)); + executor.submit(new PlayerSaverWorker(serializer, session, player)); } } \ No newline at end of file diff --git a/src/org/apollo/login/PlayerLoaderWorker.java b/src/org/apollo/login/PlayerLoaderWorker.java index 9c9bfabe..0553fe77 100644 --- a/src/org/apollo/login/PlayerLoaderWorker.java +++ b/src/org/apollo/login/PlayerLoaderWorker.java @@ -3,8 +3,8 @@ package org.apollo.login; import java.util.logging.Level; import java.util.logging.Logger; -import org.apollo.io.player.PlayerLoader; import org.apollo.io.player.PlayerLoaderResponse; +import org.apollo.io.player.PlayerSerializer; import org.apollo.net.codec.login.LoginConstants; import org.apollo.net.codec.login.LoginRequest; import org.apollo.net.session.LoginSession; @@ -22,9 +22,9 @@ public final class PlayerLoaderWorker implements Runnable { private static final Logger logger = Logger.getLogger(PlayerLoaderWorker.class.getName()); /** - * The player loader. + * The PlayerSerializer. */ - private final PlayerLoader loader; + private final PlayerSerializer loader; /** * The request. @@ -39,11 +39,11 @@ public final class PlayerLoaderWorker implements Runnable { /** * Creates a {@link PlayerLoaderWorker} which will do the work for a single player load request. * - * @param loader The current player loader. + * @param loader The {@link PlayerSerializer}. * @param session The {@link LoginSession} which initiated the request. * @param request The {@link LoginRequest} object. */ - public PlayerLoaderWorker(PlayerLoader loader, LoginSession session, LoginRequest request) { + public PlayerLoaderWorker(PlayerSerializer loader, LoginSession session, LoginRequest request) { this.loader = loader; this.session = session; this.request = request; diff --git a/src/org/apollo/login/PlayerSaverWorker.java b/src/org/apollo/login/PlayerSaverWorker.java index 2a0e369a..6ea2495c 100644 --- a/src/org/apollo/login/PlayerSaverWorker.java +++ b/src/org/apollo/login/PlayerSaverWorker.java @@ -4,7 +4,7 @@ import java.util.logging.Level; import java.util.logging.Logger; import org.apollo.game.model.entity.Player; -import org.apollo.io.player.PlayerSaver; +import org.apollo.io.player.PlayerSerializer; import org.apollo.net.session.GameSession; /** @@ -27,7 +27,7 @@ public final class PlayerSaverWorker implements Runnable { /** * The player saver. */ - private final PlayerSaver saver; + private final PlayerSerializer saver; /** * The game session. @@ -41,7 +41,7 @@ public final class PlayerSaverWorker implements Runnable { * @param session The game session. * @param player The player to save. */ - public PlayerSaverWorker(PlayerSaver saver, GameSession session, Player player) { + public PlayerSaverWorker(PlayerSerializer saver, GameSession session, Player player) { this.saver = saver; this.session = session; this.player = player; diff --git a/src/org/apollo/net/ApolloHandler.java b/src/org/apollo/net/ApolloHandler.java index ce0adfc9..3a3a8065 100644 --- a/src/org/apollo/net/ApolloHandler.java +++ b/src/org/apollo/net/ApolloHandler.java @@ -85,13 +85,13 @@ public final class ApolloHandler extends ChannelInboundHandlerAdapter { HandshakeMessage handshakeMessage = (HandshakeMessage) message; switch (handshakeMessage.getServiceId()) { - case HandshakeConstants.SERVICE_GAME: - attribute.set(new LoginSession(ctx, serverContext)); - break; + case HandshakeConstants.SERVICE_GAME: + attribute.set(new LoginSession(ctx, serverContext)); + break; - case HandshakeConstants.SERVICE_UPDATE: - attribute.set(new UpdateSession(ctx.channel(), serverContext)); - break; + case HandshakeConstants.SERVICE_UPDATE: + attribute.set(new UpdateSession(ctx.channel(), serverContext)); + break; } } diff --git a/src/org/apollo/net/codec/game/GamePacketDecoder.java b/src/org/apollo/net/codec/game/GamePacketDecoder.java index 947cd87f..6991d519 100644 --- a/src/org/apollo/net/codec/game/GamePacketDecoder.java +++ b/src/org/apollo/net/codec/game/GamePacketDecoder.java @@ -62,17 +62,17 @@ public final class GamePacketDecoder extends StatefulFrameDecoder out, GameDecoderState state) { switch (state) { - case GAME_OPCODE: - decodeOpcode(in, out); - break; - case GAME_LENGTH: - decodeLength(in); - break; - case GAME_PAYLOAD: - decodePayload(in, out); - break; - default: - throw new IllegalStateException("Invalid game decoder state."); + case GAME_OPCODE: + decodeOpcode(in, out); + break; + case GAME_LENGTH: + decodeLength(in); + break; + case GAME_PAYLOAD: + decodePayload(in, out); + break; + default: + throw new IllegalStateException("Invalid game decoder state."); } } @@ -106,20 +106,20 @@ public final class GamePacketDecoder extends StatefulFrameDecoder @Override protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out, LoginDecoderState state) { switch (state) { - case LOGIN_HANDSHAKE: - decodeHandshake(ctx, in, out); - break; - case LOGIN_HEADER: - decodeHeader(ctx, in, out); - break; - case LOGIN_PAYLOAD: - decodePayload(ctx, in, out); - break; - default: - throw new IllegalStateException("Invalid login decoder state: " + state); + case LOGIN_HANDSHAKE: + decodeHandshake(ctx, in, out); + break; + case LOGIN_HEADER: + decodeHeader(ctx, in, out); + break; + case LOGIN_PAYLOAD: + decodePayload(ctx, in, out); + break; + default: + throw new IllegalStateException("Invalid login decoder state: " + state); } } @@ -105,14 +105,14 @@ public final class LoginDecoder extends StatefulFrameDecoder */ private void decodeHeader(ChannelHandlerContext ctx, ByteBuf buffer, List out) { if (buffer.readableBytes() >= 2) { - int loginType = buffer.readUnsignedByte(); + int type = buffer.readUnsignedByte(); - if (loginType != LoginConstants.TYPE_STANDARD && loginType != LoginConstants.TYPE_RECONNECTION) { + if (type != LoginConstants.TYPE_STANDARD && type != LoginConstants.TYPE_RECONNECTION) { writeResponseCode(ctx, LoginConstants.STATUS_LOGIN_SERVER_REJECTED_SESSION); return; } - reconnecting = loginType == LoginConstants.TYPE_RECONNECTION; + reconnecting = type == LoginConstants.TYPE_RECONNECTION; loginLength = buffer.readUnsignedByte(); setState(LoginDecoderState.LOGIN_PAYLOAD); @@ -129,53 +129,51 @@ public final class LoginDecoder extends StatefulFrameDecoder private void decodePayload(ChannelHandlerContext ctx, ByteBuf buffer, List out) { if (buffer.readableBytes() >= loginLength) { ByteBuf payload = buffer.readBytes(loginLength); - int clientVersion = 255 - payload.readUnsignedByte(); + int version = 255 - payload.readUnsignedByte(); - int releaseNumber = payload.readUnsignedShort(); + int release = payload.readUnsignedShort(); - int lowMemoryFlag = payload.readUnsignedByte(); - if (lowMemoryFlag != 0 && lowMemoryFlag != 1) { + int memoryStatus = payload.readUnsignedByte(); + if (memoryStatus != 0 && memoryStatus != 1) { writeResponseCode(ctx, LoginConstants.STATUS_LOGIN_SERVER_REJECTED_SESSION); return; } - boolean lowMemory = lowMemoryFlag == 1; + boolean lowMemory = memoryStatus == 1; - int[] archiveCrcs = new int[FileSystemConstants.ARCHIVE_COUNT]; - for (int i = 0; i < 9; i++) { - archiveCrcs[i] = payload.readInt(); + int[] crcs = new int[FileSystemConstants.ARCHIVE_COUNT]; + for (int index = 0; index < 9; index++) { + crcs[index] = payload.readInt(); } - int securePayloadLength = payload.readUnsignedByte(); - if (securePayloadLength != loginLength - 41) { + int length = payload.readUnsignedByte(); + if (length != loginLength - 41) { writeResponseCode(ctx, LoginConstants.STATUS_LOGIN_SERVER_REJECTED_SESSION); return; } - ByteBuf securePayload = payload.readBytes(securePayloadLength); + ByteBuf secure = payload.readBytes(length); - BigInteger bigInteger = new BigInteger(securePayload.array()); - bigInteger = bigInteger.modPow(NetworkConstants.RSA_EXPONENT, NetworkConstants.RSA_MODULUS); + BigInteger value = new BigInteger(secure.array()); + value = value.modPow(NetworkConstants.RSA_EXPONENT, NetworkConstants.RSA_MODULUS); + secure = Unpooled.wrappedBuffer(value.toByteArray()); - securePayload = Unpooled.wrappedBuffer(bigInteger.toByteArray()); - - int secureId = securePayload.readUnsignedByte(); - if (secureId != 10) { + int id = secure.readUnsignedByte(); + if (id != 10) { writeResponseCode(ctx, LoginConstants.STATUS_LOGIN_SERVER_REJECTED_SESSION); return; } - long clientSeed = securePayload.readLong(); - long reportedServerSeed = securePayload.readLong(); - if (reportedServerSeed != serverSeed) { + long clientSeed = secure.readLong(); + long reportedSeed = secure.readLong(); + if (reportedSeed != serverSeed) { writeResponseCode(ctx, LoginConstants.STATUS_LOGIN_SERVER_REJECTED_SESSION); return; } - int uid = securePayload.readInt(); - - String username = BufferUtil.readString(securePayload); - String password = BufferUtil.readString(securePayload); + int uid = secure.readInt(); + String username = BufferUtil.readString(secure); + String password = BufferUtil.readString(secure); if (password.length() < 6 || password.length() > 20 || username.isEmpty() || username.length() > 12) { writeResponseCode(ctx, LoginConstants.STATUS_INVALID_CREDENTIALS); @@ -189,8 +187,8 @@ public final class LoginDecoder extends StatefulFrameDecoder seed[3] = (int) serverSeed; IsaacRandom decodingRandom = new IsaacRandom(seed); - for (int i = 0; i < seed.length; i++) { - seed[i] += 50; + for (int index = 0; index < seed.length; index++) { + seed[index] += 50; } IsaacRandom encodingRandom = new IsaacRandom(seed); @@ -198,9 +196,7 @@ public final class LoginDecoder extends StatefulFrameDecoder PlayerCredentials credentials = new PlayerCredentials(username, password, usernameHash, uid); IsaacRandomPair randomPair = new IsaacRandomPair(encodingRandom, decodingRandom); - LoginRequest request = new LoginRequest(credentials, randomPair, reconnecting, lowMemory, releaseNumber, archiveCrcs, clientVersion); - - out.add(request); + out.add(new LoginRequest(credentials, randomPair, reconnecting, lowMemory, release, crcs, version)); } } @@ -208,11 +204,11 @@ public final class LoginDecoder extends StatefulFrameDecoder * Writes a response code to the client and closes the current channel. * * @param ctx The context of the channel handler. - * @param responseCode The response code to write. + * @param response The response code to write. */ - private void writeResponseCode(ChannelHandlerContext ctx, int responseCode) { + private void writeResponseCode(ChannelHandlerContext ctx, int response) { ByteBuf buffer = ctx.alloc().buffer(1); - buffer.writeByte(responseCode); + buffer.writeByte(response); ctx.writeAndFlush(buffer).addListener(ChannelFutureListener.CLOSE); } diff --git a/src/org/apollo/net/codec/login/LoginRequest.java b/src/org/apollo/net/codec/login/LoginRequest.java index cac93c87..c30c620f 100644 --- a/src/org/apollo/net/codec/login/LoginRequest.java +++ b/src/org/apollo/net/codec/login/LoginRequest.java @@ -56,8 +56,7 @@ public final class LoginRequest { * @param archiveCrcs The archive CRCs. * @param clientVersion The client version. */ - public LoginRequest(PlayerCredentials credentials, IsaacRandomPair randomPair, boolean lowMemory, boolean reconnecting, - int releaseNumber, int[] archiveCrcs, int clientVersion) { + public LoginRequest(PlayerCredentials credentials, IsaacRandomPair randomPair, boolean lowMemory, boolean reconnecting, int releaseNumber, int[] archiveCrcs, int clientVersion) { this.credentials = credentials; this.randomPair = randomPair; this.lowMemory = lowMemory; diff --git a/src/org/apollo/net/codec/update/OnDemandRequest.java b/src/org/apollo/net/codec/update/OnDemandRequest.java index 52e32071..86baf132 100644 --- a/src/org/apollo/net/codec/update/OnDemandRequest.java +++ b/src/org/apollo/net/codec/update/OnDemandRequest.java @@ -41,14 +41,14 @@ public final class OnDemandRequest implements Comparable { */ public static Priority valueOf(int value) { switch (value) { - case 0: - return HIGH; - case 1: - return MEDIUM; - case 2: - return LOW; - default: - throw new IllegalArgumentException("Priority out of range - received " + value + "."); + case 0: + return HIGH; + case 1: + return MEDIUM; + case 2: + return LOW; + default: + throw new IllegalArgumentException("Priority out of range - received " + value + "."); } } diff --git a/src/org/apollo/net/package-info.java b/src/org/apollo/net/package-info.java index 26b88ffe..96ae9898 100644 --- a/src/org/apollo/net/package-info.java +++ b/src/org/apollo/net/package-info.java @@ -1,5 +1,5 @@ /** - * Contains classes related to networking. Many of these extend Netty's set of - * classes - such as the pipeline factory, handler and codecs. + * Contains classes related to networking. Many of these extend Netty's set of classes - such as the pipeline factory, + * handler and codecs. */ package org.apollo.net; \ No newline at end of file diff --git a/src/org/apollo/net/release/package-info.java b/src/org/apollo/net/release/package-info.java index 362c1d2b..2a029f38 100644 --- a/src/org/apollo/net/release/package-info.java +++ b/src/org/apollo/net/release/package-info.java @@ -1,5 +1,5 @@ /** - * Contains abstract classes which should be extended by a particular release, - * allowing for portability between various protocol and client releases. + * Contains abstract classes which should be extended by a particular release, allowing for portability between various + * protocol and client releases. */ package org.apollo.net.release; \ No newline at end of file diff --git a/src/org/apollo/net/release/r317/NpcSynchronizationMessageEncoder.java b/src/org/apollo/net/release/r317/NpcSynchronizationMessageEncoder.java index bc2472df..1bd16ca9 100644 --- a/src/org/apollo/net/release/r317/NpcSynchronizationMessageEncoder.java +++ b/src/org/apollo/net/release/r317/NpcSynchronizationMessageEncoder.java @@ -227,8 +227,7 @@ public final class NpcSynchronizationMessageEncoder extends MessageEncoder 0; if (segment.getType() == SegmentType.RUN) { Direction[] directions = ((MovementSegment) segment).getDirections(); diff --git a/src/org/apollo/net/release/r317/PlayerSynchronizationMessageEncoder.java b/src/org/apollo/net/release/r317/PlayerSynchronizationMessageEncoder.java index a1a55d14..a26e7d29 100644 --- a/src/org/apollo/net/release/r317/PlayerSynchronizationMessageEncoder.java +++ b/src/org/apollo/net/release/r317/PlayerSynchronizationMessageEncoder.java @@ -388,8 +388,7 @@ public final class PlayerSynchronizationMessageEncoder extends MessageEncoder 0; if (seg.getType() == SegmentType.TELEPORT) { Position position = ((TeleportSegment) seg).getDestination(); diff --git a/src/org/apollo/net/release/r317/ThirdObjectActionMessageDecoder.java b/src/org/apollo/net/release/r317/ThirdObjectActionMessageDecoder.java index f147104e..e1cf8263 100644 --- a/src/org/apollo/net/release/r317/ThirdObjectActionMessageDecoder.java +++ b/src/org/apollo/net/release/r317/ThirdObjectActionMessageDecoder.java @@ -18,7 +18,6 @@ public final class ThirdObjectActionMessageDecoder extends MessageDecoder { - @Override - public FirstNpcActionMessage decode(GamePacket packet) { - GamePacketReader reader = new GamePacketReader(packet); - int index = (int) reader.getSigned(DataType.SHORT, DataOrder.LITTLE); - return new FirstNpcActionMessage(index); - } + @Override + public FirstNpcActionMessage decode(GamePacket packet) { + GamePacketReader reader = new GamePacketReader(packet); + int index = (int) reader.getSigned(DataType.SHORT, DataOrder.LITTLE); + return new FirstNpcActionMessage(index); + } } \ No newline at end of file diff --git a/src/org/apollo/net/release/r377/FlaggedMouseEventMessageDecoder.java b/src/org/apollo/net/release/r377/FlaggedMouseEventMessageDecoder.java index a499c6af..61ecf663 100644 --- a/src/org/apollo/net/release/r377/FlaggedMouseEventMessageDecoder.java +++ b/src/org/apollo/net/release/r377/FlaggedMouseEventMessageDecoder.java @@ -29,7 +29,7 @@ public final class FlaggedMouseEventMessageDecoder extends MessageDecoder> 19); x = (read & 0x7f) % 765; y = (read & 0x7f) / 765; diff --git a/src/org/apollo/net/release/r377/MagicOnNpcMessageDecoder.java b/src/org/apollo/net/release/r377/MagicOnNpcMessageDecoder.java index 197a1aa8..e7b87205 100644 --- a/src/org/apollo/net/release/r377/MagicOnNpcMessageDecoder.java +++ b/src/org/apollo/net/release/r377/MagicOnNpcMessageDecoder.java @@ -15,14 +15,14 @@ import org.apollo.net.release.MessageDecoder; */ public final class MagicOnNpcMessageDecoder extends MessageDecoder { - @Override - public MagicOnNpcMessage decode(GamePacket packet) { - GamePacketReader reader = new GamePacketReader(packet); + @Override + public MagicOnNpcMessage decode(GamePacket packet) { + GamePacketReader reader = new GamePacketReader(packet); - int index = (int) reader.getUnsigned(DataType.SHORT, DataOrder.LITTLE, DataTransformation.ADD); - int spell = (int) reader.getUnsigned(DataType.SHORT, DataTransformation.ADD); + int index = (int) reader.getUnsigned(DataType.SHORT, DataOrder.LITTLE, DataTransformation.ADD); + int spell = (int) reader.getUnsigned(DataType.SHORT, DataTransformation.ADD); - return new MagicOnNpcMessage(index, spell); - } + return new MagicOnNpcMessage(index, spell); + } } \ No newline at end of file diff --git a/src/org/apollo/net/release/r377/PlayerSynchronizationMessageEncoder.java b/src/org/apollo/net/release/r377/PlayerSynchronizationMessageEncoder.java index 341a1b17..5ebfb18f 100644 --- a/src/org/apollo/net/release/r377/PlayerSynchronizationMessageEncoder.java +++ b/src/org/apollo/net/release/r377/PlayerSynchronizationMessageEncoder.java @@ -388,8 +388,7 @@ public final class PlayerSynchronizationMessageEncoder extends MessageEncoder 0; if (seg.getType() == SegmentType.TELEPORT) { Position pos = ((TeleportSegment) seg).getDestination(); diff --git a/src/org/apollo/net/release/r377/SecondNpcActionMessageDecoder.java b/src/org/apollo/net/release/r377/SecondNpcActionMessageDecoder.java index 58949385..a345064e 100644 --- a/src/org/apollo/net/release/r377/SecondNpcActionMessageDecoder.java +++ b/src/org/apollo/net/release/r377/SecondNpcActionMessageDecoder.java @@ -13,9 +13,9 @@ public final class SecondNpcActionMessageDecoder extends MessageDecoder', '<', ',', '"', '[', ']', '|', '?', '/', - '`' }; + private static final char[] NAME_CHARS = { '_', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', + 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '-', '+', '=', ':', ';', '.', '>', '<', ',', + '"', '[', ']', '|', '?', '/', '`' }; /** * Converts a long to a player name. diff --git a/src/org/apollo/util/StatefulFrameDecoder.java b/src/org/apollo/util/StatefulFrameDecoder.java index 18234ec2..2e3df6d4 100644 --- a/src/org/apollo/util/StatefulFrameDecoder.java +++ b/src/org/apollo/util/StatefulFrameDecoder.java @@ -38,6 +38,16 @@ public abstract class StatefulFrameDecoder> extends ByteToMess setState(state); } + /** + * Sets a new state. + * + * @param state The new state. + * @throws NullPointerException If the state is {@code null}. + */ + public final void setState(T state) { + this.state = Objects.requireNonNull(state, "State cannot be null."); + } + @Override protected final void decode(ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception { decode(ctx, in, out, state); @@ -54,14 +64,4 @@ public abstract class StatefulFrameDecoder> extends ByteToMess */ protected abstract void decode(ChannelHandlerContext ctx, ByteBuf in, List out, T state) throws Exception; - /** - * Sets a new state. - * - * @param state The new state. - * @throws NullPointerException If the state is {@code null}. - */ - public final void setState(T state) { - this.state = Objects.requireNonNull(state, "State cannot be null."); - } - } \ No newline at end of file diff --git a/src/org/apollo/util/TextUtil.java b/src/org/apollo/util/TextUtil.java index d401f5a1..fe76006a 100644 --- a/src/org/apollo/util/TextUtil.java +++ b/src/org/apollo/util/TextUtil.java @@ -11,10 +11,10 @@ public final class TextUtil { * An array of characters ordered by frequency - the elements with lower indices (generally) appear more often in * chat messages. */ - public static final char[] FREQUENCY_ORDERED_CHARS = { ' ', 'e', 't', 'a', 'o', 'i', 'h', 'n', 's', 'r', 'd', 'l', 'u', 'm', - 'w', 'c', 'y', 'f', 'g', 'p', 'b', 'v', 'k', 'x', 'j', 'q', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', - ' ', '!', '?', '.', ',', ':', ';', '(', ')', '-', '&', '*', '\\', '\'', '@', '#', '+', '=', '\243', '$', '%', '"', - '[', ']' }; + public static final char[] FREQUENCY_ORDERED_CHARS = { ' ', 'e', 't', 'a', 'o', 'i', 'h', 'n', 's', 'r', 'd', 'l', + 'u', 'm', 'w', 'c', 'y', 'f', 'g', 'p', 'b', 'v', 'k', 'x', 'j', 'q', 'z', '0', '1', '2', '3', '4', '5', + '6', '7', '8', '9', ' ', '!', '?', '.', ',', ':', ';', '(', ')', '-', '&', '*', '\\', '\'', '@', '#', '+', + '=', '\243', '$', '%', '"', '[', ']' }; /** * Capitalizes the string correctly. diff --git a/src/org/apollo/util/plugin/PluginManager.java b/src/org/apollo/util/plugin/PluginManager.java index f4d58d52..f11cb906 100644 --- a/src/org/apollo/util/plugin/PluginManager.java +++ b/src/org/apollo/util/plugin/PluginManager.java @@ -156,8 +156,7 @@ public final class PluginManager { * @throws DependencyException If a dependency error occurs. * @throws IOException If an I/O error occurs. */ - private void start(PluginEnvironment env, PluginMetaData plugin, Map plugins, - Set started) throws DependencyException, IOException { + private void start(PluginEnvironment env, PluginMetaData plugin, Map plugins, Set started) throws DependencyException, IOException { // TODO check for cyclic dependencies! this way just won't cut it, we need an exception if (started.contains(plugin)) { return; diff --git a/src/org/apollo/util/plugin/PluginMetaData.java b/src/org/apollo/util/plugin/PluginMetaData.java index d5fbeb3d..24f9899f 100644 --- a/src/org/apollo/util/plugin/PluginMetaData.java +++ b/src/org/apollo/util/plugin/PluginMetaData.java @@ -61,8 +61,7 @@ public final class PluginMetaData { * @param dependencies The plugin's dependencies. * @param version The plugin's version. */ - public PluginMetaData(String id, File base, String name, String description, String[] authors, String[] scripts, - String[] dependencies, double version) { + public PluginMetaData(String id, File base, String name, String description, String[] authors, String[] scripts, String[] dependencies, double version) { this.id = id; this.base = base; this.name = name;