2016-05-29 11:27:30 -07:00
--trainlogic.lua
--controls train entities stuff about connecting/disconnecting/colliding trains and other things
2016-08-28 11:59:54 -07:00
local benchmark = false
local bm = { }
local bmlt = 0
local bmsteps = 0
local bmstepint = 200
2017-01-04 12:34:18 -08:00
atprintbm = function ( action , ta )
2016-08-28 11:59:54 -07:00
if not benchmark then return end
local t = ( os.clock ( ) - ta ) * 1000
if not bm [ action ] then
bm [ action ] = t
else
bm [ action ] = bm [ action ] + t
end
bmlt = bmlt + t
end
function endstep ( )
if not benchmark then return end
bmsteps = bmsteps - 1
if bmsteps <= 0 then
bmsteps = bmstepint
for key , value in pairs ( bm ) do
minetest.chat_send_all ( key .. " " .. ( value / bmstepint ) .. " ms avg. " )
end
minetest.chat_send_all ( " Total time consumed by all advtrains actions per step: " .. ( bmlt / bmstepint ) .. " ms avg. " )
bm = { }
bmlt = 0
end
end
2016-06-02 05:42:01 -07:00
2018-01-07 11:41:48 -08:00
--acceleration for lever modes (trainhud.lua), per wagon
local t_accel_all = {
[ 0 ] = - 10 ,
[ 1 ] = - 3 ,
[ 2 ] = - 0.5 ,
2018-01-09 12:30:56 -08:00
[ 4 ] = 0.5 ,
2018-01-07 11:41:48 -08:00
}
--acceleration per engine
local t_accel_eng = {
[ 0 ] = 0 ,
[ 1 ] = 0 ,
[ 2 ] = 0 ,
2018-01-09 12:30:56 -08:00
[ 4 ] = 1.5 ,
2018-01-07 11:41:48 -08:00
}
2016-05-29 11:27:30 -07:00
2017-04-29 10:44:43 -07:00
advtrains.mainloop_trainlogic = function ( dtime )
2017-02-08 15:11:28 -08:00
--build a table of all players indexed by pts. used by damage and door system.
advtrains.playersbypts = { }
for _ , player in pairs ( minetest.get_connected_players ( ) ) do
if not advtrains.player_to_train_mapping [ player : get_player_name ( ) ] then
--players in train are not subject to damage
local ptspos = minetest.pos_to_string ( vector.round ( player : getpos ( ) ) )
advtrains.playersbypts [ ptspos ] = player
end
end
2016-05-29 11:27:30 -07:00
--regular train step
2017-01-27 14:43:01 -08:00
-- do in two steps:
-- a: predict path and add all nodes to the advtrains.detector.on_node table
-- b: check for collisions based on these data
-- (and more)
2016-06-02 05:42:01 -07:00
local t = os.clock ( )
2017-01-27 14:43:01 -08:00
advtrains.detector . on_node = { }
2016-05-29 11:27:30 -07:00
for k , v in pairs ( advtrains.trains ) do
2017-05-03 07:31:13 -07:00
advtrains.atprint_context_tid = sid ( k )
2017-05-15 04:37:06 -07:00
advtrains.atprint_context_tid_full = k
2017-01-27 14:43:01 -08:00
advtrains.train_step_a ( k , v , dtime )
2016-05-29 11:27:30 -07:00
end
2017-01-27 14:43:01 -08:00
for k , v in pairs ( advtrains.trains ) do
2017-05-03 07:31:13 -07:00
advtrains.atprint_context_tid = sid ( k )
2017-05-15 04:37:06 -07:00
advtrains.atprint_context_tid_full = k
2017-02-17 06:30:34 -08:00
advtrains.train_step_b ( k , v , dtime )
2016-11-10 11:24:47 -08:00
end
2017-05-03 07:31:13 -07:00
advtrains.atprint_context_tid = nil
2017-05-15 04:37:06 -07:00
advtrains.atprint_context_tid_full = nil
2017-05-03 07:31:13 -07:00
2017-01-04 12:34:18 -08:00
atprintbm ( " trainsteps " , t )
2016-08-28 11:59:54 -07:00
endstep ( )
2017-04-29 10:13:15 -07:00
end
2016-05-29 11:27:30 -07:00
2017-02-08 15:11:28 -08:00
minetest.register_on_joinplayer ( function ( player )
2017-04-29 10:44:43 -07:00
return advtrains.pcall ( function ( )
local pname = player : get_player_name ( )
local id = advtrains.player_to_train_mapping [ pname ]
if id then
local train = advtrains.trains [ id ]
if not train then advtrains.player_to_train_mapping [ pname ] = nil return end
--set the player to the train position.
--minetest will emerge the area and load the objects, which then will call reattach_all().
--because player is in mapping, it will not be subject to dying.
player : setpos ( train.last_pos_prev )
--independent of this, cause all wagons of the train which are loaded to reattach their players
--needed because already loaded wagons won't call reattach_all()
for _ , wagon in pairs ( minetest.luaentities ) do
if wagon.is_wagon and wagon.initialized and wagon.train_id == id then
wagon : reattach_all ( )
end
2017-02-08 15:11:28 -08:00
end
end
2017-04-29 10:44:43 -07:00
end )
2017-02-08 15:11:28 -08:00
end )
minetest.register_on_dieplayer ( function ( player )
2017-04-29 10:44:43 -07:00
return advtrains.pcall ( function ( )
local pname = player : get_player_name ( )
local id = advtrains.player_to_train_mapping [ pname ]
if id then
local train = advtrains.trains [ id ]
if not train then advtrains.player_to_train_mapping [ pname ] = nil return end
for _ , wagon in pairs ( minetest.luaentities ) do
if wagon.is_wagon and wagon.initialized and wagon.train_id == id then
--when player dies, detach him from the train
--call get_off_plr on every wagon since we don't know which one he's on.
wagon : get_off_plr ( pname )
end
2017-02-08 15:11:28 -08:00
end
end
2017-04-29 10:44:43 -07:00
end )
2017-02-08 15:11:28 -08:00
end )
2017-01-27 14:43:01 -08:00
--[[
train step structure :
- legacy stuff
- preparing the initial path and creating index
- setting node coverage old indices
- handle velocity influences :
- off - track
- atc
- player controls
- environment collision
- update index = move
- create path
2017-10-25 01:31:07 -07:00
- call stay_node on all old positions to register train there , for collision system
2017-01-27 14:43:01 -08:00
- do less important stuff such as checking trainpartload or removing
-- break --
2017-10-25 01:31:07 -07:00
- Call enter_node and leave_node callbacks ( required here because stay_node needs to be called on all trains first )
2017-01-27 14:43:01 -08:00
- handle train collisions
] ]
function advtrains . train_step_a ( id , train , dtime )
2017-05-30 05:55:41 -07:00
--atprint("--- runcnt ",advtrains.mainloop_runcnt,": index",train.index,"end_index", train.end_index,"| max_iot", train.max_index_on_track, "min_iot", train.min_index_on_track, "<> pe_min", train.path_extent_min,"pe_max", train.path_extent_max)
2017-05-15 04:37:06 -07:00
if train.min_index_on_track then
assert ( math.floor ( train.min_index_on_track ) == train.min_index_on_track )
end
2018-01-07 10:00:43 -08:00
--- 1. not exactly legacy. required now because of saving ---
2016-12-22 09:55:10 -08:00
if not train.drives_on or not train.max_speed then
advtrains.update_trainpart_properties ( id )
end
2016-05-29 11:27:30 -07:00
--TODO check for all vars to be present
2016-08-28 11:59:54 -07:00
if not train.velocity then
train.velocity = 0
end
2016-11-24 11:25:07 -08:00
if not train.movedir or ( train.movedir ~= 1 and train.movedir ~=- 1 ) then
train.movedir = 1
end
2017-01-27 14:43:01 -08:00
--- 2. prepare initial path and index if needed ---
if not train.index then train.index = 0 end
2017-05-03 07:31:13 -07:00
if not train.path then
2017-01-27 14:43:01 -08:00
if not train.last_pos then
--no chance to recover
2017-10-25 01:31:07 -07:00
atwarn ( " Unable to restore train " , id , " : missing last_pos " )
2017-01-27 14:43:01 -08:00
advtrains.trains [ id ] = nil
return false
2016-11-10 11:24:47 -08:00
end
2017-01-27 14:43:01 -08:00
local node_ok = advtrains.get_rail_info_at ( advtrains.round_vector_floor_y ( train.last_pos ) , train.drives_on )
if node_ok == nil then
--block not loaded, do nothing
2017-02-15 10:45:43 -08:00
atprint ( " last_pos " , advtrains.round_vector_floor_y ( train.last_pos ) , " not loaded and not in ndb, waiting " )
2017-01-27 14:43:01 -08:00
return nil
elseif node_ok == false then
2017-10-25 03:33:12 -07:00
atprint ( " Unable to restore train " , id , " : No rail at train's position " )
2017-01-27 14:43:01 -08:00
return false
2016-11-10 11:24:47 -08:00
end
2017-01-27 14:43:01 -08:00
if not train.last_pos_prev then
--no chance to recover
2017-10-25 01:31:07 -07:00
atwarn ( " Unable to restore train " , id , " : missing last_pos_prev " )
2017-01-27 14:43:01 -08:00
advtrains.trains [ id ] = nil
return false
2016-11-10 11:24:47 -08:00
end
2017-01-27 14:43:01 -08:00
local prevnode_ok = advtrains.get_rail_info_at ( advtrains.round_vector_floor_y ( train.last_pos_prev ) , train.drives_on )
if prevnode_ok == nil then
--block not loaded, do nothing
2017-02-15 10:45:43 -08:00
atprint ( " last_pos_prev " , advtrains.round_vector_floor_y ( train.last_pos_prev ) , " not loaded and not in ndb, waiting " )
2017-01-27 14:43:01 -08:00
return nil
elseif prevnode_ok == false then
2017-10-25 03:33:12 -07:00
atprint ( " Unable to restore train " , id , " : No rail at train's position " )
2017-01-27 14:43:01 -08:00
return false
2016-11-10 11:24:47 -08:00
end
2017-01-27 14:43:01 -08:00
train.index = ( train.restore_add_index or 0 ) + ( train.savedpos_off_track_index_offset or 0 )
--restore_add_index is set by save() to prevent trains hopping to next round index. should be between -0.5 and 0.5
--savedpos_off_track_index_offset is set if train went off track. see below.
train.path = { }
train.path_dist = { }
train.path [ 0 ] = train.last_pos
train.path [ - 1 ] = train.last_pos_prev
train.path_dist [ - 1 ] = vector.distance ( train.last_pos , train.last_pos_prev )
train.path_extent_min =- 1
train.path_extent_max = 0
2017-05-15 04:37:06 -07:00
train.min_index_on_track =- 1
train.max_index_on_track = 0
2017-02-05 08:22:13 -08:00
--[[
Bugfix for trains randomly ignoring ATC rails :
- Paths have been invalidated . 1 gets executed and ensures an initial path
- 2 a sets train end index . The problem is that path_dist is not known for the whole path , so train end index will be nearly trainlen
- Since the detector indices are also unknown , they get set to the new ( wrong ) train_end_index . Enter_node calls are not executed for the nodes that lie in between real end_index and trainlen .
- The next step , mistake is recognized , train leaves some positions . From there , everything works again .
To overcome this , we will generate the full required path here so that path_dist is available for get_train_end_index ( ) .
] ]
advtrains.pathpredict ( id , train )
2016-11-10 11:24:47 -08:00
end
2017-01-27 14:43:01 -08:00
--- 2a. set train.end_index which is required in different places, IF IT IS NOT SET YET by STMT afterwards. ---
--- table entry to avoid triple recalculation ---
if not train.end_index then
train.end_index = advtrains.get_train_end_index ( train )
2016-12-31 06:16:19 -08:00
end
2017-01-27 14:43:01 -08:00
--- 2b. set node coverage old indices ---
2017-10-25 01:51:19 -07:00
train.detector_old_index = atround ( train.index )
train.detector_old_end_index = atround ( train.end_index )
2016-05-29 12:33:09 -07:00
2017-01-27 14:43:01 -08:00
--- 3. handle velocity influences ---
local train_moves = ( train.velocity ~= 0 )
2018-01-07 11:41:48 -08:00
local tarvel_cap
2016-05-29 12:33:09 -07:00
2016-05-29 11:27:30 -07:00
if train.recently_collided_with_env then
2018-01-07 11:41:48 -08:00
tarvel_cap = 0
2018-01-09 12:30:56 -08:00
train.active_control = false
2016-08-28 12:58:13 -07:00
if not train_moves then
2018-01-07 10:00:43 -08:00
train.recently_collided_with_env = nil --reset status when stopped
2016-05-29 11:27:30 -07:00
end
end
if train.locomotives_in_train == 0 then
2018-01-07 11:41:48 -08:00
tarvel_cap = 0
2016-05-29 11:27:30 -07:00
end
2017-01-04 03:02:00 -08:00
2017-05-03 07:31:13 -07:00
--- 3a. this can be useful for debugs/warnings and is used for check_trainpartload ---
2017-10-25 01:51:19 -07:00
local t_info , train_pos = sid ( id ) , train.path [ atround ( train.index ) ]
2017-05-03 07:31:13 -07:00
if train_pos then
t_info = t_info .. " @ " .. minetest.pos_to_string ( train_pos )
2017-05-15 04:37:06 -07:00
--atprint("train_pos:",train_pos)
2017-05-03 07:31:13 -07:00
end
2017-01-27 14:43:01 -08:00
--apply off-track handling:
local front_off_track = train.max_index_on_track and train.index > train.max_index_on_track
local back_off_track = train.min_index_on_track and train.end_index < train.min_index_on_track
2017-02-05 08:22:13 -08:00
local pprint
2017-05-03 07:31:13 -07:00
2017-01-27 14:43:01 -08:00
if front_off_track and back_off_track then --allow movement in both directions
2018-01-07 11:41:48 -08:00
tarvel_cap = 1
2017-01-27 14:43:01 -08:00
elseif front_off_track then --allow movement only backward
2018-01-07 11:41:48 -08:00
if train.movedir == 1 then
tarvel_cap = 0
2017-02-05 08:22:13 -08:00
end
2018-01-07 11:41:48 -08:00
if train.movedir ==- 1 then
tarvel_cap = 1
2017-02-05 08:22:13 -08:00
end
2017-01-27 14:43:01 -08:00
elseif back_off_track then --allow movement only forward
2018-01-07 11:41:48 -08:00
if train.movedir == 1 then
tarvel_cap = 1
2017-02-05 08:22:13 -08:00
end
2018-01-07 11:41:48 -08:00
if train.movedir ==- 1 then
tarvel_cap = 0
2017-02-05 08:22:13 -08:00
end
end
2017-01-27 14:43:01 -08:00
2018-01-07 11:41:48 -08:00
--interpret ATC command and apply auto-lever control when not actively controlled
local trainvelocity = train.velocity
if not train.lever then train.lever = 3 end
if train.active_control then
advtrains.atc . train_reset_command ( id )
else
if train.atc_brake_target and train.atc_brake_target >= trainvelocity then
train.atc_brake_target = nil
2017-01-04 03:02:00 -08:00
end
2018-01-07 11:41:48 -08:00
if train.atc_wait_finish then
if not train.atc_brake_target and train.velocity == train.tarvelocity then
train.atc_wait_finish = nil
end
end
if train.atc_command then
if train.atc_delay <= 0 and not train.atc_wait_finish then
advtrains.atc . execute_atc_command ( id , train )
else
train.atc_delay = train.atc_delay - dtime
end
end
train.lever = 3
if train.tarvelocity > trainvelocity then train.lever = 4 end
if train.tarvelocity < trainvelocity then
if ( train.atc_brake_target and train.atc_brake_target < trainvelocity ) then
train.lever = 1
else
train.lever = 2
end
2017-01-04 03:02:00 -08:00
end
end
2018-01-07 11:41:48 -08:00
if tarvel_cap and tarvel_cap < train.tarvelocity then
train.tarvelocity = tarvel_cap
end
local tmp_lever = train.lever
if tarvel_cap and trainvelocity > tarvel_cap then
tmp_lever = 0
2016-11-24 11:25:07 -08:00
end
2017-01-27 14:43:01 -08:00
--- 3a. actually calculate new velocity ---
2018-01-07 11:41:48 -08:00
if tmp_lever ~= 3 then
local acc_all = t_accel_all [ tmp_lever ]
local acc_eng = t_accel_eng [ tmp_lever ]
local nwagons = # train.trainparts
local accel = acc_all + ( acc_eng * train.locomotives_in_train ) / nwagons
local vdiff = accel * dtime
if not train.active_control then
local tvdiff = train.tarvelocity - trainvelocity
if math.abs ( vdiff ) > math.abs ( tvdiff ) then
--applying this change would cross tarvelocity
vdiff = tvdiff
2016-05-29 11:27:30 -07:00
end
end
2018-01-07 11:41:48 -08:00
if tarvel_cap and trainvelocity <= tarvel_cap and trainvelocity + vdiff > tarvel_cap then
vdiff = tarvel_cap - train.velocity
end
if trainvelocity + vdiff < 0 then
vdiff = - trainvelocity
end
local mspeed = ( train.max_speed or 10 )
if trainvelocity + vdiff > mspeed then
vdiff = mspeed - trainvelocity
end
train.last_accel = ( vdiff * train.movedir )
train.velocity = train.velocity + vdiff
if train.active_control then
train.tarvelocity = train.velocity
end
2016-09-28 23:41:05 -07:00
else
2018-01-07 11:41:48 -08:00
train.last_accel = 0
2016-05-29 11:27:30 -07:00
end
2017-01-27 14:43:01 -08:00
--- 4. move train ---
2016-08-26 16:46:29 -07:00
2017-01-27 14:43:01 -08:00
train.index = train.index and train.index + ( ( ( train.velocity * train.movedir ) / ( train.path_dist [ math.floor ( train.index ) ] or 1 ) ) * dtime ) or 0
2016-05-29 11:27:30 -07:00
2017-01-27 14:43:01 -08:00
--- 4a. update train.end_index to the new position ---
train.end_index = advtrains.get_train_end_index ( train )
2016-05-29 11:27:30 -07:00
2017-01-27 14:43:01 -08:00
--- 5. extend path as necessary ---
2017-02-05 08:22:13 -08:00
--why this is an extra function, see under 3.
advtrains.pathpredict ( id , train , true )
2016-05-29 11:27:30 -07:00
2017-05-03 07:31:13 -07:00
--- 5a. make pos/yaw available for possible recover calls ---
2016-05-29 11:27:30 -07:00
if train.max_index_on_track < train.index then --whoops, train went too far. the saved position will be the last one that lies on a track, and savedpos_off_track_index_offset will hold how far to go from here
2017-10-25 01:51:19 -07:00
train.savedpos_off_track_index_offset = atround ( train.index ) - train.max_index_on_track
2016-05-29 11:27:30 -07:00
train.last_pos = train.path [ train.max_index_on_track ]
train.last_pos_prev = train.path [ train.max_index_on_track - 1 ]
2017-05-12 10:43:04 -07:00
atprint ( " train is off-track (front), last positions kept at " , train.last_pos , " / " , train.last_pos_prev )
2016-05-29 11:27:30 -07:00
elseif train.min_index_on_track + 1 > train.index then --whoops, train went even more far. same behavior
2017-10-25 01:51:19 -07:00
train.savedpos_off_track_index_offset = atround ( train.index ) - train.min_index_on_track
2016-05-29 11:27:30 -07:00
train.last_pos = train.path [ train.min_index_on_track + 1 ]
train.last_pos_prev = train.path [ train.min_index_on_track ]
2017-05-12 10:43:04 -07:00
atprint ( " train is off-track (back), last positions kept at " , train.last_pos , " / " , train.last_pos_prev )
2016-05-29 11:27:30 -07:00
else --regular case
train.savedpos_off_track_index_offset = nil
2017-10-25 01:51:19 -07:00
train.last_pos = train.path [ math.floor ( train.index + 1 ) ]
train.last_pos_prev = train.path [ math.floor ( train.index ) ]
2016-05-29 11:27:30 -07:00
end
2017-01-27 14:43:01 -08:00
2017-05-03 07:31:13 -07:00
--- 5b. Remove path items that are no longer used ---
-- Necessary since path items are no longer invalidated in save steps
local path_pregen_keep = 20
local offtrack_keep = 4
local gen_front_keep = path_pregen_keep
2017-10-25 01:51:19 -07:00
local gen_back_keep = atround ( - train.trainlen - path_pregen_keep )
2017-05-03 07:31:13 -07:00
2017-10-25 01:51:19 -07:00
local delete_min = math.min ( train.max_index_on_track - offtrack_keep , atround ( train.index ) + gen_back_keep )
local delete_max = math.max ( train.min_index_on_track + offtrack_keep , atround ( train.index ) + gen_front_keep )
2017-05-03 07:31:13 -07:00
if train.path_extent_min < delete_min then
2017-10-25 01:31:07 -07:00
--atprint(sid(id),"clearing path min ",train.path_extent_min," to ",delete_min)
2017-05-03 07:31:13 -07:00
for i = train.path_extent_min , delete_min - 1 do
train.path [ i ] = nil
train.path_dist [ i ] = nil
end
train.path_extent_min = delete_min
train.min_index_on_track = math.max ( train.min_index_on_track , delete_min )
end
if train.path_extent_max > delete_max then
2017-10-25 01:31:07 -07:00
--atprint(sid(id),"clearing path max ",train.path_extent_max," to ",delete_max)
2017-05-03 07:31:13 -07:00
train.path_dist [ delete_max ] = nil
for i = delete_max + 1 , train.path_extent_max do
train.path [ i ] = nil
train.path_dist [ i ] = nil
end
train.path_extent_max = delete_max
train.max_index_on_track = math.min ( train.max_index_on_track , delete_max )
end
2017-10-25 01:31:07 -07:00
--- 6b. call stay_node to register trains in the location table - actual enter_node stuff is done in step b ---
2017-02-05 08:22:13 -08:00
2017-10-25 02:49:34 -07:00
local ifo , ibo = train.detector_old_index , train.detector_old_end_index
2017-01-27 14:43:01 -08:00
local path = train.path
2017-02-05 08:22:13 -08:00
2017-10-25 02:49:34 -07:00
for i = ibo , ifo do
2017-10-25 01:31:07 -07:00
if path [ i ] then
2017-10-25 02:49:34 -07:00
advtrains.detector . stay_node ( path [ i ] , id )
2017-01-27 14:43:01 -08:00
end
end
--- 7. do less important stuff ---
--check for any trainpart entities if they have been unloaded. do this only if train is near a player, to not spawn entities into unloaded areas
train.check_trainpartload = ( train.check_trainpartload or 0 ) - dtime
2017-06-07 03:53:52 -07:00
local node_range = ( math.max ( ( minetest.settings : get ( " active_block_range " ) or 0 ) , 1 ) * 16 )
2017-01-27 14:43:01 -08:00
if train.check_trainpartload <= 0 then
2017-05-03 07:31:13 -07:00
local ori_pos = train_pos --see 3a.
2017-01-27 14:43:01 -08:00
--atprint("[train "..id.."] at "..minetest.pos_to_string(vector.round(ori_pos)))
local should_check = false
for _ , p in ipairs ( minetest.get_connected_players ( ) ) do
2017-10-11 02:53:14 -07:00
should_check = should_check or ( ori_pos and ( ( vector.distance ( ori_pos , p : getpos ( ) ) < node_range ) ) )
2017-01-27 14:43:01 -08:00
end
if should_check then
advtrains.update_trainpart_properties ( id )
end
train.check_trainpartload = 2
end
--remove?
if # train.trainparts == 0 then
atprint ( " [train " .. sid ( id ) .. " ] has empty trainparts, removing. " )
advtrains.detector . leave_node ( path [ train.detector_old_index ] , id )
advtrains.trains [ id ] = nil
return
end
2016-05-29 11:27:30 -07:00
end
2017-01-27 14:43:01 -08:00
2017-02-05 08:22:13 -08:00
2017-01-27 14:43:01 -08:00
function advtrains . train_step_b ( id , train , dtime )
2017-02-15 10:45:43 -08:00
--hacky fix: if train_step_a returned in phase 2, end_index may not be set.
--just return
2017-12-18 14:44:01 -08:00
if not train.index or not train.end_index then
2017-02-15 10:45:43 -08:00
return
end
2017-10-25 01:31:07 -07:00
--- 6. update node coverage ---
-- when paths get cleared, the old indices set above will be up-to-date and represent the state in which the last run of this code was made
2017-10-25 01:51:19 -07:00
local ifo , ifn , ibo , ibn = train.detector_old_index , atround ( train.index ) , train.detector_old_end_index , atround ( train.end_index )
2017-11-23 08:00:39 -08:00
--atprint(ifo,">", ifn, "<==>", ibo,">", ibn)
2017-10-25 01:31:07 -07:00
local path = train.path
if train.enter_node_all then
--field set by create_new_train_at.
--ensures that new train calls enter_node on all nodes
for i = ibn , ifn do
if path [ i ] then
advtrains.detector . enter_node ( path [ i ] , id )
end
end
train.enter_node_all = nil
else
if ifn > ifo then
for i = ifo + 1 , ifn do
if path [ i ] then
2017-10-25 02:49:34 -07:00
if advtrains.detector . occupied ( path [ i ] , id ) then
2017-10-25 01:31:07 -07:00
--if another train has signed up for this position first, it won't be recognized in train_step_b. So do collision here.
2017-10-25 02:49:34 -07:00
atprint ( " Collision detected in enter_node callbacks (front) @ " , path [ i ] , " with " , sid ( advtrains.detector . get ( path [ i ] , id ) ) )
advtrains.collide_and_spawn_couple ( id , path [ i ] , advtrains.detector . get ( path [ i ] , id ) , false )
2017-10-25 01:31:07 -07:00
end
2017-10-25 02:49:34 -07:00
atprint ( " enter_node (front) @index " , i , " @ " , path [ i ] , " on_node " , sid ( advtrains.detector . get ( path [ i ] , id ) ) )
2017-10-25 01:31:07 -07:00
advtrains.detector . enter_node ( path [ i ] , id )
end
end
elseif ifn < ifo then
for i = ifn + 1 , ifo do
if path [ i ] then
advtrains.detector . leave_node ( path [ i ] , id )
end
end
end
if ibn < ibo then
for i = ibn , ibo - 1 do
if path [ i ] then
local pts = minetest.pos_to_string ( path [ i ] )
2017-10-25 02:49:34 -07:00
if advtrains.detector . occupied ( path [ i ] , id ) then
2017-10-25 01:31:07 -07:00
--if another train has signed up for this position first, it won't be recognized in train_step_b. So do collision here.
2017-10-25 02:49:34 -07:00
atprint ( " Collision detected in enter_node callbacks (back) @ " , path [ i ] , " with " , sid ( advtrains.detector . get ( path [ i ] , id ) ) )
advtrains.collide_and_spawn_couple ( id , path [ i ] , advtrains.detector . get ( path [ i ] , id ) , true )
2017-10-25 01:31:07 -07:00
end
2017-10-25 02:49:34 -07:00
atprint ( " enter_node (back) @index " , i , " @ " , path [ i ] , " on_node " , sid ( advtrains.detector . get ( path [ i ] , id ) ) )
2017-10-25 01:31:07 -07:00
advtrains.detector . enter_node ( path [ i ] , id )
end
end
elseif ibn > ibo then
for i = ibo , ibn - 1 do
if path [ i ] then
advtrains.detector . leave_node ( path [ i ] , id )
end
end
end
end
2017-02-15 10:45:43 -08:00
2017-02-08 15:11:28 -08:00
--- 8. check for collisions with other trains and damage players ---
2017-01-27 14:43:01 -08:00
local train_moves = ( train.velocity ~= 0 )
if train_moves then
2017-11-23 08:00:39 -08:00
--TO BE REMOVED:
2017-11-27 08:46:01 -08:00
if not train.extent_h then advtrains.update_trainpart_properties ( id ) end
2017-11-23 08:00:39 -08:00
2017-01-27 14:43:01 -08:00
local collpos
local coll_grace = 1
if train.movedir == 1 then
collpos = advtrains.get_real_index_position ( train.path , train.index - coll_grace )
else
collpos = advtrains.get_real_index_position ( train.path , train.end_index + coll_grace )
end
if collpos then
local rcollpos = advtrains.round_vector_floor_y ( collpos )
2017-11-23 08:00:39 -08:00
for x =- train.extent_h , train.extent_h do
for z =- train.extent_h , train.extent_h do
2017-01-27 14:43:01 -08:00
local testpos = vector.add ( rcollpos , { x = x , y = 0 , z = z } )
2017-02-08 15:11:28 -08:00
--- 8a Check collision ---
2017-10-25 02:49:34 -07:00
if advtrains.detector . occupied ( testpos , id ) then
2017-01-27 14:43:01 -08:00
--collides
2017-10-25 02:49:34 -07:00
advtrains.collide_and_spawn_couple ( id , testpos , advtrains.detector . get ( testpos , id ) , train.movedir ==- 1 )
2017-01-27 14:43:01 -08:00
end
2017-02-08 15:11:28 -08:00
--- 8b damage players ---
2017-06-07 03:53:52 -07:00
if not minetest.settings : get_bool ( " creative_mode " ) then
2017-11-22 14:13:42 -08:00
local testpts = minetest.pos_to_string ( testpos )
2017-03-11 13:19:01 -08:00
local player = advtrains.playersbypts [ testpts ]
2017-10-25 02:49:34 -07:00
if player and not minetest.check_player_privs ( player , " creative " ) and train.velocity > 3 then
2017-03-11 13:19:01 -08:00
--instantly kill player
--drop inventory contents first, to not to spawn bones
local player_inv = player : get_inventory ( )
for i = 1 , player_inv : get_size ( " main " ) do
minetest.add_item ( testpos , player_inv : get_stack ( " main " , i ) )
end
for i = 1 , player_inv : get_size ( " craft " ) do
minetest.add_item ( testpos , player_inv : get_stack ( " craft " , i ) )
end
-- empty lists main and craft
player_inv : set_list ( " main " , { } )
player_inv : set_list ( " craft " , { } )
player : set_hp ( 0 )
2017-02-08 15:11:28 -08:00
end
end
2017-01-27 14:43:01 -08:00
end
end
2017-10-25 05:04:20 -07:00
--- 8c damage other objects ---
local objs = minetest.get_objects_inside_radius ( rcollpos , 2 )
for _ , obj in ipairs ( objs ) do
2017-11-14 14:16:08 -08:00
if not obj : is_player ( ) and obj : get_armor_groups ( ) . fleshy and obj : get_armor_groups ( ) . fleshy > 0
and obj : get_luaentity ( ) and obj : get_luaentity ( ) . name ~= " signs:text " then
2017-11-02 10:00:38 -07:00
obj : punch ( obj , 1 , { full_punch_interval = 1.0 , damage_groups = { fleshy = 1000 } , } , nil )
2017-10-25 05:04:20 -07:00
end
end
2017-01-27 14:43:01 -08:00
end
end
2016-06-02 05:42:01 -07:00
end
2016-05-29 11:27:30 -07:00
2017-01-27 14:43:01 -08:00
--returns new id
function advtrains . create_new_train_at ( pos , pos_prev )
2018-01-07 10:00:43 -08:00
local newtrain_id = advtrains.random_id ( )
while advtrains.trains [ newtrain_id ] do newtrain_id = advtrains.random_id ( ) end --ensure uniqueness
2017-01-27 14:43:01 -08:00
advtrains.trains [ newtrain_id ] = { }
advtrains.trains [ newtrain_id ] . last_pos = pos
advtrains.trains [ newtrain_id ] . last_pos_prev = pos_prev
advtrains.trains [ newtrain_id ] . tarvelocity = 0
advtrains.trains [ newtrain_id ] . velocity = 0
advtrains.trains [ newtrain_id ] . trainparts = { }
2017-02-04 12:07:18 -08:00
advtrains.trains [ newtrain_id ] . enter_node_all = true
2017-01-27 14:43:01 -08:00
return newtrain_id
end
function advtrains . get_train_end_index ( train )
return advtrains.get_real_path_index ( train , train.trainlen or 2 ) --this function can be found inside wagons.lua since it's more related to wagons. we just set trainlen as pos_in_train
2016-05-29 11:27:30 -07:00
end
function advtrains . add_wagon_to_train ( wagon , train_id , index )
local train = advtrains.trains [ train_id ]
if index then
table.insert ( train.trainparts , index , wagon.unique_id )
else
table.insert ( train.trainparts , wagon.unique_id )
end
--this is not the usual case!!!
--we may set initialized because the wagon has no chance to step()
wagon.initialized = true
2016-11-06 14:21:03 -08:00
--TODO is this art or can we throw it away?
2016-05-29 11:27:30 -07:00
advtrains.update_trainpart_properties ( train_id )
end
function advtrains . update_trainpart_properties ( train_id , invert_flipstate )
local train = advtrains.trains [ train_id ]
2017-11-22 14:13:42 -08:00
train.drives_on = advtrains.merge_tables ( advtrains.all_tracktypes )
--FIX: deep-copy the table!!!
2017-01-04 12:23:15 -08:00
train.max_speed = 20
2017-11-23 08:00:39 -08:00
train.extent_h = 0 ;
2016-05-29 11:27:30 -07:00
local rel_pos = 0
local count_l = 0
for i , w_id in ipairs ( train.trainparts ) do
2017-01-02 09:40:49 -08:00
local wagon = nil
2018-01-09 12:30:56 -08:00
local shift_dcpl_lock = false
2017-01-08 12:10:02 -08:00
for aoid , iwagon in pairs ( minetest.luaentities ) do
2017-01-17 06:29:37 -08:00
if iwagon.is_wagon and iwagon.unique_id == w_id then
2017-01-02 09:40:49 -08:00
if wagon then
--duplicate
2017-01-08 12:10:02 -08:00
atprint ( " update_trainpart_properties: Removing duplicate wagon with id= " .. aoid )
2017-01-02 09:40:49 -08:00
iwagon.object : remove ( )
else
wagon = iwagon
2016-05-29 11:27:30 -07:00
end
2017-01-02 09:40:49 -08:00
end
end
if not wagon then
if advtrains.wagon_save [ w_id ] then
--spawn a new and initialize it with the properties from wagon_save
2017-01-18 14:28:23 -08:00
wagon = minetest.add_entity ( train.last_pos , advtrains.wagon_save [ w_id ] . entity_name ) : get_luaentity ( )
2017-01-17 06:29:37 -08:00
if not wagon then
minetest.chat_send_all ( " [advtrains] Warning: Wagon " .. advtrains.wagon_save [ w_id ] . entity_name .. " does not exist. Make sure all required modules are loaded! " )
else
wagon : init_from_wagon_save ( w_id )
end
2017-01-02 09:40:49 -08:00
end
end
if wagon then
rel_pos = rel_pos + wagon.wagon_span
wagon.train_id = train_id
wagon.pos_in_train = rel_pos
wagon.pos_in_trainparts = i
wagon.old_velocity_vector = nil
if wagon.is_locomotive then
count_l = count_l + 1
end
if invert_flipstate then
wagon.wagon_flipped = not wagon.wagon_flipped
2018-01-09 12:30:56 -08:00
shift_dcpl_lock , wagon.dcpl_lock = wagon.dcpl_lock , shift_dcpl_lock
2017-01-02 09:40:49 -08:00
end
rel_pos = rel_pos + wagon.wagon_span
if wagon.drives_on then
for k , _ in pairs ( train.drives_on ) do
if not wagon.drives_on [ k ] then
train.drives_on [ k ] = nil
2016-12-22 09:55:10 -08:00
end
end
2016-05-29 11:27:30 -07:00
end
2017-01-02 09:40:49 -08:00
train.max_speed = math.min ( train.max_speed , wagon.max_speed )
2017-11-23 08:00:39 -08:00
train.extent_h = math.max ( train.extent_h , wagon.extent_h or 1 ) ;
2017-01-02 09:40:49 -08:00
else
2017-10-25 01:31:07 -07:00
atwarn ( " Did not find save data for wagon " , w_id , " . The wagon will be deleted. " )
2017-01-02 09:40:49 -08:00
--what the hell...
table.remove ( train.trainparts , pit )
2016-05-30 10:58:09 -07:00
end
2016-05-29 11:27:30 -07:00
end
train.trainlen = rel_pos
train.locomotives_in_train = count_l
end
function advtrains . split_train_at_wagon ( wagon )
--get train
local train = advtrains.trains [ wagon.train_id ]
2017-01-27 14:43:01 -08:00
if not train.path then return end
2016-06-02 05:42:01 -07:00
local real_pos_in_train = advtrains.get_real_path_index ( train , wagon.pos_in_train )
2017-10-25 02:49:34 -07:00
local pos_for_new_train = train.path [ math.floor ( real_pos_in_train + wagon.wagon_span ) ]
local pos_for_new_train_prev = train.path [ math.floor ( real_pos_in_train + wagon.wagon_span - 1 ) ]
2016-05-29 11:27:30 -07:00
--before doing anything, check if both are rails. else do not allow
if not pos_for_new_train then
2017-01-04 12:34:18 -08:00
atprint ( " split_train: pos_for_new_train not set " )
2016-05-29 11:27:30 -07:00
return false
end
2016-12-22 09:55:10 -08:00
local node_ok = advtrains.get_rail_info_at ( advtrains.round_vector_floor_y ( pos_for_new_train ) , train.drives_on )
2016-05-29 12:33:09 -07:00
if not node_ok then
2017-05-12 10:43:04 -07:00
atprint ( " split_train: pos_for_new_train " , advtrains.round_vector_floor_y ( pos_for_new_train_prev ) , " not loaded or is not a rail " )
2016-05-29 11:27:30 -07:00
return false
end
2016-05-29 12:33:09 -07:00
2016-05-29 11:27:30 -07:00
if not train.last_pos_prev then
2017-01-04 12:34:18 -08:00
atprint ( " split_train: pos_for_new_train_prev not set " )
2016-05-29 11:27:30 -07:00
return false
end
2016-12-22 09:55:10 -08:00
local prevnode_ok = advtrains.get_rail_info_at ( advtrains.round_vector_floor_y ( pos_for_new_train ) , train.drives_on )
2016-05-29 12:33:09 -07:00
if not prevnode_ok then
2017-05-12 10:43:04 -07:00
atprint ( " split_train: pos_for_new_train_prev " , advtrains.round_vector_floor_y ( pos_for_new_train_prev ) , " not loaded or is not a rail " )
2016-05-29 11:27:30 -07:00
return false
end
--create subtrain
2016-12-22 09:55:10 -08:00
local newtrain_id = advtrains.create_new_train_at ( pos_for_new_train , pos_for_new_train_prev )
2016-05-29 11:27:30 -07:00
local newtrain = advtrains.trains [ newtrain_id ]
--insert all wagons to new train
for k , v in ipairs ( train.trainparts ) do
if k >= wagon.pos_in_trainparts then
table.insert ( newtrain.trainparts , v )
train.trainparts [ k ] = nil
end
end
--update train parts
advtrains.update_trainpart_properties ( wagon.train_id ) --atm it still is the desierd id.
advtrains.update_trainpart_properties ( newtrain_id )
train.tarvelocity = 0
newtrain.velocity = train.velocity
newtrain.tarvelocity = 0
2017-02-04 12:07:18 -08:00
newtrain.enter_node_all = true
2018-01-09 12:30:56 -08:00
newtrain.couple_lck_back = train.couple_lck_back
newtrain.couple_lck_front = false
train.couple_lck_back = false
2016-05-29 11:27:30 -07:00
end
--there are 4 cases:
--1/2. F<->R F<->R regular, put second train behind first
--->frontpos of first train will match backpos of second
--3. F<->R R<->F flip one of these trains, take the other as new train
--->backpos's will match
--4. R<->F F<->R flip one of these trains and take it as new parent
--->frontpos's will match
2016-12-31 06:16:19 -08:00
2016-07-04 03:11:51 -07:00
--true when trains are facing each other. needed on colliding.
-- check done by iterating paths and checking their direction
2016-08-21 12:46:16 -07:00
--returns nil when not on the same track at all OR when required path items are not generated. this distinction may not always be needed.
2016-07-04 03:11:51 -07:00
function advtrains . trains_facing ( train1 , train2 )
2017-10-25 01:51:19 -07:00
local sr_pos = train1.path [ atround ( train1.index ) ]
local sr_pos_p = train1.path [ atround ( train1.index ) - 1 ]
2016-07-04 03:11:51 -07:00
for i = advtrains.minN ( train2.path ) , advtrains.maxN ( train2.path ) do
if vector.equals ( sr_pos , train2.path [ i ] ) then
2016-08-21 12:46:16 -07:00
if train2.path [ i + 1 ] and vector.equals ( sr_pos_p , train2.path [ i + 1 ] ) then return true end
if train2.path [ i - 1 ] and vector.equals ( sr_pos_p , train2.path [ i - 1 ] ) then return false end
2016-07-04 03:11:51 -07:00
return nil
end
end
return nil
end
2017-02-21 02:39:13 -08:00
function advtrains . collide_and_spawn_couple ( id1 , pos , id2 , t1_is_backpos )
2017-05-30 06:13:04 -07:00
if minetest.settings : get_bool ( " advtrains_disable_collisions " ) then
return
end
2017-10-25 04:31:01 -07:00
atprint ( " COLLISION: " , sid ( id1 ) , " and " , sid ( id2 ) , " at " , pos , " , t1_is_backpos= " , ( t1_is_backpos and " true " or " false " ) )
2016-12-31 06:16:19 -08:00
--TODO:
local train1 = advtrains.trains [ id1 ]
2017-02-21 02:39:13 -08:00
-- do collision
train1.recently_collided_with_env = true
train1.velocity = 0.5 * train1.velocity
train1.movedir = train1.movedir *- 1
train1.tarvelocity = 0
2016-12-31 06:16:19 -08:00
local train2 = advtrains.trains [ id2 ]
2017-01-04 12:23:15 -08:00
if not train1 or not train2 then return end
2016-12-31 06:16:19 -08:00
local found
for i = advtrains.minN ( train1.path ) , advtrains.maxN ( train1.path ) do
if vector.equals ( train1.path [ i ] , pos ) then
found = true
end
end
if not found then
2017-03-03 01:56:58 -08:00
atprint ( " Err: pos not in path. Not spawning a couple " )
2016-12-31 06:16:19 -08:00
return
end
2017-10-25 01:51:19 -07:00
local frontpos2 = train2.path [ atround ( train2.detector_old_index ) ]
local backpos2 = train2.path [ atround ( train2.detector_old_end_index ) ]
2016-12-31 06:16:19 -08:00
local t2_is_backpos
2017-05-12 10:43:04 -07:00
atprint ( " End positions: " , frontpos2 , backpos2 )
2016-12-31 06:16:19 -08:00
2017-02-21 02:39:13 -08:00
t2_is_backpos = vector.distance ( backpos2 , pos ) < vector.distance ( frontpos2 , pos )
2017-01-04 12:34:18 -08:00
atprint ( " t2_is_backpos= " .. ( t2_is_backpos and " true " or " false " ) )
2016-12-31 06:16:19 -08:00
2018-01-09 12:30:56 -08:00
local t1_has_couple , t1_couple_lck
2016-12-31 06:16:19 -08:00
if t1_is_backpos then
2016-05-31 14:13:08 -07:00
t1_has_couple = train1.couple_eid_back
2018-01-09 12:30:56 -08:00
t1_couple_lck = train1.couple_lck_back
2016-05-31 14:13:08 -07:00
else
t1_has_couple = train1.couple_eid_front
2018-01-09 12:30:56 -08:00
t1_couple_lck = train1.couple_lck_front
2016-05-31 14:13:08 -07:00
end
2018-01-09 12:30:56 -08:00
local t2_has_couple , t2_couple_lck
2016-12-31 06:16:19 -08:00
if t2_is_backpos then
2016-05-31 14:13:08 -07:00
t2_has_couple = train2.couple_eid_back
2018-01-09 12:30:56 -08:00
t2_couple_lck = train2.couple_lck_back
2016-05-31 14:13:08 -07:00
else
t2_has_couple = train2.couple_eid_front
2018-01-09 12:30:56 -08:00
t2_couple_lck = train2.couple_lck_front
2016-05-31 14:13:08 -07:00
end
2016-12-31 06:16:19 -08:00
if t1_has_couple then
if minetest.object_refs [ t1_has_couple ] then minetest.object_refs [ t1_has_couple ] : remove ( ) end
end
if t2_has_couple then
if minetest.object_refs [ t2_has_couple ] then minetest.object_refs [ t2_has_couple ] : remove ( ) end
end
2018-01-09 12:30:56 -08:00
if t1_couple_lck or t2_couple_lck then
minetest.add_entity ( pos , " advtrains:lockmarker " )
return
end
2016-12-31 06:16:19 -08:00
local obj = minetest.add_entity ( pos , " advtrains:couple " )
2017-01-04 12:34:18 -08:00
if not obj then atprint ( " failed creating object " ) return end
2016-12-31 06:16:19 -08:00
local le = obj : get_luaentity ( )
le.train_id_1 = id1
le.train_id_2 = id2
le.train1_is_backpos = t1_is_backpos
le.train2_is_backpos = t2_is_backpos
--find in object_refs
2017-03-03 01:56:58 -08:00
local p_aoi
2016-12-31 06:16:19 -08:00
for aoi , compare in pairs ( minetest.object_refs ) do
if compare == obj then
if t1_is_backpos then
train1.couple_eid_back = aoi
2016-05-31 14:13:08 -07:00
else
2016-12-31 06:16:19 -08:00
train1.couple_eid_front = aoi
2016-05-31 14:13:08 -07:00
end
2016-12-31 06:16:19 -08:00
if t2_is_backpos then
train2.couple_eid_back = aoi
else
train2.couple_eid_front = aoi
2016-05-31 14:13:08 -07:00
end
2017-03-03 01:56:58 -08:00
p_aoi = aoi
2016-05-31 14:13:08 -07:00
end
2016-05-29 11:27:30 -07:00
end
2017-03-03 01:56:58 -08:00
atprint ( " Couple spawned (ActiveObjectID " , p_aoi , " ) " )
2016-05-29 11:27:30 -07:00
end
2016-12-31 06:16:19 -08:00
--order of trains may be irrelevant in some cases. check opposite cases. TODO does this work?
--pos1 and pos2 are just needed to form a median.
2016-05-31 14:13:08 -07:00
2017-01-27 14:43:01 -08:00
function advtrains . do_connect_trains ( first_id , second_id , player )
local first , second = advtrains.trains [ first_id ] , advtrains.trains [ second_id ]
2017-04-29 10:44:43 -07:00
if not first or not second or not first.index or not second.index or not first.end_index or not second.end_index then
return false
end
2018-01-09 12:30:56 -08:00
if first.couple_lck_back or second.couple_lck_front then
2017-01-27 14:43:01 -08:00
-- trains are ordered correctly!
if player then
minetest.chat_send_player ( player : get_player_name ( ) , " Can't couple: couples locked! " )
end
return
end
local first_wagoncnt =# first.trainparts
local second_wagoncnt =# second.trainparts
2016-05-29 11:27:30 -07:00
2017-01-27 14:43:01 -08:00
for _ , v in ipairs ( second.trainparts ) do
table.insert ( first.trainparts , v )
2016-05-29 11:27:30 -07:00
end
--kick it like physics (with mass being #wagons)
2017-01-27 14:43:01 -08:00
local new_velocity = ( ( first.velocity * first_wagoncnt ) + ( second.velocity * second_wagoncnt ) ) / ( first_wagoncnt + second_wagoncnt )
2018-01-09 12:30:56 -08:00
local tmp_cpl_lck = second.couple_lck_back
2016-05-29 11:27:30 -07:00
advtrains.trains [ second_id ] = nil
advtrains.update_trainpart_properties ( first_id )
2018-01-09 12:30:56 -08:00
local train1 = advtrains.trains [ first_id ]
train1.velocity = new_velocity
train1.tarvelocity = 0
train1.couple_eid_front = nil
train1.couple_eid_back = nil
train1.couple_lck_back = tmp_cpl_lck
2017-04-29 10:44:43 -07:00
return true
2016-05-29 11:27:30 -07:00
end
function advtrains . invert_train ( train_id )
local train = advtrains.trains [ train_id ]
2017-01-28 08:06:38 -08:00
local old_path = train.path
2017-02-04 12:07:18 -08:00
local old_path_dist = train.path_dist
2016-05-29 11:27:30 -07:00
train.path = { }
2017-02-04 12:07:18 -08:00
train.path_dist = { }
train.index , train.end_index = - train.end_index , - train.index
train.path_extent_min , train.path_extent_max = - train.path_extent_max , - train.path_extent_min
train.min_index_on_track , train.max_index_on_track = - train.max_index_on_track , - train.min_index_on_track
train.detector_old_index , train.detector_old_end_index = - train.detector_old_end_index , - train.detector_old_index
2018-01-09 12:30:56 -08:00
train.couple_lck_back , train.couple_lck_front = train.couple_lck_front , train.couple_lck_back
2017-02-04 12:07:18 -08:00
2016-05-29 11:27:30 -07:00
train.velocity =- train.velocity
train.tarvelocity =- train.tarvelocity
for k , v in pairs ( old_path ) do
train.path [ - k ] = v
2017-02-04 12:07:18 -08:00
train.path_dist [ - k - 1 ] = old_path_dist [ k ]
2016-05-29 11:27:30 -07:00
end
local old_trainparts = train.trainparts
train.trainparts = { }
for k , v in ipairs ( old_trainparts ) do
table.insert ( train.trainparts , 1 , v ) --notice insertion at first place
end
advtrains.update_trainpart_properties ( train_id , true )
end
2017-02-01 15:02:11 -08:00
function advtrains . get_train_at_pos ( pos )
2017-10-25 02:49:34 -07:00
return advtrains.detector . get ( pos )
2016-05-29 11:27:30 -07:00
end
2017-02-01 15:02:11 -08:00
2017-05-03 07:31:13 -07:00
function advtrains . invalidate_all_paths ( pos )
--if a position is given, only invalidate inside a radius to save performance
local inv_radius = 50
atprint ( " invalidating all paths " )
2016-05-29 11:27:30 -07:00
for k , v in pairs ( advtrains.trains ) do
2017-05-03 07:31:13 -07:00
local exec = true
if pos and v.path and v.index and v.end_index then
--start and end pos of the train
2017-10-25 01:51:19 -07:00
local cmp1 = v.path [ atround ( v.index ) ]
local cmp2 = v.path [ atround ( v.end_index ) ]
2017-05-03 07:31:13 -07:00
if vector.distance ( pos , cmp1 ) > inv_radius and vector.distance ( pos , cmp2 ) > inv_radius then
exec = false
end
end
if exec then
2018-01-07 10:00:43 -08:00
advtrains.invalidate_path ( k )
2017-05-03 07:31:13 -07:00
end
2016-05-29 11:27:30 -07:00
end
2016-07-04 03:11:51 -07:00
end
2018-01-07 10:00:43 -08:00
function advtrains . invalidate_path ( id )
local v = advtrains.trains [ id ]
if not v then return end
--TODO duplicate code in init.lua avt_save()!
if v.index then
v.restore_add_index = v.index - math.floor ( v.index + 1 )
end
v.path = nil
v.path_dist = nil
v.index = nil
v.end_index = nil
v.min_index_on_track = nil
v.max_index_on_track = nil
v.path_extent_min = nil
v.path_extent_max = nil
v.detector_old_index = nil
v.detector_old_end_index = nil
end
2016-08-28 11:59:54 -07:00
--not blocking trains group
function advtrains . train_collides ( node )
if node and minetest.registered_nodes [ node.name ] and minetest.registered_nodes [ node.name ] . walkable then
if not minetest.registered_nodes [ node.name ] . groups.not_blocking_trains then
return true
end
end
return false
end
local nonblocknodes = {
" default:fence_wood " ,
2016-11-06 14:21:03 -08:00
" default:fence_acacia_wood " ,
" default:fence_aspen_wood " ,
" default:fence_pine_wood " ,
" default:fence_junglewood " ,
2016-08-28 11:59:54 -07:00
" default:torch " ,
2016-09-15 02:50:37 -07:00
2016-08-28 11:59:54 -07:00
" default:sign_wall " ,
2016-09-15 02:50:37 -07:00
" signs:sign_wall " ,
" signs:sign_wall_blue " ,
" signs:sign_wall_brown " ,
" signs:sign_wall_orange " ,
" signs:sign_wall_green " ,
" signs:sign_yard " ,
" signs:sign_wall_white_black " ,
" signs:sign_wall_red " ,
" signs:sign_wall_white_red " ,
" signs:sign_wall_yellow " ,
2016-08-28 11:59:54 -07:00
" signs:sign_post " ,
2016-09-15 02:50:37 -07:00
" signs:sign_hanging " ,
2016-08-28 11:59:54 -07:00
}
minetest.after ( 0 , function ( )
for _ , name in ipairs ( nonblocknodes ) do
if minetest.registered_nodes [ name ] then
minetest.registered_nodes [ name ] . groups.not_blocking_trains = 1
end
end
end )