From 328d5054a105869c7e12df1941ceedb308ef1faa Mon Sep 17 00:00:00 2001 From: orwell96 Date: Fri, 3 Feb 2017 20:40:30 +0100 Subject: Revert change to node pos hashes, and rewrite trackdb to use individual coordinates The precision of integers was not sufficient for saving pos node hashes in most cases, leading to strange bugs. This fixes broken ATC rails, broken LuaAutomation stuff and trackdb on Windows. Probably also fixes trains randomly stopping. --- advtrains/advtrains/atc.lua | 21 +++-- advtrains/advtrains/nodedb.lua | 92 ++++++++++++---------- advtrains/advtrains/tracks.lua | 13 ++- advtrains/advtrains/trainlogic.lua | 8 +- .../advtrains_luaautomation/active_common.lua | 14 ++-- advtrains/advtrains_luaautomation/atc_rail.lua | 12 ++- advtrains/advtrains_luaautomation/init.lua | 7 +- 7 files changed, 91 insertions(+), 76 deletions(-) diff --git a/advtrains/advtrains/atc.lua b/advtrains/advtrains/atc.lua index 85c62d8..609857b 100644 --- a/advtrains/advtrains/atc.lua +++ b/advtrains/advtrains/atc.lua @@ -8,8 +8,8 @@ function atc.load_data(data) local temp = data and data.controllers or {} --transcode atc controller data to node hashes: table access times for numbers are far less than for strings for pts, data in pairs(temp) do - if type(pts)=="string" then - pts=minetest.hash_node_position(minetest.string_to_pos(pts)) + if type(pts)=="number" then + pts=minetest.pos_to_string(minetest.get_position_from_hash(pts)) end atc.controllers[pts] = data end @@ -19,16 +19,10 @@ function atc.save_data() end --contents: {command="...", arrowconn=0-15 where arrow points} ---call from advtrains.detector subprogram - -function atc.trigger_controller_train_enter(pos, train_id) - atc.send_command(pos) -end - --general function atc.send_command(pos) - local pts=minetest.hash_node_position(pos) + local pts=minetest.pos_to_string(pos) if atc.controllers[pts] then --atprint("Called send_command at "..pts) local train_id = advtrains.detector.on_node[pts] @@ -88,7 +82,7 @@ advtrains.register_tracks("default", { after_dig_node=function(pos) advtrains.invalidate_all_paths() advtrains.ndb.clear(pos) - local pts=minetest.hash_node_position(pos) + local pts=minetest.pos_to_string(pos) atc.controllers[pts]=nil end, on_receive_fields = function(pos, formname, fields, player) @@ -122,12 +116,17 @@ advtrains.register_tracks("default", { end meta:set_string("formspec", atc.get_atc_controller_formspec(pos, meta)) - local pts=minetest.hash_node_position(pos) + local pts=minetest.pos_to_string(pos) local _, conn1=advtrains.get_rail_info_at(pos, advtrains.all_tracktypes) atc.controllers[pts]={command=fields.command, arrowconn=conn1} atc.send_command(pos) end end, + advtrains = { + on_train_enter = function(pos, train_id) + atc.send_command(pos) + end, + }, } end }, advtrains.trackpresets.t_30deg_straightonly) diff --git a/advtrains/advtrains/nodedb.lua b/advtrains/advtrains/nodedb.lua index e3ed56d..ddd1a67 100644 --- a/advtrains/advtrains/nodedb.lua +++ b/advtrains/advtrains/nodedb.lua @@ -2,42 +2,22 @@ --database of all nodes that have 'save_in_nodedb' field set to true in node definition - --serialization format: ---(6byte poshash) (2byte contentid) +--(2byte z) (2byte y) (2byte x) (2byte contentid) --contentid := (14bit nodeid, 2bit param2) -local function hash_to_bytes(x) - local aH = math.floor(x / 1099511627776) % 256; - local aL = math.floor(x / 4294967296) % 256; - local bH = math.floor(x / 16777216) % 256; - local bL = math.floor(x / 65536) % 256; - local cH = math.floor(x / 256) % 256; - local cL = math.floor(x ) % 256; - return(string.char(aH, aL, bH, bL, cH, cL)); -end -local function cid_to_bytes(x) +local function int_to_bytes(i) + local x=i+32768--clip to positive integers local cH = math.floor(x / 256) % 256; local cL = math.floor(x ) % 256; return(string.char(cH, cL)); end -local function bytes_to_hash(bytes) - local t={string.byte(bytes,1,-1)} - local n = - t[1] * 1099511627776 + - t[2] * 4294967296 + - t[3] * 16777216 + - t[4] * 65536 + - t[5] * 256 + - t[6] - return n -end -local function bytes_to_cid(bytes) +local function bytes_to_int(bytes) local t={string.byte(bytes,1,-1)} local n = t[1] * 256 + t[2] - return n + return n-32768 end local function l2b(x) return x%4 @@ -51,25 +31,50 @@ local ndb={} local ndb_nodeids={} local ndb_nodes={} +local function ndbget(x,y,z) + local ny=ndb_nodes[y] + if ny then + local nx=ny[x] + if nx then + return nx[z] + end + end + return nil +end +local function ndbset(x,y,z,v) + if not ndb_nodes[y] then + ndb_nodes[y]={} + end + if not ndb_nodes[y][x] then + ndb_nodes[y][x]={} + end + ndb_nodes[y][x][z]=v +end + + --load --nodeids get loaded by advtrains init.lua and passed here function ndb.load_data(data) ndb_nodeids = data and data.nodeids or {} end -local path=minetest.get_worldpath().."/advtrains_ndb" +local path=minetest.get_worldpath().."/advtrains_ndb2" local file, err = io.open(path, "r") if not file then atprint("load ndb failed: ", err or "Unknown Error") else local cnt=0 - local hst=file:read(6) + local hst_z=file:read(2) + local hst_y=file:read(2) + local hst_x=file:read(2) local cid=file:read(2) - while hst and #hst==6 and cid and #cid==2 do - ndb_nodes[bytes_to_hash(hst)]=bytes_to_cid(cid) + while hst_z and hst_y and hst_x and cid and #hst_z==2 and #hst_y==2 and #hst_x==2 and #cid==2 do + ndbset(bytes_to_int(hst_x), bytes_to_int(hst_y), bytes_to_int(hst_z), bytes_to_int(cid)) cnt=cnt+1 - hst=file:read(6) + hst_z=file:read(2) + hst_y=file:read(2) + hst_x=file:read(2) cid=file:read(2) end atprint("nodedb: read", cnt, "nodes.") @@ -80,11 +85,17 @@ end function ndb.save_data() local file, err = io.open(path, "w") if not file then - atprint("load ndb failed: ", err or "Unknown Error") + atprint("save ndb failed: ", err or "Unknown Error") else - for hash, cid in pairs(ndb_nodes) do - file:write(hash_to_bytes(hash)) - file:write(cid_to_bytes(cid)) + for y, ny in pairs(ndb_nodes) do + for x, nx in pairs(ny) do + for z, cid in pairs(nx) do + file:write(int_to_bytes(z)) + file:write(int_to_bytes(y)) + file:write(int_to_bytes(x)) + file:write(int_to_bytes(cid)) + end + end end file:close() end @@ -98,7 +109,7 @@ function ndb.get_node_or_nil(pos) return node else --maybe we have the node in the database... - local cid=ndb_nodes[minetest.hash_node_position(pos)] + local cid=ndbget(pos.x, pos.y, pos.z) if cid then local nodeid = ndb_nodeids[u14b(cid)] if nodeid then @@ -136,19 +147,16 @@ function ndb.update(pos, pnode) nid=#ndb_nodeids+1 ndb_nodeids[nid]=node.name end - local hash = minetest.hash_node_position(pos) - ndb_nodes[hash] = (nid * 4) + (l2b(node.param2 or 0)) + ndbset(pos.x, pos.y, pos.z, (nid * 4) + (l2b(node.param2 or 0)) ) --atprint("nodedb: updating node", pos, "stored nid",nid,"assigned",ndb_nodeids[nid],"resulting cid",ndb_nodes[hash]) else --at this position there is no longer a node that needs to be tracked. - local hash = minetest.hash_node_position(pos) - ndb_nodes[hash] = nil + ndbset(pos.x, pos.y, pos.z, nil) end end function ndb.clear(pos) - local hash = minetest.hash_node_position(pos) - ndb_nodes[hash] = nil + ndbset(pos.x, pos.y, pos.z, nil) end @@ -195,7 +203,7 @@ minetest.register_abm({ nodenames = {"group:save_in_nodedb"}, run_at_every_load = true, action = function(pos, node) - local cid=ndb_nodes[minetest.hash_node_position(pos)] + local cid=ndbget(pos.x, pos.y, pos.z) if cid then --if in database, detect changes and apply. local nodeid = ndb_nodeids[u14b(cid)] diff --git a/advtrains/advtrains/tracks.lua b/advtrains/advtrains/tracks.lua index a63ff4d..c5ab436 100644 --- a/advtrains/advtrains/tracks.lua +++ b/advtrains/advtrains/tracks.lua @@ -413,19 +413,19 @@ advtrains.detector.on_node = {} function advtrains.detector.enter_node(pos, train_id) local ppos=advtrains.round_vector_floor_y(pos) - local pts=minetest.hash_node_position(ppos) + local pts=minetest.pos_to_string(ppos) advtrains.detector.on_node[pts]=train_id 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.hash_node_position(ppos) + local pts=minetest.pos_to_string(ppos) advtrains.detector.on_node[pts]=nil 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.hash_node_position(ppos) + local pts=minetest.pos_to_string(ppos) advtrains.detector.on_node[pts]=train_id end @@ -434,19 +434,16 @@ end function advtrains.detector.call_enter_callback(pos, train_id) --atprint("instructed to call enter calback") - local node = minetest.get_node(pos) --this spares the check if node is nil, it has a name in any case + 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 - - --atc code wants to be notified too - advtrains.atc.trigger_controller_train_enter(pos, train_id) end function advtrains.detector.call_leave_callback(pos, train_id) --atprint("instructed to call leave calback") - local node = minetest.get_node(pos) --this spares the check if node is nil, it has a name in any case + 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) diff --git a/advtrains/advtrains/trainlogic.lua b/advtrains/advtrains/trainlogic.lua index f28528f..4b5edf5 100644 --- a/advtrains/advtrains/trainlogic.lua +++ b/advtrains/advtrains/trainlogic.lua @@ -258,8 +258,8 @@ function advtrains.train_step_a(id, train, dtime) --- 5. extend path as necessary --- - local gen_front=math.max(train.index, train.detector_old_index) + 2 - local gen_back=math.min(train.end_index, train.detector_old_end_index) - 2 + local gen_front=math.max(train.index, train.detector_old_index) + 10 + local gen_back=math.min(train.end_index, train.detector_old_end_index) - 10 local maxn=train.path_extent_max or 0 while maxn < gen_front do--pregenerate @@ -404,7 +404,7 @@ function advtrains.train_step_b(id, train, dtime) for x=-1,1 do for z=-1,1 do local testpos=vector.add(rcollpos, {x=x, y=0, z=z}) - local testpts=minetest.hash_node_position(testpos) + local testpts=minetest.pos_to_string(testpos) if advtrains.detector.on_node[testpts] and advtrains.detector.on_node[testpts]~=id then --collides advtrains.spawn_couple_on_collide(id, testpos, advtrains.detector.on_node[testpts], train.movedir==-1) @@ -755,7 +755,7 @@ function advtrains.invert_train(train_id) end function advtrains.get_train_at_pos(pos) - local ph=minetest.hash_node_position(advtrains.round_vector_floor_y(pos)) + local ph=minetest.pos_to_string(advtrains.round_vector_floor_y(pos)) return advtrains.detector.on_node[ph] end diff --git a/advtrains/advtrains_luaautomation/active_common.lua b/advtrains/advtrains_luaautomation/active_common.lua index 474838e..50a5051 100644 --- a/advtrains/advtrains_luaautomation/active_common.lua +++ b/advtrains/advtrains_luaautomation/active_common.lua @@ -3,7 +3,9 @@ local ac = {nodes={}} function ac.load(data) - ac.nodes=data and data.nodes or {} + if data then + ac.nodes=data.nodes + end end function ac.save() return {nodes = ac.nodes} @@ -14,7 +16,7 @@ function ac.after_place_node(pos, player) local meta=minetest.get_meta(pos) meta:set_string("formspec", ac.getform(pos, meta)) meta:set_string("infotext", "LuaAutomation component, unconfigured.") - local ph=minetest.hash_node_position(pos) + local ph=minetest.pos_to_string(pos) --just get first available key! for en,_ in pairs(atlatc.envs) do ac.nodes[ph]={env=en} @@ -25,7 +27,7 @@ function ac.getform(pos, meta_p) local meta = meta_p or minetest.get_meta(pos) local envs_asvalues={} - local ph=minetest.hash_node_position(pos) + local ph=minetest.pos_to_string(pos) local nodetbl = ac.nodes[ph] local env, code, err = nil, "", "" if nodetbl then @@ -49,7 +51,7 @@ end function ac.after_dig_node(pos, node, player) advtrains.invalidate_all_paths() advtrains.ndb.clear(pos) - local ph=minetest.hash_node_position(pos) + local ph=minetest.pos_to_string(pos) ac.nodes[ph]=nil end @@ -59,7 +61,7 @@ function ac.on_receive_fields(pos, formname, fields, player) end local meta=minetest.get_meta(pos) - local ph=minetest.hash_node_position(pos) + local ph=minetest.pos_to_string(pos) local nodetbl = ac.nodes[ph] or {} --if fields.quit then return end if fields.env then @@ -85,7 +87,7 @@ function ac.on_receive_fields(pos, formname, fields, player) end function ac.run_in_env(pos, evtdata, customfct_p) - local ph=minetest.hash_node_position(pos) + local ph=minetest.pos_to_string(pos) local nodetbl = ac.nodes[ph] or {} local meta diff --git a/advtrains/advtrains_luaautomation/atc_rail.lua b/advtrains/advtrains_luaautomation/atc_rail.lua index b2a8aad..f52252c 100644 --- a/advtrains/advtrains_luaautomation/atc_rail.lua +++ b/advtrains/advtrains_luaautomation/atc_rail.lua @@ -7,8 +7,14 @@ local r={} function r.fire_event(pos, evtdata) - local ph=minetest.hash_node_position(pos) - local railtbl = atlatc.active.nodes[ph] or {} + local ph=minetest.pos_to_string(pos) + local railtbl = atlatc.active.nodes[ph] + + if not railtbl then + atprint("missing rail table entry!") + return + end + local arrowconn = railtbl.arrowconn @@ -70,7 +76,7 @@ advtrains.register_tracks("default", { atlatc.active.on_receive_fields(pos, ...) --set arrowconn (for ATC) - local ph=minetest.hash_node_position(pos) + local ph=minetest.pos_to_string(pos) local _, conn1=advtrains.get_rail_info_at(pos, advtrains.all_tracktypes) atlatc.active.nodes[ph].arrowconn=conn1 end, diff --git a/advtrains/advtrains_luaautomation/init.lua b/advtrains/advtrains_luaautomation/init.lua index 37e5714..d88944f 100644 --- a/advtrains/advtrains_luaautomation/init.lua +++ b/advtrains/advtrains_luaautomation/init.lua @@ -25,7 +25,9 @@ dofile(mp.."/interrupt.lua") dofile(mp.."/active_common.lua") dofile(mp.."/atc_rail.lua") dofile(mp.."/operation_panel.lua") -dofile(mp.."/p_mesecon_iface.lua") +if mesecon then + dofile(mp.."/p_mesecon_iface.lua") +end dofile(mp.."/chatcmds.lua") @@ -34,8 +36,10 @@ local file, err = io.open(filename, "r") if not file then minetest.log("error", " Failed to read advtrains_luaautomation save data from file "..filename..": "..(err or "Unknown Error")) else + atprint("luaautomation reading file:",filename) local tbl = minetest.deserialize(file:read("*a")) if type(tbl) == "table" then + atprint(tbl) if tbl.version==1 then for envname, data in pairs(tbl.envs) do atlatc.envs[envname]=atlatc.env_load(envname, data) @@ -97,4 +101,3 @@ minetest.register_globalstep(function(dtime) atlatc.save() end end) -minetest.register_on_shutdown(atlatc.save) -- cgit v1.2.3