Class: Demiurge::AgentInternal::AgentActionIntention Private

Inherits:
Demiurge::ActionItemInternal::ActionIntention show all
Defined in:
lib/demiurge/agent.rb

Overview

This class is part of a private API. You should avoid using this class if possible, as it may be removed or be changed in the future.

Note:

There is a bit of weirdness in how this intention handles #allowed? and #offer. We want to be able to queue an action on the same tick that we execute it if the agent is idle. So we count this intention as #allowed? even if the queue is empty, then silent-cancel the intention during #offer if nobody has added anything to it. If you see a lot of cancel notifications from this object with "silent" set, now you know why.

An AgentActionIntention is how the agent takes queued actions each tick.

Instance Attribute Summary collapse

Attributes inherited from Demiurge::ActionItemInternal::ActionIntention

#action_args

Instance Method Summary collapse

Methods inherited from Intention

#cancel, #cancelled?, #try_apply

Constructor Details

#initialize(name, engine) ⇒ AgentActionIntention

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Constructor. Takes an agent name and an engine



161
162
163
164
165
166
# File 'lib/demiurge/agent.rb', line 161

def initialize(name, engine)
  super(engine, name, "")
  @agent = engine.item_by_name(name)
  raise ::Demiurge::Errors::NoSuchAgentError.new("No such agent as #{name.inspect} found in AgentActionIntention!", "agent" => name,
                                                 execution_context: engine.execution_context) unless @agent
end

Instance Attribute Details

#action_nameString (readonly)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns The queued action name this Intention will next take.

Returns:

  • (String)

    The queued action name this Intention will next take



158
159
160
# File 'lib/demiurge/agent.rb', line 158

def action_name
  @action_name
end

#agentStateItem (readonly)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns The agent to whom this Intention applies.

Returns:

  • (StateItem)

    The agent to whom this Intention applies



156
157
158
# File 'lib/demiurge/agent.rb', line 156

def agent
  @agent
end

Instance Method Details

#allowed?Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

This action is allowed if the agent is not busy, or will become not-busy soon

Returns:

  • (Boolean)


187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
# File 'lib/demiurge/agent.rb', line 187

def allowed?
  # If the agent's busy state will clear this turn, this action
  # could happen.  We intentionally don't send a "disallowed"
  # notification for the action. It's not cancelled, nor is it
  # dispatched successfully. It's just waiting for a later tick to
  # do one of those two things.
  return false if @agent.state["busy"] > 1

  # A dilemma: if we cancel now when no actions are queued, then
  # any action queued this turn (e.g. from an
  # EveryXActionsIntention) won't be executed -- we said this
  # intention wasn't happening. If we *don't* return false in the
  # "allowed?" phase then we'll wind up sending out a cancel
  # notice every turn when there are no actions. So we add a
  # "silent" info option to the normal-every-turn cancellations,
  # but we *do* allow-then-cancel even in perfectly normal
  # circumstances.
  true
end

#applyObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

If the agent can do so, take the action in question.



208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
# File 'lib/demiurge/agent.rb', line 208

def apply
  unless agent.state["busy"] > 0 || agent.state["queued_actions"].empty?
    # Pull the first entry off the action queue
    queue = @agent.state["queued_actions"]
    if queue && queue.size > 0
      if @action_queue_number != queue[0][2]
        @engine.admin_warning("Somehow the agent's action queue has gotten screwed up mid-offer!", "agent" => @name)
      else
        queue.shift # Remove the queue entry
      end
    end
    agent.run_action(@action_name, *@action_args, current_intention: self)
    agent.state["busy"] += (@action_struct["busy"] || 1)
  end
end

#apply_notificationvoid

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

This method returns an undefined value.

Send out a notification to indicate this ActionIntention was applied.

Since:

  • 0.2.0



255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
# File 'lib/demiurge/agent.rb', line 255

def apply_notification
  @engine.send_notification({
                              id: @intention_id,
                              intention_type: self.class.to_s,
                              queue_number: @action_queue_number,
                              action_name: @action_name,
                              action_args: @action_args,
                            },
                            type: Demiurge::Notifications::IntentionApplied,
                            zone: @item.zone_name,
                            location: @item.location_name,
                            actor: @item.name,
                            include_context: true)
  nil
end

#cancel_notificationvoid

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

This method returns an undefined value.

Send out a notification to indicate this ActionIntention was cancelled. If "silent" is set to true in the cancellation info, no notification will be sent.

Since:

  • 0.2.0



230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
# File 'lib/demiurge/agent.rb', line 230

def cancel_notification
  return if @cancelled_info && @cancelled_info["silent"]
  @engine.send_notification({
                              reason: @cancelled_reason,
                              by: @cancelled_by,
                              id: @intention_id,
                              intention_type: self.class.to_s,
                              info: @cancelled_info,
                              queue_number: @action_queue_number,
                              action_name: @action_name,
                              action_args: @action_args,
                            },
                            type: Demiurge::Notifications::IntentionCancelled,
                            zone: @item.zone_name,
                            location: @item.location_name,
                            actor: @item.name,
                            include_context: true)
  nil
end

#offerObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

An action being pulled from the action queue is offered normally.



169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
# File 'lib/demiurge/agent.rb', line 169

def offer
  # Don't offer the action if it's going to be a no-op.
  if @agent.state["busy"] > 0
    # See comment on "silent" in #allowed? below.
    self.cancel "Agent #{@name.inspect} was too busy to act (#{@agent.state["busy"]}).", "silent" => "true"
    return
  elsif @agent.state["queued_actions"].empty?
    self.cancel "Agent #{@name.inspect} had no actions during the 'offer' phase.", "silent" => "true"
    return
  end
  # Now offer the agent's action via the usual channels
  action = @agent.state["queued_actions"][0]
  @action_name, @action_args, @action_queue_number = *action
  @action_struct = @agent.get_action(@action_name)
  super
end