Node place/dig Lua callbacks
authorPerttu Ahola <celeron55@gmail.com>
Thu, 17 Nov 2011 09:22:24 +0000 (11:22 +0200)
committerPerttu Ahola <celeron55@gmail.com>
Tue, 29 Nov 2011 17:13:49 +0000 (19:13 +0200)
data/mods/default/init.lua
src/mapnode.h
src/scriptapi.cpp
src/scriptapi.h
src/server.cpp

index 5f8eeadee833093d44726d23e33cc570e5bd931b..966b807ae79fc3d11259cf2b54d5bdf189dc6a78 100644 (file)
@@ -78,7 +78,12 @@ end
 --
 -- Global functions:
 -- minetest.register_entity(name, prototype_table)
+-- minetest.register_tool(name, {lots of stuff})
+-- minetest.register_node(name, {lots of stuff})
+-- minetest.register_craft({output=item, recipe={...})
 -- minetest.register_globalstep(func)
+-- minetest.register_on_placenode(func)
+-- minetest.register_on_dignode(func)
 --
 -- Global objects:
 -- minetest.env - environment reference
@@ -91,9 +96,12 @@ end
 -- minetest.luaentities
 -- ^ List of lua entities, indexed by active object id
 --
+-- EnvRef is basically ServerEnvironment and ServerMap combined.
 -- EnvRef methods:
 -- - add_node(pos, content); pos={x=num, y=num, z=num}
+--   TODO: content -> MapNode as described below
 --
+-- ObjectRef is basically ServerActiveObject.
 -- ObjectRef methods:
 -- - remove(): remove object (after returning from Lua)
 -- - getpos(): returns {x=num, y=num, z=num}
@@ -106,6 +114,9 @@ end
 --   - It has the member .object, which is an ObjectRef pointing to the object
 --   - The original prototype stuff is visible directly via a metatable
 --
+-- MapNode representation:
+-- {name="name", param1=num, param2=num}
+--
 
 print("omg lol")
 print("minetest dump: "..dump(minetest))
@@ -117,6 +128,18 @@ end
 
 minetest.register_globalstep(on_step)
 
+function on_placenode(p, node)
+       print("on_placenode")
+end
+
+minetest.register_on_placenode(on_placenode)
+
+function on_dignode(p, node)
+       print("on_dignode")
+end
+
+minetest.register_on_dignode(on_dignode)
+
 minetest.register_tool("WPick", {
        image = "tool_woodpick.png",
        basetime = 2.0,
index e287ea54fec9f6137489bf34362a83de14115aa2..65fc3b3e29566394a31c58fa75d3be6bde212f7e 100644 (file)
@@ -183,6 +183,30 @@ struct MapNode
                        param2 |= (c&0x0f)<<4;
                }
        }
+       u8 getParam1() const
+       {
+               return param1;
+       }
+       void setParam1(u8 p)
+       {
+               param1 = p;
+       }
+       u8 getParam2() const
+       {
+               if(param0 < 0x80)
+                       return param2;
+               else
+                       return param2 & 0x0f;
+       }
+       void setParam2(u8 p)
+       {
+               if(param0 < 0x80)
+                       param2 = p;
+               else{
+                       param2 &= 0xf0;
+                       param2 |= (p&0x0f);
+               }
+       }
        
        void setLight(enum LightBank bank, u8 a_light, INodeDefManager *nodemgr);
        u8 getLight(enum LightBank bank, INodeDefManager *nodemgr) const;
index cd501060f9127a161f632b07b90d93e76f5cbad2..c9356fe4f4accad781f550d1b504284d9a305a65 100644 (file)
@@ -123,7 +123,7 @@ public:
        }
 };
 
-v3f readFloatPos(lua_State *L, int index)
+static v3f readFloatPos(lua_State *L, int index)
 {
        v3f pos;
        lua_pushvalue(L, index); // Push pos
@@ -142,6 +142,42 @@ v3f readFloatPos(lua_State *L, int index)
        return pos;
 }
 
+static void pushpos(lua_State *L, v3s16 p)
+{
+       lua_newtable(L);
+       lua_pushnumber(L, p.X);
+       lua_setfield(L, -2, "x");
+       lua_pushnumber(L, p.Y);
+       lua_setfield(L, -2, "y");
+       lua_pushnumber(L, p.Z);
+       lua_setfield(L, -2, "z");
+}
+
+static void pushnode(lua_State *L, const MapNode &n, INodeDefManager *ndef)
+{
+       lua_newtable(L);
+       lua_pushstring(L, ndef->get(n).name.c_str());
+       lua_setfield(L, -2, "name");
+       lua_pushnumber(L, n.getParam1());
+       lua_setfield(L, -2, "param1");
+       lua_pushnumber(L, n.getParam2());
+       lua_setfield(L, -2, "param2");
+}
+
+static MapNode readnode(lua_State *L, int index, INodeDefManager *ndef)
+{
+       lua_getfield(L, index, "name");
+       const char *name = lua_tostring(L, -1);
+       lua_pop(L, 1);
+       lua_getfield(L, index, "param1");
+       u8 param1 = lua_tonumber(L, -1);
+       lua_pop(L, 1);
+       lua_getfield(L, index, "param2");
+       u8 param2 = lua_tonumber(L, -1);
+       lua_pop(L, 1);
+       return MapNode(ndef, name, param1, param2);
+}
+
 /*
        Global functions
 */
@@ -180,32 +216,6 @@ static int l_register_entity(lua_State *L)
        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 */
-}
-
 // register_tool(name, {lots of stuff})
 static int l_register_tool(lua_State *L)
 {
@@ -395,12 +405,90 @@ static int l_register_craft(lua_State *L)
        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 */
+}
+
+// register_on_placenode(function)
+static int l_register_on_placenode(lua_State *L)
+{
+       luaL_checktype(L, 1, LUA_TFUNCTION);
+       infostream<<"register_on_placenode"<<std::endl;
+
+       lua_getglobal(L, "table");
+       lua_getfield(L, -1, "insert");
+       int table_insert = lua_gettop(L);
+       // Get minetest.registered_on_placenodes
+       lua_getglobal(L, "minetest");
+       lua_getfield(L, -1, "registered_on_placenodes");
+       luaL_checktype(L, -1, LUA_TTABLE);
+       int registered_on_placenodes = lua_gettop(L);
+       // table.insert(registered_on_placenodes, func)
+       lua_pushvalue(L, table_insert);
+       lua_pushvalue(L, registered_on_placenodes);
+       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 */
+}
+
+// register_on_dignode(function)
+static int l_register_on_dignode(lua_State *L)
+{
+       luaL_checktype(L, 1, LUA_TFUNCTION);
+       infostream<<"register_on_dignode"<<std::endl;
+
+       lua_getglobal(L, "table");
+       lua_getfield(L, -1, "insert");
+       int table_insert = lua_gettop(L);
+       // Get minetest.registered_on_dignodes
+       lua_getglobal(L, "minetest");
+       lua_getfield(L, -1, "registered_on_dignodes");
+       luaL_checktype(L, -1, LUA_TTABLE);
+       int registered_on_dignodes = lua_gettop(L);
+       // table.insert(registered_on_dignodes, func)
+       lua_pushvalue(L, table_insert);
+       lua_pushvalue(L, registered_on_dignodes);
+       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_entity", l_register_entity},
-       {"register_globalstep", l_register_globalstep},
        {"register_tool", l_register_tool},
        {"register_node", l_register_node},
        {"register_craft", l_register_craft},
+       {"register_globalstep", l_register_globalstep},
+       {"register_on_placenode", l_register_on_placenode},
+       {"register_on_dignode", l_register_on_dignode},
        {NULL, NULL}
 };
 
@@ -807,6 +895,12 @@ void scriptapi_export(lua_State *L, Server *server)
        lua_newtable(L);
        lua_setfield(L, -2, "registered_globalsteps");
 
+       lua_newtable(L);
+       lua_setfield(L, -2, "registered_on_placenodes");
+
+       lua_newtable(L);
+       lua_setfield(L, -2, "registered_on_dignodes");
+
        lua_newtable(L);
        lua_setfield(L, -2, "object_refs");
 
@@ -922,7 +1016,7 @@ void scriptapi_environment_step(lua_State *L, float dtime)
 {
        realitycheck(L);
        assert(lua_checkstack(L, 20));
-       //infostream<<"scriptapi_luaentity_step: id="<<id<<std::endl;
+       //infostream<<"scriptapi_environment_step"<<std::endl;
        StackUnroller stack_unroller(L);
 
        // Get minetest.registered_globalsteps
@@ -943,6 +1037,72 @@ void scriptapi_environment_step(lua_State *L, float dtime)
        }
 }
 
+void scriptapi_environment_on_placenode(lua_State *L, v3s16 p, MapNode newnode)
+{
+       realitycheck(L);
+       assert(lua_checkstack(L, 20));
+       //infostream<<"scriptapi_environment_on_placenode"<<std::endl;
+       StackUnroller stack_unroller(L);
+
+       // Get server from registry
+       lua_getfield(L, LUA_REGISTRYINDEX, "minetest_server");
+       Server *server = (Server*)lua_touserdata(L, -1);
+       // And get the writable node definition manager from the server
+       IWritableNodeDefManager *ndef =
+                       server->getWritableNodeDefManager();
+       
+       // Get minetest.registered_on_placenodes
+       lua_getglobal(L, "minetest");
+       lua_getfield(L, -1, "registered_on_placenodes");
+       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
+               pushpos(L, p);
+               pushnode(L, newnode, ndef);
+               if(lua_pcall(L, 2, 0, 0))
+                       script_error(L, "error: %s\n", lua_tostring(L, -1));
+               // value removed, keep key for next iteration
+       }
+}
+
+void scriptapi_environment_on_dignode(lua_State *L, v3s16 p, MapNode oldnode)
+{
+       realitycheck(L);
+       assert(lua_checkstack(L, 20));
+       //infostream<<"scriptapi_environment_on_dignode"<<std::endl;
+       StackUnroller stack_unroller(L);
+
+       // Get server from registry
+       lua_getfield(L, LUA_REGISTRYINDEX, "minetest_server");
+       Server *server = (Server*)lua_touserdata(L, -1);
+       // And get the writable node definition manager from the server
+       IWritableNodeDefManager *ndef =
+                       server->getWritableNodeDefManager();
+       
+       // Get minetest.registered_on_dignodes
+       lua_getglobal(L, "minetest");
+       lua_getfield(L, -1, "registered_on_dignodes");
+       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
+               pushpos(L, p);
+               pushnode(L, oldnode, ndef);
+               if(lua_pcall(L, 2, 0, 0))
+                       script_error(L, "error: %s\n", lua_tostring(L, -1));
+               // value removed, keep key for next iteration
+       }
+}
+
 /*
        luaentity
 */
index ecd3d7b81b0fe30749bd163e1e45f8971d19d722..e7ff84039e8aea72d26327f2754e4ae15b0a4aff 100644 (file)
@@ -22,6 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 
 #include "irrlichttypes.h"
 #include <string>
+#include "mapnode.h"
 
 class Server;
 class ServerEnvironment;
@@ -37,7 +38,12 @@ void scriptapi_add_object_reference(lua_State *L, ServerActiveObject *cobj);
 void scriptapi_rm_object_reference(lua_State *L, ServerActiveObject *cobj);
 
 /* environment */
+// On environment step
 void scriptapi_environment_step(lua_State *L, float dtime);
+// After adding node
+void scriptapi_environment_on_placenode(lua_State *L, v3s16 p, MapNode newnode);
+// After removing node
+void scriptapi_environment_on_dignode(lua_State *L, v3s16 p, MapNode oldnode);
 
 /* luaentity */
 // Returns true if succesfully added into Lua; false otherwise.
index 894c3d362d1c5c5dc65782b1978a1109233e9c0c..4671530310198bcd64c720c179cc6f1758d903e3 100644 (file)
@@ -2527,10 +2527,11 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                        u8 mineral = MINERAL_NONE;
 
                        bool cannot_remove_node = false;
-
+                       
+                       MapNode n(CONTENT_IGNORE);
                        try
                        {
-                               MapNode n = m_env->getMap().getNode(p_under);
+                               n = m_env->getMap().getNode(p_under);
                                // Get mineral
                                mineral = n.getMineral(m_nodedef);
                                // Get material at position
@@ -2734,6 +2735,11 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                                        continue;
                                client->SetBlocksNotSent(modified_blocks);
                        }
+
+                       /*
+                               Run script hook
+                       */
+                       scriptapi_environment_on_dignode(m_lua, p_under, n);
                }
                
                /*
@@ -2877,6 +2883,11 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                                        client->SetBlocksNotSent(modified_blocks);
                                }
 
+                               /*
+                                       Run script hook
+                               */
+                               scriptapi_environment_on_placenode(m_lua, p_over, n);
+
                                /*
                                        Calculate special events
                                */