From b649ea5fe4c9a7bc9b2b318fec97e5abe470fa9b Mon Sep 17 00:00:00 2001 From: orwell96 Date: Mon, 16 Jan 2017 20:07:04 +0100 Subject: replace trackdb by nodedb - trackdb is kept for large rail networks to still work but not saved anymore - saving node name and param2 instead of track connections, so also signals can be saved. - small serialization format - fast access times, almost no redundancy --- advtrains/advtrains/atc.lua | 15 ++- advtrains/advtrains/debugitems.lua | 10 +- advtrains/advtrains/init.lua | 41 +++--- advtrains/advtrains/lua_atc.lua | 166 +++++++++++++++++++++++ advtrains/advtrains/nodedb.lua | 232 +++++++++++++++++++++++++++++++++ advtrains/advtrains/pseudoload.lua | 180 ------------------------- advtrains/advtrains/signals.lua | 6 +- advtrains/advtrains/trackdb_legacy.lua | 27 ++++ advtrains/advtrains/trackplacer.lua | 16 +-- advtrains/advtrains/tracks.lua | 32 ++--- 10 files changed, 484 insertions(+), 241 deletions(-) create mode 100644 advtrains/advtrains/lua_atc.lua create mode 100644 advtrains/advtrains/nodedb.lua delete mode 100644 advtrains/advtrains/pseudoload.lua create mode 100644 advtrains/advtrains/trackdb_legacy.lua diff --git a/advtrains/advtrains/atc.lua b/advtrains/advtrains/atc.lua index e015d47..ece7075 100644 --- a/advtrains/advtrains/atc.lua +++ b/advtrains/advtrains/atc.lua @@ -3,7 +3,13 @@ local atc={} -- ATC persistence table. advtrains.atc is created by init.lua when it loads the save file. -atc.controllers = advtrains.atc.controllers +atc.controllers = {} +function atc.load_data(data) + atc.controllers = data and data.controllers or {} +end +function atc.save_data() + return atc.controllers +end --contents: {command="...", arrowconn=0-15 where arrow points} --call from advtrains.detector subprogram @@ -52,8 +58,8 @@ end --nodes local idxtrans={static=1, mesecon=2, digiline=3} -local apn_func=function(pos) - advtrains.reset_trackdb_position(pos) +local apn_func=function(pos, node) + advtrains.ndb.update(pos, node) local meta=minetest.get_meta(pos) if meta then meta:set_string("infotext", "ATC controller, unconfigured.") @@ -72,10 +78,9 @@ advtrains.register_tracks("default", { get_additional_definiton = function(def, preset, suffix, rotation) return { after_place_node=apn_func, - on_place_rail=apn_func, after_dig_node=function(pos) advtrains.invalidate_all_paths() - advtrains.reset_trackdb_position(pos) + advtrains.ndb.clear(pos) local pts=minetest.pos_to_string(pos) atc.controllers[pts]=nil end, diff --git a/advtrains/advtrains/debugitems.lua b/advtrains/advtrains/debugitems.lua index b3164ff..dcc95d9 100644 --- a/advtrains/advtrains/debugitems.lua +++ b/advtrains/advtrains/debugitems.lua @@ -24,13 +24,5 @@ minetest.register_tool("advtrains:tunnelborer", end end end, ---[[ -^ default: nil -^ Function must return either nil if no item shall be removed from -inventory, or an itemstack to replace the original itemstack. -e.g. itemstack:take_item(); return itemstack -^ Otherwise, the function is free to do what it wants. -^ The default functions handle regular use cases. -]] } -) +) diff --git a/advtrains/advtrains/init.lua b/advtrains/advtrains/init.lua index 74201b5..c8c4b56 100644 --- a/advtrains/advtrains/init.lua +++ b/advtrains/advtrains/init.lua @@ -1,7 +1,6 @@ --advtrains ---create the base table structure. -advtrains={atc={controllers={}}, detector={}, trackplacer={}, trains={}, trackdb={}, wagon_save={}} +advtrains = {trains={}, wagon_save={}} advtrains.modpath = minetest.get_modpath("advtrains") @@ -57,7 +56,21 @@ advtrains.meseconrules = {x=0, y=-1, z=-1}, {x=0, y=-2, z=0}} +dofile(advtrains.modpath.."/trainlogic.lua") +dofile(advtrains.modpath.."/trainhud.lua") +dofile(advtrains.modpath.."/trackplacer.lua") +dofile(advtrains.modpath.."/tracks.lua") +dofile(advtrains.modpath.."/atc.lua") +dofile(advtrains.modpath.."/wagons.lua") +dofile(advtrains.modpath.."/trackdb_legacy.lua") +dofile(advtrains.modpath.."/nodedb.lua") +dofile(advtrains.modpath.."/couple.lua") +dofile(advtrains.modpath.."/damage.lua") + +dofile(advtrains.modpath.."/signals.lua") +dofile(advtrains.modpath.."/misc_nodes.lua") +dofile(advtrains.modpath.."/crafting.lua") --load/save @@ -70,9 +83,11 @@ else if type(tbl) == "table" then if tbl.version then --congrats, we have the new save format. - advtrains.atc.controllers = tbl.atc_controllers advtrains.trains = tbl.trains advtrains.wagon_save = tbl.wagon_save + advtrains.ndb.load_data(tbl.ndb) + advtrains.atc.load_data(tbl.atc) + --advtrains.latc.load_data(tbl.latc) else --oh no, its the old one... advtrains.trains=tbl @@ -110,7 +125,7 @@ else end advtrains.save = function() - atprint("saving") + --atprint("saving") advtrains.invalidate_all_paths() -- update wagon saves @@ -134,14 +149,15 @@ advtrains.save = function() data.discouple=nil end end - --atprint(dump(advtrains.wagon_save)) --versions: -- 1 - Initial new save format. local save_tbl={ trains = advtrains.trains, wagon_save = advtrains.wagon_save, - atc_controllers = advtrains.atc.controllers, + atc = advtrains.atc.save_data(), + --latc = advtrains.latc.save_data(), + ndb = advtrains.ndb.save_data(), version = 1, } local datastr = minetest.serialize(save_tbl) @@ -160,18 +176,5 @@ end minetest.register_on_shutdown(advtrains.save) -dofile(advtrains.modpath.."/trainlogic.lua") -dofile(advtrains.modpath.."/trainhud.lua") -dofile(advtrains.modpath.."/trackplacer.lua") -dofile(advtrains.modpath.."/tracks.lua") -dofile(advtrains.modpath.."/atc.lua") -dofile(advtrains.modpath.."/wagons.lua") -dofile(advtrains.modpath.."/pseudoload.lua") -dofile(advtrains.modpath.."/couple.lua") -dofile(advtrains.modpath.."/damage.lua") - -dofile(advtrains.modpath.."/signals.lua") -dofile(advtrains.modpath.."/misc_nodes.lua") -dofile(advtrains.modpath.."/crafting.lua") diff --git a/advtrains/advtrains/lua_atc.lua b/advtrains/advtrains/lua_atc.lua new file mode 100644 index 0000000..313d70d --- /dev/null +++ b/advtrains/advtrains/lua_atc.lua @@ -0,0 +1,166 @@ +------------- +--LUA ATC controllers + +local latc={} + +function latc.load_data(data) +end +function latc.save_data() + return stuff +end + +latc.data +latc.env_cdata +latc.init_code="" +latc.step_code="" + +advtrains.fpath_latc=minetest.get_worldpath().."/advtrains_latc" +local file, err = io.open(advtrains.fpath_atc, "r") +if not file then + local er=err or "Unknown Error" + atprint("Failed loading advtrains latc save file "..er) +else + local tbl = minetest.deserialize(file:read("*a")) + if type(tbl) == "table" then + atc.controllers=tbl.controllers + end + file:close() +end +function latc.save() + + local datastr = minetest.serialize({controllers = atc.controllers}) + if not datastr then + minetest.log("error", " Failed to serialize latc data!") + return + end + local file, err = io.open(advtrains.fpath_atc, "w") + if err then + return err + end + file:write(datastr) + file:close() +end + +--Privilege +--Only trusted players should be enabled to build stuff which can break the server. +--If I later decide to have multiple environments ('data' tables), I better store an owner for every controller for future reference. + +minetest.register_privilege("advtrains_lua_atc", { description = "Player can place and modify LUA ATC components. Grant with care! Allows to execute bad LUA code.", give_to_singleplayer = false, default= false }) + +--Environment +--Code from mesecons_luacontroller (credit goes to Jeija and mesecons contributors) + +local safe_globals = { + "assert", "error", "ipairs", "next", "pairs", "select", + "tonumber", "tostring", "type", "unpack", "_VERSION" +} +local function safe_print(param) + print(dump(param)) +end + +local function safe_date() + return(os.date("*t",os.time())) +end + +-- string.rep(str, n) with a high value for n can be used to DoS +-- the server. Therefore, limit max. length of generated string. +local function safe_string_rep(str, n) + if #str * n > mesecon.setting("luacontroller_string_rep_max", 64000) then + debug.sethook() -- Clear hook + error("string.rep: string length overflow", 2) + end + + return string.rep(str, n) +end + +-- string.find with a pattern can be used to DoS the server. +-- Therefore, limit string.find to patternless matching. +local function safe_string_find(...) + if (select(4, ...)) ~= true then + debug.sethook() -- Clear hook + error("string.find: 'plain' (fourth parameter) must always be true in a LuaController") + end + + return string.find(...) +end + +latc.static_env = { + print = safe_print, + string = { + byte = string.byte, + char = string.char, + format = string.format, + len = string.len, + lower = string.lower, + upper = string.upper, + rep = safe_string_rep, + reverse = string.reverse, + sub = string.sub, + find = safe_string_find, + }, + math = { + abs = math.abs, + acos = math.acos, + asin = math.asin, + atan = math.atan, + atan2 = math.atan2, + ceil = math.ceil, + cos = math.cos, + cosh = math.cosh, + deg = math.deg, + exp = math.exp, + floor = math.floor, + fmod = math.fmod, + frexp = math.frexp, + huge = math.huge, + ldexp = math.ldexp, + log = math.log, + log10 = math.log10, + max = math.max, + min = math.min, + modf = math.modf, + pi = math.pi, + pow = math.pow, + rad = math.rad, + random = math.random, + sin = math.sin, + sinh = math.sinh, + sqrt = math.sqrt, + tan = math.tan, + tanh = math.tanh, + }, + table = { + concat = table.concat, + insert = table.insert, + maxn = table.maxn, + remove = table.remove, + sort = table.sort, + }, + os = { + clock = os.clock, + difftime = os.difftime, + time = os.time, + datetable = safe_date, + }, +} +latc.static_env._G = env + +for _, name in pairs(safe_globals) do + latc.static_env[name] = _G[name] +end + + +--The environment all code calls get is a proxy table with a metatable. +--When an index is read: +-- Look in static_env +-- Look in volatile_env (user_written functions and userdata) +-- Look in saved_env (everything that's not a function or userdata) +--when an index is written: +-- If in static_env, do not allow +-- if function or userdata, volatile_env +-- if table, see below +-- else, save in saved_env + + + +advtrains.latc=latc 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 + diff --git a/advtrains/advtrains/pseudoload.lua b/advtrains/advtrains/pseudoload.lua deleted file mode 100644 index 818808d..0000000 --- a/advtrains/advtrains/pseudoload.lua +++ /dev/null @@ -1,180 +0,0 @@ ---pseudoload.lua ---responsible for keeping up a database of all rail nodes existant in the world, regardless of whether the mapchunk is loaded. - -advtrains.trackdb={} ---trackdb[tt][y][x][z]={conn1, conn2, rely1, rely2, railheight} ---serialization format: ---(2byte x)(2byte y)(2byte z)(4bits conn1, 4bits conn2)[(plain rely1)|(plain rely2)|(plain railheight)]\n ---[] may be missing if 0,0,0 - ---load initially - ---[[ TODO temporary outcomment - ---delayed since all traintypes need to be registered -minetest.after(0, function() - -for tt, _ in pairs(advtrains.all_traintypes) do - local pl_fpath=minetest.get_worldpath().."/advtrains_trackdb_"..tt - advtrains.trackdb[tt]={} - local file, err = io.open(pl_fpath, "r") - if not file then - local er=err or "Unknown Error" - atprint("Failed loading advtrains trackdb save file "..er) - else - --custom format to save memory - while true do - local xbytes=file:read(2) - if not xbytes or #xbytes<2 then - break --eof reached - end - atprint(xbytes) - local ybytes=file:read(2) - local zbytes=file:read(2) - local x=(string.byte(xbytes[1])-128)*256+(string.byte(xbytes[2])) - local y=(string.byte(ybytes[1])-128)*256+(string.byte(ybytes[2])) - local z=(string.byte(zbytes[1])-128)*256+(string.byte(zbytes[2])) - - local conn1=string.byte(file:read(1)) - local conn1=string.byte(file:read(1)) - - if not advtrains.trackdb[tt][y] then advtrains.trackdb[tt][y]={} end - if not advtrains.trackdb[tt][y][x] then advtrains.trackdb[tt][y][x]={} end - - local rest=file.read("*l") - if rest~="" then - local rely1, rely2, railheight=string.match(rest, "([^|]+)|([^|]+)|([^|]+)") - if rely1 and rely2 and railheight then - advtrains.trackdb[tt][y][x][z]={ - conn1=conn1, conn2=conn2, - rely1=rely1, rely2=rely2, - railheight=railheight - } - else - advtrains.trackdb[tt][y][x][z]={ - conn1=conn1, conn2=conn2 - } - end - else - advtrains.trackdb[tt][y][x][z]={ - conn1=conn1, conn2=conn2 - } - end - end - file:close() - end -end - ---end minetest.after -end) - -function advtrains.save_trackdb() - for tt, _ in pairs(advtrains.all_traintypes) do - local pl_fpath=minetest.get_worldpath().."/advtrains_trackdb_"..tt - local file, err = io.open(pl_fpath, "w") - if not file then - local er=err or "Unknown Error" - atprint("Failed saving advtrains trackdb save file "..er) - else - --custom format to save memory - for y,tyl in pairs(advtrains.trackdb[tt]) do - for x,txl in pairs(tyl) do - for z,rail in pairs(txl) do - atprint("write "..x.." "..y.." "..z.." "..minetest.serialize(rail)) - file:write(string.char(math.floor(x/256)+128)..string.char((x%256))) - file:write(string.char(math.floor(y/256)+128)..string.char((y%256))) - file:write(string.char(math.floor(z/256)+128)..string.char((z%256))) - file:write(string.char(rail.conn1)) - file:write(string.char(rail.conn2)) - if (rail.rely1 and rail.rely1~=0) or (rail.rely2 and rail.rely2~=0) or (rail.railheight and rail.railheight~=0) then - file:write(rail.rely1.."|"..rail.rely2.."|"..rail.railheight) - end - file:write("\n") - end - end - end - file:close() - end - end -end -]]--end temp outcomment - ---trackdb keeps its own save file. -advtrains.fpath_tdb=minetest.get_worldpath().."/advtrains_trackdb2" -local file, err = io.open(advtrains.fpath_tdb, "r") -if not file then - local er=err or "Unknown Error" - atprint("Failed loading advtrains save file "..er) -else - local tbl = minetest.deserialize(file:read("*a")) - if type(tbl) == "table" then - advtrains.trackdb=tbl - end - file:close() -end -function advtrains.save_trackdb() - local datastr = minetest.serialize(advtrains.trackdb) - if not datastr then - minetest.log("error", " Failed to serialize trackdb data!") - return - end - local file, err = io.open(advtrains.fpath_tdb, "w") - if err then - return err - end - file:write(datastr) - file:close() -end - ---get_node with pseudoload. ---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=minetest.get_node_or_nil(rdp) - if not node then - --try raildb - 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 - else - return nil - end - 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) - - --already in trackdb? - if not (advtrains.trackdb and advtrains.trackdb[rdp.y] and advtrains.trackdb[rdp.y][rdp.x] and advtrains.trackdb[rdp.y][rdp.x][rdp.z]) then--TODO is this necessary? - if not advtrains.trackdb then advtrains.trackdb={} end - if not advtrains.trackdb[rdp.y] then advtrains.trackdb[rdp.y]={} end - if not advtrains.trackdb[rdp.y][rdp.x] then advtrains.trackdb[rdp.y][rdp.x]={} end - advtrains.trackdb[rdp.y][rdp.x][rdp.z]={ - conn1=conn1, conn2=conn2, - rely1=rely1, rely2=rely2, - railheight=railheight, tracktype=tracktype - } - end - - return true, conn1, conn2, rely1, rely2, railheight -end -function advtrains.reset_trackdb_position(pos) - local rdp=advtrains.round_vector_floor_y(pos) - if not advtrains.trackdb then advtrains.trackdb={} end - if not advtrains.trackdb[rdp.y] then advtrains.trackdb[rdp.y]={} end - if not advtrains.trackdb[rdp.y][rdp.x] then advtrains.trackdb[rdp.y][rdp.x]={} end - advtrains.trackdb[rdp.y][rdp.x][rdp.z]=nil - advtrains.get_rail_info_at(pos, advtrains.all_tracktypes)--to restore it. -end - - diff --git a/advtrains/advtrains/signals.lua b/advtrains/advtrains/signals.lua index 8be65e0..59c5af1 100644 --- a/advtrains/advtrains/signals.lua +++ b/advtrains/advtrains/signals.lua @@ -29,14 +29,15 @@ for r,f in pairs({on="off", off="on"}) do choppy=3, not_blocking_trains=1, not_in_creative_inventory=crea, + save_in_nodedb=1, }, mesecons = {effector = { ["action_"..f] = function (pos, node) - minetest.swap_node(pos, {name = "advtrains:retrosignal_"..f..rotation, param2 = node.param2}) + advtrains.np.swap_node(pos, {name = "advtrains:retrosignal_"..f..rotation, param2 = node.param2}) end }}, on_rightclick=function(pos, node, clicker) - minetest.swap_node(pos, {name = "advtrains:retrosignal_"..f..rotation, param2 = node.param2}) + advtrains.np.swap_node(pos, {name = "advtrains:retrosignal_"..f..rotation, param2 = node.param2}) end, }) advtrains.trackplacer.add_worked("advtrains:retrosignal", r, rotation, nil) @@ -59,6 +60,7 @@ for r,f in pairs({on="off", off="on"}) do choppy=3, not_blocking_trains=1, not_in_creative_inventory=crea, + save_in_nodedb=1, }, light_source = 1, sunlight_propagates=true, diff --git a/advtrains/advtrains/trackdb_legacy.lua b/advtrains/advtrains/trackdb_legacy.lua new file mode 100644 index 0000000..99349e8 --- /dev/null +++ b/advtrains/advtrains/trackdb_legacy.lua @@ -0,0 +1,27 @@ +--trackdb_legacy.lua +--loads the (old) track database. the only use for this is to provide data for rails that haven't been written into the ndb database. +--nothing will be saved. +--if the user thinks that he has loaded every track in his world at least once, he can delete the track database. + +--trackdb[[y][x][z]={conn1, conn2, rely1, rely2, railheight} + + +--trackdb keeps its own save file. +advtrains.fpath_tdb=minetest.get_worldpath().."/advtrains_trackdb2" +local file, err = io.open(advtrains.fpath_tdb, "r") +if not file then + atprint("Not loading a trackdb file.") +else + local tbl = minetest.deserialize(file:read("*a")) + if type(tbl) == "table" then + advtrains.trackdb=tbl + atprint("Loaded trackdb file.") + end + file:close() +end + + + + + + diff --git a/advtrains/advtrains/trackplacer.lua b/advtrains/advtrains/trackplacer.lua index e40cb59..1cb7680 100644 --- a/advtrains/advtrains/trackplacer.lua +++ b/advtrains/advtrains/trackplacer.lua @@ -117,13 +117,13 @@ function tp.bend_rail(originpos, conn, nnpref) return false--dont destroy existing track elseif adj1 and not adj2 then if tr.double_conn[adj1.."_"..newdir] then - minetest.set_node(pos, tr.double_conn[adj1.."_"..newdir]) + advtrains.ndb.swap_node(pos, tr.double_conn[adj1.."_"..newdir]) return true--if exists, connect new rail and old end end return false else if tr.single_conn[newdir] then--just rotate old rail to right orientation - minetest.set_node(pos, tr.single_conn[newdir]) + advtrains.ndb.swap_node(pos, tr.single_conn[newdir]) return true end return false @@ -145,7 +145,7 @@ function tp.placetrack(pos, nnpref, placer, itemstack, pointed_thing) end elseif #p_rails==1 then tp.bend_rail(pos, p_rails[1], nnpref) - minetest.set_node(pos, tr.single_conn[p_rails[1]]) + advtrains.ndb.swap_node(pos, tr.single_conn[p_rails[1]]) local nname=tr.single_conn[p_rails[1]].name if minetest.registered_nodes[nname] and minetest.registered_nodes[nname].after_place_node then minetest.registered_nodes[nname].after_place_node(pos, placer, itemstack, pointed_thing) @@ -158,7 +158,7 @@ function tp.placetrack(pos, nnpref, placer, itemstack, pointed_thing) if (tr.double_conn[conn1.."_"..conn2]) then tp.bend_rail(pos, conn1, nnpref) tp.bend_rail(pos, conn2, nnpref) - minetest.set_node(pos, tr.double_conn[conn1.."_"..conn2]) + advtrains.ndb.swap_node(pos, tr.double_conn[conn1.."_"..conn2]) local nname=tr.double_conn[conn1.."_"..conn2].name if minetest.registered_nodes[nname] and minetest.registered_nodes[nname].after_place_node then minetest.registered_nodes[nname].after_place_node(pos, placer, itemstack, pointed_thing) @@ -170,7 +170,7 @@ function tp.placetrack(pos, nnpref, placer, itemstack, pointed_thing) end --not found tp.bend_rail(pos, p_rails[1], nnpref) - minetest.set_node(pos, tr.single_conn[p_rails[1]]) + advtrains.ndb.swap_node(pos, tr.single_conn[p_rails[1]]) local nname=tr.single_conn[p_rails[1]].name if minetest.registered_nodes[nname] and minetest.registered_nodes[nname].after_place_node then minetest.registered_nodes[nname].after_place_node(pos, placer, itemstack, pointed_thing) @@ -245,7 +245,7 @@ minetest.register_craftitem("advtrains:trackworker",{ local modext=tp.tracks[nnprefix].twrotate[suffix] if rotation==modext[#modext] then --increase param2 - minetest.swap_node(pos, {name=nnprefix.."_"..suffix..modext[1], param2=(node.param2+1)%4}) + advtrains.ndb.swap_node(pos, {name=nnprefix.."_"..suffix..modext[1], param2=(node.param2+1)%4}) return else local modpos @@ -254,7 +254,7 @@ minetest.register_craftitem("advtrains:trackworker",{ minetest.chat_send_player(placer:get_player_name(), "This node can't be rotated using the trackworker!") return end - minetest.swap_node(pos, {name=nnprefix.."_"..suffix..modext[modpos+1], param2=node.param2}) + advtrains.ndb.swap_node(pos, {name=nnprefix.."_"..suffix..modext[modpos+1], param2=node.param2}) end advtrains.invalidate_all_paths() end @@ -284,7 +284,7 @@ minetest.register_craftitem("advtrains:trackworker",{ end end local nextsuffix=tp.tracks[nnprefix].twcycle[suffix] - minetest.swap_node(pos, {name=nnprefix.."_"..nextsuffix..rotation, param2=node.param2}) + advtrains.ndb.swap_node(pos, {name=nnprefix.."_"..nextsuffix..rotation, param2=node.param2}) --invalidate trains advtrains.invalidate_all_paths() else diff --git a/advtrains/advtrains/tracks.lua b/advtrains/advtrains/tracks.lua index 671c861..1108a06 100644 --- a/advtrains/advtrains/tracks.lua +++ b/advtrains/advtrains/tracks.lua @@ -235,10 +235,7 @@ advtrains.trackpresets = ap function advtrains.register_tracks(tracktype, def, preset) local function make_switchfunc(suffix_target, mesecon_state) local switchfunc=function(pos, node) - if advtrains.is_train_at_pos(pos) then return end - minetest.set_node(pos, {name=def.nodename_prefix.."_"..suffix_target, param2=node.param2}) - advtrains.invalidate_all_paths() - advtrains.reset_trackdb_position(pos) + advtrains.ndb.swap_node(pos, {name=def.nodename_prefix.."_"..suffix_target, param2=node.param2}) end return switchfunc, {effector = { ["action_"..mesecon_state] = switchfunc, @@ -258,10 +255,12 @@ function advtrains.register_tracks(tracktype, def, preset) rely1=conns.rely1 or 0, rely2=conns.rely2 or 0, railheight=conns.railheight or 0, + on_rightclick=switchfunc, groups = { attached_node=1, ["advtrains_track_"..tracktype]=1, + save_in_nodedb=1, dig_immediate=2, not_in_creative_inventory=(not in_creative_inv and 1 or nil), not_blocking_trains=1, @@ -299,13 +298,10 @@ function advtrains.register_tracks(tracktype, def, preset) end, after_dig_node=function(pos) advtrains.invalidate_all_paths() - advtrains.reset_trackdb_position(pos) + advtrains.ndb.update(pos) end, after_place_node=function(pos) - advtrains.reset_trackdb_position(pos) - end, - on_place_rail=function(pos) - advtrains.reset_trackdb_position(pos) + advtrains.ndb.update(pos) end, }, def.common or {}) --make trackplacer base def @@ -398,10 +394,10 @@ advtrains.detector.clean_step_before = false --The entry already being contained in advtrains.detector.on_node_restore will not trigger an on_train_enter event on the node. (when path is reset, this is saved). function advtrains.detector.enter_node(pos, train_id) local pts = minetest.pos_to_string(advtrains.round_vector_floor_y(pos)) - atprint("enterNode "..pts.." "..sid(train_id)) + --atprint("enterNode "..pts.." "..sid(train_id)) if advtrains.detector.on_node[pts] then if advtrains.trains[advtrains.detector.on_node[pts]] then - atprint(""..pts.." already occupied") + --atprint(""..pts.." already occupied") return false else advtrains.detector.leave_node(pos, advtrains.detector.on_node[pts]) @@ -417,9 +413,9 @@ function advtrains.detector.enter_node(pos, train_id) end function advtrains.detector.leave_node(pos, train_id) local pts = minetest.pos_to_string(advtrains.round_vector_floor_y(pos)) - atprint("leaveNode "..pts.." "..sid(train_id)) + --atprint("leaveNode "..pts.." "..sid(train_id)) if not advtrains.detector.on_node[pts] then - atprint(""..pts.." leave: nothing here") + --atprint(""..pts.." leave: nothing here") return false end if advtrains.detector.on_node[pts]==train_id then @@ -427,7 +423,7 @@ function advtrains.detector.leave_node(pos, train_id) advtrains.detector.on_node[pts]=nil else if advtrains.trains[advtrains.detector.on_node[pts]] then - atprint(""..pts.." occupied by another train") + --atprint(""..pts.." occupied by another train") return false else advtrains.detector.leave_node(pos, advtrains.detector.on_node[pts]) @@ -438,7 +434,7 @@ function advtrains.detector.leave_node(pos, train_id) end --called immediately before invalidating paths function advtrains.detector.setup_restore() - atprint("setup_restore") + --atprint("setup_restore") -- don't execute if it already has been called. For some reason it gets called twice... if advtrains.detector.clean_step_before then return @@ -452,7 +448,7 @@ function advtrains.detector.setup_restore() end --called one step after invalidating paths, when all trains have restored their path and called enter_node for their contents. function advtrains.detector.finalize_restore() - atprint("finalize_restore") + --atprint("finalize_restore") for pts, train_id in pairs(advtrains.detector.on_node_restore) do --atprint("called leave callback "..pts.." "..train_id) advtrains.detector.call_leave_callback(minetest.string_to_pos(pts), train_id) @@ -461,7 +457,7 @@ function advtrains.detector.finalize_restore() advtrains.detector.clean_step_before = false end function advtrains.detector.call_enter_callback(pos, train_id) - atprint("instructed to call enter calback") + --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 mregnode=minetest.registered_nodes[node.name] @@ -473,7 +469,7 @@ function advtrains.detector.call_enter_callback(pos, train_id) 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") + --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 mregnode=minetest.registered_nodes[node.name] -- cgit v1.2.3