TNI Physics Interface
TNIPhysics is a builtin TNILibrary within Trainz which allows physics plugin assets to control all the internal train physics for any traincar. This includes engine physics, braking systems and shared systems such as track/air resistance. It doesn't currently include systems such as random motion, coupling interactions, collisions or derailments.
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.
- KIND tni-physics-plugin - For the specification of the physics plugin asset kind.
NOTE: This page is a work in progress. If you notice anything out of date, please advise N3V Games. The original release of TNI Physics was in TRS19 SP3 in April 2021. However information and systems may change over time.
TNIPhysics is initialised at game startup, and will automatically locate and load any installed TNI physics plugin assets at world/map load time. All TNIPhysics plugins must have a QueryProcessingPriority function, which will allow Trainz to determine which of the user's installed plugins is best suited to handle a request. TNIPhysics will make all physics update calls through a plugin's LibraryCall interface.
The specific function calls supported by TNIPhysics are detailed in the next section.
TNIPhysics Library Calls
TNIPhysics will call the plugin library DLL with the function name "Init" on initialization. This call can safely be ignored if no initialisation is necessary. This function expects no return object, and takes no parameters.
This function is called from Trainz code to query the processing priority of a plugin for a given traincar. The function will be called across every plugin for every vehicle at load/creation time and when switching control modes (DCC vs cab). Whichever plugin returns the highest priority result will process the vehicle's physics. It has a single TNIPhysicsVehicle as the param, and expects a TNIInteger return result. The TNIPhysics_Priority enum defines a list of example return values, but the programmer is not constrained to using these defines.
- TNIPhysics_PriorityInvalid - Never use this plugin (-127)
- TNIPhysics_PriorityLowest - Only use this plugin if there's no other option (-20)
- TNIPhysics_PriorityLow - Prefer not using this plugin, but it might work ok (-10)
- TNIPhysics_PriorityDefault - This plugin can handle the request adequately (0). The builtin core plugin asset always returns this value.
- TNIPhysics_PriorityHigh - This plugin is somewhat specialised to handle the request (10)
- TNIPhysics_PriorityHighest - This plugin was built exactly for this request (20)
This function is called from Trainz code on the plugin which returns the highest valid result from a call to "QueryProcessingPriority". It notifies a physics plugin that it has been selected to manage the vehicle, and should perform any appropriate internal initialisation. This function takes a single TNIPhysicsVehicle param (being the vehicle to register) and expects no return object.
This function is the counter to RegisterVehicle, and instructs a plugin that it is no longer managing the physics for a particular vehicle. This will occur when the vehicle is deleted, or Trainz hands it over to a more appropriate plugin (based on the result of a call to the "QueryProcessingPriority" function). This function takes a single TNIPhysicsVehicle param (being the vehicle to unregister) and expects no return object.
When called, the plugin should discard any internal data is has for the specified vehicle. If Trainz required anything to be saved, then a call to SaveVehicleState() will have already made.
The main vehicle update function. This function is called from Trainz code to process a physics command stream for a specific vehicle. The function takes a TNIArray object which contains the TNIPhysicsVehicle (element 0) and a TNIStream (element 1) containing the commands to run (see enum TNIPhysicsPluginCommand for a list of physics commands and their params). Trainz expects a TNIStream return result, containing a list of physics update commands to Trainz from the plugin (see enum TNIPhysicsGameCommand).
The ProcessPhysicsCommands LibraryCall employs incoming and outgoing command buffers to communicate physics information with Trainz. The command buffer data is sequential - each command ID is written as a 16 bit integer, and will be followed followed by any relevant command parameters (see enum TNIPhysicsPluginCommand for specific command details).
As this is a raw command stream it is critical that the programmer carefully reads the documentation on each specific command, and correctly reads off each parameter value, even if they are not being used by the plugin. Failure to correctly read all command parameters will result in corruption of the stream, and undefinied application behaviour.
The stream has no terminating value, but stream end may be detected using the TNIStreamTell and TNIStreamGetSize functions, or simply by reading commands until failure is detected (e.g.
while (TNIStreamReadInt16(commandStream, 0))).
The programmer must employ similar practices when writing the reply command stream. I.e. Each command is written as a 16 bit integer (TNIStreamWriteInt16), and must be followed by the parameters detailed in enum TNIPhysicsGameCommand. Failure to write data in the correct format will result in undefined behaviour within the application.
Incoming Commands (TNIPhysicsPluginCommand)
Enumeration listing the possible physics commands the game may issue to a plugin. Commands and parameters will be written, in sequence, to the TNIStream param passed to the ProcessPhysicsCommands library call.
The main physics update function. This is regularly called by Trainz code to update the traincar physics for a particular time period. This function takes two extra params for the front and rear coupled vehicles, but keep in mind these may be using different TNI plugins.
- float - The time interval to update for.
- TNIPhysicsVehicle - The front coupled vehicle.
- TNIPhysicsVehicle - The rear coupled vehicle.
Called from Trainz to notify of an adjustment to a vehicles momentum. This is typically used to apply the results of coupler physics interactions. Vehicles for which the plugin does not internally track momentum can safely ignore this call.
- double - The new vehicle momentum.
Called by Trainz to notify that all updates relating to this vehicle for the current frame are complete. This includes all plugin updates and all coupler interactions. Plugins may use this as an appropriate location to synchronise plugin state to that of the game, or apply visible state changes only. At the time this call is made it is "too late" to perform or apply physics calculations for a given frame.
- float - The time interval that's been updated.
- double - The final momentum for this frame.
Called following an external physics state update in order to perform any physics-mode-specific follow up validation/correction. Examples include after physics/control state replication in multiplayer.
This command takes no parameters.
Called by Trainz code to request save data for a specific vehicle. If the plugin maintains any internal state for the specified vehicle then this function should save that state, so that players are able to save and reload with seamless physics behaviour. The save state should be returned to the game by adding a TNIP_ReturnSaveState command to the library call result stream (see TNIPhysicsGameCommand for more). If the plugin tracks no state for the vehicle passed, then this call can be safely ignored.
This command takes no parameters.
Called by Trainz code to load previously saved vehicle state. Note that this is always called, even if the plugin does not produce any save state when TNIP_SaveVehicleState is called. Also note that the the passed soup param may have been produced by a different plugin.
- TNISoup - A saved soup generated by a previous TNIP_SaveVehicleState call on this or another plugin. The soup will contain an AssetID param for the plugin that produced it, using the tag name "plugin-kuid".
Called by Trainz code to add coal to a steam engine. For example, when the player uses the manual "Shovel coal" command.
- double - The volume (not mass) of coal to add.
Outgoing Commands (TNIPhysicsGameCommand)
Enumeration listing the possible physics commands a plugin may issue to the game. A TNIPhysics plugin may write these commands (and their params) to the TNIStream returned by a ProcessPhysicsCommands library call.
Specifies which vehicle a sequence of update commands refers to. Use of this command is not necessary, and by default any written commands will update the vehicle which ProcessPhysicsCommands() was called for. If, however, the plugin wishes to run commands for connection data on one of the coupled vehicles (such as brake pipes, etc) then this is used to specify that vehicle.
- TNIPhysicsVehicle - The vehicle to start updating.
Used to mark the end of a vehicle update stream. This will set the update vehicle to null. Following this, a new TNIP_UpdateVehicleBegin command *must* be written before any further update commands.
This command takes no parameters.
Used to return the generated save state for a TNIP_SaveVehicleState command (documented above, in TNIPhysicsPluginCommand).
- TNISoup - A soup containing the saved plugin state. The plugin should write enough state to adequately restore its current internal state for the given vehicle on reload. It is also courtesy to return known/common save data which this plugin itself may not use/require, but which may be useful/expected by other plugins (this aids in seemless plugin switchover during gameplay).
Sets the current resistant force for train movement. This includes all track resistance, slope resistance, and internal engine resistances.
- double - The current resistance force, in Newtons.
Sets the current braking force for the train. This is the force from any/all applied brakes.
- double - The current braking force, in Newtons.
Sets the force currently being output by the engine.
- double - The current engine force, in Newtons.
Sets the force currently being applied to the wheels by the engine. In other words, this is the engine force minus any wheelslip.
- double - The current applied engine force, in Newtons.
Sets the amount of force currently being lost to wheelslip.
- double - The current wheelslip force, in Newtons.
Updates the current drawn stat.
- double - The current being drawn, in Amps.
Updates the "energy use" stat, which is used to generate the PFX "load" variable. This currently has no effect on traincar physics, just particle effects (smoke).
- double - The energy use for the current time interval.
Sets the current forward momentum for a traincar (i.e. this value will be negative if the traincar is not moving forwards).
- double - The new forward momentum for the updated traincar, in Newton seconds.
Adds momentum to the updated traincar. A negative (or positive, for backward travelling traincars) value may be used to remove momentum.
- double - The momentum to add onto the traincar, in Newton seconds.
Sets the amount of 'extra' engine mass a vehicle currently has. This is typically the fuel mass (water and coal) for steam locos.
- double - The current extra engine mass, in kg.
Sets the value of a named engine param, as returned by the script
GetEngineParam() function on Vehicle. This is used to add support for custom named parameters, attempting to override the natively supported params may not work.
- TNILabel - The name of the engine parameter to add/update.
- double - The new value of the parameter.
Sets the current engine throttle. This should gradually move toward the throttle setting, with some amount of latency.
- double - The new engine throttle amount (0 to 1).
Sets whether the brake system compressor is active.
- int8_t - The new compressor state (0- off, 1-on).
Sets the pressure of the brake system equaliser.
- double - The new equaliser pressure, in g/m^3.
Sets the pressure of the brake system main reservoir.
- double - The new main reservoir pressure, in g/m^3.
Sets the pressure of the brake system auxiliary reservoir.
- double - The new auxiliary reservoir pressure, in g/m^3.
Sets the pressure of the brake cylinder.
- double - The new brake cylinder pressure, in g/m^3.
Sets the pressure of the independent/loco brake cylinder.
- double - The new independent/loco brake cylinder pressure, in g/m^3.
Sets the pressure of the main train brake pipe.
- double - The new train brake pipe pressure, in g/m^3.
Sets the pressure of the electro-pneumatic brake pipe.
- double - The new electro-pneumatic brake pipe pressure, in g/m^3.
Sets the pressure of the no3 brake pipe.
- double - The new no3 brake pipe pressure, in g/m^3.
Sets the pressure of the no4 brake pipe.
- double - The new no4 brake pipe pressure, in g/m^3.
Notifies of the brake pressure flow rate.
- double - The new brake pressure flow rate, in g/m^3.
Steam Engine Commands
Sets the coal level in a steam locomotive. This is the current ratio between the minimum (0) and maximum (1) coal levels for the firebox. i.e., a reading of 0 indicates the fire is at minimum coal, not that it's necessarily "empty", and a value over 1 indicates the fire is over-filled with coal.
- double - The current coal level in the firebox.
Sets the water level in a steam locomotive. This is the current ratio between the minimum (0) and maximum (1) water levels for the boiler, as would be shown on the cab gauge(s). i.e., a reading of 0 indicates the boiler is at or below minimum, not that it's necessarily "empty".
- double - The current water level in the boiler.
Sets the current pressure within the boiler, in pascals.
- double - The new boiler pressure, in pascals.
Sets the current pressure within the steam chest, in pascals.
- double - The new steam chest pressure, in pascals.
Sets the amount the engine is being 'thrashed', as returned to script by a call to
- double - The amount the engine is being 'thrashed', 0 to 1 for normal engine operation, >1 for thrashing.
Informs Trainz to consume an amount of coal product, for use as steam engine fuel. The caller should first verify that there is sufficient fuel to meet the request, using TNIPhysicsGetVehicleCoalAvailable().
- int32_t - The amount of product to consume.
Informs Trainz to consume an amount of water product, for use as steam engine fuel. The caller should first verify that there is sufficient fuel to meet the request, using TNIPhysicsGetVehicleWaterAvailable().
- int32_t - The amount of product to consume.
Sets the angular velocity of the wheels on a steam locomotive. This affects the value of the "cyclespeed2" PFX variable.
- float - The angular velocity of the driving wheels, in m/s.
Sets the animation data for the wheels of a traincar. Two values are always written here, but which is used will depend on the type of wheel animation which being used by the traincar.
- float - The current wheel rotation, from 0 to 2PI.
- float - The wheel velocity, in m/s.
Sets the volume of the brake release sound on this traincar.
- float - The new brake release sound volume, 0 to 1.
Sets the value of a named PFX variable. See validation/steam-mode.txt for a list of valid variable names.
- TNILabel - The name of the variable to update.
- float - The new value of the variable.
Accessor Commands (TNIPhysics.h)
Basic accessors for TNIPhysicsVehicle member variables, including those on the frame data, engine spec or steam engine spec.
Train Control Settings
Vehicle State Accessors
Vehicle Brake Pressure State Accessors
Vehicle Track State Accessors
Vehicle Spec Accessors
Engine Spec Accessors
Engine Spec Flowsize Accessors
Engine Spec Volume Accessors
Engine Spec Pressure Accessors
Steam Engine Spec Accessors