123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240 |
- --nodedb.lua
- --database of all nodes that have 'save_in_at_nodedb' field set to true in node definition
- ndb_nodes_notrack = 0
- --serialization format:
- --(2byte z) (2byte y) (2byte x) (2byte contentid)
- --contentid := (14bit nodeid, 2bit param2)
- 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_int(bytes)
- local t={string.byte(bytes,1,-1)}
- local n =
- t[1] * 256 +
- t[2]
- return n-32768
- 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={}
- local ndb_ver
- 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/save
- local path_pre_v4=datapath.."advtrains_ndb2"
- --load pre_v4 format
- --nodeids get loaded by advtrains init.lua and passed here
- function ndb.load_data_pre_v4(data)
- print("nodedb: Loading pre v4 format")
- ndb_nodeids = data and data.nodeids or {}
- ndb_ver = data and data.ver or 0
- if ndb_ver < 1 then
- for k,v in pairs(ndb_nodeids) do
- if v == "advtrains:dtrack_xing4590_st" then
- cidDepr = k
- elseif v == "advtrains:dtrack_xing90plusx_45l" then
- cidNew = k
- end
- end
- end
- local file, err = io.open(path_pre_v4, "rb")
- if not file then
- print("Couldn't load the node database: ", err or "Unknown Error")
- else
- -- Note: code duplication because of weird coordinate order in ndb2 format (z,y,x)
- local cnt=0
- 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_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
- if (ndb_ver < 1 and cid == cidDepr) then
- cid = cidNew
- end
- ndbset(bytes_to_int(hst_x), bytes_to_int(hst_y), bytes_to_int(hst_z), bytes_to_int(cid))
- cnt=cnt+1
- hst_z=file:read(2)
- hst_y=file:read(2)
- hst_x=file:read(2)
- cid=file:read(2)
- end
- print("nodedb (ndb2 format): read", cnt, "nodes.")
- ndb_nodes_total = cnt
- file:close()
- end
- ndb_ver = 1
- end
- -- the new ndb file format is backported from cellworld, and stores the cids also in the ndb file.
- -- These functions have the form of a serialize_lib atomic load/save callback and are called from avt_save/avt_load.
- function ndb.load_callback(file)
- -- read version
- local vers_byte = file:read(1)
- local version = string.byte(vers_byte)
- if version~=1 then
- file:close()
- error("Doesn't support v4 nodedb file of version "..version)
- end
-
- -- read cid mappings
- local nstr_byte = file:read(2)
- local nstr = bytes_to_int(nstr_byte)
- for i = 1,nstr do
- local stid_byte = file:read(2)
- local stid = bytes_to_int(stid_byte)
- local stna = file:read("*l")
- --atdebug("content id:", stid, "->", stna)
- ndb_nodeids[stid] = stna
- end
- print("[nodedb] read", nstr, "node content ids.")
- -- read nodes
- local cnt=0
- local hst_x=file:read(2)
- local hst_y=file:read(2)
- local hst_z=file:read(2)
- local cid=file:read(2)
- local cidi
- 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
- cidi = bytes_to_int(cid)
- -- prevent file corruption already here
- if not ndb_nodeids[u14b(cidi)] then
- -- clear the ndb data, to reinitialize it
- -- in strict loading mode, doesn't matter as starting will be interrupted anyway
- ndb_nodeids = {}
- ndb_nodes = {}
- error("NDB file is corrupted (found entry with invalid cid)")
- end
- ndbset(bytes_to_int(hst_x), bytes_to_int(hst_y), bytes_to_int(hst_z), cidi)
- cnt=cnt+1
- hst_x=file:read(2)
- hst_y=file:read(2)
- hst_z=file:read(2)
- cid=file:read(2)
- end
- print("[nodedb] read", cnt, "nodes.")
- ndb_nodes_total = cnt
- file:close()
- end
- --function to get node. track database is not helpful here.
- function ndb.get_node_or_nil(pos)
- -- FIX for bug found on linuxworks server:
- -- a loaded node might get read before the LBM has updated its state, resulting in wrongly set signals and switches
- -- -> Using the saved node prioritarily.
- local node = ndb.get_node_raw(pos)
- if node then
- return node
- else
- -- no minetest here
- return nil
- end
- 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.get_node_raw(pos)
- local cid=ndbget(pos.x, pos.y, pos.z)
- if cid then
- local nodeid = ndb_nodeids[u14b(cid)]
- if nodeid then
- return {name=nodeid, param2 = l2b(cid)}
- end
- end
- return nil
- end
- function ndb.clear(pos)
- ndbset(pos.x, pos.y, pos.z, 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)
- advtrains = advtrains or {}
- function advtrains.get_rail_info_at(pos)
- local rdp=advtrains.round_vector_floor_y(pos)
-
- local node=ndb.get_node_or_nil(rdp)
- if not node then return end
-
- local nodename=node.name
-
- local conns, railheight, tracktype=advtrains.get_track_connections(node.name, node.param2)
-
- if not conns then
- return false
- end
-
- return true, conns, railheight
- end
- -- mapper-specific
- function ndb.mapper_find_starting_point()
- for y, ty in pairs(ndb_nodes) do
- for x, tx in pairs(ty) do
- for z, v in pairs(tx) do
- local pos = {x=x, y=y, z=z}
- local node_ok, conns, _ = advtrains.get_rail_info_at(pos)
- if node_ok then
- return pos, conns
- else
- -- this is a signal or something similar, ignore.
- tx[z]=nil
- ndb_nodes_notrack = ndb_nodes_notrack + 1
- end
- end
- end
- end
- end
- advtrains.ndb = ndb
|