demiurge 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/.travis.yml +5 -0
- data/.yardopts +5 -0
- data/AUTHORS.txt +6 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/CONCEPTS.md +271 -0
- data/Gemfile +4 -0
- data/HACKING.md +34 -0
- data/LICENSE.txt +21 -0
- data/README.md +181 -0
- data/RELOADING.md +94 -0
- data/Rakefile +10 -0
- data/SECURITY.md +103 -0
- data/WORLD_FILES.md +134 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/demiurge.gemspec +31 -0
- data/exe/demirun +16 -0
- data/lib/demiurge/action_item.rb +643 -0
- data/lib/demiurge/agent.rb +338 -0
- data/lib/demiurge/container.rb +194 -0
- data/lib/demiurge/dsl.rb +583 -0
- data/lib/demiurge/exception.rb +170 -0
- data/lib/demiurge/inert_state_item.rb +21 -0
- data/lib/demiurge/intention.rb +164 -0
- data/lib/demiurge/location.rb +85 -0
- data/lib/demiurge/notification_names.rb +93 -0
- data/lib/demiurge/tmx.rb +439 -0
- data/lib/demiurge/util.rb +67 -0
- data/lib/demiurge/version.rb +4 -0
- data/lib/demiurge/zone.rb +108 -0
- data/lib/demiurge.rb +812 -0
- metadata +165 -0
@@ -0,0 +1,170 @@
|
|
1
|
+
module Demiurge;end
|
2
|
+
|
3
|
+
# The Errors module exists to scope errors out of the top-level namespace.
|
4
|
+
module Demiurge::Errors
|
5
|
+
# Demiurge::Errors::Exception is the parent class of all Demiurge-specific
|
6
|
+
# Exceptions.
|
7
|
+
#
|
8
|
+
# @since 0.0.1
|
9
|
+
class Exception < ::RuntimeError
|
10
|
+
# @return [Hash] Additional specific data about this exception.
|
11
|
+
# @since 0.0.1
|
12
|
+
attr_reader :info
|
13
|
+
|
14
|
+
# @return [Hash{String=>String}] Context about where and how the error occurred
|
15
|
+
# @since 0.2.0
|
16
|
+
attr_reader :execution_context
|
17
|
+
|
18
|
+
# Optionally add a hash of extra data, called info, to this
|
19
|
+
# exception. You can also add the engine's execution context, if
|
20
|
+
# available.
|
21
|
+
#
|
22
|
+
# @param msg [String] The message for this Exception
|
23
|
+
# @since 0.0.1
|
24
|
+
def initialize(msg, info = {}, execution_context: nil)
|
25
|
+
super(msg)
|
26
|
+
@info = info
|
27
|
+
@execution_context = execution_context ? execution_context.dup : nil
|
28
|
+
end
|
29
|
+
|
30
|
+
def backtrace_chain
|
31
|
+
bt_chain = []
|
32
|
+
cur_cause = self.cause
|
33
|
+
while cur_cause
|
34
|
+
bt_chain.push(self.backtrace)
|
35
|
+
cur_cause = cur_cause.cause
|
36
|
+
end
|
37
|
+
bt_chain
|
38
|
+
end
|
39
|
+
|
40
|
+
# Serialize this exception to a JSON-serializable PORO.
|
41
|
+
#
|
42
|
+
# @return [Hash] The serialized {Demiurge::Errors::Exception} data
|
43
|
+
# @since 0.0.1
|
44
|
+
def jsonable()
|
45
|
+
bt = backtrace_chain.inject { |a, b| a + [ "... Caused by ..." ] + b }
|
46
|
+
{
|
47
|
+
"message" => self.message,
|
48
|
+
"info" => self.info,
|
49
|
+
"execution_context" => self.execution_context,
|
50
|
+
"backtrace" => bt
|
51
|
+
}
|
52
|
+
end
|
53
|
+
|
54
|
+
def formatted
|
55
|
+
bt = backtrace_chain.map { |t| t.join("\n") }.join("\n... Caused by ...\n")
|
56
|
+
<<FORMATTED_BLOCK
|
57
|
+
#{self.message}
|
58
|
+
Error info: #{info.inspect}
|
59
|
+
Context: #{execution_context.inspect}
|
60
|
+
#{bt}
|
61
|
+
FORMATTED_BLOCK
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# A RetryableError or its subclasses normally indicate an error that
|
66
|
+
# is likely to be transient, and where retrying the tick is a
|
67
|
+
# reasonable attempt at a solution.
|
68
|
+
#
|
69
|
+
# @since 0.0.1
|
70
|
+
class RetryableError < ::Demiurge::Errors::Exception; end
|
71
|
+
|
72
|
+
# A BadScriptError will normally not benefit from retrying. Instead,
|
73
|
+
# one or more scripts associated with this error is presumed to be
|
74
|
+
# bad or outdated. The primary thing to do with BadScriptErrors is
|
75
|
+
# to accumulate and count them and possibly to deactivate one or
|
76
|
+
# more bad scripts. Error counting can allow an administrator to
|
77
|
+
# locate (or guess) the bad script in question and disable one or
|
78
|
+
# more scripts to remove the problem. While it's technically
|
79
|
+
# possible to disable bad scripts automatically, that may sometimes
|
80
|
+
# have distressing side effects when a script was intended to run
|
81
|
+
# and didn't. It may also have false positives where a misbehaving
|
82
|
+
# script "frames" a correct script by causing errors downstream.
|
83
|
+
#
|
84
|
+
# @since 0.0.1
|
85
|
+
class BadScriptError < ::Demiurge::Errors::Exception; end
|
86
|
+
|
87
|
+
# An AssetError means that there's a problem in the format of a TMX
|
88
|
+
# file, image, JSON file or other game asset. It is unlikely to be
|
89
|
+
# retryable, but it isn't normally the result of bad admin-written
|
90
|
+
# code.
|
91
|
+
#
|
92
|
+
# @since 0.0.1
|
93
|
+
class AssetError < ::Demiurge::Errors::Exception; end
|
94
|
+
|
95
|
+
# A ReloadError is a result of state that doesn't match perfectly on
|
96
|
+
# reload. Deleting non-transient objects, renaming objects, giving
|
97
|
+
# objects a new type and changing an object's state format can all
|
98
|
+
# give a ReloadError in certain circumstances.
|
99
|
+
#
|
100
|
+
# @since 0.0.1
|
101
|
+
class ReloadError < ::Demiurge::Errors::Exception; end
|
102
|
+
|
103
|
+
|
104
|
+
|
105
|
+
# This exception occurs when trying to use an action that doesn't
|
106
|
+
# exist, such as from {Demiurge::ActionItem#run_action} or
|
107
|
+
# {Demiurge::Agent#queue_action}.
|
108
|
+
#
|
109
|
+
# @since 0.0.1
|
110
|
+
class NoSuchActionError < BadScriptError; end
|
111
|
+
|
112
|
+
# This exception occurs when trying to use an agent name that
|
113
|
+
# doesn't belong to any registered agent.
|
114
|
+
#
|
115
|
+
# @since 0.0.1
|
116
|
+
class NoSuchAgentError < BadScriptError; end
|
117
|
+
|
118
|
+
# This occurs when trying to use a nonexistent state key in a way
|
119
|
+
# that isn't allowed. This exception normally refers to object
|
120
|
+
# state, when accessed from a script.
|
121
|
+
#
|
122
|
+
# @since 0.0.1
|
123
|
+
class NoSuchStateKeyError < BadScriptError; end
|
124
|
+
|
125
|
+
# This occurs when trying to modify or cancel an intention when
|
126
|
+
# there isn't one.
|
127
|
+
#
|
128
|
+
# @since 0.0.1
|
129
|
+
class NoCurrentIntentionError < BadScriptError; end
|
130
|
+
|
131
|
+
# This occurs if intentions queue other, new intentions too many
|
132
|
+
# times in the same tick. The exception exists to prevent infinite
|
133
|
+
# loops of queued intentions. If your script wants to queue lots of
|
134
|
+
# intentions, consider queueing them during *later* ticks instead of
|
135
|
+
# immediately.
|
136
|
+
#
|
137
|
+
# @since 0.0.1
|
138
|
+
class TooManyIntentionLoopsError < BadScriptError; end
|
139
|
+
|
140
|
+
# This occurs if notifications queue other, new notifications too
|
141
|
+
# many times in the same tick. The exception exists to prevent
|
142
|
+
# infinite loops of queued notifications. If your script wants to
|
143
|
+
# queue lots of notifications, consider queueing them after the tick
|
144
|
+
# has finished, perhaps on a later tick.
|
145
|
+
#
|
146
|
+
# @since 0.0.1
|
147
|
+
class TooManyNotificationLoopsError < BadScriptError; end
|
148
|
+
|
149
|
+
# This occurs if there's a problem in the TMX file or in some kind
|
150
|
+
# of file convention (such as using "Fringe" for a hardcoded layer)
|
151
|
+
# in a specific subformat like ManaSource.
|
152
|
+
#
|
153
|
+
# @since 0.0.1
|
154
|
+
class TmxFormatError < AssetError; end
|
155
|
+
|
156
|
+
# When loading or reloading, we got an exception when parsing
|
157
|
+
# WorldFile code.
|
158
|
+
#
|
159
|
+
# @since 0.0.1
|
160
|
+
class CannotLoadWorldFiles < ReloadError; end
|
161
|
+
|
162
|
+
# When reloading, this error or a subclass can be raised if the new
|
163
|
+
# state structure or StateItems don't seem to match the old one in
|
164
|
+
# illegal ways. "Illegal" can vary, depending how conservative the
|
165
|
+
# reloading options are set.
|
166
|
+
#
|
167
|
+
# @since 0.0.1
|
168
|
+
class NonMatchingStateError < ReloadError; end
|
169
|
+
|
170
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Demiurge
|
2
|
+
|
3
|
+
# Sometimes you just want state that sits and does nothing unless
|
4
|
+
# you mess with it. Player password hashes? Top-level game settings?
|
5
|
+
# Heck, even something sort-of-active like bank inventory can make
|
6
|
+
# sense to model this way since it will never do anything on its
|
7
|
+
# own. This is especially good for things that will never interact
|
8
|
+
# with the engine cycle - something that ignores ticks, intentions,
|
9
|
+
# notifications, etc.
|
10
|
+
#
|
11
|
+
# @since 0.0.1
|
12
|
+
class InertStateItem < StateItem
|
13
|
+
# An InertStateItem doesn't intend anything, ever.
|
14
|
+
#
|
15
|
+
# @return [Array<Intention>] This array will always be empty for an InertStateItem
|
16
|
+
# @since 0.0.1
|
17
|
+
def intentions_for_next_step(*args)
|
18
|
+
[]
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,164 @@
|
|
1
|
+
module Demiurge
|
2
|
+
|
3
|
+
# An Intention is an unresolved event. Some part of the simulated
|
4
|
+
# world "wishes" to take an action. This need not be a sentient
|
5
|
+
# being - any change to the world should occur with an Intention
|
6
|
+
# then being resolved into changes in state and events -- or
|
7
|
+
# not. It's also possible for an intention to resolve to nothing at
|
8
|
+
# all. For instance, an intention to move in an impossible direction
|
9
|
+
# could simply resolve with no movement, no state change and no event.
|
10
|
+
#
|
11
|
+
# Intentions go through verification, resolution and eventually
|
12
|
+
# notification.
|
13
|
+
#
|
14
|
+
# Intentions are not, in general, serializable. They normally
|
15
|
+
# persist for only a single tick. To persist an intention for most StateItems,
|
16
|
+
# consider persisting action names instead.
|
17
|
+
#
|
18
|
+
# For more details about Intention, see {file:CONCEPTS.md}.
|
19
|
+
#
|
20
|
+
# @since 0.0.1
|
21
|
+
|
22
|
+
class Intention
|
23
|
+
# Subclasses of intention can require all sorts of constructor arguments to
|
24
|
+
# specify what the intention is. But the engine should always be supplied.
|
25
|
+
#
|
26
|
+
# @param engine [Demiurge::Engine] The engine this Intention is part of.
|
27
|
+
# @since 0.0.1
|
28
|
+
def initialize(engine)
|
29
|
+
@cancelled = false
|
30
|
+
@engine = engine
|
31
|
+
@intention_id = engine.get_intention_id
|
32
|
+
end
|
33
|
+
|
34
|
+
# This cancels the intention, and gives the reason for the
|
35
|
+
# cancellation.
|
36
|
+
#
|
37
|
+
# @param reason [String] A human-readable reason this action was cancelled
|
38
|
+
# @param info [Hash] A String-keyed Hash of additional information about the cancellation
|
39
|
+
# @return [void]
|
40
|
+
# @since 0.0.1
|
41
|
+
def cancel(reason, info = {})
|
42
|
+
@cancelled = true
|
43
|
+
@cancelled_by = caller(1, 1)
|
44
|
+
@cancelled_reason = reason
|
45
|
+
@cancelled_info = info
|
46
|
+
cancel_notification
|
47
|
+
nil
|
48
|
+
end
|
49
|
+
|
50
|
+
# Most intentions will send a cancellation notice when they are
|
51
|
+
# cancelled. By default, this will include who cancelled the
|
52
|
+
# intention and why.
|
53
|
+
#
|
54
|
+
# If the cancellation info Hash includes "silent" with a true
|
55
|
+
# value, by default no notification will be sent out. This is to
|
56
|
+
# avoid an avalache of notifications for common cancelled
|
57
|
+
# intentions that happen nearly every tick. Examples include an
|
58
|
+
# agent's action queue being empty so it cancels its intention.
|
59
|
+
# These are normal operation and nobody is likely to need
|
60
|
+
# notification every tick that they didn't ask to do anything so
|
61
|
+
# they didn't.
|
62
|
+
#
|
63
|
+
# {#cancel_notification} can be overridden by child classes
|
64
|
+
# for more specific cancel notifications.
|
65
|
+
#
|
66
|
+
# @return [void]
|
67
|
+
# @since 0.0.1
|
68
|
+
def cancel_notification
|
69
|
+
return if @cancelled_info && @cancelled_info["silent"]
|
70
|
+
@engine.send_notification({
|
71
|
+
:reason => @cancelled_reason,
|
72
|
+
:by => @cancelled_by,
|
73
|
+
:id => @intention_id,
|
74
|
+
:intention_type => self.class.to_s,
|
75
|
+
:info => @cancelled_info
|
76
|
+
},
|
77
|
+
type: Demiurge::Notifications::IntentionCancelled, zone: "admin", location: nil, actor: nil,
|
78
|
+
include_context: true)
|
79
|
+
nil
|
80
|
+
end
|
81
|
+
|
82
|
+
# Intentions should send an apply notice when they are
|
83
|
+
# successfully applied. {#apply_notification} can be overridden by
|
84
|
+
# child classes to send more specific information.
|
85
|
+
#
|
86
|
+
# @return [void]
|
87
|
+
# @since 0.2.0
|
88
|
+
def apply_notification
|
89
|
+
@engine.send_notification({
|
90
|
+
:id => @intention_id,
|
91
|
+
:intention_type => self.class.to_s,
|
92
|
+
:info => @cancelled_info
|
93
|
+
},
|
94
|
+
type: Demiurge::Notifications::IntentionApplied, zone: "admin", location: nil, actor: nil,
|
95
|
+
include_context: true)
|
96
|
+
nil
|
97
|
+
end
|
98
|
+
|
99
|
+
# This returns whether this intention has been cancelled.
|
100
|
+
#
|
101
|
+
# @return [Boolean] Whether the notification is cancelled.
|
102
|
+
def cancelled?
|
103
|
+
@cancelled
|
104
|
+
end
|
105
|
+
|
106
|
+
# This method allows child classes of Intention to check whether
|
107
|
+
# they should happen at all. If this method returns false, the
|
108
|
+
# intention will self-cancel without sending a notification and
|
109
|
+
# quietly not occur. The method exists primarily to allow
|
110
|
+
# "illegal" intentions like walking through a wall or drinking
|
111
|
+
# nonexistent water to quietly not happen without the rest of the
|
112
|
+
# simulation responding to them in any way.
|
113
|
+
#
|
114
|
+
# @return [Boolean] If this method returns false, the Intention will quietly self-cancel before the offer phase.
|
115
|
+
# @since 0.0.1
|
116
|
+
def allowed?
|
117
|
+
raise "Unimplemented 'allowed?' for intention: #{self.inspect}!"
|
118
|
+
end
|
119
|
+
|
120
|
+
# This method tells the Intention that it has successfully
|
121
|
+
# occurred and it should modify StateItems accordingly. Normally
|
122
|
+
# this will only be called after {#allowed?} and {#offer} have
|
123
|
+
# completed, and other items have had a chance to modify or cancel
|
124
|
+
# this Intention.
|
125
|
+
#
|
126
|
+
# @return [void]
|
127
|
+
# @since 0.0.1
|
128
|
+
def apply
|
129
|
+
raise "Unimplemented 'apply' for intention: #{self.inspect}!"
|
130
|
+
end
|
131
|
+
|
132
|
+
# When an Intention is "offered", that means appropriate other
|
133
|
+
# entities have a chance to modify or cancel the intention. For
|
134
|
+
# instance, a movement action in a room should be offered to that
|
135
|
+
# room, which may trigger a special action (e.g. trap) or change
|
136
|
+
# the destination of the action (e.g. exits, slippery ice,
|
137
|
+
# spinning spaces.)
|
138
|
+
#
|
139
|
+
# @see file:CONCEPTS.md
|
140
|
+
# @return [void]
|
141
|
+
# @since 0.0.1
|
142
|
+
# @note This method changed signature in 0.2.0 to stop taking an intention ID.
|
143
|
+
def offer
|
144
|
+
raise "Unimplemented 'offer' for intention: #{self.inspect}!"
|
145
|
+
end
|
146
|
+
|
147
|
+
# This is a normally-private part of the Tick cycle. It checks the
|
148
|
+
# {#allowed?} and {#offer} phases for this one specific Intention.
|
149
|
+
#
|
150
|
+
# @return [void]
|
151
|
+
# @since 0.0.1
|
152
|
+
# @api private
|
153
|
+
# @note This method changed signature in 0.2.0 to stop taking an intention ID.
|
154
|
+
def try_apply
|
155
|
+
return unless allowed?
|
156
|
+
offer
|
157
|
+
return if cancelled? # Notification should already have been sent out
|
158
|
+
apply
|
159
|
+
return if cancelled? # Notification should already have been sent out
|
160
|
+
apply_notification
|
161
|
+
nil
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
module Demiurge
|
2
|
+
# A Location is generally found inside a Zone. It may contain items
|
3
|
+
# and agents.
|
4
|
+
class Location < Container
|
5
|
+
# Constructor - set up exits
|
6
|
+
#
|
7
|
+
# @param name [String] The Engine-unique item name
|
8
|
+
# @param engine [Demiurge::Engine] The Engine this item is part of
|
9
|
+
# @param state [Hash] State data to initialize from
|
10
|
+
# @return [void]
|
11
|
+
# @since 0.0.1
|
12
|
+
def initialize(name, engine, state)
|
13
|
+
super
|
14
|
+
state["exits"] ||= []
|
15
|
+
end
|
16
|
+
|
17
|
+
def finished_init
|
18
|
+
super
|
19
|
+
# Make sure we're in our zone.
|
20
|
+
zone.ensure_contains(@name)
|
21
|
+
end
|
22
|
+
|
23
|
+
# A Location isn't located "inside" somewhere else. It is located in/at itself.
|
24
|
+
def location_name
|
25
|
+
@name
|
26
|
+
end
|
27
|
+
|
28
|
+
# A Location isn't located "inside" somewhere else. It is located in/at itself.
|
29
|
+
def location
|
30
|
+
self
|
31
|
+
end
|
32
|
+
|
33
|
+
def zone_name
|
34
|
+
@state["zone"]
|
35
|
+
end
|
36
|
+
|
37
|
+
def zone
|
38
|
+
@engine.item_by_name(@state["zone"])
|
39
|
+
end
|
40
|
+
|
41
|
+
# By default, the location can accomodate any agent number, size
|
42
|
+
# or shape, as long as it's in this location itself. Subclasses
|
43
|
+
# of location may have different abilities to accomodate different
|
44
|
+
# sizes or shapes of agent, and at different positions.
|
45
|
+
def can_accomodate_agent?(agent, position)
|
46
|
+
position == @name
|
47
|
+
end
|
48
|
+
|
49
|
+
# Return a legal position of some kind within this Location. By
|
50
|
+
# default there is only one position, which is just the Location's
|
51
|
+
# name. More complicated locations (e.g. tilemaps or procedural
|
52
|
+
# areas) may have more interesting positions inside them.
|
53
|
+
def any_legal_position
|
54
|
+
@name
|
55
|
+
end
|
56
|
+
|
57
|
+
# Is this position valid in this location?
|
58
|
+
def valid_position?(pos)
|
59
|
+
pos == @name
|
60
|
+
end
|
61
|
+
|
62
|
+
def add_exit(from:any_legal_position, to:, to_location: nil, properties:{})
|
63
|
+
to_loc, to_coords = to.split("#",2)
|
64
|
+
if to_location == nil
|
65
|
+
to_location = @engine.item_by_name(to_loc)
|
66
|
+
end
|
67
|
+
raise("'From' position #{from.inspect} is invalid when adding exit to #{@name.inspect}!") unless valid_position?(from)
|
68
|
+
raise("'To' position #{to.inspect} is invalid when adding exit to #{@name.inspect}!") unless to_location.valid_position?(to)
|
69
|
+
exit_obj = { "from" => from, "to" => to, "properties" => properties }
|
70
|
+
@state["exits"] ||= []
|
71
|
+
@state["exits"].push(exit_obj)
|
72
|
+
exit_obj
|
73
|
+
end
|
74
|
+
|
75
|
+
# This isn't guaranteed to be in a particular format for all
|
76
|
+
# Locations everywhere. Sometimes exits in this form don't even
|
77
|
+
# make sense. So: this is best-effort when queried from a random
|
78
|
+
# Location, and a known format only if you know the specific
|
79
|
+
# subclass of Location you're dealing with.
|
80
|
+
def exits
|
81
|
+
@state["exits"]
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
module Demiurge
|
2
|
+
# Notifications use string identifiers as names. It's legal to use
|
3
|
+
# strings directly, but then typos can go undetected. This also
|
4
|
+
# serves as a list of what notifications are normally
|
5
|
+
# available. Application-specific notifications should define their
|
6
|
+
# own notification constants, either in this module or another one.
|
7
|
+
#
|
8
|
+
# @since 0.2.0
|
9
|
+
module Notifications
|
10
|
+
|
11
|
+
# This notification is sent when something is misconfigured, but
|
12
|
+
# not in a continuity-threatening way.
|
13
|
+
#
|
14
|
+
# @since 0.2.0
|
15
|
+
AdminWarning = "admin_warning"
|
16
|
+
|
17
|
+
# This notification indicates that a tick has completed.
|
18
|
+
#
|
19
|
+
# @since 0.2.0
|
20
|
+
TickFinished = "tick_finished"
|
21
|
+
|
22
|
+
# This notification indicates that a new item has been registered
|
23
|
+
# by the engine.
|
24
|
+
#
|
25
|
+
# @since 0.2.0
|
26
|
+
NewItem = "new_item"
|
27
|
+
|
28
|
+
# This notification means that state loading has begun into an
|
29
|
+
# initialized engine.
|
30
|
+
#
|
31
|
+
# @since 0.2.0
|
32
|
+
LoadStateStart = "load_state_start"
|
33
|
+
|
34
|
+
# This notification means that state loading has finished in an
|
35
|
+
# initialized engine.
|
36
|
+
#
|
37
|
+
# @since 0.2.0
|
38
|
+
LoadStateEnd = "load_state_end"
|
39
|
+
|
40
|
+
# This notification is sent when a World File reload is preparing
|
41
|
+
# to start. This will be sent on verify-only reloads as well as
|
42
|
+
# normal reloads.
|
43
|
+
#
|
44
|
+
# @since 0.2.0
|
45
|
+
LoadWorldVerify = "load_world_verify"
|
46
|
+
|
47
|
+
# This notification is sent when a World File reload has
|
48
|
+
# successfully verified and has begun loading. Verify-only reloads
|
49
|
+
# do not send this signal.
|
50
|
+
#
|
51
|
+
# @since 0.2.0
|
52
|
+
LoadWorldStart = "load_world_start"
|
53
|
+
|
54
|
+
# This notification is sent when a World File reload has
|
55
|
+
# successfully completed. Verify-only reloads do not send this
|
56
|
+
# signal.
|
57
|
+
#
|
58
|
+
# @since 0.2.0
|
59
|
+
LoadWorldEnd = "load_world_end"
|
60
|
+
|
61
|
+
# This notification is sent when an agent moves between positions,
|
62
|
+
# locations and/or zones. This notification goes out at the old
|
63
|
+
# location and zone, which may be the same as the new.
|
64
|
+
#
|
65
|
+
# Fields: new_position (String), old_position (String), new_location (String), old_location (String), zone (String)
|
66
|
+
#
|
67
|
+
# @since 0.2.0
|
68
|
+
MoveFrom = "move_from"
|
69
|
+
|
70
|
+
# This notification is sent when an agent moves between positions,
|
71
|
+
# locations and/or zones. This notification goes out at the new
|
72
|
+
# location and zone, which may be the same as the old.
|
73
|
+
#
|
74
|
+
# Fields: new_position (String), old_position (String), new_location (String), old_location (String), zone (String)
|
75
|
+
#
|
76
|
+
# @since 0.2.0
|
77
|
+
MoveTo = "move_to"
|
78
|
+
|
79
|
+
# This notification is sent when an intention has been cancelled.
|
80
|
+
#
|
81
|
+
# Fields: reason (String), by (Array<String>), id (Integer), intention_type (String), info (Hash)
|
82
|
+
#
|
83
|
+
# @since 0.2.0
|
84
|
+
IntentionCancelled = "intention_cancelled"
|
85
|
+
|
86
|
+
# This notification is sent when an intention is successfully applied.
|
87
|
+
#
|
88
|
+
# Fields: id (Integer), intention_type (String), info (Hash)
|
89
|
+
#
|
90
|
+
# @since 0.2.0
|
91
|
+
IntentionApplied = "intention_applied"
|
92
|
+
end
|
93
|
+
end
|