Implement multi-occupation in detector.on_node table to finally fix collisions
This commit is contained in:
parent
1f9a9062e0
commit
f1a8b4f505
|
@ -430,20 +430,71 @@ end
|
||||||
advtrains.detector = {}
|
advtrains.detector = {}
|
||||||
advtrains.detector.on_node = {}
|
advtrains.detector.on_node = {}
|
||||||
|
|
||||||
function advtrains.detector.enter_node(pos, train_id)
|
--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 ppos=advtrains.round_vector_floor_y(pos)
|
||||||
local pts=minetest.pos_to_string(ppos)
|
local pts=minetest.pos_to_string(ppos)
|
||||||
advtrains.detector.on_node[pts]=train_id
|
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)
|
advtrains.detector.call_enter_callback(ppos, train_id)
|
||||||
end
|
end
|
||||||
function advtrains.detector.leave_node(pos, train_id)
|
function advtrains.detector.leave_node(pos, train_id)
|
||||||
local ppos=advtrains.round_vector_floor_y(pos)
|
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)
|
advtrains.detector.call_leave_callback(ppos, train_id)
|
||||||
end
|
end
|
||||||
function advtrains.detector.stay_node(pos, train_id)
|
function advtrains.detector.stay_node(pos, train_id)
|
||||||
local ppos=advtrains.round_vector_floor_y(pos)
|
local ppos=advtrains.round_vector_floor_y(pos)
|
||||||
local pts=minetest.pos_to_string(ppos)
|
local pts=minetest.pos_to_string(ppos)
|
||||||
advtrains.detector.on_node[pts]=train_id
|
|
||||||
|
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
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -394,15 +394,12 @@ function advtrains.train_step_a(id, train, dtime)
|
||||||
|
|
||||||
--- 6b. call stay_node to register trains in the location table - actual enter_node stuff is done in step b ---
|
--- 6b. call stay_node to register trains in the location table - actual enter_node stuff is done in step b ---
|
||||||
|
|
||||||
local ifn, ibn = atround(train.index), atround(train.end_index)
|
local ifo, ibo = train.detector_old_index, train.detector_old_end_index
|
||||||
local path=train.path
|
local path=train.path
|
||||||
|
|
||||||
for i=ibn, ifn do
|
for i=ibo, ifo do
|
||||||
if path[i] then
|
if path[i] then
|
||||||
local pts=minetest.pos_to_string(path[i])
|
advtrains.detector.stay_node(path[i], id)
|
||||||
if not (advtrains.detector.on_node[pts] and advtrains.detector.on_node[pts]~=id) then
|
|
||||||
advtrains.detector.stay_node(path[i], id)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -519,13 +516,12 @@ function advtrains.train_step_b(id, train, dtime)
|
||||||
if ifn>ifo then
|
if ifn>ifo then
|
||||||
for i=ifo+1, ifn do
|
for i=ifo+1, ifn do
|
||||||
if path[i] then
|
if path[i] then
|
||||||
local pts=minetest.pos_to_string(path[i])
|
if advtrains.detector.occupied(path[i], id) then
|
||||||
if advtrains.detector.on_node[pts] and advtrains.detector.on_node[pts]~=id then
|
|
||||||
--if another train has signed up for this position first, it won't be recognized in train_step_b. So do collision here.
|
--if another train has signed up for this position first, it won't be recognized in train_step_b. So do collision here.
|
||||||
atprint("Collision detected in enter_node callbacks (front) @",pts,"with",sid(advtrains.detector.on_node[pts]))
|
atprint("Collision detected in enter_node callbacks (front) @",path[i],"with",sid(advtrains.detector.get(path[i], id)))
|
||||||
advtrains.collide_and_spawn_couple(id, path[i], advtrains.detector.on_node[pts], false)
|
advtrains.collide_and_spawn_couple(id, path[i], advtrains.detector.get(path[i], id), false)
|
||||||
end
|
end
|
||||||
atprint("enter_node (front) @index",i,"@",pts,"on_node",sid(advtrains.detector.on_node[pts]))
|
atprint("enter_node (front) @index",i,"@",path[i],"on_node",sid(advtrains.detector.get(path[i], id)))
|
||||||
advtrains.detector.enter_node(path[i], id)
|
advtrains.detector.enter_node(path[i], id)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -540,12 +536,12 @@ function advtrains.train_step_b(id, train, dtime)
|
||||||
for i=ibn, ibo-1 do
|
for i=ibn, ibo-1 do
|
||||||
if path[i] then
|
if path[i] then
|
||||||
local pts=minetest.pos_to_string(path[i])
|
local pts=minetest.pos_to_string(path[i])
|
||||||
if advtrains.detector.on_node[pts] and advtrains.detector.on_node[pts]~=id then
|
if advtrains.detector.occupied(path[i], id) then
|
||||||
--if another train has signed up for this position first, it won't be recognized in train_step_b. So do collision here.
|
--if another train has signed up for this position first, it won't be recognized in train_step_b. So do collision here.
|
||||||
atprint("Collision detected in enter_node callbacks (back) @",pts,"on_node",sid(advtrains.detector.on_node[pts]))
|
atprint("Collision detected in enter_node callbacks (back) @",path[i],"with",sid(advtrains.detector.get(path[i], id)))
|
||||||
advtrains.collide_and_spawn_couple(id, path[i], advtrains.detector.on_node[pts], true)
|
advtrains.collide_and_spawn_couple(id, path[i], advtrains.detector.get(path[i], id), true)
|
||||||
end
|
end
|
||||||
atprint("enter_node (back) @index",i,"@",pts,"with",sid(advtrains.detector.on_node[pts]))
|
atprint("enter_node (back) @index",i,"@",path[i],"on_node",sid(advtrains.detector.get(path[i], id)))
|
||||||
advtrains.detector.enter_node(path[i], id)
|
advtrains.detector.enter_node(path[i], id)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -576,15 +572,14 @@ function advtrains.train_step_b(id, train, dtime)
|
||||||
for z=-1,1 do
|
for z=-1,1 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 ---
|
||||||
local testpts=minetest.pos_to_string(testpos)
|
if advtrains.detector.occupied(testpos, id) then
|
||||||
if advtrains.detector.on_node[testpts] and advtrains.detector.on_node[testpts]~=id then
|
|
||||||
--collides
|
--collides
|
||||||
advtrains.collide_and_spawn_couple(id, testpos, advtrains.detector.on_node[testpts], train.movedir==-1)
|
advtrains.collide_and_spawn_couple(id, testpos, advtrains.detector.get(testpos, id), train.movedir==-1)
|
||||||
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
|
||||||
local player=advtrains.playersbypts[testpts]
|
local player=advtrains.playersbypts[testpts]
|
||||||
if player and train.velocity>3 then
|
if player and not minetest.check_player_privs(player, "creative") and train.velocity>3 then
|
||||||
--instantly kill player
|
--instantly kill player
|
||||||
--drop inventory contents first, to not to spawn bones
|
--drop inventory contents first, to not to spawn bones
|
||||||
local player_inv=player:get_inventory()
|
local player_inv=player:get_inventory()
|
||||||
|
@ -716,8 +711,8 @@ function advtrains.split_train_at_wagon(wagon)
|
||||||
if not train.path then return end
|
if not train.path then return end
|
||||||
|
|
||||||
local real_pos_in_train=advtrains.get_real_path_index(train, wagon.pos_in_train)
|
local real_pos_in_train=advtrains.get_real_path_index(train, wagon.pos_in_train)
|
||||||
local pos_for_new_train=train.path[math.floor(real_pos_in_train+wagon.wagon_span+1)]
|
local pos_for_new_train=train.path[math.floor(real_pos_in_train+wagon.wagon_span)]
|
||||||
local pos_for_new_train_prev=train.path[math.floor(real_pos_in_train+wagon.wagon_span)]
|
local pos_for_new_train_prev=train.path[math.floor(real_pos_in_train+wagon.wagon_span-1)]
|
||||||
|
|
||||||
--before doing anything, check if both are rails. else do not allow
|
--before doing anything, check if both are rails. else do not allow
|
||||||
if not pos_for_new_train then
|
if not pos_for_new_train then
|
||||||
|
@ -930,8 +925,7 @@ function advtrains.invert_train(train_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
function advtrains.get_train_at_pos(pos)
|
function advtrains.get_train_at_pos(pos)
|
||||||
local ph=minetest.pos_to_string(advtrains.round_vector_floor_y(pos))
|
return advtrains.detector.get(pos)
|
||||||
return advtrains.detector.on_node[ph]
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function advtrains.invalidate_all_paths(pos)
|
function advtrains.invalidate_all_paths(pos)
|
||||||
|
|
|
@ -52,7 +52,7 @@ local function create_map_form(d)
|
||||||
if x>=minx and x<=maxx then
|
if x>=minx and x<=maxx then
|
||||||
for z,y in pairs(itx) do
|
for z,y in pairs(itx) do
|
||||||
if z>=minz and z<=maxz then
|
if z>=minz and z<=maxz then
|
||||||
local adn=advtrains.detector.on_node[minetest.pos_to_string({x=x, y=y, z=z})]
|
local adn=advtrains.detector.get({x=x, y=y, z=z})
|
||||||
local color="gray"
|
local color="gray"
|
||||||
if adn then
|
if adn then
|
||||||
color="red"
|
color="red"
|
||||||
|
|
|
@ -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.on_node[ph]
|
local train_id=advtrains.detector.get(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
|
||||||
|
|
Loading…
Reference in New Issue