Add player inventory callbacks
authorSmallJoker <mk939@ymail.com>
Sat, 31 Mar 2018 10:30:43 +0000 (12:30 +0200)
committerLoïc Blot <nerzhul@users.noreply.github.com>
Mon, 2 Apr 2018 15:18:48 +0000 (17:18 +0200)
builtin/game/register.lua
doc/lua_api.txt
src/inventorymanager.cpp
src/script/cpp_api/s_player.cpp
src/script/cpp_api/s_player.h

index 7b2b149e3fa58f18e7430c8b4d9c3f01898ad0f1..1e478bc3529082f75bfd4d2c9ad860e57f806611 100644 (file)
@@ -593,6 +593,8 @@ core.registered_on_priv_revoke, core.register_on_priv_revoke = make_registration
 core.registered_can_bypass_userlimit, core.register_can_bypass_userlimit = make_registration()
 core.registered_on_modchannel_message, core.register_on_modchannel_message = make_registration()
 core.registered_on_auth_fail, core.register_on_auth_fail = make_registration()
+core.registered_on_player_inventory_actions, core.register_on_player_inventory_action = make_registration()
+core.registered_allow_player_inventory_actions, core.register_allow_player_inventory_action = make_registration()
 
 --
 -- Compatibility for on_mapgen_init()
index 00f5e3f71489592e7e474258e4183f14edec0f0f..0c995b54eeea48876456c70af618ded62cf9c0d9 100644 (file)
@@ -2880,6 +2880,22 @@ Call these functions only at load time!
 * `minetest.register_craft_predict(func(itemstack, player, old_craft_grid, craft_inv))`
     * The same as before, except that it is called before the player crafts, to
       make craft prediction, and it should not change anything.
+* `minetest.register_allow_player_inventory_action(func(player, inventory, action, inventory_info))`
+    * Determinates how much of a stack may be taken, put or moved to a
+      player inventory.
+    * `player` (type `ObjectRef`) is the player who modified the inventory
+      `inventory` (type `InvRef`).
+    * List of possible `action` (string) values and their
+      `inventory_info` (table) contents:
+        * `move`: `{from_list=string, to_list=string, from_index=number, to_index=number, count=number}`
+        * `put`:  `{listname=string, index=number, stack=ItemStack}`
+        * `take`: Same as `put`
+    * Return a numeric value to limit the amount of items to be taken, put or
+      moved. A value of `-1` for `take` will make the source stack infinite.
+* `minetest.register_on_player_inventory_action(func(player, inventory, action, inventory_info))`
+    * Called after a take, put or move event from/to/in a player inventory
+    * Function arguments: see `minetest.register_allow_player_inventory_action`
+    * Does not accept or handle any return value.
 * `minetest.register_on_protection_violation(func(pos, name))`
     * Called by `builtin` and mods when a player violates protection at a
       position (eg, digs a node or punches a protected entity).
index ad567f44cdfee3af8babf2adf8e021b28a85b406..0243bd3c0ca37edd72b7a9c581a6113065d4a892 100644 (file)
@@ -314,6 +314,33 @@ void IMoveAction::apply(InventoryManager *mgr, ServerActiveObject *player, IGame
                }
        }
 
+       // Query player inventories
+
+       // Move occurs in the same player inventory
+       if (from_inv.type == InventoryLocation::PLAYER &&
+                       to_inv.type == InventoryLocation::PLAYER &&
+                       from_inv.name == to_inv.name) {
+               src_can_take_count = PLAYER_TO_SA(player)->player_inventory_AllowMove(
+                       from_inv, from_list, from_i,
+                       to_list, to_i, try_take_count, player);
+               dst_can_put_count = src_can_take_count;
+       } else {
+               // Destination is a player
+               if (to_inv.type == InventoryLocation::PLAYER) {
+                       ItemStack src_item = list_from->getItem(from_i);
+                       src_item.count = try_take_count;
+                       dst_can_put_count = PLAYER_TO_SA(player)->player_inventory_AllowPut(
+                               to_inv, to_list, to_i, src_item, player);
+               }
+               // Source is a player
+               if (from_inv.type == InventoryLocation::PLAYER) {
+                       ItemStack src_item = list_from->getItem(from_i);
+                       src_item.count = try_take_count;
+                       src_can_take_count = PLAYER_TO_SA(player)->player_inventory_AllowTake(
+                               from_inv, from_list, from_i, src_item, player);
+               }
+       }
+
        int old_count = count;
 
        /* Modify count according to collected data */
@@ -482,12 +509,34 @@ void IMoveAction::apply(InventoryManager *mgr, ServerActiveObject *player, IGame
                                        to_inv.p, to_list, to_i, src_item, player);
                }
                // Source is nodemeta
-               else if (from_inv.type == InventoryLocation::NODEMETA) {
+               if (from_inv.type == InventoryLocation::NODEMETA) {
                        PLAYER_TO_SA(player)->nodemeta_inventory_OnTake(
                                        from_inv.p, from_list, from_i, src_item, player);
                }
        }
 
+       // Player inventories
+
+       // Both endpoints are same player inventory
+       if (from_inv.type == InventoryLocation::PLAYER &&
+                       to_inv.type == InventoryLocation::PLAYER &&
+                       from_inv.name == to_inv.name) {
+               PLAYER_TO_SA(player)->player_inventory_OnMove(
+                       from_inv, from_list, from_i,
+                       to_list, to_i, count, player);
+       } else {
+               // Destination is player inventory
+               if (to_inv.type == InventoryLocation::PLAYER) {
+                       PLAYER_TO_SA(player)->player_inventory_OnPut(
+                               to_inv, to_list, to_i, src_item, player);
+               }
+               // Source is player inventory
+               if (from_inv.type == InventoryLocation::PLAYER) {
+                       PLAYER_TO_SA(player)->player_inventory_OnTake(
+                               from_inv, from_list, from_i, src_item, player);
+               }
+       }
+
        mgr->setInventoryModified(from_inv, false);
        if (inv_from != inv_to)
                mgr->setInventoryModified(to_inv, false);
index cc2b96d5e6e6e1f83bdecbcbdd205051697184f6..8c01f9b1f7c9f3dd275a67235b85fd7530978192 100644 (file)
@@ -22,6 +22,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "common/c_converter.h"
 #include "common/c_content.h"
 #include "debug.h"
+#include "inventorymanager.h"
+#include "lua_api/l_inventory.h"
+#include "lua_api/l_item.h"
 #include "util/string.h"
 
 void ScriptApiPlayer::on_newplayer(ServerActiveObject *player)
@@ -225,3 +228,146 @@ void ScriptApiPlayer::on_auth_failure(const std::string &name, const std::string
        lua_pushstring(L, ip.c_str());
        runCallbacks(2, RUN_CALLBACKS_MODE_FIRST);
 }
+
+void ScriptApiPlayer::pushMoveArguments(
+               const InventoryLocation &loc,
+               const std::string &from_list, int from_index,
+               const std::string &to_list, int to_index,
+               int count, ServerActiveObject *player)
+{
+       lua_State *L = getStack();
+       objectrefGetOrCreate(L, player); // player
+       lua_pushstring(L, "move");       // action
+       InvRef::create(L, loc);          // inventory
+       lua_newtable(L);
+       {
+               // Table containing the action information
+               lua_pushstring(L, from_list.c_str());
+               lua_setfield(L, -2, "from_list");
+               lua_pushstring(L, to_list.c_str());
+               lua_setfield(L, -2, "to_list");
+
+               lua_pushinteger(L, from_index + 1);
+               lua_setfield(L, -2, "from_index");
+               lua_pushinteger(L, to_index + 1);
+               lua_setfield(L, -2, "to_index");
+
+               lua_pushinteger(L, count);
+               lua_setfield(L, -2, "count");
+       }
+}
+
+void ScriptApiPlayer::pushPutTakeArguments(
+               const char *method, const InventoryLocation &loc,
+               const std::string &listname, int index, const ItemStack &stack,
+               ServerActiveObject *player)
+{
+       lua_State *L = getStack();
+       objectrefGetOrCreate(L, player); // player
+       lua_pushstring(L, method);       // action
+       InvRef::create(L, loc);          // inventory
+       lua_newtable(L);
+       {
+               // Table containing the action information
+               lua_pushstring(L, listname.c_str());
+               lua_setfield(L, -2, "listname");
+
+               lua_pushinteger(L, index + 1);
+               lua_setfield(L, -2, "index");
+
+               LuaItemStack::create(L, stack);
+               lua_setfield(L, -2, "stack");
+       }
+}
+
+// Return number of accepted items to be moved
+int ScriptApiPlayer::player_inventory_AllowMove(
+               const InventoryLocation &loc,
+               const std::string &from_list, int from_index,
+               const std::string &to_list, int to_index,
+               int count, ServerActiveObject *player)
+{
+       SCRIPTAPI_PRECHECKHEADER
+
+       lua_getglobal(L, "core");
+       lua_getfield(L, -1, "registered_allow_player_inventory_actions");
+       pushMoveArguments(loc, from_list, from_index, to_list, to_index, count, player);
+       runCallbacks(4, RUN_CALLBACKS_MODE_OR_SC);
+
+       return lua_type(L, -1) == LUA_TNUMBER ? lua_tonumber(L, -1) : count;
+}
+
+// Return number of accepted items to be put
+int ScriptApiPlayer::player_inventory_AllowPut(
+               const InventoryLocation &loc,
+               const std::string &listname, int index, const ItemStack &stack,
+               ServerActiveObject *player)
+{
+       SCRIPTAPI_PRECHECKHEADER
+
+       lua_getglobal(L, "core");
+       lua_getfield(L, -1, "registered_allow_player_inventory_actions");
+       pushPutTakeArguments("put", loc, listname, index, stack, player);
+       runCallbacks(4, RUN_CALLBACKS_MODE_OR_SC);
+
+       return lua_type(L, -1) == LUA_TNUMBER ? lua_tonumber(L, -1) : stack.count;
+}
+
+// Return number of accepted items to be taken
+int ScriptApiPlayer::player_inventory_AllowTake(
+               const InventoryLocation &loc,
+               const std::string &listname, int index, const ItemStack &stack,
+               ServerActiveObject *player)
+{
+       SCRIPTAPI_PRECHECKHEADER
+
+       lua_getglobal(L, "core");
+       lua_getfield(L, -1, "registered_allow_player_inventory_actions");
+       pushPutTakeArguments("take", loc, listname, index, stack, player);
+       runCallbacks(4, RUN_CALLBACKS_MODE_OR_SC);
+
+       return lua_type(L, -1) == LUA_TNUMBER ? lua_tonumber(L, -1) : stack.count;
+}
+
+// Report moved items
+void ScriptApiPlayer::player_inventory_OnMove(
+               const InventoryLocation &loc,
+               const std::string &from_list, int from_index,
+               const std::string &to_list, int to_index,
+               int count, ServerActiveObject *player)
+{
+       SCRIPTAPI_PRECHECKHEADER
+
+       lua_getglobal(L, "core");
+       lua_getfield(L, -1, "registered_on_player_inventory_actions");
+       pushMoveArguments(loc, from_list, from_index, to_list, to_index, count, player);
+       runCallbacks(4, RUN_CALLBACKS_MODE_FIRST);
+}
+
+// Report put items
+void ScriptApiPlayer::player_inventory_OnPut(
+               const InventoryLocation &loc,
+               const std::string &listname, int index, const ItemStack &stack,
+               ServerActiveObject *player)
+{
+       SCRIPTAPI_PRECHECKHEADER
+
+       lua_getglobal(L, "core");
+       lua_getfield(L, -1, "registered_on_player_inventory_actions");
+       pushPutTakeArguments("put", loc, listname, index, stack, player);
+       runCallbacks(4, RUN_CALLBACKS_MODE_FIRST);
+}
+
+// Report taken items
+void ScriptApiPlayer::player_inventory_OnTake(
+               const InventoryLocation &loc,
+               const std::string &listname, int index, const ItemStack &stack,
+               ServerActiveObject *player)
+{
+       SCRIPTAPI_PRECHECKHEADER
+
+       lua_getglobal(L, "core");
+       lua_getfield(L, -1, "registered_on_player_inventory_actions");
+       pushPutTakeArguments("take", loc, listname, index, stack, player);
+       runCallbacks(4, RUN_CALLBACKS_MODE_FIRST);
+}
index 59e1505ae6a3dcf1ecc4da28abe234b59a9dca51..d60dfcaf4011800cef1474d74088ce02fe75373e 100644 (file)
@@ -23,6 +23,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "irr_v3d.h"
 #include "util/string.h"
 
+struct InventoryLocation;
+struct ItemStack;
 struct ToolCapabilities;
 struct PlayerHPChangeReason;
 
@@ -48,4 +50,47 @@ public:
        void on_playerReceiveFields(ServerActiveObject *player,
                        const std::string &formname, const StringMap &fields);
        void on_auth_failure(const std::string &name, const std::string &ip);
+
+       // Player inventory callbacks
+       // Return number of accepted items to be moved
+       int player_inventory_AllowMove(
+               const InventoryLocation &loc,
+               const std::string &from_list, int from_index,
+               const std::string &to_list, int to_index,
+               int count, ServerActiveObject *player);
+       // Return number of accepted items to be put
+       int player_inventory_AllowPut(
+               const InventoryLocation &loc,
+               const std::string &listname, int index, const ItemStack &stack,
+               ServerActiveObject *player);
+       // Return number of accepted items to be taken
+       int player_inventory_AllowTake(
+               const InventoryLocation &loc,
+               const std::string &listname, int index, const ItemStack &stack,
+               ServerActiveObject *player);
+       // Report moved items
+       void player_inventory_OnMove(
+               const InventoryLocation &loc,
+               const std::string &from_list, int from_index,
+               const std::string &to_list, int to_index,
+               int count, ServerActiveObject *player);
+       // Report put items
+       void player_inventory_OnPut(
+               const InventoryLocation &loc,
+               const std::string &listname, int index, const ItemStack &stack,
+               ServerActiveObject *player);
+       // Report taken items
+       void player_inventory_OnTake(
+               const InventoryLocation &loc,
+               const std::string &listname, int index, const ItemStack &stack,
+               ServerActiveObject *player);
+private:
+       void pushPutTakeArguments(
+               const char *method, const InventoryLocation &loc,
+               const std::string &listname, int index, const ItemStack &stack,
+               ServerActiveObject *player);
+       void pushMoveArguments(const InventoryLocation &loc,
+               const std::string &from_list, int from_index,
+               const std::string &to_list, int to_index,
+               int count, ServerActiveObject *player);
 };