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 redundancymaster
parent
dc8b47a066
commit
b649ea5fe4
|
@ -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,
|
||||
|
|
|
@ -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.
|
||||
]]
|
||||
}
|
||||
)
|
||||
|
|
|
@ -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")
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -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
|
||||
|
|
|
@ -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]
|
||||
|
|
Loading…
Reference in New Issue