TrainzScript Message Reference

From TrainzOnline
(Difference between revisions)
Jump to: navigation, search
(When and how to send Messages)
m (How to listen for Messages: Add link to `wait` definition.)
 
(2 intermediate revisions by one user not shown)
Line 2: Line 2:
  
 
Messages:  
 
Messages:  
* are internal communications between objects within Trainz.
+
* Are internal communications between objects within Trainz.
* are completely hidden from the normal user, who won't be aware of their existence.
+
* Are completely hidden from the normal user, who won't be aware of their existence.
* provide notification of events within the Trainz environment.
+
* Provide notification of events within the Trainz script environment.
* provide a means of opening direct communications between objects.
+
* Provide a means of opening direct communications between objects.
* provide a means of sending instructions from one script to another.
+
* Provide a means of sending instructions from one script to another.
* provide a means of timing scripted actions.
+
* Provide a means of timing scripted actions.
  
 
Messages are managed by the ''Router'', a sort of internal post office, and can be exchanged between any objects which descend from ''[[GameObject]]'', this includes driver commands, rules and libraries as well as almost all mesh based scriptable objects.
 
Messages are managed by the ''Router'', a sort of internal post office, and can be exchanged between any objects which descend from ''[[GameObject]]'', this includes driver commands, rules and libraries as well as almost all mesh based scriptable objects.
  
 
Scripts can:
 
Scripts can:
* listen for messages and use them to take appropriate actions in response to events and instructions.  
+
* Listen for messages and use them to take appropriate actions in response to events and instructions.  
* use the message to extract information about the object sending or receiving the message.
+
* Use the message to extract information about the object sending or receiving the message.
* define and issue their own messages.
+
* Define and issue their own messages.
* listen in to messages intended for other objects.
+
* Listen in to messages intended for other objects.
* send messages to themselves, to arrive after a specified delay, as a 'reminder' to do something at a future time.  
+
* Send messages to themselves, to arrive after a specified delay, as a 'reminder' to do something at a future time.  
  
Messages are small data objects containing four pieces of information:
+
Messages are small data objects containing five pieces of information:
* ''msg.major'': a string identifying the message type.
+
* ''msg.major'': A string identifying the message type.
* ''msg.minor'': a string containing the message subtype or in some cases additional information.  
+
* ''msg.minor'': A string containing the message subtype or additional information.  
* ''msg.src'': the object sending the message
+
* ''msg.src'': A reference to the object that sent the message.
* ''msg.dst'': the intended recipient, some messages are ''broadcast'' or sent to the whole world, in which case ''msg.dst'' will be ''null''.
+
* ''msg.dst'': The intended recipient. May be null if the message was ''broadcast'' (legacy behavior, no longer supported).
 +
* ''msg.paramSoup'': A Soup object containing extra data about the message (may be null).
  
 
==How to listen for Messages==
 
==How to listen for Messages==
Line 29: Line 30:
  
 
* ''[[GameObject#AddHandler|AddHandler()]]'' This is the simplest listening device and is most useful when you know that you will always be interested in this type of message. ''[[GameObject#AddHandler|AddHandler()]]'' is usually set up in the ''Init()'' method of a script. Hint: omit any optional spaces in statements that include an AddHandler function, as including them causes the function to be ignored without notification in TRS2004 and perhaps other versions as well.
 
* ''[[GameObject#AddHandler|AddHandler()]]'' This is the simplest listening device and is most useful when you know that you will always be interested in this type of message. ''[[GameObject#AddHandler|AddHandler()]]'' is usually set up in the ''Init()'' method of a script. Hint: omit any optional spaces in statements that include an AddHandler function, as including them causes the function to be ignored without notification in TRS2004 and perhaps other versions as well.
* A ''wait()'' loop. This needs to run in a separate thread and allows for a temporary arrangement where you want to know about messages for a shorter period or under a specified set of conditions.
+
* A ''[[TrainzScript Keywords#wait|wait()]]'' loop. This needs to run in a separate thread and allows for a temporary arrangement where you want to know about messages for a shorter period or under a specified set of conditions.
 
* ''[[GameObject#Sniff|Sniff()]]''.  This allows you to 'eavesdrop' on messages being sent to another object.
 
* ''[[GameObject#Sniff|Sniff()]]''.  This allows you to 'eavesdrop' on messages being sent to another object.
  
Line 48: Line 49:
  
 
If the message destination is entered as ''me'' (meaning the current object) the message will be sent to the object which owns the script. If the destination is ''null'' the message will be ''broadcast'' and therefore available to any object in the session. Message broadcasting is obsolete as of TRS19 however, and may result in script exceptions or silent failures (depending on the local players compatibility setting).
 
If the message destination is entered as ''me'' (meaning the current object) the message will be sent to the object which owns the script. If the destination is ''null'' the message will be ''broadcast'' and therefore available to any object in the session. Message broadcasting is obsolete as of TRS19 however, and may result in script exceptions or silent failures (depending on the local players compatibility setting).
 
Dispatching the message causes the following:
 
* Any threads blocking (waiting) on the message will become unblocked, although code execution will not begin until scheduling reaches that thread.
 
* Any objects with handlers will execute their handlers immediately (handlers are not threaded).
 
* Any native handlers (eg. pfx code) will execute immediately.
 
  
 
If you have a reference to the message target (or if you know its name or id) you should consider the following:
 
If you have a reference to the message target (or if you know its name or id) you should consider the following:

Latest revision as of 21:02, 30 December 2020

Contents

[edit] What are Messages and how can they be used?

Messages:

  • Are internal communications between objects within Trainz.
  • Are completely hidden from the normal user, who won't be aware of their existence.
  • Provide notification of events within the Trainz script environment.
  • Provide a means of opening direct communications between objects.
  • Provide a means of sending instructions from one script to another.
  • Provide a means of timing scripted actions.

Messages are managed by the Router, a sort of internal post office, and can be exchanged between any objects which descend from GameObject, this includes driver commands, rules and libraries as well as almost all mesh based scriptable objects.

Scripts can:

  • Listen for messages and use them to take appropriate actions in response to events and instructions.
  • Use the message to extract information about the object sending or receiving the message.
  • Define and issue their own messages.
  • Listen in to messages intended for other objects.
  • Send messages to themselves, to arrive after a specified delay, as a 'reminder' to do something at a future time.

Messages are small data objects containing five pieces of information:

  • msg.major: A string identifying the message type.
  • msg.minor: A string containing the message subtype or additional information.
  • msg.src: A reference to the object that sent the message.
  • msg.dst: The intended recipient. May be null if the message was broadcast (legacy behavior, no longer supported).
  • msg.paramSoup: A Soup object containing extra data about the message (may be null).

[edit] How to listen for Messages

There are three techniques you can use:

  • AddHandler() This is the simplest listening device and is most useful when you know that you will always be interested in this type of message. AddHandler() is usually set up in the Init() method of a script. Hint: omit any optional spaces in statements that include an AddHandler function, as including them causes the function to be ignored without notification in TRS2004 and perhaps other versions as well.
  • A wait() loop. This needs to run in a separate thread and allows for a temporary arrangement where you want to know about messages for a shorter period or under a specified set of conditions.
  • Sniff(). This allows you to 'eavesdrop' on messages being sent to another object.

[edit] When and how to send Messages

You might consider issuing messages of your own under the following circumstances:

  • When an event has taken place in your script and other objects might need to know about it.
  • When you want to make your object available to other scripts to allow them to call your methods directly.
  • When you need to issue instructions to another object to carry out a particular task and you know that the target object will be able to understand your message.
  • When you want your own script to take an action at some time in the future, or at regular intervals.

There are three routines you can use to issue messages:

  • SendMessage() dispatches the message immediately.
  • PostMessage() dispatches the message via the Router with a specified delay (which can be zero). The message will be executed on the next Router update after the delay has elapsed.
  • Router.PostMessage() allows messages to be dispatched even if the object you are scripting doesn't have its own messaging capabilities.

If the message destination is entered as me (meaning the current object) the message will be sent to the object which owns the script. If the destination is null the message will be broadcast and therefore available to any object in the session. Message broadcasting is obsolete as of TRS19 however, and may result in script exceptions or silent failures (depending on the local players compatibility setting).

If you have a reference to the message target (or if you know its name or id) you should consider the following:

  • If you know which methods to use it might be more appropriate to call the other script directly.
  • You should always avoid broadcasting messages if it is possible to send them directly to the intended recipient.

[edit] Never Assume Anything

The messaging system contains many traps for the unwary. If you are working with a junction for instance you will receive an Object,Enter message whenever a train enters your object's trigger zone. It is not safe however to assume that a subsequent Object,Leave means that the train has crossed the junction and left on the other side. Any of the following would also produce Object,Leave:

  • The train might have stopped and reversed away from your object.
  • An intervening junction might have been toggled so that the train is no longer visible to your object.
  • The train might have coupled to another (and therefore ceased to exist) before reaching your object.

It is usually necessary to treat a message as an indication that the event you are interested in could have happened and to use other tests to confirm.


[edit] Example

Listening for messages and using message handler methods

include "MapObject.gs"

// script can be attached to any scenery object
// enable the message window to view the output in Driver mode
class Messenger isclass MapObject {

   public void Init(void) {
      inherited();
      // listen for Junction and World,ModuleInit messages
      AddHandler(me,"Junction","","ToggleHandler");
      AddHandler(me,"World","ModuleInit","ModuleInitHandler");
   }

   thread void TriggerMonitor(void) {
      // Trigger messages will be passed to us as a result of the 
      // Sniff() call in ModuleInitHandler
      Message msg;
      wait() {
         // listen for Trigger,Enter, print a message when heard, continue listening
         on "Trigger","Enter",msg: {
            Interface.Print("A train has entered a trigger");
            continue;
         }
         // listen for Trigger,Stopped, print a message when heard and then quit the thread
         on "Trigger","Stopped",msg: {
            Interface.Print("A train has stopped on a trigger");
            Interface.Print("Trigger monitoring discontinued");
            break;
         }
      }
   }

   void ToggleHandler(Message msg) {
      // print a message whenever Junction,Toggled is broadcast
      Interface.Print("A junction has been toggled");
   }

   void ModuleInitHandler(Message msg) {
      if (World.GetCurrentModule() == World.DRIVER_MODULE) {
         // attach a handler to the first train on the map instructing it
         // to copy any Trigger messages to us
         Sniff(World.GetTrainList()[0],"Trigger","",true);
         // start monitoring Trigger messages
         TriggerMonitor();
      }
   }

};


[edit] See Also

Personal tools