Advertisement
Guest User

Untitled

a guest
Mar 11th, 2017
92
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Haxe 6.80 KB | None | 0 0
  1. package com.ludamix.triad.entity;
  2.  
  3. /*
  4.  *
  5.  * A minimalistic, non-serializing, message-passing entity system.
  6.  *
  7.  * The entities contain only arrays of EListeners - function pointers.
  8.  * A component may live on an entity as attached listeners, or as its own entity, accessed via passthrough listeners.
  9.  * To address common methods like spawn/despawn, listeners are allowed to stack themselves on the same name.
  10.  *
  11.  * Raw data lives on the database; subclass the database to integrate more data structures.
  12.  * When you need to be clean, you can use listener calls everywhere to attain as much abstraction as necessary;
  13.  * When you need to grab data fast, you can dive into the raw database functionality.
  14.  *
  15.  * The system has, built-in:
  16.  *
  17.  *    1. Spawning: An array of "listener templates" is passed in. The templates are combined,
  18.  *       and the "spawn" listener is called by default.
  19.  *    2. Despawning: Entities have to ask to be despawnable via the createDespawnable template.
  20.  *       Then on calling "despawn" they are queued for removal. In the main loop, when flushEntities() is called,
  21.  *       the events in "on_despawn" are performed. This allows a mix of deferred and immediate actions to be taken.
  22.  *    2. Tags and property bags. Apply the createTag and createBag templates.
  23.  *
  24.  */
  25.  
  26. typedef ListenerHash = Hash<Array<Dynamic>>;
  27. typedef EStack = List<ERow>;
  28. typedef EListener = Dynamic->EStack->Dynamic->Dynamic;
  29.  
  30. class EDatabase
  31. {
  32.    
  33.     public var rows : IntHash<ERow>;
  34.     public var id_increment : Int;
  35.    
  36.     public var tags : Hash<Array<ERow>>;
  37.     public var bags : Array<Dynamic>;
  38.     public var removequeue : Array<ERow>;
  39.    
  40.     public function new()
  41.     {
  42.         rows = new IntHash();
  43.         tags = new Hash();
  44.         bags = new Array();
  45.         removequeue = new Array();
  46.         id_increment = 0;
  47.     }
  48.    
  49.     private function getFreeId()
  50.     {
  51.         while (rows.exists(id_increment))
  52.         {
  53.             id_increment++; if (id_increment < 0) id_increment = 0;
  54.         }
  55.         return id_increment;
  56.     }
  57.    
  58.     public function spawn(listener_objects : Array<Dynamic>, ?andCall = "spawn")
  59.     {
  60.         // spawns an object based on any number of listener template objects stacked together
  61.         var obj : Dynamic = { };
  62.         for (lo in listener_objects)
  63.         {
  64.             for (f in Reflect.fields(lo))
  65.             {
  66.                 var content : Dynamic = Reflect.field(lo, f);
  67.                 var existing = Reflect.field(obj, f);
  68.                 if (existing == null)
  69.                 {
  70.                     Reflect.setProperty(obj, f, content);
  71.                 }
  72.                 else
  73.                 {
  74.                     for (c in cast(content,Array<Dynamic>)) existing.push(c);
  75.                 }
  76.             }
  77.         }
  78.        
  79.         var h = new ListenerHash();
  80.         for (f in Reflect.fields(obj))
  81.         {
  82.             var content = Reflect.field(obj, f);
  83.             h.set(f, content);
  84.         }
  85.         var row = new ERow(getFreeId(), h);
  86.         rows.set(row.id, row);
  87.         if (andCall != null) call(row, andCall);
  88.         return row;
  89.     }
  90.    
  91.     public inline function call(target : ERow, listener : String, ?payload : Dynamic = null,
  92.         ?stack : EStack=null) : Dynamic
  93.     {
  94.         if (stack==null)
  95.             return target.call(this, new EStack(), listener, payload);
  96.         else
  97.             return target.call(this, stack, listener, payload);
  98.     }
  99.    
  100.     public function createTags(names_input : Array<String>)
  101.     {
  102.         var names = names_input;
  103.         var do_spawn : Dynamic = null;
  104.         var do_get : Dynamic = null;
  105.         var do_tag : Dynamic = null;
  106.         var do_untag : Dynamic = null;
  107.         var on_despawn : Dynamic = null;
  108.        
  109.         do_get = function(db : EDatabase, stack : EStack, payload : Dynamic)
  110.         { if (payload == null) throw "pass in an array"; else
  111.             {for (name in names) {payload.push(name);} return payload;} }
  112.         do_tag = function(db : EDatabase, stack : EStack, payload : Dynamic)
  113.         {
  114.             names.push(payload);  
  115.             var tagset : Array<ERow> = tags.get(payload);
  116.             if (tagset==null)
  117.             {
  118.                 tagset = new Array(); tags.set(payload, tagset);
  119.             }
  120.             tagset.push(stack.last());
  121.         }
  122.         do_untag = function(db : EDatabase, stack : EStack, payload : Dynamic)
  123.         {
  124.             names.remove(payload);  
  125.             var tagset : Array<ERow> = tags.get(payload);
  126.             if (tagset!=null)
  127.             {
  128.                 tagset.remove(stack.last());
  129.             }
  130.         }
  131.         do_spawn = function(db : EDatabase, stack : EStack, payload : Dynamic)
  132.         {
  133.             for (p in names)
  134.             {
  135.                 var tagset : Array<ERow> = tags.get(p);
  136.                 if (tagset==null)
  137.                 {
  138.                     tagset = new Array(); tags.set(p, tagset);
  139.                 }
  140.                 tagset.push(stack.last());
  141.             }
  142.         }
  143.         on_despawn = function(db : EDatabase, stack : EStack, payload : Dynamic)
  144.         {
  145.             for (n in names)
  146.             {
  147.                 var tagset : Array<ERow> = tags.get(n);
  148.                 if (tagset!=null)
  149.                 {
  150.                     tagset.remove(stack.last());
  151.                 }
  152.             }
  153.         }
  154.         return { tags:[do_get], tag:[do_tag], untag:[do_untag], spawn:[do_spawn], on_despawn:[on_despawn] };
  155.     }
  156.    
  157.     public function createBag(name : String, data : Dynamic)
  158.     {
  159.         var do_spawn : Dynamic = null;
  160.         var do_get : Dynamic = null;
  161.         var on_despawn : Dynamic = null;
  162.         do_spawn = function(db : EDatabase, stack : EStack, payload : Dynamic)
  163.             { bags.push(data); }
  164.         do_get = function(db : EDatabase, stack : EStack, payload : Dynamic)
  165.             { return data; }
  166.         on_despawn = function(db : EDatabase, stack : EStack, payload : Dynamic)
  167.             { bags.remove(data); }
  168.         return { name:[do_get], spawn:[do_spawn], on_despawn:[on_despawn] };       
  169.     }
  170.    
  171.     public function createDespawnable()
  172.     {
  173.         return {
  174.             despawn:[function(db : EDatabase, stack : EStack, payload : Dynamic)
  175.                 { var me = stack.last(); db.removequeue.remove(me); db.removequeue.push(me); } ]
  176.         };
  177.     }
  178.    
  179.     public function flushEntities()
  180.     {
  181.         while(removequeue.length>0)
  182.         {
  183.             var n = removequeue.pop();
  184.             call(n, "on_despawn");
  185.             rows.remove(n.id);
  186.         }
  187.     }
  188.    
  189. }
  190.  
  191. class ERow
  192. {
  193.    
  194.     public var id : Int;
  195.     public var listeners : ListenerHash;
  196.    
  197.     public function new(id : Int, ?listeners : ListenerHash = null)
  198.     {
  199.         this.id = id;
  200.         if (listeners == null)
  201.             this.listeners = new ListenerHash();
  202.         else
  203.             this.listeners = listeners;
  204.     }
  205.    
  206.     public inline function call(db : EDatabase,
  207.         stack : EStack, listener : String, ?payload : Dynamic = null) : Dynamic
  208.     {
  209.         var result = null;
  210.         var lar : Array<Dynamic> = listeners.get(listener);
  211.         if (lar != null)
  212.         {
  213.             stack.add(this);
  214.             for (l in lar)
  215.             {
  216.                 var copy = new EStack();
  217.                 for (n in stack) copy.add(n);
  218.                 result = l(db, copy, payload);
  219.             }
  220.         }
  221.         return result;
  222.     }
  223.    
  224.     public inline function listen(name : String, call : EListener)
  225.     {
  226.         if (listeners.exists(name))
  227.             listeners.get(name).push(call);
  228.         else
  229.         {
  230.             listeners.set(name, [call]);
  231.         }
  232.     }
  233.    
  234.     public inline function unlisten(listener : String, call: EListener)
  235.     {
  236.         var l = listeners.get(listener);
  237.         l.remove(call);
  238.         if (l.length < 1)
  239.             listeners.remove(listener);
  240.     }
  241.    
  242.     public inline function unlistenAll(listener : String) { listeners.remove(listener); }
  243.    
  244.     public function listenerNames()
  245.     {
  246.         var ar = new Array<String>(); for (n in listeners.keys()) ar.push(n); return ar;
  247.     }
  248.  
  249. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement