Add pcall wrapper to prevent server crashes when advtrains throws an error

Instead, read save files again and restore state before the crash
Rebased to latest commit
This commit is contained in:
orwell96 2017-04-05 13:57:09 +02:00
parent 337db2a573
commit f42b01c74b
9 changed files with 93 additions and 1 deletions

Binary file not shown.

View File

@ -92,12 +92,17 @@ advtrains.register_tracks("default", {
return {
after_place_node=apn_func,
after_dig_node=function(pos)
return advtrains.pcall(function()
advtrains.invalidate_all_paths()
advtrains.ndb.clear(pos)
local pts=minetest.pos_to_string(pos)
atc.controllers[pts]=nil
end)
end,
on_receive_fields = function(pos, formname, fields, player)
return advtrains.pcall(function()
if advtrains.is_protected(pos, player:get_player_name()) then
minetest.record_protection_violation(pos, player:get_player_name())
return
@ -135,6 +140,7 @@ advtrains.register_tracks("default", {
atc.send_command(pos)
end
end
end)
end,
advtrains = {
on_train_enter = function(pos, train_id)

View File

@ -31,6 +31,8 @@ minetest.register_entity("advtrains:discouple", {
end,
get_staticdata=function() return "DISCOUPLE" end,
on_punch=function(self, player)
return advtrains.pcall(function()
--only if player owns at least one wagon next to this
local own=player:get_player_name()
if self.wagon.owner and self.wagon.owner==own and not self.wagon.lock_couples then
@ -54,8 +56,11 @@ minetest.register_entity("advtrains:discouple", {
else
minetest.chat_send_player(own, attrans("You need to own at least one neighboring wagon to destroy this couple."))
end
end)
end,
on_step=function(self, dtime)
return advtrains.pcall(function()
local t=os.clock()
if not self.wagon then
self.object:remove()
@ -77,6 +82,7 @@ minetest.register_entity("advtrains:discouple", {
self.updatepct_timer=2
end
atprintbm("discouple_step", t)
end)
end,
})
@ -99,15 +105,20 @@ minetest.register_entity("advtrains:couple", {
is_couple=true,
on_activate=function(self, staticdata)
return advtrains.pcall(function()
if staticdata=="COUPLE" then
--couple entities have no right to exist further...
atprint("Couple loaded from staticdata, destroying")
self.object:remove()
return
end
end)
end,
get_staticdata=function(self) return "COUPLE" end,
on_rightclick=function(self, clicker)
return advtrains.pcall(function()
if not self.train_id_1 or not self.train_id_2 then return end
local id1, id2=self.train_id_1, self.train_id_2
@ -128,8 +139,11 @@ minetest.register_entity("advtrains:couple", {
end
atprint("Coupled trains", id1, id2)
self.object:remove()
end)
end,
on_step=function(self, dtime)
return advtrains.pcall(function()
local t=os.clock()
if not self.train_id_1 or not self.train_id_2 then atprint("Couple: train ids not set!") self.object:remove() return end
local train1=advtrains.trains[self.train_id_1]
@ -167,5 +181,6 @@ minetest.register_entity("advtrains:couple", {
end
end
atprintbm("couple step", t)
end)
end,
})

View File

@ -9,6 +9,29 @@ end
advtrains = {trains={}, wagon_save={}, player_to_train_mapping={}}
--pcall
local no_action=true
function advtrains.pcall(fun)
if no_action then return end
local succ, err, return1, return2, return3, return4=pcall(fun)
if not succ then
atwarn("Lua Error occured: ", err)
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, advtrains.load)
else
return err, return1, return2, return3, return4
end
end
advtrains.modpath = minetest.get_modpath("advtrains")
function advtrains.print_concat_table(a)
@ -94,6 +117,9 @@ dofile(advtrains.modpath.."/craft_items.lua")
--load/save
advtrains.fpath=minetest.get_worldpath().."/advtrains"
function advtrains.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"))
@ -142,6 +168,10 @@ else
end
file:close()
end
no_action=false
end
advtrains.load()
advtrains.save = function()
--atprint("saving")

View File

@ -203,6 +203,8 @@ minetest.register_abm({
nodenames = {"group:save_in_nodedb"},
run_at_every_load = true,
action = function(pos, node)
return advtrains.pcall(function()
local cid=ndbget(pos.x, pos.y, pos.z)
if cid then
--if in database, detect changes and apply.
@ -227,14 +229,18 @@ minetest.register_abm({
atprint("nodedb: ", pos, "not in database")
ndb.update(pos, node)
end
end)
end,
interval=10,
chance=1,
})
minetest.register_on_dignode(function(pos, oldnode, digger)
return advtrains.pcall(function()
ndb.clear(pos)
end)
end)
function ndb.get_nodes()
return ndb_nodes

View File

@ -187,6 +187,8 @@ function tp.register_track_placer(nnprefix, imgprefix, dispname)
wield_image = imgprefix.."_placer.png",
groups={},
on_place = function(itemstack, placer, pointed_thing)
return advtrains.pcall(function()
local name = placer:get_player_name()
if not name then
return itemstack
@ -207,6 +209,7 @@ function tp.register_track_placer(nnprefix, imgprefix, dispname)
end
end
return itemstack
end)
end,
})
end
@ -220,6 +223,7 @@ minetest.register_craftitem("advtrains:trackworker",{
wield_image = "advtrains_trackworker.png",
stack_max = 1,
on_place = function(itemstack, placer, pointed_thing)
return advtrains.pcall(function()
local name = placer:get_player_name()
if not name then
return
@ -260,8 +264,11 @@ minetest.register_craftitem("advtrains:trackworker",{
advtrains.ndb.swap_node(pos, {name=nnprefix.."_"..suffix..modext[modpos+1], param2=node.param2})
end
end
end)
end,
on_use=function(itemstack, user, pointed_thing)
return advtrains.pcall(function()
local name = user:get_player_name()
if not name then
return
@ -292,6 +299,7 @@ minetest.register_craftitem("advtrains:trackworker",{
else
atprint(name, dump(tp.tracks))
end
end)
end,
})

View File

@ -40,6 +40,8 @@ advtrains.save_interval=10
advtrains.save_timer=advtrains.save_interval
minetest.register_globalstep(function(dtime_mt)
return advtrains.pcall(function()
--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
@ -81,8 +83,11 @@ minetest.register_globalstep(function(dtime_mt)
atprintbm("trainsteps", t)
endstep()
end)
end)
minetest.register_on_joinplayer(function(player)
return advtrains.pcall(function()
local pname=player:get_player_name()
local id=advtrains.player_to_train_mapping[pname]
if id then
@ -101,8 +106,11 @@ minetest.register_on_joinplayer(function(player)
end
end
end)
end)
minetest.register_on_dieplayer(function(player)
return advtrains.pcall(function()
local pname=player:get_player_name()
local id=advtrains.player_to_train_mapping[pname]
if id then
@ -117,6 +125,7 @@ minetest.register_on_dieplayer(function(player)
end
end
end)
end)
--[[
train step structure:

View File

@ -50,6 +50,7 @@ function wagon:on_activate(sd_uid, dtime_s)
end
function wagon:get_staticdata()
return advtrains.pcall(function()
if not self:ensure_init() then return end
atprint("[wagon "..((self.unique_id and self.unique_id~="" and self.unique_id) or "no-id").."]: saving to wagon_save")
--serialize inventory, if it has one
@ -63,6 +64,7 @@ function wagon:get_staticdata()
advtrains.wagon_save[self.unique_id].name=nil
advtrains.wagon_save[self.unique_id].object=nil
return self.unique_id
end)
end
--returns: uid of wagon
function wagon:init_new_instance(train_id, properties)
@ -147,6 +149,7 @@ end
-- Remove the wagon
function wagon:on_punch(puncher, time_from_last_punch, tool_capabilities, direction)
return advtrains.pcall(function()
if not self:ensure_init() then return end
if not puncher or not puncher:is_player() then
return
@ -177,6 +180,7 @@ function wagon:on_punch(puncher, time_from_last_punch, tool_capabilities, direct
inv:add_item("main", item)
end
end
end)
end
function wagon:destroy()
--some rules:
@ -211,6 +215,8 @@ end
function wagon:on_step(dtime)
return advtrains.pcall(function()
if not self:ensure_init() then return end
local t=os.clock()
@ -465,6 +471,7 @@ function wagon:on_step(dtime)
self.old_acceleration_vector=accelerationvec
self.old_yaw=yaw
atprintbm("wagon step", t)
end)
end
function advtrains.get_real_path_index(train, pit)
@ -485,6 +492,8 @@ function advtrains.get_real_path_index(train, pit)
end
function wagon:on_rightclick(clicker)
return advtrains.pcall(function()
if not self:ensure_init() then return end
if not clicker or not clicker:is_player() then
return
@ -564,6 +573,7 @@ function wagon:on_rightclick(clicker)
self:show_get_on_form(pname)
end
end
end)
end
function wagon:get_on(clicker, seatno)
@ -708,6 +718,8 @@ function wagon:show_wagon_properties(pname)
minetest.show_formspec(pname, "advtrains_prop_"..self.unique_id, form)
end
minetest.register_on_player_receive_fields(function(player, formname, fields)
return advtrains.pcall(function()
local uid=string.match(formname, "^advtrains_geton_(.+)$")
if uid then
for _,wagon in pairs(minetest.luaentities) do
@ -780,6 +792,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
end
end
end)
end)
function wagon:seating_from_key_helper(pname, fields, no)
local sgr=self.seats[no].group
for _,access in ipairs(self.seat_groups[sgr].access_to) do
@ -841,6 +854,7 @@ function advtrains.register_wagon(sysname, prototype, desc, inv_img)
stack_max = 1,
on_place = function(itemstack, placer, pointed_thing)
return advtrains.pcall(function()
if not pointed_thing.type == "node" then
return
end
@ -876,6 +890,7 @@ function advtrains.register_wagon(sysname, prototype, desc, inv_img)
end
return itemstack
end)
end,
})
end

View File

@ -22,6 +22,8 @@ function iq.add(t, pos, evtdata)
end
minetest.register_globalstep(function(dtime)
return advtrains.pcall(function()
if run then
timer=timer + math.min(dtime, 0.2)
for i=1,#queue do
@ -42,6 +44,7 @@ minetest.register_globalstep(function(dtime)
end
end
end)
end)