Named Objects Library
Named Objects Library (SP2 and later)
The Named Objects Library is a library that may be used to manage information about available named objects in the current session. The library can manage cached data for several common objects type, which can be individually asynchronously refreshed in the background using threads inside the library, and can return at any time synchronously the content of any of the managed caches.
Usually, an asset using the Named Objects Library will first load and initialize the library in its init routine, will then register the objects type to be cached in the library (which will immediately start the asynchronous process of collecting the cached data for this object type), and will later use the cached data by calling the library to retrieve the current cached data. The library uses all the new object search API available since Tane SP2 and will automaticly refresh in the background any expired cache data. Also under surveyor mode, all cached data are refreshed every 5 seconds to include new added objects edited under surveyor ; under driver mode only consists cached data are refreshed every 5 seconds to ensure that consists emited from portals are added to the cached data.
Named Objects Library has been designed and developped to support the new search request Tane SP2 API for all the assets by pguy. It is not a general purpose API interface but an adapted interface to make Tane SP2 migration easy for pguy's assets. The API is now published and public, as it may be interesting for some other scripters that have not already done this migration to use this library for their own migration to the new interfaces.
The present article is for scripters who wants to use the Named Objects Library and give details below on how to configure an asset to use the Named Objects Library, on how to initialise in an asset the library and on how to register the objects type you want to cache, and finaly on how later to retrieve the current content of a cache for a specific object type.
Named Objects Library : How to use it ?
To use the Named Object Library in any of your assets, you need first to modify its config.txt file to add the Named Objects Library in its kuid table section and in its script include table so that your asset can reference the Named Objects Library to import the Named Object Library API as a static class nochelper contained in nochelper.gs inside the Named Objects Library Asset.
The current Named Objects Library available on DLS is <kuid2:61392:4053:10> but there will be soon a new release 11 <kuid2:61392:4053:11> that will bring supports for track circuit blocks objects.
Your asset config.txt file should include the following sections to be able to load the Named Objects Library API as nochelper static class :
script-include-table { . . . noclib <kuid:61392:4053> . . . }
and
kuid-table { . . . noclib <kuid2:61392:4053:10> . . . }
with these two modifications in your asset config.txt file, you should now be able to import the noclib API by adding :
import "nochelper.gs"
to your assets script files needing to call the noclib API
Named Objects Library : How to initialise it ?
Now that we have imported the file "nochelper.gs" in your scripts, all other needed steps will be done by calling some API functions defined in the nochelper static class.
First, you need to initialise the library by calling
public void Init(Asset p_asset) ;
this call is mandatory with p_asset being the current asset that will use the library. You can check that the initialisation has been successfull by calling
public bool IsLibraryAvailable(void) ;
that will return true if the library has been initialised and false if it is not the case. These calls are generally made inside your asset init function but can be located else where as long as they are done before any other call to the library.
For example, your asset init function may look like :
public void Init(Asset p_asset) { . . . my asset initialisation code . . . nochelper.Init(p_asset) ; if (!nochelper.IsLibraryAvailable()) { . . . my asset error code for noclib not available . . . } . . . }
Named Objects Library : How to register the objects type you want to be cached by the library
The Named Objects Library currently supports 13 objects type that are defined in nochelper static class as integer values :
public define int NOC_TRACKMARK = 1 ; // for trackmarks names public define int NOC_TRACKMARK_LIST = 2 ; // for trackmark list names public define int NOC_TRIGGER = 4 ; // for triggers public define int NOC_SIGNAL = 8 ; // for signals public define int NOC_JUNCTION = 16 ; // for junctions public define int NOC_CROSSING = 32 ; // for crossings public define int NOC_TCB = 64 ; // for track circuit block detector public define int NOC_ITS = 128 ; // for interlocking towers public define int NOC_CONSIST = 512 ; // for trains or consists public define int NOC_VEHICLE = 1024 ; // for vehicles public define int NOC_INDUSTRY = 4096 ; // for industries public define int NOC_STATION = 8192 ; // for passenger stations public define int NOC_PORTAL = 16384 ; // for portals
A cache in the library is defined by its objects type integer value and by a searchFilter string. After being refreshed, a cache will contain an array of NamedObjectInfo objects containing all available objects matching the cache objects type and whose name begin by the search filter. If the search filter is empty (blank string) all the objects matching the cache objects type are returned.
To add an object type and searchFilter to be cached by the library, you only need to call one of these functions :
public int AddNamedObjectsTypeToCache(int cacheType, string searchFilter, bool autoupdate, float period, GameObject notifyGameObject) ; public int AddNamedObjectsTypeToCache(int cacheType, string searchFilter, bool autoupdate, float period) ; public int AddNamedObjectsTypeToCache(int cacheType,GameObject notifyGameObject) ; public int AddNamedObjectsTypeToCache(int cacheType) ;
where cacheType defines the type of objects to be cached searchfilter is an optional string to limit the search to all objects whose name are prefixed by searchfilter autoupdate is now an obsolete bool parameter that will be ignored. autoupdate is always done in surveyor mode every 5 seconds and only for consists in driver mode every 5 seconds. notifyGameObject is an optional GameObject reference that will receive a message "Noclib","CacheRefreshComplete" when the cached data will be available (Cf RefreshNamedObjectsCache below)
When a AddNamedObjectsTypeToCache call is made to the library, the library checks if there has been already a similar call made earlier by another asset. If it is the case, the library will reuse the already existing cached data array ; if it is not the case it will create the new cached data array. In all cases it will start an implicit refresh cache operation to collect or refresh the available information on the existing objects matching both the cache objects type and the searchfilter prefix.
The integer value returned is a sequential number for the implicit refresh operation that can be later used to check if the asynchronous cache refresh operation is complete.
The cache refresh operations are optimized by the library. If several cache refresh operations for the same cache type and search filter are pending when the asynchronous refresh thread starts its operation, all the pending cache refresh operations are merged in only one refresh operation notifying all the requesters.
Depending on the number of objects to scan and retrieve in your route, the duration of a cache refresh operation may last from a few miliseconds to several seconds.
If you want to be sure that the implicit cache refresh operation is complete, you will need to wait for the "Noclib","CacheRefreshComplete" message to be received by the notifyGameObject and check that the parameter soup included in the message has the expected cache type (cachetype tag), search filter (searchfilter tag) and refresh serial value (refreshserialvalue tag) for the cache refresh operation just being completed.
It is also possible to call IsNamedObjectsCacheRefreshComplete described later in this documentation with the cache type, search filter and refresh sequential number to check.
Cached data supports the search results expiry notification option included in Tane SP2 and will redo an automatic cache refresh operation if the current cached data expires. This means that rename or deletion of objects should be detected and cached data will be then refreshed. New objects added are not so easily detected : that is why all cached data is refreshed every 5 seconds in surveyor mode and only consist cached data is refreshed every 5 seconds in driver mode, so that cached data contains the most recent data with a latency of 5 seconds for performance reason.
AddNamedObjectsTypeToCache are generally located in the Init function of your asset and you need to make one call for each of the objects type to be cached.
for example, if you want to cache both interlocking towers and consists, you will have in your asset init function :
public void Init(Asset p_asset) { . . . my asset initialisation code . . . nochelper.Init(p_asset) ; if (!nochelper.IsLibraryAvailable()) { . . . my asset error code for noclib not available . . . } AddNamedObjectsTypeToCache(nochelper.NOC_ITS) ; AddNamedObjectsTypeToCache(nochelper.NOC_CONSIST) ; }
Named Objects Library : How to retrieve the cached objects
Now that we have added the objects we want to be managed in the cache, the last step is to call the library to retrieve the data currently in the cache
To retrieve the data currently in cache, you will call this function :
public NamedObjectInfo[] GetNamedObjects(int cacheType,string searchFilter) ; // returns named objects cache with filter public NamedObjectInfo[] GetNamedObjects(int cacheType) ; // returns named objects cache
where cacheType defines the type of objects to be retrieved searchfilter is an optional string to limit the search to only objects whose name are prefixed by searchfilter
These calls returns an array of NamedObjectInfo containing all the current data for the target cacheType and searchFilter.
For readers who do not already know NamedObjectInfo class data, NamedObjectInfo class object is a class defined in World.gs that is used to return available data on exisisting objects in a route and session. You will find below its class definition extracted from World.gs :
//============================================================================= // Name: NamedObjectInfo // Desc: The result type used by AsyncObjectSearchResult, see below for more. //============================================================================= final class NamedObjectInfo { public GameObject objectRef; // A reference to the object, if it's loaded public GameObjectID objectId; // The unique ID of the object public string localisedUsername; // The display name for the object, in the current language public string categoryString; // The category code string for the object };
For each object returned, NamedObjectInfo gives you its reference if loaded, its unique GameObjectID, its display name and its category list string for future search.
Take care that reference to the object may be no longer valid if the object has been unloaded since the information was cached, and you should check if the reference is still valid by calling
bool isStillValid = Router.DoesGameObjectStillExist(GameObject obj);
before using the object reference. If the reference is null or is no longer valid, you can retrieve a reference on the object by calling some functions in world.gs using the unique object gameobjectid :
public native GameObject GetGameObjectByIDIfLoaded(GameObjectID objectID); will return a GameObject reference if the object is currently loaded and null if it is no longer loaded public GameObject SynchronouslyLoadGameObjectByID(GameObjectID objectID) ; will load the gameobject and return the new gameobject reference. This primitive can only be called under a thread
for example, if you want to loop on all existing interlocking towers, you will use the following code :
. . . NameObjectInfo[] itInfos = nochelper.GetNamedObjects(nochelper.NOC_ITS) ; if (itInfos.size()) for (I=0;i<itInfos.size();I++) { . . . processing to be done on each itInfos . . . }
Named Objects Library : How to refresh the cached objects
In order to refresh a named objects cache you will call one of these functions :
public int RefreshNamedObjectsCache(int cacheType, string searchFilter, GameObject postGameObject) ; // refresh cached type with post option public int RefreshNamedObjectsCache(int cacheType, GameObject postGameObject) ; // refresh cached type with post option public int RefreshNamedObjectsCache(int cacheType) ; // refresh cached type
where cacheType defines the type of objects to be refreshed searchfilter is an optional string to limit the search to only objects whose name are prefixed by searchfilter postGameObject is an optional GameObject that will be notified that the cache refresh operation is complete by receiving a message "Noclib","CacheRefreshComplete" from the library
The integer value returned is a unique refresh sequential serial number that can be used later to check if the cache refresh operation is complete. If you want to be sure that the cache refresh operation is complete, you will need to wait for the "Noclib","CacheRefreshComplete" message to be received by the postGameObject and check that the parameter soup included in the message has the expected cache type (cachetype tag), search filter (searchfilter tag) and refresh serial value (refreshserialvalue tag) for the cache refresh operation just being completed. It is also possible to call IsNamedObjectsCacheRefreshComplete described later in this documentation with the cache type, search filter and refresh sequential number to check the cache refresh completion.
It is not needed to call RefreshNamedObjectsCache(. . .) just after a AddNamedObjectsToCache(. . .) as the AddNamedObjectsToCache processing includes already an implicit RefreshNamedObjectsCache call to initialise the cached data.
It is also possible to check if a cache refresh is complete by calling one of these functions :
public bool IsNamedObjectsCacheRefreshComplete(int cacheType, string searchFilter, int refreshSerialValue, GameObject postGameObject) ; public bool IsNamedObjectsCacheRefreshComplete(int cacheType, string searchFilter, GameObject postGameObject) ; public bool IsNamedObjectsCacheRefreshComplete(int cacheType, GameObject postGameObject) ; public bool IsNamedObjectsCacheRefreshComplete(int cacheType, string searchFilter) ; public bool IsNamedObjectsCacheRefreshComplete(int cacheType) ;
where cacheType and searchFilter defines the cache objects type to be checked refreshSerialValue is an integer value identifying the cache refresh operation to check, which has been retuned by a previous RefreshNamedObjectsCache or AddNamedObjectsToCache request. postGameObject is an optional GameObject that will be notified that the cache refresh operation is now complete by receiving a message "Noclib","CacheRefreshComplete" from the library if the cache refresh operation is still in progress.
Named Objects Library : alternative RetrieveNamedObjects API
The above API is fine for regular recurrent request to retrieve available named objects and using cache techniques it enables to optimize scripts by sharing data between multiple assets and to offer synchronous answers to requests that have been pre fetched asynchronously.
But sometimes scripts needs to make a non recurrent request for some specific objects for which caching is not usefull.
The alternative RetrieveNamedObjects API has been added to the Named Objects Library recently (in version 10) for this purpose. You can call it this way, if you are executing under a thread :
public NamedObjectInfo[] RetrieveNamedObjects(int cacheType,string searchFilter,bool searchInCache,bool keepInCache) ; public NamedObjectInfo[] RetrieveNamedObjects(int cacheType,bool searchInCache,bool keepInCache) ; public NamedObjectInfo[] RetrieveNamedObjects(int cacheType,string searchFilter) ; public NamedObjectInfo[] RetrieveNamedObjects(int cacheType) ;
where cacheType is the type of objects you want to retrieve searchFilter is the prefix for the objects to be searched searchInCache is a bool option to try to retrieve first the objects in the cached data keepInCache is a bool option to update the cached data if a new search request has been done
As you may have guess, these functions can be called even if no objects of cacheType have been added to the named objects cache library. RetrieveNamedObjects needs to be called under a thread. If searchInCache is true, it will first try to find a cache in the library matching cacheType and searchFilter. If it finds one, it will return the current cache data. If it does not find one or if searchInCache is false, it will start a new asynchronous search request for these objects and will wait for the end of this search request. If keepInCache is set to true, it will copy the results to any matching existing cache in the library or will create a new cached data in the library to keep the data in cache for future use. And it will finaly return the results to the caller.
This function may be more easy to use for callers under a thread and for specific request done only once and not recurrent between assets.
public NamedObjectInfo[] RetrieveNamedObjects(int cacheType,string[] searchFilters,bool searchInCache,bool keepInCache) ; public NamedObjectInfo[] RetrieveNamedObjects(int cacheType,string[] searchFilters) ;
These functions enables to return in a unique NamedObjectInof array objects of rthe same cacheType matching several searchFilters with some results coming from already existing data cached and other results being only new search results not cached.
Named Objects Library : other miscellaneous functions
The nochelper class includes also a few other specific functions :
public NamedObjectInfo[] GetTrackMarksInList(string sList) ; can be called to retrieve trackmarks belonging to a specific trackmark list. Needs NOC_TRACKMARK_LIST to be currently cached. This primitive is needed for DriveToTrackMarkList driver command. public int GetPlatformsCountForStation(string stationName) ; can be called to retrieve the number of platforms for a virtual passenger station name. Needs NOC_STATION to be currently cached. This primitive is needed for DriveToStation driver command. public GameObjectID GetPlatformsStationID(string sVirtualPlatformName); can be called to retrieve the real station GameObjectID for a virtual platform name. Needs NOC_STATION to be currently cached. This primitive is needed for DriveToStation driver command. public string GetPlatformsTrack(string sVirtualPlatformName) ; can be called to retrieve the real track name for a virtual platform name. Needs NOC_STATION to be currently loaded This primitive is needed for DriveToStation driver command.