aboutsummaryrefslogtreecommitdiff
path: root/advtrains/advtrains/nodedb.lua
diff options
context:
space:
mode:
Diffstat (limited to 'advtrains/advtrains/nodedb.lua')
-rw-r--r--advtrains/advtrains/nodedb.lua232
1 files changed, 232 insertions, 0 deletions
diff --git a/advtrains/advtrains/nodedb.lua b/advtrains/advtrains/nodedb.lua
new file mode 100644
index 0000000..0e1d836
--- /dev/null
+++ b/advtrains/advtrains/nodedb.lua
@@ -0,0 +1,232 @@
+--nodedb.lua
+--database of all nodes that have 'save_in_nodedb' field set to true in node definition
+
+
+
+--serialization format:
+--(6byte poshash) (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 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 t={string.byte(bytes,1,-1)}
+ local n =
+ t[1] * 256 +
+ t[2]
+ return n
+end
+local function l2b(x)
+ return x%4
+end
+local function u14b(x)
+ return math.floor(x/4)
+end
+local ndb={}
+
+--local variables for performance
+local ndb_nodeids={}
+local ndb_nodes={}
+
+--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 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 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)
+ cnt=cnt+1
+ hst=file:read(6)
+ cid=file:read(2)
+ end
+ atprint("nodedb: read", cnt, "nodes.")
+ file:close()
+end
+
+--save
+function ndb.save_data()
+ local file, err = io.open(path, "w")
+ if not file then
+ atprint("load 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))
+ end
+ file:close()
+ end
+ return {nodeids = ndb_nodeids}
+end
+
+--function to get node. track database is not helpful here.
+function ndb.get_node_or_nil(pos)
+ local node=minetest.get_node_or_nil(pos)
+ if node then
+ return node
+ else
+ --maybe we have the node in the database...
+ local cid=ndb_nodes[minetest.hash_node_position(pos)]
+ if cid then
+ local nodeid = ndb_nodeids[u14b(cid)]
+ if nodeid then
+ --atprint("ndb.get_node_or_nil",pos,"found node",nodeid,"cid",cid,"par2",l2b(cid))
+ return {name=nodeid, param2 = l2b(cid)}
+ end
+ end
+ end
+ atprint("ndb.get_node_or_nil",pos,"not found")
+end
+function ndb.get_node(pos)
+ local n=ndb.get_node_or_nil(pos)
+ if not n then
+ return {name="ignore", param2=0}
+ end
+ return n
+end
+
+function ndb.swap_node(pos, node)
+ minetest.swap_node(pos, node)
+ ndb.update(pos, node)
+end
+
+function ndb.update(pos, pnode)
+ local node = pnode or minetest.get_node_or_nil(pos)
+ if not node or node.name=="ignore" then return end
+ if minetest.registered_nodes[node.name] and minetest.registered_nodes[node.name].groups.save_in_nodedb then
+ local nid
+ for tnid, nname in pairs(ndb_nodeids) do
+ if nname==node.name then
+ nid=tnid
+ end
+ end
+ if not nid then
+ 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))
+ --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
+ end
+end
+
+function ndb.clear(pos)
+ local hash = minetest.hash_node_position(pos)
+ ndb_nodes[hash] = nil
+end
+
+
+--get_node with pseudoload. now we only need track data, so we can use the trackdb as second fallback
+--nothing new will be saved inside the trackdb.
+--returns:
+--true, conn1, conn2, rely1, rely2, railheight in case everything's right.
+--false if it's not a rail or the train does not drive on this rail, but it is loaded or
+--nil if the node is neither loaded nor in trackdb
+--the distraction between false and nil will be needed only in special cases.(train initpos)
+function advtrains.get_rail_info_at(pos, drives_on)
+ local rdp=advtrains.round_vector_floor_y(pos)
+
+ local node=ndb.get_node_or_nil(rdp)
+
+ --still no node?
+ --advtrains.trackdb is nil when there's no data available.
+ if not node then
+ if advtrains.trackdb then
+ --try raildb (see trackdb_legacy.lua)
+ local dbe=(advtrains.trackdb[rdp.y] and advtrains.trackdb[rdp.y][rdp.x] and advtrains.trackdb[rdp.y][rdp.x][rdp.z])
+ if dbe then
+ for tt,_ in pairs(drives_on) do
+ if not dbe.tracktype or tt==dbe.tracktype then
+ return true, dbe.conn1, dbe.conn2, dbe.rely1 or 0, dbe.rely2 or 0, dbe.railheight or 0
+ end
+ end
+ end
+ end
+ return nil
+ end
+ local nodename=node.name
+ if(not advtrains.is_track_and_drives_on(nodename, drives_on)) then
+ return false
+ end
+ local conn1, conn2, rely1, rely2, railheight, tracktype=advtrains.get_track_connections(node.name, node.param2)
+
+ return true, conn1, conn2, rely1, rely2, railheight
+end
+
+
+minetest.register_abm({
+ name = "advtrains:nodedb_on_load_update",
+ nodenames = {"group:save_in_nodedb"},
+ run_at_every_load = true,
+ action = function(pos, node)
+ local cid=ndb_nodes[minetest.hash_node_position(pos)]
+ if cid then
+ --if in database, detect changes and apply.
+ local nodeid = ndb_nodeids[u14b(cid)]
+ local param2 = l2b(cid)
+ if not nodeid then
+ --something went wrong
+ atprint("nodedb: lbm nid not found", pos, "with nid", u14b(cid), "param2", param2, "cid is", cid)
+ ndb.update(pos, node)
+ else
+ if (nodeid~=node.name or param2~=node.param2) then
+ atprint("nodedb: lbm replaced", pos, "with nodeid", nodeid, "param2", param2, "cid is", cid)
+ minetest.swap_node(pos, {name=nodeid, param2 = param2})
+ end
+ end
+ else
+ --if not in database, take it.
+ atprint("nodedb: ", pos, "not in database")
+ ndb.update(pos, node)
+ end
+ end,
+ interval=10,
+ chance=1,
+ })
+
+minetest.register_on_dignode(function(pos, oldnode, digger)
+ ndb.clear(pos)
+end)
+
+function ndb.t()
+ return ndb_nodes[141061759008906]
+end
+
+advtrains.ndb=ndb
+