HowTo/Upgrade obsolete script functions
(Created page with "This page serves as a hub for how to upgrade/replace uses of various obsolete script functions.") |
|||
(23 intermediate revisions by 3 users not shown) | |||
Line 1: | Line 1: | ||
This page serves as a hub for how to upgrade/replace uses of various obsolete script functions. | This page serves as a hub for how to upgrade/replace uses of various obsolete script functions. | ||
+ | |||
+ | Note that this is not a comprehensive list. Trainz has existed for more than two decades and there are dozens of obsolete script functions as a result. This guide aims to cover only the more complex upgrade cases, where the replacement functions may not be immediately obvious, or may be considerably more difficult to use. | ||
+ | |||
+ | __NOEDITSECTION__ | ||
+ | ==GameObject.GetId== | ||
+ | '''Previous Usage'''<br> | ||
+ | Returns a numeric ID used to identify a GameObject within the script context. This ID is not consistent between Route/Session loads and cannot be used for long term storage. | ||
+ | |||
+ | '''Reason for Obsoletion'''<br> | ||
+ | With the advent of [[Asynchronous_Route_Streaming|Route streaming]] world objects may now be unloaded/reloaded during gameplay, and these IDs can be reused by different objects. This makes the ID itself unreliable, and uses of it are better served by more modern functions. | ||
+ | |||
+ | '''Replacement Function'''<br> | ||
+ | Standard uses of the integer ID can be swapped to using the objects GameObjectID instead. Call GameObject.GetGameObject() to get the ID. | ||
+ | |||
+ | '''Further Reading''' | ||
+ | * See GameObjectID.gs in your Trainz installations resources/script folder for more information on the GameObjectID class. | ||
+ | * See [[HowTo/Upgrade_GameObject.GetId()]] for a practical example of how to replace some common integer ID uses with GameObjectID. | ||
+ | |||
+ | ==GameObject.GetName== | ||
+ | '''Previous Usage'''<br> | ||
+ | Returns a string ID used to identify a GameObject within the script context. This ID is automatically generated by Trainz code, using the object type or asset name as a prefix. It can generally be considered constant between runs of the game, and was therefore suitable for long term storage. | ||
+ | |||
+ | '''Reason for Obsoletion'''<br> | ||
+ | This script name was often confused for the objects localised (translatable) name, and (despite script comments to the contrary) was never truly guaranteed unique. | ||
+ | |||
+ | '''Replacement Function'''<br> | ||
+ | Cases which use of the script name as an ID can be swapped to using the objects GameObjectID instead. Cases which use it for display to the player should instead use the localised name. | ||
+ | |||
+ | '''Further Reading''' | ||
+ | * See GameObjectID.gs in your Trainz installations resources/script folder for more information on the GameObjectID class. | ||
+ | * See [[HowTo/Upgrade_GameObject.GetName()]] for a practical example of how to replace some common script name uses with GameObjectID or localised name. | ||
+ | |||
+ | ==Library.LibraryCall== | ||
+ | '''Previous Usage'''<br> | ||
+ | An alternate version of the [[Class_Library#LibraryCall|LibraryCall]] interface which accepts GameObject parameters instead of GSObject. This function was added as obsolete, in order to highlight scripts which were mistakenly calling LibraryCall with a GameObject array, and relying on the script compiler to implicitly cast the type. | ||
+ | |||
+ | '''Reason for Obsoletion'''<br> | ||
+ | This function was added as obsolete, in order to highlight otherwise hard-to-diagnose issues with failing implicit casts. | ||
+ | |||
+ | '''Replacement Function'''<br> | ||
+ | Cases which are found to call this variant should be updated to call the non-obsolete LibraryCall function, by declaring the objectParam as a GSObject array.<br> | ||
+ | Cases which are found to override this variant should be updated to instead override the GSObject variant, but changing the function prototype and updating any uses of the objectParam as required. This may mean adding new explicit casts, and care should be taken to validate that those casts succeed.<br> | ||
+ | |||
+ | '''Further Reading''' | ||
+ | * See the [[Class_Library|Library class documentation]] for more information on the Library class and the LibraryCall interface. | ||
+ | |||
+ | ==Router.GetGameObject== | ||
+ | '''Previous Usage'''<br> | ||
+ | Returns a GameObject instance from either it's script name or integer ID. | ||
+ | |||
+ | '''Reason for Obsoletion'''<br> | ||
+ | As both GetId() and GetName() are obsolete, both the string and int variants of this function are also obsolete. See GameObject.GetId and GameObject.GetName above for more information. | ||
+ | |||
+ | '''Replacement Function'''<br> | ||
+ | All uses of the integer ID and script name identifiers should be replaced with GameObjectID. To retrieve an GameObject which is currently loaded into memory, a script may then call Router.GetGameObject(GameObjectID) or World.GetGameObjectByIDIfLoaded(GameObjectID). | ||
+ | |||
+ | If a script requires access to an object which may not be loaded, it may call World.GetGameObjectByID(GameObjectID) to request that native code loads the object. Note that this requires native code to load the entire tile/section that the object is in, which may impact performance, and may take some time. As the call may take a while, it behaves asynchronously, returning a [[Class_AsyncObjectSearchResult|AsyncObjectSearchResult]] to the caller. | ||
+ | |||
+ | '''Further Reading''' | ||
+ | * See GameObjectID.gs in your Trainz installations resources/script folder for more information on the GameObjectID class. | ||
+ | * See [[HowTo/Upgrade_GameObject.GetName()]] for a practical example of how to upgrade uses of Router.GetGameObject(string). | ||
+ | |||
+ | ==World.Get*List== | ||
+ | '''Previous Usage'''<br> | ||
+ | These functions (e.g. World.GetJunctionList()) were used to return a list of a particular type of items within the World. | ||
+ | |||
+ | '''Reason for Obsoletion'''<br> | ||
+ | The functions represented a considerable performance hit, especially on large Routes. With the advent of [[Asynchronous_Route_Streaming|Route streaming]] they are also only able to return objects which are currently loaded, limiting their usefulness. | ||
+ | |||
+ | '''Replacement Function'''<br> | ||
+ | Due to the inherent performance concerns it is no longer possible to synchronously query for a list of objects within the world. Instead, an asynchronous interface now exists to run searches for objects of a particular type or name, World.GetNamedObjectList(). This function takes a category string and partial name, and returns a list of matching objects. Both parameters are optional, but at least one must be provided. The function returns a [[Class_AsyncObjectSearchResult|AsyncObjectSearchResult]] to the caller. | ||
+ | |||
+ | '''Further Reading''' | ||
+ | * See [[HowTo/Search_for_objects_in_the_world]] for a practical example of how to list objects using category codes. | ||
+ | |||
+ | ==Asset.GetConfigSoup== | ||
+ | '''Previous Usage'''<br> | ||
+ | This function returns the config.txt file for an asset, as a Soup object. | ||
+ | |||
+ | '''Reason for Obsoletion'''<br> | ||
+ | Calls to this function may require loading an asset config file from disk, which can be very slow (in computational terms). For this reason, the function has been marked obsolete to avoid performance issues in script. | ||
+ | |||
+ | '''Replacement Function'''<br> | ||
+ | A new async query interface exists on Asset which will cache the config file on a background thread. To use this feature script must first call Asset.CacheConfigSoup(), and then wait on the returned AsyncQueryHelper. When the caching is complete, the caller may call Asset.GetConfigSoupCached() to get the config file Soup. | ||
+ | |||
+ | '''Further Reading''' | ||
+ | * See [[HowTo/Read string table or Config text]] for more clarifications. | ||
+ | |||
+ | ==Asset.GetStringTable== | ||
+ | '''Previous Usage'''<br> | ||
+ | This function returns the localised string-table from the config.txt file for an asset. | ||
+ | |||
+ | '''Reason for Obsoletion'''<br> | ||
+ | Calls to this function may require loading an asset config file from disk, which can be very slow (in computational terms). For this reason, the function has been marked obsolete to avoid performance issues in script. | ||
+ | |||
+ | '''Replacement Function'''<br> | ||
+ | A new async query interface exists on Asset which will cache the config file on a background thread. To use this feature script must first call Asset.CacheConfigSoup(), and then wait on the returned AsyncQueryHelper. When the caching is complete, the caller may call Asset.GetStringTable() to get the StringTable. | ||
+ | |||
+ | '''Further Reading''' | ||
+ | * See [[HowTo/Read string table or Config text]] for more clarifications. | ||
+ | |||
+ | ==TrainzScript.GetAssetList== | ||
+ | '''Previous Usage'''<br> | ||
+ | This function is used to return a list of installed assets of a given kind (e.g. "signal"). | ||
+ | |||
+ | '''Reason for Obsoletion'''<br> | ||
+ | Asset searches can be very slow, and this function was marked obsolete for performance reasons. | ||
+ | |||
+ | '''Replacement Function'''<br> | ||
+ | A much more powerful asset search system exists in [[Class_TrainzAssetSearch|TrainzAssetSearch]]. This class allows script to asynchronously search on any criteria, eliminating the performance concerns. | ||
+ | |||
+ | ==TrainzScript.SearchAssets== | ||
+ | '''Previous Usage'''<br> | ||
+ | This function is used to return a list of assets of a given asset category filter. | ||
+ | |||
+ | '''Reason for Obsoletion'''<br> | ||
+ | Asset searches can be very slow, and this function was marked obsolete for performance reasons. | ||
+ | |||
+ | '''Replacement Function'''<br> | ||
+ | A much more powerful asset search system exists in [[Class_TrainzAssetSearch|TrainzAssetSearch]]. This class allows script to asynchronously search on any criteria, eliminating the performance concerns. | ||
+ | |||
+ | ==Router.MESSAGE_BROADCAST== | ||
+ | '''Previous Usage'''<br> | ||
+ | This pseudo router ID was used to post a message to ALL game objects. | ||
+ | |||
+ | '''Reason for Obsoletion'''<br> | ||
+ | Broadcasting is inefficient by nature, and the same effects can be achieved by having scripts listen (via Sniff() or AddHandler()) to the specific objects and messages that they're interested in. Additionally, game objects have a limited message queue capacity, so with large numbers of objects broadcasting it was common to overflow the message queues and permanently lose messages, leading to unexpected and unpredictable outcomes. Finally, with [[Asynchronous Route Streaming]], broadcasts do not actually reach all objects in the route. | ||
+ | |||
+ | '''Replacement Function'''<br> | ||
+ | No replacement functionality is required. Scripts should use the existing PostMessage(), Sniff, AddHandler() and similar functionality instead of broadcasting. This should be kept to the minimum necessary to achieve the desired goal. | ||
+ | In order to support interoperability with legacy scripts that expect message broadcasts, the LegacyBroadcastMessage() function can be used in parallel with any updated mechanisms. | ||
+ | |||
+ | |||
+ | ==See Also== | ||
+ | * [[TrainzScript_Language_Reference|TrainzScript Language Reference]] | ||
+ | * [[Compatibility_mode|Compatibility Mode Setting]] | ||
+ | * [[Asynchronous_Route_Streaming| Asynchronous Route Streaming]] | ||
+ | * [[HowTo/Upgrade obsolete script functions - simple examples]] |
Latest revision as of 21:58, 11 August 2023
This page serves as a hub for how to upgrade/replace uses of various obsolete script functions.
Note that this is not a comprehensive list. Trainz has existed for more than two decades and there are dozens of obsolete script functions as a result. This guide aims to cover only the more complex upgrade cases, where the replacement functions may not be immediately obvious, or may be considerably more difficult to use.
Contents |
GameObject.GetId
Previous Usage
Returns a numeric ID used to identify a GameObject within the script context. This ID is not consistent between Route/Session loads and cannot be used for long term storage.
Reason for Obsoletion
With the advent of Route streaming world objects may now be unloaded/reloaded during gameplay, and these IDs can be reused by different objects. This makes the ID itself unreliable, and uses of it are better served by more modern functions.
Replacement Function
Standard uses of the integer ID can be swapped to using the objects GameObjectID instead. Call GameObject.GetGameObject() to get the ID.
Further Reading
- See GameObjectID.gs in your Trainz installations resources/script folder for more information on the GameObjectID class.
- See HowTo/Upgrade_GameObject.GetId() for a practical example of how to replace some common integer ID uses with GameObjectID.
GameObject.GetName
Previous Usage
Returns a string ID used to identify a GameObject within the script context. This ID is automatically generated by Trainz code, using the object type or asset name as a prefix. It can generally be considered constant between runs of the game, and was therefore suitable for long term storage.
Reason for Obsoletion
This script name was often confused for the objects localised (translatable) name, and (despite script comments to the contrary) was never truly guaranteed unique.
Replacement Function
Cases which use of the script name as an ID can be swapped to using the objects GameObjectID instead. Cases which use it for display to the player should instead use the localised name.
Further Reading
- See GameObjectID.gs in your Trainz installations resources/script folder for more information on the GameObjectID class.
- See HowTo/Upgrade_GameObject.GetName() for a practical example of how to replace some common script name uses with GameObjectID or localised name.
Library.LibraryCall
Previous Usage
An alternate version of the LibraryCall interface which accepts GameObject parameters instead of GSObject. This function was added as obsolete, in order to highlight scripts which were mistakenly calling LibraryCall with a GameObject array, and relying on the script compiler to implicitly cast the type.
Reason for Obsoletion
This function was added as obsolete, in order to highlight otherwise hard-to-diagnose issues with failing implicit casts.
Replacement Function
Cases which are found to call this variant should be updated to call the non-obsolete LibraryCall function, by declaring the objectParam as a GSObject array.
Cases which are found to override this variant should be updated to instead override the GSObject variant, but changing the function prototype and updating any uses of the objectParam as required. This may mean adding new explicit casts, and care should be taken to validate that those casts succeed.
Further Reading
- See the Library class documentation for more information on the Library class and the LibraryCall interface.
Router.GetGameObject
Previous Usage
Returns a GameObject instance from either it's script name or integer ID.
Reason for Obsoletion
As both GetId() and GetName() are obsolete, both the string and int variants of this function are also obsolete. See GameObject.GetId and GameObject.GetName above for more information.
Replacement Function
All uses of the integer ID and script name identifiers should be replaced with GameObjectID. To retrieve an GameObject which is currently loaded into memory, a script may then call Router.GetGameObject(GameObjectID) or World.GetGameObjectByIDIfLoaded(GameObjectID).
If a script requires access to an object which may not be loaded, it may call World.GetGameObjectByID(GameObjectID) to request that native code loads the object. Note that this requires native code to load the entire tile/section that the object is in, which may impact performance, and may take some time. As the call may take a while, it behaves asynchronously, returning a AsyncObjectSearchResult to the caller.
Further Reading
- See GameObjectID.gs in your Trainz installations resources/script folder for more information on the GameObjectID class.
- See HowTo/Upgrade_GameObject.GetName() for a practical example of how to upgrade uses of Router.GetGameObject(string).
World.Get*List
Previous Usage
These functions (e.g. World.GetJunctionList()) were used to return a list of a particular type of items within the World.
Reason for Obsoletion
The functions represented a considerable performance hit, especially on large Routes. With the advent of Route streaming they are also only able to return objects which are currently loaded, limiting their usefulness.
Replacement Function
Due to the inherent performance concerns it is no longer possible to synchronously query for a list of objects within the world. Instead, an asynchronous interface now exists to run searches for objects of a particular type or name, World.GetNamedObjectList(). This function takes a category string and partial name, and returns a list of matching objects. Both parameters are optional, but at least one must be provided. The function returns a AsyncObjectSearchResult to the caller.
Further Reading
- See HowTo/Search_for_objects_in_the_world for a practical example of how to list objects using category codes.
Asset.GetConfigSoup
Previous Usage
This function returns the config.txt file for an asset, as a Soup object.
Reason for Obsoletion
Calls to this function may require loading an asset config file from disk, which can be very slow (in computational terms). For this reason, the function has been marked obsolete to avoid performance issues in script.
Replacement Function
A new async query interface exists on Asset which will cache the config file on a background thread. To use this feature script must first call Asset.CacheConfigSoup(), and then wait on the returned AsyncQueryHelper. When the caching is complete, the caller may call Asset.GetConfigSoupCached() to get the config file Soup.
Further Reading
- See HowTo/Read string table or Config text for more clarifications.
Asset.GetStringTable
Previous Usage
This function returns the localised string-table from the config.txt file for an asset.
Reason for Obsoletion
Calls to this function may require loading an asset config file from disk, which can be very slow (in computational terms). For this reason, the function has been marked obsolete to avoid performance issues in script.
Replacement Function
A new async query interface exists on Asset which will cache the config file on a background thread. To use this feature script must first call Asset.CacheConfigSoup(), and then wait on the returned AsyncQueryHelper. When the caching is complete, the caller may call Asset.GetStringTable() to get the StringTable.
Further Reading
- See HowTo/Read string table or Config text for more clarifications.
TrainzScript.GetAssetList
Previous Usage
This function is used to return a list of installed assets of a given kind (e.g. "signal").
Reason for Obsoletion
Asset searches can be very slow, and this function was marked obsolete for performance reasons.
Replacement Function
A much more powerful asset search system exists in TrainzAssetSearch. This class allows script to asynchronously search on any criteria, eliminating the performance concerns.
TrainzScript.SearchAssets
Previous Usage
This function is used to return a list of assets of a given asset category filter.
Reason for Obsoletion
Asset searches can be very slow, and this function was marked obsolete for performance reasons.
Replacement Function
A much more powerful asset search system exists in TrainzAssetSearch. This class allows script to asynchronously search on any criteria, eliminating the performance concerns.
Router.MESSAGE_BROADCAST
Previous Usage
This pseudo router ID was used to post a message to ALL game objects.
Reason for Obsoletion
Broadcasting is inefficient by nature, and the same effects can be achieved by having scripts listen (via Sniff() or AddHandler()) to the specific objects and messages that they're interested in. Additionally, game objects have a limited message queue capacity, so with large numbers of objects broadcasting it was common to overflow the message queues and permanently lose messages, leading to unexpected and unpredictable outcomes. Finally, with Asynchronous Route Streaming, broadcasts do not actually reach all objects in the route.
Replacement Function
No replacement functionality is required. Scripts should use the existing PostMessage(), Sniff, AddHandler() and similar functionality instead of broadcasting. This should be kept to the minimum necessary to achieve the desired goal.
In order to support interoperability with legacy scripts that expect message broadcasts, the LegacyBroadcastMessage() function can be used in parallel with any updated mechanisms.