mirror of
https://github.com/2006-Scape/apollo.git
synced 2026-07-05 16:49:04 +00:00
Merge pull request #217 from Major-/tutorial_island
Fix many issues with the Tutorial island plugin
This commit is contained in:
+46
-10
@@ -18,6 +18,9 @@ java_import 'org.apollo.game.model.World'
|
|||||||
java_import 'org.apollo.game.model.entity.Player'
|
java_import 'org.apollo.game.model.entity.Player'
|
||||||
java_import 'org.apollo.game.model.event.EventListener'
|
java_import 'org.apollo.game.model.event.EventListener'
|
||||||
java_import 'org.apollo.game.model.event.PlayerEvent'
|
java_import 'org.apollo.game.model.event.PlayerEvent'
|
||||||
|
java_import 'org.apollo.game.model.event.impl.LoginEvent'
|
||||||
|
java_import 'org.apollo.game.model.event.ProxyEvent'
|
||||||
|
java_import 'org.apollo.game.model.event.ProxyEventListener'
|
||||||
java_import 'org.apollo.game.model.entity.setting.PrivilegeLevel'
|
java_import 'org.apollo.game.model.entity.setting.PrivilegeLevel'
|
||||||
java_import 'org.apollo.game.scheduling.ScheduledTask'
|
java_import 'org.apollo.game.scheduling.ScheduledTask'
|
||||||
java_import 'org.apollo.game.plugin.PluginContext'
|
java_import 'org.apollo.game.plugin.PluginContext'
|
||||||
@@ -129,23 +132,26 @@ def schedule(*args, &block)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Defines some sort of action to take upon an message. The following types of
|
@@proxy_listener = ProxyEventListener.new
|
||||||
# message are currently valid:
|
$world.listen_for(ProxyEvent.java_class, @@proxy_listener)
|
||||||
|
|
||||||
|
# Defines some sort of action to take upon an message. The following types of message are currently
|
||||||
|
# valid:
|
||||||
#
|
#
|
||||||
# * :command
|
# * :command
|
||||||
# * :message
|
# * :message
|
||||||
# * :button
|
# * :button
|
||||||
# * Any valid Event, as a symbol in ruby snake_case form.
|
# * Any valid Event, as a symbol in ruby snake_case form.
|
||||||
#
|
#
|
||||||
# A command takes one or two arguments (the command name and optionally the
|
# A command takes one or two arguments (the command name and optionally the minimum rights level to
|
||||||
# minimum rights level to use it). The minimum rights level defaults to
|
# use it). The minimum rights level defaults to STANDARD. The block should have two arguments:
|
||||||
# STANDARD. The block should have two arguments: player and command.
|
# player and command.
|
||||||
#
|
#
|
||||||
# An message takes no arguments. The block should have three arguments: the chain
|
# An message takes no arguments. The block should have two arguments: the player and the message
|
||||||
# context, the player and the message object.
|
# object.
|
||||||
#
|
#
|
||||||
# A button takes one argument (the id). The block should have one argument: the
|
# A button takes one argument (the id). The block should have one argument: the player who clicked
|
||||||
# player who clicked the button.
|
# the button.
|
||||||
def on(type, *args, &block)
|
def on(type, *args, &block)
|
||||||
case type
|
case type
|
||||||
when :command then on_command(args, block)
|
when :command then on_command(args, block)
|
||||||
@@ -153,11 +159,41 @@ def on(type, *args, &block)
|
|||||||
when :button then on_button(args, block)
|
when :button then on_button(args, block)
|
||||||
else
|
else
|
||||||
class_name = type.to_s.camelize.concat('Event')
|
class_name = type.to_s.camelize.concat('Event')
|
||||||
type = Java::JavaClass.for_name("org.apollo.game.model.event.impl.#{class_name}")
|
|
||||||
|
begin
|
||||||
|
type = Java::JavaClass.for_name("org.apollo.game.model.event.impl.#{class_name}")
|
||||||
|
rescue
|
||||||
|
@@proxy_listener.add(class_name, ProcEventListener.new(block))
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
$world.listen_for(type, ProcEventListener.new(block))
|
$world.listen_for(type, ProcEventListener.new(block))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Contains extension methods for World.
|
||||||
|
module WorldExtensions
|
||||||
|
|
||||||
|
# Overrides World#submit, providing special-case behaviour for Events defined in Ruby, which
|
||||||
|
# need to be wrapped in a ProxyEvent, until https://github.com/jruby/jruby/issues/2359 is
|
||||||
|
# resolved.
|
||||||
|
def submit(event)
|
||||||
|
if event.java_class.name.end_with?(".Event", ".PlayerEvent")
|
||||||
|
event = ProxyEvent.new(event.class.name, event)
|
||||||
|
end
|
||||||
|
|
||||||
|
super(event)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
# Prepend the methods defined in WorldExtensions to World.
|
||||||
|
class World
|
||||||
|
prepend WorldExtensions
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
# Defines an action to be taken upon a button press.
|
# Defines an action to be taken upon a button press.
|
||||||
def on_button(args, proc)
|
def on_button(args, proc)
|
||||||
fail 'Button must have one argument.' unless args.length == 1
|
fail 'Button must have one argument.' unless args.length == 1
|
||||||
|
|||||||
@@ -254,7 +254,7 @@ class Dialogue
|
|||||||
def options
|
def options
|
||||||
@options.dup
|
@options.dup
|
||||||
end
|
end
|
||||||
|
|
||||||
# Sets the precondition of this dialogue.
|
# Sets the precondition of this dialogue.
|
||||||
def precondition(player=nil, &block)
|
def precondition(player=nil, &block)
|
||||||
@precondition = block unless block.nil?
|
@precondition = block unless block.nil?
|
||||||
@@ -413,8 +413,11 @@ end
|
|||||||
|
|
||||||
# Sends a dialogue displaying only text.
|
# Sends a dialogue displaying only text.
|
||||||
def send_text_dialogue(player, dialogue)
|
def send_text_dialogue(player, dialogue)
|
||||||
title = dialogue.title
|
text = dialogue.text
|
||||||
send_generic_dialogue(player, dialogue, title, TEXT_DIALOGUE_IDS)
|
dialogue_id = TEXT_DIALOGUE_IDS[text.size - 1]
|
||||||
|
|
||||||
|
text.each_with_index { |line, index| set_text(player, dialogue_id + 1 + index, line) }
|
||||||
|
player.interface_set.open_dialogue(ContinueDialogueAdapter.new(player, dialogue.options[0]), dialogue_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Sends a dialogue displaying the player's head.
|
# Sends a dialogue displaying the player's head.
|
||||||
@@ -555,4 +558,4 @@ GLYPH_SPACING = [ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
|||||||
# Gets the width of a single character.
|
# Gets the width of a single character.
|
||||||
def get_width(char)
|
def get_width(char)
|
||||||
return GLYPH_SPACING[char.ord]
|
return GLYPH_SPACING[char.ord]
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -9,27 +9,48 @@ java_import 'org.apollo.game.model.Position'
|
|||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
# The ids of tabs that are displayed when the player has yet to start the tutorial.
|
# Contains constants used during the Runescape Guide part of Tutorial Island.
|
||||||
INITIAL_TABS = [-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 2449, 904, -1, -1]
|
module GuideConstants
|
||||||
|
|
||||||
# The character design interface id.
|
# The Runescape Guide Npc.
|
||||||
CHARACTER_DESIGN = 3559
|
RUNESCAPE_GUIDE = spawn_npc name: :runescape_guide, x: 3093, y: 3107
|
||||||
|
|
||||||
# The Runescape guide Npc
|
# The character design interface id.
|
||||||
@runescape_guide = spawn_npc name: :runescape_guide, x: 3093, y: 3107
|
CHARACTER_DESIGN_INTERFACE = 3559
|
||||||
|
|
||||||
|
# The id of the door of the house new players spawn in.
|
||||||
|
DOOR_ID = 3014
|
||||||
|
|
||||||
|
# The Position of the door of the house new players spawn in.
|
||||||
|
DOOR_POSITION = Position.new(3098, 3107)
|
||||||
|
|
||||||
|
# The HintIconMessage sent to display a hint arrow above the door of the house new players spawn
|
||||||
|
# in.
|
||||||
|
DOOR_HINT = PositionHintIconMessage.new(HintIconMessage::Type::WEST, DOOR_POSITION, 120)
|
||||||
|
|
||||||
|
# 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].freeze
|
||||||
|
|
||||||
|
# The HintIconMessage sent to remove a hint arrow from above the door.
|
||||||
|
RESET_DOOR_HINT = PositionHintIconMessage.reset
|
||||||
|
|
||||||
|
# The HintIconMessage sent to remove a hint arrow from an Npc.
|
||||||
|
RESET_NPC_HINT = MobHintIconMessage.reset(EntityType::NPC)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
# Sends the appropriate data to the client when the player logs in to the game.
|
# Sends the appropriate data to the client when the player logs in to the game.
|
||||||
on :login do |_event, player|
|
on :login do |_event, player|
|
||||||
if player.in_tutorial_island && player.privilege_level != RIGHTS_ADMIN
|
if player.in_tutorial_island && player.privilege_level != RIGHTS_ADMIN
|
||||||
TutorialInstructions.show_instruction(player)
|
TutorialInstructions.show_instruction(player)
|
||||||
|
|
||||||
INITIAL_TABS.each_with_index do |tab, index|
|
GuideConstants::INITIAL_TABS.each_with_index do |tab, index|
|
||||||
player.send(SwitchTabInterfaceMessage.new(index, tab))
|
player.send(SwitchTabInterfaceMessage.new(index, tab))
|
||||||
end
|
end
|
||||||
|
|
||||||
if player.tutorial_island_progress == :not_started
|
if player.tutorial_island_progress == :not_started
|
||||||
show_hint_icon(player)
|
player.interface_set.open_window(GuideConstants::CHARACTER_DESIGN_INTERFACE)
|
||||||
player.interface_set.open_window(CHARACTER_DESIGN)
|
player.send(MobHintIconMessage.create(GuideConstants::RUNESCAPE_GUIDE))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -95,23 +116,43 @@ conversation :tutorial_runescape_guide do
|
|||||||
|
|
||||||
close do |player|
|
close do |player|
|
||||||
if player.tutorial_island_progress < :runescape_guide_finished
|
if player.tutorial_island_progress < :runescape_guide_finished
|
||||||
reset_hint_icon(player)
|
player.send(GuideConstants::RESET_NPC_HINT)
|
||||||
# TODO: Maybe move this, define a constant for the Position and height
|
|
||||||
player.send(PositionHintIconMessage.new(HintIconMessage::Type::SOUTH, Position.new(3097, 3107), 120))
|
player.send(GuideConstants::DOOR_HINT)
|
||||||
player.tutorial_island_progress = :runescape_guide_finished
|
player.tutorial_island_progress = :runescape_guide_finished
|
||||||
end
|
end
|
||||||
|
|
||||||
TutorialInstructions.show_instruction(player)
|
TutorialInstructions.show_instruction(player)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# The dialogue displayed if the player attempts to leave the Runescape Guide's house before they
|
||||||
|
# have spoken to him.
|
||||||
|
dialogue :talk_to_guide do
|
||||||
|
type :text
|
||||||
|
|
||||||
|
text 'You need to talk to the Runescape Guide before you are allowed to proceed through this '\
|
||||||
|
'door.'
|
||||||
|
|
||||||
|
close do |player|
|
||||||
|
TutorialInstructions.show_instruction(player)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Enables the hint icon above the Runescape guide.
|
on :open_door do |event, player|
|
||||||
def show_hint_icon(player)
|
door = event.door
|
||||||
player.send(MobHintIconMessage.create(@runescape_guide))
|
|
||||||
|
if player.in_tutorial_island && door.position.equals(GuideConstants::DOOR_POSITION)
|
||||||
|
if player.tutorial_island_progress < :runescape_guide_finished
|
||||||
|
send_dialogue(player, get_dialogue(:tutorial_runescape_guide, :talk_to_guide))
|
||||||
|
event.terminate
|
||||||
|
elsif player.tutorial_island_progress == :runescape_guide_finished
|
||||||
|
player.tutorial_island_progress = :moving_around
|
||||||
|
player.send(GuideConstants::RESET_DOOR_HINT)
|
||||||
|
TutorialInstructions.show_instruction(player)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Resets the hint icon.
|
|
||||||
def reset_hint_icon(player)
|
|
||||||
player.send(MobHintIconMessage.reset(EntityType::NPC))
|
|
||||||
end
|
|
||||||
|
|||||||
@@ -18,7 +18,8 @@ module TutorialInstructions
|
|||||||
when :given_axe then :viewing_items
|
when :given_axe then :viewing_items
|
||||||
when :cut_tree then :cut_tree
|
when :cut_tree then :cut_tree
|
||||||
when :cutting_tree then :please_wait
|
when :cutting_tree then :please_wait
|
||||||
else fail 'No dialogue for current stage #{progress} exists.'
|
|
||||||
|
else raise "No dialogue for current stage #{progress} exists."
|
||||||
end
|
end
|
||||||
|
|
||||||
dialogue = instructions.part(name)
|
dialogue = instructions.part(name)
|
||||||
|
|||||||
@@ -17,7 +17,8 @@
|
|||||||
</scripts>
|
</scripts>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>dialogue</dependency>
|
<dependency>dialogue</dependency>
|
||||||
|
<dependency>door</dependency>
|
||||||
<dependency>entity-spawning</dependency>
|
<dependency>entity-spawning</dependency>
|
||||||
<dependency>quest</dependency>
|
<dependency>quest</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</plugin>
|
</plugin>
|
||||||
|
|||||||
@@ -2,15 +2,15 @@
|
|||||||
private
|
private
|
||||||
|
|
||||||
# The array of stages in tutorial island.
|
# The array of stages in tutorial island.
|
||||||
STAGES = []
|
@stages = []
|
||||||
|
|
||||||
# The stages that are used when interacting with the Runescape Guide.
|
# The stages that are used when interacting with the Runescape Guide.
|
||||||
RUNESCAPE_GUIDE = [:not_started, :talk_to_people, :go_through_door, :runescape_guide_finished,
|
RUNESCAPE_GUIDE = [:not_started, :talk_to_people, :go_through_door, :runescape_guide_finished,
|
||||||
:moving_around]
|
:moving_around].freeze
|
||||||
STAGES.concat(RUNESCAPE_GUIDE)
|
@stages.concat(RUNESCAPE_GUIDE)
|
||||||
|
|
||||||
# The stages that are used when interacting with the Survival Expert.
|
# The stages that are used when interacting with the Survival Expert.
|
||||||
SURVIVAL_EXPERT = [:given_axe, :cut_tree, :cutting_tree]
|
SURVIVAL_EXPERT = [:given_axe, :cut_tree, :cutting_tree].freeze
|
||||||
STAGES.concat(SURVIVAL_EXPERT)
|
@stages.concat(SURVIVAL_EXPERT)
|
||||||
|
|
||||||
quest :tutorial_island, STAGES
|
quest :tutorial_island, @stages
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ conversation :tutorial_surivival_expert do
|
|||||||
' tricks. First off we\'re going to start with the most basic survival skill of all: '\
|
' tricks. First off we\'re going to start with the most basic survival skill of all: '\
|
||||||
'making a fire.'
|
'making a fire.'
|
||||||
|
|
||||||
close(&:add_survival_items)
|
close { |player| add_survival_items(player) }
|
||||||
end
|
end
|
||||||
|
|
||||||
dialogue :hello_again do
|
dialogue :hello_again do
|
||||||
@@ -54,7 +54,7 @@ conversation :tutorial_surivival_expert do
|
|||||||
text 'Hello again. I\'m here to teach you a few survival tips and tricks. First off we\'re '\
|
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.'
|
'going to start with the most basic survival skill of all: making a fire.'
|
||||||
|
|
||||||
close(&:add_survival_items)
|
close { |player| add_survival_items(player) }
|
||||||
end
|
end
|
||||||
|
|
||||||
# The dialogue displayed when the Survival Expert gives the player a bronze axe.
|
# The dialogue displayed when the Survival Expert gives the player a bronze axe.
|
||||||
@@ -123,7 +123,7 @@ def add_survival_items(player)
|
|||||||
|
|
||||||
unless inventory.contains(SurvivalConstants::TINDERBOX)
|
unless inventory.contains(SurvivalConstants::TINDERBOX)
|
||||||
inventory.add(SurvivalConstants::TINDERBOX)
|
inventory.add(SurvivalConstants::TINDERBOX)
|
||||||
dialogue = (dialogue == :give_bronze_axe) ? :give_axe_and_tinderbox : give_tinderbox
|
dialogue = (dialogue == :give_bronze_axe) ? :give_axe_and_tinderbox : :give_tinderbox
|
||||||
end
|
end
|
||||||
|
|
||||||
send_dialogue(player, get_dialogue(:tutorial_surivival_expert, dialogue))
|
send_dialogue(player, get_dialogue(:tutorial_surivival_expert, dialogue))
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
|
|
||||||
java_import 'org.apollo.game.action.DistancedAction'
|
java_import 'org.apollo.game.action.DistancedAction'
|
||||||
|
java_import 'org.apollo.game.model.event.Event'
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
# A distanced action which opens a door.
|
# A distanced action which opens a door.
|
||||||
class OpenDoorAction < DistancedAction
|
class OpenDoorAction < DistancedAction
|
||||||
@@ -13,8 +16,11 @@ class OpenDoorAction < DistancedAction
|
|||||||
end
|
end
|
||||||
|
|
||||||
def executeAction
|
def executeAction
|
||||||
mob.turn_to(@door.position)
|
if $world.submit(OpenDoorEvent.new(mob, @door))
|
||||||
DoorUtil.toggle(@door)
|
mob.turn_to(@door.position)
|
||||||
|
DoorUtil.toggle(@door)
|
||||||
|
end
|
||||||
|
|
||||||
stop
|
stop
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -24,10 +30,25 @@ class OpenDoorAction < DistancedAction
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# MessageListener for opening and closing doors.
|
# A PlayerEvent that is fired when a player attempts to open a door.
|
||||||
|
class OpenDoorEvent < PlayerEvent
|
||||||
|
attr_reader :door
|
||||||
|
|
||||||
|
def initialize(player, door)
|
||||||
|
super(player)
|
||||||
|
@door = door
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
# Listens for FirstObjectActions performed on doors.
|
||||||
on :message, :first_object_action do |player, message|
|
on :message, :first_object_action do |player, message|
|
||||||
if DoorUtil.door?(message.id)
|
id = message.id
|
||||||
door = DoorUtil.get_door_object(message.position, message.id)
|
|
||||||
|
if DoorUtil.door?(id)
|
||||||
|
door = DoorUtil.get_door_object(message.position, id)
|
||||||
player.start_action(OpenDoorAction.new(player, door)) unless door.nil?
|
player.start_action(OpenDoorAction.new(player, door)) unless door.nil?
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -25,24 +25,24 @@ public abstract class HintIconMessage extends Message {
|
|||||||
CENTER(2),
|
CENTER(2),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A HintIcon that hovers north over a Position.
|
* A HintIcon that hovers west over a Position.
|
||||||
*/
|
*/
|
||||||
NORTH(3),
|
WEST(3),
|
||||||
|
|
||||||
/**
|
|
||||||
* A HintIcon that hovers south over a Position.
|
|
||||||
*/
|
|
||||||
SOUTH(4),
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A HintIcon that hovers east over a Position.
|
* A HintIcon that hovers east over a Position.
|
||||||
*/
|
*/
|
||||||
EAST(5),
|
EAST(4),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A HintIcon that hovers west over a Position.
|
* A HintIcon that hovers south over a Position.
|
||||||
*/
|
*/
|
||||||
WEST(6),
|
SOUTH(5),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A HintIcon that hovers north over a Position.
|
||||||
|
*/
|
||||||
|
NORTH(6),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A HintIcon that hovers over a Player.
|
* A HintIcon that hovers over a Player.
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
package org.apollo.game.message.impl;
|
package org.apollo.game.message.impl;
|
||||||
|
|
||||||
import org.apollo.game.model.Position;
|
|
||||||
|
|
||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
|
import org.apollo.game.model.Position;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A {@link HintIconMessage} which displays a hint over a Position.
|
* A {@link HintIconMessage} which displays a hint over a Position.
|
||||||
@@ -16,20 +15,20 @@ public final class PositionHintIconMessage extends HintIconMessage {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests if the specified Type if valid for a Position HintIcon.
|
* Tests if the specified Type if valid for a Position HintIcon.
|
||||||
*
|
*
|
||||||
* @param type The Type to test.
|
* @param type The Type to test.
|
||||||
* @return The Type if it was valid.
|
* @return The Type if it was valid.
|
||||||
*/
|
*/
|
||||||
private static Type testType(Type type) {
|
private static Type testType(Type type) {
|
||||||
Preconditions.checkArgument(type != Type.NPC && type != Type.PLAYER,
|
Preconditions.checkArgument(type != Type.NPC && type != Type.PLAYER,
|
||||||
"Hint icons over a Position may not have a type of Player or Npc.");
|
"Hint icons over a Position may not have a type of Player or Npc.");
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new {@link PositionHintIconMessage} which resets the current
|
* Creates a new {@link PositionHintIconMessage} which resets the current
|
||||||
* HintIcon.
|
* HintIcon.
|
||||||
*
|
*
|
||||||
* @return The new {@link PositionHintIconMessage}, never {@code null}.
|
* @return The new {@link PositionHintIconMessage}, never {@code null}.
|
||||||
*/
|
*/
|
||||||
public static PositionHintIconMessage reset() {
|
public static PositionHintIconMessage reset() {
|
||||||
@@ -48,7 +47,7 @@ public final class PositionHintIconMessage extends HintIconMessage {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a new {@link PositionHintIconMessage}.
|
* Constructs a new {@link PositionHintIconMessage}.
|
||||||
*
|
*
|
||||||
* @param type The Type of the HintIcon.
|
* @param type The Type of the HintIcon.
|
||||||
* @param position The Position of the hint icon.
|
* @param position The Position of the hint icon.
|
||||||
* @param height The display height of the hint icon.
|
* @param height The display height of the hint icon.
|
||||||
@@ -61,7 +60,7 @@ public final class PositionHintIconMessage extends HintIconMessage {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the Position of the HintIcon.
|
* Gets the Position of the HintIcon.
|
||||||
*
|
*
|
||||||
* @return The Position of the HintIcon.
|
* @return The Position of the HintIcon.
|
||||||
*/
|
*/
|
||||||
public Position getPosition() {
|
public Position getPosition() {
|
||||||
@@ -70,7 +69,7 @@ public final class PositionHintIconMessage extends HintIconMessage {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the display height of the HintIcon.
|
* Gets the display height of the HintIcon.
|
||||||
*
|
*
|
||||||
* @return The display height of the HintIcon.
|
* @return The display height of the HintIcon.
|
||||||
*/
|
*/
|
||||||
public int getHeight() {
|
public int getHeight() {
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import java.util.Map;
|
|||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import com.google.common.base.Preconditions;
|
||||||
import org.apollo.Service;
|
import org.apollo.Service;
|
||||||
import org.apollo.cache.IndexedFileSystem;
|
import org.apollo.cache.IndexedFileSystem;
|
||||||
import org.apollo.cache.decoder.ItemDefinitionDecoder;
|
import org.apollo.cache.decoder.ItemDefinitionDecoder;
|
||||||
@@ -31,8 +32,6 @@ import org.apollo.game.scheduling.Scheduler;
|
|||||||
import org.apollo.game.scheduling.impl.NpcMovementTask;
|
import org.apollo.game.scheduling.impl.NpcMovementTask;
|
||||||
import org.apollo.util.NameUtil;
|
import org.apollo.util.NameUtil;
|
||||||
|
|
||||||
import com.google.common.base.Preconditions;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The world class is a singleton which contains objects like the {@link MobRepository} for players and NPCs. It should
|
* The world class is a singleton which contains objects like the {@link MobRepository} for players and NPCs. It should
|
||||||
* only contain things relevant to the in-game world and not classes which deal with I/O and such (these may be better
|
* only contain things relevant to the in-game world and not classes which deal with I/O and such (these may be better
|
||||||
@@ -86,6 +85,11 @@ public final class World {
|
|||||||
*/
|
*/
|
||||||
private final MobRepository<Npc> npcRepository = new MobRepository<>(WorldConstants.MAXIMUM_NPCS);
|
private final MobRepository<Npc> npcRepository = new MobRepository<>(WorldConstants.MAXIMUM_NPCS);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Queue of Npcs that have yet to be removed from the repository.
|
||||||
|
*/
|
||||||
|
private final Queue<Npc> oldNpcs = new ArrayDeque<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The {@link MobRepository} of {@link Player}s.
|
* The {@link MobRepository} of {@link Player}s.
|
||||||
*/
|
*/
|
||||||
@@ -100,11 +104,6 @@ public final class World {
|
|||||||
* The Queue of Npcs that have yet to be added to the repository.
|
* The Queue of Npcs that have yet to be added to the repository.
|
||||||
*/
|
*/
|
||||||
private final Queue<Npc> queuedNpcs = new ArrayDeque<>();
|
private final Queue<Npc> queuedNpcs = new ArrayDeque<>();
|
||||||
|
|
||||||
/**
|
|
||||||
* The Queue of Npcs that have yet to be removed from the repository.
|
|
||||||
*/
|
|
||||||
private final Queue<Npc> oldNpcs = new ArrayDeque<>();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This world's {@link RegionRepository}.
|
* This world's {@link RegionRepository}.
|
||||||
@@ -209,8 +208,8 @@ public final class World {
|
|||||||
releaseNumber = release;
|
releaseNumber = release;
|
||||||
|
|
||||||
SynchronousDecoder decoder = new SynchronousDecoder(new ItemDefinitionDecoder(fs),
|
SynchronousDecoder decoder = new SynchronousDecoder(new ItemDefinitionDecoder(fs),
|
||||||
new NpcDefinitionDecoder(fs), new GameObjectDecoder(fs, this),
|
new NpcDefinitionDecoder(fs), new GameObjectDecoder(fs, this),
|
||||||
EquipmentDefinitionParser.fromFile("data/equipment-" + release + "" + ".dat"));
|
EquipmentDefinitionParser.fromFile("data/equipment-" + release + "" + ".dat"));
|
||||||
|
|
||||||
decoder.block();
|
decoder.block();
|
||||||
|
|
||||||
@@ -315,8 +314,7 @@ public final class World {
|
|||||||
* @param npc The npc.
|
* @param npc The npc.
|
||||||
*/
|
*/
|
||||||
public void unregister(final Npc npc) {
|
public void unregister(final Npc npc) {
|
||||||
Preconditions.checkNotNull(npc, "Npc may not be null.");
|
Preconditions.checkNotNull(npc, "Npc must not be null.");
|
||||||
|
|
||||||
oldNpcs.add(npc);
|
oldNpcs.add(npc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -362,7 +360,7 @@ public final class World {
|
|||||||
npcMovement.addNpc(npc);
|
npcMovement.addNpc(npc);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
logger.warning("Failed to register npc, repository capacity reached: [count=" + npcRepository.size() + "]");
|
logger.warning("Failed to register npc (capacity reached): [count=" + npcRepository.size() + "]");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -373,7 +371,7 @@ public final class World {
|
|||||||
private void unregisterNpcs() {
|
private void unregisterNpcs() {
|
||||||
while (!oldNpcs.isEmpty()) {
|
while (!oldNpcs.isEmpty()) {
|
||||||
Npc npc = oldNpcs.poll();
|
Npc npc = oldNpcs.poll();
|
||||||
|
|
||||||
Region region = regions.fromPosition(npc.getPosition());
|
Region region = regions.fromPosition(npc.getPosition());
|
||||||
region.removeEntity(npc);
|
region.removeEntity(npc);
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,52 @@
|
|||||||
|
package org.apollo.game.model.event;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An {@link Event} that wraps another {@link Event}.
|
||||||
|
*
|
||||||
|
* This is a workaround for JRuby issue <a href="https://github.com/jruby/jruby/issues/2359">2359</a>. This class
|
||||||
|
* should <strong>not</strong> be used in Java.
|
||||||
|
*
|
||||||
|
* @author Major
|
||||||
|
*/
|
||||||
|
public final class ProxyEvent extends Event {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Event created by a Ruby plugin.
|
||||||
|
*/
|
||||||
|
private final Event event;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the Ruby Event.
|
||||||
|
*/
|
||||||
|
private final String name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the ProxyEvent.
|
||||||
|
*
|
||||||
|
* @param name The name of the {@link Event} defined in Ruby.
|
||||||
|
* @param event The Event created by a Ruby plugin.
|
||||||
|
*/
|
||||||
|
public ProxyEvent(String name, Event event) {
|
||||||
|
this.name = name;
|
||||||
|
this.event = event;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the name of the {@link Event} defined in Ruby.
|
||||||
|
*
|
||||||
|
* @return The name.
|
||||||
|
*/
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the {@link Event} created in a Ruby plugin.
|
||||||
|
*
|
||||||
|
* @return The Ruby {@link Event}.
|
||||||
|
*/
|
||||||
|
public Event getRuby() {
|
||||||
|
return event;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
package org.apollo.game.model.event;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An {@link EventListener} for {@link ProxyEvent}s.
|
||||||
|
*
|
||||||
|
* This is a workaround for JRuby issue <a href="https://github.com/jruby/jruby/issues/2359">2359</a>.
|
||||||
|
*
|
||||||
|
* @author Major
|
||||||
|
*/
|
||||||
|
public final class ProxyEventListener implements EventListener<ProxyEvent> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link Map} from Event names to {@link List}s of {@link EventListener}s.
|
||||||
|
*/
|
||||||
|
private final Map<String, List<EventListener<Event>>> listeners = new HashMap<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers an {@link EventListener} to this proxy. This method is <strong>not</strong> type-safe, and must only
|
||||||
|
* be called from ruby.
|
||||||
|
*
|
||||||
|
* @param name The name of the Event. Must not be {@code null}.
|
||||||
|
* @param listener The {@link EventListener} to add. Must not be {@code null}.
|
||||||
|
*/
|
||||||
|
public void add(String name, EventListener<Event> listener) {
|
||||||
|
List<EventListener<Event>> listeners = this.listeners.computeIfAbsent(name, n -> new ArrayList<>(2));
|
||||||
|
listeners.add(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public void handle(ProxyEvent event) {
|
||||||
|
List<EventListener<Event>> chain = listeners.get(event.getName());
|
||||||
|
|
||||||
|
if (chain != null) {
|
||||||
|
for (EventListener<Event> listener : chain) {
|
||||||
|
Event ruby = event.getRuby();
|
||||||
|
listener.handle(ruby);
|
||||||
|
|
||||||
|
if (ruby.terminated()) {
|
||||||
|
event.terminate();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -20,11 +20,6 @@ public final class RubyPluginEnvironment implements PluginEnvironment {
|
|||||||
*/
|
*/
|
||||||
private final ScriptingContainer container = new ScriptingContainer();
|
private final ScriptingContainer container = new ScriptingContainer();
|
||||||
|
|
||||||
/**
|
|
||||||
* The World this RubyPluginEnvironment is for.
|
|
||||||
*/
|
|
||||||
private final World world;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates and bootstraps the Ruby plugin environment.
|
* Creates and bootstraps the Ruby plugin environment.
|
||||||
*
|
*
|
||||||
@@ -32,7 +27,7 @@ public final class RubyPluginEnvironment implements PluginEnvironment {
|
|||||||
* @throws IOException If an I/O error occurs during bootstrapping.
|
* @throws IOException If an I/O error occurs during bootstrapping.
|
||||||
*/
|
*/
|
||||||
public RubyPluginEnvironment(World world) throws IOException {
|
public RubyPluginEnvironment(World world) throws IOException {
|
||||||
this.world = world;
|
container.put("$world", world);
|
||||||
parseBootstrapper();
|
parseBootstrapper();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,7 +37,7 @@ public final class RubyPluginEnvironment implements PluginEnvironment {
|
|||||||
container.runScriptlet(is, name);
|
container.runScriptlet(is, name);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
throw new RuntimeException("Error parsing scriptlet " + name + ".");
|
throw new RuntimeException("Error parsing scriptlet " + name + ".", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,7 +56,6 @@ public final class RubyPluginEnvironment implements PluginEnvironment {
|
|||||||
@Override
|
@Override
|
||||||
public void setContext(PluginContext context) {
|
public void setContext(PluginContext context) {
|
||||||
container.put("$ctx", context);
|
container.put("$ctx", context);
|
||||||
container.put("$world", world);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -15,7 +15,7 @@ public final class FlashTabInterfaceMessageEncoder extends MessageEncoder<FlashT
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public GamePacket encode(FlashTabInterfaceMessage message) {
|
public GamePacket encode(FlashTabInterfaceMessage message) {
|
||||||
GamePacketBuilder builder = new GamePacketBuilder(283);
|
GamePacketBuilder builder = new GamePacketBuilder(238);
|
||||||
builder.put(DataType.BYTE, message.getTab());
|
builder.put(DataType.BYTE, message.getTab());
|
||||||
return builder.toGamePacket();
|
return builder.toGamePacket();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user