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.
master
orwell96 2017-02-03 20:40:30 +01:00
parent a72dda17be
commit 328d5054a1
7 changed files with 91 additions and 76 deletions

View File

@ -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)

View File

@ -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)]

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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,

View File

@ -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)