From 28717b4d65dc2e4080d5c7bde799fb4b87ef9a9d Mon Sep 17 00:00:00 2001 From: orwell96 Date: Wed, 3 May 2017 16:31:13 +0200 Subject: Performance improvements: Don't clear paths unless absolutely necessary instead delete path elements that are too far from the train one-by-one Also when switching a switch or changing rails, only clear train paths of trains that are nearby. --- advtrains/advtrains/atc.lua | 2 +- advtrains/advtrains/init.lua | 38 +++++++- advtrains/advtrains/tracks.lua | 4 +- advtrains/advtrains/trainlogic.lua | 108 ++++++++++++++++----- .../advtrains_luaautomation/active_common.lua | 2 +- 5 files changed, 119 insertions(+), 35 deletions(-) (limited to 'advtrains') diff --git a/advtrains/advtrains/atc.lua b/advtrains/advtrains/atc.lua index ed631a3..5f1f64d 100644 --- a/advtrains/advtrains/atc.lua +++ b/advtrains/advtrains/atc.lua @@ -93,7 +93,7 @@ advtrains.register_tracks("default", { after_place_node=apn_func, after_dig_node=function(pos) return advtrains.pcall(function() - advtrains.invalidate_all_paths() + advtrains.invalidate_all_paths(pos) advtrains.ndb.clear(pos) local pts=minetest.pos_to_string(pos) atc.controllers[pts]=nil diff --git a/advtrains/advtrains/init.lua b/advtrains/advtrains/init.lua index 022fcee..3fc16ed 100644 --- a/advtrains/advtrains/init.lua +++ b/advtrains/advtrains/init.lua @@ -37,7 +37,7 @@ advtrains.modpath = minetest.get_modpath("advtrains") function advtrains.print_concat_table(a) local str="" local stra="" - for i=1,50 do + for i=1,10 do t=a[i] if t==nil then stra=stra.."nil " @@ -67,9 +67,12 @@ end atprint=function() end if minetest.setting_getbool("advtrains_debug") then atprint=function(t, ...) + local context=advtrains.atprint_context_tid + if not context then context="" end + --if context~="4527" then return end local text=advtrains.print_concat_table({t, ...}) - minetest.log("action", "[advtrains]"..text) - minetest.chat_send_all("[advtrains]"..text) + minetest.log("action", "[advtrains]"..context..">"..text) + minetest.chat_send_all("[advtrains]"..context..">"..text) end end atwarn=function(t, ...) @@ -171,7 +174,8 @@ end advtrains.avt_save = function() --atprint("saving") - advtrains.invalidate_all_paths() + --No more invalidating. + --Instead, remove path a.s.o from the saved table manually -- update wagon saves for _,wagon in pairs(minetest.luaentities) do @@ -195,10 +199,34 @@ advtrains.avt_save = function() end end + local tmp_trains={} + for id, train in pairs(advtrains.trains) do + --first, deep_copy the train + local v=advtrains.merge_tables(train) + --then invalidate + if v.index then + v.restore_add_index=v.index-math.floor(v.index+0.5) + end + v.path=nil + v.path_dist=nil + v.index=nil + v.end_index=nil + v.min_index_on_track=nil + v.max_index_on_track=nil + v.path_extent_min=nil + v.path_extent_max=nil + + v.detector_old_index=nil + v.detector_old_end_index=nil + + --then save it + tmp_trains[id]=v + end + --versions: -- 1 - Initial new save format. local save_tbl={ - trains = advtrains.trains, + trains = tmp_trains, wagon_save = advtrains.wagon_save, ptmap = advtrains.player_to_train_mapping, atc = advtrains.atc.save_data(), diff --git a/advtrains/advtrains/tracks.lua b/advtrains/advtrains/tracks.lua index 86c87ba..b390c6a 100644 --- a/advtrains/advtrains/tracks.lua +++ b/advtrains/advtrains/tracks.lua @@ -263,13 +263,13 @@ function advtrains.register_tracks(tracktype, def, preset) local rcswitchfunc=function(pos, node, player) if minetest.check_player_privs(player:get_player_name(), {train_operator=true}) then advtrains.ndb.swap_node(pos, {name=def.nodename_prefix.."_"..suffix_target, param2=node.param2}) - advtrains.invalidate_all_paths() + advtrains.invalidate_all_paths(pos) end end local switchfunc=function(pos, node, newstate) if newstate~=is_state then advtrains.ndb.swap_node(pos, {name=def.nodename_prefix.."_"..suffix_target, param2=node.param2}) - advtrains.invalidate_all_paths() + advtrains.invalidate_all_paths(pos) end end local mesec diff --git a/advtrains/advtrains/trainlogic.lua b/advtrains/advtrains/trainlogic.lua index 7dad80c..e62c864 100644 --- a/advtrains/advtrains/trainlogic.lua +++ b/advtrains/advtrains/trainlogic.lua @@ -55,12 +55,16 @@ advtrains.mainloop_trainlogic=function(dtime) local t=os.clock() advtrains.detector.on_node={} for k,v in pairs(advtrains.trains) do + advtrains.atprint_context_tid=sid(k) advtrains.train_step_a(k, v, dtime) end for k,v in pairs(advtrains.trains) do + advtrains.atprint_context_tid=sid(k) advtrains.train_step_b(k, v, dtime) end + advtrains.atprint_context_tid=nil + atprintbm("trainsteps", t) endstep() end @@ -140,7 +144,7 @@ function advtrains.train_step_a(id, train, dtime) end --- 2. prepare initial path and index if needed --- if not train.index then train.index=0 end - if not train.path or #train.path<2 then + if not train.path then if not train.last_pos then --no chance to recover atprint("train hasn't saved last-pos, removing train.") @@ -224,36 +228,43 @@ function advtrains.train_step_a(id, train, dtime) train.tarvelocity=0 end + --- 3a. this can be useful for debugs/warnings and is used for check_trainpartload --- + local t_info, train_pos=sid(id), train.path[math.floor(train.index)] + if train_pos then + t_info=t_info.." @"..minetest.pos_to_string(train_pos) + end + --apply off-track handling: local front_off_track=train.max_index_on_track and train.index>train.max_index_on_track local back_off_track=train.min_index_on_track and train.end_index1 then train.tarvelocity=1 - atwarn("Train",sid(id)," is off track at both ends. Clipping velocity to 1") + atwarn("Train",t_info,"is off track at both ends. Clipping velocity to 1") pprint=true end elseif front_off_track then--allow movement only backward if train.movedir==1 and train.tarvelocity>0 then train.tarvelocity=0 - atwarn("Train",sid(id)," is off track. Trying to drive further out. Velocity clipped to 0") + atwarn("Train",t_info,"is off track. Trying to drive further out. Velocity clipped to 0") pprint=true end if train.movedir==-1 and train.tarvelocity>1 then train.tarvelocity=1 - atwarn("Train",sid(id)," is off track. Velocity clipped to 1") + atwarn("Train",t_info,"is off track. Velocity clipped to 1") pprint=true end elseif back_off_track then--allow movement only forward if train.movedir==-1 and train.tarvelocity>0 then train.tarvelocity=0 - atwarn("Train",sid(id)," is off track. Trying to drive further out. Velocity clipped to 0") + atwarn("Train",t_info,"is off track. Trying to drive further out. Velocity clipped to 0") pprint=true end if train.movedir==1 and train.tarvelocity>1 then train.tarvelocity=1 - atwarn("Train",sid(id)," is off track. Velocity clipped to 1") + atwarn("Train",t_info,"is off track. Velocity clipped to 1") pprint=true end end @@ -322,7 +333,7 @@ function advtrains.train_step_a(id, train, dtime) --why this is an extra function, see under 3. advtrains.pathpredict(id, train, true) - --make pos/yaw available for possible recover calls + --- 5a. make pos/yaw available for possible recover calls --- if train.max_index_on_trackdelete_max then + 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 + train.path_dist[i]=nil + end + train.path_extent_max=delete_max + 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 @@ -406,7 +447,7 @@ function advtrains.train_step_a(id, train, dtime) train.check_trainpartload=(train.check_trainpartload or 0)-dtime local node_range=(math.max((minetest.setting_get("active_block_range") or 0),1)*16) if train.check_trainpartload<=0 then - local ori_pos=advtrains.get_real_index_position(path, train.index) --not much to calculate + local ori_pos=train_pos --see 3a. --atprint("[train "..id.."] at "..minetest.pos_to_string(vector.round(ori_pos))) local should_check=false @@ -429,6 +470,7 @@ end --about regular: Used by 1. to ensure path gets generated far enough, since end index is not known at this time. function advtrains.pathpredict(id, train, regular) + --TODO duplicate code under 5b. local path_pregen=10 local gen_front= path_pregen @@ -440,7 +482,7 @@ function advtrains.pathpredict(id, train, regular) local maxn=train.path_extent_max or 0 while maxn < gen_front do--pregenerate - --atprint("maxn conway for ",maxn,minetest.pos_to_string(path[maxn]),maxn-1,minetest.pos_to_string(path[maxn-1])) + atprint("maxn conway for ",maxn,minetest.pos_to_string(train.path[maxn]),maxn-1,minetest.pos_to_string(train.path[maxn-1])) local conway=advtrains.conway(train.path[maxn], train.path[maxn-1], train.drives_on) if conway then train.path[maxn+1]=conway @@ -458,7 +500,7 @@ function advtrains.pathpredict(id, train, regular) local minn=train.path_extent_min or -1 while minn > gen_back do - --atprint("minn conway for ",minn,minetest.pos_to_string(path[minn]),minn+1,minetest.pos_to_string(path[minn+1])) + atprint("minn conway for ",minn,minetest.pos_to_string(train.path[minn]),minn+1,minetest.pos_to_string(train.path[minn+1])) local conway=advtrains.conway(train.path[minn], train.path[minn+1], train.drives_on) if conway then train.path[minn-1]=conway @@ -858,23 +900,37 @@ function advtrains.get_train_at_pos(pos) return advtrains.detector.on_node[ph] end -function advtrains.invalidate_all_paths() - --atprint("invalidating all paths") +function advtrains.invalidate_all_paths(pos) + --if a position is given, only invalidate inside a radius to save performance + local inv_radius=50 + atprint("invalidating all paths") for k,v in pairs(advtrains.trains) do - if v.index then - v.restore_add_index=v.index-math.floor(v.index+0.5) - end - v.path=nil - v.path_dist=nil - v.index=nil - v.end_index=nil - v.min_index_on_track=nil - v.max_index_on_track=nil - v.path_extent_min=nil - v.path_extent_max=nil - - v.detector_old_index=nil - v.detector_old_end_index=nil + local exec=true + if pos and v.path and v.index and v.end_index then + --start and end pos of the train + local cmp1=v.path[math.floor(v.index)] + local cmp2=v.path[math.floor(v.end_index)] + if vector.distance(pos, cmp1)>inv_radius and vector.distance(pos, cmp2)>inv_radius then + exec=false + end + end + if exec then + --TODO duplicate code in init.lua avt_save()! + if v.index then + v.restore_add_index=v.index-math.floor(v.index+0.5) + end + v.path=nil + v.path_dist=nil + v.index=nil + v.end_index=nil + v.min_index_on_track=nil + v.max_index_on_track=nil + v.path_extent_min=nil + v.path_extent_max=nil + + v.detector_old_index=nil + v.detector_old_end_index=nil + end end end diff --git a/advtrains/advtrains_luaautomation/active_common.lua b/advtrains/advtrains_luaautomation/active_common.lua index e17af91..8c910c6 100644 --- a/advtrains/advtrains_luaautomation/active_common.lua +++ b/advtrains/advtrains_luaautomation/active_common.lua @@ -49,7 +49,7 @@ function ac.getform(pos, meta_p) end function ac.after_dig_node(pos, node, player) - advtrains.invalidate_all_paths() + advtrains.invalidate_all_paths(pos) advtrains.ndb.clear(pos) local ph=minetest.pos_to_string(pos) ac.nodes[ph]=nil -- cgit v1.2.3