Reduce ServerEnvironment propagation (#9642)

ServerEnvironment is a huge class with many accessors. In various places it's not needed

Remove it to reduce the ServerEnvironment view.

Idea here is to reduce size of some of our objects to transport lightweight managers and permit easier testing

Pathfinder is now tied to a generic map, not a ServerMap, it can be
ported to client
This commit is contained in:
Loïc Blot 2020-04-11 19:59:43 +02:00 committed by GitHub
parent 5146086a64
commit 5cc06e4748
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 71 additions and 118 deletions

@ -25,7 +25,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "util/numeric.h" #include "util/numeric.h"
#include "map.h" #include "map.h"
#include "mapblock.h" #include "mapblock.h"
#include "serverenvironment.h"
#include "nodedef.h" #include "nodedef.h"
#include "treegen.h" #include "treegen.h"
#include "voxelalgorithms.h" #include "voxelalgorithms.h"
@ -120,10 +119,9 @@ void make_tree(MMVManip &vmanip, v3s16 p0, bool is_apple_tree,
// L-System tree LUA spawner // L-System tree LUA spawner
treegen::error spawn_ltree(ServerEnvironment *env, v3s16 p0, treegen::error spawn_ltree(ServerMap *map, v3s16 p0,
const NodeDefManager *ndef, const TreeDef &tree_definition) const NodeDefManager *ndef, const TreeDef &tree_definition)
{ {
ServerMap *map = &env->getServerMap();
std::map<v3s16, MapBlock*> modified_blocks; std::map<v3s16, MapBlock*> modified_blocks;
MMVManip vmanip(map); MMVManip vmanip(map);
v3s16 tree_blockp = getNodeBlockPos(p0); v3s16 tree_blockp = getNodeBlockPos(p0);

@ -26,8 +26,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
class MMVManip; class MMVManip;
class NodeDefManager; class NodeDefManager;
class ServerEnvironment; class ServerMap;
namespace treegen { namespace treegen {
@ -73,7 +72,7 @@ namespace treegen {
treegen::error make_ltree(MMVManip &vmanip, v3s16 p0, treegen::error make_ltree(MMVManip &vmanip, v3s16 p0,
const NodeDefManager *ndef, TreeDef tree_definition); const NodeDefManager *ndef, TreeDef tree_definition);
// Spawn L-systems tree from LUA // Spawn L-systems tree from LUA
treegen::error spawn_ltree (ServerEnvironment *env, v3s16 p0, treegen::error spawn_ltree (ServerMap *map, v3s16 p0,
const NodeDefManager *ndef, const TreeDef &tree_definition); const NodeDefManager *ndef, const TreeDef &tree_definition);
// L-System tree gen helper functions // L-System tree gen helper functions

@ -23,8 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
/******************************************************************************/ /******************************************************************************/
#include "pathfinder.h" #include "pathfinder.h"
#include "serverenvironment.h" #include "map.h"
#include "server.h"
#include "nodedef.h" #include "nodedef.h"
//#define PATHFINDER_DEBUG //#define PATHFINDER_DEBUG
@ -180,10 +179,8 @@ private:
class Pathfinder { class Pathfinder {
public: public:
/** Pathfinder() = delete;
* default constructor Pathfinder(Map *map, const NodeDefManager *ndef) : m_map(map), m_ndef(ndef) {}
*/
Pathfinder() = default;
~Pathfinder(); ~Pathfinder();
@ -197,8 +194,7 @@ public:
* @param max_drop maximum number of blocks a path may drop * @param max_drop maximum number of blocks a path may drop
* @param algo Algorithm to use for finding a path * @param algo Algorithm to use for finding a path
*/ */
std::vector<v3s16> getPath(ServerEnvironment *env, std::vector<v3s16> getPath(v3s16 source,
v3s16 source,
v3s16 destination, v3s16 destination,
unsigned int searchdistance, unsigned int searchdistance,
unsigned int max_jump, unsigned int max_jump,
@ -328,7 +324,9 @@ private:
friend class GridNodeContainer; friend class GridNodeContainer;
GridNodeContainer *m_nodes_container = nullptr; GridNodeContainer *m_nodes_container = nullptr;
ServerEnvironment *m_env = 0; /**< minetest environment pointer */ Map *m_map = nullptr;
const NodeDefManager *m_ndef = nullptr;
friend class PathfinderCompareHeuristic; friend class PathfinderCompareHeuristic;
@ -410,7 +408,7 @@ class PathfinderCompareHeuristic
/* implementation */ /* implementation */
/******************************************************************************/ /******************************************************************************/
std::vector<v3s16> get_path(ServerEnvironment* env, std::vector<v3s16> get_path(Map* map, const NodeDefManager *ndef,
v3s16 source, v3s16 source,
v3s16 destination, v3s16 destination,
unsigned int searchdistance, unsigned int searchdistance,
@ -418,10 +416,7 @@ std::vector<v3s16> get_path(ServerEnvironment* env,
unsigned int max_drop, unsigned int max_drop,
PathAlgorithm algo) PathAlgorithm algo)
{ {
Pathfinder searchclass; return Pathfinder(map, ndef).getPath(source, destination,
return searchclass.getPath(env,
source, destination,
searchdistance, max_jump, max_drop, algo); searchdistance, max_jump, max_drop, algo);
} }
@ -521,13 +516,13 @@ void PathGridnode::setCost(v3s16 dir, const PathCost &cost)
void GridNodeContainer::initNode(v3s16 ipos, PathGridnode *p_node) void GridNodeContainer::initNode(v3s16 ipos, PathGridnode *p_node)
{ {
const NodeDefManager *ndef = m_pathf->m_env->getGameDef()->ndef(); const NodeDefManager *ndef = m_pathf->m_ndef;
PathGridnode &elem = *p_node; PathGridnode &elem = *p_node;
v3s16 realpos = m_pathf->getRealPos(ipos); v3s16 realpos = m_pathf->getRealPos(ipos);
MapNode current = m_pathf->m_env->getMap().getNode(realpos); MapNode current = m_pathf->m_map->getNode(realpos);
MapNode below = m_pathf->m_env->getMap().getNode(realpos + v3s16(0, -1, 0)); MapNode below = m_pathf->m_map->getNode(realpos + v3s16(0, -1, 0));
if ((current.param0 == CONTENT_IGNORE) || if ((current.param0 == CONTENT_IGNORE) ||
@ -610,8 +605,7 @@ PathGridnode &MapGridNodeContainer::access(v3s16 p)
/******************************************************************************/ /******************************************************************************/
std::vector<v3s16> Pathfinder::getPath(ServerEnvironment *env, std::vector<v3s16> Pathfinder::getPath(v3s16 source,
v3s16 source,
v3s16 destination, v3s16 destination,
unsigned int searchdistance, unsigned int searchdistance,
unsigned int max_jump, unsigned int max_jump,
@ -624,15 +618,8 @@ std::vector<v3s16> Pathfinder::getPath(ServerEnvironment *env,
#endif #endif
std::vector<v3s16> retval; std::vector<v3s16> retval;
//check parameters
if (env == 0) {
ERROR_TARGET << "Missing environment pointer" << std::endl;
return retval;
}
//initialization //initialization
m_searchdistance = searchdistance; m_searchdistance = searchdistance;
m_env = env;
m_maxjump = max_jump; m_maxjump = max_jump;
m_maxdrop = max_drop; m_maxdrop = max_drop;
m_start = source; m_start = source;
@ -681,15 +668,14 @@ std::vector<v3s16> Pathfinder::getPath(ServerEnvironment *env,
#endif #endif
//fail if source or destination is walkable //fail if source or destination is walkable
const NodeDefManager *ndef = m_env->getGameDef()->ndef(); MapNode node_at_pos = m_map->getNode(destination);
MapNode node_at_pos = m_env->getMap().getNode(destination); if (m_ndef->get(node_at_pos).walkable) {
if (ndef->get(node_at_pos).walkable) {
VERBOSE_TARGET << "Destination is walkable. " << VERBOSE_TARGET << "Destination is walkable. " <<
"Pos: " << PP(destination) << std::endl; "Pos: " << PP(destination) << std::endl;
return retval; return retval;
} }
node_at_pos = m_env->getMap().getNode(source); node_at_pos = m_map->getNode(source);
if (ndef->get(node_at_pos).walkable) { if (m_ndef->get(node_at_pos).walkable) {
VERBOSE_TARGET << "Source is walkable. " << VERBOSE_TARGET << "Source is walkable. " <<
"Pos: " << PP(source) << std::endl; "Pos: " << PP(source) << std::endl;
return retval; return retval;
@ -843,7 +829,6 @@ v3s16 Pathfinder::getRealPos(v3s16 ipos)
/******************************************************************************/ /******************************************************************************/
PathCost Pathfinder::calcCost(v3s16 pos, v3s16 dir) PathCost Pathfinder::calcCost(v3s16 pos, v3s16 dir)
{ {
const NodeDefManager *ndef = m_env->getGameDef()->ndef();
PathCost retval; PathCost retval;
retval.updated = true; retval.updated = true;
@ -857,7 +842,7 @@ PathCost Pathfinder::calcCost(v3s16 pos, v3s16 dir)
return retval; return retval;
} }
MapNode node_at_pos2 = m_env->getMap().getNode(pos2); MapNode node_at_pos2 = m_map->getNode(pos2);
//did we get information about node? //did we get information about node?
if (node_at_pos2.param0 == CONTENT_IGNORE ) { if (node_at_pos2.param0 == CONTENT_IGNORE ) {
@ -866,9 +851,9 @@ PathCost Pathfinder::calcCost(v3s16 pos, v3s16 dir)
return retval; return retval;
} }
if (!ndef->get(node_at_pos2).walkable) { if (!m_ndef->get(node_at_pos2).walkable) {
MapNode node_below_pos2 = MapNode node_below_pos2 =
m_env->getMap().getNode(pos2 + v3s16(0, -1, 0)); m_map->getNode(pos2 + v3s16(0, -1, 0));
//did we get information about node? //did we get information about node?
if (node_below_pos2.param0 == CONTENT_IGNORE ) { if (node_below_pos2.param0 == CONTENT_IGNORE ) {
@ -878,7 +863,7 @@ PathCost Pathfinder::calcCost(v3s16 pos, v3s16 dir)
} }
//test if the same-height neighbor is suitable //test if the same-height neighbor is suitable
if (ndef->get(node_below_pos2).walkable) { if (m_ndef->get(node_below_pos2).walkable) {
//SUCCESS! //SUCCESS!
retval.valid = true; retval.valid = true;
retval.value = 1; retval.value = 1;
@ -889,19 +874,19 @@ PathCost Pathfinder::calcCost(v3s16 pos, v3s16 dir)
else { else {
//test if we can fall a couple of nodes (m_maxdrop) //test if we can fall a couple of nodes (m_maxdrop)
v3s16 testpos = pos2 + v3s16(0, -1, 0); v3s16 testpos = pos2 + v3s16(0, -1, 0);
MapNode node_at_pos = m_env->getMap().getNode(testpos); MapNode node_at_pos = m_map->getNode(testpos);
while ((node_at_pos.param0 != CONTENT_IGNORE) && while ((node_at_pos.param0 != CONTENT_IGNORE) &&
(!ndef->get(node_at_pos).walkable) && (!m_ndef->get(node_at_pos).walkable) &&
(testpos.Y > m_limits.MinEdge.Y)) { (testpos.Y > m_limits.MinEdge.Y)) {
testpos += v3s16(0, -1, 0); testpos += v3s16(0, -1, 0);
node_at_pos = m_env->getMap().getNode(testpos); node_at_pos = m_map->getNode(testpos);
} }
//did we find surface? //did we find surface?
if ((testpos.Y >= m_limits.MinEdge.Y) && if ((testpos.Y >= m_limits.MinEdge.Y) &&
(node_at_pos.param0 != CONTENT_IGNORE) && (node_at_pos.param0 != CONTENT_IGNORE) &&
(ndef->get(node_at_pos).walkable)) { (m_ndef->get(node_at_pos).walkable)) {
if ((pos2.Y - testpos.Y - 1) <= m_maxdrop) { if ((pos2.Y - testpos.Y - 1) <= m_maxdrop) {
//SUCCESS! //SUCCESS!
retval.valid = true; retval.valid = true;
@ -927,34 +912,34 @@ PathCost Pathfinder::calcCost(v3s16 pos, v3s16 dir)
v3s16 targetpos = pos2; // position for jump target v3s16 targetpos = pos2; // position for jump target
v3s16 jumppos = pos; // position for checking if jumping space is free v3s16 jumppos = pos; // position for checking if jumping space is free
MapNode node_target = m_env->getMap().getNode(targetpos); MapNode node_target = m_map->getNode(targetpos);
MapNode node_jump = m_env->getMap().getNode(jumppos); MapNode node_jump = m_map->getNode(jumppos);
bool headbanger = false; // true if anything blocks jumppath bool headbanger = false; // true if anything blocks jumppath
while ((node_target.param0 != CONTENT_IGNORE) && while ((node_target.param0 != CONTENT_IGNORE) &&
(ndef->get(node_target).walkable) && (m_ndef->get(node_target).walkable) &&
(targetpos.Y < m_limits.MaxEdge.Y)) { (targetpos.Y < m_limits.MaxEdge.Y)) {
//if the jump would hit any solid node, discard //if the jump would hit any solid node, discard
if ((node_jump.param0 == CONTENT_IGNORE) || if ((node_jump.param0 == CONTENT_IGNORE) ||
(ndef->get(node_jump).walkable)) { (m_ndef->get(node_jump).walkable)) {
headbanger = true; headbanger = true;
break; break;
} }
targetpos += v3s16(0, 1, 0); targetpos += v3s16(0, 1, 0);
jumppos += v3s16(0, 1, 0); jumppos += v3s16(0, 1, 0);
node_target = m_env->getMap().getNode(targetpos); node_target = m_map->getNode(targetpos);
node_jump = m_env->getMap().getNode(jumppos); node_jump = m_map->getNode(jumppos);
} }
//check headbanger one last time //check headbanger one last time
if ((node_jump.param0 == CONTENT_IGNORE) || if ((node_jump.param0 == CONTENT_IGNORE) ||
(ndef->get(node_jump).walkable)) { (m_ndef->get(node_jump).walkable)) {
headbanger = true; headbanger = true;
} }
//did we find surface without banging our head? //did we find surface without banging our head?
if ((!headbanger) && (targetpos.Y <= m_limits.MaxEdge.Y) && if ((!headbanger) && (targetpos.Y <= m_limits.MaxEdge.Y) &&
(!ndef->get(node_target).walkable)) { (!m_ndef->get(node_target).walkable)) {
if (targetpos.Y - pos2.Y <= m_maxjump) { if (targetpos.Y - pos2.Y <= m_maxjump) {
//SUCCESS! //SUCCESS!
@ -1254,21 +1239,20 @@ v3s16 Pathfinder::walkDownwards(v3s16 pos, unsigned int max_down) {
if (max_down == 0) if (max_down == 0)
return pos; return pos;
v3s16 testpos = v3s16(pos); v3s16 testpos = v3s16(pos);
MapNode node_at_pos = m_env->getMap().getNode(testpos); MapNode node_at_pos = m_map->getNode(testpos);
const NodeDefManager *ndef = m_env->getGameDef()->ndef();
unsigned int down = 0; unsigned int down = 0;
while ((node_at_pos.param0 != CONTENT_IGNORE) && while ((node_at_pos.param0 != CONTENT_IGNORE) &&
(!ndef->get(node_at_pos).walkable) && (!m_ndef->get(node_at_pos).walkable) &&
(testpos.Y > m_limits.MinEdge.Y) && (testpos.Y > m_limits.MinEdge.Y) &&
(down <= max_down)) { (down <= max_down)) {
testpos += v3s16(0, -1, 0); testpos += v3s16(0, -1, 0);
down++; down++;
node_at_pos = m_env->getMap().getNode(testpos); node_at_pos = m_map->getNode(testpos);
} }
//did we find surface? //did we find surface?
if ((testpos.Y >= m_limits.MinEdge.Y) && if ((testpos.Y >= m_limits.MinEdge.Y) &&
(node_at_pos.param0 != CONTENT_IGNORE) && (node_at_pos.param0 != CONTENT_IGNORE) &&
(ndef->get(node_at_pos).walkable)) { (m_ndef->get(node_at_pos).walkable)) {
if (down == 0) { if (down == 0) {
pos = testpos; pos = testpos;
} else if ((down - 1) <= max_down) { } else if ((down - 1) <= max_down) {

@ -29,7 +29,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
/* Forward declarations */ /* Forward declarations */
/******************************************************************************/ /******************************************************************************/
class ServerEnvironment; class NodeDefManager;
class Map;
/******************************************************************************/ /******************************************************************************/
/* Typedefs and macros */ /* Typedefs and macros */
@ -54,7 +55,7 @@ typedef enum {
/******************************************************************************/ /******************************************************************************/
/** c wrapper function to use from scriptapi */ /** c wrapper function to use from scriptapi */
std::vector<v3s16> get_path(ServerEnvironment *env, std::vector<v3s16> get_path(Map *map, const NodeDefManager *ndef,
v3s16 source, v3s16 source,
v3s16 destination, v3s16 destination,
unsigned int searchdistance, unsigned int searchdistance,

@ -577,7 +577,7 @@ int ModApiEnvMod::l_get_node_timer(lua_State *L)
// Do it // Do it
v3s16 p = read_v3s16(L, 1); v3s16 p = read_v3s16(L, 1);
NodeTimerRef::create(L, p, env); NodeTimerRef::create(L, p, &env->getServerMap());
return 1; return 1;
} }
@ -1193,7 +1193,7 @@ int ModApiEnvMod::l_find_path(lua_State *L)
algo = PA_DIJKSTRA; algo = PA_DIJKSTRA;
} }
std::vector<v3s16> path = get_path(env, pos1, pos2, std::vector<v3s16> path = get_path(&env->getServerMap(), env->getGameDef()->ndef(), pos1, pos2,
searchdistance, max_jump, max_drop, algo); searchdistance, max_jump, max_drop, algo);
if (!path.empty()) { if (!path.empty()) {
@ -1257,8 +1257,9 @@ int ModApiEnvMod::l_spawn_tree(lua_State *L)
else else
return 0; return 0;
ServerMap *map = &env->getServerMap();
treegen::error e; treegen::error e;
if ((e = treegen::spawn_ltree (env, p0, ndef, tree_def)) != treegen::SUCCESS) { if ((e = treegen::spawn_ltree (map, p0, ndef, tree_def)) != treegen::SUCCESS) {
if (e == treegen::UNBALANCED_BRACKETS) { if (e == treegen::UNBALANCED_BRACKETS) {
luaL_error(L, "spawn_tree(): closing ']' has no matching opening bracket"); luaL_error(L, "spawn_tree(): closing ']' has no matching opening bracket");
} else { } else {

@ -41,11 +41,9 @@ int NodeTimerRef::l_set(lua_State *L)
{ {
MAP_LOCK_REQUIRED; MAP_LOCK_REQUIRED;
NodeTimerRef *o = checkobject(L, 1); NodeTimerRef *o = checkobject(L, 1);
ServerEnvironment *env = o->m_env;
if(env == NULL) return 0;
f32 t = readParam<float>(L,2); f32 t = readParam<float>(L,2);
f32 e = readParam<float>(L,3); f32 e = readParam<float>(L,3);
env->getMap().setNodeTimer(NodeTimer(t, e, o->m_p)); o->m_map->setNodeTimer(NodeTimer(t, e, o->m_p));
return 0; return 0;
} }
@ -53,10 +51,8 @@ int NodeTimerRef::l_start(lua_State *L)
{ {
MAP_LOCK_REQUIRED; MAP_LOCK_REQUIRED;
NodeTimerRef *o = checkobject(L, 1); NodeTimerRef *o = checkobject(L, 1);
ServerEnvironment *env = o->m_env;
if(env == NULL) return 0;
f32 t = readParam<float>(L,2); f32 t = readParam<float>(L,2);
env->getMap().setNodeTimer(NodeTimer(t, 0, o->m_p)); o->m_map->setNodeTimer(NodeTimer(t, 0, o->m_p));
return 0; return 0;
} }
@ -64,9 +60,7 @@ int NodeTimerRef::l_stop(lua_State *L)
{ {
MAP_LOCK_REQUIRED; MAP_LOCK_REQUIRED;
NodeTimerRef *o = checkobject(L, 1); NodeTimerRef *o = checkobject(L, 1);
ServerEnvironment *env = o->m_env; o->m_map->removeNodeTimer(o->m_p);
if(env == NULL) return 0;
env->getMap().removeNodeTimer(o->m_p);
return 0; return 0;
} }
@ -74,10 +68,7 @@ int NodeTimerRef::l_is_started(lua_State *L)
{ {
MAP_LOCK_REQUIRED; MAP_LOCK_REQUIRED;
NodeTimerRef *o = checkobject(L, 1); NodeTimerRef *o = checkobject(L, 1);
ServerEnvironment *env = o->m_env; NodeTimer t = o->m_map->getNodeTimer(o->m_p);
if(env == NULL) return 0;
NodeTimer t = env->getMap().getNodeTimer(o->m_p);
lua_pushboolean(L,(t.timeout != 0)); lua_pushboolean(L,(t.timeout != 0));
return 1; return 1;
} }
@ -86,10 +77,7 @@ int NodeTimerRef::l_get_timeout(lua_State *L)
{ {
MAP_LOCK_REQUIRED; MAP_LOCK_REQUIRED;
NodeTimerRef *o = checkobject(L, 1); NodeTimerRef *o = checkobject(L, 1);
ServerEnvironment *env = o->m_env; NodeTimer t = o->m_map->getNodeTimer(o->m_p);
if(env == NULL) return 0;
NodeTimer t = env->getMap().getNodeTimer(o->m_p);
lua_pushnumber(L,t.timeout); lua_pushnumber(L,t.timeout);
return 1; return 1;
} }
@ -98,37 +86,21 @@ int NodeTimerRef::l_get_elapsed(lua_State *L)
{ {
MAP_LOCK_REQUIRED; MAP_LOCK_REQUIRED;
NodeTimerRef *o = checkobject(L, 1); NodeTimerRef *o = checkobject(L, 1);
ServerEnvironment *env = o->m_env; NodeTimer t = o->m_map->getNodeTimer(o->m_p);
if(env == NULL) return 0;
NodeTimer t = env->getMap().getNodeTimer(o->m_p);
lua_pushnumber(L,t.elapsed); lua_pushnumber(L,t.elapsed);
return 1; return 1;
} }
NodeTimerRef::NodeTimerRef(v3s16 p, ServerEnvironment *env):
m_p(p),
m_env(env)
{
}
// Creates an NodeTimerRef and leaves it on top of stack // Creates an NodeTimerRef and leaves it on top of stack
// Not callable from Lua; all references are created on the C side. // Not callable from Lua; all references are created on the C side.
void NodeTimerRef::create(lua_State *L, v3s16 p, ServerEnvironment *env) void NodeTimerRef::create(lua_State *L, v3s16 p, ServerMap *map)
{ {
NodeTimerRef *o = new NodeTimerRef(p, env); NodeTimerRef *o = new NodeTimerRef(p, map);
*(void **)(lua_newuserdata(L, sizeof(void *))) = o; *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
luaL_getmetatable(L, className); luaL_getmetatable(L, className);
lua_setmetatable(L, -2); lua_setmetatable(L, -2);
} }
void NodeTimerRef::set_null(lua_State *L)
{
NodeTimerRef *o = checkobject(L, -1);
o->m_env = NULL;
}
void NodeTimerRef::Register(lua_State *L) void NodeTimerRef::Register(lua_State *L)
{ {
lua_newtable(L); lua_newtable(L);

@ -22,13 +22,13 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "irr_v3d.h" #include "irr_v3d.h"
#include "lua_api/l_base.h" #include "lua_api/l_base.h"
class ServerEnvironment; class ServerMap;
class NodeTimerRef : public ModApiBase class NodeTimerRef : public ModApiBase
{ {
private: private:
v3s16 m_p; v3s16 m_p;
ServerEnvironment *m_env = nullptr; ServerMap *m_map;
static const char className[]; static const char className[];
static const luaL_Reg methods[]; static const luaL_Reg methods[];
@ -50,14 +50,12 @@ private:
static int l_get_elapsed(lua_State *L); static int l_get_elapsed(lua_State *L);
public: public:
NodeTimerRef(v3s16 p, ServerEnvironment *env); NodeTimerRef(v3s16 p, ServerMap *map) : m_p(p), m_map(map) {}
~NodeTimerRef() = default; ~NodeTimerRef() = default;
// Creates an NodeTimerRef and leaves it on top of stack // Creates an NodeTimerRef and leaves it on top of stack
// Not callable from Lua; all references are created on the C side. // Not callable from Lua; all references are created on the C side.
static void create(lua_State *L, v3s16 p, ServerEnvironment *env); static void create(lua_State *L, v3s16 p, ServerMap *map);
static void set_null(lua_State *L);
static void Register(lua_State *L); static void Register(lua_State *L);
}; };