From 8bea1648a3ddcf044b7c292fddd8ab52f175c1e2 Mon Sep 17 00:00:00 2001
From: Jeffrey Phillips Freeman <the@jeffreyfreeman.me>
Date: Wed, 6 May 2020 19:59:05 -0400
Subject: [PATCH] Actions are now handled through a priority queue.

---
 lib/aethyr/core/components/manager.rb  | 31 ++++++++++++++++++++++++--
 lib/aethyr/core/connection/server.rb   |  3 +++
 lib/aethyr/core/util/priority_queue.rb |  2 ++
 3 files changed, 34 insertions(+), 2 deletions(-)

diff --git a/lib/aethyr/core/components/manager.rb b/lib/aethyr/core/components/manager.rb
index 2bac117..4120397 100644
--- a/lib/aethyr/core/components/manager.rb
+++ b/lib/aethyr/core/components/manager.rb
@@ -5,6 +5,7 @@ require 'aethyr/core/errors'
 require 'aethyr/core/objects/info/calendar'
 require 'aethyr/core/registry'
 require 'aethyr/core/util/publisher'
+require 'aethyr/core/util/priority_queue'
 require 'set'
 
 #The Manager class uses the wisper to recieve commands from objects, which
@@ -22,9 +23,12 @@ class Manager < Publisher
   #a Manager object in an external script.
   def initialize(objects = nil)
     Aethyr::Extend::HandlerRegistry.handle(self)
+
     @soft_restart = false
     @storage = StorageMachine.new
     @uptime = Time.new.to_i
+    @future_actions = PriorityQueue.new
+    @pending_actions = PriorityQueue.new
 
     unless objects
       @cancelled_events = Set.new
@@ -43,8 +47,26 @@ class Manager < Publisher
     end
   end
 
-  def submit_action action
-    action.action
+  def submit_action( action, priority: 0, wait: nil )
+    if wait.nil? || wait <= 0
+      @pending_actions.push(action, priority)
+    else
+      activate_when = Manager::epoch_now + wait
+      @future_actions.push({:action => action, :priority => priority}, activate_when)
+    end
+  end
+
+  def pop_action
+    # first check for any future actions ready to become active
+    when_next = @future_actions.min_priority
+    while when_next && when_next < Manager::epoch_now do
+      future_next = @future_actions.pop_min
+      @pending_actions.push(future_next[:action], future_next[:priority])
+      when_next = @future_actions.min_priority
+    end
+
+    #return and pop whatever the next thing in the queue is.
+    return @pending_actions.pop_min
   end
 
   #Checks if a game object ID exists already, to avoid conflicts.
@@ -427,4 +449,9 @@ class Manager < Publisher
   def to_s
     "The Manager"
   end
+
+  private
+  def self.epoch_now
+    return DateTime.now.strftime('%s')
+  end
 end
diff --git a/lib/aethyr/core/connection/server.rb b/lib/aethyr/core/connection/server.rb
index 7c330bc..0326d2f 100644
--- a/lib/aethyr/core/connection/server.rb
+++ b/lib/aethyr/core/connection/server.rb
@@ -74,6 +74,9 @@ module Aethyr
             end
           end
 
+          next_action = $manager.pop_action
+          next_action.action unless next_action.nil?
+
           # TODO this is a hack to fix a bug from calling resizeterm
           #check if global refresh is needed
           need_refresh = false
diff --git a/lib/aethyr/core/util/priority_queue.rb b/lib/aethyr/core/util/priority_queue.rb
index 2cd83bc..19bce22 100644
--- a/lib/aethyr/core/util/priority_queue.rb
+++ b/lib/aethyr/core/util/priority_queue.rb
@@ -405,6 +405,8 @@ class PriorityQueue
     delete_min[0] rescue nil
   end
 
+  alias pop_min delete_min_return_key
+
   # call-seq:
   #    delete_min_return_priority -> priority
   #
-- 
GitLab