From f145d498a6d91e3f5f3dcf921db8b74c98a7dad2 Mon Sep 17 00:00:00 2001
From: Perttu Ahola <celeron55@gmail.com>
Date: Sat, 12 Nov 2011 02:25:30 +0200
Subject: [PATCH] Scripting WIP

---
 data/scripts/default.lua |  17 +-
 src/content_sao.cpp      |  13 ++
 src/content_sao.h        |   3 +
 src/environment.cpp      |   4 +-
 src/scriptapi.cpp        | 405 +++++++++++++++++++++++++++++----------
 src/scriptapi.h          |   8 +-
 src/server.cpp           |   3 +
 7 files changed, 341 insertions(+), 112 deletions(-)

diff --git a/data/scripts/default.lua b/data/scripts/default.lua
index 005e9ac15..b6c6b0d89 100644
--- a/data/scripts/default.lua
+++ b/data/scripts/default.lua
@@ -155,28 +155,21 @@ end
 
 -- Called periodically
 function TNT:on_step(dtime)
-	print("TNT:on_step()")
-	--[[self.timer = self.timer + dtime
-	if self.timer > 4.0 then
-		self.to_be_deleted = true -- Environment will delete this object at a suitable point of execution
-		env:explode(self.pos, 3) -- Uh... well, something like that
-	end]]
+	--print("TNT:on_step()")
 end
 
 -- Called when object is punched
 function TNT:on_punch(hitter)
 	print("TNT:on_punch()")
-	--[[-- If tool is bomb defuser, revert back to being a block
-	local item = hitter.inventory.get_current()
-	if item.itemtype == "tool" and item.param == "bomb_defuser" then
-		env:add_node(self.pos, 3072)
-		self.to_be_deleted = true
-	end]]
 end
 
 -- Called when object is right-clicked
 function TNT:on_rightclick(clicker)
 	print("TNT:on_rightclick()")
+	pos = self.object:getpos()
+	print("TNT:on_rightclick(): object position: "..dump(pos))
+	pos = {x=pos.x+0.5+1, y=pos.y+0.5, z=pos.z+0.5}
+	minetest.env:add_node(pos, 0)
 end
 
 print("TNT dump: "..dump(TNT))
diff --git a/src/content_sao.cpp b/src/content_sao.cpp
index 3507ec154..567b489d9 100644
--- a/src/content_sao.cpp
+++ b/src/content_sao.cpp
@@ -1593,4 +1593,17 @@ InventoryItem* LuaEntitySAO::createPickedUpItem()
 	return item;
 }
 
+u16 LuaEntitySAO::punch(const std::string &toolname, v3f dir,
+		const std::string &playername)
+{
+	return 0;
+}
+
+void LuaEntitySAO::rightClick(Player *player)
+{
+	if(!m_registered)
+		return;
+	lua_State *L = m_env->getLua();
+	scriptapi_luaentity_rightclick_player(L, m_id, player->getName());
+}
 
diff --git a/src/content_sao.h b/src/content_sao.h
index f0eec29b6..115b9ead4 100644
--- a/src/content_sao.h
+++ b/src/content_sao.h
@@ -212,6 +212,9 @@ class LuaEntitySAO : public ServerActiveObject
 	std::string getClientInitializationData();
 	std::string getStaticData();
 	InventoryItem* createPickedUpItem();
+	u16 punch(const std::string &toolname, v3f dir,
+			const std::string &playername);
+	void rightClick(Player *player);
 private:
 	std::string m_init_name;
 	std::string m_init_state;
diff --git a/src/environment.cpp b/src/environment.cpp
index d7a647ac8..ed45cee69 100644
--- a/src/environment.cpp
+++ b/src/environment.cpp
@@ -1497,10 +1497,10 @@ u16 ServerEnvironment::addActiveObjectRaw(ServerActiveObject *object,
 				<<" statically"<<std::endl;
 	}
 	
+	// Register reference in scripting api (must be done before post-init)
+	scriptapi_add_object_reference(m_lua, object);
 	// Post-initialize object
 	object->addedToEnvironment(object->getId());
-	// Register reference in scripting api
-	scriptapi_add_object_reference(m_lua, object);
 
 	return object->getId();
 }
diff --git a/src/scriptapi.cpp b/src/scriptapi.cpp
index fc5364c87..2704f6c43 100644
--- a/src/scriptapi.cpp
+++ b/src/scriptapi.cpp
@@ -76,6 +76,24 @@ static void realitycheck(lua_State *L)
 	}
 }
 
+class StackUnroller
+{
+private:
+	lua_State *m_lua;
+	int m_original_top;
+public:
+	StackUnroller(lua_State *L):
+		m_lua(L),
+		m_original_top(-1)
+	{
+		m_original_top = lua_gettop(m_lua); // store stack height
+	}
+	~StackUnroller()
+	{
+		lua_settop(m_lua, m_original_top); // restore stack height
+	}
+};
+
 // Register new object prototype
 // register_entity(name, prototype)
 static int l_register_entity(lua_State *L)
@@ -145,6 +163,131 @@ static const struct luaL_Reg minetest_entity_m [] = {
 	{NULL, NULL}
 };
 
+/*
+	Reference objects
+*/
+#define method(class, name) {#name, class::l_##name}
+
+class EnvRef
+{
+private:
+	ServerEnvironment *m_env;
+
+	static const char className[];
+	static const luaL_reg methods[];
+
+	static EnvRef *checkobject(lua_State *L, int narg)
+	{
+		luaL_checktype(L, narg, LUA_TUSERDATA);
+		void *ud = luaL_checkudata(L, narg, className);
+		if(!ud) luaL_typerror(L, narg, className);
+		return *(EnvRef**)ud;  // unbox pointer
+	}
+	
+	// Exported functions
+
+	// EnvRef:add_node(pos, content)
+	// pos = {x=num, y=num, z=num}
+	// content = number
+	static int l_add_node(lua_State *L)
+	{
+		infostream<<"EnvRef::l_add_node()"<<std::endl;
+		EnvRef *o = checkobject(L, 1);
+		ServerEnvironment *env = o->m_env;
+		if(env == NULL) return 0;
+		// pos
+		v3s16 pos;
+		lua_pushvalue(L, 2); // Push pos
+		luaL_checktype(L, -1, LUA_TTABLE);
+		lua_getfield(L, -1, "x");
+		pos.X = lua_tonumber(L, -1);
+		lua_pop(L, 1);
+		lua_getfield(L, -1, "y");
+		pos.Y = lua_tonumber(L, -1);
+		lua_pop(L, 1);
+		lua_getfield(L, -1, "z");
+		pos.Z = lua_tonumber(L, -1);
+		lua_pop(L, 1);
+		lua_pop(L, 1); // Pop pos
+		// content
+		u16 content = 0;
+		lua_pushvalue(L, 3); // Push content
+		content = lua_tonumber(L, -1);
+		lua_pop(L, 1); // Pop content
+		// Do it
+		env->getMap().addNodeWithEvent(pos, MapNode(content));
+		return 0;
+	}
+
+	static int gc_object(lua_State *L) {
+		EnvRef *o = *(EnvRef **)(lua_touserdata(L, 1));
+		delete o;
+		return 0;
+	}
+
+public:
+	EnvRef(ServerEnvironment *env):
+		m_env(env)
+	{
+		infostream<<"EnvRef created"<<std::endl;
+	}
+
+	~EnvRef()
+	{
+		infostream<<"EnvRef destructing"<<std::endl;
+	}
+
+	// Creates an EnvRef and leaves it on top of stack
+	// Not callable from Lua; all references are created on the C side.
+	static void create(lua_State *L, ServerEnvironment *env)
+	{
+		EnvRef *o = new EnvRef(env);
+		//infostream<<"EnvRef::create: o="<<o<<std::endl;
+		*(void **)(lua_newuserdata(L, sizeof(void *))) = o;
+		luaL_getmetatable(L, className);
+		lua_setmetatable(L, -2);
+	}
+
+	static void set_null(lua_State *L)
+	{
+		EnvRef *o = checkobject(L, -1);
+		o->m_env = NULL;
+	}
+	
+	static void Register(lua_State *L)
+	{
+		lua_newtable(L);
+		int methodtable = lua_gettop(L);
+		luaL_newmetatable(L, className);
+		int metatable = lua_gettop(L);
+
+		lua_pushliteral(L, "__metatable");
+		lua_pushvalue(L, methodtable);
+		lua_settable(L, metatable);  // hide metatable from Lua getmetatable()
+
+		lua_pushliteral(L, "__index");
+		lua_pushvalue(L, methodtable);
+		lua_settable(L, metatable);
+
+		lua_pushliteral(L, "__gc");
+		lua_pushcfunction(L, gc_object);
+		lua_settable(L, metatable);
+
+		lua_pop(L, 1);  // drop metatable
+
+		luaL_openlib(L, 0, methods, 0);  // fill methodtable
+		lua_pop(L, 1);  // drop methodtable
+
+		// Cannot be created from Lua
+		//lua_register(L, className, create_object);
+	}
+};
+const char EnvRef::className[] = "EnvRef";
+const luaL_reg EnvRef::methods[] = {
+	method(EnvRef, add_node),
+	{0,0}
+};
+
 class ObjectRef
 {
 private:
@@ -173,6 +316,23 @@ class ObjectRef
 		return 0;
 	}
 
+	static int l_getpos(lua_State *L)
+	{
+		ObjectRef *o = checkobject(L, 1);
+		ServerActiveObject *co = o->m_object;
+		if(co == NULL) return 0;
+		infostream<<"ObjectRef::l_getpos(): id="<<co->getId()<<std::endl;
+		v3f pos = co->getBasePosition() / BS;
+		lua_newtable(L);
+		lua_pushnumber(L, pos.X);
+		lua_setfield(L, -2, "x");
+		lua_pushnumber(L, pos.Y);
+		lua_setfield(L, -2, "y");
+		lua_pushnumber(L, pos.Z);
+		lua_setfield(L, -2, "z");
+		return 1;
+	}
+
 	static int gc_object(lua_State *L) {
 		//ObjectRef *o = checkobject(L, 1);
 		ObjectRef *o = *(ObjectRef **)(lua_touserdata(L, 1));
@@ -185,15 +345,16 @@ class ObjectRef
 	ObjectRef(ServerActiveObject *object):
 		m_object(object)
 	{
-		infostream<<"ObjectRef created for id="<<m_object->getId()<<std::endl;
+		//infostream<<"ObjectRef created for id="<<m_object->getId()<<std::endl;
 	}
 
 	~ObjectRef()
 	{
-		if(m_object)
-			infostream<<"ObjectRef destructing for id="<<m_object->getId()<<std::endl;
+		/*if(m_object)
+			infostream<<"ObjectRef destructing for id="
+					<<m_object->getId()<<std::endl;
 		else
-			infostream<<"ObjectRef destructing for id=unknown"<<std::endl;
+			infostream<<"ObjectRef destructing for id=unknown"<<std::endl;*/
 	}
 
 	// Creates an ObjectRef and leaves it on top of stack
@@ -210,9 +371,6 @@ class ObjectRef
 	static void set_null(lua_State *L)
 	{
 		ObjectRef *o = checkobject(L, -1);
-		ServerActiveObject *co = o->m_object;
-		if(co == NULL)
-			return;
 		o->m_object = NULL;
 	}
 	
@@ -244,16 +402,17 @@ class ObjectRef
 		//lua_register(L, className, create_object);
 	}
 };
-
 const char ObjectRef::className[] = "ObjectRef";
-
-#define method(class, name) {#name, class::l_##name}
-
 const luaL_reg ObjectRef::methods[] = {
 	method(ObjectRef, remove),
+	method(ObjectRef, getpos),
 	{0,0}
 };
 
+/*
+	Main export function
+*/
+
 void scriptapi_export(lua_State *L, Server *server)
 {
 	realitycheck(L);
@@ -285,8 +444,8 @@ void scriptapi_export(lua_State *L, Server *server)
 			+ DIR_DELIM + "base.lua").c_str());*/
 	
 	// Create entity reference metatable
-	luaL_newmetatable(L, "minetest.entity_reference");
-	lua_pop(L, 1);
+	//luaL_newmetatable(L, "minetest.entity_reference");
+	//lua_pop(L, 1);
 	
 	// Create entity prototype
 	luaL_newmetatable(L, "minetest.entity");
@@ -297,10 +456,33 @@ void scriptapi_export(lua_State *L, Server *server)
 	luaL_register(L, NULL, minetest_entity_m);
 	// Put other stuff in metatable
 
-	// Entity C reference
+	// Environment C reference
+	EnvRef::Register(L);
+
+	// Object C reference
 	ObjectRef::Register(L);
 }
 
+void scriptapi_add_environment(lua_State *L, ServerEnvironment *env)
+{
+	realitycheck(L);
+	assert(lua_checkstack(L, 20));
+	infostream<<"scriptapi_add_environment"<<std::endl;
+
+	// Create EnvRef on stack
+	EnvRef::create(L, env);
+	int envref = lua_gettop(L);
+
+	// minetest.env = envref
+	lua_getglobal(L, "minetest");
+	luaL_checktype(L, -1, LUA_TTABLE);
+	lua_pushvalue(L, envref);
+	lua_setfield(L, -2, "env");
+	
+	// pop minetest and envref
+	lua_pop(L, 2);
+}
+
 // Dump stack top with the dump2 function
 static void dump2(lua_State *L, const char *name)
 {
@@ -313,6 +495,79 @@ static void dump2(lua_State *L, const char *name)
 		script_error(L, "error: %s\n", lua_tostring(L, -1));
 }
 
+/*
+	object_reference
+*/
+
+void scriptapi_add_object_reference(lua_State *L, ServerActiveObject *cobj)
+{
+	realitycheck(L);
+	assert(lua_checkstack(L, 20));
+	infostream<<"scriptapi_add_object_reference: id="<<cobj->getId()<<std::endl;
+
+	// Create object on stack
+	ObjectRef::create(L, cobj); // Puts ObjectRef (as userdata) on stack
+	int object = lua_gettop(L);
+
+	// Get minetest.object_refs table
+	lua_getglobal(L, "minetest");
+	lua_getfield(L, -1, "object_refs");
+	luaL_checktype(L, -1, LUA_TTABLE);
+	int objectstable = lua_gettop(L);
+	
+	// object_refs[id] = object
+	lua_pushnumber(L, cobj->getId()); // Push id
+	lua_pushvalue(L, object); // Copy object to top of stack
+	lua_settable(L, objectstable);
+	
+	// pop object_refs, minetest and the object
+	lua_pop(L, 3);
+}
+
+void scriptapi_rm_object_reference(lua_State *L, ServerActiveObject *cobj)
+{
+	realitycheck(L);
+	assert(lua_checkstack(L, 20));
+	infostream<<"scriptapi_rm_object_reference: id="<<cobj->getId()<<std::endl;
+
+	// Get minetest.object_refs table
+	lua_getglobal(L, "minetest");
+	lua_getfield(L, -1, "object_refs");
+	luaL_checktype(L, -1, LUA_TTABLE);
+	int objectstable = lua_gettop(L);
+	
+	// Get object_refs[id]
+	lua_pushnumber(L, cobj->getId()); // Push id
+	lua_gettable(L, objectstable);
+	// Set object reference to NULL
+	ObjectRef::set_null(L);
+	lua_pop(L, 1); // pop object
+
+	// Set object_refs[id] = nil
+	lua_pushnumber(L, cobj->getId()); // Push id
+	lua_pushnil(L);
+	lua_settable(L, objectstable);
+	
+	// pop object_refs, minetest
+	lua_pop(L, 2);
+}
+
+static void objectref_get(lua_State *L, u16 id)
+{
+	// Get minetest.object_refs[i]
+	lua_getglobal(L, "minetest");
+	lua_getfield(L, -1, "object_refs");
+	luaL_checktype(L, -1, LUA_TTABLE);
+	lua_pushnumber(L, id);
+	lua_gettable(L, -2);
+	lua_remove(L, -2); // object_refs
+	lua_remove(L, -2); // minetest
+}
+
+/*
+	luaentity
+*/
+
 void scriptapi_luaentity_add(lua_State *L, u16 id, const char *name,
 		const char *init_state)
 {
@@ -320,8 +575,7 @@ void scriptapi_luaentity_add(lua_State *L, u16 id, const char *name,
 	assert(lua_checkstack(L, 20));
 	infostream<<"scriptapi_luaentity_add: id="<<id<<" name=\""
 			<<name<<"\""<<std::endl;
-
-	int initial_top = lua_gettop(L);
+	StackUnroller stack_unroller(L);
 	
 	// Create object as a dummy string (TODO: Create properly)
 
@@ -344,13 +598,13 @@ void scriptapi_luaentity_add(lua_State *L, u16 id, const char *name,
 	lua_pushvalue(L, prototype_table);
 	lua_setmetatable(L, -2);
 	
-	/*// Set prototype_table.__index = prototype_table
-	lua_pushvalue(L, prototype_table); // Copy to top of stack
-	lua_pushvalue(L, -1); // duplicate prototype_table
-	lua_setfield(L, -2, "__index");*/
-	
-	/*lua_pushstring(L, "debug from C");
-	lua_setfield(L, -2, "on_step");*/
+	// Add object reference
+	// This should be userdata with metatable ObjectRef
+	objectref_get(L, id);
+	luaL_checktype(L, -1, LUA_TUSERDATA);
+	if(!luaL_checkudata(L, -1, "ObjectRef"))
+		luaL_typerror(L, -1, "ObjectRef");
+	lua_setfield(L, -2, "object");
 
 	// Get minetest.luaentities table
 	lua_getglobal(L, "minetest");
@@ -362,8 +616,6 @@ void scriptapi_luaentity_add(lua_State *L, u16 id, const char *name,
 	lua_pushnumber(L, id); // Push id
 	lua_pushvalue(L, object); // Copy object to top of stack
 	lua_settable(L, luaentities);
-	
-	lua_settop(L, initial_top); // Reset stack
 }
 
 void scriptapi_luaentity_rm(lua_State *L, u16 id)
@@ -378,12 +630,6 @@ void scriptapi_luaentity_rm(lua_State *L, u16 id)
 	luaL_checktype(L, -1, LUA_TTABLE);
 	int objectstable = lua_gettop(L);
 	
-	/*// Get luaentities[id]
-	lua_pushnumber(L, cobj->getId()); // Push id
-	lua_gettable(L, objectstable);
-	// Object is at stack top
-	lua_pop(L, 1); // pop object*/
-
 	// Set luaentities[id] = nil
 	lua_pushnumber(L, id); // Push id
 	lua_pushnil(L);
@@ -392,38 +638,16 @@ void scriptapi_luaentity_rm(lua_State *L, u16 id)
 	lua_pop(L, 2); // pop luaentities, minetest
 }
 
-void scriptapi_luaentity_step(lua_State *L, u16 id, float dtime)
+static void luaentity_get(lua_State *L, u16 id)
 {
-	realitycheck(L);
-	assert(lua_checkstack(L, 20));
-	infostream<<"scriptapi_luaentity_step: id="<<id<<std::endl;
-
 	// Get minetest.luaentities[i]
 	lua_getglobal(L, "minetest");
 	lua_getfield(L, -1, "luaentities");
 	luaL_checktype(L, -1, LUA_TTABLE);
 	lua_pushnumber(L, id);
 	lua_gettable(L, -2);
-	int object = lua_gettop(L);
-	// State: object is at top of stack
-	/*dump2(L, "entity");
-	lua_getmetatable(L, -1);
-	dump2(L, "getmetatable(entity)");
-	lua_getfield(L, -1, "__index");
-	dump2(L, "getmetatable(entity).__index");
-	lua_pop(L, 1);
-	lua_pop(L, 1);*/
-	// Get step function
-	lua_getfield(L, -1, "on_step");
-	luaL_checktype(L, -1, LUA_TFUNCTION);
-	lua_pushvalue(L, object); // self
-	lua_pushnumber(L, dtime); // dtime
-	// Call with 2 arguments, 0 results
-	if(lua_pcall(L, 2, 0, 0))
-		script_error(L, "error running function 'step': %s\n", lua_tostring(L, -1));
-
-	lua_pop(L, 1); // pop object
-	lua_pop(L, 2); // pop luaentities, minetest
+	lua_remove(L, -2); // luaentities
+	lua_remove(L, -2); // minetest
 }
 
 std::string scriptapi_luaentity_get_state(lua_State *L, u16 id)
@@ -435,56 +659,45 @@ std::string scriptapi_luaentity_get_state(lua_State *L, u16 id)
 	return "";
 }
 
-void scriptapi_add_object_reference(lua_State *L, ServerActiveObject *cobj)
+void scriptapi_luaentity_step(lua_State *L, u16 id, float dtime)
 {
 	realitycheck(L);
 	assert(lua_checkstack(L, 20));
-	infostream<<"scriptapi_add_object_reference: id="<<cobj->getId()<<std::endl;
+	//infostream<<"scriptapi_luaentity_step: id="<<id<<std::endl;
+	StackUnroller stack_unroller(L);
 
-	// Create object on stack
-	ObjectRef::create(L, cobj); // Puts ObjectRef (as userdata) on stack
+	// Get minetest.luaentities[id]
+	luaentity_get(L, id);
 	int object = lua_gettop(L);
-
-	// Get minetest.object_refs table
-	lua_getglobal(L, "minetest");
-	lua_getfield(L, -1, "object_refs");
-	luaL_checktype(L, -1, LUA_TTABLE);
-	int objectstable = lua_gettop(L);
-	
-	// object_refs[id] = object
-	lua_pushnumber(L, cobj->getId()); // Push id
-	lua_pushvalue(L, object); // Copy object to top of stack
-	lua_settable(L, objectstable);
-	
-	// pop object_refs, minetest and the object
-	lua_pop(L, 3);
+	// State: object is at top of stack
+	// Get step function
+	lua_getfield(L, -1, "on_step");
+	luaL_checktype(L, -1, LUA_TFUNCTION);
+	lua_pushvalue(L, object); // self
+	lua_pushnumber(L, dtime); // dtime
+	// Call with 2 arguments, 0 results
+	if(lua_pcall(L, 2, 0, 0))
+		script_error(L, "error running function 'step': %s\n", lua_tostring(L, -1));
 }
 
-void scriptapi_rm_object_reference(lua_State *L, ServerActiveObject *cobj)
+void scriptapi_luaentity_rightclick_player(lua_State *L, u16 id,
+		const char *playername)
 {
 	realitycheck(L);
 	assert(lua_checkstack(L, 20));
-	infostream<<"scriptapi_rm_object_reference: id="<<cobj->getId()<<std::endl;
-
-	// Get minetest.object_refs table
-	lua_getglobal(L, "minetest");
-	lua_getfield(L, -1, "object_refs");
-	luaL_checktype(L, -1, LUA_TTABLE);
-	int objectstable = lua_gettop(L);
-	
-	// Get object_refs[id]
-	lua_pushnumber(L, cobj->getId()); // Push id
-	lua_gettable(L, objectstable);
-	// Set object reference to NULL
-	ObjectRef::set_null(L);
-	lua_pop(L, 1); // pop object
+	//infostream<<"scriptapi_luaentity_step: id="<<id<<std::endl;
+	StackUnroller stack_unroller(L);
 
-	// Set object_refs[id] = nil
-	lua_pushnumber(L, cobj->getId()); // Push id
-	lua_pushnil(L);
-	lua_settable(L, objectstable);
-	
-	// pop object_refs, minetest
-	lua_pop(L, 2);
+	// Get minetest.luaentities[id]
+	luaentity_get(L, id);
+	int object = lua_gettop(L);
+	// State: object is at top of stack
+	// Get step function
+	lua_getfield(L, -1, "on_rightclick");
+	luaL_checktype(L, -1, LUA_TFUNCTION);
+	lua_pushvalue(L, object); // self
+	// Call with 1 arguments, 0 results
+	if(lua_pcall(L, 1, 0, 0))
+		script_error(L, "error running function 'step': %s\n", lua_tostring(L, -1));
 }
 
diff --git a/src/scriptapi.h b/src/scriptapi.h
index 18c2b3838..9d10ec77e 100644
--- a/src/scriptapi.h
+++ b/src/scriptapi.h
@@ -24,19 +24,23 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include <string>
 
 class Server;
+class ServerEnvironment;
 class ServerActiveObject;
 typedef struct lua_State lua_State;
 
 void scriptapi_export(lua_State *L, Server *server);
-	
+void scriptapi_add_environment(lua_State *L, ServerEnvironment *env);
+
 void scriptapi_add_object_reference(lua_State *L, ServerActiveObject *cobj);
 void scriptapi_rm_object_reference(lua_State *L, ServerActiveObject *cobj);
 
 void scriptapi_luaentity_add(lua_State *L, u16 id, const char *name,
 		const char *init_state);
 void scriptapi_luaentity_rm(lua_State *L, u16 id);
-void scriptapi_luaentity_step(lua_State *L, u16 id, float dtime);
 std::string scriptapi_luaentity_get_state(lua_State *L, u16 id);
+void scriptapi_luaentity_step(lua_State *L, u16 id, float dtime);
+void scriptapi_luaentity_rightclick_player(lua_State *L, u16 id,
+		const char *playername);
 
 #endif
 
diff --git a/src/server.cpp b/src/server.cpp
index 82671bf89..88ac6fd70 100644
--- a/src/server.cpp
+++ b/src/server.cpp
@@ -1001,6 +1001,9 @@ Server::Server(
 	// Initialize Environment
 	
 	m_env = new ServerEnvironment(new ServerMap(mapsavedir), m_lua);
+
+	// Give environment reference to scripting api
+	scriptapi_add_environment(m_lua, m_env);
 	
 	// Register us to receive map edit events
 	m_env->getMap().addEventReceiver(this);
-- 
GitLab