on_metadata_inventory_{move,offer,take}
parent
d7447cdf9e
commit
aba7134301
|
@ -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,
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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) &&
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -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.
|
||||||
|
|
Loading…
Reference in New Issue