}
}
+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)
{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:
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));
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
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;
}
//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);
+ 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");
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)
{
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)
{
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)
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");
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)
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);
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)
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));
}