Dispatcher
From TrainzOnline
		(Difference between revisions)
		
		
|  (Created page with "TBD: Update text  TBD: Repost or update additional informations after reposting the registered objectsoup  * CONTCRANE: Repost a goid list of reachable stacks. The contcrane i...") | |||
| Line 1: | Line 1: | ||
| TBD: Update text | TBD: Update text | ||
| − | TBD: Repost or update additional informations after reposting the registered objectsoup | + |   '''TBD: Repost or update additional informations after reposting the registered objectsoup.''' | 
| + |   * CONTCRANE: Repost a goid list of reachable stacks. The contcrane itself informs the stacks about it's object data to update the maximum count of stackable containers. | ||
| + |   * CONTSTACK: ??? | ||
| + |   * CONTAINER: If a container has no stack place, randomly attach him to a free stack place and repost it. In case there is no one, repost an empty stack goid with place zero. '''''TBD: What happens if the stack it attached to does not exist? Possibly handled as a free container?''''' | ||
| − | * CONTCRANE: Repost a goid list of reachable stacks. The contcrane itself informs the stacks about it's object data to update the maximum count of stackable containers. | + | ==Asset files pre version 0.1== | 
| − | * CONTSTACK: ??? | + | The files compile errorless and the messaging runs well. No more functionality implemented and tested in this pre version. | 
| − | * CONTAINER: If a container has no stack place, randomly attach him to a free stack place and repost it. In case there is no one, repost an empty stack goid with place zero.  | + | |
| + | ===config.txt=== | ||
| + | <CODE> | ||
| + |   kuid               <kuid2:215489:110000:1> | ||
| + |   username           "aCTS DISPATCHER Library V1" | ||
| + |   kind               "Library" | ||
| + |   category-class     "YL" | ||
| + |   trainz-build       4.6 | ||
| + | |||
| + |   description        "aCTS DISPATCHER Library V1" | ||
| + | |||
| + |   script             "acts_dispatcher.gs" | ||
| + |   class              "acts_dispatcher" | ||
| + | |||
| + |   thumbnails | ||
| + |   { | ||
| + |     0 | ||
| + |     { | ||
| + |       image          "acts_dispatcher_thumb.jpg" | ||
| + |       width          240 | ||
| + |       height         180 | ||
| + |     } | ||
| + |   }  | ||
| + | </CODE> | ||
| + | |||
| + | ===acts_dispatcher.gs=== | ||
| + | <CODE> | ||
| + |   include "acts_global_values.gs" | ||
| + |   include "acts_tools_script.gs" | ||
| + | |||
| + |   //----------------------------------------------------------------------------- | ||
| + |   // aCTS Dispatcher V0.1 Central Script - acts_dispatcher | ||
| + |   //----------------------------------------------------------------------------- | ||
| + |   // X acts_dispatcher             <-- acts_dispatcher_script | ||
| + |   // X acts_dispatcher_script      <-- acts_dispatcher_globals | ||
| + |   // X acts_dispatcher_globals     <-- acts_global_values | ||
| + |   //   acts_global_values          <-- MapObject | ||
| + |   //----------------------------------------------------------------------------- | ||
| + | |||
| + |   //----------------------------------------------------------------------------- | ||
| + |   class acts_dispatcher_globals isclass acts_global_values | ||
| + |   { | ||
| + |     //--------------------------------------------------------------------------- | ||
| + |     // Store from dispatcher received object registration values to the  | ||
| + |     // respective dispatchers sub soup. The sub soups register ids run as int   | ||
| + |     // from 0 ... The received id -1 tells, that the object isn't yet | ||
| + |     // registered. | ||
| + |     //--------------------------------------------------------------------------- | ||
| + |     // Because the register id number list gets gaps while unregistering it will | ||
| + |     // be nessecary to have some gap filling methods additionally. See | ||
| + |     // AppendInsertUpdateObjectDataSoups and FindObjectSoupEntry methods. | ||
| + |     //--------------------------------------------------------------------------- | ||
| + |     // AssetInstanceSoup { | ||
| + |     //   ObjectDataSoup { ... },    Only container, contstack, contcrane | ||
| + |     //   LocationSoup { ... },      Only container, contstack, contcrane | ||
| + |     //   OrientationSoup { ... },   Only container, contstack, contcrane | ||
| + |     //   SkinDataSoup { ... },      Only container | ||
| + |     //   ContentDataSoup { ... },   Only container | ||
| + |     // X DispatcherDataSoup { ... } Only dispatcher | ||
| + |     // X ContainerSoups  { ... }    Only dispatcher | ||
| + |     // X ContstackSoups  { ... }    Only dispatcher | ||
| + |     // X ContcraneSoups  { ... }    Only dispatcher | ||
| + |     // } | ||
| + |     //--------------------------------------------------------------------------- | ||
| + |     Soup ContainerSoups = Constructors.NewSoup(); | ||
| + |     Soup ContstackSoups = Constructors.NewSoup(); | ||
| + |     Soup ContcraneSoups = Constructors.NewSoup(); | ||
| + |     //--------------------------------------------------------------------------- | ||
| + |     Soup DispatcherDataSoup = Constructors.NewSoup(); | ||
| + |     //--------------------------------------------------------------------------- | ||
| + |     // ObjectDataSoup received from and posted to objects. | ||
| + |     //--------------------------------------------------------------------------- | ||
| + |     // ObjectDataSoup { goid GameObjectID, type string, dispID int, | ||
| + |     //                  length int, height int, | ||
| + |     //                  stack goid, place int,           Only container | ||
| + |     //                  active bool, action string }, | ||
| + |     // activ: true means the object sended a register message while session run. | ||
| + |     //        All objects were set false while initialising dispatcher and if | ||
| + |     //        they stay false their entries will be deleted next initialising. | ||
| + |     // actions: ["APPENDED", "INSERTED", "UPDATED"]; | ||
| + |     //--------------------------------------------------------------------------- | ||
| + |     GameObjectID dispgoid = me.GetGameObjectID(); | ||
| + |     string objecttype; | ||
| + |     GameObjectID objectgoid; | ||
| + |     //--------------------------------------------------------------------------- | ||
| + |   }; | ||
| + | |||
| + |   class acts_dispatcher_script isclass acts_dispatcher_globals | ||
| + |   { | ||
| + |     //--------------------------------------------------------------------------- | ||
| + |     public void SetProperties(Soup soup)   // Callback method after Init method | ||
| + |     { | ||
| + |       inherited(soup); | ||
| + |       //------------------------------------------------------------------------- | ||
| + |       DispatcherDataSoup.Copy(soup.GetNamedSoup("DispatcherData")); | ||
| + |       ContainerSoups.Copy(soup.GetNamedSoup("ContainerSoups")); | ||
| + |       ContstackSoups.Copy(soup.GetNamedSoup("ContstackSoups")); | ||
| + |       ContcraneSoups.Copy(soup.GetNamedSoup("ContcraneSoups")); | ||
| + |       //------------------------------------------------------------------------- | ||
| + |       isSetPropertiesMethodFinnished = true; | ||
| + |       PostMessage(me,"OBJECTINIT","SETPROPS_FINNISH",0); | ||
| + |       return; | ||
| + |     } | ||
| + |     //--------------------------------------------------------------------------- | ||
| + |     public Soup GetProperties(void)   // Callback method before closing session  | ||
| + |     { | ||
| + |       Soup soup = inherited(); | ||
| + |       //------------------------------------------------------------------------- | ||
| + |       DispatcherDataSoup.SetNamedTag("firstrun",false); | ||
| + |       //------------------------------------------------------------------------- | ||
| + |       soup.SetNamedSoup("DispatcherData",DispatcherDataSoup); | ||
| + |       soup.SetNamedSoup("ContainerSoups",ContainerSoups); | ||
| + |       soup.SetNamedSoup("ContstackSoups",ContstackSoups); | ||
| + |       soup.SetNamedSoup("ContcraneSoups",ContcraneSoups); | ||
| + |       //------------------------------------------------------------------------- | ||
| + |       return soup; | ||
| + |     }  | ||
| + |     //--------------------------------------------------------------------------- | ||
| + |     public void WorldInitHandler(Message msg) | ||
| + |     { | ||
| + |       if (acts_debug) Interface.Log(Interface.GetTimeStamp() | ||
| + |               + " [" + dispgoid.SerialiseToString() + "]" | ||
| + |               + " DISPATCHER GOT WORLDINIT MESSAGE [" | ||
| + |               + msg.major+"] ["+msg.minor+"]"); | ||
| + |       //------------------------------------------------------------------------- | ||
| + |       // If one of the two methods (Init or SetProperties) isn't finished yet,  | ||
| + |       // post "World","ModuleInit" message a little bit later again. | ||
| + |       // So it is guaranteed that the Init and SetProperties methods are finished | ||
| + |       // as well as the "World","ModuleInit" message tells to be save using the  | ||
| + |       // World.GetCurrentModule method. | ||
| + |       //------------------------------------------------------------------------- | ||
| + |       if (!(isSetPropertiesMethodFinnished and isInitMethodFinnished)) | ||
| + |       { | ||
| + |          //---------------------------------------------------------------------- | ||
| + |          // While first run and before first session save for libraries the  | ||
| + |          // SetProperties methon will not run, whle no soup stored. If this case | ||
| + |          // isn't handeled, the repost of "World","ModuleInit" runs infinitly. | ||
| + |          //---------------------------------------------------------------------- | ||
| + |          if (!DispatcherDataSoup.GetNamedTagAsBool("firstrun"))  | ||
| + |             PostMessage(me, "World", "ModuleInit", 0.1); | ||
| + |       } | ||
| + |       //------------------------------------------------------------------------- | ||
| + |       isWorldInitFinnished = true; | ||
| + |       PostMessage(me, "OBJECTINIT", "WORLD_INIT_FINNISHED", 0.0); | ||
| + |       //------------------------------------------------------------------------- | ||
| + |       return; | ||
| + |     } | ||
| + |     //--------------------------------------------------------------------------- | ||
| + |     public void ObjectInitHandler(Message msg) | ||
| + |     { | ||
| + |       //------------------------------------------------------------------------- | ||
| + |       // Until the Trainz core send the "World","ModuleInit" message it is not | ||
| + |       // guarented to decide with the World.GetCurrentModule method to be in the  | ||
| + |       // returned module!  | ||
| + |       //------------------------------------------------------------------------- | ||
| + |       if (acts_debug) Interface.Log(Interface.GetTimeStamp() | ||
| + |               + " [" + dispgoid.SerialiseToString() + "]" | ||
| + |               + " DISPATCHER GOT MESSAGE ["+msg.major+"] ["+msg.minor+"]"); | ||
| + |       //-------------------------------------------------------------------------*/ | ||
| + |       if (msg.dst==me and msg.major=="OBJECTINIT") | ||
| + |       { | ||
| + |         //----------------------------------------------------------------------- | ||
| + |         if (msg.minor=="INIT_FINNISHED") | ||
| + |         { | ||
| + |           //--------------------------------------------------------------------- | ||
| + |           // Not used yet | ||
| + |           //--------------------------------------------------------------------- | ||
| + |         } | ||
| + |         //----------------------------------------------------------------------- | ||
| + |         if (msg.minor=="SETPROPS_FINNISHED") | ||
| + |         { | ||
| + |           //--------------------------------------------------------------------- | ||
| + |           // If DispatcherDataSoup is empty, this is the first call unsaved call | ||
| + |           //--------------------------------------------------------------------- | ||
| + |           if (DispatcherDataSoup.CountTags()==0) | ||
| + |              DispatcherDataSoup.SetNamedTag("firstrun",true); | ||
| + |         } | ||
| + |         //----------------------------------------------------------------------- | ||
| + |         if (msg.minor=="WORLD_INIT_FINNISHED") | ||
| + |         { | ||
| + |           //--------------------------------------------------------------------- | ||
| + |           // Do no module only, driver module only or surveyor module only | ||
| + |           // related initiations | ||
| + |           //--------------------------------------------------------------------- | ||
| + |           if (World.GetCurrentModule() == World.DRIVER_MODULE) | ||
| + |           { | ||
| + |             //------------------------------------------------------------------- | ||
| + |             // Not used yet | ||
| + |             //------------------------------------------------------------------- | ||
| + |           } | ||
| + |           //--------------------------------------------------------------------- | ||
| + |           if (World.GetCurrentModule() == World.SURVEYOR_MODULE) | ||
| + |           { | ||
| + |             //------------------------------------------------------------------- | ||
| + |             // Not used yet | ||
| + |             //------------------------------------------------------------------- | ||
| + |           } | ||
| + |           //--------------------------------------------------------------------- | ||
| + |           if (World.GetCurrentModule() == World.NO_MODULE) | ||
| + |           { | ||
| + |             //------------------------------------------------------------------- | ||
| + |             // Not used yet | ||
| + |             //------------------------------------------------------------------- | ||
| + |           } | ||
| + |         } | ||
| + |       } | ||
| + |     } | ||
| + |     //--------------------------------------------------------------------------- | ||
| + |     // Search the objects soup for next free entry gap. Parameter dsp is the | ||
| + |     // object's type dispatcher sub soup (ContainerSoups, ContstackSoups or | ||
| + |     // ContcraneSoups). Method returns a soup. | ||
| + |     // soup { entry int, action string, active bool } | ||
| + |     //--------------------------------------------------------------------------- | ||
| + |     Soup FindObjectSoupEntry(GameObjectID goid, Soup dsp) | ||
| + |     { | ||
| + |       int entry; | ||
| + |       string action; | ||
| + |       Soup rsp = Constructors.NewSoup(); | ||
| + |       rsp.SetNamedTag("active",true); | ||
| + |       int i; | ||
| + |       for (i=0; i<dsp.CountTags(); i++) | ||
| + |       { | ||
| + |         entry = Str.ToInt(dsp.GetIndexedTagName(i)); | ||
| + |         Soup sp = dsp.GetNamedSoup(entry); | ||
| + |         if (sp.GetNamedTagAsGameObjectID("goid")==goid)   // TBD: goid compar ison | ||
| + |         { | ||
| + |           rsp.SetNamedTag("entry",entry); | ||
| + |           rsp.SetNamedTag("action","UPDATED"); | ||
| + |           return rsp; | ||
| + |         } | ||
| + |       } | ||
| + |       entry = actsTools.GetObjectSoupGap(dsp); | ||
| + |       if (entry==dsp.CountTags()) rsp.SetNamedTag("action","APPENDED"); | ||
| + |       else rsp.SetNamedTag("action","INSERTED"); | ||
| + |       rsp.SetNamedTag("entry",entry); | ||
| + |       return rsp; | ||
| + |     } | ||
| + |     //--------------------------------------------------------------------------- | ||
| + |     // Search the goid and update, insert or append the soup to register | ||
| + |     // Parameter osp is the posted ObjectDataSoup. The other three are the | ||
| + |     // dispatcher's object soups subsoups. | ||
| + |     //--------------------------------------------------------------------------- | ||
| + |     void AppendInsertUpdateObjectDataSoups(Soup osp, | ||
| + |                       Soup ContSps, Soup StackSps, Soup CraneSps) | ||
| + |     {  | ||
| + |       //------------------------------------------------------------------------- | ||
| + |       string type = osp.GetNamedTag("type"); | ||
| + |       GameObjectID objgoid = osp.GetNamedTagAsGameObjectID("type"); | ||
| + |       Soup objsps = Constructors.NewSoup(); | ||
| + |       if (type == "CONTAINER") objsps = ContSps; | ||
| + |       if (type == "CONTSTACK") objsps = StackSps; | ||
| + |       if (type == "CONTCRANE") objsps = CraneSps; | ||
| + |       Soup entry = FindObjectSoupEntry(objgoid, objsps); | ||
| + |       // entry { entry int, active bool, action string } | ||
| + |       // actions = ["APPENDED", "INSERTED", "UPDATED"]; | ||
| + |       osp.SetNamedTag("active", true); | ||
| + |       osp.SetNamedTag("action", entry.GetNamedTag("action")); | ||
| + |       objsps.SetNamedSoup(entry.GetNamedTagAsInt("entry"), osp); | ||
| + |       //------------------------------------------------------------------------- | ||
| + |       // Post retour that register is updated | ||
| + |       //------------------------------------------------------------------------- | ||
| + |       GameObject obj = Router.GetGameObject(objgoid); | ||
| + |       PostMessage(obj, "DISPATCHER", | ||
| + |                        "OBJECTSOUP_" + entry.GetNamedTag("action"), osp, 0.0); | ||
| + |       //------------------------------------------------------------------------- | ||
| + |       if (acts_debug) Interface.Log(Interface.GetTimeStamp() | ||
| + |               + " [" + dispgoid.SerialiseToString() + "]" | ||
| + |               + " DISPATCHER OBJECTSOUP " + entry.GetNamedTag("action")  | ||
| + |               + " " + type + " GOID [" + objgoid.SerialiseToString() + "]"); | ||
| + |       if (acts_debug) Interface.Log(Interface.GetTimeStamp() | ||
| + |               + " CONTENT OF " + entry.GetNamedTag("action") + " SOUP FROM GOID" | ||
| + |               + " [" + objgoid.SerialiseToString() + "]"); | ||
| + |       if (acts_debug) actsTools.ShowSoup(osp,"OSP=>");    | ||
| + |       //-------------------------------------------------------------------------*/ | ||
| + |       return; | ||
| + |     } | ||
| + |     //--------------------------------------------------------------------------- | ||
| + |     public void RegisterHandler(Message msg) | ||
| + |     { | ||
| + |       if (msg.dst==me and msg.major=="REGISTER") | ||
| + |       { | ||
| + |         //----------------------------------------------------------------------- | ||
| + |         if (acts_debug) Interface.Log(Interface.GetTimeStamp() | ||
| + |                 + " ["+dispgoid.SerialiseToString()+"]" | ||
| + |                 + " DISPATCHER GOT MESSAGE FROM OBJECT [" | ||
| + |                 + (cast<GameObject>msg.src).GetGameObjectID().SerialiseToString() | ||
| + |                 + "] [" + msg.major + "] [" + msg.minor + "]"); | ||
| + |         //-----------------------------------------------------------------------*/ | ||
| + |         if (msg.minor=="REGISTER_ME") | ||
| + |         { | ||
| + |           //--------------------------------------------------------------------- | ||
| + |           // Update, insert or append the ObjectDataSoup | ||
| + |           //--------------------------------------------------------------------- | ||
| + |           Soup RegDataSoup = Constructors.NewSoup(); | ||
| + |           RegDataSoup.Copy(cast<Soup>msg.paramSoup); | ||
| + |           //--------------------------------------------------------------------- | ||
| + |           if (acts_debug) Interface.Log(Interface.GetTimeStamp() | ||
| + |                         + " SOUP CONTENT OF 'DataSoup To Register' GOID" | ||
| + |                         + " [" + dispgoid.SerialiseToString() + "]"); | ||
| + |           if (acts_debug) actsTools.ShowSoup(RegDataSoup,"=>"); | ||
| + |           //--------------------------------------------------------------------- | ||
| + |           AppendInsertUpdateObjectDataSoups(RegDataSoup,  | ||
| + |                             ContainerSoups, ContstackSoups, ContcraneSoups); | ||
| + |           //--------------------------------------------------------------------- | ||
| + |           // TBD: Repost or update additional informations | ||
| + |           //   * CONTCRANE: Repost a goid list of reachable stacks. The contcrane | ||
| + |           //       itself informs the stacks about it's object data to update the | ||
| + |           //       maximum count of stackable containers. | ||
| + |           //   * CONTSTACK: ??? | ||
| + |           //   * CONTAINER: If a container has no stack place, randomly attach | ||
| + |           //       him to a free stack place and repost it. In case there is no | ||
| + |           //       one, repost an empty stack goid with place zero. | ||
| + |           //       TBD: What happens if the stack it attached to does not exist? | ||
| + |           //            Possibly handled as a free container?        | ||
| + |           //--------------------------------------------------------------------- | ||
| + |         } | ||
| + |         //----------------------------------------------------------------------- | ||
| + |       } | ||
| + |       return; | ||
| + |     } | ||
| + |   }; | ||
| + | |||
| + |   class acts_dispatcher isclass acts_dispatcher_script | ||
| + |   { | ||
| + |     public void Init() | ||
| + |     { | ||
| + |       inherited(); | ||
| + |       //------------------------------------------------------------------------- | ||
| + |       // Make shure that the right module is set for World.GetCurrentModle() | ||
| + |       // (see world.gs lines 939ff.) to start driver only or surveyor only | ||
| + |       // related initiations and tell me, if my Init and SetProperties methods | ||
| + |       // are finished | ||
| + |       //------------------------------------------------------------------------- | ||
| + |       AddHandler(me, "World", "ModuleInit", "WorldInitHandler"); | ||
| + |       AddHandler(me, "OBJECTINIT", "", "ObjectInitHandler"); | ||
| + |       AddHandler(me, "REGISTER",   "", "RegisterHandler"); | ||
| + |       //------------------------------------------------------------------------- | ||
| + |       // Set asset special initial values | ||
| + |       //------------------------------------------------------------------------- | ||
| + |       objecttype = "DISPATCHER"; | ||
| + |       //------------------------------------------------------------------------- | ||
| + |       isInitMethodFinnished = true; | ||
| + |       PostMessage(me,"OBJECTINIT","INIT_FINNISHED",0.0);   // Init method finnished | ||
| + |       return; | ||
| + |     } | ||
| + |   }; | ||
| + | </CODE> | ||
| + | |||
| + | ===acts_global_values.gs=== | ||
| + | <CODE> | ||
| + |   include "mapobject.gs" | ||
| + | |||
| + |   //----------------------------------------------------------------------------- | ||
| + |   // Common aCTS values V0.1 - Dispatcher, Container, Stack, Crane Tools Script | ||
| + |   //----------------------------------------------------------------------------- | ||
| + | |||
| + |   class acts_global_values isclass MapObject | ||
| + |   { | ||
| + |     //--------------------------------------------------------------------------- | ||
| + |     // Global variables | ||
| + |     //--------------------------------------------------------------------------- | ||
| + |     bool acts_debug = true; | ||
| + |     //--------------------------------------------------------------------------- | ||
| + |     float baseboardwidth = 720; | ||
| + |     //--------------------------------------------------------------------------- | ||
| + |     // Technical values from normatives | ||
| + |     // -------------------------------------------------------------------------- | ||
| + |     int container_length_10ft =  2991;   // in [mm] | ||
| + |     int container_length_20ft =  6058;   // in [mm] | ||
| + |     int container_length_40ft = 12192;   // in [mm] | ||
| + |     int container_length_45ft = 13716;   // in [mm] | ||
| + |     int container_length_53ft = 16154;   // in [mm] | ||
| + |     // -------------------------------------------------------------------------- | ||
| + |     int container_width   = 2438;   // in [mm] | ||
| + |     int container_height  = 2591;   // in [mm] | ||
| + |     int container_deltahc =  305;   // in [mm] | ||
| + |     // -------------------------------------------------------------------------- | ||
| + |     bool isWorldInitFinnished = false; | ||
| + |     bool isInitMethodFinnished = false; | ||
| + |     bool isSetPropertiesMethodFinnished = false; | ||
| + |     //--------------------------------------------------------------------------- | ||
| + |   }; | ||
| + | </CODE> | ||
| + | |||
| + | ===acts_tools_script.gs.gs=== | ||
| + | <CODE> | ||
| + |   include "acts_global_values.gs" | ||
| + | |||
| + |   //----------------------------------------------------------------------------- | ||
| + |   // Common aCTS methods V0.1 - Dispatcher, Container, Stack, Crane Tools Script | ||
| + |   //----------------------------------------------------------------------------- | ||
| + | |||
| + |   final static class actsTools isclass acts_global_values | ||
| + |   { | ||
| + |     //--------------------------------------------------------------------------- | ||
| + |     // Log soup content of a soup of soups only and without subsoups | ||
| + |     //--------------------------------------------------------------------------- | ||
| + |     public void ShowSoup(Soup sp, string ind) | ||
| + |     { | ||
| + |       if (sp.CountTags()!=0) | ||
| + |       { | ||
| + |         int i; | ||
| + |         for (i=0; i<sp.CountTags(); i++) | ||
| + |           if (acts_debug) Interface.Log(ind + sp.GetIndexedTagName(i) | ||
| + |                   + " ["+sp.GetNamedTag(sp.GetIndexedTagName(i))+"]"); | ||
| + |       } | ||
| + |       return; | ||
| + |     } | ||
| + |     public void ShowSoups(Soup soup, string indent) | ||
| + |     { | ||
| + |       string ind = "="+indent; | ||
| + |       int sc = soup.CountTags(); | ||
| + |       int i; | ||
| + |       for (i=0; i<sc; i++) | ||
| + |       { | ||
| + |         if (acts_debug) Interface.Log(indent + i + ".SubSoup"); | ||
| + |         actsTools.ShowSoup(soup.GetNamedSoup(i),ind); | ||
| + |       } | ||
| + |       return; | ||
| + |     } | ||
| + |     //--------------------------------------------------------------------------- | ||
| + |     // Set all ObjectSoups active false and get the last insert gap | ||
| + |     // TBD: Starting with a sorted soup  | ||
| + |     //--------------------------------------------------------------------------- | ||
| + |     public void ResetObjectSoups(Soup soup) | ||
| + |     { | ||
| + |       int i; | ||
| + |       int gap = soup.CountTags();; | ||
| + |       for (i=0; i<soup.CountTags(); i++) | ||
| + |       { | ||
| + |         int tn = Str.ToInt(soup.GetIndexedTagName(i)); | ||
| + |         Soup sp = soup.GetNamedSoup(tn); | ||
| + |         if (sp.GetNamedTagAsBool("active")) | ||
| + |         { | ||
| + |           sp.SetNamedTag("active",false); | ||
| + |           soup.SetNamedSoup(tn,sp); | ||
| + |         } else soup.RemoveNamedTag(tn);  | ||
| + |       } | ||
| + |       return; | ||
| + |     } | ||
| + |     //--------------------------------------------------------------------------- | ||
| + |     // Return the first indexed gap in existing objectsoups tagnames | ||
| + |     //--------------------------------------------------------------------------- | ||
| + |     public int GetObjectSoupGap(Soup soup) | ||
| + |     { | ||
| + |       int i; | ||
| + |       for (i=0; i<soup.CountTags(); i++) | ||
| + |         if (soup.GetIndexForNamedTag(i)==-1) return i; | ||
| + |       return soup.CountTags(); | ||
| + |     } | ||
| + |     //--------------------------------------------------------------------------- | ||
| + |     // Generate soup representation from WorldCoordinate | ||
| + |     //--------------------------------------------------------------------------- | ||
| + |     public Soup WCoordToSoup(WorldCoordinate pos) | ||
| + |     { | ||
| + |       Soup sp = Constructors.NewSoup(); | ||
| + |       sp.SetNamedTag("bbx",pos.baseboardX); | ||
| + |       sp.SetNamedTag("bby",pos.baseboardY); | ||
| + |       sp.SetNamedTag("px",pos.x); | ||
| + |       sp.SetNamedTag("py",pos.y); | ||
| + |       sp.SetNamedTag("pz",pos.z); | ||
| + |       return sp; | ||
| + |     } | ||
| + |     //--------------------------------------------------------------------------- | ||
| + |     // Generate WorldCoordinate from its soup representation | ||
| + |     //--------------------------------------------------------------------------- | ||
| + |     public WorldCoordinate WCoordFromSoup(Soup sp) | ||
| + |     { | ||
| + |       WorldCoordinate WC; | ||
| + |       WC.baseboardX = sp.GetNamedTagAsInt("bbx"); | ||
| + |       WC.baseboardY = sp.GetNamedTagAsInt("bby"); | ||
| + |       WC.x = sp.GetNamedTagAsFloat("px"); | ||
| + |       WC.y = sp.GetNamedTagAsFloat("py"); | ||
| + |       WC.z = sp.GetNamedTagAsFloat("pz"); | ||
| + |       return WC; | ||
| + |     } | ||
| + |     //--------------------------------------------------------------------------- | ||
| + |     // Normalize the WC to baseboard width | ||
| + |     //--------------------------------------------------------------------------- | ||
| + |     public WorldCoordinate WCoordNormalize(WorldCoordinate WC) | ||
| + |     { | ||
| + |       WorldCoordinate nWC; | ||
| + |       //------------------------------------------------------------------------- | ||
| + |       int bx = WC.x * 1000.0 / baseboardwidth;   // Basebord delta | ||
| + |       if (WC.x < 0.0) bx--; | ||
| + |       nWC.baseboardX = WC.baseboardX + bx; | ||
| + |       nWC.x = WC.x - bx * baseboardwidth; | ||
| + |       //------------------------------------------------------------------------- | ||
| + |       int by = WC.y * 1000.0 / baseboardwidth;   // Basebord delta | ||
| + |       if (WC.y < 0.0) by--; | ||
| + |       nWC.baseboardY = WC.baseboardX + by; | ||
| + |       nWC.y = WC.y - by * baseboardwidth; | ||
| + |       //------------------------------------------------------------------------- | ||
| + |       nWC.z = WC.z; | ||
| + |       return nWC; | ||
| + |     } | ||
| + |     //--------------------------------------------------------------------------- | ||
| + |     // Adjust baseboard from one WorlCoordinate to another | ||
| + |     //--------------------------------------------------------------------------- | ||
| + |     public WorldCoordinate  | ||
| + |            WCoordAdjustBaseboard(WorldCoordinate frWC, WorldCoordinate toWC) | ||
| + |     { | ||
| + |       WorldCoordinate adjWC; | ||
| + |       //------------------------------------------------------------------------- | ||
| + |       adjWC.x = toWC.x + (frWC.baseboardX - toWC.baseboardX)*baseboardwidth; | ||
| + |       adjWC.baseboardX = frWC.baseboardX; | ||
| + |       adjWC.y = toWC.y + (frWC.baseboardY - toWC.baseboardY)*baseboardwidth; | ||
| + |       adjWC.baseboardY = frWC.baseboardY; | ||
| + |       adjWC.z = toWC.z; | ||
| + |       //------------------------------------------------------------------------- | ||
| + |       return adjWC; | ||
| + |     } | ||
| + |     //--------------------------------------------------------------------------- | ||
| + |     // Generate soup representation from Orientation | ||
| + |     //--------------------------------------------------------------------------- | ||
| + |     public Soup OrientationToSoup(Orientation rot) | ||
| + |     { | ||
| + |       Soup sp = Constructors.NewSoup(); | ||
| + |       sp.SetNamedTag("gx",rot.rx * 1800.0 / Math.PI); | ||
| + |       sp.SetNamedTag("gy",rot.ry * 1800.0 / Math.PI); | ||
| + |       sp.SetNamedTag("gz",rot.rz * 1800.0 / Math.PI); | ||
| + |       sp.SetNamedTag("rx",rot.rx); | ||
| + |       sp.SetNamedTag("ry",rot.ry); | ||
| + |       sp.SetNamedTag("rz",rot.rz); | ||
| + |       return sp; | ||
| + |     } | ||
| + |     //--------------------------------------------------------------------------- | ||
| + |     // Generate Orientation from its soup representation | ||
| + |     //--------------------------------------------------------------------------- | ||
| + |     public Orientation OrientationFromSoup(Soup sp) | ||
| + |     { | ||
| + |       Orientation OR; | ||
| + |       OR.rx = sp.GetNamedTagAsFloat("rx"); | ||
| + |       OR.ry = sp.GetNamedTagAsFloat("ry"); | ||
| + |       OR.rz = sp.GetNamedTagAsFloat("rz"); | ||
| + |       return OR; | ||
| + |     } | ||
| + |     //--------------------------------------------------------------------------- | ||
| + |     // Adjust location and orientation to even mm and even 1/10° inplace | ||
| + |     //--------------------------------------------------------------------------- | ||
| + |     public bool AutoAdjustTransformation(WorldCoordinate W, Orientation O) | ||
| + |     { | ||
| + |       float rd; | ||
| + |       bool changed = false; | ||
| + |       if (W.x<0) rd=-0.0005; else rd=0.0005;   // rounding to full [mm] | ||
| + |       int wcx = (W.x+rd) * 1000.0; | ||
| + |       if (W.y<0) rd=-0.0005; else rd=0.0005; | ||
| + |       int wcy = (W.y+rd) * 1000.0; | ||
| + |       if (W.z<0) rd=-0.0005; else rd=0.0005; | ||
| + |       int wcz = (W.z+rd) * 1000.0; | ||
| + |       // rounding to full [1/10°] - here only z-axis, x,y-axis are set to zero | ||
| + |       // to make shure the CTS is horizontal plane | ||
| + |       if (O.rz<0) rd=-0.5; else rd=0.5; | ||
| + |       int orz = O.rz * 1800.0 / Math.PI + rd; | ||
| + |       if (W.x != wcx/1000.0) {W.x = wcx/1000.0; changed=true; } | ||
| + |       if (W.y != wcy/1000.0) {W.y = wcy/1000.0; changed=true; } | ||
| + |       if(W.z != 0.0) { W.z = 0.0; changed=true; } | ||
| + |       if(O.rx != 0.0) { O.rx = 0.0; changed=true; } | ||
| + |       if(O.ry != 0.0) { O.ry = 0.0; changed=true; } | ||
| + |       if(O.rz != orz * Math.PI / 1800.0)  | ||
| + |       { O.rz = orz * Math.PI / 1800.0; changed=true; } | ||
| + |       //------------------------------------------------------------------------- | ||
| + |       return changed; | ||
| + |     } | ||
| + |     //--------------------------------------------------------------------------- | ||
| + |     // Auto adjust WorldCoordinate and Orientation to [mm] and [1/10°] | ||
| + |     // Adjusts the object and returns original and adjusted WC and OR as soup. | ||
| + |     //--------------------------------------------------------------------------- | ||
| + |     public Soup AutoAdjustMapObject(MapObject M) | ||
| + |     { | ||
| + |       //------------------------------------------------------------------------- | ||
| + |       // M = cast<MapObject>(me); | ||
| + |       //------------------------------------------------------------------------- | ||
| + |       bool changed = false;     | ||
| + |       Soup sp = Constructors.NewSoup(); | ||
| + |       WorldCoordinate W = M.GetMapObjectPosition(); | ||
| + |       Orientation     O = M.GetMapObjectOrientation(); | ||
| + |       sp.SetNamedSoup("OriginalLocationSoup", WCoordToSoup(W)); | ||
| + |       sp.SetNamedSoup("OriginalOrientationSoup", OrientationToSoup(O)); | ||
| + |       changed = AutoAdjustTransformation(W,O); | ||
| + |       M.SetMapObjectPosition(W); | ||
| + |       M.SetMapObjectOrientation(O); | ||
| + |       sp.SetNamedSoup("AdjustedLocationSoup", WCoordToSoup(W)); | ||
| + |       sp.SetNamedSoup("AdjustedOrientationSoup", OrientationToSoup(O)); | ||
| + |       sp.SetNamedTag("changed", changed); | ||
| + |       //------------------------------------------------------------------------- | ||
| + |       return sp; | ||
| + |     } | ||
| + |   }; | ||
| + | </CODE> | ||
| [[Category:ACTS]] | [[Category:ACTS]] | ||
Revision as of 00:56, 25 April 2024
TBD: Update text
TBD: Repost or update additional informations after reposting the registered objectsoup. * CONTCRANE: Repost a goid list of reachable stacks. The contcrane itself informs the stacks about it's object data to update the maximum count of stackable containers. * CONTSTACK: ??? * CONTAINER: If a container has no stack place, randomly attach him to a free stack place and repost it. In case there is no one, repost an empty stack goid with place zero. TBD: What happens if the stack it attached to does not exist? Possibly handled as a free container?
| Contents | 
Asset files pre version 0.1
The files compile errorless and the messaging runs well. No more functionality implemented and tested in this pre version.
config.txt
 kuid               <kuid2:215489:110000:1>
 username           "aCTS DISPATCHER Library V1"
 kind               "Library"
 category-class     "YL"
 trainz-build       4.6
 
 description        "aCTS DISPATCHER Library V1"
 
 script             "acts_dispatcher.gs"
 class              "acts_dispatcher"
 
 thumbnails
 {
   0
   {
     image          "acts_dispatcher_thumb.jpg"
     width          240
     height         180
   }
 } 
acts_dispatcher.gs
 include "acts_global_values.gs"
 include "acts_tools_script.gs"
 
 //-----------------------------------------------------------------------------
 // aCTS Dispatcher V0.1 Central Script - acts_dispatcher
 //-----------------------------------------------------------------------------
 // X acts_dispatcher             <-- acts_dispatcher_script
 // X acts_dispatcher_script      <-- acts_dispatcher_globals
 // X acts_dispatcher_globals     <-- acts_global_values
 //   acts_global_values          <-- MapObject
 //-----------------------------------------------------------------------------
 
 //-----------------------------------------------------------------------------
 class acts_dispatcher_globals isclass acts_global_values
 {
   //---------------------------------------------------------------------------
   // Store from dispatcher received object registration values to the 
   // respective dispatchers sub soup. The sub soups register ids run as int  
   // from 0 ... The received id -1 tells, that the object isn't yet
   // registered.
   //---------------------------------------------------------------------------
   // Because the register id number list gets gaps while unregistering it will
   // be nessecary to have some gap filling methods additionally. See
   // AppendInsertUpdateObjectDataSoups and FindObjectSoupEntry methods.
   //---------------------------------------------------------------------------
   // AssetInstanceSoup {
   //   ObjectDataSoup { ... },    Only container, contstack, contcrane
   //   LocationSoup { ... },      Only container, contstack, contcrane
   //   OrientationSoup { ... },   Only container, contstack, contcrane
   //   SkinDataSoup { ... },      Only container
   //   ContentDataSoup { ... },   Only container
   // X DispatcherDataSoup { ... } Only dispatcher
   // X ContainerSoups  { ... }    Only dispatcher
   // X ContstackSoups  { ... }    Only dispatcher
   // X ContcraneSoups  { ... }    Only dispatcher
   // }
   //---------------------------------------------------------------------------
   Soup ContainerSoups = Constructors.NewSoup();
   Soup ContstackSoups = Constructors.NewSoup();
   Soup ContcraneSoups = Constructors.NewSoup();
   //---------------------------------------------------------------------------
   Soup DispatcherDataSoup = Constructors.NewSoup();
   //---------------------------------------------------------------------------
   // ObjectDataSoup received from and posted to objects.
   //---------------------------------------------------------------------------
   // ObjectDataSoup { goid GameObjectID, type string, dispID int,
   //                  length int, height int,
   //                  stack goid, place int,           Only container
   //                  active bool, action string },
   // activ: true means the object sended a register message while session run.
   //        All objects were set false while initialising dispatcher and if
   //        they stay false their entries will be deleted next initialising.
   // actions: ["APPENDED", "INSERTED", "UPDATED"];
   //---------------------------------------------------------------------------
   GameObjectID dispgoid = me.GetGameObjectID();
   string objecttype;
   GameObjectID objectgoid;
   //---------------------------------------------------------------------------
 };
 
 class acts_dispatcher_script isclass acts_dispatcher_globals
 {
   //---------------------------------------------------------------------------
   public void SetProperties(Soup soup)   // Callback method after Init method
   {
     inherited(soup);
     //-------------------------------------------------------------------------
     DispatcherDataSoup.Copy(soup.GetNamedSoup("DispatcherData"));
     ContainerSoups.Copy(soup.GetNamedSoup("ContainerSoups"));
     ContstackSoups.Copy(soup.GetNamedSoup("ContstackSoups"));
     ContcraneSoups.Copy(soup.GetNamedSoup("ContcraneSoups"));
     //-------------------------------------------------------------------------
     isSetPropertiesMethodFinnished = true;
     PostMessage(me,"OBJECTINIT","SETPROPS_FINNISH",0);
     return;
   }
   //---------------------------------------------------------------------------
   public Soup GetProperties(void)   // Callback method before closing session 
   {
     Soup soup = inherited();
     //-------------------------------------------------------------------------
     DispatcherDataSoup.SetNamedTag("firstrun",false);
     //-------------------------------------------------------------------------
     soup.SetNamedSoup("DispatcherData",DispatcherDataSoup);
     soup.SetNamedSoup("ContainerSoups",ContainerSoups);
     soup.SetNamedSoup("ContstackSoups",ContstackSoups);
     soup.SetNamedSoup("ContcraneSoups",ContcraneSoups);
     //-------------------------------------------------------------------------
     return soup;
   } 
   //---------------------------------------------------------------------------
   public void WorldInitHandler(Message msg)
   {
     if (acts_debug) Interface.Log(Interface.GetTimeStamp()
             + " [" + dispgoid.SerialiseToString() + "]"
             + " DISPATCHER GOT WORLDINIT MESSAGE ["
             + msg.major+"] ["+msg.minor+"]");
     //-------------------------------------------------------------------------
     // If one of the two methods (Init or SetProperties) isn't finished yet, 
     // post "World","ModuleInit" message a little bit later again.
     // So it is guaranteed that the Init and SetProperties methods are finished
     // as well as the "World","ModuleInit" message tells to be save using the 
     // World.GetCurrentModule method.
     //-------------------------------------------------------------------------
     if (!(isSetPropertiesMethodFinnished and isInitMethodFinnished))
     {
        //----------------------------------------------------------------------
        // While first run and before first session save for libraries the 
        // SetProperties methon will not run, whle no soup stored. If this case
        // isn't handeled, the repost of "World","ModuleInit" runs infinitly.
        //----------------------------------------------------------------------
        if (!DispatcherDataSoup.GetNamedTagAsBool("firstrun")) 
           PostMessage(me, "World", "ModuleInit", 0.1);
     }
     //-------------------------------------------------------------------------
     isWorldInitFinnished = true;
     PostMessage(me, "OBJECTINIT", "WORLD_INIT_FINNISHED", 0.0);
     //-------------------------------------------------------------------------
     return;
   }
   //---------------------------------------------------------------------------
   public void ObjectInitHandler(Message msg)
   {
     //-------------------------------------------------------------------------
     // Until the Trainz core send the "World","ModuleInit" message it is not
     // guarented to decide with the World.GetCurrentModule method to be in the 
     // returned module! 
     //-------------------------------------------------------------------------
     if (acts_debug) Interface.Log(Interface.GetTimeStamp()
             + " [" + dispgoid.SerialiseToString() + "]"
             + " DISPATCHER GOT MESSAGE ["+msg.major+"] ["+msg.minor+"]");
     //-------------------------------------------------------------------------*/
     if (msg.dst==me and msg.major=="OBJECTINIT")
     {
       //-----------------------------------------------------------------------
       if (msg.minor=="INIT_FINNISHED")
       {
         //---------------------------------------------------------------------
         // Not used yet
         //---------------------------------------------------------------------
       }
       //-----------------------------------------------------------------------
       if (msg.minor=="SETPROPS_FINNISHED")
       {
         //---------------------------------------------------------------------
         // If DispatcherDataSoup is empty, this is the first call unsaved call
         //---------------------------------------------------------------------
         if (DispatcherDataSoup.CountTags()==0)
            DispatcherDataSoup.SetNamedTag("firstrun",true);
       }
       //-----------------------------------------------------------------------
       if (msg.minor=="WORLD_INIT_FINNISHED")
       {
         //---------------------------------------------------------------------
         // Do no module only, driver module only or surveyor module only
         // related initiations
         //---------------------------------------------------------------------
         if (World.GetCurrentModule() == World.DRIVER_MODULE)
         {
           //-------------------------------------------------------------------
           // Not used yet
           //-------------------------------------------------------------------
         }
         //---------------------------------------------------------------------
         if (World.GetCurrentModule() == World.SURVEYOR_MODULE)
         {
           //-------------------------------------------------------------------
           // Not used yet
           //-------------------------------------------------------------------
         }
         //---------------------------------------------------------------------
         if (World.GetCurrentModule() == World.NO_MODULE)
         {
           //-------------------------------------------------------------------
           // Not used yet
           //-------------------------------------------------------------------
         }
       }
     }
   }
   //---------------------------------------------------------------------------
   // Search the objects soup for next free entry gap. Parameter dsp is the
   // object's type dispatcher sub soup (ContainerSoups, ContstackSoups or
   // ContcraneSoups). Method returns a soup.
   // soup { entry int, action string, active bool }
   //---------------------------------------------------------------------------
   Soup FindObjectSoupEntry(GameObjectID goid, Soup dsp)
   {
     int entry;
     string action;
     Soup rsp = Constructors.NewSoup();
     rsp.SetNamedTag("active",true);
     int i;
     for (i=0; i<dsp.CountTags(); i++)
     {
       entry = Str.ToInt(dsp.GetIndexedTagName(i));
       Soup sp = dsp.GetNamedSoup(entry);
       if (sp.GetNamedTagAsGameObjectID("goid")==goid)   // TBD: goid compar ison
       {
         rsp.SetNamedTag("entry",entry);
         rsp.SetNamedTag("action","UPDATED");
         return rsp;
       }
     }
     entry = actsTools.GetObjectSoupGap(dsp);
     if (entry==dsp.CountTags()) rsp.SetNamedTag("action","APPENDED");
     else rsp.SetNamedTag("action","INSERTED");
     rsp.SetNamedTag("entry",entry);
     return rsp;
   }
   //---------------------------------------------------------------------------
   // Search the goid and update, insert or append the soup to register
   // Parameter osp is the posted ObjectDataSoup. The other three are the
   // dispatcher's object soups subsoups.
   //---------------------------------------------------------------------------
   void AppendInsertUpdateObjectDataSoups(Soup osp,
                     Soup ContSps, Soup StackSps, Soup CraneSps)
   { 
     //-------------------------------------------------------------------------
     string type = osp.GetNamedTag("type");
     GameObjectID objgoid = osp.GetNamedTagAsGameObjectID("type");
     Soup objsps = Constructors.NewSoup();
     if (type == "CONTAINER") objsps = ContSps;
     if (type == "CONTSTACK") objsps = StackSps;
     if (type == "CONTCRANE") objsps = CraneSps;
     Soup entry = FindObjectSoupEntry(objgoid, objsps);
     // entry { entry int, active bool, action string }
     // actions = ["APPENDED", "INSERTED", "UPDATED"];
     osp.SetNamedTag("active", true);
     osp.SetNamedTag("action", entry.GetNamedTag("action"));
     objsps.SetNamedSoup(entry.GetNamedTagAsInt("entry"), osp);
     //-------------------------------------------------------------------------
     // Post retour that register is updated
     //-------------------------------------------------------------------------
     GameObject obj = Router.GetGameObject(objgoid);
     PostMessage(obj, "DISPATCHER",
                      "OBJECTSOUP_" + entry.GetNamedTag("action"), osp, 0.0);
     //-------------------------------------------------------------------------
     if (acts_debug) Interface.Log(Interface.GetTimeStamp()
             + " [" + dispgoid.SerialiseToString() + "]"
             + " DISPATCHER OBJECTSOUP " + entry.GetNamedTag("action") 
             + " " + type + " GOID [" + objgoid.SerialiseToString() + "]");
     if (acts_debug) Interface.Log(Interface.GetTimeStamp()
             + " CONTENT OF " + entry.GetNamedTag("action") + " SOUP FROM GOID"
             + " [" + objgoid.SerialiseToString() + "]");
     if (acts_debug) actsTools.ShowSoup(osp,"OSP=>");   
     //-------------------------------------------------------------------------*/
     return;
   }
   //---------------------------------------------------------------------------
   public void RegisterHandler(Message msg)
   {
     if (msg.dst==me and msg.major=="REGISTER")
     {
       //-----------------------------------------------------------------------
       if (acts_debug) Interface.Log(Interface.GetTimeStamp()
               + " ["+dispgoid.SerialiseToString()+"]"
               + " DISPATCHER GOT MESSAGE FROM OBJECT ["
               + (cast<GameObject>msg.src).GetGameObjectID().SerialiseToString()
               + "] [" + msg.major + "] [" + msg.minor + "]");
       //-----------------------------------------------------------------------*/
       if (msg.minor=="REGISTER_ME")
       {
         //---------------------------------------------------------------------
         // Update, insert or append the ObjectDataSoup
         //---------------------------------------------------------------------
         Soup RegDataSoup = Constructors.NewSoup();
         RegDataSoup.Copy(cast<Soup>msg.paramSoup);
         //---------------------------------------------------------------------
         if (acts_debug) Interface.Log(Interface.GetTimeStamp()
                       + " SOUP CONTENT OF 'DataSoup To Register' GOID"
                       + " [" + dispgoid.SerialiseToString() + "]");
         if (acts_debug) actsTools.ShowSoup(RegDataSoup,"=>");
         //---------------------------------------------------------------------
         AppendInsertUpdateObjectDataSoups(RegDataSoup, 
                           ContainerSoups, ContstackSoups, ContcraneSoups);
         //---------------------------------------------------------------------
         // TBD: Repost or update additional informations
         //   * CONTCRANE: Repost a goid list of reachable stacks. The contcrane
         //       itself informs the stacks about it's object data to update the
         //       maximum count of stackable containers.
         //   * CONTSTACK: ???
         //   * CONTAINER: If a container has no stack place, randomly attach
         //       him to a free stack place and repost it. In case there is no
         //       one, repost an empty stack goid with place zero.
         //       TBD: What happens if the stack it attached to does not exist?
         //            Possibly handled as a free container?       
         //---------------------------------------------------------------------
       }
       //-----------------------------------------------------------------------
     }
     return;
   }
 };
 
 class acts_dispatcher isclass acts_dispatcher_script
 {
   public void Init()
   {
     inherited();
     //-------------------------------------------------------------------------
     // Make shure that the right module is set for World.GetCurrentModle()
     // (see world.gs lines 939ff.) to start driver only or surveyor only
     // related initiations and tell me, if my Init and SetProperties methods
     // are finished
     //-------------------------------------------------------------------------
     AddHandler(me, "World", "ModuleInit", "WorldInitHandler");
     AddHandler(me, "OBJECTINIT", "", "ObjectInitHandler");
     AddHandler(me, "REGISTER",   "", "RegisterHandler");
     //-------------------------------------------------------------------------
     // Set asset special initial values
     //-------------------------------------------------------------------------
     objecttype = "DISPATCHER";
     //-------------------------------------------------------------------------
     isInitMethodFinnished = true;
     PostMessage(me,"OBJECTINIT","INIT_FINNISHED",0.0);   // Init method finnished
     return;
   }
 };
acts_global_values.gs
 include "mapobject.gs"
 
 //-----------------------------------------------------------------------------
 // Common aCTS values V0.1 - Dispatcher, Container, Stack, Crane Tools Script
 //-----------------------------------------------------------------------------
 
 class acts_global_values isclass MapObject
 {
   //---------------------------------------------------------------------------
   // Global variables
   //---------------------------------------------------------------------------
   bool acts_debug = true;
   //---------------------------------------------------------------------------
   float baseboardwidth = 720;
   //---------------------------------------------------------------------------
   // Technical values from normatives
   // --------------------------------------------------------------------------
   int container_length_10ft =  2991;   // in [mm]
   int container_length_20ft =  6058;   // in [mm]
   int container_length_40ft = 12192;   // in [mm]
   int container_length_45ft = 13716;   // in [mm]
   int container_length_53ft = 16154;   // in [mm]
   // --------------------------------------------------------------------------
   int container_width   = 2438;   // in [mm]
   int container_height  = 2591;   // in [mm]
   int container_deltahc =  305;   // in [mm]
   // --------------------------------------------------------------------------
   bool isWorldInitFinnished = false;
   bool isInitMethodFinnished = false;
   bool isSetPropertiesMethodFinnished = false;
   //---------------------------------------------------------------------------
 };
acts_tools_script.gs.gs
 include "acts_global_values.gs"
 
 //-----------------------------------------------------------------------------
 // Common aCTS methods V0.1 - Dispatcher, Container, Stack, Crane Tools Script
 //-----------------------------------------------------------------------------
 
 final static class actsTools isclass acts_global_values
 {
   //---------------------------------------------------------------------------
   // Log soup content of a soup of soups only and without subsoups
   //---------------------------------------------------------------------------
   public void ShowSoup(Soup sp, string ind)
   {
     if (sp.CountTags()!=0)
     {
       int i;
       for (i=0; i<sp.CountTags(); i++)
         if (acts_debug) Interface.Log(ind + sp.GetIndexedTagName(i)
                 + " ["+sp.GetNamedTag(sp.GetIndexedTagName(i))+"]");
     }
     return;
   }
   public void ShowSoups(Soup soup, string indent)
   {
     string ind = "="+indent;
     int sc = soup.CountTags();
     int i;
     for (i=0; i<sc; i++)
     {
       if (acts_debug) Interface.Log(indent + i + ".SubSoup");
       actsTools.ShowSoup(soup.GetNamedSoup(i),ind);
     }
     return;
   }
   //---------------------------------------------------------------------------
   // Set all ObjectSoups active false and get the last insert gap
   // TBD: Starting with a sorted soup 
   //---------------------------------------------------------------------------
   public void ResetObjectSoups(Soup soup)
   {
     int i;
     int gap = soup.CountTags();;
     for (i=0; i<soup.CountTags(); i++)
     {
       int tn = Str.ToInt(soup.GetIndexedTagName(i));
       Soup sp = soup.GetNamedSoup(tn);
       if (sp.GetNamedTagAsBool("active"))
       {
         sp.SetNamedTag("active",false);
         soup.SetNamedSoup(tn,sp);
       } else soup.RemoveNamedTag(tn); 
     }
     return;
   }
   //---------------------------------------------------------------------------
   // Return the first indexed gap in existing objectsoups tagnames
   //---------------------------------------------------------------------------
   public int GetObjectSoupGap(Soup soup)
   {
     int i;
     for (i=0; i<soup.CountTags(); i++)
       if (soup.GetIndexForNamedTag(i)==-1) return i;
     return soup.CountTags();
   }
   //---------------------------------------------------------------------------
   // Generate soup representation from WorldCoordinate
   //---------------------------------------------------------------------------
   public Soup WCoordToSoup(WorldCoordinate pos)
   {
     Soup sp = Constructors.NewSoup();
     sp.SetNamedTag("bbx",pos.baseboardX);
     sp.SetNamedTag("bby",pos.baseboardY);
     sp.SetNamedTag("px",pos.x);
     sp.SetNamedTag("py",pos.y);
     sp.SetNamedTag("pz",pos.z);
     return sp;
   }
   //---------------------------------------------------------------------------
   // Generate WorldCoordinate from its soup representation
   //---------------------------------------------------------------------------
   public WorldCoordinate WCoordFromSoup(Soup sp)
   {
     WorldCoordinate WC;
     WC.baseboardX = sp.GetNamedTagAsInt("bbx");
     WC.baseboardY = sp.GetNamedTagAsInt("bby");
     WC.x = sp.GetNamedTagAsFloat("px");
     WC.y = sp.GetNamedTagAsFloat("py");
     WC.z = sp.GetNamedTagAsFloat("pz");
     return WC;
   }
   //---------------------------------------------------------------------------
   // Normalize the WC to baseboard width
   //---------------------------------------------------------------------------
   public WorldCoordinate WCoordNormalize(WorldCoordinate WC)
   {
     WorldCoordinate nWC;
     //-------------------------------------------------------------------------
     int bx = WC.x * 1000.0 / baseboardwidth;   // Basebord delta
     if (WC.x < 0.0) bx--;
     nWC.baseboardX = WC.baseboardX + bx;
     nWC.x = WC.x - bx * baseboardwidth;
     //-------------------------------------------------------------------------
     int by = WC.y * 1000.0 / baseboardwidth;   // Basebord delta
     if (WC.y < 0.0) by--;
     nWC.baseboardY = WC.baseboardX + by;
     nWC.y = WC.y - by * baseboardwidth;
     //-------------------------------------------------------------------------
     nWC.z = WC.z;
     return nWC;
   }
   //---------------------------------------------------------------------------
   // Adjust baseboard from one WorlCoordinate to another
   //---------------------------------------------------------------------------
   public WorldCoordinate 
          WCoordAdjustBaseboard(WorldCoordinate frWC, WorldCoordinate toWC)
   {
     WorldCoordinate adjWC;
     //-------------------------------------------------------------------------
     adjWC.x = toWC.x + (frWC.baseboardX - toWC.baseboardX)*baseboardwidth;
     adjWC.baseboardX = frWC.baseboardX;
     adjWC.y = toWC.y + (frWC.baseboardY - toWC.baseboardY)*baseboardwidth;
     adjWC.baseboardY = frWC.baseboardY;
     adjWC.z = toWC.z;
     //-------------------------------------------------------------------------
     return adjWC;
   }
   //---------------------------------------------------------------------------
   // Generate soup representation from Orientation
   //---------------------------------------------------------------------------
   public Soup OrientationToSoup(Orientation rot)
   {
     Soup sp = Constructors.NewSoup();
     sp.SetNamedTag("gx",rot.rx * 1800.0 / Math.PI);
     sp.SetNamedTag("gy",rot.ry * 1800.0 / Math.PI);
     sp.SetNamedTag("gz",rot.rz * 1800.0 / Math.PI);
     sp.SetNamedTag("rx",rot.rx);
     sp.SetNamedTag("ry",rot.ry);
     sp.SetNamedTag("rz",rot.rz);
     return sp;
   }
   //---------------------------------------------------------------------------
   // Generate Orientation from its soup representation
   //---------------------------------------------------------------------------
   public Orientation OrientationFromSoup(Soup sp)
   {
     Orientation OR;
     OR.rx = sp.GetNamedTagAsFloat("rx");
     OR.ry = sp.GetNamedTagAsFloat("ry");
     OR.rz = sp.GetNamedTagAsFloat("rz");
     return OR;
   }
   //---------------------------------------------------------------------------
   // Adjust location and orientation to even mm and even 1/10° inplace
   //---------------------------------------------------------------------------
   public bool AutoAdjustTransformation(WorldCoordinate W, Orientation O)
   {
     float rd;
     bool changed = false;
     if (W.x<0) rd=-0.0005; else rd=0.0005;   // rounding to full [mm]
     int wcx = (W.x+rd) * 1000.0;
     if (W.y<0) rd=-0.0005; else rd=0.0005;
     int wcy = (W.y+rd) * 1000.0;
     if (W.z<0) rd=-0.0005; else rd=0.0005;
     int wcz = (W.z+rd) * 1000.0;
     // rounding to full [1/10°] - here only z-axis, x,y-axis are set to zero
     // to make shure the CTS is horizontal plane
     if (O.rz<0) rd=-0.5; else rd=0.5;
     int orz = O.rz * 1800.0 / Math.PI + rd;
     if (W.x != wcx/1000.0) {W.x = wcx/1000.0; changed=true; }
     if (W.y != wcy/1000.0) {W.y = wcy/1000.0; changed=true; }
     if(W.z != 0.0) { W.z = 0.0; changed=true; }
     if(O.rx != 0.0) { O.rx = 0.0; changed=true; }
     if(O.ry != 0.0) { O.ry = 0.0; changed=true; }
     if(O.rz != orz * Math.PI / 1800.0) 
     { O.rz = orz * Math.PI / 1800.0; changed=true; }
     //-------------------------------------------------------------------------
     return changed;
   }
   //---------------------------------------------------------------------------
   // Auto adjust WorldCoordinate and Orientation to [mm] and [1/10°]
   // Adjusts the object and returns original and adjusted WC and OR as soup.
   //---------------------------------------------------------------------------
   public Soup AutoAdjustMapObject(MapObject M)
   {
     //-------------------------------------------------------------------------
     // M = cast<MapObject>(me);
     //-------------------------------------------------------------------------
     bool changed = false;    
     Soup sp = Constructors.NewSoup();
     WorldCoordinate W = M.GetMapObjectPosition();
     Orientation     O = M.GetMapObjectOrientation();
     sp.SetNamedSoup("OriginalLocationSoup", WCoordToSoup(W));
     sp.SetNamedSoup("OriginalOrientationSoup", OrientationToSoup(O));
     changed = AutoAdjustTransformation(W,O);
     M.SetMapObjectPosition(W);
     M.SetMapObjectOrientation(O);
     sp.SetNamedSoup("AdjustedLocationSoup", WCoordToSoup(W));
     sp.SetNamedSoup("AdjustedOrientationSoup", OrientationToSoup(O));
     sp.SetNamedTag("changed", changed);
     //-------------------------------------------------------------------------
     return sp;
   }
 };
