Restructure path system
The changes to the path system have not yet been integrated...
This commit is contained in:
parent
da0e7ac756
commit
3420a1a912
@ -28,9 +28,12 @@ function advtrains.dirCoordSet(coord, dir)
|
||||
end
|
||||
return {x=coord.x+x, y=coord.y, z=coord.z+z}
|
||||
end
|
||||
advtrains.pos_add_dir = advtrains.dirCoordSet
|
||||
|
||||
function advtrains.dirToCoord(dir)
|
||||
return advtrains.dirCoordSet({x=0, y=0, z=0}, dir)
|
||||
end
|
||||
advtrains.dir_to_vector = advtrains.dirToCoord
|
||||
|
||||
function advtrains.maxN(list, expectstart)
|
||||
local n=expectstart or 0
|
||||
@ -51,6 +54,8 @@ end
|
||||
function atround(number)
|
||||
return math.floor(number+0.5)
|
||||
end
|
||||
atfloor = math.floor
|
||||
|
||||
|
||||
function advtrains.round_vector_floor_y(vec)
|
||||
return {x=math.floor(vec.x+0.5), y=math.floor(vec.y), z=math.floor(vec.z+0.5)}
|
||||
@ -60,8 +65,8 @@ function advtrains.yawToDirection(yaw, conn1, conn2)
|
||||
if not conn1 or not conn2 then
|
||||
error("given nil to yawToDirection: conn1="..(conn1 or "nil").." conn2="..(conn1 or "nil"))
|
||||
end
|
||||
local yaw1=math.pi*(conn1/8)
|
||||
local yaw2=math.pi*(conn2/8)
|
||||
local yaw1 = advtrains.dir_to_angle(conn1)
|
||||
local yaw2 = advtrains.dir_to_angle(conn2)
|
||||
local adiff1 = advtrains.minAngleDiffRad(yaw, yaw1)
|
||||
local adiff2 = advtrains.minAngleDiffRad(yaw, yaw2)
|
||||
|
||||
@ -75,8 +80,7 @@ end
|
||||
function advtrains.yawToAnyDir(yaw)
|
||||
local min_conn, min_diff=0, 10
|
||||
for conn, vec in pairs(advtrains.dir_trans_tbl) do
|
||||
local uvec = vector.normalize(advtrains.dirToCoord(conn))
|
||||
local yaw1 = math.atan2(uvec.z, uvec.x)
|
||||
local yaw1 = advtrains.dir_to_angle(conn)
|
||||
local diff = advtrains.minAngleDiffRad(yaw, yaw1)
|
||||
if diff < min_diff then
|
||||
min_conn = conn
|
||||
@ -88,8 +92,7 @@ end
|
||||
function advtrains.yawToClosestConn(yaw, conns)
|
||||
local min_connid, min_diff=1, 10
|
||||
for connid, conn in ipairs(conns) do
|
||||
local uvec = vector.normalize(advtrains.dirToCoord(conn.c))
|
||||
local yaw1 = math.atan2(uvec.z, uvec.x)
|
||||
local yaw1 = advtrains.dir_to_angle(conn.c)
|
||||
local diff = advtrains.minAngleDiffRad(yaw, yaw1)
|
||||
if diff < min_diff then
|
||||
min_connid = connid
|
||||
@ -99,6 +102,11 @@ function advtrains.yawToClosestConn(yaw, conns)
|
||||
return min_connid
|
||||
end
|
||||
|
||||
function advtrains.dir_to_angle(dir)
|
||||
local uvec = vector.normalize(advtrains.dirToCoord())
|
||||
local yaw1 = math.atan2(uvec.z, -uvec.x)
|
||||
end
|
||||
|
||||
|
||||
function advtrains.minAngleDiffRad(r1, r2)
|
||||
local pi, pi2 = math.pi, 2*math.pi
|
||||
|
@ -184,6 +184,10 @@ function advtrains.avt_load()
|
||||
if tbl.version then
|
||||
--congrats, we have the new save format.
|
||||
advtrains.trains = tbl.trains
|
||||
--Save the train id into the train table to avoid having to pass id around
|
||||
for id, train in pairs(advtrains.trains) do
|
||||
train.id = id
|
||||
end
|
||||
advtrains.wagon_save = tbl.wagon_save
|
||||
advtrains.player_to_train_mapping = tbl.ptmap or {}
|
||||
advtrains.ndb.load_data(tbl.ndb)
|
||||
|
@ -24,17 +24,7 @@ function advtrains.conway(midreal, prev, drives_on)--in order prev,mid,return
|
||||
return vector.add(advtrains.round_vector_floor_y(next), {x=0, y=nextrailheight, z=0}), midconns[nconnid].c
|
||||
end
|
||||
|
||||
--about regular: Used by 1. to ensure path gets generated far enough, since end index is not known at this time.
|
||||
function advtrains.pathpredict(id, train, regular)
|
||||
--TODO duplicate code under 5b.
|
||||
local path_pregen=10
|
||||
|
||||
local gen_front= path_pregen
|
||||
local gen_back= - train.trainlen - path_pregen
|
||||
if regular then
|
||||
gen_front=math.max(train.index, train.detector_old_index) + path_pregen
|
||||
gen_back=math.min(train.end_index, train.detector_old_end_index) - path_pregen
|
||||
end
|
||||
function advtrains.pathpredict(id, train, gen_front, gen_back)
|
||||
|
||||
local maxn=train.path_extent_max or 0
|
||||
while maxn < gen_front do--pregenerate
|
||||
@ -80,3 +70,155 @@ function advtrains.pathpredict(id, train, regular)
|
||||
if not train.min_index_on_track then train.min_index_on_track=-1 end
|
||||
if not train.max_index_on_track then train.max_index_on_track=0 end
|
||||
end
|
||||
|
||||
-- Naming conventions:
|
||||
-- 'index' - An index of the train.path table.
|
||||
-- 'offset' - A value in meters that determines how far on the path to walk relative to a certain index
|
||||
-- 'n' - Referring or pointing towards the 'next' path item, the one with index+1
|
||||
-- 'p' - Referring or pointing towards the 'prev' path item, the one with index-1
|
||||
-- 'f' - Referring to the positive end of the path (the end with the higher index)
|
||||
-- 'b' - Referring to the negative end of the path (the end with the lower index)
|
||||
|
||||
-- New path structure of trains:
|
||||
--Tables:
|
||||
-- path - path positions. 'indices' are relative to this. At the moment, at.round_vector_floor_y(path[i])
|
||||
-- is the node this item corresponds to, however, this will change in the future.
|
||||
-- path_node - (reserved)
|
||||
-- path_cn - Connid of the current node that points towards path[i+1]
|
||||
-- path_cp - Connid of the current node that points towards path[i-1]
|
||||
-- When the day comes on that path!=node, these will only be set if this index represents a transition between rail nodes
|
||||
-- path_dist - The distance (in meters) between this (path[i]) and the next (path[i+1]) item of the path
|
||||
-- path_dir - The direction of this path item's transition to the next path item, which is the angle of conns[path_cn[i]].c
|
||||
--Variables:
|
||||
-- path_ext_f/b - how far path[i] is set
|
||||
-- path_trk_f/b - how far the path extends along a track. beyond those values, paths are generated in a straight line.
|
||||
-- path_req_f/b - how far path items were requested in the last step
|
||||
|
||||
-- creates the path data structure, reconstructing the train from a position and a connid
|
||||
-- Important! train.drives_on must exist while calling this method
|
||||
-- returns: true - successful
|
||||
-- nil - node not yet available/unloaded, please wait
|
||||
-- false - node definitely gone, remove train
|
||||
function advtrains.path_create(train, pos, connid, rel_index)
|
||||
local posr = advtrains.round_vector_floor_y(pos)
|
||||
local node_ok, conns, rhe = advtrains.get_rail_info_at(pos, train.drives_on)
|
||||
if not node_ok then
|
||||
return node_ok
|
||||
end
|
||||
local mconnid = advtrains.get_matching_conn(connid, #conns)
|
||||
train.index = rel_index
|
||||
train.path = { [0] = { x=posr.x, y=posr.y+rhe, z=posr.z } }
|
||||
train.path_cn = { [0] = connid }
|
||||
train.path_cp = { [0] = mconnid }
|
||||
train.path_dist = {}
|
||||
|
||||
train.path_dir = {
|
||||
[ 0] = conns[connid],
|
||||
[-1] = conns[mconnid]
|
||||
}
|
||||
|
||||
train.path_ext_f=0
|
||||
train.path_ext_b=0
|
||||
train.path_trk_f=0
|
||||
train.path_trk_b=0
|
||||
train.path_req_f=0
|
||||
train.path_req_b=0
|
||||
|
||||
end
|
||||
|
||||
-- Function to get path entry at a position. This function will automatically calculate more of the path when required.
|
||||
-- returns: pos, on_track
|
||||
function advtrains.path_get(train, index)
|
||||
if index ~= atfloor(index) then
|
||||
error("For train "..train.id..": Called path_get() but index="..index.." is not a round number")
|
||||
end
|
||||
while index > train.path_ext_f do
|
||||
local pos = train.path[train.path_ext_f]
|
||||
local connid = train.path_cn[train.path_ext_f]
|
||||
local node_ok, this_conns, adj_pos, adj_connid, conn_idx, nextrail_y
|
||||
if train.path_ext_f == train.path_trk_f then
|
||||
node_ok, this_conns = advtrains.get_rail_info_at(this_pos)
|
||||
if not node_ok then error("For train "..train.id..": Path item "..train.path_ext_f.." on-track but not a valid node!") end
|
||||
adj_pos, adj_connid, conn_idx, nextrail_y = advtrains.get_adjacent_rail(pos, this_conns, connid, train.drives_on)
|
||||
end
|
||||
train.path_ext_f = train.path_ext_f + 1
|
||||
if adj_pos then
|
||||
adj_pos.y = adj_pos.y + nextrail_y
|
||||
train.path_cp[train.path_ext_f] = adj_connid
|
||||
local mconnid = advtrains.get_matching_conn(adj_connid)
|
||||
train.path_cn[train.path_ext_f] = mconnid
|
||||
train.path_dir[train.path_ext_f] = this_conns[mconnid]
|
||||
train.path_trk_f = train.path_ext_f
|
||||
else
|
||||
-- off-track fallback behavior
|
||||
adj_pos = advtrains.pos_add_dir(pos, train.path_dir[train.path_ext_f-1])
|
||||
train.path_dir[train.path_ext_f] = train.path_dir[train.path_ext_f-1]
|
||||
end
|
||||
train.path[train.path_ext_f] = adj_pos
|
||||
train.path_dist[train.path_ext_f - 1] = vector.distance(pos, adj_pos)
|
||||
end
|
||||
while index < train.path_ext_b do
|
||||
local pos = train.path[train.path_ext_b]
|
||||
local connid = train.path_cp[train.path_ext_b]
|
||||
local node_ok, this_conns, adj_pos, adj_connid, conn_idx, nextrail_y
|
||||
if train.path_ext_b == train.path_trk_b then
|
||||
node_ok, this_conns = advtrains.get_rail_info_at(this_pos)
|
||||
if not node_ok then error("For train "..train.id..": Path item "..train.path_ext_f.." on-track but not a valid node!") end
|
||||
adj_pos, adj_connid, conn_idx, nextrail_y = advtrains.get_adjacent_rail(pos, this_conns, connid, train.drives_on)
|
||||
end
|
||||
train.path_ext_b = train.path_ext_b - 1
|
||||
if adj_pos then
|
||||
adj_pos.y = adj_pos.y + nextrail_y
|
||||
train.path_cp[train.path_ext_b] = adj_connid
|
||||
local mconnid = advtrains.get_matching_conn(adj_connid)
|
||||
train.path_cn[train.path_ext_b] = mconnid
|
||||
train.path_dir[train.path_ext_b] = advtrains.oppd(this_conns[mconnid]) --we need to rotate this here so that it points in positive path direction
|
||||
train.path_trk_b = train.path_ext_b
|
||||
else
|
||||
-- off-track fallback behavior
|
||||
adj_pos = advtrains.pos_add_dir(pos, train.path_dir[train.path_ext_b-1])
|
||||
train.path_dir[train.path_ext_b] = train.path_dir[train.path_ext_b-1]
|
||||
end
|
||||
train.path[train.path_ext_b] = adj_pos
|
||||
train.path_dist[train.path_ext_b] = vector.distance(pos, adj_pos)
|
||||
end
|
||||
|
||||
return train.path[index], (index<=train.path_trk_f and index>=train.path_trk_b)
|
||||
|
||||
end
|
||||
|
||||
-- interpolated position to fractional index given, and angle based on path_dir
|
||||
-- returns: pos, angle(yaw)
|
||||
function advtrains.path_get_interpolated(train, index)
|
||||
local i_floor = atfloor(index)
|
||||
local i_ceil = i_floor + 1
|
||||
local frac = index - i_floor
|
||||
local p_floor, = advtrains.path_get(train, i_floor)
|
||||
local p_ceil = advtrains.path_get(train, i_ceil)
|
||||
|
||||
local d_floor = train.path_dir[i_floor]
|
||||
local d_ceil = train.path_dir[i_ceil]
|
||||
local a_floor = advtrains.dir_to_angle(d_floor)
|
||||
local a_ceil = advtrains.dir_to_angle(d_ceil)
|
||||
|
||||
local ang = advtrains.minAngleDiffRad(a_floor, a_ceil)
|
||||
|
||||
return vector.add(p_floor, vector.multiply(vector.subtract(p_ceil, p_floor), frac), (a_floor + frac * ang)%(2*math.pi) -- TODO does this behave correctly?
|
||||
end
|
||||
|
||||
function advtrains.path_get_by_offset(train, index, offset)
|
||||
local pos_in_train_left=pit
|
||||
local index=train.index
|
||||
if pos_in_train_left>(index-math.floor(index))*(train.path_dist[math.floor(index)] or 1) then
|
||||
pos_in_train_left=pos_in_train_left - (index-math.floor(index))*(train.path_dist[math.floor(index)] or 1)
|
||||
index=math.floor(index)
|
||||
while pos_in_train_left>(train.path_dist[index-1] or 1) do
|
||||
pos_in_train_left=pos_in_train_left - (train.path_dist[index-1] or 1)
|
||||
index=index-1
|
||||
end
|
||||
index=index-(pos_in_train_left/(train.path_dist[index-1] or 1))
|
||||
else
|
||||
index=index-(pos_in_train_left/(train.path_dist[math.floor(index-1)] or 1))
|
||||
end
|
||||
return index
|
||||
end
|
||||
|
@ -219,7 +219,7 @@ function advtrains.train_step_a(id, train, dtime)
|
||||
- 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)
|
||||
advtrains.pathpredict(id, train, 3, -train.trainlen-3)
|
||||
end
|
||||
|
||||
--- 2a. set train.end_index which is required in different places, IF IT IS NOT SET YET by STMT afterwards. ---
|
||||
@ -359,9 +359,36 @@ function advtrains.train_step_a(id, train, dtime)
|
||||
--- 4a. update train.end_index to the new position ---
|
||||
train.end_index=advtrains.get_train_end_index(train)
|
||||
|
||||
--- 4b calculate how far a path is required ---
|
||||
local path_req_dd = 10 -- path required in driving direction
|
||||
local path_req_ndd = 4 -- path required against driving direction
|
||||
|
||||
-- when using easyBSS (block signalling), we need to make sure that the whole brake distance is known
|
||||
if advtrains_easybss then
|
||||
local acc_all = t_accel_all[1]
|
||||
local acc_eng = t_accel_eng[1]
|
||||
local nwagons = #train.trainparts
|
||||
local acc = acc_all + (acc_eng*train.locomotives_in_train)/nwagons
|
||||
local vel = train.velocity
|
||||
local brakedst = (vel*vel) / (2*acc)
|
||||
path_req_dd = math.ceil(brakedst+10)
|
||||
end
|
||||
|
||||
|
||||
local idx_front=math.max(train.index, train.detector_old_index)
|
||||
local idx_back=math.min(train.end_index, train.detector_old_end_index)
|
||||
local path_req_front, path_req_back
|
||||
if train.movedir == 1 then
|
||||
path_req_front = atround(idx_front + path_req_dd)
|
||||
path_req_back = atround(idx_back - path_req_ndd)
|
||||
else
|
||||
path_req_front = atround(idx_front + path_req_ndd)
|
||||
path_req_back = atround(idx_back - path_req_dd)
|
||||
end
|
||||
|
||||
--- 5. extend path as necessary ---
|
||||
--why this is an extra function, see under 3.
|
||||
advtrains.pathpredict(id, train, true)
|
||||
advtrains.pathpredict(id, train, path_req_front, path_req_back)
|
||||
|
||||
--- 5a. make pos/yaw available for possible recover calls ---
|
||||
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
|
||||
@ -382,13 +409,11 @@ function advtrains.train_step_a(id, train, dtime)
|
||||
|
||||
--- 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 del_keep=8
|
||||
local offtrack_keep=4
|
||||
local gen_front_keep= path_pregen_keep
|
||||
local gen_back_keep= atround(- train.trainlen - path_pregen_keep)
|
||||
|
||||
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)
|
||||
local delete_min=math.min(train.max_index_on_track - offtrack_keep, path_req_back - del_keep)
|
||||
local delete_max=math.max(train.min_index_on_track + offtrack_keep, path_req_front + del_keep)
|
||||
|
||||
if train.path_extent_min<delete_min then
|
||||
--atprint(sid(id),"clearing path min ",train.path_extent_min," to ",delete_min)
|
||||
@ -582,6 +607,7 @@ function advtrains.create_new_train_at(pos, pos_prev)
|
||||
while advtrains.trains[newtrain_id] do newtrain_id=advtrains.random_id() end--ensure uniqueness
|
||||
|
||||
advtrains.trains[newtrain_id]={}
|
||||
advtrains.trains[newtrain_id].id = newtrain_id
|
||||
advtrains.trains[newtrain_id].last_pos=pos
|
||||
advtrains.trains[newtrain_id].last_pos_prev=pos_prev
|
||||
advtrains.trains[newtrain_id].tarvelocity=0
|
||||
|
Loading…
x
Reference in New Issue
Block a user