aboutsummaryrefslogtreecommitdiff
path: root/src/debug.cpp
Commit message (Collapse)AuthorAge
* Fix some misspellings (#8104)Paul Ouellette2019-01-16
|
* Remove DSTACK support (#6346)Loïc Blot2017-08-30
| | | Debugstacks is not useful, we don't really use it, the DebugStack is not pertinent, gdb and lldb are better if we really want to debug.
* Modernize src/c* src/d* and src/e* files (#6263)Loïc Blot2017-08-17
| | | | | | | | | | | | | | | | | * Modernize src/c* src/d* and src/e* files * default operator * redundant init * delete default constructors on CraftDefinition childs (never used) * fix some missing init values * const ref fix reported by clang-tidy * ranged-based for loops * simple conditions & returns * empty stl function instead of size * emplace_back stl function instead of push_back + construct temp obj * auto for some iterators * code style fixes * c++ stl headers instead of C stl headers (stdio.h -> cstdio)
* C++11 patchset 9: move hardcoded init parameters to class definitions (part ↵Loïc Blot2017-06-16
| | | | | | | | | | | | | | | | | | | | | | | | 1) (#5984) * C++11 patchset 9: move hardcoded init parameters to class definitions C++11 introduced the possibility to define the default values directly in class definitions, do it on current code Also remove some unused attributes * CollisionInfo::bouncy * collisionMoveResult::collides_xy * collisionMoveResult::standing_on_unloaded * Clouds::speed * More constructor cleanups + some variables removal * remove only write guiFormSpecMenu::m_old_tooltip * move header included inside defintions in genericobject.h * remove some unused since years exception classes * remove unused & empty debug_stacks_init * remove unused & empty content_nodemeta_serialize_legacy * remove forgotten useless bool (bouncy) in collision.cpp code
* Remove threads.h and replace its definitions with their C++11 equivalents ↵ShadowNinja2017-06-11
| | | | | | (#5957) This also changes threadProc's signature, since C++11 supports arbitrary thread function signatures.
* Use C++11 mutexes only (remove compat code) (#5922)Loïc Blot2017-06-06
| | | | * Fix event LINT & remove default constructor/destructors * remove compat code & modernize autolock header
* Add server side ncurses terminalest312015-11-06
| | | | | | | | | | | | | | | | | | | | | | | | This adds a chat console the server owner can use for administration or to talk with players. It runs in its own thread, which makes the user interface immune to the server's lag, behaving just like a client, except timeout. As it uses the same console code as the f10 console, things like nick completion or a scroll buffer basically come for free. The terminal itself is written in a general way so that adding a client version later on is just about implementing an interface. Fatal errors are printed after the console exists and the ncurses terminal buffer gets cleaned up with endwin(), so that the error still remains visible. The server owner can chose their username their entered text will have in chat and where players can send PMs to. Once the username is secured with a password to prevent anybody to take over the server, the owner can execute admin tasks over the console. This change includes a contribution by @kahrl who has improved ncurses library detection.
* Fix C++11 compatibilitykwolekr2015-10-31
|
* Refactor thread utility interfacekwolekr2015-10-16
| | | | | - Add "thr_" prefix to thread utility functions - Compare threadid_ts in a portable manner, where possible
* Refactor loggingShadowNinja2015-10-14
| | | | | | | | | - Add warning log level - Change debug_log_level setting to enumeration string - Map Irrlicht log events to MT log events - Encapsulate log_* functions and global variables into a class, Logger - Unify dstream with standard logging mechanism - Unify core.debug() with standard core.log() script API
* Clean up threadingShadowNinja2015-08-23
| | | | | | | | | | | | | | | | | | | | * Rename everything. * Strip J prefix. * Change UpperCamelCase functions to lowerCamelCase. * Remove global (!) semaphore count mutex on OSX. * Remove semaphore count getter (unused, unsafe, depended on internal API functions on Windows, and used a hack on OSX). * Add `Atomic<type>`. * Make `Thread` handle thread names. * Add support for C++11 multi-threading. * Combine pthread and win32 sources. * Remove `ThreadStarted` (unused, unneeded). * Move some includes from the headers to the sources. * Move all of `Event` into its header (allows inlining with no new includes). * Make `Event` use `Semaphore` (except on Windows). * Move some porting functions into `Thread`. * Integrate logging with `Thread`. * Add threading test.
* Fix MSVC compile errorShadowNinja2015-03-27
|
* Clean up and tweak build systemShadowNinja2015-03-27
| | | | | | | | | | | | | | | | * Combine client and server man pages. * Update unit test options and available databases in man page. * Add `--worldname` to man page. * Fix a bunch of places where `"Minetest"` was used directly instead of `PROJECT_NAME`. * Disable server build by default on all operating systems. * Make `ENABLE_FREETYPE` not fail if FreeType isn't found. * Enable LevelDB, Redis, and FreeType detection by default. * Remove the `VERSION_PATCH_ORIG` hack. * Add option to search for and use system JSONCPP. * Remove broken LuaJIT version detection. * Rename `DISABLE_LUAJIT` to `ENABLE_LUAJIT`. * Rename `minetest_*` variables in `version.{h,cpp}` to `g_*`. * Clean up style of CMake files.
* For usages of assert() that are meant to persist in Release builds (when ↵Craig Robbins2015-03-07
| | | | NDEBUG is defined), replace those usages with persistent alternatives
* Create minidump on fatal Win32 exceptionskwolekr2015-02-02
| | | | | Remove software exception translator function, simplifying exception handler macros. FatalSystemExceptions are left unhandled.
* Performance fixes.onkrot2015-01-13
|
* Add support for Android 2.3+sapier2014-06-29
| | | | | | | | | | | | | There have been plenty of ppl involved in creating this version. I don't wanna mention names as I'm sure I'd forget someone so I just tell where help has been done: - The partial android versions done by various ppl - Testing on different android devices - reviewing code (especially the in core changes) - testing controls - reviewing texts A big thank you to everyone helping this to be completed!
* Cleanup jthread and fix win32 buildsapier2013-12-01
|
* Always use builtin JThread librarykwolekr2013-09-15
|
* Omnicleanup: header cleanup, add ModApiUtil shared between game and mainmenuKahrl2013-08-14
|
* Migrate to STL containers/algorithms.Ilya Zhuravlev2013-03-11
|
* Update Copyright YearsSfan52013-02-24
|
* Change Minetest-c55 to MinetestPilzAdam2013-02-24
|
* Optimize headersPerttu Ahola2012-06-17
|
* Switch the license to be LGPLv2/later, with small parts still remaining as ↵Perttu Ahola2012-06-05
| | | | GPLv2/later, by agreement of major contributors
* Remove useless debug output (log at info level)Perttu Ahola2012-03-11
|
* Clean up log messages everywherePerttu Ahola2012-03-11
|
* Improve debug stack printing interfacePerttu Ahola2011-11-29
|
* Prevent threadid_t from losing precision when casted on 64bit systemsq662011-08-11
|
* fixed warnings reported by cppcheckPerttu Ahola2011-04-11
|
* fixes toward mingw compatibilityPerttu Ahola2011-02-10
|
* local game connects to 127.0.0.1 instead of localhost (windows returns an ↵Perttu Ahola2011-02-08
| | | | ipv6 address sometimes which is not supported)
* backing up some stuffPerttu Ahola2011-01-26
|
* Added a more flexible path system (and fixed some minor stuff)Perttu Ahola2011-01-07
|
* better debug output in segfaults and stack overflows in windowsPerttu Ahola2010-12-27
|
* some work-in-progressPerttu Ahola2010-12-22
|
* license stuff (more to come)Perttu Ahola2010-11-29
|
* Windows bug fixesPerttu Ahola2010-11-29
|
* Initial filesPerttu Ahola2010-11-27
span class="hl slc">--pcall local no_action=false local function reload_saves() atwarn("Restoring saved state in 1 second...") no_action=true advtrains.lock_path_inval = false --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 advtrains.modpath = minetest.get_modpath("advtrains") --Advtrains dump (special treatment of pos and sigd) function atdump(t, intend) local str if type(t)=="table" then if t.x and t.y and t.z then str=minetest.pos_to_string(t) elseif t.p and t.s then -- interlocking sigd str="S["..minetest.pos_to_string(t.p).."/"..t.s.."]" elseif advtrains.lines and t.s and t.m then -- RwT str=advtrains.lines.rwt.to_string(t) else str="{" local intd = (intend or "") .. " " for k,v in pairs(t) do if type(k)~="string" or not string.match(k, "^path[_]?") then -- do not print anything path-related str = str .. "\n" .. intd .. atdump(k, intd) .. " = " ..atdump(v, intd) end end str = str .. "\n" .. (intend or "") .. "}" end elseif type(t)=="boolean" then if t then str="true" else str="false" end elseif type(t)=="function" then str="<function>" elseif type(t)=="userdata" then str="<userdata>" else str=""..t end return str end 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="" str=str..atdump(t).." " end end return str end atprint=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 --ONLY use this function for temporary debugging. for consistent debug prints use atprint atdebug=function(t, ...) local text=advtrains.print_concat_table({t, ...}) minetest.log("action", "[advtrains]"..text) minetest.chat_send_all("[advtrains]"..text) end if minetest.settings:get_bool("advtrains_enable_debugging") then atprint=function(t, ...) local context=advtrains.atprint_context_tid or "" if not context then return end local text=advtrains.print_concat_table({t, ...}) advtrains.drb_record(context, text) --atlog("@@",advtrains.atprint_context_tid,t,...) end dofile(advtrains.modpath.."/debugringbuffer.lua") end function assertt(var, typ) if type(var)~=typ then error("Assertion failed, variable has to be of type "..typ) end 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}} advtrains.fpath=minetest.get_worldpath().."/advtrains" dofile(advtrains.modpath.."/path.lua") dofile(advtrains.modpath.."/trainlogic.lua") dofile(advtrains.modpath.."/trainhud.lua") dofile(advtrains.modpath.."/trackplacer.lua") dofile(advtrains.modpath.."/copytool.lua") dofile(advtrains.modpath.."/tracks.lua") dofile(advtrains.modpath.."/occupation.lua") dofile(advtrains.modpath.."/atc.lua") dofile(advtrains.modpath.."/wagons.lua") dofile(advtrains.modpath.."/protection.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.."/log.lua") dofile(advtrains.modpath.."/passive.lua") if mesecon then dofile(advtrains.modpath.."/p_mesecon_iface.lua") end dofile(advtrains.modpath.."/lzb.lua") --load/save -- backup variables, used if someone should accidentally delete a sub-mod -- As of version 4, only used once during migration from version 3 to 4 -- Since version 4, each of the mods stores a separate save file. local MDS_interlocking, MDS_lines advtrains.fpath=minetest.get_worldpath().."/advtrains" dofile(advtrains.modpath.."/log.lua") function advtrains.read_component(name) local path = advtrains.fpath.."_"..name minetest.log("action", "[advtrains] loading "..path) local file, err = io.open(path, "r") if not file then minetest.log("warning", " Failed to read advtrains save data from file "..path..": "..(err or "Unknown Error")) minetest.log("warning", " (this is normal when first enabling advtrains on this world)") return end local tbl = minetest.deserialize(file:read("*a")) file:close() return tbl end function advtrains.avt_load() -- check for new, split advtrains save file local version = advtrains.read_component("version") local tbl if version and version == 4 then advtrains.load_version_4() return -- NOTE: From here, legacy loading code! elseif version and version == 3 then -- we are dealing with the split-up system minetest.log("action", "[advtrains] loading savefiles version 3") local il_save = { tcbs = true, ts = true, signalass = true, rs_locks = true, rs_callbacks = true, influence_points = true, npr_rails = true, } tbl={ trains = true, wagon_save = true, ptmap = true, atc = true, ndb = true, lines = true, version = 2, } for i,k in pairs(il_save) do il_save[i] = advtrains.read_component("interlocking_"..i) end for i,k in pairs(tbl) do tbl[i] = advtrains.read_component(i) end tbl["interlocking"] = il_save else local file, err = io.open(advtrains.fpath, "r") if not file then minetest.log("warning", " Failed to read advtrains save data from file "..advtrains.fpath..": "..(err or "Unknown Error")) minetest.log("warning", " (this is normal when first enabling advtrains on this world)") return else tbl = minetest.deserialize(file:read("*a")) file:close() end end if type(tbl) == "table" then if tbl.version then --congrats, we have the new save format. advtrains.trains = tbl.trains --Save the train id into the train table to avoid having to pass id around for id, train in pairs(advtrains.trains) do train.id = id end advtrains.wagons = tbl.wagon_save advtrains.player_to_train_mapping = tbl.ptmap or {} advtrains.ndb.load_data_pre_v4(tbl.ndb) advtrains.atc.load_data(tbl.atc) if advtrains.interlocking then advtrains.interlocking.db.load(tbl.interlocking) else MDS_interlocking = tbl.interlocking end if advtrains.lines then advtrains.lines.load(tbl.lines) else MDS_lines = tbl.lines end --remove wagon_save entries that are not part of a train local todel=advtrains.merge_tables(advtrains.wagon_save) for tid, train in pairs(advtrains.trains) do train.id = tid for _, wid in ipairs(train.trainparts) do todel[wid]=nil end end for wid, _ in pairs(todel) do atwarn("Removing unused wagon", wid, "from wagon_save table.") advtrains.wagon_save[wid]=nil end 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 -- moved from advtrains.load() atlatc.load_pre_v4() -- end of legacy loading code end function advtrains.load_version_4() minetest.log("action", "[advtrains] loading savefiles version 4 (serialize_lib)") --== load core == local at_save = serialize_lib.load_atomic(advtrains.fpath.."_core.ls") if at_save then advtrains.trains = at_save.trains --Save the train id into the train table to avoid having to pass id around for id, train in pairs(advtrains.trains) do train.id = id end advtrains.wagons = at_save.wagons advtrains.player_to_train_mapping = at_save.ptmap or {} advtrains.atc.load_data(at_save.atc) --remove wagon_save entries that are not part of a train local todel=advtrains.merge_tables(advtrains.wagon_save) for tid, train in pairs(advtrains.trains) do train.id = tid for _, wid in ipairs(train.trainparts) do todel[wid]=nil end end for wid, _ in pairs(todel) do atwarn("Removing unused wagon", wid, "from wagon_save table.") advtrains.wagon_save[wid]=nil end end --== load ndb serialize_lib.load_atomic(advtrains.fpath.."_ndb4.ls", advtrains.ndb.load_callback) --== load interlocking == if advtrains.interlocking then local il_save = serialize_lib.load_atomic(advtrains.fpath.."_interlocking.ls") if il_save then advtrains.interlocking.db.load(il_save) end end --== load lines == if advtrains.lines then local ln_save = serialize_lib.load_atomic(advtrains.fpath.."_lines.ls") if ln_save then advtrains.lines.load(ln_save) end end --== load luaatc == if atlatc then local la_save = serialize_lib.load_atomic(advtrains.fpath.."_atlatc.ls") if la_save then atlatc.load(la_save) end end end advtrains.save_component = function (tbl, name) -- Saves each component of the advtrains file separately -- -- required for now to shrink the advtrains db to overcome lua -- limitations. -- Note: as of version 4, only used for the "advtrains_version" file local datastr = minetest.serialize(tbl) if not datastr then minetest.log("error", " Failed to serialize advtrains save data!") return end local path = advtrains.fpath.."_"..name local success = minetest.safe_file_write(path, datastr) if not success then minetest.log("error", " Failed to write advtrains save data to file "..path) end end advtrains.avt_save = function(remove_players_from_wagons) --atdebug("Saving advtrains files (version 4)") if remove_players_from_wagons then for w_id, data in pairs(advtrains.wagons) do data.seatp={} end advtrains.player_to_train_mapping={} end local tmp_trains={} for id, train in pairs(advtrains.trains) do --first, deep_copy the train if #train.trainparts > 0 then local v=advtrains.save_keys(train, { "last_pos", "last_connid", "last_frac", "velocity", "tarvelocity", "trainparts", "recently_collided_with_env", "atc_brake_target", "atc_wait_finish", "atc_command", "atc_delay", "door_open", "text_outside", "text_inside", "line", "routingcode", "il_sections", "speed_restriction", "is_shunt", "points_split", "autocouple", "ars_disable", }) --then save it tmp_trains[id]=v else atwarn("Train",id,"had no wagons left because of some bug. It is being deleted. Wave it goodbye!") advtrains.remove_train(id) end end for id, wdata in pairs(advtrains.wagons) do local _,proto = advtrains.get_wagon_prototype(wdata) if proto.has_inventory then local inv=minetest.get_inventory({type="detached", name="advtrains_wgn_"..id}) if inv then -- inventory is not initialized when wagon was never loaded -- TOOD: What happens with unloading rails when they don't find the inventory? wdata.ser_inv=advtrains.serialize_inventory(inv) end end -- TODO apply save-keys here too -- TODO temp wdata.dcpl_lock = nil end --versions: -- 1 - Initial new save format. -- 2 - version as of tss branch 11-2018+ -- 3 - split-up savefile system by gabriel -- 4 - serialize_lib -- save of core advtrains local at_save={ trains = tmp_trains, wagons = advtrains.wagons, ptmap = advtrains.player_to_train_mapping, atc = advtrains.atc.save_data(), } --save of interlocking local il_save if advtrains.interlocking then il_save = advtrains.interlocking.db.save() else il_save = MDS_interlocking end -- save of lines local ln_save if advtrains.lines then ln_save = advtrains.lines.save() else ln_save = MDS_lines end -- save of luaatc local la_save if atlatc then la_save = atlatc.save() end -- parts table for serialize_lib API: -- any table that is nil will not be included and thus not be overwritten local parts_table = { ["core.ls"] = at_save, ["interlocking.ls"] = il_save, ["lines.ls"] = ln_save, ["atlatc.ls"] = la_save, ["ndb4.ls"] = true, -- data not used } local callbacks_table = { ["ndb4.ls"] = advtrains.ndb.save_callback } if DUMP_DEBUG_SAVE then local file, err = io.open(advtrains.fpath.."_DUMP", "w") if err then return end file:write(dump(parts_table)) file:close() end --THE MAGIC HAPPENS HERE local succ, err = serialize_lib.save_atomic_multiple(parts_table, advtrains.fpath.."_", callbacks_table) if not succ then atwarn("Saving failed: "..err) else -- store version advtrains.save_component(4, "version") end end --## MAIN LOOP ##-- --Calls all subsequent main tasks of both advtrains and atlatc local init_load=false local save_interval=60 local save_timer=save_interval advtrains.mainloop_runcnt=0 local t = 0 minetest.register_globalstep(function(dtime_mt) if no_action then -- the advtrains globalstep is skipped by command. Return immediately return end 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 local dtime = dtime_mt if GENERATE_ATRICIFIAL_LAG then dtime = HOW_MANY_LAG if os.clock()<t then return end t = os.clock()+HOW_MANY_LAG 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 if advtrains.lines then advtrains.lines.step(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) --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 == No longer loading here. Now part of avt_save() legacy loading. 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 if no_action then atlog("[save] Saving requested externally, but Advtrains step is disabled. Not saving any data as state may be inconsistent.") 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") --TODO very simple yet hacky workaround for the "green signals" bug advtrains.invalidate_all_paths() 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) 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, }) -- 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) advtrains.invalidate_all_paths() return true, "Successfully invalidated train routes" end, }) minetest.register_chatcommand("at_disable_step", { params = "<yes/no>", description = "Disable the advtrains globalstep temporarily", privs = {server=true}, func = function(name, param) if minetest.is_yes(param) then -- disable everything, and turn off saving no_action = true; atwarn("The advtrains globalstep has been disabled. Trains are not moving, and no data is saved! Run '/at_disable_step no' to enable again!") return true, "Disabled advtrains successfully" elseif no_action then atwarn("Re-enabling advtrains globalstep...") reload_saves() return true else return false, "Advtrains is already running normally!" end end, }) advtrains.is_no_action = function() return no_action end local tot=(os.clock()-lot)*1000 minetest.log("action", "[advtrains] Loaded in "..tot.."ms")