diff options
Diffstat (limited to 'advtrains/init.lua')
-rw-r--r-- | advtrains/init.lua | 402 |
1 files changed, 402 insertions, 0 deletions
diff --git a/advtrains/init.lua b/advtrains/init.lua new file mode 100644 index 0000000..6255780 --- /dev/null +++ b/advtrains/init.lua @@ -0,0 +1,402 @@ +-- Boilerplate to support localized strings if intllib mod is installed. +if minetest.get_modpath("intllib") then + attrans = intllib.Getter() +else + attrans = function(s,a,...)a={a,...}return s:gsub("@(%d+)",function(n)return a[tonumber(n)]end)end +end + +--advtrains + +advtrains = {trains={}, wagon_save={}, player_to_train_mapping={}} + +--pcall +local no_action=false + +local function reload_saves() + atwarn("Restoring saved state in 1 second...") + no_action=true + --read last save state and continue, as if server was restarted + for aoi, le in pairs(minetest.luaentities) do + if le.is_wagon then + le.object:remove() + end + end + minetest.after(1, function() + advtrains.load() + atwarn("Reload successful!") + advtrains.ndb.restore_all() + end) +end + +function advtrains.pcall(fun) + if no_action then return end + + local succ, return1, return2, return3, return4=xpcall(fun, function(err) + if advtrains.atprint_context_tid then + local train=advtrains.trains[advtrains.atprint_context_tid_full] + advtrains.dumppath(train.path) + atwarn("Dumping last debug outputs: ", err) + atprint("Train state: index",train.index,"end_index", train.end_index,"| max_iot", train.max_index_on_track, "min_iot", train.min_index_on_track, "<> pe_min", train.path_extent_min,"pe_max", train.path_extent_max) + if minetest.settings:get_bool("advtrains_enable_debugging") then + advtrains.drb_dump(advtrains.atprint_context_tid) + end + end + atwarn("Lua Error occured: ", err) + atwarn(debug.traceback()) + end) + if not succ then + reload_saves() + else + return return1, return2, return3, return4 + end +end + + +advtrains.modpath = minetest.get_modpath("advtrains") + +function advtrains.print_concat_table(a) + local str="" + local stra="" + local t + for i=1,20 do + t=a[i] + if t==nil then + stra=stra.."nil " + else + str=str..stra + stra="" + if type(t)=="table" then + if t.x and t.y and t.z then + str=str..minetest.pos_to_string(t) + else + str=str..dump(t) + end + elseif type(t)=="boolean" then + if t then + str=str.."true" + else + str=str.."false" + end + else + str=str..t + end + str=str.." " + end + end + return str +end + +atprint=function() end +atdebug=function() end +atlog=function(t, ...) + local text=advtrains.print_concat_table({t, ...}) + minetest.log("action", "[advtrains]"..text) +end +atwarn=function(t, ...) + local text=advtrains.print_concat_table({t, ...}) + minetest.log("warning", "[advtrains]"..text) + minetest.chat_send_all("[advtrains] -!- "..text) +end +sid=function(id) if id then return string.sub(id, -6) end end + +if minetest.settings:get_bool("advtrains_enable_debugging") then + atprint=function(t, ...) + local context=advtrains.atprint_context_tid + if not context then return end + local text=advtrains.print_concat_table({t, ...}) + advtrains.drb_record(context, text) + end + atdebug=function(t, ...) + local text=advtrains.print_concat_table({t, ...}) + minetest.log("action", "[advtrains]"..text) + minetest.chat_send_all("[advtrains]"..text) + end + dofile(advtrains.modpath.."/debugringbuffer.lua") +end + +dofile(advtrains.modpath.."/helpers.lua"); +--dofile(advtrains.modpath.."/debugitems.lua"); + +advtrains.meseconrules = +{{x=0, y=0, z=-1}, + {x=1, y=0, z=0}, + {x=-1, y=0, z=0}, + {x=0, y=0, z=1}, + {x=1, y=1, z=0}, + {x=1, y=-1, z=0}, + {x=-1, y=1, z=0}, + {x=-1, y=-1, z=0}, + {x=0, y=1, z=1}, + {x=0, y=-1, z=1}, + {x=0, y=1, z=-1}, + {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.."/signals.lua") +dofile(advtrains.modpath.."/misc_nodes.lua") +dofile(advtrains.modpath.."/crafting.lua") +dofile(advtrains.modpath.."/craft_items.lua") +dofile(advtrains.modpath.."/loading.lua") + +if minetest.global_exists("digtron") then + dofile(advtrains.modpath.."/digtron.lua") +end + +--load/save + +advtrains.fpath=minetest.get_worldpath().."/advtrains" + +function advtrains.avt_load() + local file, err = io.open(advtrains.fpath, "r") + if not file then + minetest.log("error", " Failed to read advtrains save data from file "..advtrains.fpath..": "..(err or "Unknown Error")) + else + local tbl = minetest.deserialize(file:read("*a")) + if type(tbl) == "table" then + if tbl.version then + --congrats, we have the new save format. + advtrains.trains = tbl.trains + advtrains.wagon_save = tbl.wagon_save + advtrains.player_to_train_mapping = tbl.ptmap or {} + advtrains.ndb.load_data(tbl.ndb) + advtrains.atc.load_data(tbl.atc) + else + --oh no, its the old one... + advtrains.trains=tbl + --load ATC + advtrains.fpath_atc=minetest.get_worldpath().."/advtrains_atc" + local file, err = io.open(advtrains.fpath_atc, "r") + if not file then + local er=err or "Unknown Error" + atprint("Failed loading advtrains atc save file "..er) + else + local tbl = minetest.deserialize(file:read("*a")) + if type(tbl) == "table" then + advtrains.atc.controllers=tbl.controllers + end + file:close() + end + --load wagon saves + 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" + atprint("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 + end + else + minetest.log("error", " Failed to deserialize advtrains save data: Not a table!") + end + file:close() + end +end + +advtrains.avt_save = function(remove_players_from_wagons) + --atprint("saving") + --No more invalidating. + --Instead, remove path a.s.o from the saved table manually + + -- update wagon saves + for _,wagon in pairs(minetest.luaentities) do + if wagon.is_wagon and wagon.initialized then + wagon:get_staticdata() + end + end + --cross out userdata + for w_id, data in pairs(advtrains.wagon_save) do + data.name=nil + data.object=nil + if data.driver then + data.driver_name=data.driver:get_player_name() + data.driver=nil + else + data.driver_name=nil + end + if data.discouple then + data.discouple.object:remove() + data.discouple=nil + end + if remove_players_from_wagons then + data.seatp={} + end + end + if remove_players_from_wagons then + advtrains.player_to_train_mapping={} + end + + local tmp_trains={} + for id, train in pairs(advtrains.trains) do + --first, deep_copy the train + local v=advtrains.merge_tables(train) + --then invalidate + if v.index then + v.restore_add_index=v.index-math.floor(v.index+0.5) + end + v.path=nil + v.path_dist=nil + v.index=nil + v.end_index=nil + v.min_index_on_track=nil + v.max_index_on_track=nil + v.path_extent_min=nil + v.path_extent_max=nil + + v.detector_old_index=nil + v.detector_old_end_index=nil + + --then save it + tmp_trains[id]=v + end + + --versions: + -- 1 - Initial new save format. + local save_tbl={ + trains = tmp_trains, + wagon_save = advtrains.wagon_save, + ptmap = advtrains.player_to_train_mapping, + atc = advtrains.atc.save_data(), + ndb = advtrains.ndb.save_data(), + version = 1, + } + local datastr = minetest.serialize(save_tbl) + if not datastr then + minetest.log("error", " Failed to serialize advtrains save data!") + return + end + local file, err = io.open(advtrains.fpath, "w") + if err then + minetest.log("error", " Failed to write advtrains save data to file "..advtrains.fpath..": "..(err or "Unknown Error")) + return + end + file:write(datastr) + file:close() +end + +--## MAIN LOOP ##-- +--Calls all subsequent main tasks of both advtrains and atlatc +local init_load=false +local save_interval=20 +local save_timer=save_interval +advtrains.mainloop_runcnt=0 + +minetest.register_globalstep(function(dtime_mt) + return advtrains.pcall(function() + advtrains.mainloop_runcnt=advtrains.mainloop_runcnt+1 + atprint("Running the main loop, runcnt",advtrains.mainloop_runcnt) + --call load once. see advtrains.load() comment + if not init_load then + advtrains.load() + end + --limit dtime: if trains move too far in one step, automation may cause stuck and wrongly braking trains + local dtime=dtime_mt + if dtime>0.2 then + atprint("Limiting dtime to 0.2!") + dtime=0.2 + end + + advtrains.mainloop_trainlogic(dtime) + if advtrains_itm_mainloop then + advtrains_itm_mainloop(dtime) + end + if atlatc then + atlatc.mainloop_stepcode(dtime) + atlatc.interrupt.mainloop(dtime) + end + + + --trigger a save when necessary + save_timer=save_timer-dtime + if save_timer<=0 then + local t=os.clock() + --save + advtrains.save() + save_timer=save_interval + atprintbm("saving", t) + end + end) +end) + +--if something goes wrong in these functions, there is no help. no pcall here. + +--## MAIN LOAD ROUTINE ## +-- Causes the loading of everything +-- first time called in main loop (after the init phase) because luaautomation has to initialize first. +function advtrains.load() + advtrains.avt_load() --loading advtrains. includes ndb at advtrains.ndb.load_data() + if atlatc then + atlatc.load() --includes interrupts + end + if advtrains_itm_init then + advtrains_itm_init() + end + init_load=true + no_action=false + atlog("[load_all]Loaded advtrains save files") +end + +--## MAIN SAVE ROUTINE ## +-- Causes the saving of everything +function advtrains.save(remove_players_from_wagons) + if not init_load then + --wait... we haven't loaded yet?! + atwarn("Instructed to save() but load() was never called!") + return + end + advtrains.avt_save(remove_players_from_wagons) --saving advtrains. includes ndb at advtrains.ndb.save_data() + if atlatc then + atlatc.save() + end + atprint("[save_all]Saved advtrains save files") +end +minetest.register_on_shutdown(advtrains.save) + +-- This chat command provides a solution to the problem known on the LinuxWorks server +-- There are many players that joined a single time, got on a train and then left forever +-- These players still occupy seats in the trains. +minetest.register_chatcommand("at_empty_seats", + { + params = "", -- Short parameter description + description = "Detach all players, especially the offline ones, from all trains. Use only when no one serious is on a train.", -- Full description + privs = {train_operator=true, server=true}, -- Require the "privs" privilege to run + func = function(name, param) + return advtrains.pcall(function() + atwarn("Data is being saved. While saving, advtrains will remove the players from trains. Save files will be reloaded afterwards!") + advtrains.save(true) + reload_saves() + end) + end, +}) +-- This chat command solves another problem: Trains getting randomly stuck. +minetest.register_chatcommand("at_reroute", + { + params = "", + description = "Delete all train routes, force them to recalculate", + privs = {train_operator=true}, -- Only train operator is required, since this is relatively safe. + func = function(name, param) + return advtrains.pcall(function() + atwarn("Train routes will be recalculated now") + advtrains.save(false) + reload_saves() + end) + end, +}) + |