Add player inventory callbacks

This commit is contained in:
SmallJoker 2018-03-31 12:30:43 +02:00 committed by Loïc Blot
parent 12edb200eb
commit f6eff57f7c
5 changed files with 259 additions and 1 deletions

@ -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_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_modchannel_message, core.register_on_modchannel_message = make_registration()
core.registered_on_auth_fail, core.register_on_auth_fail = 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() -- Compatibility for on_mapgen_init()

@ -2880,6 +2880,22 @@ Call these functions only at load time!
* `minetest.register_craft_predict(func(itemstack, player, old_craft_grid, craft_inv))` * `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 * The same as before, except that it is called before the player crafts, to
make craft prediction, and it should not change anything. 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))` * `minetest.register_on_protection_violation(func(pos, name))`
* Called by `builtin` and mods when a player violates protection at a * Called by `builtin` and mods when a player violates protection at a
position (eg, digs a node or punches a protected entity). position (eg, digs a node or punches a protected entity).

@ -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; int old_count = count;
/* Modify count according to collected data */ /* 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); to_inv.p, to_list, to_i, src_item, player);
} }
// Source is nodemeta // Source is nodemeta
else if (from_inv.type == InventoryLocation::NODEMETA) { if (from_inv.type == InventoryLocation::NODEMETA) {
PLAYER_TO_SA(player)->nodemeta_inventory_OnTake( PLAYER_TO_SA(player)->nodemeta_inventory_OnTake(
from_inv.p, from_list, from_i, src_item, player); 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); mgr->setInventoryModified(from_inv, false);
if (inv_from != inv_to) if (inv_from != inv_to)
mgr->setInventoryModified(to_inv, false); mgr->setInventoryModified(to_inv, false);

@ -22,6 +22,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "common/c_converter.h" #include "common/c_converter.h"
#include "common/c_content.h" #include "common/c_content.h"
#include "debug.h" #include "debug.h"
#include "inventorymanager.h"
#include "lua_api/l_inventory.h"
#include "lua_api/l_item.h"
#include "util/string.h" #include "util/string.h"
void ScriptApiPlayer::on_newplayer(ServerActiveObject *player) 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()); lua_pushstring(L, ip.c_str());
runCallbacks(2, RUN_CALLBACKS_MODE_FIRST); 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);
}

@ -23,6 +23,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "irr_v3d.h" #include "irr_v3d.h"
#include "util/string.h" #include "util/string.h"
struct InventoryLocation;
struct ItemStack;
struct ToolCapabilities; struct ToolCapabilities;
struct PlayerHPChangeReason; struct PlayerHPChangeReason;
@ -48,4 +50,47 @@ public:
void on_playerReceiveFields(ServerActiveObject *player, void on_playerReceiveFields(ServerActiveObject *player,
const std::string &formname, const StringMap &fields); const std::string &formname, const StringMap &fields);
void on_auth_failure(const std::string &name, const std::string &ip); 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);
}; };