From 62f5e05c097aa8838c9863081902fe84450b4ba0 Mon Sep 17 00:00:00 2001 From: orwell96 Date: Sun, 29 May 2016 21:33:09 +0200 Subject: added trackdb and unloaded wagons handling --- helpers.lua | 44 ++++++++---------- helpers.lua~ | 48 ++++++++------------ pseudoload.lua | 137 +++++++++++++++++++++++++++++++------------------------- pseudoload.lua~ | 130 ++++++++++++++++++++++++++++------------------------- tracks.lua | 9 +++- tracks.lua~ | 12 +++-- trainlogic.lua | 128 +++++++++++++++++++++++++++++++++++++--------------- trainlogic.lua~ | 128 +++++++++++++++++++++++++++++++++++++--------------- wagons.lua | 2 + wagons.lua~ | 6 ++- 10 files changed, 385 insertions(+), 259 deletions(-) diff --git a/helpers.lua b/helpers.lua index 02367d8..515784b 100644 --- a/helpers.lua +++ b/helpers.lua @@ -58,23 +58,19 @@ rely1, rely2 tell to which height the connections are pointed to. 1 means it wil ]] -function advtrains.conway(midreal, prev, drives_on)--in order prev,mid,return +function advtrains.conway(midreal, prev, traintype)--in order prev,mid,return local mid=advtrains.round_vector_floor_y(midreal) - if(not advtrains.is_track_and_drives_on(minetest.get_node(mid).name, drives_on)) then - --print("[advtrains]in conway: no rail, returning!") - return nil - end - if(not prev or not advtrains.is_track_and_drives_on(minetest.get_node(advtrains.round_vector_floor_y(prev)).name, drives_on)) then - --print("[advtrains]in conway: no prev rail, there should be an initial path!, returning!") + local drives_on=advtrains.all_traintypes[traintype].drives_on + + if not advtrains.get_rail_info_at(advtrains.round_vector_floor_y(prev), traintype) then return nil end - local midnode=minetest.get_node_or_nil(mid) - if not midnode then --print("[advtrains][conway] midnode is ignore") + + local midnode_ok, middir1, middir2, midrely1, midrely2=advtrains.get_rail_info_at(advtrains.round_vector_floor_y(mid), traintype) + if not midnode_ok then return nil end - local middir1, middir2, midrely1, midrely2=advtrains.get_track_connections(midnode.name, midnode.param2) - local next, chkdir, chkrely, y_offset y_offset=0 --print("[advtrains] in order mid1,mid2",middir1,middir2) @@ -110,29 +106,21 @@ function advtrains.conway(midreal, prev, drives_on)--in order prev,mid,return print("[advtrains]in conway: no next rail(nil), returning!") return nil end - local nextnode=minetest.get_node_or_nil(advtrains.round_vector_floor_y(next)) - if not nextnode then print("[advtrains][conway] nextnode is ignore") - return nil - end + + local nextnode_ok, nextdir1, nextdir2, nextrely1, nextrely2, nextrailheight=advtrains.get_rail_info_at(advtrains.round_vector_floor_y(mid), traintype) --is it a rail? - if(not advtrains.is_track_and_drives_on(nextnode.name, drives_on)) then + if(not nextnode_ok) then print("[advtrains]in conway: next "..minetest.pos_to_string(next).." not a rail, trying one node below!") next.y=next.y-1 y_offset=y_offset-1 - nextnode=minetest.get_node_or_nil(advtrains.round_vector_floor_y(next)) - if not nextnode then --print("[advtrains][conway] nextnode is ignore") - return nil - end - if(not advtrains.is_track_and_drives_on(nextnode.name, drives_on)) then + nextnode_ok, nextdir1, nextdir2, nextrely1, nextrely2, nextrailheight=advtrains.get_rail_info_at(advtrains.round_vector_floor_y(mid), traintype) + if(not nextnode_ok) then print("[advtrains]in conway: one below "..minetest.pos_to_string(next).." is not a rail either, returning!") return nil end end - --print("[advtrains]trying to find if rail connects: "..(next and minetest.pos_to_string(next) or "nil").."(chkdir is "..(chkdir or "nil")..", y-offset "..y_offset..")") - - local nextdir1, nextdir2, nextrely1, nextrely2, nextrailheight=advtrains.get_track_connections(nextnode.name, nextnode.param2) --is this next rail connecting to the mid? if not ( (((nextdir1+4)%8)==chkdir and nextrely1==chkrely-y_offset) or (((nextdir2+4)%8)==chkdir and nextrely2==chkrely-y_offset) ) then @@ -140,9 +128,13 @@ function advtrains.conway(midreal, prev, drives_on)--in order prev,mid,return next.y=next.y-1 y_offset=y_offset-1 - nextdir1, nextdir2, nextrely1, nextrely2, nextrailheight=advtrains.get_track_connections(nextnode.name, nextnode.param2) + nextnode_ok, nextdir1, nextdir2, nextrely1, nextrely2, nextrailheight=advtrains.get_rail_info_at(advtrains.round_vector_floor_y(mid), traintype) + if(not nextnode_ok) then + print("[advtrains]in conway: (at connecting if check again) one below "..minetest.pos_to_string(next).." is not a rail either, returning!") + return nil + end if not ( (((nextdir1+4)%8)==chkdir and nextrely1==chkrely) or (((nextdir2+4)%8)==chkdir and nextrely2==chkrely) ) then - print("[advtrains]in conway: next "..minetest.pos_to_string(next).." rail not connecting, returning!") + print("[advtrains]in conway: one below "..minetest.pos_to_string(next).." rail not connecting, returning!") --print("[advtrains] in order mid1,2,next1,2,chkdir "..middir1.." "..middir2.." "..nextdir1.." "..nextdir2.." "..chkdir) return nil end diff --git a/helpers.lua~ b/helpers.lua~ index aa48584..2573436 100644 --- a/helpers.lua~ +++ b/helpers.lua~ @@ -58,23 +58,19 @@ rely1, rely2 tell to which height the connections are pointed to. 1 means it wil ]] -function advtrains.conway(midreal, prev, drives_on)--in order prev,mid,return +function advtrains.conway(midreal, prev, traintype)--in order prev,mid,return local mid=advtrains.round_vector_floor_y(midreal) - if(not advtrains.is_track_and_drives_on(minetest.get_node(mid).name, drives_on)) then - --print("[advtrains]in conway: no rail, returning!") - return nil - end - if(not prev or not advtrains.is_track_and_drives_on(minetest.get_node(advtrains.round_vector_floor_y(prev)).name, drives_on)) then - --print("[advtrains]in conway: no prev rail, there should be an initial path!, returning!") + local drives_on=advtrains.all_traintypes[traintype].drives_on + + if not advtrains.get_rail_info_at(advtrains.round_vector_floor_y(prev), traintype) then return nil end - local midnode=minetest.get_node_or_nil(mid) - if not midnode then --print("[advtrains][conway] midnode is ignore") + + local midnode_ok, middir1, middir2, midrely1, midrely2=advtrains.get_rail_info_at(advtrains.round_vector_floor_y(mid), traintype) + if not midnode_ok then return nil end - local middir1, middir2, midrely1, midrely2=advtrains.get_track_connections(midnode.name, midnode.param2) - local next, chkdir, chkrely, y_offset y_offset=0 --print("[advtrains] in order mid1,mid2",middir1,middir2) @@ -110,29 +106,21 @@ function advtrains.conway(midreal, prev, drives_on)--in order prev,mid,return print("[advtrains]in conway: no next rail(nil), returning!") return nil end - local nextnode=minetest.get_node_or_nil(advtrains.round_vector_floor_y(next)) - if not nextnode then print("[advtrains][conway] nextnode is ignore") - return nil - end + + local nextnode_ok, nextdir1, nextdir2, nextrely1, nextrely2, nextrailheight=advtrains.get_rail_info_at(advtrains.round_vector_floor_y(mid), traintype) --is it a rail? - if(not advtrains.is_track_and_drives_on(nextnode.name, drives_on)) then + if(not nextnode_ok) then print("[advtrains]in conway: next "..minetest.pos_to_string(next).." not a rail, trying one node below!") next.y=next.y-1 y_offset=y_offset-1 - nextnode=minetest.get_node_or_nil(advtrains.round_vector_floor_y(next)) - if not nextnode then --print("[advtrains][conway] nextnode is ignore") - return nil - end - if(not advtrains.is_track_and_drives_on(nextnode.name, drives_on)) then + nextnode_ok, nextdir1, nextdir2, nextrely1, nextrely2, nextrailheight=advtrains.get_rail_info_at(advtrains.round_vector_floor_y(mid), traintype) + if(not nextnode_ok) then print("[advtrains]in conway: one below "..minetest.pos_to_string(next).." is not a rail either, returning!") return nil end end - --print("[advtrains]trying to find if rail connects: "..(next and minetest.pos_to_string(next) or "nil").."(chkdir is "..(chkdir or "nil")..", y-offset "..y_offset..")") - - local nextdir1, nextdir2, nextrely1, nextrely2, nextrailheight=advtrains.get_track_connections(nextnode.name, nextnode.param2) --is this next rail connecting to the mid? if not ( (((nextdir1+4)%8)==chkdir and nextrely1==chkrely-y_offset) or (((nextdir2+4)%8)==chkdir and nextrely2==chkrely-y_offset) ) then @@ -140,8 +128,8 @@ function advtrains.conway(midreal, prev, drives_on)--in order prev,mid,return next.y=next.y-1 y_offset=y_offset-1 - nextdir1, nextdir2, nextrely1, nextrely2, nextrailheight=advtrains.get_track_connections(nextnode.name, nextnode.param2) - if not ( (((nextdir1+4)%8)==chkdir and nextrely1==chkrely) or (((nextdir2+4)%8)==chkdir and nextrely2==chkrely) ) then + nextnode_ok, nextdir1, nextdir2, nextrely1, nextrely2, nextrailheight=advtrains.get_rail_info_at(advtrains.round_vector_floor_y(mid), traintype) + if not nextnode_ok or not ( (((nextdir1+4)%8)==chkdir and nextrely1==chkrely) or (((nextdir2+4)%8)==chkdir and nextrely2==chkrely) ) then print("[advtrains]in conway: next "..minetest.pos_to_string(next).." rail not connecting, returning!") --print("[advtrains] in order mid1,2,next1,2,chkdir "..middir1.." "..middir2.." "..nextdir1.." "..nextdir2.." "..chkdir) return nil @@ -199,17 +187,17 @@ function advtrains.merge_tables(a, ...) end function advtrains.yaw_from_3_positions(prev, curr, next) local pts=minetest.pos_to_string - print("p3 "..pts(prev)..pts(curr)..pts(next)) + --print("p3 "..pts(prev)..pts(curr)..pts(next)) local prev2curr=math.atan2((curr.x-prev.x), (prev.z-curr.z)) local curr2next=math.atan2((next.x-curr.x), (curr.z-next.z)) - print("y3 "..(prev2curr*360/(2*math.pi)).." "..(curr2next*360/(2*math.pi))) + --print("y3 "..(prev2curr*360/(2*math.pi)).." "..(curr2next*360/(2*math.pi))) return prev2curr+(advtrains.minAngleDiffRad(prev2curr, curr2next)/2) end function advtrains.get_wagon_yaw(front, first, second, back, pct) local pts=minetest.pos_to_string - print("p "..pts(front)..pts(first)..pts(second)..pts(back)) + --print("p "..pts(front)..pts(first)..pts(second)..pts(back)) local y2=advtrains.yaw_from_3_positions(second, first, front) local y1=advtrains.yaw_from_3_positions(back, second, first) - print("y "..(y1*360/(2*math.pi)).." "..(y2*360/(2*math.pi))) + --print("y "..(y1*360/(2*math.pi)).." "..(y2*360/(2*math.pi))) return y1+advtrains.minAngleDiffRad(y1, y2)*pct end diff --git a/pseudoload.lua b/pseudoload.lua index 532b429..5b2e4a4 100644 --- a/pseudoload.lua +++ b/pseudoload.lua @@ -3,81 +3,89 @@ --responsible for keeping up a database of all rail nodes existant in the world, regardless of whether the mapchunk is loaded. advtrains.trackdb={} ---trackdb[y][x][z]={conn1, conn2, rely1, rely2, railheight} +--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 -advtrains.pl_fpath=minetest.get_worldpath().."/advtrains_trackdb" -local file, err = io.open(advtrains.pl_fpath, "r") -if not file then - local er=err or "Unknown Error" - print("[advtrains]Failed loading advtrains trackdb save file "..er) -else - --custom format to save memory - while true do - local xbytes=file:read(2) - if not xbytes then - break --eof reached - end - 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[y] then advtrains.trackdb[y]={} end - if not advtrains.trackdb[y][x] then advtrains.trackdb[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[y][x][z]={ - conn1=conn1, conn2=conn2, - rely1=rely1, rely2=rely2, - railheight=railheight - } +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" + print("[advtrains]Failed loading advtrains trackdb save file "..er) + else + --custom format to save memory + while true do + local xbytes=file:read(2) + if not xbytes then + break --eof reached + end + 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[y][x][z]={ + advtrains.trackdb[tt][y][x][z]={ conn1=conn1, conn2=conn2 } end - else - advtrains.trackdb[y][x][z]={ - conn1=conn1, conn2=conn2 - } end + file:close() end - file:close() end + + function advtrains.save_trackdb() - local file, err = io.open(advtrains.pl_fpath, "w") - if not file then - local er=err or "Unknown Error" - print("[advtrains]Failed saving advtrains trackdb save file "..er) - else - --custom format to save memory - for x,txl in pairs(advtrains.trackdb) do - for y,tyl in pairs(txl) do - for z,rail in pairs(tyl) do - 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) + 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" + print("[advtrains]Failed saving advtrains trackdb save file "..er) + else + --custom format to save memory + for x,txl in pairs(advtrains.trackdb[tt]) do + for y,tyl in pairs(txl) do + for z,rail in pairs(tyl) do + 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 - file:write("\n") end end + file:close() end - file:close() end end @@ -92,7 +100,7 @@ function advtrains.get_rail_info_at(pos, traintype) if not node then --try raildb local rdp=vector.round(rdp) - local dbe=advtrains.trackdb[rdp.y][rdp.x][rdp.z] + local dbe=advtrains.trackdb[traintype][rdp.y][rdp.x][rdp.z] if dbe then return true, dbe.conn1, dbe.conn2, dbe.rely1 or 0, dbe.rely2 or 0, dbe.railheight or 0 else @@ -107,7 +115,7 @@ function advtrains.get_rail_info_at(pos, traintype) --already in trackdb? local rdp=vector.round(rdp) - if not advtrains.trackdb[rdp.y][rdp.x][rdp.z] then--TODO is this write prevention here really needed? + if not advtrains.trackdb[traintype][rdp.y][rdp.x][rdp.z] then--TODO is this necessary? advtrains.trackdb[rdp.y][rdp.x][rdp.z]={ conn1=conn1, conn2=conn2, rely1=rely1, rely2=rely2, @@ -117,5 +125,12 @@ function advtrains.get_rail_info_at(pos, traintype) return true, conn1, conn2, rely1, rely2, railheight end - +function advtrains.reset_trackdb_position(pos) + local rdp=vector.round(pos) + for tt, _ in pairs(advtrains.all_traintypes) do + advtrains.trackdb[tt][rdp.y][rdp.x][rdp.z]=nil + advtrains.get_rail_info_at(pos, tt)--to restore it. + end +end + diff --git a/pseudoload.lua~ b/pseudoload.lua~ index 6b04dda..be6b309 100644 --- a/pseudoload.lua~ +++ b/pseudoload.lua~ @@ -3,81 +3,89 @@ --responsible for keeping up a database of all rail nodes existant in the world, regardless of whether the mapchunk is loaded. advtrains.trackdb={} ---trackdb[y][x][z]={conn1, conn2, rely1, rely2, railheight} +--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 -advtrains.pl_fpath=minetest.get_worldpath().."/advtrains_trackdb" -local file, err = io.open(advtrains.pl_fpath, "r") -if not file then - local er=err or "Unknown Error" - print("[advtrains]Failed loading advtrains trackdb save file "..er) -else - --custom format to save memory - while true do - local xbytes=file:read(2) - if not xbytes then - break --eof reached - end - 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[y] then advtrains.trackdb[y]={} end - if not advtrains.trackdb[y][x] then advtrains.trackdb[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[y][x][z]={ - conn1=conn1, conn2=conn2, - rely1=rely1, rely2=rely2, - railheight=railheight - } +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" + print("[advtrains]Failed loading advtrains trackdb save file "..er) + else + --custom format to save memory + while true do + local xbytes=file:read(2) + if not xbytes then + break --eof reached + end + 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[y][x][z]={ + advtrains.trackdb[tt][y][x][z]={ conn1=conn1, conn2=conn2 } end - else - advtrains.trackdb[y][x][z]={ - conn1=conn1, conn2=conn2 - } end + file:close() end - file:close() end + + function advtrains.save_trackdb() - local file, err = io.open(advtrains.pl_fpath, "w") - if not file then - local er=err or "Unknown Error" - print("[advtrains]Failed saving advtrains trackdb save file "..er) - else - --custom format to save memory - for x,txl in pairs(advtrains.trackdb) do - for y,tyl in pairs(txl) do - for z,rail in pairs(tyl) do - 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) + 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" + print("[advtrains]Failed saving advtrains trackdb save file "..er) + else + --custom format to save memory + for x,txl in pairs(advtrains.trackdb[tt]) do + for y,tyl in pairs(txl) do + for z,rail in pairs(tyl) do + 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 - file:write("\n") end end + file:close() end - file:close() end end @@ -87,12 +95,12 @@ end --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_at(pos, traintype) +function advtrains.get_rail_info_at(pos, traintype) local node=minetest.get_node_or_nil(pos) if not node then --try raildb local rdp=vector.round(rdp) - local dbe=advtrains.trackdb[rdp.y][rdp.x][rdp.z] + local dbe=advtrains.trackdb[traintype][rdp.y][rdp.x][rdp.z] if dbe then return true, dbe.conn1, dbe.conn2, dbe.rely1 or 0, dbe.rely2 or 0, dbe.railheight or 0 else @@ -107,7 +115,7 @@ function advtrains.get_rail_at(pos, traintype) --already in trackdb? local rdp=vector.round(rdp) - if not advtrains.trackdb[rdp.y][rdp.x][rdp.z] then--TODO is this write prevention here really needed? + if not advtrains.trackdb[traintype][rdp.y][rdp.x][rdp.z] then--TODO is this necessary? advtrains.trackdb[rdp.y][rdp.x][rdp.z]={ conn1=conn1, conn2=conn2, rely1=rely1, rely2=rely2, diff --git a/tracks.lua b/tracks.lua index b164dd5..54c7100 100644 --- a/tracks.lua +++ b/tracks.lua @@ -31,6 +31,7 @@ function advtrains.register_tracks(tracktype, def) if advtrains.is_train_at_pos(pos) then return end advtrains.invalidate_all_paths() minetest.set_node(pos, {name=def.nodename_prefix.."_"..suffix_target, param2=node.param2}) + advtrains.reset_trackdb_position(pos) end end local function make_overdef(img_suffix, conn1, conn2, switchfunc) @@ -70,8 +71,12 @@ function advtrains.register_tracks(tracktype, def) can_dig=function(pos) return not advtrains.is_train_at_pos(pos) end, - after_dig_node=function() + after_dig_node=function(pos) advtrains.invalidate_all_paths() + advtrains.reset_trackdb_position(pos) + end + after_place_node=function(pos) + advtrains.reset_trackdb_position(pos) end } minetest.register_node(def.nodename_prefix.."_st", advtrains.merge_tables(common_def, make_overdef("st", 0, 4), def.straight or {})) @@ -136,7 +141,7 @@ end function advtrains.get_track_connections(name, param2) local nodedef=minetest.registered_nodes[name] - if not nodedef then print("[advtrains] get_track_connections couldn't find nodedef for nodename "..(name or "nil")) return 0,4 end + if not nodedef then print("[advtrains] get_track_connections couldn't find nodedef for nodename "..(name or "nil")) return 0, 4, 0, 0, 0 end local noderot=param2 if not param2 then noderot=0 end if noderot > 3 then print("[advtrains] get_track_connections: rail has invaild param2 of "..noderot) noderot=0 end diff --git a/tracks.lua~ b/tracks.lua~ index b2513b2..07dc056 100644 --- a/tracks.lua~ +++ b/tracks.lua~ @@ -31,6 +31,7 @@ function advtrains.register_tracks(tracktype, def) if advtrains.is_train_at_pos(pos) then return end advtrains.invalidate_all_paths() minetest.set_node(pos, {name=def.nodename_prefix.."_"..suffix_target, param2=node.param2}) + advtrains.reset_trackdb_position(pos) end end local function make_overdef(img_suffix, conn1, conn2, switchfunc) @@ -70,8 +71,9 @@ function advtrains.register_tracks(tracktype, def) can_dig=function(pos) return not advtrains.is_train_at_pos(pos) end, - after_dig_node=function() + after_dig_node=function(pos) advtrains.invalidate_all_paths() + advtrains.reset_trackdb_position(pos) end } minetest.register_node(def.nodename_prefix.."_st", advtrains.merge_tables(common_def, make_overdef("st", 0, 4), def.straight or {})) @@ -101,13 +103,15 @@ function advtrains.register_tracks(tracktype, def) rely1=0, rely2=0.5, railheight=0.25, - }, def.straight or {})) + description = def.description.." (vertical track lower node)", + }, def.vert1 or {})) minetest.register_node(def.nodename_prefix.."_vert2", advtrains.merge_tables(common_def, make_overdef("vert2", 0, 4), { mesh = "trackvertical2.b3d", rely1=0.5, rely2=1, railheight=0.75, - },def.straight45 or {})) + description = def.description.." (vertical track lower node)", + },def.vert2 or {})) advtrains.register_track_placer(def.nodename_prefix, def.texture_prefix, def.description) table.insert(advtrains.all_tracktypes, tracktype) @@ -134,7 +138,7 @@ end function advtrains.get_track_connections(name, param2) local nodedef=minetest.registered_nodes[name] - if not nodedef then print("[advtrains] get_track_connections couldn't find nodedef for nodename "..(name or "nil")) return 0,4 end + if not nodedef then print("[advtrains] get_track_connections couldn't find nodedef for nodename "..(name or "nil")) return 0, 4, 0, 0, 0 end local noderot=param2 if not param2 then noderot=0 end if noderot > 3 then print("[advtrains] get_track_connections: rail has invaild param2 of "..noderot) noderot=0 end diff --git a/trainlogic.lua b/trainlogic.lua index 74e9c97..87c5d33 100644 --- a/trainlogic.lua +++ b/trainlogic.lua @@ -32,6 +32,18 @@ else end file:close() end +advtrains.fpath_ws=minetest.get_worldpath().."/advtrains_wagon_save" +local file, err = io.open(advtrains.fpath_ws, "r") +if not file then + local er=err or "Unknown Error" + print("[advtrains]Failed loading advtrains save file "..er) +else + local tbl = minetest.deserialize(file:read("*a")) + if type(tbl) == "table" then + advtrains.wagon_save=tbl + end + file:close() +end advtrains.save = function() @@ -48,6 +60,25 @@ advtrains.save = function() end file:write(datastr) file:close() + + -- update wagon saves + for _,wagon in pairs(minetest.luaentities) do + if wagon.is_wagon and wagon.initialized then + advtrains.wagon_save[wagon.unique_id]=advtrains.merge_tables(wagon)--so, will only copy non_metatable elements + end + end + + datastr = minetest.serialize(advtrains.wagon_save) + if not datastr then + minetest.log("error", "[advtrains] Failed to serialize train data!") + return + end + file, err = io.open(advtrains.fpath_ws, "w") + if err then + return err + end + file:write(datastr) + file:close() end minetest.register_on_shutdown(advtrains.save) @@ -136,6 +167,45 @@ function advtrains.train_step(id, train, dtime) end end end + + --check for any trainpart entities if they have been unloaded. do this only if both front and end positions are loaded, to ensure train entities will be placed inside loaded area, and only every second. + train.check_trainpartload=train.check_trainpartload-dtime + if train.check_trainpartload<=0 and posfront and posback and minetest.get_node_or_nil(posfront) and minetest.get_node_or_nil(posback) then + --it is better to iterate luaentites only once + local found_uids={} + for _,wagon in pairs(minetest.luaentities) do + if wagon.is_wagon and wagon.initialized and wagon.train_id==id then + if found_uids[wagon.unique_id] then + --duplicate found, delete it + wagon.object and wagon.object:remove() + else + found_uids[wagon.unique_id]=true + end + end + end + --now iterate trainparts and check. then cross them out to see if there are wagons over for any reason + for pit, w_id in ipairs(train.trainparts) do + if found_uids[w_id] then + found_uids[w_id]=nil + elseif advtrains.wagon_save[w_id] then + --spawn a new and initialize it with the properties from wagon_save + local le=minetest.env:add_entity(posfront, "advtrains:"..sysname):get_luaentity() + for k,v in pairs(advtrains.wagon_save[w_id]) do + le[k]=v + end + else + --what the hell... + local le=minetest.env:add_entity(posfront, "advtrains:"..sysname):get_luaentity() + le.unique_id=w_id + le.train_id=id + le.pos_in_trainparts=pit + advtrains.update_trainpart_properties(id, train) + end + end + train.check_trainpartload=1 + end + + --handle collided_with_env if train.recently_collided_with_env then train.tarvelocity=0 @@ -229,41 +299,35 @@ function advtrains.pathpredict(id, train) return false end - local node=minetest.get_node_or_nil(advtrains.round_vector_floor_y(train.last_pos)) - if not node then - --print("pathpredict:last_pos node "..minetest.pos_to_string(advtrains.round_vector_floor_y(train.last_pos)).." is nil. block probably not loaded") - return nil - end - local nodename=node.name + local node_ok=advtrains.get_rail_info_at(advtrains.round_vector_floor_y(train.last_pos), train.traintype) - if(not advtrains.is_track_and_drives_on(nodename, advtrains.all_traintypes[train.traintype].drives_on)) then - advtrains.dumppath(train.path) - print("at index "..train.index) + if node_ok==nil then + --block not loaded, do nothing + return nil + elseif node_ok==false then print("[advtrains]no track here, (fail) removing train.") advtrains.trains[id]=nil return false end + if not train.last_pos_prev then --no chance to recover print("[advtrains]train hasn't saved last-pos_prev, removing train.") advtrains.trains[id]=nil return false end - local prevnode=minetest.get_node_or_nil(advtrains.round_vector_floor_y(train.last_pos_prev)) - if not prevnode then - --print("pathpredict:last_pos_prev node "..minetest.pos_to_string(advtrains.round_vector_floor_y(train.last_pos_prev)).." is nil. block probably not loaded") - return nil - end - local prevnodename=prevnode.name - if(not advtrains.is_track_and_drives_on(prevnodename, advtrains.all_traintypes[train.traintype].drives_on)) then + local prevnode_ok=advtrains.get_rail_info_at(advtrains.round_vector_floor_y(train.last_pos_prev), train.traintype) + + if prevnode_ok==nil then + --block not loaded, do nothing + return nil + elseif prevnode_ok==false then print("[advtrains]no track at prev, (fail) removing train.") advtrains.trains[id]=nil return false end - local conn1, conn2=advtrains.get_track_connections(nodename, node.param2) - train.index=(train.restore_add_index or 0)+(train.savedpos_off_track_index_offset or 0) --restore_add_index is set by save() to prevent trains hopping to next round index. should be between -0.5 and 0.5 --savedpos_off_track_index_offset is set if train went off track. see below. @@ -277,7 +341,7 @@ function advtrains.pathpredict(id, train) local maxn=advtrains.maxN(train.path) while (maxn-train.index) < 2 do--pregenerate --print("[advtrains]maxn conway for ",maxn,minetest.pos_to_string(path[maxn]),maxn-1,minetest.pos_to_string(path[maxn-1])) - local conway=advtrains.conway(train.path[maxn], train.path[maxn-1], advtrains.all_traintypes[train.traintype].drives_on) + local conway=advtrains.conway(train.path[maxn], train.path[maxn-1], train.traintype) if conway then train.path[maxn+1]=conway train.max_index_on_track=maxn @@ -294,7 +358,7 @@ function advtrains.pathpredict(id, train) local minn=advtrains.minN(train.path) while (train.index-minn) < (train.trainlen or 0) + 2 do --post_generate. has to be at least trainlen. --print("[advtrains]minn conway for ",minn,minetest.pos_to_string(path[minn]),minn+1,minetest.pos_to_string(path[minn+1])) - local conway=advtrains.conway(train.path[minn], train.path[minn+1], advtrains.all_traintypes[train.traintype].drives_on) + local conway=advtrains.conway(train.path[minn], train.path[minn+1], train.traintype) if conway then train.path[minn-1]=conway train.min_index_on_track=minn @@ -384,30 +448,20 @@ function advtrains.split_train_at_wagon(wagon) print("split_train: pos_for_new_train not set") return false end - local node=minetest.get_node_or_nil(advtrains.round_vector_floor_y(pos_for_new_train)) - if not node then - print("split_train: pos_for_new_train node "..minetest.pos_to_string(advtrains.round_vector_floor_y(pos_for_new_train)).." is nil. block probably not loaded") - return nil - end - local nodename=node.name - - if(not advtrains.is_track_and_drives_on(nodename, advtrains.all_traintypes[train.traintype].drives_on)) then - print("split_train: pos_for_new_train "..minetest.pos_to_string(advtrains.round_vector_floor_y(pos_for_new_train_prev)).." is not a rail") + local node_ok=advtrains.get_rail_info_at(advtrains.round_vector_floor_y(pos_for_new_train), train.traintype) + if not node_ok then + print("split_train: pos_for_new_train "..minetest.pos_to_string(advtrains.round_vector_floor_y(pos_for_new_train_prev)).." not loaded or is not a rail") return false end + if not train.last_pos_prev then print("split_train: pos_for_new_train_prev not set") return false end - local prevnode=minetest.get_node_or_nil(advtrains.round_vector_floor_y(pos_for_new_train_prev)) - if not node then - print("split_train: pos_for_new_train_prev node "..minetest.pos_to_string(advtrains.round_vector_floor_y(pos_for_new_train_prev)).." is nil. block probably not loaded") - return false - end - local prevnodename=prevnode.name - if(not advtrains.is_track_and_drives_on(prevnodename, advtrains.all_traintypes[train.traintype].drives_on)) then - print("split_train: pos_for_new_train_prev "..minetest.pos_to_string(advtrains.round_vector_floor_y(pos_for_new_train_prev)).." is not a rail") + local prevnode_ok=advtrains.get_rail_info_at(advtrains.round_vector_floor_y(pos_for_new_train), train.traintype) + if not prevnode_ok then + print("split_train: pos_for_new_train_prev "..minetest.pos_to_string(advtrains.round_vector_floor_y(pos_for_new_train_prev)).." not loaded or is not a rail") return false end diff --git a/trainlogic.lua~ b/trainlogic.lua~ index 9838f81..25e8b54 100644 --- a/trainlogic.lua~ +++ b/trainlogic.lua~ @@ -32,6 +32,18 @@ else end file:close() end +advtrains.fpath_ws=minetest.get_worldpath().."/advtrains_wagon_save" +local file, err = io.open(advtrains.fpath_ws, "r") +if not file then + local er=err or "Unknown Error" + print("[advtrains]Failed loading advtrains save file "..er) +else + local tbl = minetest.deserialize(file:read("*a")) + if type(tbl) == "table" then + advtrains.wagon_save=tbl + end + file:close() +end advtrains.save = function() @@ -48,6 +60,25 @@ advtrains.save = function() end file:write(datastr) file:close() + + -- update wagon saves + for _,wagon in pairs(minetest.luaentities) do + if wagon.is_wagon and wagon.initialized then + advtrains.wagon_save[wagon.unique_id]=advtrains.merge_tables(wagon)--so, will only copy non_metatable elements + end + end + + datastr = minetest.serialize(advtrains.wagon_save) + if not datastr then + minetest.log("error", "[advtrains] Failed to serialize train data!") + return + end + file, err = io.open(advtrains.fpath_ws, "w") + if err then + return err + end + file:write(datastr) + file:close() end minetest.register_on_shutdown(advtrains.save) @@ -136,6 +167,44 @@ function advtrains.train_step(id, train, dtime) end end end + + --check for any trainpart entities if they have been unloaded. do this only if both front and end positions are loaded, to ensure train entities will be placed inside loaded area, and only every second. + train.check_trainpartload=train.check_trainpartload-dtime + if train.check_trainpartload<=0 and posfront and posback and minetest.get_node_or_nil(posfront) and minetest.get_node_or_nil(posback) then + --it is better to iterate luaentites only once + local found_uids={} + for _,wagon in pairs(minetest.luaentities) do + if wagon.is_wagon and wagon.initialized and wagon.train_id==id then + if found_uids[wagon.unique_id] then + --duplicate found, delete it + wagon.object and wagon.object:remove() + else + found_uids[wagon.unique_id]=true + end + end + end + --now iterate trainparts and check. then cross them out to see if there are wagons over for any reason + for pit, w_id in ipairs(train.trainparts) do + if found_uids[w_id] then + found_uids[w_id]=nil + elseif advtrains.wagon_save[w_id] then + --spawn a new and initialize it with the properties from wagon_save + local le=minetest.env:add_entity(posfront, "advtrains:"..sysname):get_luaentity() + for k,v in pairs(advtrains.wagon_save[w_id]) do + le[k]=v + end + else + --what the hell... + local le=minetest.env:add_entity(posfront, "advtrains:"..sysname):get_luaentity() + le.train_id=id + le.pos_in_trainparts=pit + --update trainpart properties when train stepped... + end + end + train.check_trainpartload=1 + end + + --handle collided_with_env if train.recently_collided_with_env then train.tarvelocity=0 @@ -228,41 +297,36 @@ function advtrains.pathpredict(id, train) advtrains.train[id]=nil return false end - local node=minetest.get_node_or_nil(advtrains.round_vector_floor_y(train.last_pos)) - if not node then - --print("pathpredict:last_pos node "..minetest.pos_to_string(advtrains.round_vector_floor_y(train.last_pos)).." is nil. block probably not loaded") - return nil - end - local nodename=node.name - if(not advtrains.is_track_and_drives_on(nodename, advtrains.all_traintypes[train.traintype].drives_on)) then - advtrains.dumppath(train.path) - print("at index "..train.index) + local node_ok=advtrains.get_rail_info_at(advtrains.round_vector_floor_y(train.last_pos), train.traintype) + + if node_ok==nil then + --block not loaded, do nothing + return nil + elseif node_ok==false then print("[advtrains]no track here, (fail) removing train.") advtrains.trains[id]=nil return false end + if not train.last_pos_prev then --no chance to recover print("[advtrains]train hasn't saved last-pos_prev, removing train.") advtrains.trains[id]=nil return false end - local prevnode=minetest.get_node_or_nil(advtrains.round_vector_floor_y(train.last_pos_prev)) - if not prevnode then - --print("pathpredict:last_pos_prev node "..minetest.pos_to_string(advtrains.round_vector_floor_y(train.last_pos_prev)).." is nil. block probably not loaded") - return nil - end - local prevnodename=prevnode.name - if(not advtrains.is_track_and_drives_on(prevnodename, advtrains.all_traintypes[train.traintype].drives_on)) then + local prevnode_ok=advtrains.get_rail_info_at(advtrains.round_vector_floor_y(train.last_pos_prev), train.traintype) + + if prevnode_ok==nil then + --block not loaded, do nothing + return nil + elseif prevnode_ok==false then print("[advtrains]no track at prev, (fail) removing train.") advtrains.trains[id]=nil return false end - local conn1, conn2=advtrains.get_track_connections(nodename, node.param2) - train.index=(train.restore_add_index or 0)+(train.savedpos_off_track_index_offset or 0) --restore_add_index is set by save() to prevent trains hopping to next round index. should be between -0.5 and 0.5 --savedpos_off_track_index_offset is set if train went off track. see below. @@ -276,7 +340,7 @@ function advtrains.pathpredict(id, train) local maxn=advtrains.maxN(train.path) while (maxn-train.index) < 2 do--pregenerate --print("[advtrains]maxn conway for ",maxn,minetest.pos_to_string(path[maxn]),maxn-1,minetest.pos_to_string(path[maxn-1])) - local conway=advtrains.conway(train.path[maxn], train.path[maxn-1], advtrains.all_traintypes[train.traintype].drives_on) + local conway=advtrains.conway(train.path[maxn], train.path[maxn-1], train.traintype) if conway then train.path[maxn+1]=conway train.max_index_on_track=maxn @@ -293,7 +357,7 @@ function advtrains.pathpredict(id, train) local minn=advtrains.minN(train.path) while (train.index-minn) < (train.trainlen or 0) + 2 do --post_generate. has to be at least trainlen. --print("[advtrains]minn conway for ",minn,minetest.pos_to_string(path[minn]),minn+1,minetest.pos_to_string(path[minn+1])) - local conway=advtrains.conway(train.path[minn], train.path[minn+1], advtrains.all_traintypes[train.traintype].drives_on) + local conway=advtrains.conway(train.path[minn], train.path[minn+1], train.traintype) if conway then train.path[minn-1]=conway train.min_index_on_track=minn @@ -383,30 +447,20 @@ function advtrains.split_train_at_wagon(wagon) print("split_train: pos_for_new_train not set") return false end - local node=minetest.get_node_or_nil(advtrains.round_vector_floor_y(pos_for_new_train)) - if not node then - print("split_train: pos_for_new_train node "..minetest.pos_to_string(advtrains.round_vector_floor_y(pos_for_new_train)).." is nil. block probably not loaded") - return nil - end - local nodename=node.name - - if(not advtrains.is_track_and_drives_on(nodename, advtrains.all_traintypes[train.traintype].drives_on)) then - print("split_train: pos_for_new_train "..minetest.pos_to_string(advtrains.round_vector_floor_y(pos_for_new_train_prev)).." is not a rail") + local node_ok=advtrains.get_rail_info_at(advtrains.round_vector_floor_y(pos_for_new_train), train.traintype) + if not node_ok then + print("split_train: pos_for_new_train "..minetest.pos_to_string(advtrains.round_vector_floor_y(pos_for_new_train_prev)).." not loaded or is not a rail") return false end + if not train.last_pos_prev then print("split_train: pos_for_new_train_prev not set") return false end - local prevnode=minetest.get_node_or_nil(advtrains.round_vector_floor_y(pos_for_new_train_prev)) - if not node then - print("split_train: pos_for_new_train_prev node "..minetest.pos_to_string(advtrains.round_vector_floor_y(pos_for_new_train_prev)).." is nil. block probably not loaded") - return false - end - local prevnodename=prevnode.name - if(not advtrains.is_track_and_drives_on(prevnodename, advtrains.all_traintypes[train.traintype].drives_on)) then - print("split_train: pos_for_new_train_prev "..minetest.pos_to_string(advtrains.round_vector_floor_y(pos_for_new_train_prev)).." is not a rail") + local prevnode_ok=advtrains.get_rail_info_at(advtrains.round_vector_floor_y(pos_for_new_train), train.traintype) + if not prevnode_ok then + print("split_train: pos_for_new_train_prev "..minetest.pos_to_string(advtrains.round_vector_floor_y(pos_for_new_train_prev)).." not loaded or is not a rail") return false end diff --git a/wagons.lua b/wagons.lua index 7c634f0..ea54e19 100644 --- a/wagons.lua +++ b/wagons.lua @@ -89,6 +89,8 @@ function wagon:on_activate(staticdata, dtime_s) end function wagon:get_staticdata() + --save to table before being unloaded + advtrains.wagon_save[self.unique_id]=advtrains.merge_tables(self) return minetest.serialize({ unique_id=self.unique_id, train_id=self.train_id, diff --git a/wagons.lua~ b/wagons.lua~ index 1d08bf7..dff1576 100644 --- a/wagons.lua~ +++ b/wagons.lua~ @@ -60,6 +60,7 @@ function wagon:on_activate(staticdata, dtime_s) if tmp then self.unique_id=tmp.unique_id self.train_id=tmp.train_id + self.wagon_flipped=tmp.wagon_flipped end end @@ -88,9 +89,12 @@ function wagon:on_activate(staticdata, dtime_s) end function wagon:get_staticdata() + --save to table before being unloaded + advtrains.wagon_save[self.unique_id]=advtrains.merge_tables(self) return minetest.serialize({ unique_id=self.unique_id, train_id=self.train_id, + wagon_flipped=self.wagon_flipped, }) end @@ -177,7 +181,7 @@ function wagon:on_step(dtime) return end - local pos_in_train_left=self.pos_in_train+0 + local pos_in_train_left=(self.pos_in_train or 0)+0 --pos_in_train may be not set if this was emergency-instantiated by train_step when it found out that an object is missing but no wagon_save was found. local index=gp.index if pos_in_train_left>(index-math.floor(index))*(gp.path_dist[math.floor(index)] or 1) then pos_in_train_left=pos_in_train_left - (index-math.floor(index))*(gp.path_dist[math.floor(index)] or 1) -- cgit v1.2.3