nodedb.lua 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. --nodedb.lua
  2. --database of all nodes that have 'save_in_at_nodedb' field set to true in node definition
  3. ndb_nodes_notrack = 0
  4. --serialization format:
  5. --(2byte z) (2byte y) (2byte x) (2byte contentid)
  6. --contentid := (14bit nodeid, 2bit param2)
  7. local function int_to_bytes(i)
  8. local x=i+32768--clip to positive integers
  9. local cH = math.floor(x / 256) % 256;
  10. local cL = math.floor(x ) % 256;
  11. return(string.char(cH, cL));
  12. end
  13. local function bytes_to_int(bytes)
  14. local t={string.byte(bytes,1,-1)}
  15. local n =
  16. t[1] * 256 +
  17. t[2]
  18. return n-32768
  19. end
  20. local function l2b(x)
  21. return x%4
  22. end
  23. local function u14b(x)
  24. return math.floor(x/4)
  25. end
  26. local ndb={}
  27. --local variables for performance
  28. local ndb_nodeids={}
  29. local ndb_nodes={}
  30. local ndb_ver
  31. local function ndbget(x,y,z)
  32. local ny=ndb_nodes[y]
  33. if ny then
  34. local nx=ny[x]
  35. if nx then
  36. return nx[z]
  37. end
  38. end
  39. return nil
  40. end
  41. local function ndbset(x,y,z,v)
  42. if not ndb_nodes[y] then
  43. ndb_nodes[y]={}
  44. end
  45. if not ndb_nodes[y][x] then
  46. ndb_nodes[y][x]={}
  47. end
  48. ndb_nodes[y][x][z]=v
  49. end
  50. -- load/save
  51. local path_pre_v4=datapath.."advtrains_ndb2"
  52. --load pre_v4 format
  53. --nodeids get loaded by advtrains init.lua and passed here
  54. function ndb.load_data_pre_v4(data)
  55. print("nodedb: Loading pre v4 format")
  56. ndb_nodeids = data and data.nodeids or {}
  57. ndb_ver = data and data.ver or 0
  58. if ndb_ver < 1 then
  59. for k,v in pairs(ndb_nodeids) do
  60. if v == "advtrains:dtrack_xing4590_st" then
  61. cidDepr = k
  62. elseif v == "advtrains:dtrack_xing90plusx_45l" then
  63. cidNew = k
  64. end
  65. end
  66. end
  67. local file, err = io.open(path_pre_v4, "rb")
  68. if not file then
  69. print("Couldn't load the node database: ", err or "Unknown Error")
  70. else
  71. -- Note: code duplication because of weird coordinate order in ndb2 format (z,y,x)
  72. local cnt=0
  73. local hst_z=file:read(2)
  74. local hst_y=file:read(2)
  75. local hst_x=file:read(2)
  76. local cid=file:read(2)
  77. 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
  78. if (ndb_ver < 1 and cid == cidDepr) then
  79. cid = cidNew
  80. end
  81. ndbset(bytes_to_int(hst_x), bytes_to_int(hst_y), bytes_to_int(hst_z), bytes_to_int(cid))
  82. cnt=cnt+1
  83. hst_z=file:read(2)
  84. hst_y=file:read(2)
  85. hst_x=file:read(2)
  86. cid=file:read(2)
  87. end
  88. print("nodedb (ndb2 format): read", cnt, "nodes.")
  89. ndb_nodes_total = cnt
  90. file:close()
  91. end
  92. ndb_ver = 1
  93. end
  94. -- the new ndb file format is backported from cellworld, and stores the cids also in the ndb file.
  95. -- These functions have the form of a serialize_lib atomic load/save callback and are called from avt_save/avt_load.
  96. function ndb.load_callback(file)
  97. -- read version
  98. local vers_byte = file:read(1)
  99. local version = string.byte(vers_byte)
  100. if version~=1 then
  101. file:close()
  102. error("Doesn't support v4 nodedb file of version "..version)
  103. end
  104. -- read cid mappings
  105. local nstr_byte = file:read(2)
  106. local nstr = bytes_to_int(nstr_byte)
  107. for i = 1,nstr do
  108. local stid_byte = file:read(2)
  109. local stid = bytes_to_int(stid_byte)
  110. local stna = file:read("*l")
  111. --atdebug("content id:", stid, "->", stna)
  112. ndb_nodeids[stid] = stna
  113. end
  114. print("[nodedb] read", nstr, "node content ids.")
  115. -- read nodes
  116. local cnt=0
  117. local hst_x=file:read(2)
  118. local hst_y=file:read(2)
  119. local hst_z=file:read(2)
  120. local cid=file:read(2)
  121. local cidi
  122. 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
  123. cidi = bytes_to_int(cid)
  124. -- prevent file corruption already here
  125. if not ndb_nodeids[u14b(cidi)] then
  126. -- clear the ndb data, to reinitialize it
  127. -- in strict loading mode, doesn't matter as starting will be interrupted anyway
  128. ndb_nodeids = {}
  129. ndb_nodes = {}
  130. error("NDB file is corrupted (found entry with invalid cid)")
  131. end
  132. ndbset(bytes_to_int(hst_x), bytes_to_int(hst_y), bytes_to_int(hst_z), cidi)
  133. cnt=cnt+1
  134. hst_x=file:read(2)
  135. hst_y=file:read(2)
  136. hst_z=file:read(2)
  137. cid=file:read(2)
  138. end
  139. print("[nodedb] read", cnt, "nodes.")
  140. ndb_nodes_total = cnt
  141. file:close()
  142. end
  143. --function to get node. track database is not helpful here.
  144. function ndb.get_node_or_nil(pos)
  145. -- FIX for bug found on linuxworks server:
  146. -- a loaded node might get read before the LBM has updated its state, resulting in wrongly set signals and switches
  147. -- -> Using the saved node prioritarily.
  148. local node = ndb.get_node_raw(pos)
  149. if node then
  150. return node
  151. else
  152. -- no minetest here
  153. return nil
  154. end
  155. end
  156. function ndb.get_node(pos)
  157. local n=ndb.get_node_or_nil(pos)
  158. if not n then
  159. return {name="ignore", param2=0}
  160. end
  161. return n
  162. end
  163. function ndb.get_node_raw(pos)
  164. local cid=ndbget(pos.x, pos.y, pos.z)
  165. if cid then
  166. local nodeid = ndb_nodeids[u14b(cid)]
  167. if nodeid then
  168. return {name=nodeid, param2 = l2b(cid)}
  169. end
  170. end
  171. return nil
  172. end
  173. function ndb.clear(pos)
  174. ndbset(pos.x, pos.y, pos.z, nil)
  175. end
  176. --get_node with pseudoload. now we only need track data, so we can use the trackdb as second fallback
  177. --nothing new will be saved inside the trackdb.
  178. --returns:
  179. --true, conn1, conn2, rely1, rely2, railheight in case everything's right.
  180. --false if it's not a rail or the train does not drive on this rail, but it is loaded or
  181. --nil if the node is neither loaded nor in trackdb
  182. --the distraction between false and nil will be needed only in special cases.(train initpos)
  183. advtrains = advtrains or {}
  184. function advtrains.get_rail_info_at(pos)
  185. local rdp=advtrains.round_vector_floor_y(pos)
  186. local node=ndb.get_node_or_nil(rdp)
  187. if not node then return end
  188. local nodename=node.name
  189. local conns, railheight, tracktype=advtrains.get_track_connections(node.name, node.param2)
  190. if not conns then
  191. return false
  192. end
  193. return true, conns, railheight
  194. end
  195. -- mapper-specific
  196. function ndb.mapper_find_starting_point()
  197. for y, ty in pairs(ndb_nodes) do
  198. for x, tx in pairs(ty) do
  199. for z, v in pairs(tx) do
  200. local pos = {x=x, y=y, z=z}
  201. local node_ok, conns, _ = advtrains.get_rail_info_at(pos)
  202. if node_ok then
  203. return pos, conns
  204. else
  205. -- this is a signal or something similar, ignore.
  206. tx[z]=nil
  207. ndb_nodes_notrack = ndb_nodes_notrack + 1
  208. end
  209. end
  210. end
  211. end
  212. end
  213. advtrains.ndb = ndb