HowTo/Upgrade GameObject.GetId()

From TrainzOnline
< HowTo(Difference between revisions)
Jump to: navigation, search
Line 119: Line 119:
 
#The function will now force the tile/section which contains the junction object to be loaded into memory. If this junction set is gameplay critical, the forcing the tile to load is likely acceptable, but it does come with a performance cost and script should avoid doing this over multiple items.
 
#The function will now force the tile/section which contains the junction object to be loaded into memory. If this junction set is gameplay critical, the forcing the tile to load is likely acceptable, but it does come with a performance cost and script should avoid doing this over multiple items.
 
#The function is now declared as a [[TrainzScript_Keywords#thread|thread]]. Script threads allow an object to use function calls like wait() and Sleep() and in this case, to perform a synchronous object load. This simplifies the update somewhat, but to use the SynchronouslyLoadGameObjectByID() helper function the calling function must be running on a thread, so that it can wait for the asynchronous query to complete.
 
#The function is now declared as a [[TrainzScript_Keywords#thread|thread]]. Script threads allow an object to use function calls like wait() and Sleep() and in this case, to perform a synchronous object load. This simplifies the update somewhat, but to use the SynchronouslyLoadGameObjectByID() helper function the calling function must be running on a thread, so that it can wait for the asynchronous query to complete.
#The function no longer has a return code. This is necessary because the function is now asynchronous, meaning that the caller will continue execution after calling SetJunctionDirection(), before SetJunctionDirection() has a chance to run or complete.
+
#The function no longer has a return code. This is necessary because the function is now asynchronous, meaning that the caller will continue execution after calling SetJunctionDirection(), before SetJunctionDirection() has a chance to run or complete. If it is necessary for the caller to be notified of the success or failure of this call, then this is best achieved with message posts.
  
 
It is worth noting that an object cannot have too many thread functions running on it at once, so too many calls to SetJunctionDirection() will result in a script exception with the error code ER_ThreadError.
 
It is worth noting that an object cannot have too many thread functions running on it at once, so too many calls to SetJunctionDirection() will result in a script exception with the error code ER_ThreadError.
 
  
 
==Saving/Loading an ID==
 
==Saving/Loading an ID==

Revision as of 14:39, 3 March 2022

The following is an example of how to update a script which uses the obsolete script function GameObject.GetId(). It is intended to be read by content creators already familiar with TrainzScript, but perhaps unfamiliar with the more modern concepts invovled with Asynchronous Route Streaming.

It is recommended readers first familiarise themselves with topics covered in the following pages:

Contents

Overview

The script function GameObject.GetId() returns an integer ID which identifies an object within the script context. This ID is unique and constant for the life of the object only. When the specific object reference is released the ID becomes usable by other objects, and if the game is reloaded the world item represented by that GameObject (e.g. a Signal) will have some other ID.

This makes this ID of limited usefulness, and with the introduction of Route streaming they cannot be trusted and are considered obsolete. The modern replacement function is

public native GameObjectID GameObject.GetGameObjectID(void);

Getting an Object ID

The following example script shows a simple class which gets and stores objects integer ID.

class Example
{
  int             m_gameObjectID = -1;
  
  public void SetObject(GameObject obj)
  {
    // Save the objects ID.
    if (obj)
      m_gameObjectID = obj.GetId();
    else
      m_gameObjectID = -1;
  }
};

This class has a single member variable used to store the ID of an object, and a function which sets the object reference. To upgrade the script to support modern versions of Trainz, the integer ID must be replaced with a GameObjectID, and the GetId() call replaced with GetGameObjectID().

class Example
{
  GameObjectID    m_gameObjectID = null;
  
  public void SetObject(GameObject obj)
  {
    // Save the objects ID.
    if (obj)
      m_gameObjectID = obj.GetGameObjectID();
    else
      m_gameObjectID = null;
  }
};

Getting an Object from an ID

The above example is a demonstration only, and serves no useful purpose. To give it some purpose, let's consider a class which sets a junction direction. In older versions of Trainz this was quite simple, as the object was more or less guaranteed to remain loaded forever.

class Example
{
  int             m_junctionID = -1;
  
  public void SetJunction(Junction junc)
  {
    // Save the junctions ID.
    if (junc)
      m_junctionID = junc.GetId();
    else
      m_junctionID = -1;
  }
  
  public bool SetJunctionDirection(SecurityToken token, int direction)
  {
    if (m_junctionID < 0)
      return false;
    
    Junction junc = cast<Junction>(Router.GetGameObject(m_junctionID));
    if (!junc)
      return false;     
    
    return junc.SetDirection(token, direction);
  }
};

Now we have a potentially useful helper class. However, the approach will not work in TRS19 and later, because Route streaming means the object may be unloaded, and it's integer ID can change. As such, we must instead use the GameObjectID, as follows:

class Example
{
  GameObjectID    m_junctionID = null;
  
  public void SetJunction(Junction junc)
  {
    // Save the junctions ID.
    if (junc)
      m_junctionID = junc.GetGameObjectID();
    else
      m_junctionID = null;
  }
  
  public bool SetJunctionDirection(SecurityToken token, int direction)
  {
    if (!m_junctionID)
      return false;
    
    Junction junc = cast<Junction>(Router.GetGameObject(m_junctionID));
    if (!junc)
      return false;     
    
    return junc.SetDirection(token, direction);
  }
};

This approach is a direct replacement to the original functions, but if Route streaming is enabled and the junction has been unloaded, then a call to SetJunctionDirection() will fail. In many use cases this may be appropriate, and if the caller checks the return result from SetJunctionDirection() then they can reattempt the call later. However, if it's critical that the junction is updated immediately, then script can instead request that the junction is loaded, as follows:

public thread void SetJunctionDirection(SecurityToken token, int direction)
{
  if (!m_junctionID)
    return;
  
  Junction junc = cast<Junction>(World.SynchronouslyLoadGameObjectByID(m_junctionID));
  if (!junc)
    return;     
  
  junc.SetDirection(token, direction);
}

There are several important things to note about this new function.

  1. The function will now force the tile/section which contains the junction object to be loaded into memory. If this junction set is gameplay critical, the forcing the tile to load is likely acceptable, but it does come with a performance cost and script should avoid doing this over multiple items.
  2. The function is now declared as a thread. Script threads allow an object to use function calls like wait() and Sleep() and in this case, to perform a synchronous object load. This simplifies the update somewhat, but to use the SynchronouslyLoadGameObjectByID() helper function the calling function must be running on a thread, so that it can wait for the asynchronous query to complete.
  3. The function no longer has a return code. This is necessary because the function is now asynchronous, meaning that the caller will continue execution after calling SetJunctionDirection(), before SetJunctionDirection() has a chance to run or complete. If it is necessary for the caller to be notified of the success or failure of this call, then this is best achieved with message posts.

It is worth noting that an object cannot have too many thread functions running on it at once, so too many calls to SetJunctionDirection() will result in a script exception with the error code ER_ThreadError.

Saving/Loading an ID

Logging an ID

Personal tools