Initial NodeMetaRef stuff
authorPerttu Ahola <celeron55@gmail.com>
Mon, 28 Nov 2011 01:06:21 +0000 (03:06 +0200)
committerPerttu Ahola <celeron55@gmail.com>
Tue, 29 Nov 2011 17:13:56 +0000 (19:13 +0200)
data/mods/default/init.lua
src/scriptapi.cpp
src/server.cpp

index c59c34fc79dd4a44715f73cd00f9b5b0b8afd794..3954c717f60aa9a74b0a19bb2fac3d7fcc5b565f 100644 (file)
 -- - remove_node(pos)
 -- - get_node(pos)
 -- - add_luaentity(pos, name)
+-- - get_meta(pos) -- Get a NodeMetaRef at that position
+--
+-- NodeMetaRef
+-- - settext(text) -- eg. set the text of a sign
 --
 -- ObjectRef is basically ServerActiveObject.
 -- ObjectRef methods:
@@ -1359,7 +1363,8 @@ minetest.register_on_chat_message(function(name, message)
        end
 end)
 
-minetest.register_abm({
+-- Grow papyrus on TNT every 10 seconds
+--[[minetest.register_abm({
        nodenames = {"TNT"},
        interval = 10.0,
        chance = 1,
@@ -1368,7 +1373,23 @@ minetest.register_abm({
                pos.y = pos.y + 1
                minetest.env:add_node(pos, {name="papyrus"})
        end,
-})
+})]]
+
+-- Replace texts of alls signs with "foo" every 10 seconds
+--[[minetest.register_abm({
+       nodenames = {"sign_wall"},
+       interval = 10.0,
+       chance = 1,
+       action = function(pos, node, active_object_count, active_object_count_wider)
+               print("ABM: Sign text changed")
+               local meta = minetest.env:get_meta(pos)
+               meta:settext("foo")
+       end,
+})]]
+
+-- LuaNodeMetadata should support something like this
+--meta.setvar("somevariable", {x=0, y=0, z=0})
+--meta.getvar("somevariable") -> {x=0, y=0, z=0}
 
 --
 -- Done, print some random stuff
index 3294ac57f4b24d9357fbc6e0a4810f6caf4b83bf..bf2868907aabcf80c3b4fde870ec53a7a8ba3d4e 100644 (file)
@@ -40,14 +40,12 @@ extern "C" {
 #include "craftdef.h"
 #include "main.h" // For g_settings
 #include "settings.h" // For accessing g_settings
+#include "nodemetadata.h"
+#include "mapblock.h" // For getNodeBlockPos
 
 /*
 TODO:
-- Random node triggers (like grass growth)
 - All kinds of callbacks
-- Object visual client-side stuff
-       - Blink effect
-       - Spritesheets and animation
 - LuaNodeMetadata
        blockdef.metadata_name =
                ""
@@ -62,7 +60,7 @@ TODO:
        meta.set("owner", playername)
        meta.get("owner")
 - Item definition (actually, only CraftItem)
-- (not scripting) Putting items in node metadata (virtual)
+- Putting items in NodeMetadata (?)
 */
 
 static void stackDump(lua_State *L, std::ostream &o)
@@ -584,6 +582,7 @@ static int l_register_abm(lua_State *L)
                if(lua_isnil(L, -1))
                        break;
                lua_pop(L, 1);
+               id++;
        }
        lua_pop(L, 1);
 
@@ -1038,10 +1037,135 @@ static void luaentity_get(lua_State *L, u16 id)
 }
 
 /*
-       Reference objects
+       Reference wrappers
 */
+
 #define method(class, name) {#name, class::l_##name}
 
+/*
+       NodeMetaRef
+*/
+
+class NodeMetaRef
+{
+private:
+       v3s16 m_p;
+       ServerEnvironment *m_env;
+
+       static const char className[];
+       static const luaL_reg methods[];
+
+       static NodeMetaRef *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 *(NodeMetaRef**)ud;  // unbox pointer
+       }
+       
+       static NodeMetadata* getmeta(NodeMetaRef *ref)
+       {
+               NodeMetadata *meta = ref->m_env->getMap().getNodeMetadata(ref->m_p);
+               return meta;
+       }
+
+       static void reportMetadataChange(NodeMetaRef *ref)
+       {
+               // Inform other things that the metadata has changed
+               v3s16 blockpos = getNodeBlockPos(ref->m_p);
+               MapEditEvent event;
+               event.type = MEET_BLOCK_NODE_METADATA_CHANGED;
+               event.p = blockpos;
+               ref->m_env->getMap().dispatchEvent(&event);
+               // Set the block to be saved
+               MapBlock *block = ref->m_env->getMap().getBlockNoCreateNoEx(blockpos);
+               if(block)
+                       block->raiseModified(MOD_STATE_WRITE_NEEDED, "l_settext");
+       }
+       
+       // Exported functions
+       
+       // garbage collector
+       static int gc_object(lua_State *L) {
+               NodeMetaRef *o = *(NodeMetaRef **)(lua_touserdata(L, 1));
+               delete o;
+               return 0;
+       }
+
+       // settext(self, text)
+       static int l_settext(lua_State *L)
+       {
+               NodeMetaRef *ref = checkobject(L, 1);
+               NodeMetadata *meta = getmeta(ref);
+               if(meta == NULL) return 0;
+               // Do it
+               std::string text = lua_tostring(L, 2);
+               meta->setText(text);
+               // Inform other things that the metadata has changed
+               reportMetadataChange(ref);
+               return 0;
+       }
+
+public:
+       NodeMetaRef(v3s16 p, ServerEnvironment *env):
+               m_p(p),
+               m_env(env)
+       {
+       }
+
+       ~NodeMetaRef()
+       {
+       }
+
+       // Creates an NodeMetaRef 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, v3s16 p, ServerEnvironment *env)
+       {
+               NodeMetaRef *o = new NodeMetaRef(p, env);
+               //infostream<<"NodeMetaRef::create: o="<<o<<std::endl;
+               *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
+               luaL_getmetatable(L, className);
+               lua_setmetatable(L, -2);
+       }
+
+       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 NodeMetaRef::className[] = "NodeMetaRef";
+const luaL_reg NodeMetaRef::methods[] = {
+       method(NodeMetaRef, settext),
+       {0,0}
+};
+
+/*
+       EnvRef
+*/
+
 class EnvRef
 {
 private:
@@ -1129,6 +1253,19 @@ private:
                return 0;
        }
 
+       // EnvRef:get_meta(pos)
+       static int l_get_meta(lua_State *L)
+       {
+               infostream<<"EnvRef::l_get_meta()"<<std::endl;
+               EnvRef *o = checkobject(L, 1);
+               ServerEnvironment *env = o->m_env;
+               if(env == NULL) return 0;
+               // Do it
+               v3s16 p = readpos(L, 2);
+               NodeMetaRef::create(L, p, env);
+               return 1;
+       }
+
        static int gc_object(lua_State *L) {
                EnvRef *o = *(EnvRef **)(lua_touserdata(L, 1));
                delete o;
@@ -1198,9 +1335,14 @@ const luaL_reg EnvRef::methods[] = {
        method(EnvRef, remove_node),
        method(EnvRef, get_node),
        method(EnvRef, add_luaentity),
+       method(EnvRef, get_meta),
        {0,0}
 };
 
+/*
+       ObjectRef
+*/
+
 class ObjectRef
 {
 private:
@@ -1536,11 +1678,10 @@ void scriptapi_export(lua_State *L, Server *server)
        // Put functions in metatable
        luaL_register(L, NULL, minetest_entity_m);
        // Put other stuff in metatable
-
-       // Environment C reference
+       
+       // Register reference wrappers
+       NodeMetaRef::Register(L);
        EnvRef::Register(L);
-
-       // Object C reference
        ObjectRef::Register(L);
 }
 
index bb91749afaa4458f24b8785e54dac96da919433e..51f8814feb92f4b5e66dd59375ce98a86a7f377c 100644 (file)
@@ -3190,12 +3190,10 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                NodeMetadata *meta = m_env->getMap().getNodeMetadata(p);
                if(!meta)
                        return;
-               if(meta->typeId() != LEGN(m_nodedef, "CONTENT_SIGN_WALL"))
-                       return;
-               SignNodeMetadata *signmeta = (SignNodeMetadata*)meta;
-               signmeta->setText(text);
+
+               meta->setText(text);
                
-               actionstream<<player->getName()<<" writes \""<<text<<"\" to sign "
+               actionstream<<player->getName()<<" writes \""<<text<<"\" to sign"
                                <<" at "<<PP(p)<<std::endl;
                                
                v3s16 blockpos = getNodeBlockPos(p);