From 139a26fccce1e622d58f1673284e2addfb0d1ed2 Mon Sep 17 00:00:00 2001 From: orwell96 Date: Wed, 25 Apr 2018 16:38:12 +0200 Subject: Bugfixes part 1 There's something wrong with the new paths, next time build a path validity checker to trace the issue --- advtrains/helpers.lua | 10 +- advtrains/init.lua | 47 ++++---- advtrains/nodedb.lua | 4 +- advtrains/occupation.lua | 27 +++-- advtrains/path.lua | 99 ++++++++++----- advtrains/textures/advtrains_wagon_placeholder.png | Bin 0 -> 723 bytes advtrains/trainhud.lua | 2 +- advtrains/trainlogic.lua | 88 +++++++------- advtrains/wagons.lua | 134 +++++++++++---------- 9 files changed, 227 insertions(+), 184 deletions(-) create mode 100644 advtrains/textures/advtrains_wagon_placeholder.png diff --git a/advtrains/helpers.lua b/advtrains/helpers.lua index 70afadd..9ad5a8e 100644 --- a/advtrains/helpers.lua +++ b/advtrains/helpers.lua @@ -103,8 +103,8 @@ function advtrains.yawToClosestConn(yaw, conns) end function advtrains.dir_to_angle(dir) - local uvec = vector.normalize(advtrains.dirToCoord()) - local yaw1 = math.atan2(uvec.z, -uvec.x) + local uvec = vector.normalize(advtrains.dirToCoord(dir)) + return math.atan2(uvec.z, -uvec.x) end @@ -304,8 +304,8 @@ function advtrains.get_adjacent_rail(this_posnr, this_conns_p, conn_idx, drives_ end if not conn_idx then for coni, _ in ipairs(this_conns) do - local adj_pos, adj_conn_idx, _, nry = advtrains.get_adjacent_rail(this_pos, this_conns, coni) - if adj_pos then return adj_pos,adj_conn_idx,coni,nry end + local adj_pos, adj_conn_idx, _, nry, nco = advtrains.get_adjacent_rail(this_pos, this_conns, coni) + if adj_pos then return adj_pos,adj_conn_idx,coni,nry, nco end end return nil end @@ -330,7 +330,7 @@ function advtrains.get_adjacent_rail(this_posnr, this_conns_p, conn_idx, drives_ end local adj_connid = advtrains.conn_matches_to({c=conn.c, y=conn_y}, nextconns) if adj_connid then - return adj_pos, adj_connid, conn_idx, nextrail_y + return adj_pos, adj_connid, conn_idx, nextrail_y, nextconns end return nil end diff --git a/advtrains/init.lua b/advtrains/init.lua index 0043c22..69b482d 100644 --- a/advtrains/init.lua +++ b/advtrains/init.lua @@ -1,3 +1,7 @@ + +local lot = os.clock() +minetest.log("action", "[advtrains] Loading...") + -- Boilerplate to support localized strings if intllib mod is installed. if minetest.get_modpath("intllib") then attrans = intllib.Getter() @@ -10,7 +14,7 @@ end --Constant for maximum connection value/division of the circle AT_CMAX = 16 -advtrains = {trains={}, wagon_save={}, player_to_train_mapping={}} +advtrains = {trains={}, player_to_train_mapping={}} --pcall local no_action=false @@ -34,24 +38,16 @@ end function advtrains.pcall(fun) if no_action then return end - local succ, return1, return2, return3, return4=xpcall(fun, function(err) - if advtrains.atprint_context_tid then - local train=advtrains.trains[advtrains.atprint_context_tid_full] - advtrains.dumppath(train.path) - atwarn("Dumping last debug outputs: ", err) - atprint("Train state: index",train.index,"end_index", train.end_index,"| max_iot", train.max_index_on_track, "min_iot", train.min_index_on_track, "<> pe_min", train.path_extent_min,"pe_max", train.path_extent_max) - if minetest.settings:get_bool("advtrains_enable_debugging") then - advtrains.drb_dump(advtrains.atprint_context_tid) - end - end - atwarn("Lua Error occured: ", err) - atwarn(debug.traceback()) - end) - if not succ then - reload_saves() - else - return return1, return2, return3, return4 - end + --local succ, return1, return2, return3, return4=xpcall(fun, function(err) + -- atwarn("Lua Error occured: ", err) + -- atwarn(debug.traceback()) + -- end) + --if not succ then + -- reload_saves() + --else + -- return return1, return2, return3, return4 + --end + return fun() end @@ -149,6 +145,7 @@ dofile(advtrains.modpath.."/trainlogic.lua") dofile(advtrains.modpath.."/trainhud.lua") dofile(advtrains.modpath.."/trackplacer.lua") dofile(advtrains.modpath.."/tracks.lua") +dofile(advtrains.modpath.."/occupation.lua") dofile(advtrains.modpath.."/atc.lua") dofile(advtrains.modpath.."/wagons.lua") dofile(advtrains.modpath.."/protection.lua") @@ -282,10 +279,6 @@ advtrains.avt_save = function(remove_players_from_wagons) "atc_brake_target", "atc_wait_finish", "atc_command", "atc_delay", "door_open", "text_outside", "text_inside", "couple_lck_front", "couple_lck_back", "line" }) - --then invalidate - if train.index then - v.restore_add_index=train.index-math.floor(train.index+1) - end --then save it tmp_trains[id]=v end @@ -294,7 +287,7 @@ advtrains.avt_save = function(remove_players_from_wagons) -- 1 - Initial new save format. local save_tbl={ trains = tmp_trains, - wagon_save = advtrains.wagon_save, + wagon_save = advtrains.wagons, ptmap = advtrains.player_to_train_mapping, atc = advtrains.atc.save_data(), ndb = advtrains.ndb.save_data(), @@ -351,7 +344,7 @@ minetest.register_globalstep(function(dtime_mt) if save_timer<=0 then local t=os.clock() --save - advtrains.save() + --advtrains.save() save_timer=save_interval atprintbm("saving", t) end @@ -390,7 +383,7 @@ function advtrains.save(remove_players_from_wagons) end atprint("[save_all]Saved advtrains save files") end -minetest.register_on_shutdown(advtrains.save) +--minetest.register_on_shutdown(advtrains.save) -- This chat command provides a solution to the problem known on the LinuxWorks server -- There are many players that joined a single time, got on a train and then left forever @@ -422,3 +415,5 @@ minetest.register_chatcommand("at_reroute", end, }) +local tot=(os.clock()-lot)*1000 +minetest.log("action", "[advtrains] Loaded in "..tot.."ms") diff --git a/advtrains/nodedb.lua b/advtrains/nodedb.lua index 592e730..6695eba 100644 --- a/advtrains/nodedb.lua +++ b/advtrains/nodedb.lua @@ -210,7 +210,7 @@ ndb.run_lbm = function(pos, node) end else --if not in database, take it. - atlog("Node Database:", pos, "was not found in the database, have you used worldedit?") + --atlog("Node Database:", pos, "was not found in the database, have you used worldedit?") ndb.update(pos, node) end return false @@ -256,7 +256,7 @@ ndb.restore_all = function() end end end - local text="Restore node database: Replaced"..cnt.."nodes, removed"..dcnt.."ghost nodes." + local text="Restore node database: Replaced "..cnt.." nodes, removed "..dcnt.." ghost nodes." atlog(text) return text end diff --git a/advtrains/occupation.lua b/advtrains/occupation.lua index f6fa6fc..7af4a3d 100644 --- a/advtrains/occupation.lua +++ b/advtrains/occupation.lua @@ -64,7 +64,7 @@ Composition of a step: 4. we iterate our change lists and determine what to do ]]-- -local o +local o = {} o.restore_required = true @@ -74,6 +74,8 @@ local seqnum = 0 local occ = {} local occ_chg = {} +local addchg, handle_chg + local function occget(p) local t = occ[p.y] @@ -81,10 +83,11 @@ local function occget(p) occ[p.y] = {} t = occ[p.y] end + local s = t t = t[p.x] if not t then - t[p.x] = {} - t = t[p.x] + s[p.x] = {} + t = s[p.x] end return t[p.z] end @@ -94,15 +97,17 @@ local function occgetcreate(p) occ[p.y] = {} t = occ[p.y] end + local s = t t = t[p.x] if not t then - t[p.x] = {} - t = t[p.x] + s[p.x] = {} + t = s[p.x] end + s = t t = t[p.z] if not t then - t[p.z] = {} - t = t[p.z] + s[p.z] = {} + t = s[p.z] end return t end @@ -119,7 +124,7 @@ end function o.init_occupation(train_id, pos, oid) local t = occgetcreate(pos) local i = 1 - while t[i] + while t[i] do if t[i]==train_id then break end @@ -132,7 +137,7 @@ end function o.set_occupation(train_id, pos, oid) local t = occgetcreate(pos) local i = 1 - while t[i] + while t[i] do if t[i]==train_id then break end @@ -171,7 +176,7 @@ function o.clear_occupation(train_id, pos) end end -local function addchg(pos, train_id, old, new) +function addchg(pos, train_id, old, new) occ_chg[#occ_chg + 1] = { pos = pos, train_id = train_id, @@ -196,7 +201,7 @@ function o.end_step() seqnum = seqnum + 1 end -local function handle_chg(t, pos, train_id, old, new) +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) diff --git a/advtrains/path.lua b/advtrains/path.lua index a98a1b5..039085c 100644 --- a/advtrains/path.lua +++ b/advtrains/path.lua @@ -113,8 +113,8 @@ function advtrains.path_create(train, pos, connid, rel_index) train.path_dist = {} train.path_dir = { - [ 0] = conns[connid], - [-1] = conns[mconnid] + [1] = conns[connid].c, + [0] = advtrains.oppd(conns[mconnid].c) } train.path_ext_f=0 @@ -123,31 +123,49 @@ function advtrains.path_create(train, pos, connid, rel_index) train.path_trk_b=0 train.path_req_f=0 train.path_req_b=0 + atdebug("path_create",train) end +function advtrains.path_invalidate(train) + train.path = nil + train.path_dist = nil + train.path_cp = nil + train.path_cn = nil + train.path_dir = nil + train.path_ext_f=0 + train.path_ext_b=0 + train.path_trk_f=0 + train.path_trk_b=0 + train.path_req_f=0 + train.path_req_b=0 +end + -- Function to get path entry at a position. This function will automatically calculate more of the path when required. -- returns: pos, on_track function advtrains.path_get(train, index) + if not train.path then + error("For train "..train.id..": path_get called but there's no path set yet!") + end if index ~= atfloor(index) then error("For train "..train.id..": Called path_get() but index="..index.." is not a round number") end while index > train.path_ext_f do local pos = train.path[train.path_ext_f] local connid = train.path_cn[train.path_ext_f] - local node_ok, this_conns, adj_pos, adj_connid, conn_idx, nextrail_y + local node_ok, this_conns, adj_pos, adj_connid, conn_idx, nextrail_y, next_conns if train.path_ext_f == train.path_trk_f then - node_ok, this_conns = advtrains.get_rail_info_at(this_pos) + node_ok, this_conns = advtrains.get_rail_info_at(pos) if not node_ok then error("For train "..train.id..": Path item "..train.path_ext_f.." on-track but not a valid node!") end - adj_pos, adj_connid, conn_idx, nextrail_y = advtrains.get_adjacent_rail(pos, this_conns, connid, train.drives_on) + adj_pos, adj_connid, conn_idx, nextrail_y, next_conns = advtrains.get_adjacent_rail(pos, this_conns, connid, train.drives_on) end train.path_ext_f = train.path_ext_f + 1 if adj_pos then adj_pos.y = adj_pos.y + nextrail_y train.path_cp[train.path_ext_f] = adj_connid - local mconnid = advtrains.get_matching_conn(adj_connid) + local mconnid = advtrains.get_matching_conn(adj_connid, #next_conns) train.path_cn[train.path_ext_f] = mconnid - train.path_dir[train.path_ext_f] = this_conns[mconnid] + train.path_dir[train.path_ext_f+1] = this_conns[mconnid].c train.path_trk_f = train.path_ext_f else -- off-track fallback behavior @@ -160,19 +178,21 @@ function advtrains.path_get(train, index) while index < train.path_ext_b do local pos = train.path[train.path_ext_b] local connid = train.path_cp[train.path_ext_b] - local node_ok, this_conns, adj_pos, adj_connid, conn_idx, nextrail_y + local node_ok, this_conns, adj_pos, adj_connid, conn_idx, nextrail_y, next_conns if train.path_ext_b == train.path_trk_b then - node_ok, this_conns = advtrains.get_rail_info_at(this_pos) + node_ok, this_conns = advtrains.get_rail_info_at(pos) if not node_ok then error("For train "..train.id..": Path item "..train.path_ext_f.." on-track but not a valid node!") end - adj_pos, adj_connid, conn_idx, nextrail_y = advtrains.get_adjacent_rail(pos, this_conns, connid, train.drives_on) + adj_pos, adj_connid, conn_idx, nextrail_y, next_conns = advtrains.get_adjacent_rail(pos, this_conns, connid, train.drives_on) end train.path_ext_b = train.path_ext_b - 1 if adj_pos then adj_pos.y = adj_pos.y + nextrail_y - train.path_cp[train.path_ext_b] = adj_connid - local mconnid = advtrains.get_matching_conn(adj_connid) - train.path_cn[train.path_ext_b] = mconnid - train.path_dir[train.path_ext_b] = advtrains.oppd(this_conns[mconnid]) --we need to rotate this here so that it points in positive path direction + train.path_cn[train.path_ext_b] = adj_connid + local mconnid = advtrains.get_matching_conn(adj_connid, #next_conns) + train.path_cp[train.path_ext_b] = mconnid + + train.path_dir[train.path_ext_b] = advtrains.oppd(this_conns[mconnid].c) + train.path_trk_b = train.path_ext_b else -- off-track fallback behavior @@ -200,7 +220,7 @@ function advtrains.path_get_interpolated(train, index) local i_floor = atfloor(index) local i_ceil = i_floor + 1 local frac = index - i_floor - local p_floor, = advtrains.path_get(train, i_floor) + local p_floor = advtrains.path_get(train, i_floor) local p_ceil = advtrains.path_get(train, i_ceil) -- Note: minimal code duplication to path_get_adjacent, for performance @@ -211,7 +231,7 @@ function advtrains.path_get_interpolated(train, index) local ang = advtrains.minAngleDiffRad(a_floor, a_ceil) - return vector.add(p_floor, vector.multiply(vector.subtract(npos2, npos), 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 -- TODO does this behave correctly? end -- returns the 2 path positions directly adjacent to index and the fraction on how to interpolate between them -- returns: pos_floor, pos_ceil, fraction @@ -219,26 +239,43 @@ function advtrains.path_get_adjacent(train, index) local i_floor = atfloor(index) local i_ceil = i_floor + 1 local frac = index - i_floor - local p_floor, = advtrains.path_get(train, i_floor) + local p_floor = advtrains.path_get(train, i_floor) local p_ceil = advtrains.path_get(train, i_ceil) return p_floor, p_ceil, frac end function advtrains.path_get_index_by_offset(train, index, offset) - local pos_in_train_left=pit - local index=train.index - if pos_in_train_left>(index-math.floor(index))*(train.path_dist[math.floor(index)] or 1) then - pos_in_train_left=pos_in_train_left - (index-math.floor(index))*(train.path_dist[math.floor(index)] or 1) - index=math.floor(index) - while pos_in_train_left>(train.path_dist[index-1] or 1) do - pos_in_train_left=pos_in_train_left - (train.path_dist[index-1] or 1) - index=index-1 + local off = offset + local idx = atfloor(index) + -- go down to floor. Calculate required path_dist + advtrains.path_get_adjacent(train, idx) + off = off + ((index-idx) * train.path_dist[idx]) + --atdebug("pibo: 1 off=",off,"idx=",idx," index=",index) + + -- then walk the path back until we overshoot (off becomes >=0) + while off<0 do + idx = idx - 1 + advtrains.path_get_adjacent(train, idx) + off = off + train.path_dist[idx] + end + --atdebug("pibo: 2 off=",off,"idx=",idx) + -- then walk the path forward until we would overshoot + while off - train.path_dist[idx] >= 0 do + idx = idx - 1 + advtrains.path_get_adjacent(train, idx) + if not train.path_dist[idx] then + atdebug("second while",idx) + for i=-5,5 do + atdebug(idx+i,train.path_dist[idx+i]) + end end - index=index-(pos_in_train_left/(train.path_dist[index-1] or 1)) - else - index=index-(pos_in_train_left/(train.path_dist[math.floor(index-1)] or 1)) + off = off - train.path_dist[idx] end - return index + --atdebug("pibo: 3 off=",off,"idx=",idx," returns:",idx + (off / train.path_dist[idx])) + -- we should now be on the floor of the index we actually want. + -- give them the rest! + + return idx + (off / train.path_dist[idx]) end local PATH_CLEAR_KEEP = 2 @@ -246,14 +283,14 @@ local PATH_CLEAR_KEEP = 2 function advtrains.path_clear_unused(train) for i = train.path_ext_b, train.path_req_b - PATH_CLEAR_KEEP do train.path[i] = nil - train.path_dist[i] = nil + train.path_dist[i-1] = nil train.path_cp[i] = nil train.path_cn[i] = nil train.path_dir[i] = nil end for i = train.path_req_f + PATH_CLEAR_KEEP, train.path_ext_f do train.path[i] = nil - train.path_dist[i-1] = nil + train.path_dist[i] = nil train.path_cp[i] = nil train.path_cn[i] = nil train.path_dir[i+1] = nil diff --git a/advtrains/textures/advtrains_wagon_placeholder.png b/advtrains/textures/advtrains_wagon_placeholder.png new file mode 100644 index 0000000..383c181 Binary files /dev/null and b/advtrains/textures/advtrains_wagon_placeholder.png differ diff --git a/advtrains/trainhud.lua b/advtrains/trainhud.lua index e48e3e4..26af2a1 100644 --- a/advtrains/trainhud.lua +++ b/advtrains/trainhud.lua @@ -60,7 +60,7 @@ function advtrains.on_control_change(pc, train, flip) end act=true else - train.movedir = -train.movedir + --train.movedir = -train.movedir end end if pc.left then diff --git a/advtrains/trainlogic.lua b/advtrains/trainlogic.lua index 110d3f6..12ec8b5 100644 --- a/advtrains/trainlogic.lua +++ b/advtrains/trainlogic.lua @@ -70,24 +70,26 @@ advtrains.mainloop_trainlogic=function(dtime) for k,v in pairs(advtrains.trains) do advtrains.atprint_context_tid=sid(k) advtrains.atprint_context_tid_full=k - train_ensure_clean(k, v, dtime) + advtrains.train_ensure_clean(k, v, dtime, advtrains.occ.restore_required) end for k,v in pairs(advtrains.trains) do advtrains.atprint_context_tid=sid(k) advtrains.atprint_context_tid_full=k - train_step_b(k, v, dtime) + advtrains.train_step_b(k, v, dtime) end for k,v in pairs(advtrains.trains) do advtrains.atprint_context_tid=sid(k) advtrains.atprint_context_tid_full=k - train_step_c(k, v, dtime) + advtrains.train_step_c(k, v, dtime) end advtrains.atprint_context_tid=nil advtrains.atprint_context_tid_full=nil + advtrains.occ.end_step() + atprintbm("trainsteps", t) endstep() end @@ -216,7 +218,7 @@ local function write_occupation(win, train_id, train, write_mode) local c_index = math.ceil(win[1]) while win[n_window] do local winix = win[n_window] - local oid = WINDOW_ZONE_IDS[n_windows - 1] + 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 @@ -242,7 +244,7 @@ end -- - the train's path got cleared -- - the occupation table got cleared -- Additionally, this gets called outside the step cycle to initialize and/or remove a train, then occ_write_mode is set. -local function train_ensure_clean(id, train, dtime, report_occupations, occ_write_mode) +function advtrains.train_ensure_clean(id, train, dtime, report_occupations, occ_write_mode) train.dirty = true if train.no_step then return end @@ -258,29 +260,31 @@ local function train_ensure_clean(id, train, dtime, report_occupations, occ_writ --restore path if not train.path then if not train.last_pos then - atwarn("Train",id": Restoring path failed, no last_pos set! Train will be disabled. You can try to fix the issue in the save file.") + atwarn("Train",id,": Restoring path failed, no last_pos set! Train will be disabled. You can try to fix the issue in the save file.") train.no_step = true return end if not train.last_connid then - atwarn("Train",id": Restoring path failed, no last_connid set! Will assume 1") + atwarn("Train",id,": Restoring path: no last_connid set! Will assume 1") end - local result = advtrains.path_create(train, train.last_pos, train.last_connid, train.last_frac or 0) + local result = advtrains.path_create(train, train.last_pos, train.last_connid or 1, train.last_frac or 0) if result==false then - atwarn("Train",id": Restoring path failed, node at",train.last_pos,"is gone! Train will be disabled. You can try to fix the issue in the save file.") + atwarn("Train",id,": Restoring path failed, node at",train.last_pos,"is gone! Train will be disabled. You can try to fix the issue in the save file.") train.no_step = true return elseif result==nil then if not train.wait_for_path then - atwarn("Train",id": Can't initialize: Waiting for the (yet unloaded) node at",train.last_pos," to be loaded.") + atwarn("Train",id,": Can't initialize: Waiting for the (yet unloaded) node at",train.last_pos," to be loaded.") end train.wait_for_path = true end -- by now, we should have a working initial path + train.wait_for_path = false train.occwindows = nil advtrains.update_trainpart_properties(id) + atdebug("Train",id,": Successfully restored path at",train.last_pos," connid",train.last_connid," frac",train.last_frac) -- TODO recoverposition?! end @@ -289,18 +293,18 @@ local function train_ensure_clean(id, train, dtime, report_occupations, occ_writ train.occwindows = calc_occwindows(id, train) end if report_occupations then - write_occupation(train.occwindows, train, occ_write_mode) + write_occupation(train.occwindows, id, train, occ_write_mode) end train.dirty = false -- TODO einbauen! end -local function train_step_b(id, train, dtime) +function advtrains.train_step_b(id, train, dtime) if train.no_step or train.wait_for_path then return end -- in this code, we check variables such as path_trk_? and path_dist. We need to ensure that the path is known for the whole 'Train' zone - advtrains.path_get(train, train.index + 1) - advtrains.path_get(train, train.end_index - 1) + advtrains.path_get(train, atfloor(train.index + 2)) + advtrains.path_get(train, atfloor(train.end_index - 1)) --- 3. handle velocity influences --- local train_moves=(train.velocity~=0) @@ -318,7 +322,7 @@ local function train_step_b(id, train, dtime) end --- 3a. this can be useful for debugs/warnings and is used for check_trainpartload --- - local t_info, train_pos=sid(id), advtrains.path_get(atfloor(train.index)) + local t_info, train_pos=sid(id), advtrains.path_get(train, atfloor(train.index)) if train_pos then t_info=t_info.." @"..minetest.pos_to_string(train_pos) --atprint("train_pos:",train_pos) @@ -416,13 +420,13 @@ local function train_step_b(id, train, dtime) end -local function train_recalc_occupation() +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 -local function 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 -- all location/extent-critical actions have been done. @@ -433,7 +437,7 @@ if train.no_step or train.wait_for_path then return end -- Set our path restoration position local fli = atfloor(train.index) - train.last_pos = advtrains.path_get(fli) + train.last_pos = advtrains.path_get(train, fli) train.last_connid = train.path_cn[fli] train.last_frac = train.index - fli @@ -453,7 +457,8 @@ if train.no_step or train.wait_for_path then return end local collpos local coll_grace=1 - collpos=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)) if collpos then local rcollpos=advtrains.round_vector_floor_y(collpos) for x=-train.extent_h,train.extent_h do @@ -509,8 +514,8 @@ function advtrains.create_new_train_at(pos, connid, ioff, trainparts) local new_id=advtrains.random_id() while advtrains.trains[new_id] do new_id=advtrains.random_id() end--ensure uniqueness - t={} - t.id = newtrain_id + local t={} + t.id = new_id t.last_pos=pos t.last_connid=connid @@ -520,22 +525,24 @@ function advtrains.create_new_train_at(pos, connid, ioff, trainparts) t.velocity=0 t.trainparts=trainparts - advtrains.trains[new_id] = t + atdebug("Created new train:",t) advtrains.update_trainpart_properties(new_id) - train_ensure_clean(new_id, advtrains.trains[new_id], 0, true, 1) + advtrains.train_ensure_clean(new_id, advtrains.trains[new_id], 0, true, 1) - return newtrain_id + return new_id end function advtrains.remove_train(id) local train = advtrains.trains[id] + advtrains.train_ensure_clean(id, train) + advtrains.update_trainpart_properties(id) - train_ensure_clean(id, train, 0, true, 2) + advtrains.train_ensure_clean(id, train, 0, true, 2) local tp = train.trainparts @@ -549,7 +556,7 @@ end function advtrains.add_wagon_to_train(wagon_id, train_id, index) local train=advtrains.trains[train_id] - train_ensure_clean(train_id, train) + advtrains.train_ensure_clean(train_id, train) if index then table.insert(train.trainparts, index, wagon_id) @@ -578,10 +585,10 @@ function advtrains.update_trainpart_properties(train_id, invert_flipstate) -- 1st: update wagon data (pos_in_train a.s.o) if data then - local wagon = minetest.registered_luaentites[data.type] + local wagon = advtrains.wagon_prototypes[data.type] if not wagon then atwarn("Wagon '",data.type,"' couldn't be found. Please check that all required modules are loaded!") - wagon = minetest.registered_luaentites["advtrains:wagon_placeholder"] + wagon = advtrains.wagon_prototypes["advtrains:wagon_placeholder"] end rel_pos=rel_pos+wagon.wagon_span @@ -608,6 +615,8 @@ function advtrains.update_trainpart_properties(train_id, invert_flipstate) train.extent_h = math.max(train.extent_h, wagon.extent_h or 1); end end + train.trainlen = rel_pos + train.locomotives_in_train = count_l end -- This function checks whether entities need to be spawned for certain wagons, and spawns them. @@ -624,13 +633,11 @@ function advtrains.spawn_wagons(train_id) if minetest.get_node_or_nil(pos) then local wt = advtrains.get_wagon_prototype(data) - wagon=minetest.add_entity(pos, wt):get_luaentity() + local wagon = minetest.add_entity(pos, wt):get_luaentity() wagon:set_id(w_id) end end end - - end end @@ -641,7 +648,7 @@ function advtrains.split_train_at_wagon(wagon_id) local train=advtrains.trains[data.train_id] local _, wagon = advtrains.get_wagon_prototype(data) - train_ensure_clean(data.train_id, train) + advtrains.train_ensure_clean(data.train_id, train) local index=advtrains.path_get_index_by_offset(train, train.index, -(data.pos_in_train + wagon.wagon_span)) @@ -901,21 +908,8 @@ end function advtrains.invalidate_path(id) local v=advtrains.trains[id] if not v then return end - --TODO duplicate code in init.lua avt_save()! - if v.index then - v.restore_add_index=v.index-math.floor(v.index+1) - 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 + advtrains.path_invalidate(v) + v.dirty = true end --not blocking trains group diff --git a/advtrains/wagons.lua b/advtrains/wagons.lua index 83f919e..c3217e2 100644 --- a/advtrains/wagons.lua +++ b/advtrains/wagons.lua @@ -2,24 +2,27 @@ -- Holds all logic related to wagons -- From now on, wagons are, just like trains, just entries in a table -- All data that is static is stored in the entity prototype (self). --- A copy of the entity prototype is always available inside minetest.registered_luaentities +-- A copy of the entity prototype is always available inside wagon_prototypes -- All dynamic data is stored in the (new) wagons table -- An entity is ONLY spawned by update_trainpart_properties when it finds it useful. -- Only data that are only important to the entity itself are stored in the luaentity advtrains.wagons = {} +advtrains.wagon_prototypes = {} + -- -function advtrains.create_wagon(type, owner) +function advtrains.create_wagon(wtype, owner) local new_id=advtrains.random_id() while advtrains.wagons[new_id] do new_id=advtrains.random_id() end local wgn = {} - wgn.type = type + wgn.type = wtype wgn.seatp = {} wgn.owner = owner wgn.id = new_id ---wgn.train_id = train_id --- will get this via update_trainpart_properties advtrains.wagons[new_id] = wgn + atdebug("Created new wagon:",wgn) return new_id end @@ -59,6 +62,9 @@ function wagon:set_id(wid) local data = advtrains.wagons[self.id] + data.object = self.object + atdebug("Created wagon entity:",self.name," w_id",wid," t_id",data.train_id) + if self.has_inventory then --to be used later local inv=minetest.create_detached_inventory("advtrains_wgn_"..self.id, { @@ -89,20 +95,27 @@ function wagon:set_id(wid) if self.custom_on_activate then self:custom_on_activate(dtime_s) end +end function wagon:get_staticdata() return "STATIC" end function wagon:ensure_init() - if self.initialized then - if self.noninitticks then self.noninitticks=nil end - return true + -- Note: A wagon entity won't exist when there's no train, because the train is + -- the thing that actually creates the entity + -- 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 + local data = advtrains.wagons[self.id] + if data.train_id then + if self.noninitticks then self.noninitticks=nil end + return true + end end if not self.noninitticks then self.noninitticks=0 end self.noninitticks=self.noninitticks+1 if self.noninitticks>20 then - self.object:remove() + self:destroy() else self.object:setvelocity({x=0,y=0,z=0}) end @@ -110,7 +123,8 @@ function wagon:ensure_init() end function wagon:train() - return advtrains.trains[self.train_id] + local data = advtrains.wagons[self.id] + return advtrains.trains[data.train_id] end -- Remove the wagon @@ -158,26 +172,28 @@ function wagon:destroy() -- single left-click shows warning -- shift leftclick destroys -- not when a driver is inside - local data = advtrains.wagons[self.id] - - if self.custom_on_destroy then - self.custom_on_destroy(self) - end - - for seat,_ in pairs(data.seatp) do - self:get_off(seat) + if self.id then + local data = advtrains.wagons[self.id] + + if self.custom_on_destroy then + self.custom_on_destroy(self) + end + + for seat,_ in pairs(data.seatp) do + self:get_off(seat) + end + + if data.train_id and self:train() then + table.remove(self:train().trainparts, data.pos_in_trainparts) + advtrains.update_trainpart_properties(self.train_id) + advtrains.wagons[self.id]=nil + if self.discouple then self.discouple.object:remove() end--will have no effect on unloaded objects + return true + end end - atprint("[wagon ", self.id, "]: destroying") self.object:remove() - - if self.train_id and self:train() then - table.remove(self:train().trainparts, data.pos_in_trainparts) - advtrains.update_trainpart_properties(self.train_id) - advtrains.wagons[self.id]=nil - if self.discouple then self.discouple.object:remove() end--will have no effect on unloaded objects - return true end @@ -190,16 +206,10 @@ function wagon:on_step(dtime) local data = advtrains.wagons[self.id] if not pos then - atprint("["..self.unique_id.."][fatal] missing position (object:getpos() returned nil)") + atdebug("["..self.id.."][fatal] missing position (object:getpos() returned nil)") return end - --is my train still here - if not self.train_id or not self:train() then - atprint("[wagon "..self.unique_id.."] missing train_id, destroying") - self:destroy() - return - end if not data.seatp then data.seatp={} end @@ -331,7 +341,7 @@ function wagon:on_step(dtime) if data.pos_in_trainparts and data.pos_in_trainparts>1 then if train.velocity==0 and not data.dcpl_lock then if not self.discouple or not self.discouple.object:getyaw() then - atprint(self.unique_id,"trying to spawn discouple") + atprint(self.id,"trying to spawn discouple") local yaw = self.object:getyaw() local flipsign=data.wagon_flipped and -1 or 1 local dcpl_pos = vector.add(pos, {y=0, x=-math.sin(yaw)*self.wagon_span*flipsign, z=math.cos(yaw)*self.wagon_span*flipsign}) @@ -342,7 +352,7 @@ function wagon:on_step(dtime) --box is hidden when attached, so unuseful. --object:set_attach(self.object, "", {x=0, y=0, z=self.wagon_span*10}, {x=0, y=0, z=0}) self.discouple=le - atprint(self.unique_id,"success") + atprint(self.id,"success") else atprint("Couldn't spawn DisCouple") end @@ -370,7 +380,7 @@ function wagon:on_step(dtime) --automatic get_on --needs to know index and path - if self.door_entry and gp.door_open and gp.door_open~=0 and gp.velocity==0 then + if self.door_entry and train.door_open and train.door_open~=0 and train.velocity==0 then --using the mapping created by the trainlogic globalstep for i, ino in ipairs(self.door_entry) do --fct is the flipstate flag from door animation above @@ -399,7 +409,7 @@ function wagon:on_step(dtime) end --checking for environment collisions(a 3x3 cube around the center) - if not gp.recently_collided_with_env then + if not train.recently_collided_with_env then local collides=false local exh = self.extent_h or 1 local exv = self.extent_v or 2 @@ -407,9 +417,10 @@ function wagon:on_step(dtime) for y=0,exv do for z=-exh,exh do local node=minetest.get_node_or_nil(vector.add(npos, {x=x, y=y, z=z})) - if (advtrains.train_collides(node)) then - collides=true - end + -- TODO + --if (advtrains.train_collides(node)) then + -- collides=true + --end end end end @@ -432,8 +443,8 @@ function wagon:on_step(dtime) end --FIX: use index of the wagon, not of the train. - local velocity = (gp.velocity*gp.movedir) - local acceleration = (gp.last_accel or 0) + local velocity = train.velocity + local acceleration = (train.acceleration or 0) local velocityvec = vector.multiply(vdir, velocity) local accelerationvec = vector.multiply(vdir, acceleration) @@ -482,13 +493,13 @@ function wagon:on_step(dtime) self:update_animation(gp.velocity, self.old_velocity) end if self.custom_on_velocity_change then - self:custom_on_velocity_change(gp.velocity, self.old_velocity or 0, dtime) + self:custom_on_velocity_change(train.velocity, self.old_velocity or 0, dtime) end end self.old_velocity_vector=velocityvec - self.old_velocity = gp.velocity + self.old_velocity = train.velocity self.old_acceleration_vector=accelerationvec self.old_yaw=yaw atprintbm("wagon step", t) @@ -542,7 +553,7 @@ function wagon:on_rightclick(clicker) for pos,ent in ipairs(poss) do form = form .. "button_exit[0.5,"..(pos-0.5)..";4,1;"..ent.key..";"..ent.name.."]" end - minetest.show_formspec(pname, "advtrains_seating_"..self.unique_id, form) + minetest.show_formspec(pname, "advtrains_seating_"..self.id, form) end else self:get_off(no) @@ -553,7 +564,7 @@ function wagon:on_rightclick(clicker) if self.seat_groups then if #self.seats==0 then if self.has_inventory and self.get_inventory_formspec then - minetest.show_formspec(pname, "advtrains_inv_"..self.unique_id, self:get_inventory_formspec(pname)) + minetest.show_formspec(pname, "advtrains_inv_"..self.id, self:get_inventory_formspec(pname)) end return end @@ -687,7 +698,7 @@ function wagon:show_get_on_form(pname) local data = advtrains.wagons[self.id] if #self.seats==0 then if self.has_inventory and self.get_inventory_formspec then - minetest.show_formspec(pname, "advtrains_inv_"..self.unique_id, self:get_inventory_formspec(pname)) + minetest.show_formspec(pname, "advtrains_inv_"..self.id, self:get_inventory_formspec(pname)) end return end @@ -705,7 +716,7 @@ function wagon:show_get_on_form(pname) if self.has_inventory and self.get_inventory_formspec then form=form.."button_exit[1,7;3,1;inv;"..attrans("Show Inventory").."]" end - minetest.show_formspec(pname, "advtrains_geton_"..self.unique_id, form) + minetest.show_formspec(pname, "advtrains_geton_"..self.id, form) end function wagon:show_wagon_properties(pname) --[[ @@ -754,9 +765,9 @@ function wagon:show_bordcom(pname) linhei=5 local pre_own, pre_wl, owns_any = nil, nil, minetest.check_player_privs(pname, "train_admin") for i, tpid in ipairs(train.trainparts) do - local ent = advtrains.wagon_save[tpid] + local ent = advtrains.wagons[tpid] if ent then - local ename = ent.entity_name + local ename = ent.type form = form .. "item_image["..i..","..linhei..";1,1;"..ename.."]" if i~=1 then if not ent.dcpl_lock then @@ -809,7 +820,7 @@ function wagon:show_bordcom(pname) end form = form .. "button[0.5,8;3,1;Save;save]" - minetest.show_formspec(pname, "advtrains_bordcom_"..self.unique_id, form) + minetest.show_formspec(pname, "advtrains_bordcom_"..self.id, form) end function wagon:handle_bordcom_fields(pname, formname, fields) local data = advtrains.wagons[self.id] @@ -837,8 +848,8 @@ function wagon:handle_bordcom_fields(pname, formname, fields) for i, tpid in ipairs(train.trainparts) do if fields["dcpl_"..i] then for _,wagon in pairs(minetest.luaentities) do - if wagon.is_wagon and wagon.initialized and wagon.unique_id==tpid then - wagon:safe_decouple(pname) -- TODO: Move this into external function (don't search entity?) + if wagon.is_wagon and wagon.initialized and wagon.id==tpid then + wagon:safe_decouple(pname) -- TODO: Move this into external function (don't search entity?) end end end @@ -954,7 +965,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields) uid=string.match(formname, "^advtrains_bordcom_(.+)$") if uid then for _,wagon in pairs(minetest.luaentities) do - if wagon.is_wagon and wagon.initialized and wagon.unique_id==uid then + if wagon.is_wagon and wagon.initialized and wagon.id==uid then wagon:handle_bordcom_fields(player:get_player_name(), formname, fields) end end @@ -962,7 +973,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields) end) end) function wagon:seating_from_key_helper(pname, fields, no) - local data = advtrains.wagons[wagon.id] + local data = advtrains.wagons[self.id] local sgr=self.seats[no].group for _,access in ipairs(self.seat_groups[sgr].access_to) do if fields["sgr_"..access] and self:check_seat_group_access(pname, access) then @@ -1000,7 +1011,7 @@ function wagon:check_seat_group_access(pname, sgr) return true end function wagon:reattach_all() - local data = advtrains.wagons[wagon.id] + local data = advtrains.wagons[self.id] if not data.seatp then data.seatp={} end for seatno, pname in pairs(data.seatp) do local p=minetest.get_player_by_name(pname) @@ -1015,7 +1026,7 @@ function wagon:safe_decouple(pname) minetest.chat_send_player(pname, "Missing train_operator privilege") return false end - local data = advtrains.wagons[wagon.id] + local data = advtrains.wagons[self.id] if data.dcpl_lock then minetest.chat_send_player(pname, "Couple is locked (ask owner or admin to unlock it)") return false @@ -1028,11 +1039,11 @@ end function advtrains.get_wagon_prototype(data) local wt = data.type - if not minetest.registered_luaentities[wt] then + if not advtrains.wagon_prototypes[wt] then atprint("Unable to load wagon type",wt,", using placeholder") wt="advtrains:wagon_placeholder" end - return wt, minetest.registered_luaentities[wt] + return wt, advtrains.wagon_prototypes[wt] end function advtrains.register_wagon(sysname_p, prototype, desc, inv_img, nincreative) @@ -1042,6 +1053,7 @@ function advtrains.register_wagon(sysname_p, prototype, desc, inv_img, nincreati end setmetatable(prototype, {__index=wagon}) minetest.register_entity(":"..sysname,prototype) + advtrains.wagon_prototypes[sysname] = prototype minetest.register_craftitem(":"..sysname, { description = desc, @@ -1049,7 +1061,7 @@ function advtrains.register_wagon(sysname_p, prototype, desc, inv_img, nincreati wield_image = inv_img, stack_max = 1, - groups = { not_in_creative_inventory = nincreative and 0 or 1} + groups = { not_in_creative_inventory = nincreative and 1 or 0}, on_place = function(itemstack, placer, pointed_thing) return advtrains.pcall(function() @@ -1082,7 +1094,7 @@ function advtrains.register_wagon(sysname_p, prototype, desc, inv_img, nincreati return end - local wid = advtrains.create_wagon(type, pname) + local wid = advtrains.create_wagon(sysname, pname) local id=advtrains.create_new_train_at(pointed_thing.under, plconnid, 0, {wid}) @@ -1099,7 +1111,7 @@ end -- Placeholder wagon. Will be spawned whenever a mod is missing advtrains.register_wagon("advtrains:wagon_placeholder", { visual="sprite", - textures = {"advtrains_wheel.png"}, + textures = {"advtrains_wagon_placeholder.png"}, collisionbox = {-0.3,-0.3,-0.3, 0.3,0.3,0.3}, visual_size = {x=0.7, y=0.7}, initial_sprite_basepos = {x=0, y=0}, @@ -1112,5 +1124,5 @@ advtrains.register_wagon("advtrains:wagon_placeholder", { assign_to_seat_group = {}, wagon_span=1, drops={}, -}, "Wagon placeholder", "advtrains_subway_wagon_inv.png", true) +}, "Wagon placeholder", "advtrains_wagon_placeholder.png", true) -- cgit v1.2.3