summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPerttu Ahola <celeron55@gmail.com>2011-11-12 02:25:30 +0200
committerPerttu Ahola <celeron55@gmail.com>2011-11-29 19:13:39 +0200
commitf145d498a6d91e3f5f3dcf921db8b74c98a7dad2 (patch)
tree8546af949d63af226fc4e858fe5678248a9f8e4a /src
parent41c91391fce65147aa7f3b5ceb7db5758709199a (diff)
downloadminetest-f145d498a6d91e3f5f3dcf921db8b74c98a7dad2.tar.gz
minetest-f145d498a6d91e3f5f3dcf921db8b74c98a7dad2.tar.bz2
minetest-f145d498a6d91e3f5f3dcf921db8b74c98a7dad2.zip
Scripting WIP
Diffstat (limited to 'src')
-rw-r--r--src/content_sao.cpp13
-rw-r--r--src/content_sao.h3
-rw-r--r--src/environment.cpp4
-rw-r--r--src/scriptapi.cpp405
-rw-r--r--src/scriptapi.h8
-rw-r--r--src/server.cpp3
6 files changed, 336 insertions, 100 deletions
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 @@ public:
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 @@ private:
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 @@ public:
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 @@ public:
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 @@ public:
//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);