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
dev:core:path [2020-04-28 20:27]
orwell
dev:core:path [2023-01-11 15:13] (current)
56independent [Path generation] Add newline for clearer text
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.1588098446.txt.gz · Last modified: 2020-04-28 20:27 by orwell