#include "serverobject.h"
#include "script.h"
//#include "luna.h"
+#include "luaentity_common.h"
+#include "content_sao.h" // For LuaEntitySAO
+
+/*
+TODO:
+- Node type definition
+- Random node triggers
+- Object visual client-side stuff
+ - Blink effect
+ - Spritesheets and animation
+- Named node types and dynamic id allocation per MapBlock
+- LuaNodeMetadata
+ blockdef.has_metadata = true/false
+ - Stores an inventory and stuff in a Settings object
+ meta.inventory_add_list("main")
+ blockdef.on_inventory_modified
+ meta.set("owner", playername)
+ meta.get("owner")
+*/
static void stackDump(lua_State *L, std::ostream &o)
{
}
}
-// Register new object prototype (must be based on entity)
-static int l_register_object(lua_State *L)
+class StackUnroller
{
- const char *name = luaL_checkstring(L, 1);
- luaL_checkany(L, 2);
- infostream<<"register_object: "<<name<<std::endl;
- // Get the minetest table
- lua_getglobal(L, "minetest");
- // Get field "registered_objects"
- lua_getfield(L, -1, "registered_objects");
- luaL_checktype(L, -1, LUA_TTABLE);
- int objectstable = lua_gettop(L);
- // Object is in param 2
- lua_pushvalue(L, 2); // Copy object to top of stack
- lua_setfield(L, objectstable, name); // registered_objects[name] = object
+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
+ }
+};
- return 0; /* number of results */
+v3f readFloatPos(lua_State *L, int index)
+{
+ v3f pos;
+ lua_pushvalue(L, index); // 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
+ pos *= BS; // Scale to internal format
+ return pos;
}
-static int l_new_entity(lua_State *L)
+/*
+ Global functions
+*/
+
+// Register new object prototype
+// register_entity(name, prototype)
+static int l_register_entity(lua_State *L)
{
- /* o = o or {}
- setmetatable(o, self)
- self.__index = self
- return o */
- if(lua_isnil(L, -1))
- lua_newtable(L);
+ const char *name = luaL_checkstring(L, 1);
+ luaL_checktype(L, 2, LUA_TTABLE);
+ infostream<<"register_entity: "<<name<<std::endl;
+
+ // Get minetest.registered_entities
+ lua_getglobal(L, "minetest");
+ lua_getfield(L, -1, "registered_entities");
luaL_checktype(L, -1, LUA_TTABLE);
+ int registered_entities = lua_gettop(L);
+ lua_pushvalue(L, 2); // Object = param 2 -> stack top
+ // registered_entities[name] = object
+ lua_setfield(L, registered_entities, name);
+
+ // Get registered object to top of stack
+ lua_pushvalue(L, 2);
+
+ // Set __index to point to itself
+ lua_pushvalue(L, -1);
+ lua_setfield(L, -2, "__index");
+
+ // Set metatable.__index = metatable
luaL_getmetatable(L, "minetest.entity");
lua_pushvalue(L, -1); // duplicate metatable
lua_setfield(L, -2, "__index");
+ // Set object metatable
lua_setmetatable(L, -2);
- // return table
- return 1;
+
+ return 0; /* number of results */
+}
+
+// Register a global step function
+// register_globalstep(function)
+static int l_register_globalstep(lua_State *L)
+{
+ luaL_checktype(L, 1, LUA_TFUNCTION);
+ infostream<<"register_globalstep"<<std::endl;
+
+ lua_getglobal(L, "table");
+ lua_getfield(L, -1, "insert");
+ int table_insert = lua_gettop(L);
+ // Get minetest.registered_globalsteps
+ lua_getglobal(L, "minetest");
+ lua_getfield(L, -1, "registered_globalsteps");
+ luaL_checktype(L, -1, LUA_TTABLE);
+ int registered_globalsteps = lua_gettop(L);
+ // table.insert(registered_globalsteps, func)
+ lua_pushvalue(L, table_insert);
+ lua_pushvalue(L, registered_globalsteps);
+ lua_pushvalue(L, 1); // push function from argument 1
+ // Call insert
+ if(lua_pcall(L, 2, 0, 0))
+ script_error(L, "error: %s\n", lua_tostring(L, -1));
+
+ return 0; /* number of results */
}
static const struct luaL_Reg minetest_f [] = {
- {"register_object", l_register_object},
- {"new_entity", l_new_entity},
+ {"register_entity", l_register_entity},
+ {"register_globalstep", l_register_globalstep},
{NULL, NULL}
};
-static int l_entity_set_deleted(lua_State *L)
-{
- return 0;
-}
+/*
+ LuaEntity functions
+*/
static const struct luaL_Reg minetest_entity_m [] = {
- {"set_deleted", l_entity_set_deleted},
{NULL, NULL}
};
+/*
+ Getters for stuff in main tables
+*/
+
+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
+}
+
+static void luaentity_get(lua_State *L, u16 id)
+{
+ // 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);
+ lua_remove(L, -2); // luaentities
+ lua_remove(L, -2); // minetest
+}
+
+/*
+ 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 *(ObjectRef**)ud; // unbox pointer
}
+ static ServerActiveObject* getobject(ObjectRef *ref)
+ {
+ ServerActiveObject *co = ref->m_object;
+ return co;
+ }
+
+ static LuaEntitySAO* getluaobject(ObjectRef *ref)
+ {
+ ServerActiveObject *obj = getobject(ref);
+ if(obj == NULL)
+ return NULL;
+ if(obj->getType() != ACTIVEOBJECT_TYPE_LUAENTITY)
+ return NULL;
+ return (LuaEntitySAO*)obj;
+ }
+
// Exported functions
+
+ // garbage collector
+ static int gc_object(lua_State *L) {
+ ObjectRef *o = *(ObjectRef **)(lua_touserdata(L, 1));
+ //infostream<<"ObjectRef::gc_object: o="<<o<<std::endl;
+ delete o;
+ return 0;
+ }
+ // remove(self)
static int l_remove(lua_State *L)
{
- ObjectRef *o = checkobject(L, 1);
- ServerActiveObject *co = o->m_object;
+ ObjectRef *ref = checkobject(L, 1);
+ ServerActiveObject *co = getobject(ref);
if(co == NULL) return 0;
infostream<<"ObjectRef::l_remove(): id="<<co->getId()<<std::endl;
co->m_removed = true;
return 0;
}
-
- static int gc_object(lua_State *L) {
- //ObjectRef *o = checkobject(L, 1);
- ObjectRef *o = *(ObjectRef **)(lua_touserdata(L, 1));
- //infostream<<"ObjectRef::gc_object: o="<<o<<std::endl;
- delete o;
+
+ // getpos(self)
+ // returns: {x=num, y=num, z=num}
+ static int l_getpos(lua_State *L)
+ {
+ ObjectRef *ref = checkobject(L, 1);
+ ServerActiveObject *co = getobject(ref);
+ if(co == NULL) return 0;
+ 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;
+ }
+
+ // setpos(self, pos)
+ static int l_setpos(lua_State *L)
+ {
+ ObjectRef *ref = checkobject(L, 1);
+ //LuaEntitySAO *co = getluaobject(ref);
+ ServerActiveObject *co = getobject(ref);
+ if(co == NULL) return 0;
+ // pos
+ v3f pos = readFloatPos(L, 2);
+ // Do it
+ co->setPos(pos);
+ return 0;
+ }
+
+ // moveto(self, pos, continuous=false)
+ static int l_moveto(lua_State *L)
+ {
+ ObjectRef *ref = checkobject(L, 1);
+ //LuaEntitySAO *co = getluaobject(ref);
+ ServerActiveObject *co = getobject(ref);
+ if(co == NULL) return 0;
+ // pos
+ v3f pos = readFloatPos(L, 2);
+ // continuous
+ bool continuous = lua_toboolean(L, 3);
+ // Do it
+ co->moveTo(pos, continuous);
return 0;
}
+ // add_to_inventory(self, itemstring)
+ // returns: true if item was added, false otherwise
+ static int l_add_to_inventory(lua_State *L)
+ {
+ ObjectRef *ref = checkobject(L, 1);
+ luaL_checkstring(L, 2);
+ ServerActiveObject *co = getobject(ref);
+ if(co == NULL) return 0;
+ // itemstring
+ const char *itemstring = lua_tostring(L, 2);
+ infostream<<"ObjectRef::l_add_to_inventory(): id="<<co->getId()
+ <<" itemstring=\""<<itemstring<<"\""<<std::endl;
+ // Do it
+ std::istringstream is(itemstring, std::ios::binary);
+ InventoryItem *item = InventoryItem::deSerialize(is);
+ bool fits = co->addToInventory(item);
+ // Return
+ lua_pushboolean(L, fits);
+ return 1;
+ }
+
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
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),
+ method(ObjectRef, setpos),
+ method(ObjectRef, moveto),
+ method(ObjectRef, add_to_inventory),
{0,0}
};
+// Creates a new anonymous reference if id=0
+static void objectref_get_or_create(lua_State *L, ServerActiveObject *cobj)
+{
+ if(cobj->getId() == 0){
+ ObjectRef::create(L, cobj);
+ } else {
+ objectref_get(L, cobj->getId());
+ }
+}
+
+/*
+ Main export function
+*/
+
void scriptapi_export(lua_State *L, Server *server)
{
realitycheck(L);
assert(lua_checkstack(L, 20));
infostream<<"scriptapi_export"<<std::endl;
+ StackUnroller stack_unroller(L);
// Register global functions in table minetest
lua_newtable(L);
// Get the main minetest table
lua_getglobal(L, "minetest");
- // Add registered_objects table in minetest
+ // Add tables to minetest
+
+ /*lua_newtable(L);
+ lua_setfield(L, -2, "registered_blocks");*/
+
lua_newtable(L);
- lua_setfield(L, -2, "registered_objects");
+ lua_setfield(L, -2, "registered_entities");
+
+ lua_newtable(L);
+ lua_setfield(L, -2, "registered_globalsteps");
- // Add object_refs table in minetest
lua_newtable(L);
lua_setfield(L, -2, "object_refs");
- // Add luaentities table in minetest
lua_newtable(L);
lua_setfield(L, -2, "luaentities");
- // Load and run some base Lua stuff
- /*script_load(L, (porting::path_data + DIR_DELIM + "scripts"
- + DIR_DELIM + "base.lua").c_str());*/
-
- // Create entity reference metatable
- luaL_newmetatable(L, "minetest.entity_reference");
- lua_pop(L, 1);
-
// Create entity prototype
luaL_newmetatable(L, "minetest.entity");
// metatable.__index = metatable
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_luaentity_register(lua_State *L, u16 id, const char *name,
- const char *init_state)
+void scriptapi_add_environment(lua_State *L, ServerEnvironment *env)
{
realitycheck(L);
assert(lua_checkstack(L, 20));
- infostream<<"scriptapi_luaentity_register: id="<<id<<std::endl;
-
- // Create object as a dummy string (TODO: Create properly)
- lua_pushstring(L, "dummy object string");
+ infostream<<"scriptapi_add_environment"<<std::endl;
+ StackUnroller stack_unroller(L);
+
+ // 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");
+}
+
+#if 0
+// Dump stack top with the dump2 function
+static void dump2(lua_State *L, const char *name)
+{
+ // Dump object (debug)
+ lua_getglobal(L, "dump2");
+ luaL_checktype(L, -1, LUA_TFUNCTION);
+ lua_pushvalue(L, -2); // Get previous stack top as first parameter
+ lua_pushstring(L, name);
+ if(lua_pcall(L, 2, 0, 0))
+ script_error(L, "error: %s\n", lua_tostring(L, -1));
+}
+#endif
+
+/*
+ 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;
+ StackUnroller stack_unroller(L);
+
+ // Create object on stack
+ ObjectRef::create(L, cobj); // Puts ObjectRef (as userdata) on stack
int object = lua_gettop(L);
- // Get minetest.luaentities table
+ // Get minetest.object_refs table
lua_getglobal(L, "minetest");
- lua_getfield(L, -1, "luaentities");
+ lua_getfield(L, -1, "object_refs");
luaL_checktype(L, -1, LUA_TTABLE);
int objectstable = lua_gettop(L);
- // luaentities[id] = object
- lua_pushnumber(L, id); // Push id
+ // 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);
-
- lua_pop(L, 3); // pop luaentities, minetest and the object
}
-void scriptapi_luaentity_deregister(lua_State *L, u16 id)
+void scriptapi_rm_object_reference(lua_State *L, ServerActiveObject *cobj)
{
realitycheck(L);
assert(lua_checkstack(L, 20));
- infostream<<"scriptapi_luaentity_deregister: id="<<id<<std::endl;
+ infostream<<"scriptapi_rm_object_reference: id="<<cobj->getId()<<std::endl;
+ StackUnroller stack_unroller(L);
- // Get minetest.luaentities table
+ // Get minetest.object_refs table
lua_getglobal(L, "minetest");
- lua_getfield(L, -1, "luaentities");
+ lua_getfield(L, -1, "object_refs");
luaL_checktype(L, -1, LUA_TTABLE);
int objectstable = lua_gettop(L);
- /*// Get luaentities[id]
+ // Get object_refs[id]
lua_pushnumber(L, cobj->getId()); // Push id
lua_gettable(L, objectstable);
- // Object is at stack top
- lua_pop(L, 1); // pop object*/
+ // Set object reference to NULL
+ ObjectRef::set_null(L);
+ lua_pop(L, 1); // pop object
- // Set luaentities[id] = nil
+ // Set object_refs[id] = nil
lua_pushnumber(L, cobj->getId()); // Push id
lua_pushnil(L);
lua_settable(L, objectstable);
+}
+
+/*
+ environment
+*/
+
+void scriptapi_environment_step(lua_State *L, float dtime)
+{
+ realitycheck(L);
+ assert(lua_checkstack(L, 20));
+ //infostream<<"scriptapi_luaentity_step: id="<<id<<std::endl;
+ StackUnroller stack_unroller(L);
+
+ // Get minetest.registered_globalsteps
+ lua_getglobal(L, "minetest");
+ lua_getfield(L, -1, "registered_globalsteps");
+ luaL_checktype(L, -1, LUA_TTABLE);
+ int table = lua_gettop(L);
+ // Foreach
+ lua_pushnil(L);
+ while(lua_next(L, table) != 0){
+ // key at index -2 and value at index -1
+ luaL_checktype(L, -1, LUA_TFUNCTION);
+ // Call function
+ lua_pushnumber(L, dtime);
+ if(lua_pcall(L, 1, 0, 0))
+ script_error(L, "error: %s\n", lua_tostring(L, -1));
+ // value removed, keep key for next iteration
+ }
+}
+
+/*
+ luaentity
+*/
+
+bool scriptapi_luaentity_add(lua_State *L, u16 id, const char *name,
+ const char *init_state)
+{
+ realitycheck(L);
+ assert(lua_checkstack(L, 20));
+ infostream<<"scriptapi_luaentity_add: id="<<id<<" name=\""
+ <<name<<"\""<<std::endl;
+ StackUnroller stack_unroller(L);
- lua_pop(L, 2); // pop luaentities, minetest
+ // Create object as a dummy string (TODO: Create properly)
+
+ // Get minetest.registered_entities[name]
+ lua_getglobal(L, "minetest");
+ lua_getfield(L, -1, "registered_entities");
+ luaL_checktype(L, -1, LUA_TTABLE);
+ lua_pushstring(L, name);
+ lua_gettable(L, -2);
+ // Should be a table, which we will use as a prototype
+ //luaL_checktype(L, -1, LUA_TTABLE);
+ if(lua_type(L, -1) != LUA_TTABLE){
+ errorstream<<"LuaEntity name \""<<name<<"\" not defined"<<std::endl;
+ return false;
+ }
+ int prototype_table = lua_gettop(L);
+ //dump2(L, "prototype_table");
+
+ // Create entity object
+ lua_newtable(L);
+ int object = lua_gettop(L);
+
+ // Set object metatable
+ lua_pushvalue(L, prototype_table);
+ lua_setmetatable(L, -2);
+
+ // 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");
+
+ // minetest.luaentities[id] = object
+ lua_getglobal(L, "minetest");
+ lua_getfield(L, -1, "luaentities");
+ luaL_checktype(L, -1, LUA_TTABLE);
+ lua_pushnumber(L, id); // Push id
+ lua_pushvalue(L, object); // Copy object to top of stack
+ lua_settable(L, -3);
+
+ // This callback doesn't really make sense
+ /*// Get on_activate function
+ lua_pushvalue(L, object);
+ lua_getfield(L, -1, "on_activate");
+ 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 %s:on_activate: %s\n",
+ name, lua_tostring(L, -1));*/
+
+ return true;
}
-void scriptapi_luaentity_step(lua_State *L, u16 id,
- float dtime, bool send_recommended)
+void scriptapi_luaentity_rm(lua_State *L, u16 id)
{
realitycheck(L);
assert(lua_checkstack(L, 20));
- infostream<<"scriptapi_luaentity_step: id="<<id<<std::endl;
+ infostream<<"scriptapi_luaentity_rm: id="<<id<<std::endl;
// Get minetest.luaentities table
lua_getglobal(L, "minetest");
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);
-
- // TODO: Call step function
-
- lua_pop(L, 1); // pop object
+ // Set luaentities[id] = nil
+ lua_pushnumber(L, id); // Push id
+ lua_pushnil(L);
+ lua_settable(L, objectstable);
+
lua_pop(L, 2); // pop luaentities, minetest
}
return "";
}
-void scriptapi_add_object_reference(lua_State *L, ServerActiveObject *cobj)
+void scriptapi_luaentity_get_properties(lua_State *L, u16 id,
+ LuaEntityProperties *prop)
{
realitycheck(L);
assert(lua_checkstack(L, 20));
- infostream<<"scriptapi_add_object_reference: id="<<cobj->getId()<<std::endl;
+ infostream<<"scriptapi_luaentity_get_properties: id="<<id<<std::endl;
+ StackUnroller stack_unroller(L);
- // Create object on stack
- ObjectRef::create(L, cobj); // Puts ObjectRef (as userdata) on stack
- int object = lua_gettop(L);
+ // 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);
+ lua_getfield(L, -1, "physical");
+ if(lua_isboolean(L, -1))
+ prop->physical = lua_toboolean(L, -1);
+ lua_pop(L, 1);
- // 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);
+ lua_getfield(L, -1, "weight");
+ prop->weight = lua_tonumber(L, -1);
+ lua_pop(L, 1);
+
+ lua_getfield(L, -1, "collisionbox");
+ if(lua_istable(L, -1)){
+ lua_rawgeti(L, -1, 1);
+ prop->collisionbox.MinEdge.X = lua_tonumber(L, -1);
+ lua_pop(L, 1);
+ lua_rawgeti(L, -1, 2);
+ prop->collisionbox.MinEdge.Y = lua_tonumber(L, -1);
+ lua_pop(L, 1);
+ lua_rawgeti(L, -1, 3);
+ prop->collisionbox.MinEdge.Z = lua_tonumber(L, -1);
+ lua_pop(L, 1);
+ lua_rawgeti(L, -1, 4);
+ prop->collisionbox.MaxEdge.X = lua_tonumber(L, -1);
+ lua_pop(L, 1);
+ lua_rawgeti(L, -1, 5);
+ prop->collisionbox.MaxEdge.Y = lua_tonumber(L, -1);
+ lua_pop(L, 1);
+ lua_rawgeti(L, -1, 6);
+ prop->collisionbox.MaxEdge.Z = lua_tonumber(L, -1);
+ lua_pop(L, 1);
+ }
+ lua_pop(L, 1);
+
+ lua_getfield(L, -1, "visual");
+ if(lua_isstring(L, -1))
+ prop->visual = lua_tostring(L, -1);
+ lua_pop(L, 1);
- // pop object_refs, minetest and the object
- lua_pop(L, 3);
+ lua_getfield(L, -1, "textures");
+ if(lua_istable(L, -1)){
+ prop->textures.clear();
+ int table = lua_gettop(L);
+ lua_pushnil(L);
+ while(lua_next(L, table) != 0){
+ // key at index -2 and value at index -1
+ if(lua_isstring(L, -1))
+ prop->textures.push_back(lua_tostring(L, -1));
+ else
+ prop->textures.push_back("");
+ // removes value, keeps key for next iteration
+ lua_pop(L, 1);
+ }
+ }
+ lua_pop(L, 1);
+
}
-void scriptapi_rm_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_rm_object_reference: id="<<cobj->getId()<<std::endl;
+ //infostream<<"scriptapi_luaentity_step: id="<<id<<std::endl;
+ StackUnroller stack_unroller(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);
-
- // 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
+ // 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_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));
+}
- // 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);
+// Calls entity:on_punch(ObjectRef puncher)
+void scriptapi_luaentity_punch(lua_State *L, u16 id,
+ ServerActiveObject *puncher)
+{
+ realitycheck(L);
+ assert(lua_checkstack(L, 20));
+ //infostream<<"scriptapi_luaentity_step: id="<<id<<std::endl;
+ StackUnroller stack_unroller(L);
+
+ // Get minetest.luaentities[id]
+ luaentity_get(L, id);
+ int object = lua_gettop(L);
+ // State: object is at top of stack
+ // Get function
+ lua_getfield(L, -1, "on_punch");
+ luaL_checktype(L, -1, LUA_TFUNCTION);
+ lua_pushvalue(L, object); // self
+ objectref_get_or_create(L, puncher); // Clicker reference
+ // Call with 2 arguments, 0 results
+ if(lua_pcall(L, 2, 0, 0))
+ script_error(L, "error running function 'on_punch': %s\n", lua_tostring(L, -1));
+}
+
+// Calls entity:on_rightclick(ObjectRef clicker)
+void scriptapi_luaentity_rightclick(lua_State *L, u16 id,
+ ServerActiveObject *clicker)
+{
+ realitycheck(L);
+ assert(lua_checkstack(L, 20));
+ //infostream<<"scriptapi_luaentity_step: id="<<id<<std::endl;
+ StackUnroller stack_unroller(L);
+
+ // Get minetest.luaentities[id]
+ luaentity_get(L, id);
+ int object = lua_gettop(L);
+ // State: object is at top of stack
+ // Get function
+ lua_getfield(L, -1, "on_rightclick");
+ luaL_checktype(L, -1, LUA_TFUNCTION);
+ lua_pushvalue(L, object); // self
+ objectref_get_or_create(L, clicker); // Clicker reference
+ // Call with 2 arguments, 0 results
+ if(lua_pcall(L, 2, 0, 0))
+ script_error(L, "error running function 'on_rightclick': %s\n", lua_tostring(L, -1));
}