Scripting WIP; Lua entity step callback works
authorPerttu Ahola <celeron55@gmail.com>
Fri, 11 Nov 2011 22:46:05 +0000 (00:46 +0200)
committerPerttu Ahola <celeron55@gmail.com>
Tue, 29 Nov 2011 17:13:39 +0000 (19:13 +0200)
data/scripts/default.lua
src/content_sao.cpp
src/scriptapi.cpp
src/scriptapi.h

index c525ecf1e4331a0ef7962b690d12796f600ee1a8..005e9ac1570460522f232d032d9556f92dad21e0 100644 (file)
@@ -61,7 +61,7 @@ end]]
        return s
 end]]
 
-function basic_serialize(o)
+function basic_dump2(o)
        if type(o) == "number" then
                return tostring(o)
        elseif type(o) == "string" then
@@ -70,6 +70,8 @@ function basic_serialize(o)
                return tostring(o)
        elseif type(o) == "function" then
                return "<function>"
+       elseif type(o) == "userdata" then
+               return "<userdata>"
        elseif type(o) == "nil" then
                return "nil"
        else
@@ -78,13 +80,14 @@ function basic_serialize(o)
        end
 end
 
-function serialize(o, name, dumped)
+function dump2(o, name, dumped)
        name = name or "_"
        dumped = dumped or {}
        io.write(name, " = ")
        if type(o) == "number" or type(o) == "string" or type(o) == "boolean"
-                       or type(o) == "function" or type(o) == "nil" then
-               io.write(basic_serialize(o), "\n")
+                       or type(o) == "function" or type(o) == "nil"
+                       or type(o) == "userdata" then
+               io.write(basic_dump2(o), "\n")
        elseif type(o) == "table" then
                if dumped[o] then
                        io.write(dumped[o], "\n")
@@ -92,8 +95,8 @@ function serialize(o, name, dumped)
                        dumped[o] = name
                        io.write("{}\n") -- new table
                        for k,v in pairs(o) do
-                               local fieldname = string.format("%s[%s]", name, basic_serialize(k))
-                               serialize(v, fieldname, dumped)
+                               local fieldname = string.format("%s[%s]", name, basic_dump2(k))
+                               dump2(v, fieldname, dumped)
                        end
                end
        else
@@ -131,8 +134,6 @@ end
 print("omg lol")
 print("minetest dump: "..dump(minetest))
 
-minetest.register_entity("a", "dummy string");
-
 --local TNT = minetest.new_entity {
 local TNT = {
        -- Maybe handle gravity and collision this way? dunno
@@ -148,30 +149,34 @@ local TNT = {
 }
 
 -- Called after object is created
-function TNT:on_create(env)
+function TNT:on_create()
+       print("TNT:on_create()")
 end
 
 -- Called periodically
-function TNT:on_step(env, dtime)
-       self.timer = self.timer + dtime
+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
+       end]]
 end
 
 -- Called when object is punched
-function TNT:on_punch(env, hitter)
-       -- If tool is bomb defuser, revert back to being a block
+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]]
 end
 
 -- Called when object is right-clicked
-function TNT:on_rightclick(self, env, hitter)
+function TNT:on_rightclick(clicker)
+       print("TNT:on_rightclick()")
 end
 
 print("TNT dump: "..dump(TNT))
@@ -181,5 +186,5 @@ minetest.register_entity("TNT", TNT)
 
 --print("minetest.registered_entities: "..dump(minetest.registered_entities))
 print("minetest.registered_entities:")
-serialize(minetest.registered_entities)
+dump2(minetest.registered_entities)
 
index d1303b4712686b46fe005e82538240601b52b5dd..3507ec1542d7fbb8883b8bed07d1bf0f184eb3ea 100644 (file)
@@ -1516,7 +1516,7 @@ LuaEntitySAO::~LuaEntitySAO()
 {
        if(m_registered){
                lua_State *L = m_env->getLua();
-               scriptapi_luaentity_deregister(L, m_id);
+               scriptapi_luaentity_rm(L, m_id);
        }
 }
 
@@ -1527,7 +1527,7 @@ void LuaEntitySAO::addedToEnvironment(u16 id)
        // Create entity by name and state
        m_registered = true;
        lua_State *L = m_env->getLua();
-       scriptapi_luaentity_register(L, id, m_init_name.c_str(), m_init_state.c_str());
+       scriptapi_luaentity_add(L, id, m_init_name.c_str(), m_init_state.c_str());
 }
 
 ServerActiveObject* LuaEntitySAO::create(ServerEnvironment *env, v3f pos,
@@ -1553,7 +1553,7 @@ void LuaEntitySAO::step(float dtime, bool send_recommended)
 {
        if(m_registered){
                lua_State *L = m_env->getLua();
-               scriptapi_luaentity_step(L, m_id, dtime, send_recommended);
+               scriptapi_luaentity_step(L, m_id, dtime);
        }
 }
 
@@ -1578,7 +1578,6 @@ std::string LuaEntitySAO::getStaticData()
        // state
        if(m_registered){
                lua_State *L = m_env->getLua();
-               scriptapi_luaentity_deregister(L, m_id);
                std::string state = scriptapi_luaentity_get_state(L, m_id);
                os<<serializeLongString(state);
        } else {
index d055c19766ffe55d90cf8526ca5ccaffc3790d3f..fc5364c8776e824e12a3b7d962d6da3fbbd835ef 100644 (file)
@@ -76,21 +76,36 @@ static void realitycheck(lua_State *L)
        }
 }
 
-// Register new object prototype (must be based on entity)
+// Register new object prototype
+// register_entity(name, prototype)
 static int l_register_entity(lua_State *L)
 {
        const char *name = luaL_checkstring(L, 1);
-       luaL_checkany(L, 2);
+       luaL_checktype(L, 2, LUA_TTABLE);
        infostream<<"register_entity: "<<name<<std::endl;
-       // Get the minetest table
+
+       // Get minetest.registered_entities
        lua_getglobal(L, "minetest");
-       // Get field "registered_entities"
        lua_getfield(L, -1, "registered_entities");
        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_entities[name] = object
+       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 0; /* number of results */
 }
@@ -286,36 +301,76 @@ void scriptapi_export(lua_State *L, Server *server)
        ObjectRef::Register(L);
 }
 
-void scriptapi_luaentity_register(lua_State *L, u16 id, const char *name,
+// 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));
+}
+
+void 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_register: id="<<id<<std::endl;
+       infostream<<"scriptapi_luaentity_add: id="<<id<<" name=\""
+                       <<name<<"\""<<std::endl;
+
+       int initial_top = lua_gettop(L);
        
        // Create object as a dummy string (TODO: Create properly)
-       lua_pushstring(L, "dummy object string");
+
+       // 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);
+       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);
+       
+       /*// 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");*/
+
        // Get minetest.luaentities table
        lua_getglobal(L, "minetest");
        lua_getfield(L, -1, "luaentities");
        luaL_checktype(L, -1, LUA_TTABLE);
-       int objectstable = lua_gettop(L);
+       int luaentities = lua_gettop(L);
        
        // luaentities[id] = object
        lua_pushnumber(L, id); // Push id
        lua_pushvalue(L, object); // Copy object to top of stack
-       lua_settable(L, objectstable);
+       lua_settable(L, luaentities);
        
-       lua_pop(L, 3); // pop luaentities, minetest and the object
+       lua_settop(L, initial_top); // Reset stack
 }
 
-void scriptapi_luaentity_deregister(lua_State *L, u16 id)
+void scriptapi_luaentity_rm(lua_State *L, u16 id)
 {
        realitycheck(L);
        assert(lua_checkstack(L, 20));
-       infostream<<"scriptapi_luaentity_deregister: id="<<id<<std::endl;
+       infostream<<"scriptapi_luaentity_rm: id="<<id<<std::endl;
 
        // Get minetest.luaentities table
        lua_getglobal(L, "minetest");
@@ -337,24 +392,35 @@ void scriptapi_luaentity_deregister(lua_State *L, u16 id)
        lua_pop(L, 2); // pop luaentities, minetest
 }
 
-void scriptapi_luaentity_step(lua_State *L, u16 id,
-               float dtime, bool send_recommended)
+void scriptapi_luaentity_step(lua_State *L, u16 id, float dtime)
 {
        realitycheck(L);
        assert(lua_checkstack(L, 20));
-       //infostream<<"scriptapi_luaentity_step: id="<<id<<std::endl;
+       infostream<<"scriptapi_luaentity_step: id="<<id<<std::endl;
 
-       // Get minetest.luaentities table
+       // Get minetest.luaentities[i]
        lua_getglobal(L, "minetest");
        lua_getfield(L, -1, "luaentities");
        luaL_checktype(L, -1, LUA_TTABLE);
-       int objectstable = lua_gettop(L);
-       
-       // Get luaentities[id]
-       lua_pushnumber(L, id); // Push id
-       lua_gettable(L, objectstable);
-
-       // TODO: Call step function
+       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
index a97d707a831d8cc884fd7d306feeb86f5849f303..18c2b3838a44ef75b027028ed762c7397e469fb2 100644 (file)
@@ -32,11 +32,10 @@ void scriptapi_export(lua_State *L, Server *server);
 void scriptapi_add_object_reference(lua_State *L, ServerActiveObject *cobj);
 void scriptapi_rm_object_reference(lua_State *L, ServerActiveObject *cobj);
 
-void scriptapi_luaentity_register(lua_State *L, u16 id, const char *name,
+void scriptapi_luaentity_add(lua_State *L, u16 id, const char *name,
                const char *init_state);
-void scriptapi_luaentity_deregister(lua_State *L, u16 id);
-void scriptapi_luaentity_step(lua_State *L, u16 id,
-               float dtime, bool send_recommended);
+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);
 
 #endif