From c67770833b772e438f81ac80f10f1c46bbeebcfa Mon Sep 17 00:00:00 2001 From: orwell96 Date: Wed, 25 Oct 2017 10:31:07 +0200 Subject: Fix coupling and collisions in certain cases If a train moved towards another train, and the other train's step was executed after the first one's, the trains did eventually not collide. Fix by moving the enter_node and collision check to step_b Also change some couple behavior --- advtrains/couple.lua | 36 +++++++----- advtrains/init.lua | 2 + advtrains/trainlogic.lua | 148 ++++++++++++++++++++++++----------------------- 3 files changed, 100 insertions(+), 86 deletions(-) (limited to 'advtrains') diff --git a/advtrains/couple.lua b/advtrains/couple.lua index 7bab241..6741de8 100644 --- a/advtrains/couple.lua +++ b/advtrains/couple.lua @@ -154,27 +154,33 @@ minetest.register_entity("advtrains:couple", { return end - local tp1 - if not self.train1_is_backpos then - tp1=advtrains.get_real_index_position(train1.path, train1.index) - else - tp1=advtrains.get_real_index_position(train1.path, train1.end_index) - end - local tp2 - if not self.train2_is_backpos then - tp2=advtrains.get_real_index_position(train2.path, train2.index) - else - tp2=advtrains.get_real_index_position(train2.path, train2.end_index) - end - if not tp1 or not tp2 or not (vector.distance(tp1,tp2)0 or train2.velocity>0 then + if not self.position_set then --ensures that train stands a single time before check fires. Using flag below + return + end + atprint("Couple: train is moving, destroying") self.object:remove() return - else + end + + if not self.position_set then + local tp1 + if not self.train1_is_backpos then + tp1=advtrains.get_real_index_position(train1.path, train1.index) + else + tp1=advtrains.get_real_index_position(train1.path, train1.end_index) + end + local tp2 + if not self.train2_is_backpos then + tp2=advtrains.get_real_index_position(train2.path, train2.index) + else + tp2=advtrains.get_real_index_position(train2.path, train2.end_index) + end local pos_median=advtrains.pos_median(tp1, tp2) if not vector.equals(pos_median, self.object:getpos()) then self.object:setpos(pos_median) end + self.position_set=true end atprintbm("couple step", t) advtrains.atprint_context_tid=nil diff --git a/advtrains/init.lua b/advtrains/init.lua index 6255780..6f81a40 100644 --- a/advtrains/init.lua +++ b/advtrains/init.lua @@ -105,6 +105,8 @@ if minetest.settings:get_bool("advtrains_enable_debugging") then if not context then return end local text=advtrains.print_concat_table({t, ...}) advtrains.drb_record(context, text) + + --atlog("@@",advtrains.atprint_context_tid,t,...) end atdebug=function(t, ...) local text=advtrains.print_concat_table({t, ...}) diff --git a/advtrains/trainlogic.lua b/advtrains/trainlogic.lua index d8130e9..6a0e61a 100644 --- a/advtrains/trainlogic.lua +++ b/advtrains/trainlogic.lua @@ -125,10 +125,11 @@ train step structure: - environment collision - update index = move - create path -- update node coverage +- call stay_node on all old positions to register train there, for collision system - do less important stuff such as checking trainpartload or removing -- break -- +- Call enter_node and leave_node callbacks (required here because stay_node needs to be called on all trains first) - handle train collisions ]] @@ -154,7 +155,7 @@ function advtrains.train_step_a(id, train, dtime) if not train.path then if not train.last_pos then --no chance to recover - atprint("train hasn't saved last-pos, removing train.") + atwarn("Unable to restore train ",id,": missing last_pos") advtrains.trains[id]=nil return false end @@ -166,14 +167,14 @@ function advtrains.train_step_a(id, train, dtime) atprint("last_pos", advtrains.round_vector_floor_y(train.last_pos), "not loaded and not in ndb, waiting") return nil elseif node_ok==false then - atprint("no track here, (fail) removing train.") + atwarn("Unable to restore train ",id,": No rail at train's position") advtrains.trains[id]=nil return false end if not train.last_pos_prev then --no chance to recover - atprint("train hasn't saved last-pos_prev, removing train.") + atwarn("Unable to restore train ",id,": missing last_pos_prev") advtrains.trains[id]=nil return false end @@ -185,7 +186,7 @@ function advtrains.train_step_a(id, train, dtime) atprint("last_pos_prev", advtrains.round_vector_floor_y(train.last_pos_prev), "not loaded and not in ndb, waiting") return nil elseif prevnode_ok==false then - atprint("no track at prev, (fail) removing train.") + atwarn("Unable to restore train ",id,": No rail at train's position") advtrains.trains[id]=nil return false end @@ -372,7 +373,7 @@ function advtrains.train_step_a(id, train, dtime) local delete_max=math.max(train.min_index_on_track + offtrack_keep, math.floor(train.index)+gen_front_keep) if train.path_extent_mindelete_max then - atprint(sid(id),"clearing path max ",train.path_extent_max," to ",delete_max) + --atprint(sid(id),"clearing path max ",train.path_extent_max," to ",delete_max) train.path_dist[delete_max]=nil for i=delete_max+1,train.path_extent_max do train.path[i]=nil @@ -391,70 +392,16 @@ function advtrains.train_step_a(id, train, dtime) train.max_index_on_track=math.min(train.max_index_on_track, delete_max) end - --- 6. update node coverage --- - - -- when paths get cleared, the old indices set above will be up-to-date and represent the state in which the last run of this code was made - local ifo, ifn, ibo, ibn = train.detector_old_index, math.floor(train.index), train.detector_old_end_index, math.floor(train.end_index) + --- 6b. call stay_node to register trains in the location table - actual enter_node stuff is done in step b --- + local ifn, ibn = math.floor(train.index), math.floor(train.end_index) local path=train.path - if train.enter_node_all then - --field set by create_new_train_at. - --ensures that new train calls enter_node on all nodes - for i=ibn, ifn do - if path[i] then - advtrains.detector.enter_node(path[i], id) - end - end - train.enter_node_all=nil - else - for i=ibn, ifn do - if path[i] then - local pts=minetest.pos_to_string(path[i]) - 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 - - if ifn>ifo then - for i=ifo+1, ifn do - if path[i] then - local pts=minetest.pos_to_string(path[i]) - 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. - atprint("Collision detected in enter_node callbacks (front) @",pts,"with",sid(advtrains.detector.on_node[pts])) - advtrains.collide_and_spawn_couple(id, path[i], advtrains.detector.on_node[pts], false) - end - atprint("enter_node (front) @index",i,"@",pts,"on_node",sid(advtrains.detector.on_node[pts])) - advtrains.detector.enter_node(path[i], id) - end - end - elseif ifnibo then - for i=ibo, ibn-1 do - if path[i] then - advtrains.detector.leave_node(path[i], id) - end + for i=ibn, ifn do + if path[i] then + local pts=minetest.pos_to_string(path[i]) + 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 @@ -502,7 +449,7 @@ function advtrains.pathpredict(id, train, regular) while maxn < gen_front do--pregenerate local conway if train.max_index_on_track == maxn then - atprint("maxn conway for ",maxn,train.path[maxn],maxn-1,train.path[maxn-1]) + --atprint("maxn conway for ",maxn,train.path[maxn],maxn-1,train.path[maxn-1]) conway=advtrains.conway(train.path[maxn], train.path[maxn-1], train.drives_on) end if conway then @@ -523,7 +470,7 @@ function advtrains.pathpredict(id, train, regular) while minn > gen_back do local conway if train.min_index_on_track == minn then - atprint("minn conway for ",minn,train.path[minn],minn+1,train.path[minn+1]) + --atprint("minn conway for ",minn,train.path[minn],minn+1,train.path[minn+1]) conway=advtrains.conway(train.path[minn], train.path[minn+1], train.drives_on) end if conway then @@ -551,6 +498,65 @@ function advtrains.train_step_b(id, train, dtime) if not train.end_index then return end + + --- 6. update node coverage --- + + -- when paths get cleared, the old indices set above will be up-to-date and represent the state in which the last run of this code was made + local ifo, ifn, ibo, ibn = train.detector_old_index, math.floor(train.index), train.detector_old_end_index, math.floor(train.end_index) + + local path=train.path + + if train.enter_node_all then + --field set by create_new_train_at. + --ensures that new train calls enter_node on all nodes + for i=ibn, ifn do + if path[i] then + advtrains.detector.enter_node(path[i], id) + end + end + train.enter_node_all=nil + else + if ifn>ifo then + for i=ifo+1, ifn do + if path[i] then + local pts=minetest.pos_to_string(path[i]) + 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. + atprint("Collision detected in enter_node callbacks (front) @",pts,"with",sid(advtrains.detector.on_node[pts])) + advtrains.collide_and_spawn_couple(id, path[i], advtrains.detector.on_node[pts], false) + end + atprint("enter_node (front) @index",i,"@",pts,"on_node",sid(advtrains.detector.on_node[pts])) + advtrains.detector.enter_node(path[i], id) + end + end + elseif ifnibo then + for i=ibo, ibn-1 do + if path[i] then + advtrains.detector.leave_node(path[i], id) + end + end + end + end --- 8. check for collisions with other trains and damage players --- @@ -695,7 +701,7 @@ function advtrains.update_trainpart_properties(train_id, invert_flipstate) end else - atprint(w_id.." not loaded and no save available") + atwarn("Did not find save data for wagon",w_id,". The wagon will be deleted.") --what the hell... table.remove(train.trainparts, pit) end -- cgit v1.2.3