TNI Socket Interface
TNISocket is a builtin TNILibrary within Trainz which allows TNI plugins to communicate via TCP/IP sockets.
Before continuing, it is recommended you first familiarise yourself with the following pages:
- TrainzNativeInterface - For an overview of TNI and the associated licensing requirements
- TNI Core Interface - For details of the core TNI functionality, object types, etc.
NOTE: This page is a work in progress, and reflects technologies which are not yet present in retail versions of Trainz.
TNISocket is a TNILibrary built into Trainz native code. It is entirely thread safe, and may be loaded and called at any time from within any TNI plugin DLL.
TNISocket is intended to be used for the following purposes:
- Communication with networked hardware devices running on the same local network as the Trainz client. Examples include dedicated train-related hardware such as DCC interfaces or cab simulators, or kit-form hardware such as raw electronics interfaces. Devices such as printers, and standard services such as file shares or web sites should not be accessed in this manner.
- Communication with executable processes running on the same machine, or same local network, as the Trainz client. The executable processes should remain usable while Trainz is not running, and Trainz should remain usable while the executable process is not running. This means that an external process which helps efficiently edit a route or session is permitted, but an external process which is required to load or drive a given route or session is not permitted.
The following usages are specifically prohibited:
- Communication between multiple Trainz clients for purposes such as multiplayer chat, gameplay, etc. (You should use the iTrainz network for this purpose.)
- Exposing the TNI to an external process for the primary purpose of avoiding the security and code-review limitations placed on the TNI plugins. In short, if your desired goal can be achieved without relying on an external process, we will reject any TNI proposal for an external process implementation.
- File sharing, web browsing, etc. Use a web browser, there's no need to build this into Trainz.
- Generic socket access. Your TNI proposal must clearly indicate how your plugin will use the TNISocket interface, and you must take reasonable precautions to avoid using the TNISocket interface outside of that specified purpose.
- Excessive activity. Your plugin should perform a reasonable minimum of effort to achieve its goals. Plugins which generate substantial amounts of network traffic without showing a clear requirement will be rejected. This includes metrics such as bytes per second, packets per second, and connections per second.
TNISocket communication is implemented through TNIStream. Certain stream operations, such as TNIStreamTell(), TNIStreamGetSize(), and TNIStreamStoreObjectReference(), are not available on socket streams. All TNIStream operations are blocking, and are interrupted by stream closure.
As TNISocket is a blocking interface, any call made will block the calling thread until it completes or fails. Care must be taken to ensure that your TNI Plugin does not become unresponsive - this will not affect the Trainz client but may affect your plugin's user experience and may be cause for rejection of your plugin. The simplest approach is to spawn a new thread per socket, ensuring that delays on a socket do not lead to delays on your TNI Plugin's librarycall interface. Since most TNI plugins will only work with one socket, this is not expected to cause any difficulties or performance concerns.
All data is encoded as raw binary with no additional protocol. Text strings are sent as a 32-bit length followed by raw UTF8. AssetIDs do not yet have a standardised format and should not be used. Raw data bytes may be sent using TNIStreamWriteInt8Array().
Text-based protocols can be implemented by building the desired string and sending it via TNIStreamWriteInt8Array(), and by reading character-at-a-time using TNIStreamReadInt8() until encountering the appropriate CR/LF sequence.