User Tools

Site Tools


dev:core:path

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
Last revision Both sides next revision
dev:core:path [2020-04-28 20:27]
orwell
dev:core:path [2020-06-24 12:49]
orwell add callbacks
Line 57: Line 57:
 The path is generated on the fly, as path items are requested. The path is generated on the fly, as path items are requested.
  
-Every call to ''advtrains.path_get()'' (or one of the related functions) automatically generates the path as far as needed.+Every call to ''advtrains.path_get()'' (or one of the related functions) automatically generates the path as far as needed. In order to access any of the secondary path tables (such as path_speed or path_cn), you need to make sure that ''advtrains.path_get()'' was called before. However, advtrains ensures that the range from ''train.index'' to ''train.end_index'' is always existent. 
 + 
 +The path system deletes path items that are behind the train and no longer needed automatically. 
 + 
 +===== Invalidation and restoration ===== 
 + 
 +Whenever the tracks in the world change (e.g. a switch is switched), it is required to update (say 'invalidate') the paths of trains that include the changed track. This happens by a call to ''advtrains.invalidate_all_paths(pos)''
 + 
 +//With the ''new_lzb'' branch, it is preferred to use ''advtrains.invalidate_all_paths_ahead(pos)''. See ''invalidate ahead'' below.// 
 + 
 +A path invalidation clears all path-related tables and variables. They remain cleared until the next call to ''train_ensure_init()'', which should be called before operating on a train, but is at least called before the next train step. 
 + 
 +To restore the path from save files or after a path invalidation, the following values are saved in the train (and in the save files) in every step: 
 + 
 +<code> 
 +train.last_pos -- the world position of the path item currently at floor(train.index) 
 +train.last_connid = the connid of the track connection pointing forward 
 +train.last_frac = the fractional part of train.index 
 +</code> 
 + 
 +To restore, train.last_pos becomes path item 0, train.index becomes last_frac, and path generation continues in last_connid direction. This causes an index shift, which also prevents integer overflows. 
 + 
 +Note that, to have an estimated rough position of a train, you can simply query ''train.last_pos''
 + 
 +A path invalidation can also occur when LZB checkpoints change, see [[dev:core:lzb]] for more info on that. 
 + 
 +===== Invalidate Ahead ===== 
 + 
 +In order to prevent a complete path recalculation when a far-away rail changes, ''path_invalidate_ahead()'' was added in the ''new_lzb'' branch. This function clears path items that are **ahead of** (exclusive) the passed index, and does not cause an index shift. 
 + 
 +Obviously, due to the way the path restoration works, this would cause problems when the starting index is behind the train's current index. By default, when this case happens, ''path_invalidate_ahead()'' throws an error. However passing the ''ignore_when_passed = true'' parameter causes nothing to happen in this case, which is sometimes desirable and sufficient (e.g. when a switch is switched after the train has already passed it, it doesn't matter). 
 + 
 +''path_invalidate_ahead()'' also invalidates LZB checkpoints and re-calls approach callbacks up from the given index. Important: LZB invalidation occurs **inclusive**, so the first approach callback to be called again is the node at ''index'', although the first path item that was actually cleared was ''index + 1''. This is required for interlocking signals to work. 
 + 
 +In the future, path_invalidate_ahead() is to be preferred over path_invalidate(). 
 + 
 +===== Callbacks ===== 
 + 
 +A callback system exists to react to path-related events. Most internal components (e.g. LZB) use these to hook into the path system. 
 + 
 +==== Path callbacks ==== 
 + 
 +There's a relevant comment in occupation.lua: 
 +<code> 
 +Callback system for 3rd-party path checkers: 
 +advtrains.te_register_on_new_path(func(id, train)) 
 +-- Called when a train's path is re-initalized, either when it was invalidated 
 +-- or the saves were just loaded 
 +-- It can be assumed that everything is in the state of when the last run 
 +-- of on_update was made, but all indices are shifted by an unknown amount. 
 + 
 +advtrains.te_register_on_update(func(id, train)) 
 +-- Called each step and after a train moved, its length changed or some other event occured 
 +-- The path is unmodified, and train.index and train.end_index can be reliably 
 +-- queried for the new position and length of the train. 
 +-- note that this function might be called multiple times per step, and this  
 +-- function being called does not necessarily mean that something has changed. 
 +-- It is ensured that on_new_path callbacks are executed prior to these callbacks whenever 
 +-- an invalidation or a reload occured. 
 + 
 +advtrains.te_register_on_create(func(id, train)) 
 +-- Called right after a train is created, right after the initial new_path callback 
 +advtrains.te_register_on_remove(func(id, train)) 
 +-- Called right before a train is deleted 
 + 
 + 
 +All callbacks are allowed to save certain values inside the train table, but they must ensure that 
 +those are reinitialized in the on_new_path callback. The on_new_path callback must explicitly 
 +set ALL OF those values to nil or to a new updated value, and must not rely on their existence. 
 +</code> 
 + 
 +''new_lzb'' adds another callback for invalidate_ahead: 
 + 
 +<code> 
 +advtrains.te_register_on_invalidate_ahead(func(id, train, start_idx)) 
 +</code> 
 + 
 +==== Node Callbacks ==== 
 + 
 +The node callbacks are driven by a special Path Callback defined in trainlogic.lua: 
 +<code> 
 +-- enter/leave-node callbacks 
 +-- signature is advtrains.tnc_register_on_enter/leave(function(pos, id, train, index) ... end) 
 +advtrains.tnc_register_on_enter(func(pos, id, train, index)) 
 +advtrains.tnc_register_on_leave(func(pos, id, train, index)) 
 + 
 +-- Node callback for approaching 
 +-- Might be called multiple times, whenever path is recalculated. Also called for the first node the train is standing on, then has_entered is true. 
 +-- signature is function(pos, id, train, index, has_entered, lzbdata) 
 +-- has_entered: true if the "enter" callback has already been executed for this train in this location 
 +-- lzbdata: arbitrary data (shared between all callbacks), deleted when LZB is restarted. 
 +-- These callbacks are called in order of distance as train progresses along tracks, so lzbdata can be used to 
 +-- keep track of a train's state once it passes this point 
 +advtrains.tnc_register_on_approach(func(pos, id, train, index, has_entered, lzbdata)) 
 +</code> 
  
dev/core/path.txt · Last modified: 2023-01-11 15:13 by 56independent