Mainly make collisions and coupling work

Missing: ATC stuff, yaw problems
master
orwell96 2018-05-17 21:37:01 +02:00
parent 5dca155333
commit 24b0639c5f
8 changed files with 201 additions and 191 deletions

View File

@ -30,7 +30,7 @@ function atc.send_command(pos, par_tid)
local pts=minetest.pos_to_string(pos) local pts=minetest.pos_to_string(pos)
if atc.controllers[pts] then if atc.controllers[pts] then
--atprint("Called send_command at "..pts) --atprint("Called send_command at "..pts)
local train_id = par_tid or advtrains.detector.get(pos) -- TODO: succesively replace those detector calls! local train_id = par_tid or advtrains.get_train_at_pos(pos)
if train_id then if train_id then
if advtrains.trains[train_id] then if advtrains.trains[train_id] then
--atprint("send_command inside if: "..sid(train_id)) --atprint("send_command inside if: "..sid(train_id))
@ -131,7 +131,7 @@ advtrains.atc_function = function(def, preset, suffix, rotation)
local pts=minetest.pos_to_string(pos) local pts=minetest.pos_to_string(pos)
local _, conns=advtrains.get_rail_info_at(pos, advtrains.all_tracktypes) local _, conns=advtrains.get_rail_info_at(pos, advtrains.all_tracktypes)
atc.controllers[pts]={command=fields.command} atc.controllers[pts]={command=fields.command}
if advtrains.detector.get(pos) then if #advtrains.occ.get_trains_at(pos) > 0 then
atc.send_command(pos) atc.send_command(pos)
end end
end end

View File

@ -44,19 +44,19 @@ minetest.register_entity("advtrains:discouple", {
end, end,
on_step=function(self, dtime) on_step=function(self, dtime)
return advtrains.pcall(function() return advtrains.pcall(function()
local t=os.clock()
if not self.wagon then if not self.wagon then
self.object:remove() self.object:remove()
atprint("Discouple: no wagon, destroying")
return return
end end
--getyaw seems to be a reliable method to check if an object is loaded...if it returns nil, it is not. --getyaw seems to be a reliable method to check if an object is loaded...if it returns nil, it is not.
if not self.wagon.object:getyaw() then if not self.wagon.object:getyaw() then
atprint("Discouple: wagon no longer loaded, destroying")
self.object:remove() self.object:remove()
return return
end end
atprintbm("discouple_step", t) if not self.wagon:train() and self.wagon:train().velocity > 0 then
self.object:remove()
return
end
end) end)
end, end,
}) })
@ -102,13 +102,13 @@ minetest.register_entity("advtrains:couple", {
advtrains.train_ensure_init(self.train_id_2, train2) advtrains.train_ensure_init(self.train_id_2, train2)
local id1, id2=self.train_id_1, self.train_id_2 local id1, id2=self.train_id_1, self.train_id_2
local bp1, bp2 = self.t1_is_backpos, self.t2_is_backpos local bp1, bp2 = self.t1_is_front, self.t2_is_front
if not bp1 then if bp1 then
if train1.couple_lock_front then if train1.couple_lock_front then
lockmarker(self.object) lockmarker(self.object)
return return
end end
if not bp2 then if bp2 then
if train2.couple_lock_front then if train2.couple_lock_front then
lockmarker(self.object) lockmarker(self.object)
return return
@ -127,7 +127,7 @@ minetest.register_entity("advtrains:couple", {
lockmarker(self.object) lockmarker(self.object)
return return
end end
if not bp2 then if bp2 then
if train2.couple_lock_front then if train2.couple_lock_front then
lockmarker(self.object) lockmarker(self.object)
return return
@ -174,13 +174,13 @@ minetest.register_entity("advtrains:couple", {
if not self.position_set then if not self.position_set then
local tp1 local tp1
if not self.train1_is_backpos then if self.t1_is_front then
tp1=advtrains.path_get_interpolated(train1, train1.index) tp1=advtrains.path_get_interpolated(train1, train1.index)
else else
tp1=advtrains.path_get_interpolated(train1, train1.end_index) tp1=advtrains.path_get_interpolated(train1, train1.end_index)
end end
local tp2 local tp2
if not self.train2_is_backpos then if self.t2_is_front then
tp2=advtrains.path_get_interpolated(train2, train2.index) tp2=advtrains.path_get_interpolated(train2, train2.index)
else else
tp2=advtrains.path_get_interpolated(train2, train2.end_index) tp2=advtrains.path_get_interpolated(train2, train2.end_index)

View File

@ -56,7 +56,7 @@ Whenever a path gets invalidated or path items are deleted, their index counterp
When a train needs to know whether a position is blocked by another train, it will (and is permitted to) When a train needs to know whether a position is blocked by another train, it will (and is permitted to)
query the train.index and train.end_index and compare them to the blocked position's index. query the train.index and train.end_index and compare them to the blocked position's index.
Callback system for 3rd-party path checkers: TODO Callback system for 3rd-party path checkers:
advtrains.te_register_on_new_path(func(id, train)) advtrains.te_register_on_new_path(func(id, train))
-- Called when a train's path is re-initalized, either when it was invalidated -- Called when a train's path is re-initalized, either when it was invalidated
-- or the saves were just loaded -- or the saves were just loaded
@ -72,6 +72,12 @@ advtrains.te_register_on_update(func(id, train))
-- It is ensured that on_new_path callbacks are executed prior to these callbacks whenever -- It is ensured that on_new_path callbacks are executed prior to these callbacks whenever
-- an invalidation or a reload occured. -- an invalidation or a reload occured.
advtrains.te_register_on_create(func(id, train))
-- Called right after a train is created, right after the initial new_path callback
advtrains.te_register_on_remove(func(id, train))
-- Called right before a train is deleted
All callbacks are allowed to save certain values inside the train table, but they must ensure that 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 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. set ALL OF those values to nil or to a new updated value, and must not rely on their existence.
@ -162,11 +168,13 @@ function o.check_collision(pos, train_id)
if not t then return end if not t then return end
local i = 1 local i = 1
while t[i] do while t[i] do
if t[i]~=train_id then local ti = t[i]
if ti~=train_id then
local idx = t[i+1] local idx = t[i+1]
local train = advtrains.trains[train_id] local train = advtrains.trains[ti]
advtrains.train_ensure_init(train_id, train) atdebug("checking train",t[i],"index",idx,"<>",train.index,train.end_index)
if idx >= train.end_index and idx <= train.index then if idx >= train.end_index and idx <= train.index then
atdebug("collides.")
return true return true
end end
end end
@ -183,19 +191,39 @@ function o.get_occupations(train, index)
local ppos, ontrack = advtrains.path_get(train, index) local ppos, ontrack = advtrains.path_get(train, index)
if not ontrack then if not ontrack then
atdebug("Train",train.id,"get_occupations requested off-track",index) atdebug("Train",train.id,"get_occupations requested off-track",index)
return {}, pos return {}, ppos
end end
local pos = advtrains.round_vector_floor_y(ppos) local pos = advtrains.round_vector_floor_y(ppos)
local t = occget(pos) local t = occget(pos)
if not t then return {} end
local r = {} local r = {}
local i = 1 local i = 1
local train_id = train.id local train_id = train.id
while t[i] do while t[i] do
if t[i]~=train_id then if t[i]~=train_id then
r[train_id] = t[i+1] r[t[i]] = t[i+1]
end end
i = i + 2 i = i + 2
end end
return r, pos return r, pos
end end
-- Gets a mapping of train id's to indexes of trains that stand or drive over
-- returns (table with train_id->index), position
function o.get_trains_at(ppos)
local pos = advtrains.round_vector_floor_y(ppos)
local t = occget(pos)
if not t then return {} end
local r = {}
local i = 1
while t[i] do
local train = advtrains.trains[t[i]]
local idx = t[i+1]
if train.end_index - 0.5 <= idx and idx <= train.index + 0.5 then
r[t[i]] = idx
end
i = i + 2
end
return r
end
advtrains.occ = o advtrains.occ = o

View File

@ -137,7 +137,7 @@ function advtrains.path_setrestore(train, invert)
idx = train.end_index idx = train.end_index
end end
local pos, connid, frac = advtrains.path_getrestore(train, idx, invert) local pos, connid, frac = advtrains.path_getrestore(train, idx, invert, true)
train.last_pos = pos train.last_pos = pos
train.last_connid = connid train.last_connid = connid
@ -145,23 +145,25 @@ function advtrains.path_setrestore(train, invert)
end end
-- Get restore position, connid and frac (in this order) for a train that will originate at the passed index -- 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. -- 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) function advtrains.path_getrestore(train, index, invert, tmp)
local idx = train.index local idx = index
local cns = train.path_cn local cns = train.path_cn
if invert then if invert then
idx = train.end_index
cns = train.path_cp cns = train.path_cp
end end
fli = atfloor(train.index) fli = atfloor(index)
advtrains.path_get(train, fli)
if fli > train.path_trk_f then if fli > train.path_trk_f then
fli = train.path_trk_f fli = train.path_trk_f
end end
if fli < train.path_trk_b then if fli < train.path_trk_b then
fli = train.path_trk_b fli = train.path_trk_b
end end
if not tmp then
atdebug ("getrestore ",atround(train.index),"calc",atround(index),fli)
end
return advtrains.path_get(train, fli), return advtrains.path_get(train, fli),
cns[fli], cns[fli],
(idx - fli) * (invert and -1 or 1) (idx - fli) * (invert and -1 or 1)
@ -359,7 +361,7 @@ function advtrains.path_clear_unused(train)
train.path_cp[i] = nil train.path_cp[i] = nil
train.path_cn[i] = nil train.path_cn[i] = nil
train.path_dir[i+1] = nil train.path_dir[i+1] = nil
train.path_ext_b = i - 1 train.path_ext_f = i - 1
end end
train.path_req_f = math.ceil(train.index) train.path_req_f = math.ceil(train.index)

View File

@ -389,100 +389,6 @@ function advtrains.get_track_connections(name, param2)
return advtrains.rotate_conn_by(nodedef.at_conns, noderot*AT_CMAX/4), (nodedef.at_rail_y or 0), tracktype return advtrains.rotate_conn_by(nodedef.at_conns, noderot*AT_CMAX/4), (nodedef.at_rail_y or 0), tracktype
end end
--detector code
--holds a table with nodes on which trains are on.
advtrains.detector = {}
advtrains.detector.on_node = {}
--Returns true when position is occupied by a train other than train_id, false when occupied by the same train as train_id and nil in case there's no train at all
function advtrains.detector.occupied(pos, train_id)
local ppos=advtrains.round_vector_floor_y(pos)
local pts=minetest.pos_to_string(ppos)
local s=advtrains.detector.on_node[pts]
if not s then return nil end
if s==train_id then return false end
--in case s is a table, it's always occupied by another train
return true
end
-- If given a train id as second argument, this is considered as 'not there'.
-- Returns the train id of (one of, nondeterministic) the trains at this position
function advtrains.detector.get(pos, train_id)
local ppos=advtrains.round_vector_floor_y(pos)
local pts=minetest.pos_to_string(ppos)
local s=advtrains.detector.on_node[pts]
if not s then return nil end
if type(s)=="table" then
for _,t in ipairs(s) do
if t~=train_id then return t end
end
return nil
end
return s
end
function advtrains.detector.enter_node(pos, train_id)
advtrains.detector.stay_node(pos, train_id)
local ppos=advtrains.round_vector_floor_y(pos)
advtrains.detector.call_enter_callback(ppos, train_id)
end
function advtrains.detector.leave_node(pos, train_id)
local ppos=advtrains.round_vector_floor_y(pos)
local pts=minetest.pos_to_string(ppos)
local s=advtrains.detector.on_node[pts]
if type(s)=="table" then
local i
for j,t in ipairs(s) do
if t==train_id then i=j end
end
if not i then return end
s=table.remove(s,i)
if #s==0 then
s=nil
elseif #s==1 then
s=s[1]
end
advtrains.detector.on_node[pts]=s
else
advtrains.detector.on_node[pts]=nil
end
advtrains.detector.call_leave_callback(ppos, train_id)
end
function advtrains.detector.stay_node(pos, train_id)
local ppos=advtrains.round_vector_floor_y(pos)
local pts=minetest.pos_to_string(ppos)
local s=advtrains.detector.on_node[pts]
if not s then
advtrains.detector.on_node[pts]=train_id
elseif type(s)=="string" then
advtrains.detector.on_node[pts]={s, train_id}
elseif type(s)=="table" then
advtrains.detector.on_node[pts]=table.insert(s, train_id)
end
end
function advtrains.detector.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 advtrains.detector.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
-- slope placer. Defined in register_tracks. -- slope placer. Defined in register_tracks.
--crafted with rail and gravel --crafted with rail and gravel
local sl={} local sl={}

View File

@ -176,29 +176,24 @@ end
-- Occupation Callback system -- Occupation Callback system
-- see occupation.lua -- see occupation.lua
local callbacks_new_path = {} local function mkcallback(name)
local callbacks_update = {} local callt = {}
advtrains["te_register_on_"..name] = function(func)
function advtrains.te_register_on_new_path(func) assertt(func, "function")
assertt(func, "function") table.insert(callt, func)
table.insert(callbacks_new_path, func) end
end return callt, function(id, train)
function advtrains.te_register_on_update(func) for _,f in ipairs(callt) do
assertt(func, "function") f(id, train)
table.insert(callbacks_update, func) end
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 end
local callbacks_new_path, run_callbacks_new_path = mkcallback("new_path")
local callbacks_update, run_callbacks_update = mkcallback("update")
local callbacks_create, run_callbacks_create = mkcallback("create")
local callbacks_remove, run_callbacks_remove = mkcallback("remove")
-- train_ensure_init: responsible for creating a state that we can work on, after one of the following events has happened: -- train_ensure_init: 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
@ -385,7 +380,7 @@ 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() recalc_end_index(train)
end end
@ -420,22 +415,21 @@ if train.no_step or train.wait_for_path then return end
if train_moves then if train_moves then
local collpos local collided = false
local coll_grace=1 local coll_grace=1
local collindex = advtrains.path_get_index_by_offset(train, train.index, coll_grace) local collindex = advtrains.path_get_index_by_offset(train, train.index, -coll_grace)
collpos = advtrains.path_get(train, atround(collindex)) local collpos = advtrains.path_get(train, atround(collindex))
if collpos then if collpos then
local rcollpos=advtrains.round_vector_floor_y(collpos) local rcollpos=advtrains.round_vector_floor_y(collpos)
for x=-train.extent_h,train.extent_h do for x=-train.extent_h,train.extent_h do
for z=-train.extent_h,train.extent_h do for z=-train.extent_h,train.extent_h do
local testpos=vector.add(rcollpos, {x=x, y=0, z=z}) local testpos=vector.add(rcollpos, {x=x, y=0, z=z})
--- 8a Check collision --- --- 8a Check collision ---
if advtrains.occ.check_collision(testpos, id) then if not collided and advtrains.occ.check_collision(testpos, id) then
--collides --collides
--advtrains.collide_and_spawn_couple(id, testpos, advtrains.detector.get(testpos, id), train.movedir==-1)
train.velocity = 0 train.velocity = 0
train.tarvelocity = 0 train.tarvelocity = 0
atwarn("Train",id,"collided!") collided = true
end end
--- 8b damage players --- --- 8b damage players ---
if not minetest.settings:get_bool("creative_mode") then if not minetest.settings:get_bool("creative_mode") then
@ -499,7 +493,9 @@ advtrains.te_register_on_new_path(function(id, train)
old_index = atround(train.index), old_index = atround(train.index),
old_end_index = atround(train.end_index), old_end_index = atround(train.end_index),
} }
atdebug(id,"tnc init",train.index,train.end_index)
end) end)
advtrains.te_register_on_update(function(id, train) advtrains.te_register_on_update(function(id, train)
local new_index = atround(train.index) local new_index = atround(train.index)
local new_end_index = atround(train.end_index) local new_end_index = atround(train.end_index)
@ -507,14 +503,38 @@ advtrains.te_register_on_update(function(id, train)
local old_end_index = train.tnc.old_end_index local old_end_index = train.tnc.old_end_index
while old_index < new_index do while old_index < new_index do
old_index = old_index + 1 old_index = old_index + 1
local pos = advtrains.round_vector_floor_y(advtrains.path_get(old_index)) local pos = advtrains.round_vector_floor_y(advtrains.path_get(train,old_index))
tnc_call_enter_callback(pos, id) tnc_call_enter_callback(pos, id)
end end
while old_end_index > new_end_index do while old_end_index < new_end_index do
local pos = advtrains.round_vector_floor_y(advtrains.path_get(old_end_index)) local pos = advtrains.round_vector_floor_y(advtrains.path_get(train,old_end_index))
tnc_call_leave_callback(pos, id) tnc_call_leave_callback(pos, id)
old_end_index = old_end_index - 1 old_end_index = old_end_index + 1
end end
train.tnc.old_index = new_index
train.tnc.old_end_index = new_end_index
end)
advtrains.te_register_on_create(function(id, train)
local index = atround(train.index)
local end_index = atround(train.end_index)
while end_index <= index do
local pos = advtrains.round_vector_floor_y(advtrains.path_get(train,end_index))
tnc_call_enter_callback(pos, id)
end_index = end_index + 1
end
atdebug(id,"tnc create",train.index,train.end_index)
end)
advtrains.te_register_on_remove(function(id, train)
local index = atround(train.index)
local end_index = atround(train.end_index)
while end_index <= index do
local pos = advtrains.round_vector_floor_y(advtrains.path_get(train,end_index))
tnc_call_leave_callback(pos, id)
end_index = end_index + 1
end
atdebug(id,"tnc remove",train.index,train.end_index)
end) 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.
@ -572,9 +592,10 @@ 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.train_ensure_init(new_id, advtrains.trains[new_id]) advtrains.train_ensure_init(new_id, advtrains.trains[new_id])
run_callbacks_create(new_id, advtrains.trains[new_id])
return new_id return new_id
end end
@ -583,9 +604,13 @@ function advtrains.remove_train(id)
advtrains.train_ensure_init(id, train) advtrains.train_ensure_init(id, train)
run_callbacks_remove(id, train)
advtrains.path_invalidate(train) advtrains.path_invalidate(train)
advtrains.couple_invalidate(train)
local tp = train.trainparts local tp = train.trainparts
atdebug("Removing train",id,"leftover trainparts:",tp)
advtrains.trains[id] = nil advtrains.trains[id] = nil
@ -661,6 +686,8 @@ function advtrains.update_trainpart_properties(train_id, invert_flipstate)
train.locomotives_in_train = count_l train.locomotives_in_train = count_l
end end
local ablkrng = minetest.settings:get("active_block_range")*16
-- This function checks whether entities need to be spawned for certain wagons, and spawns them. -- This function checks whether entities need to be spawned for certain wagons, and spawns them.
function advtrains.spawn_wagons(train_id) function advtrains.spawn_wagons(train_id)
local train = advtrains.trains[train_id] local train = advtrains.trains[train_id]
@ -668,12 +695,23 @@ function advtrains.spawn_wagons(train_id)
for i, w_id in ipairs(train.trainparts) do for i, w_id in ipairs(train.trainparts) do
local data = advtrains.wagons[w_id] local data = advtrains.wagons[w_id]
if data then if data then
if data.train_id ~= train_id then
atwarn("Train",train_id,"Wagon #",1,": Saved train ID",data.train_id,"did not match!")
data.train_id = train_id
end
if not data.object or not data.object:getyaw() then if not data.object or not data.object:getyaw() then
-- eventually need to spawn new object. check if position is loaded. -- eventually need to spawn new object. check if position is loaded.
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 = advtrains.path_get(train, atfloor(index)) local pos = advtrains.path_get(train, atfloor(index))
if minetest.get_node_or_nil(pos) then local spawn = false
for _,p in pairs(minetest.get_connected_players()) do
if vector.distance(p:get_pos(),pos)<=ablkrng then
spawn = true
end
end
if spawn then
local wt = advtrains.get_wagon_prototype(data) local wt = advtrains.get_wagon_prototype(data)
local wagon = minetest.add_entity(pos, wt):get_luaentity() local wagon = minetest.add_entity(pos, wt):get_luaentity()
wagon:set_id(w_id) wagon:set_id(w_id)
@ -693,16 +731,15 @@ function advtrains.split_train_at_wagon(wagon_id)
advtrains.train_ensure_init(old_id, train) advtrains.train_ensure_init(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)
-- find new initial path position for this train -- find new initial path position for this train
local pos, connid, frac = advtrains.path_getrestore(train, index) local pos, connid, frac = advtrains.path_getrestore(train, index)
-- build trainparts table, passing it directly to the train constructor -- build trainparts table, passing it directly to the train constructor
local tp = {} local tp = {}
for k,v in ipairs(train.trainparts) do for k,v in ipairs(train.trainparts) do
if k>=wagon.pos_in_trainparts then if k >= data.pos_in_trainparts then
table.insert(tp, v) table.insert(tp, v)
train.trainparts[k]=nil train.trainparts[k]=nil
end end
@ -728,7 +765,7 @@ function advtrains.split_train_at_wagon(wagon_id)
end end
-- coupling -- coupling
local CPL_CHK_DST = 1 local CPL_CHK_DST = -1
local CPL_ZONE = 2 local CPL_ZONE = 2
-- train.couple_* contain references to ObjectRefs of couple objects, which contain all relevant information -- train.couple_* contain references to ObjectRefs of couple objects, which contain all relevant information
@ -739,11 +776,24 @@ local function createcouple(pos, train1, t1_is_front, train2, t2_is_front)
local le=obj:get_luaentity() local le=obj:get_luaentity()
le.train_id_1=train1.id le.train_id_1=train1.id
le.train_id_2=train2.id le.train_id_2=train2.id
le.train1_is_backpos=not t1_is_front le.t1_is_front=t1_is_front
le.train2_is_backpos=not t2_is_front le.t2_is_front=t2_is_front
atdebug("created couple between",train1.id,t1_is_front,train2.id,t2_is_front)
if t1_is_front then
train1.cpl_front = obj
else
train1.cpl_back = obj
end
if t2_is_front then
train2.cpl_front = obj
else
train2.cpl_back = obj
end
end end
function advtrains.train_check_couples(train) function advtrains.train_check_couples(train)
atdebug("rechecking couples")
if train.cpl_front then if train.cpl_front then
if not train.cpl_front:getyaw() then if not train.cpl_front:getyaw() then
-- objectref is no longer valid. reset. -- objectref is no longer valid. reset.
@ -756,6 +806,7 @@ function advtrains.train_check_couples(train)
for tid, idx in pairs(front_trains) do for tid, idx in pairs(front_trains) do
local other_train = advtrains.trains[tid] local other_train = advtrains.trains[tid]
advtrains.train_ensure_init(tid, other_train) advtrains.train_ensure_init(tid, other_train)
atdebug(train.id,"front: ",idx,"on",tid,atround(other_train.index),atround(other_train.end_index))
if other_train.velocity == 0 then if other_train.velocity == 0 then
if idx>=other_train.index and idx<=other_train.index + CPL_ZONE then if idx>=other_train.index and idx<=other_train.index + CPL_ZONE then
createcouple(pos, train, true, other_train, true) createcouple(pos, train, true, other_train, true)
@ -794,7 +845,17 @@ function advtrains.train_check_couples(train)
end end
end end
function advtrains.couple_invalidate(train)
if train.cpl_back then
train.cpl_back:remove()
train.cpl_back = nil
end
if train.cpl_front then
train.cpl_front:remove()
train.cpl_front = nil
end
train.was_standing = nil
end
-- relevant code for this comment is in couple.lua -- relevant code for this comment is in couple.lua
@ -833,6 +894,9 @@ function advtrains.do_connect_trains(first_id, second_id)
first.velocity=0 first.velocity=0
first.tarvelocity=0 first.tarvelocity=0
first.couple_lck_back=tmp_cpl_lck first.couple_lck_back=tmp_cpl_lck
advtrains.update_trainpart_properties(first_id)
advtrains.couple_invalidate(first)
return true return true
end end
@ -845,8 +909,12 @@ function advtrains.invert_train(train_id)
-- 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
if train.door_open then
train.door_open = - train.door_open
end
advtrains.path_invalidate(train) advtrains.path_invalidate(train)
advtrains.couple_invalidate(train)
local old_trainparts=train.trainparts local old_trainparts=train.trainparts
train.trainparts={} train.trainparts={}
@ -857,7 +925,7 @@ function advtrains.invert_train(train_id)
end end
function advtrains.get_train_at_pos(pos) function advtrains.get_train_at_pos(pos)
return advtrains.detector.get(pos) return advtrains.occ.get_trains_at(pos)[1]
end end
function advtrains.invalidate_all_paths(pos) function advtrains.invalidate_all_paths(pos)
@ -883,6 +951,7 @@ function advtrains.invalidate_path(id)
local v=advtrains.trains[id] local v=advtrains.trains[id]
if not v then return end if not v then return end
advtrains.path_invalidate(v) advtrains.path_invalidate(v)
advtrains.couple_invalidate(v)
v.dirty = true v.dirty = true
end end

View File

@ -10,6 +10,7 @@
advtrains.wagons = {} advtrains.wagons = {}
advtrains.wagon_prototypes = {} advtrains.wagon_prototypes = {}
-- TODO: That yaw thing is still not fixed. seems like minetest itself obeys the counterclockwise system...
-- --
function advtrains.create_wagon(wtype, owner) function advtrains.create_wagon(wtype, owner)
@ -107,14 +108,18 @@ function wagon:ensure_init()
-- Train not being set just means that this will happen as soon as the train calls update_trainpart_properties. -- Train not being set just means that this will happen as soon as the train calls update_trainpart_properties.
if self.initialized and self.id then if self.initialized and self.id then
local data = advtrains.wagons[self.id] local data = advtrains.wagons[self.id]
if data.train_id then if data and data.train_id and self:train() then
if self.noninitticks then self.noninitticks=nil end if self.noninitticks then self.noninitticks=nil end
return true return true
end end
end end
if not self.noninitticks then self.noninitticks=0 end if not self.noninitticks then
atwarn("wagon",self.id,"uninitialized init=",self.initialized)
self.noninitticks=0
end
self.noninitticks=self.noninitticks+1 self.noninitticks=self.noninitticks+1
if self.noninitticks>20 then if self.noninitticks>20 then
atwarn("wagon",self.id,"uninitialized, removing")
self:destroy() self:destroy()
else else
self.object:setvelocity({x=0,y=0,z=0}) self.object:setvelocity({x=0,y=0,z=0})
@ -174,6 +179,10 @@ function wagon:destroy()
-- not when a driver is inside -- not when a driver is inside
if self.id then if self.id then
local data = advtrains.wagons[self.id] local data = advtrains.wagons[self.id]
if not data then
atwarn("wagon:destroy(): data is not set!")
return
end
if self.custom_on_destroy then if self.custom_on_destroy then
self.custom_on_destroy(self) self.custom_on_destroy(self)
@ -184,14 +193,12 @@ function wagon:destroy()
end end
if data.train_id and self:train() then if data.train_id and self:train() then
table.remove(self:train().trainparts, data.pos_in_trainparts) advtrains.remove_train(data.train_id)
advtrains.update_trainpart_properties(data.train_id)
advtrains.wagons[self.id]=nil advtrains.wagons[self.id]=nil
if self.discouple then self.discouple.object:remove() end--will have no effect on unloaded objects if self.discouple then self.discouple.object:remove() end--will have no effect on unloaded objects
return true
end end
end end
atprint("[wagon ", self.id, "]: destroying") atdebug("[wagon ", self.id, "]: destroying")
self.object:remove() self.object:remove()
end end
@ -247,7 +254,7 @@ function wagon:on_step(dtime)
advtrains.on_control_change(pc, self:train(), data.wagon_flipped) advtrains.on_control_change(pc, self:train(), data.wagon_flipped)
--bordcom --bordcom
if pc.sneak and pc.jump then if pc.sneak and pc.jump then
self:show_bordcom(self.seatp[seatno]) self:show_bordcom(data.seatp[seatno])
end end
--sound horn when required --sound horn when required
if self.horn_sound and pc.aux1 and not pc.sneak and not self.horn_handle then if self.horn_sound and pc.aux1 and not pc.sneak and not self.horn_handle then
@ -458,6 +465,7 @@ function wagon:on_step(dtime)
or not vector.equals(accelerationvec, self.old_acceleration_vector) or not vector.equals(accelerationvec, self.old_acceleration_vector)
or self.old_yaw~=yaw or self.old_yaw~=yaw
or self.updatepct_timer<=0 then--only send update packet if something changed or self.updatepct_timer<=0 then--only send update packet if something changed
self.object:setpos(pos) self.object:setpos(pos)
self.object:setvelocity(velocityvec) self.object:setvelocity(velocityvec)
self.object:setacceleration(accelerationvec) self.object:setacceleration(accelerationvec)
@ -494,6 +502,10 @@ function wagon:on_step(dtime)
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)
end end
-- remove discouple object, because it will be in a wrong location
if self.discouple then
self.discouple.object:remove()
end
end end
@ -529,7 +541,7 @@ function wagon:on_rightclick(clicker)
poss[#poss+1]={name=attrans("Show Inventory"), key="inv"} poss[#poss+1]={name=attrans("Show Inventory"), key="inv"}
end end
if self.seat_groups[sgr].driving_ctrl_access and advtrains.check_driving_couple_protection(pname, data.owner, data.whitelist) then if self.seat_groups[sgr].driving_ctrl_access and advtrains.check_driving_couple_protection(pname, data.owner, data.whitelist) then
poss[#poss+1]={name=attrans("Bord Computer"), key="bordcom"} poss[#poss+1]={name=attrans("Board Computer"), key="bordcom"}
end end
if data.owner==pname then if data.owner==pname then
poss[#poss+1]={name=attrans("Wagon properties"), key="prop"} poss[#poss+1]={name=attrans("Wagon properties"), key="prop"}
@ -706,7 +718,7 @@ function wagon:show_get_on_form(pname)
local addtext, colorcode="", "" local addtext, colorcode="", ""
if data.seatp and data.seatp[seatno] then if data.seatp and data.seatp[seatno] then
colorcode="#FF0000" colorcode="#FF0000"
addtext=" ("..self.seatp[seatno]..")" addtext=" ("..data.seatp[seatno]..")"
end end
form=form..comma..colorcode..seattbl.name..addtext form=form..comma..colorcode..seattbl.name..addtext
comma="," comma=","
@ -732,16 +744,12 @@ function wagon:show_wagon_properties(pname)
end end
--BordCom --BordCom
local function checkcouple(eid) local function checkcouple(ent)
if not eid then return nil end
local ent=minetest.object_refs[eid]
if not ent or not ent:getyaw() then if not ent or not ent:getyaw() then
eid=nil
return nil return nil
end end
local le = ent:get_luaentity() local le = ent:get_luaentity()
if not le or not le.is_couple then if not le or not le.is_couple then
eid=nil
return nil return nil
end end
return le return le
@ -793,8 +801,8 @@ function wagon:show_bordcom(pname)
form = form .. "label[0.5,"..(linhei)..";<--]" form = form .. "label[0.5,"..(linhei)..";<--]"
end end
--check cpl_eid_front and _back of train --check cpl_eid_front and _back of train
local couple_front = checkcouple(train.couple_eid_front) local couple_front = checkcouple(train.cpl_front)
local couple_back = checkcouple(train.couple_eid_back) local couple_back = checkcouple(train.cpl_back)
if couple_front then if couple_front then
form = form .. "image_button[0.5,"..(linhei+1)..";1,1;advtrains_couple.png;cpl_f;]" form = form .. "image_button[0.5,"..(linhei+1)..";1,1;advtrains_couple.png;cpl_f;]"
end end
@ -872,8 +880,8 @@ function wagon:handle_bordcom_fields(pname, formname, fields)
end end
end end
--check cpl_eid_front and _back of train --check cpl_eid_front and _back of train
local couple_front = checkcouple(train.couple_eid_front) local couple_front = checkcouple(train.cpl_front)
local couple_back = checkcouple(train.couple_eid_back) local couple_back = checkcouple(train.cpl_back)
if fields.cpl_f and couple_front then if fields.cpl_f and couple_front then
couple_front:on_rightclick(pname) couple_front:on_rightclick(pname)

View File

@ -24,7 +24,7 @@ function r.fire_event(pos, evtdata)
--prepare ingame API for ATC. Regenerate each time since pos needs to be known --prepare ingame API for ATC. Regenerate each time since pos needs to be known
--If no train, then return false. --If no train, then return false.
local train_id=advtrains.detector.get(pos) local train_id=advtrains.get_train_at_pos(pos)
local train, atc_arrow, tvel local train, atc_arrow, tvel
if train_id then train=advtrains.trains[train_id] end if train_id then train=advtrains.trains[train_id] end
if train then if train then
@ -34,19 +34,16 @@ function r.fire_event(pos, evtdata)
atlatc.interrupt.add(0,pos,evtdata) atlatc.interrupt.add(0,pos,evtdata)
return return
end end
for index, ppos in pairs(train.path) do local index = advtrains.path_lookup(train, pos)
if vector.equals(advtrains.round_vector_floor_y(ppos), pos) then
atc_arrow = local iconnid = 1
vector.equals( if index then
advtrains.dirCoordSet(pos, arrowconn), iconnid = train.path_cn[index]
advtrains.round_vector_floor_y(train.path[index+train.movedir]) else
) atwarn("ATC rail at", pos, ": Rail not on train's path! Can't determine arrow direction. Assuming +!")
end
end
if atc_arrow==nil then
atwarn("LuaAutomation ATC rail at", pos, ": Rail not on train's path! Can't determine arrow direction. Assuming +!")
atc_arrow=true
end end
atc_arrow = iconnid == 1
tvel=train.velocity tvel=train.velocity
end end
local customfct={ local customfct={