Implement a reverse path lookup for trains instead of an occupations window system
This commit is contained in:
parent
caf2bda7bc
commit
b420a71939
|
@ -140,7 +140,7 @@ If you can't enter or leave a train because the doors are closed, holding the Sn
|
||||||
Most modders will be satisfied with the built-in tracks. If cog railways, maglev trains and mine trains are added, it is necessary to understand the definition of tracks. Although the tracks API is there, explaining it would require more effort than me creating the wanted definitions myself. Contact me if you need to register your own rails using my registration functions.
|
Most modders will be satisfied with the built-in tracks. If cog railways, maglev trains and mine trains are added, it is necessary to understand the definition of tracks. Although the tracks API is there, explaining it would require more effort than me creating the wanted definitions myself. Contact me if you need to register your own rails using my registration functions.
|
||||||
|
|
||||||
However, it is still possible to register single rails by understanding the node properties of rails.
|
However, it is still possible to register single rails by understanding the node properties of rails.
|
||||||
minetest.register_node(nodename, {
|
minetest.register_node(nodename, { -- TODO this is outdated!
|
||||||
... usual node definition ...
|
... usual node definition ...
|
||||||
groups = {
|
groups = {
|
||||||
advtrains_track_<tracktype>=1
|
advtrains_track_<tracktype>=1
|
||||||
|
@ -151,27 +151,27 @@ minetest.register_node(nodename, {
|
||||||
connect1 = 0,
|
connect1 = 0,
|
||||||
connect2 = 8,
|
connect2 = 8,
|
||||||
^- These values tell the direction (horizontal) the rail ends are pointing to. 0 means +Z, then rotation values increase clockwise. For a translation of directions to positions see helpers.lua.
|
^- These values tell the direction (horizontal) the rail ends are pointing to. 0 means +Z, then rotation values increase clockwise. For a translation of directions to positions see helpers.lua.
|
||||||
rely1=0,
|
rely1=0,
|
||||||
rely2=0,
|
rely2=0,
|
||||||
^- the Y height of the rail end 1/2. A value of >=1 means that the rail end points to the next y layer at rely-1
|
^- the Y height of the rail end 1/2. A value of >=1 means that the rail end points to the next y layer at rely-1
|
||||||
railheight=0,
|
railheight=0,
|
||||||
^- the height value of this rail that is saved in the path. usually the median of rely1 and rely2.
|
^- the height value of this rail that is saved in the path. usually the median of rely1 and rely2.
|
||||||
|
|
||||||
can_dig=function(pos)
|
can_dig=function(pos)
|
||||||
return not advtrains.get_train_at_pos(pos)
|
return not advtrains.get_train_at_pos(pos)
|
||||||
end,
|
end,
|
||||||
after_dig_node=function(pos)
|
after_dig_node=function(pos)
|
||||||
advtrains.ndb.update(pos)
|
advtrains.ndb.update(pos)
|
||||||
end,
|
end,
|
||||||
after_place_node=function(pos)
|
after_place_node=function(pos)
|
||||||
advtrains.ndb.update(pos)
|
advtrains.ndb.update(pos)
|
||||||
end,
|
end,
|
||||||
^- the code in these 3 default minetest API functions is required for advtrains to work, however you can add your own code
|
^- the code in these 3 default minetest API functions is required for advtrains to work, however you can add your own code
|
||||||
|
|
||||||
advtrains = {
|
advtrains = {
|
||||||
on_train_enter=function(pos, train_id) end
|
on_train_enter=function(pos, train_id) end
|
||||||
^- called when a train enters the rail
|
^- called when a train enters the rail
|
||||||
on_train_leave=function(pos, train_id) end
|
on_train_leave=function(pos, train_id) end
|
||||||
^- called when a train leaves the rail
|
^- called when a train leaves the rail
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -175,7 +175,7 @@ local matchptn={
|
||||||
end,
|
end,
|
||||||
["B([0-9B]+)"]=function(id, train, match)
|
["B([0-9B]+)"]=function(id, train, match)
|
||||||
if match=="B" then
|
if match=="B" then
|
||||||
train.atc_brake_target = -1 -- this means emergency brake. TODO don't forget to implement in train step!
|
train.atc_brake_target = -1
|
||||||
train.tarvelocity = 0
|
train.tarvelocity = 0
|
||||||
elseif train.velocity>tonumber(match) then
|
elseif train.velocity>tonumber(match) then
|
||||||
train.atc_brake_target=tonumber(match)
|
train.atc_brake_target=tonumber(match)
|
||||||
|
|
|
@ -109,7 +109,7 @@ end
|
||||||
|
|
||||||
function advtrains.dir_to_angle(dir)
|
function advtrains.dir_to_angle(dir)
|
||||||
local uvec = vector.normalize(advtrains.dirToCoord(dir))
|
local uvec = vector.normalize(advtrains.dirToCoord(dir))
|
||||||
return math.atan2(uvec.z, uvec.x)
|
return math.atan2(uvec.x, uvec.z)
|
||||||
end
|
end
|
||||||
|
|
||||||
local pi, pi2 = math.pi, 2*math.pi
|
local pi, pi2 = math.pi, 2*math.pi
|
||||||
|
@ -153,8 +153,6 @@ function advtrains.conn_angle_median(cdir1, cdir2)
|
||||||
return ang1 + advtrains.minAngleDiffRad(ang1, ang2)/2
|
return ang1 + advtrains.minAngleDiffRad(ang1, ang2)/2
|
||||||
end
|
end
|
||||||
|
|
||||||
-- TODO removed dumppath, where is this used?
|
|
||||||
|
|
||||||
function advtrains.merge_tables(a, ...)
|
function advtrains.merge_tables(a, ...)
|
||||||
local new={}
|
local new={}
|
||||||
for _,t in ipairs({a,...}) do
|
for _,t in ipairs({a,...}) do
|
||||||
|
@ -170,8 +168,6 @@ function advtrains.save_keys(tbl, keys)
|
||||||
return new
|
return new
|
||||||
end
|
end
|
||||||
|
|
||||||
-- TODO yaw_from_3_positions and get_wagon_yaw removed
|
|
||||||
|
|
||||||
function advtrains.get_real_index_position(path, index)
|
function advtrains.get_real_index_position(path, index)
|
||||||
if not path or not index then return end
|
if not path or not index then return end
|
||||||
|
|
||||||
|
@ -258,7 +254,7 @@ function advtrains.rotate_conn_by(conn, rotate)
|
||||||
return tmp
|
return tmp
|
||||||
end
|
end
|
||||||
|
|
||||||
--TODO use this
|
|
||||||
function advtrains.oppd(dir)
|
function advtrains.oppd(dir)
|
||||||
return advtrains.rotate_conn_by(dir, AT_CMAX/2)
|
return advtrains.rotate_conn_by(dir, AT_CMAX/2)
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
-- occupation.lua
|
-- occupation.lua
|
||||||
--[[
|
--[[
|
||||||
Collects and manages positions where trains occupy and/or reserve/require space
|
Collects and manages positions where trains occupy and/or reserve/require space
|
||||||
|
THIS SECTION ABOVE IS OUTDATED, look below
|
||||||
|
|
||||||
Zone diagram of a train:
|
Zone diagram of a train:
|
||||||
|___| |___| --> Direction of travel
|
|___| |___| --> Direction of travel
|
||||||
|
@ -41,41 +42,46 @@ occ_chg[n] = {
|
||||||
new_val, (0 when entry was deleted)
|
new_val, (0 when entry was deleted)
|
||||||
}
|
}
|
||||||
|
|
||||||
*Sequence number:
|
---------------------
|
||||||
Sequence number system reserved for possible future use, but unused.
|
It turned out that, especially for the TSS, some more, even overlapping zones are required.
|
||||||
The train will (and has to) memorize it's zone path indexes ("windows"), and do all actions that in any way modify these zone lengths
|
Packing those into a data structure would just become a huge mess!
|
||||||
in the movement phase (after restore, but before reporting occupations)
|
Instead, this occupation system will store the path indices of positions in the corresponding.
|
||||||
((
|
train's paths.
|
||||||
The sequence number is used to determine out-of-date entries to the occupation list
|
So, the occupation is a reverse lookup of paths.
|
||||||
The current sequence number (seqnum) is increased each step, until it rolls over MAX_SEQNUM, which is when a complete reset is triggered
|
Then, a callback system will handle changes in those indices, as follows:
|
||||||
Inside a step, when a train updates an occupation, the sequence number is set to the currently active sequence number
|
|
||||||
Whenever checking an entry for other occupations (e.g. in the aware zone), all entries that have a seqnum different from the current seqnum
|
|
||||||
are considered not existant, and are cleared.
|
|
||||||
Note that those outdated entries are only cleared on-demand, so there will be a large memory overhead over time. This is why in certain time intervals
|
|
||||||
complete resets are required (however, this method should be much more performant than resetting the whole occ table each step, to spare continuous memory allocations)
|
|
||||||
This complex behavior is required because there is no way to reliably determine which positions are _no longer_ occupied...
|
|
||||||
))
|
|
||||||
|
|
||||||
Composition of a step:
|
Whenever the train generates new path items (path_get/path_create), their counterpart indices will be filled in here.
|
||||||
|
Whenever a path gets invalidated or path items are deleted, their index counterpart is erased from here.
|
||||||
|
|
||||||
1. (only when needed) restore step - write all current occupations into the table
|
When a train needs to know whether a position is blocked by another train, it will (and is permitted to)
|
||||||
2. trains move
|
query the train.index and train.end_index and compare them to the blocked position's index.
|
||||||
3. trains pass new occupations to here. We keep track of which entries have changed
|
|
||||||
4. we iterate our change lists and determine what to do
|
Callback system for 3rd-party path checkers: TODO
|
||||||
|
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.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
]]--
|
]]--
|
||||||
local o = {}
|
local o = {}
|
||||||
|
|
||||||
o.restore_required = true
|
|
||||||
|
|
||||||
local MAX_SEQNUM = 65500
|
|
||||||
local seqnum = 0
|
|
||||||
|
|
||||||
local occ = {}
|
local occ = {}
|
||||||
local occ_chg = {}
|
local occ_chg = {}
|
||||||
|
|
||||||
local addchg, handle_chg
|
|
||||||
|
|
||||||
|
|
||||||
local function occget(p)
|
local function occget(p)
|
||||||
local t = occ[p.y]
|
local t = occ[p.y]
|
||||||
|
@ -112,16 +118,8 @@ local function occgetcreate(p)
|
||||||
return t
|
return t
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Resets the occupation memory, and sets the o.restore_required flag that instructs trains to report their occupations before moving
|
|
||||||
function o.reset()
|
|
||||||
o.restore_required = true
|
|
||||||
occ = {}
|
|
||||||
occ_chg = {}
|
|
||||||
seqnum = 0
|
|
||||||
end
|
|
||||||
|
|
||||||
-- set occupation inside the restore step
|
function o.set_item(train_id, pos, idx)
|
||||||
function o.init_occupation(train_id, pos, oid)
|
|
||||||
local t = occgetcreate(pos)
|
local t = occgetcreate(pos)
|
||||||
local i = 1
|
local i = 1
|
||||||
while t[i] do
|
while t[i] do
|
||||||
|
@ -131,28 +129,11 @@ function o.init_occupation(train_id, pos, oid)
|
||||||
i = i + 2
|
i = i + 2
|
||||||
end
|
end
|
||||||
t[i] = train_id
|
t[i] = train_id
|
||||||
t[i+1] = oid
|
t[i+1] = idx
|
||||||
end
|
|
||||||
|
|
||||||
function o.set_occupation(train_id, pos, oid)
|
|
||||||
local t = occgetcreate(pos)
|
|
||||||
local i = 1
|
|
||||||
while t[i] do
|
|
||||||
if t[i]==train_id then
|
|
||||||
break
|
|
||||||
end
|
|
||||||
i = i + 2
|
|
||||||
end
|
|
||||||
local oldoid = t[i+1] or 0
|
|
||||||
if oldoid ~= oid then
|
|
||||||
addchg(pos, train_id, oldoid, oid)
|
|
||||||
end
|
|
||||||
t[i] = train_id
|
|
||||||
t[i+1] = oid
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function o.clear_occupation(train_id, pos)
|
function o.clear_item(train_id, pos)
|
||||||
local t = occget(pos)
|
local t = occget(pos)
|
||||||
if not t then return end
|
if not t then return end
|
||||||
local i = 1
|
local i = 1
|
||||||
|
@ -176,94 +157,6 @@ function o.clear_occupation(train_id, pos)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function addchg(pos, train_id, old, new)
|
|
||||||
occ_chg[#occ_chg + 1] = {
|
|
||||||
pos = pos,
|
|
||||||
train_id = train_id,
|
|
||||||
old_val = old,
|
|
||||||
new_val = new,
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Called after all occupations have been fed in
|
|
||||||
-- This function is doing the interesting work...
|
|
||||||
function o.end_step()
|
|
||||||
count_chg = false
|
|
||||||
|
|
||||||
for _,chg in ipairs(occ_chg) do
|
|
||||||
local t = occget(chg.pos)
|
|
||||||
if not t then
|
|
||||||
atwarn("o.end_step() change entry but there's no entry in occ table!",chg)
|
|
||||||
end
|
|
||||||
handle_chg(t, chg.pos, chg.train_id, chg.old_val, chg.new_val)
|
|
||||||
end
|
|
||||||
|
|
||||||
seqnum = seqnum + 1
|
|
||||||
end
|
|
||||||
|
|
||||||
function handle_chg(t, pos, train_id, old, new)
|
|
||||||
-- Handling the actual "change" is only necessary on_train_enter (change to 1) and on_train_leave (change from 1)
|
|
||||||
if new==1 then
|
|
||||||
o.call_enter_callback(pos, train_id)
|
|
||||||
elseif old==1 then
|
|
||||||
o.call_leave_callback(pos, train_id)
|
|
||||||
end
|
|
||||||
|
|
||||||
--all other cases check the simultaneous presence of 2 or more occupations
|
|
||||||
if #t<=2 then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
local blocking = {}
|
|
||||||
local aware = {}
|
|
||||||
local i = 1
|
|
||||||
while t[i] do
|
|
||||||
if t[i+1] ~= 7 then --anything not aware zone:
|
|
||||||
blocking[#blocking+1] = i
|
|
||||||
else
|
|
||||||
aware[#aware+1] = i
|
|
||||||
end
|
|
||||||
i = i + 2
|
|
||||||
end
|
|
||||||
if #blocking > 0 then
|
|
||||||
-- the aware trains should brake
|
|
||||||
for _, ix in ipairs(aware) do
|
|
||||||
advtrains.atc.train_set_command(t[ix], "B2")
|
|
||||||
end
|
|
||||||
if #blocking > 1 then
|
|
||||||
-- not good, 2 trains interfered with their blocking zones
|
|
||||||
-- make them brake too
|
|
||||||
local txt = {}
|
|
||||||
for _, ix in ipairs(blocking) do
|
|
||||||
advtrains.atc.train_set_command(t[ix], "B2")
|
|
||||||
txt[#txt+1] = t[ix]
|
|
||||||
end
|
|
||||||
atwarn("Trains",table.concat(txt, ","), "interfered with their blocking zones, braking...")
|
|
||||||
-- TODO: different behavior for automatic trains! they need to be notified of those brake events and handle them!
|
|
||||||
-- To drive in safety zone is ok when train is controlled by hand
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
function o.call_enter_callback(pos, train_id)
|
|
||||||
--atprint("instructed to call enter calback")
|
|
||||||
|
|
||||||
local node = advtrains.ndb.get_node(pos) --this spares the check if node is nil, it has a name in any case
|
|
||||||
local mregnode=minetest.registered_nodes[node.name]
|
|
||||||
if mregnode and mregnode.advtrains and mregnode.advtrains.on_train_enter then
|
|
||||||
mregnode.advtrains.on_train_enter(pos, train_id)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
function o.call_leave_callback(pos, train_id)
|
|
||||||
--atprint("instructed to call leave calback")
|
|
||||||
|
|
||||||
local node = advtrains.ndb.get_node(pos) --this spares the check if node is nil, it has a name in any case
|
|
||||||
local mregnode=minetest.registered_nodes[node.name]
|
|
||||||
if mregnode and mregnode.advtrains and mregnode.advtrains.on_train_leave then
|
|
||||||
mregnode.advtrains.on_train_leave(pos, train_id)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Checks whether some other train (apart from train_id) has it's 0 zone here
|
-- Checks whether some other train (apart from train_id) has it's 0 zone here
|
||||||
function o.check_collision(pos, train_id)
|
function o.check_collision(pos, train_id)
|
||||||
local npos = advtrains.round_vector_floor_y(pos)
|
local npos = advtrains.round_vector_floor_y(pos)
|
||||||
|
@ -272,7 +165,10 @@ function o.check_collision(pos, train_id)
|
||||||
local i = 1
|
local i = 1
|
||||||
while t[i] do
|
while t[i] do
|
||||||
if t[i]~=train_id then
|
if t[i]~=train_id then
|
||||||
if t[i+1] ~= 7 then
|
local idx = t[i+1]
|
||||||
|
local train = advtrains.trains[train_id]
|
||||||
|
advtrains.train_ensure_clean(train_id, train)
|
||||||
|
if idx >= train.end_index and idx <= train.index then
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -123,12 +123,58 @@ function advtrains.path_create(train, pos, connid, rel_index)
|
||||||
train.path_req_f=0
|
train.path_req_f=0
|
||||||
train.path_req_b=0
|
train.path_req_b=0
|
||||||
|
|
||||||
|
advtrains.occ.set_item(train.id, posr, 0)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Sets position and connid to properly restore after a crash, e.g. in order
|
||||||
|
-- to save the train or to invalidate its path
|
||||||
|
-- Assumes that the train is in clean state
|
||||||
|
-- if invert ist true, setrestore will use the end index
|
||||||
|
function advtrains.path_setrestore(train, invert)
|
||||||
|
local idx = train.index
|
||||||
|
if invert then
|
||||||
|
idx = train.end_index
|
||||||
|
end
|
||||||
|
|
||||||
|
local pos, connid, frac = advtrains.path_getrestore(train, idx, invert)
|
||||||
|
|
||||||
|
train.last_pos = pos
|
||||||
|
train.last_connid = connid
|
||||||
|
train.last_frac = frac
|
||||||
|
end
|
||||||
|
-- Get restore position, connid and frac (in this order) for a train that will originate at the passed index
|
||||||
|
-- If invert is set, it will return path_cp and multiply frac by -1, in order to reverse the train there.
|
||||||
|
function advtrains.path_getrestore(train, index, invert)
|
||||||
|
local idx = train.index
|
||||||
|
local cns = train.path_cn
|
||||||
|
|
||||||
|
if invert then
|
||||||
|
idx = train.end_index
|
||||||
|
cns = train.path_cp
|
||||||
|
end
|
||||||
|
|
||||||
|
fli = atfloor(train.index)
|
||||||
|
if fli > train.path_trk_f then
|
||||||
|
fli = train.path_trk_f
|
||||||
|
end
|
||||||
|
if fli < train.path_trk_b then
|
||||||
|
fli = train.path_trk_b
|
||||||
|
end
|
||||||
|
|
||||||
|
return advtrains.path_get(train, fli),
|
||||||
|
cns[fli],
|
||||||
|
(idx - fli) * (invert and -1 or 1)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Invalidates a path
|
-- Invalidates a path
|
||||||
-- TODO: this is supposed to clear stuff from the occupation tables
|
-- this is supposed to clear stuff from the occupation tables
|
||||||
-- (note: why didn't I think of that earlier?)
|
|
||||||
function advtrains.path_invalidate(train)
|
function advtrains.path_invalidate(train)
|
||||||
|
if train.path then
|
||||||
|
for i,p in pairs(train.path) do
|
||||||
|
advtrains.occ.clear_item(train.id, advtrains.round_vector_floor_y(p))
|
||||||
|
end
|
||||||
|
end
|
||||||
train.path = nil
|
train.path = nil
|
||||||
train.path_dist = nil
|
train.path_dist = nil
|
||||||
train.path_cp = nil
|
train.path_cp = nil
|
||||||
|
@ -172,6 +218,8 @@ function advtrains.path_get(train, index)
|
||||||
end
|
end
|
||||||
pef = pef + 1
|
pef = pef + 1
|
||||||
if adj_pos then
|
if adj_pos then
|
||||||
|
advtrains.occ.set_item(train.id, adj_pos, pef)
|
||||||
|
|
||||||
adj_pos.y = adj_pos.y + nextrail_y
|
adj_pos.y = adj_pos.y + nextrail_y
|
||||||
train.path_cp[pef] = adj_connid
|
train.path_cp[pef] = adj_connid
|
||||||
local mconnid = advtrains.get_matching_conn(adj_connid, #next_conns)
|
local mconnid = advtrains.get_matching_conn(adj_connid, #next_conns)
|
||||||
|
@ -199,6 +247,8 @@ function advtrains.path_get(train, index)
|
||||||
end
|
end
|
||||||
peb = peb - 1
|
peb = peb - 1
|
||||||
if adj_pos then
|
if adj_pos then
|
||||||
|
advtrains.occ.set_item(train.id, adj_pos, peb)
|
||||||
|
|
||||||
adj_pos.y = adj_pos.y + nextrail_y
|
adj_pos.y = adj_pos.y + nextrail_y
|
||||||
train.path_cn[peb] = adj_connid
|
train.path_cn[peb] = adj_connid
|
||||||
local mconnid = advtrains.get_matching_conn(adj_connid, #next_conns)
|
local mconnid = advtrains.get_matching_conn(adj_connid, #next_conns)
|
||||||
|
@ -207,7 +257,7 @@ function advtrains.path_get(train, index)
|
||||||
train.path_trk_b = peb
|
train.path_trk_b = peb
|
||||||
else
|
else
|
||||||
-- off-track fallback behavior
|
-- off-track fallback behavior
|
||||||
adj_pos = advtrains.pos_add_angle(pos, train.path_dir[peb+1])
|
adj_pos = advtrains.pos_add_angle(pos, train.path_dir[peb+1] + math.pi)
|
||||||
train.path_dir[peb] = train.path_dir[peb+1]
|
train.path_dir[peb] = train.path_dir[peb+1]
|
||||||
end
|
end
|
||||||
train.path[peb] = adj_pos
|
train.path[peb] = adj_pos
|
||||||
|
@ -241,7 +291,7 @@ function advtrains.path_get_interpolated(train, index)
|
||||||
|
|
||||||
local ang = advtrains.minAngleDiffRad(a_floor, a_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), p_floor, p_ceil -- TODO does this behave correctly?
|
return vector.add(p_floor, vector.multiply(vector.subtract(p_ceil, p_floor), frac)), (a_floor + frac * ang)%(2*math.pi), p_floor, p_ceil
|
||||||
end
|
end
|
||||||
-- returns the 2 path positions directly adjacent to index and the fraction on how to interpolate between them
|
-- returns the 2 path positions directly adjacent to index and the fraction on how to interpolate between them
|
||||||
-- returns: pos_floor, pos_ceil, fraction
|
-- returns: pos_floor, pos_ceil, fraction
|
||||||
|
@ -293,6 +343,7 @@ local PATH_CLEAR_KEEP = 4
|
||||||
function advtrains.path_clear_unused(train)
|
function advtrains.path_clear_unused(train)
|
||||||
local i
|
local i
|
||||||
for i = train.path_ext_b, train.path_req_b - PATH_CLEAR_KEEP do
|
for i = train.path_ext_b, train.path_req_b - PATH_CLEAR_KEEP do
|
||||||
|
advtrains.occ.clear_item(train.id, advtrains.round_vector_floor_y(train.path[i]))
|
||||||
train.path[i] = nil
|
train.path[i] = nil
|
||||||
train.path_dist[i-1] = nil
|
train.path_dist[i-1] = nil
|
||||||
train.path_cp[i] = nil
|
train.path_cp[i] = nil
|
||||||
|
@ -302,6 +353,7 @@ function advtrains.path_clear_unused(train)
|
||||||
end
|
end
|
||||||
|
|
||||||
for i = train.path_ext_f,train.path_req_f + PATH_CLEAR_KEEP,-1 do
|
for i = train.path_ext_f,train.path_req_f + PATH_CLEAR_KEEP,-1 do
|
||||||
|
advtrains.occ.clear_item(train.id, advtrains.round_vector_floor_y(train.path[i]))
|
||||||
train.path[i] = nil
|
train.path[i] = nil
|
||||||
train.path_dist[i] = nil
|
train.path_dist[i] = nil
|
||||||
train.path_cp[i] = nil
|
train.path_cp[i] = nil
|
||||||
|
|
|
@ -70,7 +70,7 @@ advtrains.mainloop_trainlogic=function(dtime)
|
||||||
for k,v in pairs(advtrains.trains) do
|
for k,v in pairs(advtrains.trains) do
|
||||||
advtrains.atprint_context_tid=sid(k)
|
advtrains.atprint_context_tid=sid(k)
|
||||||
advtrains.atprint_context_tid_full=k
|
advtrains.atprint_context_tid_full=k
|
||||||
advtrains.train_ensure_clean(k, v, dtime, advtrains.occ.restore_required)
|
advtrains.train_ensure_clean(k, v)
|
||||||
end
|
end
|
||||||
|
|
||||||
for k,v in pairs(advtrains.trains) do
|
for k,v in pairs(advtrains.trains) do
|
||||||
|
@ -135,12 +135,6 @@ minetest.register_on_dieplayer(function(player)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
--[[
|
--[[
|
||||||
The occupation window system.
|
|
||||||
|
|
||||||
Each train occupies certain nodes as certain occupation types. See occupation.lua for a graphic and an ID listing.
|
|
||||||
There's an occwindows table in the train table. This is clearable, such as the path, and therefore needs to be exactly reconstructible.
|
|
||||||
During runtime, the extents (in meters) of the zones are determined. the occwindows table holds the assigned fractional path indices.
|
|
||||||
After the train moves, the occupation windows are re-calculated, and all differences are written to the occupation tables.
|
|
||||||
|
|
||||||
Zone diagram of a train (copy from occupation.lua!):
|
Zone diagram of a train (copy from occupation.lua!):
|
||||||
|___| |___| --> Direction of travel
|
|___| |___| --> Direction of travel
|
||||||
|
@ -150,10 +144,10 @@ Zone diagram of a train (copy from occupation.lua!):
|
||||||
[1] [2] [3] [4] [5] [6] [7] [8]
|
[1] [2] [3] [4] [5] [6] [7] [8]
|
||||||
This mapping from indices in occwindows to zone ids is contained in WINDOW_ZONE_IDS
|
This mapping from indices in occwindows to zone ids is contained in WINDOW_ZONE_IDS
|
||||||
|
|
||||||
occwindows = {
|
|
||||||
[n] = (index of the position determined in the graphic above,
|
The occupation system has been abandoned. The constants will still be used
|
||||||
where floor(i) belongs to the left zone and floor(i+1) belongs to the right.
|
to determine the couple distance
|
||||||
}
|
(because of the reverse lookup, the couple system simplifies a lot...)
|
||||||
|
|
||||||
]]--
|
]]--
|
||||||
-- unless otherwise stated, in meters.
|
-- unless otherwise stated, in meters.
|
||||||
|
@ -181,6 +175,7 @@ end
|
||||||
|
|
||||||
|
|
||||||
-- Calculates the indices where the window borders of the occupation windows are.
|
-- Calculates the indices where the window borders of the occupation windows are.
|
||||||
|
-- TODO adapt this code to new system, probably into a callback
|
||||||
local function calc_occwindows(id, train)
|
local function calc_occwindows(id, train)
|
||||||
local end_index = advtrains.path_get_index_by_offset(train, train.index, -train.trainlen)
|
local end_index = advtrains.path_get_index_by_offset(train, train.index, -train.trainlen)
|
||||||
train.end_index = end_index
|
train.end_index = end_index
|
||||||
|
@ -212,45 +207,50 @@ local function calc_occwindows(id, train)
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
-- this function either inits (no write_mode), sets(1) or clears(2) the occupations for train
|
-- Small local util function to recalculate train's end index
|
||||||
local function write_occupation(win, train_id, train, write_mode)
|
local function recalc_end_index(train)
|
||||||
local n_window = 2
|
train.end_index = advtrains.path_get_index_by_offset(train, train.index, -train.trainlen)
|
||||||
local c_index = math.ceil(win[1])
|
|
||||||
while win[n_window] do
|
|
||||||
local winix = win[n_window]
|
|
||||||
local oid = WINDOW_ZONE_IDS[n_window - 1]
|
|
||||||
while winix > c_index do
|
|
||||||
local pos = advtrains.path_get(train, c_index)
|
|
||||||
if write_mode == 1 then
|
|
||||||
advtrains.occ.set_occupation(train_id, pos, oid)
|
|
||||||
elseif write_mode == 2 then
|
|
||||||
advtrains.occ.clear_occupation(train_id, pos)
|
|
||||||
else
|
|
||||||
advtrains.occ.init_occupation(train_id, pos, oid)
|
|
||||||
end
|
|
||||||
c_index = c_index + 1
|
|
||||||
end
|
|
||||||
c_index = math.ceil(winix)
|
|
||||||
n_window = n_window + 1
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
end
|
||||||
local function apply_occupation_changes(old, new, train_id, train)
|
|
||||||
-- TODO
|
-- Occupation Callback system
|
||||||
|
-- see occupation.lua
|
||||||
|
|
||||||
|
local callbacks_new_path = {}
|
||||||
|
local callbacks_update = {}
|
||||||
|
|
||||||
|
function advtrains.tb_register_on_new_path(func)
|
||||||
|
assertt(func, "function")
|
||||||
|
table.insert(callbacks_new_path, func)
|
||||||
|
end
|
||||||
|
function advtrains.tb_register_on_update(func)
|
||||||
|
assertt(func, "function")
|
||||||
|
table.insert(callbacks_update, func)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function run_callbacks_new_path(id, train)
|
||||||
|
for _,f in ipairs(callbacks_new_path) do
|
||||||
|
f(id, train)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local function run_callbacks_update(id, train)
|
||||||
|
for _,f in ipairs(callbacks_new_path) do
|
||||||
|
f(id, train)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
-- train_ensure_clean: responsible for creating a state that we can work on, after one of the following events has happened:
|
-- train_ensure_clean: responsible for creating a state that we can work on, after one of the following events has happened:
|
||||||
-- - the train's path got cleared
|
-- - the train's path got cleared
|
||||||
-- - the occupation table got cleared
|
-- - save files were loaded
|
||||||
-- Additionally, this gets called outside the step cycle to initialize and/or remove a train, then occ_write_mode is set.
|
-- Additionally, this gets called outside the step cycle to initialize and/or remove a train, then occ_write_mode is set.
|
||||||
function advtrains.train_ensure_clean(id, train, dtime, report_occupations, occ_write_mode)
|
function advtrains.train_ensure_clean(id, train)
|
||||||
train.dirty = true
|
train.dirty = true
|
||||||
if train.no_step then return end
|
if train.no_step then return end
|
||||||
|
|
||||||
assertdef(train, "velocity", 0)
|
assertdef(train, "velocity", 0)
|
||||||
assertdef(train, "tarvelocity", 0)
|
assertdef(train, "tarvelocity", 0)
|
||||||
assertdef(train, "acceleration", 0)
|
assertdef(train, "acceleration", 0)
|
||||||
|
assertdef(train, "id", id)
|
||||||
|
|
||||||
|
|
||||||
if not train.drives_on or not train.max_speed then
|
if not train.drives_on or not train.max_speed then
|
||||||
|
@ -282,18 +282,14 @@ function advtrains.train_ensure_clean(id, train, dtime, report_occupations, occ_
|
||||||
end
|
end
|
||||||
-- by now, we should have a working initial path
|
-- by now, we should have a working initial path
|
||||||
train.wait_for_path = false
|
train.wait_for_path = false
|
||||||
train.occwindows = nil
|
|
||||||
advtrains.update_trainpart_properties(id)
|
advtrains.update_trainpart_properties(id)
|
||||||
|
recalc_end_index(train)
|
||||||
|
|
||||||
atdebug("Train",id,": Successfully restored path at",train.last_pos," connid",train.last_connid," frac",train.last_frac)
|
atdebug("Train",id,": Successfully restored path at",train.last_pos," connid",train.last_connid," frac",train.last_frac)
|
||||||
-- TODO recoverposition?!
|
|
||||||
end
|
-- run on_new_path callbacks
|
||||||
|
run_callbacks_new_path(id, train)
|
||||||
--restore occupation windows
|
|
||||||
if not train.occwindows then
|
|
||||||
train.occwindows = calc_occwindows(id, train)
|
|
||||||
end
|
|
||||||
if report_occupations then
|
|
||||||
write_occupation(train.occwindows, id, train, occ_write_mode)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
train.dirty = false -- TODO einbauen!
|
train.dirty = false -- TODO einbauen!
|
||||||
|
@ -346,8 +342,15 @@ function advtrains.train_step_b(id, train, dtime)
|
||||||
if train.active_control then
|
if train.active_control then
|
||||||
advtrains.atc.train_reset_command(id)
|
advtrains.atc.train_reset_command(id)
|
||||||
else
|
else
|
||||||
if train.atc_brake_target and train.atc_brake_target>=trainvelocity then
|
local braketar = train.atc_brake_target
|
||||||
|
local emerg = false -- atc_brake_target==-1 means emergency brake (BB command)
|
||||||
|
if braketar == -1 then
|
||||||
|
braketar = 0
|
||||||
|
emerg = true
|
||||||
|
end
|
||||||
|
if braketar and braketar>=trainvelocity then
|
||||||
train.atc_brake_target=nil
|
train.atc_brake_target=nil
|
||||||
|
braketar = nil
|
||||||
end
|
end
|
||||||
if train.atc_wait_finish then
|
if train.atc_wait_finish then
|
||||||
if not train.atc_brake_target and train.velocity==train.tarvelocity then
|
if not train.atc_brake_target and train.velocity==train.tarvelocity then
|
||||||
|
@ -365,8 +368,12 @@ function advtrains.train_step_b(id, train, dtime)
|
||||||
train.lever = 3
|
train.lever = 3
|
||||||
if train.tarvelocity>trainvelocity then train.lever=4 end
|
if train.tarvelocity>trainvelocity then train.lever=4 end
|
||||||
if train.tarvelocity<trainvelocity then
|
if train.tarvelocity<trainvelocity then
|
||||||
if (train.atc_brake_target and train.atc_brake_target<trainvelocity) then
|
if (braketar and braketar<trainvelocity) then
|
||||||
train.lever=1
|
if emerg then
|
||||||
|
train.lever = 0
|
||||||
|
else
|
||||||
|
train.lever=1
|
||||||
|
end
|
||||||
else
|
else
|
||||||
train.lever=2
|
train.lever=2
|
||||||
end
|
end
|
||||||
|
@ -417,30 +424,20 @@ function advtrains.train_step_b(id, train, dtime)
|
||||||
--- 4. move train ---
|
--- 4. move train ---
|
||||||
|
|
||||||
train.index=train.index and train.index+((train.velocity/(train.path_dist[math.floor(train.index)] or 1))*dtime) or 0
|
train.index=train.index and train.index+((train.velocity/(train.path_dist[math.floor(train.index)] or 1))*dtime) or 0
|
||||||
|
recalc_end_index()
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local function train_recalc_occupation(id, train)
|
|
||||||
local new_occwindows = calc_occwindows(id, train)
|
|
||||||
apply_occupation_changes(train.occwindows, new_occwindows, id)
|
|
||||||
train.occwindows = new_occwindows
|
|
||||||
end
|
|
||||||
|
|
||||||
function advtrains.train_step_c(id, train, dtime)
|
function advtrains.train_step_c(id, train, dtime)
|
||||||
if train.no_step or train.wait_for_path then return end
|
if train.no_step or train.wait_for_path then return end
|
||||||
|
|
||||||
-- all location/extent-critical actions have been done.
|
-- all location/extent-critical actions have been done.
|
||||||
-- calculate the new occupation window
|
-- calculate the new occupation window
|
||||||
train_recalc_occupation(id, train)
|
run_callbacks_update(id, train)
|
||||||
|
|
||||||
advtrains.path_clear_unused(train)
|
advtrains.path_clear_unused(train)
|
||||||
|
|
||||||
-- Set our path restoration position
|
advtrains.path_setrestore(train)
|
||||||
-- TODO make a common function to find a restore positionon the path, in case the wanted position is off-track
|
|
||||||
local fli = atfloor(train.index)
|
|
||||||
train.last_pos = advtrains.path_get(train, fli)
|
|
||||||
train.last_connid = train.path_cn[fli]
|
|
||||||
train.last_frac = train.index - fli
|
|
||||||
|
|
||||||
-- less important stuff
|
-- less important stuff
|
||||||
|
|
||||||
|
@ -507,6 +504,52 @@ if train.no_step or train.wait_for_path then return end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Default occupation callbacks for node callbacks
|
||||||
|
-- (remember, train.end_index is set separately because callbacks are
|
||||||
|
-- asserted to rely on this)
|
||||||
|
|
||||||
|
local function tnc_call_enter_callback(pos, train_id)
|
||||||
|
--atprint("instructed to call enter calback")
|
||||||
|
|
||||||
|
local node = advtrains.ndb.get_node(pos) --this spares the check if node is nil, it has a name in any case
|
||||||
|
local mregnode=minetest.registered_nodes[node.name]
|
||||||
|
if mregnode and mregnode.advtrains and mregnode.advtrains.on_train_enter then
|
||||||
|
mregnode.advtrains.on_train_enter(pos, train_id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local function tnc_call_leave_callback(pos, train_id)
|
||||||
|
--atprint("instructed to call leave calback")
|
||||||
|
|
||||||
|
local node = advtrains.ndb.get_node(pos) --this spares the check if node is nil, it has a name in any case
|
||||||
|
local mregnode=minetest.registered_nodes[node.name]
|
||||||
|
if mregnode and mregnode.advtrains and mregnode.advtrains.on_train_leave then
|
||||||
|
mregnode.advtrains.on_train_leave(pos, train_id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
advtrains.te_register_on_new_path(function(id, train)
|
||||||
|
train.tnc = {
|
||||||
|
old_index = atround(train.index)
|
||||||
|
old_end_index = atround(train.end_index)
|
||||||
|
}
|
||||||
|
end)
|
||||||
|
advtrains.te_register_on_update(function(id, train)
|
||||||
|
local new_index = atround(train.index)
|
||||||
|
local new_end_index = atround(train.end_index)
|
||||||
|
local old_index = train.tnc.old_index
|
||||||
|
local old_end_index = train.tnc.old_end_index
|
||||||
|
while old_index < new_index do
|
||||||
|
old_index = old_index + 1
|
||||||
|
local pos = advtrains.round_vector_floor_y(advtrains.path_get(old_index))
|
||||||
|
tnc_call_enter_callback(pos, id)
|
||||||
|
end
|
||||||
|
while old_end_index > new_end_index do
|
||||||
|
local pos = advtrains.round_vector_floor_y(advtrains.path_get(old_end_index))
|
||||||
|
tnc_call_leave_callback(pos, id)
|
||||||
|
old_end_index = old_end_index - 1
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
--TODO: Collisions!
|
--TODO: Collisions!
|
||||||
|
|
||||||
|
|
||||||
|
@ -529,9 +572,8 @@ function advtrains.create_new_train_at(pos, connid, ioff, trainparts)
|
||||||
advtrains.trains[new_id] = t
|
advtrains.trains[new_id] = t
|
||||||
atdebug("Created new train:",t)
|
atdebug("Created new train:",t)
|
||||||
|
|
||||||
advtrains.update_trainpart_properties(new_id)
|
|
||||||
|
|
||||||
advtrains.train_ensure_clean(new_id, advtrains.trains[new_id], 0, true, 1)
|
advtrains.train_ensure_clean(new_id, advtrains.trains[new_id])
|
||||||
|
|
||||||
return new_id
|
return new_id
|
||||||
end
|
end
|
||||||
|
@ -541,9 +583,7 @@ function advtrains.remove_train(id)
|
||||||
|
|
||||||
advtrains.train_ensure_clean(id, train)
|
advtrains.train_ensure_clean(id, train)
|
||||||
|
|
||||||
advtrains.update_trainpart_properties(id)
|
advtrains.path_invalidate(train)
|
||||||
|
|
||||||
advtrains.train_ensure_clean(id, train, 0, true, 2)
|
|
||||||
|
|
||||||
local tp = train.trainparts
|
local tp = train.trainparts
|
||||||
|
|
||||||
|
@ -566,7 +606,8 @@ function advtrains.add_wagon_to_train(wagon_id, train_id, index)
|
||||||
end
|
end
|
||||||
|
|
||||||
advtrains.update_trainpart_properties(train_id)
|
advtrains.update_trainpart_properties(train_id)
|
||||||
train_recalc_occupation(train_id, train)
|
recalc_end_index(train)
|
||||||
|
run_callbacks_update(train_id, train)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- this function sets wagon's pos_in_train(parts) properties and train's max_speed and drives_on (and more)
|
-- this function sets wagon's pos_in_train(parts) properties and train's max_speed and drives_on (and more)
|
||||||
|
@ -646,31 +687,17 @@ end
|
||||||
function advtrains.split_train_at_wagon(wagon_id)
|
function advtrains.split_train_at_wagon(wagon_id)
|
||||||
--get train
|
--get train
|
||||||
local data = advtrains.wagons[wagon_id]
|
local data = advtrains.wagons[wagon_id]
|
||||||
local train=advtrains.trains[data.train_id]
|
local old_id = data.train_id
|
||||||
|
local train=advtrains.trains[old_id]
|
||||||
local _, wagon = advtrains.get_wagon_prototype(data)
|
local _, wagon = advtrains.get_wagon_prototype(data)
|
||||||
|
|
||||||
advtrains.train_ensure_clean(data.train_id, train)
|
advtrains.train_ensure_clean(old_id, train)
|
||||||
|
|
||||||
local index=advtrains.path_get_index_by_offset(train, train.index, -(data.pos_in_train + wagon.wagon_span))
|
local index=advtrains.path_get_index_by_offset(train, train.index, -(data.pos_in_train + wagon.wagon_span))
|
||||||
|
|
||||||
if index < train.path_trk_b or index > train.path_trk_f then
|
-- find new initial path position for this train
|
||||||
atprint("split_train: pos_for_new_train is off-track") -- TODO function for finding initial positions from a path
|
local pos, connid, frac = advtrains.path_getrestore(train, index)
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
local pos, _, frac = advtrains.path_get_adjacent(train, index)
|
|
||||||
local nconn = train.path_cn[atfloor(index)]
|
|
||||||
--before doing anything, check if both are rails. else do not allow
|
|
||||||
if not pos then
|
|
||||||
atprint("split_train: pos_for_new_train not set")
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
local npos = advtrains.round_vector_floor_y(pos)
|
|
||||||
local node_ok=advtrains.get_rail_info_at(npos, train.drives_on)
|
|
||||||
if not node_ok then
|
|
||||||
atprint("split_train: pos_for_new_train ",advtrains.round_vector_floor_y(pos_for_new_train_prev)," not loaded or is not a rail")
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
-- build trainparts table, passing it directly to the train constructor
|
-- build trainparts table, passing it directly to the train constructor
|
||||||
local tp = {}
|
local tp = {}
|
||||||
|
@ -682,12 +709,9 @@ function advtrains.split_train_at_wagon(wagon_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
--create subtrain
|
--create subtrain
|
||||||
local newtrain_id=advtrains.create_new_train_at(npos, nconn, frac, tp)
|
local newtrain_id=advtrains.create_new_train_at(pos, connid, frac, tp)
|
||||||
local newtrain=advtrains.trains[newtrain_id]
|
local newtrain=advtrains.trains[newtrain_id]
|
||||||
|
|
||||||
--update train parts
|
|
||||||
advtrains.update_trainpart_properties(data.train_id)--atm it still is the desierd id.
|
|
||||||
|
|
||||||
train.tarvelocity=0
|
train.tarvelocity=0
|
||||||
newtrain.velocity=train.velocity
|
newtrain.velocity=train.velocity
|
||||||
newtrain.tarvelocity=0
|
newtrain.tarvelocity=0
|
||||||
|
@ -696,6 +720,11 @@ function advtrains.split_train_at_wagon(wagon_id)
|
||||||
newtrain.couple_lck_front=false
|
newtrain.couple_lck_front=false
|
||||||
train.couple_lck_back=false
|
train.couple_lck_back=false
|
||||||
|
|
||||||
|
--update train parts
|
||||||
|
advtrains.update_trainpart_properties(old_id)
|
||||||
|
recalc_end_index(train)
|
||||||
|
run_callbacks_update(old_id, train)
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--there are 4 cases:
|
--there are 4 cases:
|
||||||
|
@ -709,7 +738,7 @@ end
|
||||||
--true when trains are facing each other. needed on colliding.
|
--true when trains are facing each other. needed on colliding.
|
||||||
-- check done by iterating paths and checking their direction
|
-- check done by iterating paths and checking their direction
|
||||||
--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.
|
--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.
|
||||||
-- TODO do we need to change this behavior, since direct path accesses are now discouraged?
|
-- TODO Will be changed when implementing coupling.
|
||||||
function advtrains.trains_facing(train1, train2)
|
function advtrains.trains_facing(train1, train2)
|
||||||
local sr_pos=train1.path[atround(train1.index)]
|
local sr_pos=train1.path[atround(train1.index)]
|
||||||
local sr_pos_p=train1.path[atround(train1.index)-1]
|
local sr_pos_p=train1.path[atround(train1.index)-1]
|
||||||
|
@ -858,12 +887,9 @@ end
|
||||||
function advtrains.invert_train(train_id)
|
function advtrains.invert_train(train_id)
|
||||||
local train=advtrains.trains[train_id]
|
local train=advtrains.trains[train_id]
|
||||||
|
|
||||||
advtrains.train_ensure_clean(train_id, train, 0)
|
advtrains.train_ensure_clean(train_id, train)
|
||||||
-- Set the path restoration position to the opposite direction
|
|
||||||
local fli = atfloor(train.end_index) + 1
|
advtrains.path_setrestore(train, true)
|
||||||
train.last_pos = advtrains.path_get(train, fli)
|
|
||||||
train.last_connid = train.path_cp[fli]
|
|
||||||
train.last_frac = fli - train.end_index
|
|
||||||
|
|
||||||
-- rotate some other stuff
|
-- rotate some other stuff
|
||||||
train.couple_lck_back, train.couple_lck_front = train.couple_lck_front, train.couple_lck_back
|
train.couple_lck_back, train.couple_lck_front = train.couple_lck_front, train.couple_lck_back
|
||||||
|
|
|
@ -196,8 +196,6 @@ function wagon:destroy()
|
||||||
self.object:remove()
|
self.object:remove()
|
||||||
end
|
end
|
||||||
|
|
||||||
local pihalf = math.pi/2
|
|
||||||
|
|
||||||
function wagon:on_step(dtime)
|
function wagon:on_step(dtime)
|
||||||
return advtrains.pcall(function()
|
return advtrains.pcall(function()
|
||||||
if not self:ensure_init() then return end
|
if not self:ensure_init() then return end
|
||||||
|
@ -296,12 +294,12 @@ function wagon:on_step(dtime)
|
||||||
local fct=data.wagon_flipped and -1 or 1
|
local fct=data.wagon_flipped and -1 or 1
|
||||||
--set line number
|
--set line number
|
||||||
if self.name == "advtrains:subway_wagon" and train.line and train.line~=self.line_cache then
|
if self.name == "advtrains:subway_wagon" and train.line and train.line~=self.line_cache then
|
||||||
local new_line_tex="advtrains_subway_wagon.png^advtrains_subway_wagon_line"..gp.line..".png"
|
local new_line_tex="advtrains_subway_wagon.png^advtrains_subway_wagon_line"..train.line..".png"
|
||||||
self.object:set_properties({
|
self.object:set_properties({
|
||||||
textures={new_line_tex},
|
textures={new_line_tex},
|
||||||
})
|
})
|
||||||
self.line_cache=train.line
|
self.line_cache=train.line
|
||||||
elseif self.line_cache~=nil and gp.line==nil then
|
elseif self.line_cache~=nil and train.line==nil then
|
||||||
self.object:set_properties({
|
self.object:set_properties({
|
||||||
textures=self.textures,
|
textures=self.textures,
|
||||||
})
|
})
|
||||||
|
@ -366,8 +364,9 @@ function wagon:on_step(dtime)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
--for path to be available. if not, skip step
|
--for path to be available. if not, skip step
|
||||||
if not train.path then
|
if not train.path or train.no_step then
|
||||||
self.object:setvelocity({x=0, y=0, z=0})
|
self.object:setvelocity({x=0, y=0, z=0})
|
||||||
|
self.object:setacceleration({x=0, y=0, z=0})
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
if not data.pos_in_train then
|
if not data.pos_in_train then
|
||||||
|
@ -376,11 +375,9 @@ function wagon:on_step(dtime)
|
||||||
|
|
||||||
-- Calculate new position, yaw and direction vector
|
-- Calculate new position, yaw and direction vector
|
||||||
local index = advtrains.path_get_index_by_offset(train, train.index, -data.pos_in_train)
|
local index = advtrains.path_get_index_by_offset(train, train.index, -data.pos_in_train)
|
||||||
local pos, tyaw, npos, npos2 = advtrains.path_get_interpolated(train, index)
|
local pos, yaw, npos, npos2 = advtrains.path_get_interpolated(train, index)
|
||||||
local vdir = vector.normalize(vector.subtract(npos2, npos))
|
local vdir = vector.normalize(vector.subtract(npos2, npos))
|
||||||
|
|
||||||
local yaw = tyaw - pihalf
|
|
||||||
|
|
||||||
--automatic get_on
|
--automatic get_on
|
||||||
--needs to know index and path
|
--needs to know index and path
|
||||||
if self.door_entry and train.door_open and train.door_open~=0 and train.velocity==0 then
|
if self.door_entry and train.door_open and train.door_open~=0 and train.velocity==0 then
|
||||||
|
@ -391,7 +388,7 @@ function wagon:on_step(dtime)
|
||||||
local ix1, ix2 = advtrains.path_get_adjacent(train, aci)
|
local ix1, ix2 = advtrains.path_get_adjacent(train, aci)
|
||||||
-- the two wanted positions are ix1 and ix2 + (2nd-1st rotated by 90deg)
|
-- the two wanted positions are ix1 and ix2 + (2nd-1st rotated by 90deg)
|
||||||
-- (x z) rotated by 90deg is (-z x) (http://stackoverflow.com/a/4780141)
|
-- (x z) rotated by 90deg is (-z x) (http://stackoverflow.com/a/4780141)
|
||||||
local add = { x = (ix2.z-ix1.z)*gp.door_open, y = 0, z = (ix1.x-ix2.x)*gp.door_open }
|
local add = { x = (ix2.z-ix1.z)*train.door_open, y = 0, z = (ix1.x-ix2.x)*train.door_open }
|
||||||
local pts1=vector.round(vector.add(ix1, add))
|
local pts1=vector.round(vector.add(ix1, add))
|
||||||
local pts2=vector.round(vector.add(ix2, add))
|
local pts2=vector.round(vector.add(ix2, add))
|
||||||
if minetest.get_item_group(minetest.get_node(pts1).name, "platform")>0 then
|
if minetest.get_item_group(minetest.get_node(pts1).name, "platform")>0 then
|
||||||
|
@ -420,10 +417,9 @@ function wagon:on_step(dtime)
|
||||||
for y=0,exv do
|
for y=0,exv do
|
||||||
for z=-exh,exh do
|
for z=-exh,exh do
|
||||||
local node=minetest.get_node_or_nil(vector.add(npos, {x=x, y=y, z=z}))
|
local node=minetest.get_node_or_nil(vector.add(npos, {x=x, y=y, z=z}))
|
||||||
-- TODO
|
if (advtrains.train_collides(node)) then
|
||||||
--if (advtrains.train_collides(node)) then
|
collides=true
|
||||||
-- collides=true
|
end
|
||||||
--end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -431,13 +427,13 @@ function wagon:on_step(dtime)
|
||||||
if self.collision_count and self.collision_count>10 then
|
if self.collision_count and self.collision_count>10 then
|
||||||
--enable collision mercy to get trains stuck in walls out of walls
|
--enable collision mercy to get trains stuck in walls out of walls
|
||||||
--actually do nothing except limiting the velocity to 1
|
--actually do nothing except limiting the velocity to 1
|
||||||
gp.velocity=math.min(gp.velocity, 1)
|
train.velocity=math.min(train.velocity, 1)
|
||||||
gp.tarvelocity=math.min(gp.tarvelocity, 1)
|
train.tarvelocity=math.min(train.tarvelocity, 1)
|
||||||
else
|
else
|
||||||
gp.recently_collided_with_env=true
|
train.recently_collided_with_env=true
|
||||||
gp.velocity=2*gp.velocity
|
train.velocity=0
|
||||||
gp.movedir=-gp.movedir
|
-- TODO what should happen when a train collides?
|
||||||
gp.tarvelocity=0
|
train.tarvelocity=0
|
||||||
self.collision_count=(self.collision_count or 0)+1
|
self.collision_count=(self.collision_count or 0)+1
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
|
@ -481,7 +477,7 @@ function wagon:on_step(dtime)
|
||||||
self.player_yaw[name] = p:get_look_horizontal()-self.old_yaw
|
self.player_yaw[name] = p:get_look_horizontal()-self.old_yaw
|
||||||
end
|
end
|
||||||
-- set player looking direction using calculated offset
|
-- set player looking direction using calculated offset
|
||||||
--TODO p:set_look_horizontal((self.player_yaw[name] or 0)+yaw)
|
p:set_look_horizontal((self.player_yaw[name] or 0)+yaw)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
self.turning = true
|
self.turning = true
|
||||||
|
@ -493,7 +489,7 @@ function wagon:on_step(dtime)
|
||||||
self.object:setyaw(yaw)
|
self.object:setyaw(yaw)
|
||||||
self.updatepct_timer=2
|
self.updatepct_timer=2
|
||||||
if self.update_animation then
|
if self.update_animation then
|
||||||
self:update_animation(gp.velocity, self.old_velocity)
|
self:update_animation(train.velocity, self.old_velocity)
|
||||||
end
|
end
|
||||||
if self.custom_on_velocity_change then
|
if self.custom_on_velocity_change then
|
||||||
self:custom_on_velocity_change(train.velocity, self.old_velocity or 0, dtime)
|
self:custom_on_velocity_change(train.velocity, self.old_velocity or 0, dtime)
|
||||||
|
@ -664,13 +660,13 @@ function wagon:get_off(seatno)
|
||||||
if self.door_entry and train.door_open and train.door_open~=0 and train.velocity==0 and train.index and train.path then
|
if self.door_entry and train.door_open and train.door_open~=0 and train.velocity==0 and train.index and train.path then
|
||||||
local index = advtrains.path_get_index_by_offset(train, train.index, -data.pos_in_train)
|
local index = advtrains.path_get_index_by_offset(train, train.index, -data.pos_in_train)
|
||||||
for i, ino in ipairs(self.door_entry) do
|
for i, ino in ipairs(self.door_entry) do
|
||||||
--fct is the flipstate flag from door animation above
|
local fct=data.wagon_flipped and -1 or 1
|
||||||
local aci = advtrains.path_get_index_by_offset(train, index, ino*fct)
|
local aci = advtrains.path_get_index_by_offset(train, index, ino*fct)
|
||||||
local ix1, ix2 = advtrains.path_get_adjacent(train, aci)
|
local ix1, ix2 = advtrains.path_get_adjacent(train, aci)
|
||||||
-- the two wanted positions are ix1 and ix2 + (2nd-1st rotated by 90deg)
|
-- the two wanted positions are ix1 and ix2 + (2nd-1st rotated by 90deg)
|
||||||
-- (x z) rotated by 90deg is (-z x) (http://stackoverflow.com/a/4780141)
|
-- (x z) rotated by 90deg is (-z x) (http://stackoverflow.com/a/4780141)
|
||||||
local add = { x = (ix2.z-ix1.z)*gp.door_open, y = 0, z = (ix1.x-ix2.x)*gp.door_open }
|
local add = { x = (ix2.z-ix1.z)*train.door_open, y = 0, z = (ix1.x-ix2.x)*train.door_open }
|
||||||
local oadd = { x = (ix2.z-ix1.z)*gp.door_open*2, y = 1, z = (ix1.x-ix2.x)*gp.door_open*2}
|
local oadd = { x = (ix2.z-ix1.z)*train.door_open*2, y = 1, z = (ix1.x-ix2.x)*train.door_open*2}
|
||||||
local platpos=vector.round(vector.add(ix1, add))
|
local platpos=vector.round(vector.add(ix1, add))
|
||||||
local offpos=vector.round(vector.add(ix1, oadd))
|
local offpos=vector.round(vector.add(ix1, oadd))
|
||||||
atprint("platpos:", platpos, "offpos:", offpos)
|
atprint("platpos:", platpos, "offpos:", offpos)
|
||||||
|
|
Loading…
Reference in New Issue