on_metadata_inventory_{move,offer,take}

This commit is contained in:
Perttu Ahola 2012-06-02 00:33:51 +03:00
parent d7447cdf9e
commit aba7134301
6 changed files with 274 additions and 23 deletions

View File

@ -262,6 +262,41 @@ function minetest.node_dig(pos, node, digger)
end end
end end
function minetest.node_metadata_inventory_move_allow_all(pos, from_list,
from_index, to_list, to_index, count, player)
minetest.log("verbose", "node_metadata_inventory_move_allow_all")
local meta = minetest.env:get_meta(pos)
local inv = meta:get_inventory()
local from_stack = inv:get_stack(from_list, from_index)
local taken_items = from_stack:take_item(count)
inv:set_stack(from_list, from_index, from_stack)
local to_stack = inv:get_stack(to_list, to_index)
to_stack:add_item(taken_items)
inv:set_stack(to_list, to_index, to_stack)
end
function minetest.node_metadata_inventory_offer_allow_all(pos, listname, index, stack, player)
minetest.log("verbose", "node_metadata_inventory_offer_allow_all")
local meta = minetest.env:get_meta(pos)
local inv = meta:get_inventory()
local the_stack = inv:get_stack(listname, index)
the_stack:add_item(stack)
inv:set_stack(listname, index, the_stack)
return ItemStack("")
end
function minetest.node_metadata_inventory_take_allow_all(pos, listname, index, count, player)
minetest.log("verbose", "node_metadata_inventory_take_allow_all")
local meta = minetest.env:get_meta(pos)
local inv = meta:get_inventory()
local the_stack = inv:get_stack(listname, index)
local taken_items = the_stack:take_item(count)
inv:set_stack(listname, index, the_stack)
return taken_items
end
-- This is used to allow mods to redefine minetest.item_place and so on -- This is used to allow mods to redefine minetest.item_place and so on
local function redef_wrapper(table, name) local function redef_wrapper(table, name)
return function(...) return function(...)
@ -295,6 +330,12 @@ minetest.nodedef_default = {
on_punch = redef_wrapper(minetest, 'node_punch'), -- minetest.node_punch on_punch = redef_wrapper(minetest, 'node_punch'), -- minetest.node_punch
on_dig = redef_wrapper(minetest, 'node_dig'), -- minetest.node_dig on_dig = redef_wrapper(minetest, 'node_dig'), -- minetest.node_dig
on_receive_fields = nil,
on_metadata_inventory_move = minetest.node_metadata_inventory_move_allow_all,
on_metadata_inventory_offer = minetest.node_metadata_inventory_offer_allow_all,
on_metadata_inventory_take = minetest.node_metadata_inventory_take_allow_all,
-- Node properties -- Node properties
drawtype = "normal", drawtype = "normal",
visual_scale = 1.0, visual_scale = 1.0,

View File

@ -1039,7 +1039,38 @@ Node definition (register_node)
on_receive_fields = func(pos, formname, fields, sender), on_receive_fields = func(pos, formname, fields, sender),
^ fields = {name1 = value1, name2 = value2, ...} ^ fields = {name1 = value1, name2 = value2, ...}
^ Called when an UI form (eg. sign text input) returns data
^ default: nil ^ default: nil
on_metadata_inventory_move = func(pos, from_list, from_index,
to_list, to_index, count, player),
^ Called when a player wants to move items inside the metadata
^ Should move items, or some items, if permitted. If not, should do
nothing.
^ The engine ensures the action is valid, i.e. the stack fits at the
given position
^ default: minetest.node_metadata_inventory_move_allow_all
on_metadata_inventory_offer = func(pos, listname, index, stack, player),
^ Called when a player wants to put something into the metadata
inventory
^ Should check if the action is permitted (the engine ensures the
action is valid, i.e. the stack fits at the given position)
^ If permitted, modify the metadata inventory and return the
"leftover" stack (normally nil).
^ If not permitted, return itemstack.
^ default: minetest.node_metadata_inventory_offer_allow_all
on_metadata_inventory_take = func(pos, listname, index, count, player),
^ Called when a player wants to take something out of the metadata
inventory
^ Should check if the action is permitted (the engine ensures the
action is valid, i.e. there's a stack of at least “count” items at
that position)
^ If permitted, modify the metadata inventory and return the
stack of items
^ If not permitted, return nil.
^ default: minetest.node_metadata_inventory_take_allow_all
} }
Recipe: (register_craft) Recipe: (register_craft)

View File

@ -526,24 +526,35 @@ bool GUIInventoryMenu::OnEvent(const SEvent& event)
u32 s_count = 0; u32 s_count = 0;
if(s.isValid()) if(s.isValid())
{ do{ // breakable
inv_s = m_invmgr->getInventory(s.inventoryloc); inv_s = m_invmgr->getInventory(s.inventoryloc);
assert(inv_s);
if(!inv_s){
errorstream<<"InventoryMenu: The selected inventory location "
<<"\""<<s.inventoryloc.dump()<<"\" doesn't exist"
<<std::endl;
s.i = -1; // make it invalid again
break;
}
InventoryList *list = inv_s->getList(s.listname); InventoryList *list = inv_s->getList(s.listname);
if(list == NULL){ if(list == NULL){
errorstream<<"InventoryMenu: The selected inventory list \"" errorstream<<"InventoryMenu: The selected inventory list \""
<<s.listname<<"\" does not exist"<<std::endl; <<s.listname<<"\" does not exist"<<std::endl;
s.i = -1; // make it invalid again s.i = -1; // make it invalid again
} else if((u32)s.i >= list->getSize()){ break;
}
if((u32)s.i >= list->getSize()){
errorstream<<"InventoryMenu: The selected inventory list \"" errorstream<<"InventoryMenu: The selected inventory list \""
<<s.listname<<"\" is too small (i="<<s.i<<", size=" <<s.listname<<"\" is too small (i="<<s.i<<", size="
<<list->getSize()<<")"<<std::endl; <<list->getSize()<<")"<<std::endl;
s.i = -1; // make it invalid again s.i = -1; // make it invalid again
} else{ break;
s_count = list->getItem(s.i).count;
} }
}
s_count = list->getItem(s.i).count;
}while(0);
bool identical = (m_selected_item != NULL) && s.isValid() && bool identical = (m_selected_item != NULL) && s.isValid() &&
(inv_selected == inv_s) && (inv_selected == inv_s) &&

View File

@ -27,6 +27,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "utility.h" #include "utility.h"
#include "craftdef.h" #include "craftdef.h"
#define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
/* /*
InventoryLocation InventoryLocation
*/ */
@ -197,27 +199,82 @@ void IMoveAction::apply(InventoryManager *mgr, ServerActiveObject *player, IGame
<<", to_list=\""<<to_list<<"\""<<std::endl; <<", to_list=\""<<to_list<<"\""<<std::endl;
return; return;
} }
/*
This performs the actual movement // Handle node metadata move
if(from_inv.type == InventoryLocation::NODEMETA &&
to_inv.type == InventoryLocation::NODEMETA &&
from_inv.p == to_inv.p)
{
lua_State *L = player->getEnv()->getLua();
int count0 = count;
if(count0 == 0)
count0 = list_from->getItem(from_i).count;
infostream<<player->getDescription()<<" moving "<<count0
<<" items inside node at "<<PP(from_inv.p)<<std::endl;
scriptapi_node_on_metadata_inventory_move(L, from_inv.p,
from_list, from_i, to_list, to_i, count0, player);
}
// Handle node metadata take
else if(from_inv.type == InventoryLocation::NODEMETA)
{
lua_State *L = player->getEnv()->getLua();
int count0 = count;
if(count0 == 0)
count0 = list_from->getItem(from_i).count;
infostream<<player->getDescription()<<" taking "<<count0
<<" items from node at "<<PP(from_inv.p)<<std::endl;
ItemStack return_stack = scriptapi_node_on_metadata_inventory_take(
L, from_inv.p, from_list, from_i, count0, player);
if(return_stack.count == 0)
infostream<<"Node metadata gave no items"<<std::endl;
return_stack = list_to->addItem(to_i, return_stack);
list_to->addItem(return_stack); // Force return of everything
}
// Handle node metadata offer
else if(to_inv.type == InventoryLocation::NODEMETA)
{
lua_State *L = player->getEnv()->getLua();
int count0 = count;
if(count0 == 0)
count0 = list_from->getItem(from_i).count;
ItemStack offer_stack = list_from->takeItem(from_i, count0);
infostream<<player->getDescription()<<" offering "
<<offer_stack.count<<" items to node at "
<<PP(to_inv.p)<<std::endl;
ItemStack reject_stack = scriptapi_node_on_metadata_inventory_offer(
L, to_inv.p, to_list, to_i, offer_stack, player);
if(reject_stack.count == offer_stack.count)
infostream<<"Node metadata rejected all items"<<std::endl;
else if(reject_stack.count != 0)
infostream<<"Node metadata rejected some items"<<std::endl;
reject_stack = list_from->addItem(from_i, reject_stack);
list_from->addItem(reject_stack); // Force return of everything
}
// Handle regular move
else
{
/*
This performs the actual movement
If something is wrong (source item is empty, destination is the If something is wrong (source item is empty, destination is the
same as source), nothing happens same as source), nothing happens
*/ */
list_from->moveItem(from_i, list_to, to_i, count); list_from->moveItem(from_i, list_to, to_i, count);
infostream<<"IMoveAction::apply(): moved "
<<" count="<<count
<<" from inv=\""<<from_inv.dump()<<"\""
<<" list=\""<<from_list<<"\""
<<" i="<<from_i
<<" to inv=\""<<to_inv.dump()<<"\""
<<" list=\""<<to_list<<"\""
<<" i="<<to_i
<<std::endl;
}
mgr->setInventoryModified(from_inv); mgr->setInventoryModified(from_inv);
if(inv_from != inv_to) if(inv_from != inv_to)
mgr->setInventoryModified(to_inv); mgr->setInventoryModified(to_inv);
infostream<<"IMoveAction::apply(): moved at "
<<" count="<<count<<"\""
<<" from inv=\""<<from_inv.dump()<<"\""
<<" list=\""<<from_list<<"\""
<<" i="<<from_i
<<" to inv=\""<<to_inv.dump()<<"\""
<<" list=\""<<to_list<<"\""
<<" i="<<to_i
<<std::endl;
} }
void IMoveAction::clientApply(InventoryManager *mgr, IGameDef *gamedef) void IMoveAction::clientApply(InventoryManager *mgr, IGameDef *gamedef)

View File

@ -1470,7 +1470,7 @@ private:
ItemStack &item = o->m_stack; ItemStack &item = o->m_stack;
u32 takecount = 1; u32 takecount = 1;
if(!lua_isnone(L, 2)) if(!lua_isnone(L, 2))
takecount = lua_tointeger(L, 2); takecount = luaL_checkinteger(L, 2);
ItemStack taken = item.takeItem(takecount); ItemStack taken = item.takeItem(takecount);
create(L, taken); create(L, taken);
return 1; return 1;
@ -5014,6 +5014,101 @@ void scriptapi_node_on_receive_fields(lua_State *L, v3s16 p,
script_error(L, "error: %s", lua_tostring(L, -1)); script_error(L, "error: %s", lua_tostring(L, -1));
} }
void scriptapi_node_on_metadata_inventory_move(lua_State *L, v3s16 p,
const std::string &from_list, int from_index,
const std::string &to_list, int to_index,
int count, ServerActiveObject *player)
{
realitycheck(L);
assert(lua_checkstack(L, 20));
StackUnroller stack_unroller(L);
INodeDefManager *ndef = get_server(L)->ndef();
// If node doesn't exist, we don't know what callback to call
MapNode node = get_env(L)->getMap().getNodeNoEx(p);
if(node.getContent() == CONTENT_IGNORE)
return;
// Push callback function on stack
if(!get_item_callback(L, ndef->get(node).name.c_str(),
"on_metadata_inventory_move"))
return;
// function(pos, from_list, from_index, to_list, to_index, count, player)
push_v3s16(L, p);
lua_pushstring(L, from_list.c_str());
lua_pushinteger(L, from_index + 1);
lua_pushstring(L, to_list.c_str());
lua_pushinteger(L, to_index + 1);
lua_pushinteger(L, count);
objectref_get_or_create(L, player);
if(lua_pcall(L, 7, 0, 0))
script_error(L, "error: %s", lua_tostring(L, -1));
}
ItemStack scriptapi_node_on_metadata_inventory_offer(lua_State *L, v3s16 p,
const std::string &listname, int index, ItemStack &stack,
ServerActiveObject *player)
{
realitycheck(L);
assert(lua_checkstack(L, 20));
StackUnroller stack_unroller(L);
INodeDefManager *ndef = get_server(L)->ndef();
// If node doesn't exist, we don't know what callback to call
MapNode node = get_env(L)->getMap().getNodeNoEx(p);
if(node.getContent() == CONTENT_IGNORE)
return stack;
// Push callback function on stack
if(!get_item_callback(L, ndef->get(node).name.c_str(),
"on_metadata_inventory_offer"))
return stack;
// Call function(pos, listname, index, stack, player)
push_v3s16(L, p);
lua_pushstring(L, listname.c_str());
lua_pushinteger(L, index + 1);
LuaItemStack::create(L, stack);
objectref_get_or_create(L, player);
if(lua_pcall(L, 5, 1, 0))
script_error(L, "error: %s", lua_tostring(L, -1));
return read_item(L, -1);
}
ItemStack scriptapi_node_on_metadata_inventory_take(lua_State *L, v3s16 p,
const std::string &listname, int index, int count,
ServerActiveObject *player)
{
realitycheck(L);
assert(lua_checkstack(L, 20));
StackUnroller stack_unroller(L);
INodeDefManager *ndef = get_server(L)->ndef();
// If node doesn't exist, we don't know what callback to call
MapNode node = get_env(L)->getMap().getNodeNoEx(p);
if(node.getContent() == CONTENT_IGNORE)
return ItemStack();
// Push callback function on stack
if(!get_item_callback(L, ndef->get(node).name.c_str(),
"on_metadata_inventory_take"))
return ItemStack();
// Call function(pos, listname, index, count, player)
push_v3s16(L, p);
lua_pushstring(L, listname.c_str());
lua_pushinteger(L, index + 1);
lua_pushinteger(L, count);
objectref_get_or_create(L, player);
if(lua_pcall(L, 5, 1, 0))
script_error(L, "error: %s", lua_tostring(L, -1));
return read_item(L, -1);
}
/* /*
environment environment
*/ */

View File

@ -82,12 +82,28 @@ bool scriptapi_node_on_punch(lua_State *L, v3s16 p, MapNode node,
ServerActiveObject *puncher); ServerActiveObject *puncher);
bool scriptapi_node_on_dig(lua_State *L, v3s16 p, MapNode node, bool scriptapi_node_on_dig(lua_State *L, v3s16 p, MapNode node,
ServerActiveObject *digger); ServerActiveObject *digger);
// Node constructor
void scriptapi_node_on_construct(lua_State *L, v3s16 p, MapNode node); void scriptapi_node_on_construct(lua_State *L, v3s16 p, MapNode node);
// Node destructor
void scriptapi_node_on_destruct(lua_State *L, v3s16 p, MapNode node); void scriptapi_node_on_destruct(lua_State *L, v3s16 p, MapNode node);
// Called when a metadata form returns values
void scriptapi_node_on_receive_fields(lua_State *L, v3s16 p, void scriptapi_node_on_receive_fields(lua_State *L, v3s16 p,
const std::string &formname, const std::string &formname,
const std::map<std::string, std::string> &fields, const std::map<std::string, std::string> &fields,
ServerActiveObject *sender); ServerActiveObject *sender);
// Moves items
void scriptapi_node_on_metadata_inventory_move(lua_State *L, v3s16 p,
const std::string &from_list, int from_index,
const std::string &to_list, int to_index,
int count, ServerActiveObject *player);
// Inserts items, returns rejected items
ItemStack scriptapi_node_on_metadata_inventory_offer(lua_State *L, v3s16 p,
const std::string &listname, int index, ItemStack &stack,
ServerActiveObject *player);
// Takes items, returns taken items
ItemStack scriptapi_node_on_metadata_inventory_take(lua_State *L, v3s16 p,
const std::string &listname, int index, int count,
ServerActiveObject *player);
/* luaentity */ /* luaentity */
// Returns true if succesfully added into Lua; false otherwise. // Returns true if succesfully added into Lua; false otherwise.