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



167
168
169
170
171
172
# File 'lib/demiurge/agent.rb', line 167

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



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

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



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

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)


193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
# File 'lib/demiurge/agent.rb', line 193

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.



214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
# File 'lib/demiurge/agent.rb', line 214

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



261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
# File 'lib/demiurge/agent.rb', line 261

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



236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
# File 'lib/demiurge/agent.rb', line 236

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.



175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
# File 'lib/demiurge/agent.rb', line 175

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