Detached inventory callbacks and reworked node metadata callbacks
This commit is contained in:
parent
2ac20982e0
commit
9eaf93d41d
|
@ -21,4 +21,5 @@ dofile(minetest.get_modpath("__builtin").."/privileges.lua")
|
||||||
dofile(minetest.get_modpath("__builtin").."/auth.lua")
|
dofile(minetest.get_modpath("__builtin").."/auth.lua")
|
||||||
dofile(minetest.get_modpath("__builtin").."/chatcommands.lua")
|
dofile(minetest.get_modpath("__builtin").."/chatcommands.lua")
|
||||||
dofile(minetest.get_modpath("__builtin").."/static_spawn.lua")
|
dofile(minetest.get_modpath("__builtin").."/static_spawn.lua")
|
||||||
|
dofile(minetest.get_modpath("__builtin").."/detached_inventory.lua")
|
||||||
|
|
||||||
|
|
|
@ -16,4 +16,7 @@ minetest.digprop_woodlike = digprop_err
|
||||||
minetest.digprop_leaveslike = digprop_err
|
minetest.digprop_leaveslike = digprop_err
|
||||||
minetest.digprop_glasslike = digprop_err
|
minetest.digprop_glasslike = digprop_err
|
||||||
|
|
||||||
|
minetest.node_metadata_inventory_move_allow_all = function()
|
||||||
|
minetest.log("info", "WARNING: minetest.node_metadata_inventory_move_allow_all is obsolete and does nothing.")
|
||||||
|
end
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
-- Minetest: builtin/detached_inventory.lua
|
||||||
|
|
||||||
|
minetest.detached_inventories = {}
|
||||||
|
|
||||||
|
function minetest.create_detached_inventory(name, callbacks)
|
||||||
|
local stuff = {}
|
||||||
|
stuff.name = name
|
||||||
|
if callbacks then
|
||||||
|
stuff.allow_move = callbacks.allow_move
|
||||||
|
stuff.allow_put = callbacks.allow_put
|
||||||
|
stuff.allow_take = callbacks.allow_take
|
||||||
|
stuff.on_move = callbacks.on_move
|
||||||
|
stuff.on_put = callbacks.on_put
|
||||||
|
stuff.on_take = callbacks.on_take
|
||||||
|
end
|
||||||
|
minetest.detached_inventories[name] = stuff
|
||||||
|
return minetest.create_detached_inventory_raw(name)
|
||||||
|
end
|
||||||
|
|
|
@ -318,41 +318,6 @@ 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
|
||||||
-- NOTE: This is not the preferred way. Preferred way is to provide enough
|
-- NOTE: This is not the preferred way. Preferred way is to provide enough
|
||||||
-- callbacks to not require redefining global functions. -celeron55
|
-- callbacks to not require redefining global functions. -celeron55
|
||||||
|
|
|
@ -851,7 +851,8 @@ minetest.get_inventory(location) -> InvRef
|
||||||
^ location = eg. {type="player", name="celeron55"}
|
^ location = eg. {type="player", name="celeron55"}
|
||||||
{type="node", pos={x=, y=, z=}}
|
{type="node", pos={x=, y=, z=}}
|
||||||
{type="detached", name="creative"}
|
{type="detached", name="creative"}
|
||||||
minetest.create_detached_inventory(name) -> InvRef
|
minetest.create_detached_inventory(name, callbacks) -> InvRef
|
||||||
|
^ callbacks: See "Detached inventory callbacks"
|
||||||
^ Creates a detached inventory. If it already exists, it is cleared.
|
^ Creates a detached inventory. If it already exists, it is cleared.
|
||||||
|
|
||||||
Item handling:
|
Item handling:
|
||||||
|
@ -1361,35 +1362,25 @@ Node definition (register_node)
|
||||||
^ Called when an UI form (eg. sign text input) returns data
|
^ Called when an UI form (eg. sign text input) returns data
|
||||||
^ default: nil
|
^ default: nil
|
||||||
|
|
||||||
|
allow_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 inventory
|
||||||
|
^ Return value: number of items allowed to move
|
||||||
|
|
||||||
|
allow_metadata_inventory_put = func(pos, listname, index, stack, player),
|
||||||
|
^ Called when a player wants to put something into the inventory
|
||||||
|
^ Return value: number of items allowed to put
|
||||||
|
|
||||||
|
allow_metadata_inventory_take = func(pos, listname, index, count, player),
|
||||||
|
^ Called when a player wants to take something out of the inventory
|
||||||
|
^ Return value: number of items allowed to take
|
||||||
|
|
||||||
on_metadata_inventory_move = func(pos, from_list, from_index,
|
on_metadata_inventory_move = func(pos, from_list, from_index,
|
||||||
to_list, to_index, count, player),
|
to_list, to_index, count, player),
|
||||||
^ Called when a player wants to move items inside the metadata
|
on_metadata_inventory_put = func(pos, listname, index, stack, player),
|
||||||
^ 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),
|
on_metadata_inventory_take = func(pos, listname, index, count, player),
|
||||||
^ Called when a player wants to take something out of the metadata
|
^ Called after the actual action has happened, according to what was allowed.
|
||||||
inventory
|
^ No return value
|
||||||
^ 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 for register_craft: (shaped)
|
Recipe for register_craft: (shaped)
|
||||||
|
@ -1446,3 +1437,24 @@ Chatcommand definition (register_chatcommand)
|
||||||
func = function(name, param), -- called when command is run
|
func = function(name, param), -- called when command is run
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Detached inventory callbacks
|
||||||
|
{
|
||||||
|
allow_move = func(inv, from_list, from_index, to_list, to_index, count, player),
|
||||||
|
^ Called when a player wants to move items inside the inventory
|
||||||
|
^ Return value: number of items allowed to move
|
||||||
|
|
||||||
|
allow_put = func(inv, listname, index, stack, player),
|
||||||
|
^ Called when a player wants to put something into the inventory
|
||||||
|
^ Return value: number of items allowed to put
|
||||||
|
|
||||||
|
allow_take = func(inv, listname, index, count, player),
|
||||||
|
^ Called when a player wants to take something out of the inventory
|
||||||
|
^ Return value: number of items allowed to take
|
||||||
|
|
||||||
|
on_move = func(inv, from_list, from_index, to_list, to_index, count, player),
|
||||||
|
on_put = func(inv, listname, index, stack, player),
|
||||||
|
on_take = func(inv, listname, index, count, player),
|
||||||
|
^ Called after the actual action has happened, according to what was allowed.
|
||||||
|
^ No return value
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -1150,7 +1150,7 @@ minetest.register_node("default:chest", {
|
||||||
on_construct = function(pos)
|
on_construct = function(pos)
|
||||||
local meta = minetest.env:get_meta(pos)
|
local meta = minetest.env:get_meta(pos)
|
||||||
meta:set_string("formspec",
|
meta:set_string("formspec",
|
||||||
"invsize[8,9;]"..
|
"size[8,9]"..
|
||||||
"list[current_name;main;0,0;8,4;]"..
|
"list[current_name;main;0,0;8,4;]"..
|
||||||
"list[current_player;main;0,5;8,4;]")
|
"list[current_player;main;0,5;8,4;]")
|
||||||
meta:set_string("infotext", "Chest")
|
meta:set_string("infotext", "Chest")
|
||||||
|
@ -1162,25 +1162,6 @@ minetest.register_node("default:chest", {
|
||||||
local inv = meta:get_inventory()
|
local inv = meta:get_inventory()
|
||||||
return inv:is_empty("main")
|
return inv:is_empty("main")
|
||||||
end,
|
end,
|
||||||
on_metadata_inventory_move = function(pos, from_list, from_index,
|
|
||||||
to_list, to_index, count, player)
|
|
||||||
minetest.log("action", player:get_player_name()..
|
|
||||||
" moves stuff in chest at "..minetest.pos_to_string(pos))
|
|
||||||
return minetest.node_metadata_inventory_move_allow_all(
|
|
||||||
pos, from_list, from_index, to_list, to_index, count, player)
|
|
||||||
end,
|
|
||||||
on_metadata_inventory_offer = function(pos, listname, index, stack, player)
|
|
||||||
minetest.log("action", player:get_player_name()..
|
|
||||||
" moves stuff to chest at "..minetest.pos_to_string(pos))
|
|
||||||
return minetest.node_metadata_inventory_offer_allow_all(
|
|
||||||
pos, listname, index, stack, player)
|
|
||||||
end,
|
|
||||||
on_metadata_inventory_take = function(pos, listname, index, count, player)
|
|
||||||
minetest.log("action", player:get_player_name()..
|
|
||||||
" takes stuff from chest at "..minetest.pos_to_string(pos))
|
|
||||||
return minetest.node_metadata_inventory_take_allow_all(
|
|
||||||
pos, listname, index, count, player)
|
|
||||||
end,
|
|
||||||
})
|
})
|
||||||
|
|
||||||
local function has_locked_chest_privilege(meta, player)
|
local function has_locked_chest_privilege(meta, player)
|
||||||
|
@ -1207,7 +1188,7 @@ minetest.register_node("default:chest_locked", {
|
||||||
on_construct = function(pos)
|
on_construct = function(pos)
|
||||||
local meta = minetest.env:get_meta(pos)
|
local meta = minetest.env:get_meta(pos)
|
||||||
meta:set_string("formspec",
|
meta:set_string("formspec",
|
||||||
"invsize[8,9;]"..
|
"size[8,9]"..
|
||||||
"list[current_name;main;0,0;8,4;]"..
|
"list[current_name;main;0,0;8,4;]"..
|
||||||
"list[current_player;main;0,5;8,4;]")
|
"list[current_player;main;0,5;8,4;]")
|
||||||
meta:set_string("infotext", "Locked Chest")
|
meta:set_string("infotext", "Locked Chest")
|
||||||
|
@ -1220,53 +1201,55 @@ minetest.register_node("default:chest_locked", {
|
||||||
local inv = meta:get_inventory()
|
local inv = meta:get_inventory()
|
||||||
return inv:is_empty("main")
|
return inv:is_empty("main")
|
||||||
end,
|
end,
|
||||||
on_metadata_inventory_move = function(pos, from_list, from_index,
|
allow_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player)
|
||||||
to_list, to_index, count, player)
|
|
||||||
local meta = minetest.env:get_meta(pos)
|
local meta = minetest.env:get_meta(pos)
|
||||||
if not has_locked_chest_privilege(meta, player) then
|
if not has_locked_chest_privilege(meta, player) then
|
||||||
minetest.log("action", player:get_player_name()..
|
minetest.log("action", player:get_player_name()..
|
||||||
" tried to access a locked chest belonging to "..
|
" tried to access a locked chest belonging to "..
|
||||||
meta:get_string("owner").." at "..
|
meta:get_string("owner").." at "..
|
||||||
minetest.pos_to_string(pos))
|
minetest.pos_to_string(pos))
|
||||||
return
|
return 0
|
||||||
end
|
end
|
||||||
|
return count
|
||||||
|
end,
|
||||||
|
allow_metadata_inventory_put = function(pos, listname, index, stack, player)
|
||||||
|
local meta = minetest.env:get_meta(pos)
|
||||||
|
if not has_locked_chest_privilege(meta, player) then
|
||||||
|
minetest.log("action", player:get_player_name()..
|
||||||
|
" tried to access a locked chest belonging to "..
|
||||||
|
meta:get_string("owner").." at "..
|
||||||
|
minetest.pos_to_string(pos))
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
return stack:get_count()
|
||||||
|
end,
|
||||||
|
allow_metadata_inventory_take = function(pos, listname, index, count, player)
|
||||||
|
local meta = minetest.env:get_meta(pos)
|
||||||
|
if not has_locked_chest_privilege(meta, player) then
|
||||||
|
minetest.log("action", player:get_player_name()..
|
||||||
|
" tried to access a locked chest belonging to "..
|
||||||
|
meta:get_string("owner").." at "..
|
||||||
|
minetest.pos_to_string(pos))
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
return count
|
||||||
|
end,
|
||||||
|
on_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player)
|
||||||
minetest.log("action", player:get_player_name()..
|
minetest.log("action", player:get_player_name()..
|
||||||
" moves stuff in locked chest at "..minetest.pos_to_string(pos))
|
" moves stuff in locked chest at "..minetest.pos_to_string(pos))
|
||||||
return minetest.node_metadata_inventory_move_allow_all(
|
|
||||||
pos, from_list, from_index, to_list, to_index, count, player)
|
|
||||||
end,
|
end,
|
||||||
on_metadata_inventory_offer = function(pos, listname, index, stack, player)
|
on_metadata_inventory_put = function(pos, listname, index, stack, player)
|
||||||
local meta = minetest.env:get_meta(pos)
|
|
||||||
if not has_locked_chest_privilege(meta, player) then
|
|
||||||
minetest.log("action", player:get_player_name()..
|
|
||||||
" tried to access a locked chest belonging to "..
|
|
||||||
meta:get_string("owner").." at "..
|
|
||||||
minetest.pos_to_string(pos))
|
|
||||||
return stack
|
|
||||||
end
|
|
||||||
minetest.log("action", player:get_player_name()..
|
minetest.log("action", player:get_player_name()..
|
||||||
" moves stuff to locked chest at "..minetest.pos_to_string(pos))
|
" moves stuff to locked chest at "..minetest.pos_to_string(pos))
|
||||||
return minetest.node_metadata_inventory_offer_allow_all(
|
|
||||||
pos, listname, index, stack, player)
|
|
||||||
end,
|
end,
|
||||||
on_metadata_inventory_take = function(pos, listname, index, count, player)
|
on_metadata_inventory_take = function(pos, listname, index, count, player)
|
||||||
local meta = minetest.env:get_meta(pos)
|
|
||||||
if not has_locked_chest_privilege(meta, player) then
|
|
||||||
minetest.log("action", player:get_player_name()..
|
|
||||||
" tried to access a locked chest belonging to "..
|
|
||||||
meta:get_string("owner").." at "..
|
|
||||||
minetest.pos_to_string(pos))
|
|
||||||
return
|
|
||||||
end
|
|
||||||
minetest.log("action", player:get_player_name()..
|
minetest.log("action", player:get_player_name()..
|
||||||
" takes stuff from locked chest at "..minetest.pos_to_string(pos))
|
" takes stuff from locked chest at "..minetest.pos_to_string(pos))
|
||||||
return minetest.node_metadata_inventory_take_allow_all(
|
|
||||||
pos, listname, index, count, player)
|
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
|
|
||||||
default.furnace_inactive_formspec =
|
default.furnace_inactive_formspec =
|
||||||
"invsize[8,9;]"..
|
"size[8,9]"..
|
||||||
"image[2,2;1,1;default_furnace_fire_bg.png]"..
|
"image[2,2;1,1;default_furnace_fire_bg.png]"..
|
||||||
"list[current_name;fuel;2,3;1,1;]"..
|
"list[current_name;fuel;2,3;1,1;]"..
|
||||||
"list[current_name;src;2,1;1,1;]"..
|
"list[current_name;src;2,1;1,1;]"..
|
||||||
|
@ -1405,7 +1388,7 @@ minetest.register_abm({
|
||||||
meta:set_string("infotext","Furnace active: "..percent.."%")
|
meta:set_string("infotext","Furnace active: "..percent.."%")
|
||||||
hacky_swap_node(pos,"default:furnace_active")
|
hacky_swap_node(pos,"default:furnace_active")
|
||||||
meta:set_string("formspec",
|
meta:set_string("formspec",
|
||||||
"invsize[8,9;]"..
|
"size[8,9]"..
|
||||||
"image[2,2;1,1;default_furnace_fire_bg.png^[lowpart:"..
|
"image[2,2;1,1;default_furnace_fire_bg.png^[lowpart:"..
|
||||||
(100-percent)..":default_furnace_fire_fg.png]"..
|
(100-percent)..":default_furnace_fire_fg.png]"..
|
||||||
"list[current_name;fuel;2,3;1,1;]"..
|
"list[current_name;fuel;2,3;1,1;]"..
|
||||||
|
|
|
@ -516,7 +516,7 @@ minetest.register_craft({
|
||||||
|
|
||||||
--[[minetest.register_on_joinplayer(function(player)
|
--[[minetest.register_on_joinplayer(function(player)
|
||||||
minetest.after(3, function()
|
minetest.after(3, function()
|
||||||
player:set_inventory_formspec("invsize[8,7.5;]"..
|
player:set_inventory_formspec("size[8,7.5]"..
|
||||||
"image[1,0.6;1,2;player.png]"..
|
"image[1,0.6;1,2;player.png]"..
|
||||||
"list[current_player;main;0,3.5;8,4;]"..
|
"list[current_player;main;0,3.5;8,4;]"..
|
||||||
"list[current_player;craft;3,0;3,3;]"..
|
"list[current_player;craft;3,0;3,3;]"..
|
||||||
|
@ -525,7 +525,29 @@ minetest.register_craft({
|
||||||
end)]]
|
end)]]
|
||||||
|
|
||||||
-- Create a detached inventory
|
-- Create a detached inventory
|
||||||
local inv = minetest.create_detached_inventory("test_inventory")
|
local inv = minetest.create_detached_inventory("test_inventory", {
|
||||||
|
allow_move = function(inv, from_list, from_index, to_list, to_index, count, player)
|
||||||
|
experimental.print_to_everything("allow move asked")
|
||||||
|
return count -- Allow all
|
||||||
|
end,
|
||||||
|
allow_put = function(inv, listname, index, stack, player)
|
||||||
|
experimental.print_to_everything("allow put asked")
|
||||||
|
return 1 -- Allow only 1
|
||||||
|
end,
|
||||||
|
allow_take = function(inv, listname, index, count, player)
|
||||||
|
experimental.print_to_everything("allow take asked")
|
||||||
|
return 4 -- Allow 4 at max
|
||||||
|
end,
|
||||||
|
on_move = function(inv, from_list, from_index, to_list, to_index, count, player)
|
||||||
|
experimental.print_to_everything(player:get_player_name().." moved items")
|
||||||
|
end,
|
||||||
|
on_put = function(inv, listname, index, stack, player)
|
||||||
|
experimental.print_to_everything(player:get_player_name().." put items")
|
||||||
|
end,
|
||||||
|
on_take = function(inv, listname, index, count, player)
|
||||||
|
experimental.print_to_everything(player:get_player_name().." took items")
|
||||||
|
end,
|
||||||
|
})
|
||||||
inv:set_size("main", 4*6)
|
inv:set_size("main", 4*6)
|
||||||
inv:add_item("main", "experimental:tester_tool_1")
|
inv:add_item("main", "experimental:tester_tool_1")
|
||||||
inv:add_item("main", "experimental:tnt 5")
|
inv:add_item("main", "experimental:tnt 5")
|
||||||
|
|
|
@ -215,10 +215,9 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
invsize.Y = stof(f.next(";"));
|
invsize.Y = stof(f.next(";"));
|
||||||
errorstream<<"WARNING: invsize is deprecated, use size"<<std::endl;
|
|
||||||
f.next("]");
|
f.next("]");
|
||||||
}
|
}
|
||||||
infostream<<"size ("<<invsize.X<<","<<invsize.Y<<")"<<std::endl;
|
infostream<<"Form size ("<<invsize.X<<","<<invsize.Y<<")"<<std::endl;
|
||||||
|
|
||||||
padding = v2s32(screensize.Y/40, screensize.Y/40);
|
padding = v2s32(screensize.Y/40, screensize.Y/40);
|
||||||
spacing = v2s32(screensize.Y/12, screensize.Y/13);
|
spacing = v2s32(screensize.Y/12, screensize.Y/13);
|
||||||
|
|
|
@ -199,69 +199,110 @@ void IMoveAction::apply(InventoryManager *mgr, ServerActiveObject *player, IGame
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle node metadata move
|
/*
|
||||||
if(from_inv.type == InventoryLocation::NODEMETA &&
|
Collect information of endpoints
|
||||||
to_inv.type == InventoryLocation::NODEMETA &&
|
*/
|
||||||
from_inv.p != to_inv.p)
|
|
||||||
|
int try_take_count = count;
|
||||||
|
if(try_take_count == 0)
|
||||||
|
try_take_count = list_from->getItem(from_i).count;
|
||||||
|
|
||||||
|
int src_can_take_count = 0xffff;
|
||||||
|
int dst_can_put_count = 0xffff;
|
||||||
|
|
||||||
|
/* Query detached inventories */
|
||||||
|
|
||||||
|
// Move occurs in the same detached inventory
|
||||||
|
if(from_inv.type == InventoryLocation::DETACHED &&
|
||||||
|
to_inv.type == InventoryLocation::DETACHED &&
|
||||||
|
from_inv.name == to_inv.name)
|
||||||
{
|
{
|
||||||
errorstream<<"Directly moving items between two nodes is "
|
lua_State *L = player->getEnv()->getLua();
|
||||||
<<"disallowed."<<std::endl;
|
src_can_take_count = scriptapi_detached_inventory_allow_move(
|
||||||
return;
|
L, from_inv.name, from_list, from_i,
|
||||||
|
to_list, to_i, try_take_count, player);
|
||||||
|
dst_can_put_count = src_can_take_count;
|
||||||
}
|
}
|
||||||
else if(from_inv.type == InventoryLocation::NODEMETA &&
|
else
|
||||||
|
{
|
||||||
|
// Destination is detached
|
||||||
|
if(to_inv.type == InventoryLocation::DETACHED)
|
||||||
|
{
|
||||||
|
lua_State *L = player->getEnv()->getLua();
|
||||||
|
ItemStack src_item = list_from->getItem(from_i);
|
||||||
|
src_item.count = try_take_count;
|
||||||
|
dst_can_put_count = scriptapi_detached_inventory_allow_put(
|
||||||
|
L, to_inv.name, to_list, to_i, src_item, player);
|
||||||
|
}
|
||||||
|
// Source is detached
|
||||||
|
if(from_inv.type == InventoryLocation::DETACHED)
|
||||||
|
{
|
||||||
|
lua_State *L = player->getEnv()->getLua();
|
||||||
|
src_can_take_count = scriptapi_detached_inventory_allow_take(
|
||||||
|
L, from_inv.name, from_list, from_i, try_take_count, player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Query node metadata inventories */
|
||||||
|
|
||||||
|
// Both endpoints are nodemeta
|
||||||
|
// Move occurs in the same nodemeta inventory
|
||||||
|
if(from_inv.type == InventoryLocation::NODEMETA &&
|
||||||
to_inv.type == InventoryLocation::NODEMETA &&
|
to_inv.type == InventoryLocation::NODEMETA &&
|
||||||
from_inv.p == to_inv.p)
|
from_inv.p == to_inv.p)
|
||||||
{
|
{
|
||||||
lua_State *L = player->getEnv()->getLua();
|
lua_State *L = player->getEnv()->getLua();
|
||||||
int count0 = count;
|
src_can_take_count = scriptapi_nodemeta_inventory_allow_move(
|
||||||
if(count0 == 0)
|
L, from_inv.p, from_list, from_i,
|
||||||
count0 = list_from->getItem(from_i).count;
|
to_list, to_i, try_take_count, player);
|
||||||
infostream<<player->getDescription()<<" moving "<<count0
|
dst_can_put_count = src_can_take_count;
|
||||||
<<" 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
|
else
|
||||||
{
|
{
|
||||||
|
// Destination is nodemeta
|
||||||
|
if(to_inv.type == InventoryLocation::NODEMETA)
|
||||||
|
{
|
||||||
|
lua_State *L = player->getEnv()->getLua();
|
||||||
|
ItemStack src_item = list_from->getItem(from_i);
|
||||||
|
src_item.count = try_take_count;
|
||||||
|
dst_can_put_count = scriptapi_nodemeta_inventory_allow_put(
|
||||||
|
L, to_inv.p, to_list, to_i, src_item, player);
|
||||||
|
}
|
||||||
|
// Source is nodemeta
|
||||||
|
if(from_inv.type == InventoryLocation::NODEMETA)
|
||||||
|
{
|
||||||
|
lua_State *L = player->getEnv()->getLua();
|
||||||
|
src_can_take_count = scriptapi_nodemeta_inventory_allow_take(
|
||||||
|
L, from_inv.p, from_list, from_i, try_take_count, player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Modify count according to collected data */
|
||||||
|
int new_count = try_take_count;
|
||||||
|
if(new_count > src_can_take_count)
|
||||||
|
new_count = src_can_take_count;
|
||||||
|
if(new_count > dst_can_put_count)
|
||||||
|
new_count = dst_can_put_count;
|
||||||
|
|
||||||
|
/* If no items will be moved, don't go further */
|
||||||
|
if(new_count == 0)
|
||||||
|
{
|
||||||
|
infostream<<"IMoveAction::apply(): move was completely disallowed: "
|
||||||
|
<<" 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;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
count = new_count;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
This performs the actual movement
|
Perform actual move
|
||||||
|
|
||||||
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
|
||||||
|
@ -277,6 +318,76 @@ void IMoveAction::apply(InventoryManager *mgr, ServerActiveObject *player, IGame
|
||||||
<<" list=\""<<to_list<<"\""
|
<<" list=\""<<to_list<<"\""
|
||||||
<<" i="<<to_i
|
<<" i="<<to_i
|
||||||
<<std::endl;
|
<<std::endl;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Report move to endpoints
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Detached inventories */
|
||||||
|
|
||||||
|
// Both endpoints are same detached
|
||||||
|
if(from_inv.type == InventoryLocation::DETACHED &&
|
||||||
|
to_inv.type == InventoryLocation::DETACHED &&
|
||||||
|
from_inv.name == to_inv.name)
|
||||||
|
{
|
||||||
|
lua_State *L = player->getEnv()->getLua();
|
||||||
|
scriptapi_detached_inventory_on_move(
|
||||||
|
L, from_inv.name, from_list, from_i,
|
||||||
|
to_list, to_i, count, player);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Destination is detached
|
||||||
|
if(to_inv.type == InventoryLocation::DETACHED)
|
||||||
|
{
|
||||||
|
lua_State *L = player->getEnv()->getLua();
|
||||||
|
ItemStack src_item = list_from->getItem(from_i);
|
||||||
|
src_item.count = count;
|
||||||
|
scriptapi_detached_inventory_on_put(
|
||||||
|
L, to_inv.name, to_list, to_i, src_item, player);
|
||||||
|
}
|
||||||
|
// Source is detached
|
||||||
|
if(from_inv.type == InventoryLocation::DETACHED)
|
||||||
|
{
|
||||||
|
lua_State *L = player->getEnv()->getLua();
|
||||||
|
ItemStack src_item = list_from->getItem(from_i);
|
||||||
|
src_item.count = count;
|
||||||
|
scriptapi_detached_inventory_on_take(
|
||||||
|
L, from_inv.name, from_list, from_i, src_item.count, player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Node metadata inventories */
|
||||||
|
|
||||||
|
// Both endpoints are same nodemeta
|
||||||
|
if(from_inv.type == InventoryLocation::NODEMETA &&
|
||||||
|
to_inv.type == InventoryLocation::NODEMETA &&
|
||||||
|
from_inv.p == to_inv.p)
|
||||||
|
{
|
||||||
|
lua_State *L = player->getEnv()->getLua();
|
||||||
|
scriptapi_nodemeta_inventory_on_move(
|
||||||
|
L, from_inv.p, from_list, from_i,
|
||||||
|
to_list, to_i, count, player);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
// Destination is nodemeta
|
||||||
|
if(to_inv.type == InventoryLocation::NODEMETA)
|
||||||
|
{
|
||||||
|
lua_State *L = player->getEnv()->getLua();
|
||||||
|
ItemStack src_item = list_from->getItem(from_i);
|
||||||
|
src_item.count = count;
|
||||||
|
scriptapi_nodemeta_inventory_on_put(
|
||||||
|
L, to_inv.p, to_list, to_i, src_item, player);
|
||||||
|
}
|
||||||
|
// Source is nodemeta
|
||||||
|
else if(from_inv.type == InventoryLocation::NODEMETA)
|
||||||
|
{
|
||||||
|
lua_State *L = player->getEnv()->getLua();
|
||||||
|
ItemStack src_item = list_from->getItem(from_i);
|
||||||
|
src_item.count = count;
|
||||||
|
scriptapi_nodemeta_inventory_on_take(
|
||||||
|
L, from_inv.p, from_list, from_i, src_item.count, player);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mgr->setInventoryModified(from_inv);
|
mgr->setInventoryModified(from_inv);
|
||||||
|
@ -361,54 +472,88 @@ void IDropAction::apply(InventoryManager *mgr, ServerActiveObject *player, IGame
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ItemStack item1;
|
/*
|
||||||
|
Collect information of endpoints
|
||||||
|
*/
|
||||||
|
|
||||||
// Handle node metadata take
|
int take_count = list_from->getItem(from_i).count;
|
||||||
|
if(count != 0 && count < take_count)
|
||||||
|
take_count = count;
|
||||||
|
int src_can_take_count = take_count;
|
||||||
|
|
||||||
|
// Source is detached
|
||||||
|
if(from_inv.type == InventoryLocation::DETACHED)
|
||||||
|
{
|
||||||
|
lua_State *L = player->getEnv()->getLua();
|
||||||
|
src_can_take_count = scriptapi_detached_inventory_allow_take(
|
||||||
|
L, from_inv.name, from_list, from_i, take_count, player);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Source is nodemeta
|
||||||
if(from_inv.type == InventoryLocation::NODEMETA)
|
if(from_inv.type == InventoryLocation::NODEMETA)
|
||||||
{
|
{
|
||||||
lua_State *L = player->getEnv()->getLua();
|
lua_State *L = player->getEnv()->getLua();
|
||||||
int count0 = count;
|
src_can_take_count = scriptapi_nodemeta_inventory_allow_take(
|
||||||
if(count0 == 0)
|
L, from_inv.p, from_list, from_i, take_count, player);
|
||||||
count0 = list_from->getItem(from_i).count;
|
|
||||||
infostream<<player->getDescription()<<" dropping "<<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;
|
|
||||||
item1 = return_stack;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Take item from source list
|
|
||||||
if(count == 0)
|
|
||||||
item1 = list_from->changeItem(from_i, ItemStack());
|
|
||||||
else
|
|
||||||
item1 = list_from->takeItem(from_i, count);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Drop the item and apply the returned ItemStack
|
if(src_can_take_count < take_count)
|
||||||
ItemStack item2 = item1;
|
take_count = src_can_take_count;
|
||||||
if(scriptapi_item_on_drop(player->getEnv()->getLua(), item2, player,
|
|
||||||
|
int actually_dropped_count = 0;
|
||||||
|
|
||||||
|
// Drop the item
|
||||||
|
ItemStack item1 = list_from->getItem(from_i);
|
||||||
|
if(scriptapi_item_on_drop(player->getEnv()->getLua(), item1, player,
|
||||||
player->getBasePosition() + v3f(0,1,0)))
|
player->getBasePosition() + v3f(0,1,0)))
|
||||||
{
|
{
|
||||||
|
actually_dropped_count = take_count - item1.count;
|
||||||
|
|
||||||
|
if(actually_dropped_count == 0){
|
||||||
|
infostream<<"Actually dropped no items"<<std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't remove from inventory in creative mode
|
||||||
if(g_settings->getBool("creative_mode") == true
|
if(g_settings->getBool("creative_mode") == true
|
||||||
&& from_inv.type == InventoryLocation::PLAYER)
|
&& from_inv.type == InventoryLocation::PLAYER){
|
||||||
item2 = item1; // creative mode
|
}
|
||||||
|
else{
|
||||||
|
// Take item from source list
|
||||||
|
ItemStack item2 = list_from->takeItem(from_i, actually_dropped_count);
|
||||||
|
|
||||||
list_from->addItem(from_i, item2);
|
if(item2.count != actually_dropped_count)
|
||||||
|
errorstream<<"Could not take dropped count of items"<<std::endl;
|
||||||
|
|
||||||
// Unless we have put the same amount back as we took in the first place,
|
|
||||||
// set inventory modified flag
|
|
||||||
if(item2.count != item1.count)
|
|
||||||
mgr->setInventoryModified(from_inv);
|
mgr->setInventoryModified(from_inv);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
infostream<<"IDropAction::apply(): dropped "
|
infostream<<"IDropAction::apply(): dropped "
|
||||||
<<" from inv=\""<<from_inv.dump()<<"\""
|
<<" from inv=\""<<from_inv.dump()<<"\""
|
||||||
<<" list=\""<<from_list<<"\""
|
<<" list=\""<<from_list<<"\""
|
||||||
<<" i="<<from_i
|
<<" i="<<from_i
|
||||||
<<std::endl;
|
<<std::endl;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Report drop to endpoints
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Source is detached
|
||||||
|
if(from_inv.type == InventoryLocation::DETACHED)
|
||||||
|
{
|
||||||
|
lua_State *L = player->getEnv()->getLua();
|
||||||
|
scriptapi_detached_inventory_on_take(
|
||||||
|
L, from_inv.name, from_list, from_i, actually_dropped_count, player);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Source is nodemeta
|
||||||
|
if(from_inv.type == InventoryLocation::NODEMETA)
|
||||||
|
{
|
||||||
|
lua_State *L = player->getEnv()->getLua();
|
||||||
|
scriptapi_nodemeta_inventory_on_take(
|
||||||
|
L, from_inv.p, from_list, from_i, actually_dropped_count, player);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IDropAction::clientApply(InventoryManager *mgr, IGameDef *gamedef)
|
void IDropAction::clientApply(InventoryManager *mgr, IGameDef *gamedef)
|
||||||
|
|
|
@ -4579,8 +4579,8 @@ static int l_get_inventory(lua_State *L)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// create_detached_inventory(name)
|
// create_detached_inventory_raw(name)
|
||||||
static int l_create_detached_inventory(lua_State *L)
|
static int l_create_detached_inventory_raw(lua_State *L)
|
||||||
{
|
{
|
||||||
const char *name = luaL_checkstring(L, 1);
|
const char *name = luaL_checkstring(L, 1);
|
||||||
if(get_server(L)->createDetachedInventory(name) != NULL){
|
if(get_server(L)->createDetachedInventory(name) != NULL){
|
||||||
|
@ -4866,7 +4866,7 @@ static const struct luaL_Reg minetest_f [] = {
|
||||||
{"chat_send_player", l_chat_send_player},
|
{"chat_send_player", l_chat_send_player},
|
||||||
{"get_player_privs", l_get_player_privs},
|
{"get_player_privs", l_get_player_privs},
|
||||||
{"get_inventory", l_get_inventory},
|
{"get_inventory", l_get_inventory},
|
||||||
{"create_detached_inventory", l_create_detached_inventory},
|
{"create_detached_inventory_raw", l_create_detached_inventory_raw},
|
||||||
{"get_dig_params", l_get_dig_params},
|
{"get_dig_params", l_get_dig_params},
|
||||||
{"get_hit_params", l_get_hit_params},
|
{"get_hit_params", l_get_hit_params},
|
||||||
{"get_current_modname", l_get_current_modname},
|
{"get_current_modname", l_get_current_modname},
|
||||||
|
@ -5734,7 +5734,128 @@ 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,
|
/*
|
||||||
|
Node metadata inventory callbacks
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Return number of accepted items to be moved
|
||||||
|
int scriptapi_nodemeta_inventory_allow_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 0;
|
||||||
|
|
||||||
|
// Push callback function on stack
|
||||||
|
if(!get_item_callback(L, ndef->get(node).name.c_str(),
|
||||||
|
"allow_metadata_inventory_move"))
|
||||||
|
return count;
|
||||||
|
|
||||||
|
// function(pos, from_list, from_index, to_list, to_index, count, player)
|
||||||
|
// pos
|
||||||
|
push_v3s16(L, p);
|
||||||
|
// from_list
|
||||||
|
lua_pushstring(L, from_list.c_str());
|
||||||
|
// from_index
|
||||||
|
lua_pushinteger(L, from_index + 1);
|
||||||
|
// to_list
|
||||||
|
lua_pushstring(L, to_list.c_str());
|
||||||
|
// to_index
|
||||||
|
lua_pushinteger(L, to_index + 1);
|
||||||
|
// count
|
||||||
|
lua_pushinteger(L, count);
|
||||||
|
// player
|
||||||
|
objectref_get_or_create(L, player);
|
||||||
|
if(lua_pcall(L, 7, 1, 0))
|
||||||
|
script_error(L, "error: %s", lua_tostring(L, -1));
|
||||||
|
return luaL_checkinteger(L, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return number of accepted items to be put
|
||||||
|
int scriptapi_nodemeta_inventory_allow_put(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 0;
|
||||||
|
|
||||||
|
// Push callback function on stack
|
||||||
|
if(!get_item_callback(L, ndef->get(node).name.c_str(),
|
||||||
|
"allow_metadata_inventory_put"))
|
||||||
|
return stack.count;
|
||||||
|
|
||||||
|
// Call function(pos, listname, index, stack, player)
|
||||||
|
// pos
|
||||||
|
push_v3s16(L, p);
|
||||||
|
// listname
|
||||||
|
lua_pushstring(L, listname.c_str());
|
||||||
|
// index
|
||||||
|
lua_pushinteger(L, index + 1);
|
||||||
|
// stack
|
||||||
|
LuaItemStack::create(L, stack);
|
||||||
|
// player
|
||||||
|
objectref_get_or_create(L, player);
|
||||||
|
if(lua_pcall(L, 5, 1, 0))
|
||||||
|
script_error(L, "error: %s", lua_tostring(L, -1));
|
||||||
|
return luaL_checkinteger(L, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return number of accepted items to be taken
|
||||||
|
int scriptapi_nodemeta_inventory_allow_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 0;
|
||||||
|
|
||||||
|
// Push callback function on stack
|
||||||
|
if(!get_item_callback(L, ndef->get(node).name.c_str(),
|
||||||
|
"allow_metadata_inventory_take"))
|
||||||
|
return count;
|
||||||
|
|
||||||
|
// Call function(pos, listname, index, count, player)
|
||||||
|
// pos
|
||||||
|
push_v3s16(L, p);
|
||||||
|
// listname
|
||||||
|
lua_pushstring(L, listname.c_str());
|
||||||
|
// index
|
||||||
|
lua_pushinteger(L, index + 1);
|
||||||
|
// count
|
||||||
|
lua_pushinteger(L, count);
|
||||||
|
// player
|
||||||
|
objectref_get_or_create(L, player);
|
||||||
|
if(lua_pcall(L, 5, 1, 0))
|
||||||
|
script_error(L, "error: %s", lua_tostring(L, -1));
|
||||||
|
return luaL_checkinteger(L, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Report moved items
|
||||||
|
void scriptapi_nodemeta_inventory_on_move(lua_State *L, v3s16 p,
|
||||||
const std::string &from_list, int from_index,
|
const std::string &from_list, int from_index,
|
||||||
const std::string &to_list, int to_index,
|
const std::string &to_list, int to_index,
|
||||||
int count, ServerActiveObject *player)
|
int count, ServerActiveObject *player)
|
||||||
|
@ -5756,18 +5877,26 @@ void scriptapi_node_on_metadata_inventory_move(lua_State *L, v3s16 p,
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// function(pos, from_list, from_index, to_list, to_index, count, player)
|
// function(pos, from_list, from_index, to_list, to_index, count, player)
|
||||||
|
// pos
|
||||||
push_v3s16(L, p);
|
push_v3s16(L, p);
|
||||||
|
// from_list
|
||||||
lua_pushstring(L, from_list.c_str());
|
lua_pushstring(L, from_list.c_str());
|
||||||
|
// from_index
|
||||||
lua_pushinteger(L, from_index + 1);
|
lua_pushinteger(L, from_index + 1);
|
||||||
|
// to_list
|
||||||
lua_pushstring(L, to_list.c_str());
|
lua_pushstring(L, to_list.c_str());
|
||||||
|
// to_index
|
||||||
lua_pushinteger(L, to_index + 1);
|
lua_pushinteger(L, to_index + 1);
|
||||||
|
// count
|
||||||
lua_pushinteger(L, count);
|
lua_pushinteger(L, count);
|
||||||
|
// player
|
||||||
objectref_get_or_create(L, player);
|
objectref_get_or_create(L, player);
|
||||||
if(lua_pcall(L, 7, 0, 0))
|
if(lua_pcall(L, 7, 0, 0))
|
||||||
script_error(L, "error: %s", lua_tostring(L, -1));
|
script_error(L, "error: %s", lua_tostring(L, -1));
|
||||||
}
|
}
|
||||||
|
|
||||||
ItemStack scriptapi_node_on_metadata_inventory_offer(lua_State *L, v3s16 p,
|
// Report put items
|
||||||
|
void scriptapi_nodemeta_inventory_on_put(lua_State *L, v3s16 p,
|
||||||
const std::string &listname, int index, ItemStack &stack,
|
const std::string &listname, int index, ItemStack &stack,
|
||||||
ServerActiveObject *player)
|
ServerActiveObject *player)
|
||||||
{
|
{
|
||||||
|
@ -5780,25 +5909,30 @@ ItemStack scriptapi_node_on_metadata_inventory_offer(lua_State *L, v3s16 p,
|
||||||
// If node doesn't exist, we don't know what callback to call
|
// If node doesn't exist, we don't know what callback to call
|
||||||
MapNode node = get_env(L)->getMap().getNodeNoEx(p);
|
MapNode node = get_env(L)->getMap().getNodeNoEx(p);
|
||||||
if(node.getContent() == CONTENT_IGNORE)
|
if(node.getContent() == CONTENT_IGNORE)
|
||||||
return stack;
|
return;
|
||||||
|
|
||||||
// Push callback function on stack
|
// Push callback function on stack
|
||||||
if(!get_item_callback(L, ndef->get(node).name.c_str(),
|
if(!get_item_callback(L, ndef->get(node).name.c_str(),
|
||||||
"on_metadata_inventory_offer"))
|
"on_metadata_inventory_put"))
|
||||||
return stack;
|
return;
|
||||||
|
|
||||||
// Call function(pos, listname, index, stack, player)
|
// Call function(pos, listname, index, stack, player)
|
||||||
|
// pos
|
||||||
push_v3s16(L, p);
|
push_v3s16(L, p);
|
||||||
|
// listname
|
||||||
lua_pushstring(L, listname.c_str());
|
lua_pushstring(L, listname.c_str());
|
||||||
|
// index
|
||||||
lua_pushinteger(L, index + 1);
|
lua_pushinteger(L, index + 1);
|
||||||
|
// stack
|
||||||
LuaItemStack::create(L, stack);
|
LuaItemStack::create(L, stack);
|
||||||
|
// player
|
||||||
objectref_get_or_create(L, player);
|
objectref_get_or_create(L, player);
|
||||||
if(lua_pcall(L, 5, 1, 0))
|
if(lua_pcall(L, 5, 0, 0))
|
||||||
script_error(L, "error: %s", lua_tostring(L, -1));
|
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,
|
// Report taken items
|
||||||
|
void scriptapi_nodemeta_inventory_on_take(lua_State *L, v3s16 p,
|
||||||
const std::string &listname, int index, int count,
|
const std::string &listname, int index, int count,
|
||||||
ServerActiveObject *player)
|
ServerActiveObject *player)
|
||||||
{
|
{
|
||||||
|
@ -5811,22 +5945,270 @@ ItemStack scriptapi_node_on_metadata_inventory_take(lua_State *L, v3s16 p,
|
||||||
// If node doesn't exist, we don't know what callback to call
|
// If node doesn't exist, we don't know what callback to call
|
||||||
MapNode node = get_env(L)->getMap().getNodeNoEx(p);
|
MapNode node = get_env(L)->getMap().getNodeNoEx(p);
|
||||||
if(node.getContent() == CONTENT_IGNORE)
|
if(node.getContent() == CONTENT_IGNORE)
|
||||||
return ItemStack();
|
return;
|
||||||
|
|
||||||
// Push callback function on stack
|
// Push callback function on stack
|
||||||
if(!get_item_callback(L, ndef->get(node).name.c_str(),
|
if(!get_item_callback(L, ndef->get(node).name.c_str(),
|
||||||
"on_metadata_inventory_take"))
|
"on_metadata_inventory_take"))
|
||||||
return ItemStack();
|
return;
|
||||||
|
|
||||||
// Call function(pos, listname, index, count, player)
|
// Call function(pos, listname, index, count, player)
|
||||||
|
// pos
|
||||||
push_v3s16(L, p);
|
push_v3s16(L, p);
|
||||||
|
// listname
|
||||||
lua_pushstring(L, listname.c_str());
|
lua_pushstring(L, listname.c_str());
|
||||||
|
// index
|
||||||
lua_pushinteger(L, index + 1);
|
lua_pushinteger(L, index + 1);
|
||||||
|
// count
|
||||||
lua_pushinteger(L, count);
|
lua_pushinteger(L, count);
|
||||||
|
// player
|
||||||
|
objectref_get_or_create(L, player);
|
||||||
|
if(lua_pcall(L, 5, 0, 0))
|
||||||
|
script_error(L, "error: %s", lua_tostring(L, -1));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Detached inventory callbacks
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Retrieves minetest.detached_inventories[name][callbackname]
|
||||||
|
// If that is nil or on error, return false and stack is unchanged
|
||||||
|
// If that is a function, returns true and pushes the
|
||||||
|
// function onto the stack
|
||||||
|
static bool get_detached_inventory_callback(lua_State *L,
|
||||||
|
const std::string &name, const char *callbackname)
|
||||||
|
{
|
||||||
|
lua_getglobal(L, "minetest");
|
||||||
|
lua_getfield(L, -1, "detached_inventories");
|
||||||
|
lua_remove(L, -2);
|
||||||
|
luaL_checktype(L, -1, LUA_TTABLE);
|
||||||
|
lua_getfield(L, -1, name.c_str());
|
||||||
|
lua_remove(L, -2);
|
||||||
|
// Should be a table
|
||||||
|
if(lua_type(L, -1) != LUA_TTABLE)
|
||||||
|
{
|
||||||
|
errorstream<<"Item \""<<name<<"\" not defined"<<std::endl;
|
||||||
|
lua_pop(L, 1);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
lua_getfield(L, -1, callbackname);
|
||||||
|
lua_remove(L, -2);
|
||||||
|
// Should be a function or nil
|
||||||
|
if(lua_type(L, -1) == LUA_TFUNCTION)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if(lua_isnil(L, -1))
|
||||||
|
{
|
||||||
|
lua_pop(L, 1);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
errorstream<<"Detached inventory \""<<name<<"\" callback \""
|
||||||
|
<<callbackname<<"\" is not a function"<<std::endl;
|
||||||
|
lua_pop(L, 1);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return number of accepted items to be moved
|
||||||
|
int scriptapi_detached_inventory_allow_move(lua_State *L,
|
||||||
|
const std::string &name,
|
||||||
|
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);
|
||||||
|
|
||||||
|
// Push callback function on stack
|
||||||
|
if(!get_detached_inventory_callback(L, name, "allow_move"))
|
||||||
|
return count;
|
||||||
|
|
||||||
|
// function(inv, from_list, from_index, to_list, to_index, count, player)
|
||||||
|
// inv
|
||||||
|
InventoryLocation loc;
|
||||||
|
loc.setDetached(name);
|
||||||
|
InvRef::create(L, loc);
|
||||||
|
// from_list
|
||||||
|
lua_pushstring(L, from_list.c_str());
|
||||||
|
// from_index
|
||||||
|
lua_pushinteger(L, from_index + 1);
|
||||||
|
// to_list
|
||||||
|
lua_pushstring(L, to_list.c_str());
|
||||||
|
// to_index
|
||||||
|
lua_pushinteger(L, to_index + 1);
|
||||||
|
// count
|
||||||
|
lua_pushinteger(L, count);
|
||||||
|
// player
|
||||||
|
objectref_get_or_create(L, player);
|
||||||
|
if(lua_pcall(L, 7, 1, 0))
|
||||||
|
script_error(L, "error: %s", lua_tostring(L, -1));
|
||||||
|
return luaL_checkinteger(L, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return number of accepted items to be put
|
||||||
|
int scriptapi_detached_inventory_allow_put(lua_State *L,
|
||||||
|
const std::string &name,
|
||||||
|
const std::string &listname, int index, ItemStack &stack,
|
||||||
|
ServerActiveObject *player)
|
||||||
|
{
|
||||||
|
realitycheck(L);
|
||||||
|
assert(lua_checkstack(L, 20));
|
||||||
|
StackUnroller stack_unroller(L);
|
||||||
|
|
||||||
|
// Push callback function on stack
|
||||||
|
if(!get_detached_inventory_callback(L, name, "allow_put"))
|
||||||
|
return stack.count; // All will be accepted
|
||||||
|
|
||||||
|
// Call function(inv, listname, index, stack, player)
|
||||||
|
// inv
|
||||||
|
InventoryLocation loc;
|
||||||
|
loc.setDetached(name);
|
||||||
|
InvRef::create(L, loc);
|
||||||
|
// listname
|
||||||
|
lua_pushstring(L, listname.c_str());
|
||||||
|
// index
|
||||||
|
lua_pushinteger(L, index + 1);
|
||||||
|
// stack
|
||||||
|
LuaItemStack::create(L, stack);
|
||||||
|
// player
|
||||||
objectref_get_or_create(L, player);
|
objectref_get_or_create(L, player);
|
||||||
if(lua_pcall(L, 5, 1, 0))
|
if(lua_pcall(L, 5, 1, 0))
|
||||||
script_error(L, "error: %s", lua_tostring(L, -1));
|
script_error(L, "error: %s", lua_tostring(L, -1));
|
||||||
return read_item(L, -1);
|
return luaL_checkinteger(L, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return number of accepted items to be taken
|
||||||
|
int scriptapi_detached_inventory_allow_take(lua_State *L,
|
||||||
|
const std::string &name,
|
||||||
|
const std::string &listname, int index, int count,
|
||||||
|
ServerActiveObject *player)
|
||||||
|
{
|
||||||
|
realitycheck(L);
|
||||||
|
assert(lua_checkstack(L, 20));
|
||||||
|
StackUnroller stack_unroller(L);
|
||||||
|
|
||||||
|
// Push callback function on stack
|
||||||
|
if(!get_detached_inventory_callback(L, name, "allow_take"))
|
||||||
|
return count; // All will be accepted
|
||||||
|
|
||||||
|
// Call function(inv, listname, index, count, player)
|
||||||
|
// inv
|
||||||
|
InventoryLocation loc;
|
||||||
|
loc.setDetached(name);
|
||||||
|
InvRef::create(L, loc);
|
||||||
|
// listname
|
||||||
|
lua_pushstring(L, listname.c_str());
|
||||||
|
// index
|
||||||
|
lua_pushinteger(L, index + 1);
|
||||||
|
// count
|
||||||
|
lua_pushinteger(L, count);
|
||||||
|
// player
|
||||||
|
objectref_get_or_create(L, player);
|
||||||
|
if(lua_pcall(L, 5, 1, 0))
|
||||||
|
script_error(L, "error: %s", lua_tostring(L, -1));
|
||||||
|
return luaL_checkinteger(L, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Report moved items
|
||||||
|
void scriptapi_detached_inventory_on_move(lua_State *L,
|
||||||
|
const std::string &name,
|
||||||
|
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);
|
||||||
|
|
||||||
|
// Push callback function on stack
|
||||||
|
if(!get_detached_inventory_callback(L, name, "on_move"))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// function(inv, from_list, from_index, to_list, to_index, count, player)
|
||||||
|
// inv
|
||||||
|
InventoryLocation loc;
|
||||||
|
loc.setDetached(name);
|
||||||
|
InvRef::create(L, loc);
|
||||||
|
// from_list
|
||||||
|
lua_pushstring(L, from_list.c_str());
|
||||||
|
// from_index
|
||||||
|
lua_pushinteger(L, from_index + 1);
|
||||||
|
// to_list
|
||||||
|
lua_pushstring(L, to_list.c_str());
|
||||||
|
// to_index
|
||||||
|
lua_pushinteger(L, to_index + 1);
|
||||||
|
// count
|
||||||
|
lua_pushinteger(L, count);
|
||||||
|
// player
|
||||||
|
objectref_get_or_create(L, player);
|
||||||
|
if(lua_pcall(L, 7, 0, 0))
|
||||||
|
script_error(L, "error: %s", lua_tostring(L, -1));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Report put items
|
||||||
|
void scriptapi_detached_inventory_on_put(lua_State *L,
|
||||||
|
const std::string &name,
|
||||||
|
const std::string &listname, int index, ItemStack &stack,
|
||||||
|
ServerActiveObject *player)
|
||||||
|
{
|
||||||
|
realitycheck(L);
|
||||||
|
assert(lua_checkstack(L, 20));
|
||||||
|
StackUnroller stack_unroller(L);
|
||||||
|
|
||||||
|
// Push callback function on stack
|
||||||
|
if(!get_detached_inventory_callback(L, name, "on_put"))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Call function(inv, listname, index, stack, player)
|
||||||
|
// inv
|
||||||
|
InventoryLocation loc;
|
||||||
|
loc.setDetached(name);
|
||||||
|
InvRef::create(L, loc);
|
||||||
|
// listname
|
||||||
|
lua_pushstring(L, listname.c_str());
|
||||||
|
// index
|
||||||
|
lua_pushinteger(L, index + 1);
|
||||||
|
// stack
|
||||||
|
LuaItemStack::create(L, stack);
|
||||||
|
// player
|
||||||
|
objectref_get_or_create(L, player);
|
||||||
|
if(lua_pcall(L, 5, 0, 0))
|
||||||
|
script_error(L, "error: %s", lua_tostring(L, -1));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Report taken items
|
||||||
|
void scriptapi_detached_inventory_on_take(lua_State *L,
|
||||||
|
const std::string &name,
|
||||||
|
const std::string &listname, int index, int count,
|
||||||
|
ServerActiveObject *player)
|
||||||
|
{
|
||||||
|
realitycheck(L);
|
||||||
|
assert(lua_checkstack(L, 20));
|
||||||
|
StackUnroller stack_unroller(L);
|
||||||
|
|
||||||
|
// Push callback function on stack
|
||||||
|
if(!get_detached_inventory_callback(L, name, "on_take"))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Call function(inv, listname, index, count, player)
|
||||||
|
// inv
|
||||||
|
InventoryLocation loc;
|
||||||
|
loc.setDetached(name);
|
||||||
|
InvRef::create(L, loc);
|
||||||
|
// listname
|
||||||
|
lua_pushstring(L, listname.c_str());
|
||||||
|
// index
|
||||||
|
lua_pushinteger(L, index + 1);
|
||||||
|
// count
|
||||||
|
lua_pushinteger(L, count);
|
||||||
|
// player
|
||||||
|
objectref_get_or_create(L, player);
|
||||||
|
if(lua_pcall(L, 5, 0, 0))
|
||||||
|
script_error(L, "error: %s", lua_tostring(L, -1));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -101,17 +101,66 @@ 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,
|
/* Node metadata inventory callbacks */
|
||||||
|
// Return number of accepted items to be moved
|
||||||
|
int scriptapi_nodemeta_inventory_allow_move(lua_State *L, v3s16 p,
|
||||||
const std::string &from_list, int from_index,
|
const std::string &from_list, int from_index,
|
||||||
const std::string &to_list, int to_index,
|
const std::string &to_list, int to_index,
|
||||||
int count, ServerActiveObject *player);
|
int count, ServerActiveObject *player);
|
||||||
// Inserts items, returns rejected items
|
// Return number of accepted items to be put
|
||||||
ItemStack scriptapi_node_on_metadata_inventory_offer(lua_State *L, v3s16 p,
|
int scriptapi_nodemeta_inventory_allow_put(lua_State *L, v3s16 p,
|
||||||
const std::string &listname, int index, ItemStack &stack,
|
const std::string &listname, int index, ItemStack &stack,
|
||||||
ServerActiveObject *player);
|
ServerActiveObject *player);
|
||||||
// Takes items, returns taken items
|
// Return number of accepted items to be taken
|
||||||
ItemStack scriptapi_node_on_metadata_inventory_take(lua_State *L, v3s16 p,
|
int scriptapi_nodemeta_inventory_allow_take(lua_State *L, v3s16 p,
|
||||||
|
const std::string &listname, int index, int count,
|
||||||
|
ServerActiveObject *player);
|
||||||
|
// Report moved items
|
||||||
|
void scriptapi_nodemeta_inventory_on_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);
|
||||||
|
// Report put items
|
||||||
|
void scriptapi_nodemeta_inventory_on_put(lua_State *L, v3s16 p,
|
||||||
|
const std::string &listname, int index, ItemStack &stack,
|
||||||
|
ServerActiveObject *player);
|
||||||
|
// Report taken items
|
||||||
|
void scriptapi_nodemeta_inventory_on_take(lua_State *L, v3s16 p,
|
||||||
|
const std::string &listname, int index, int count,
|
||||||
|
ServerActiveObject *player);
|
||||||
|
|
||||||
|
/* Detached inventory callbacks */
|
||||||
|
// Return number of accepted items to be moved
|
||||||
|
int scriptapi_detached_inventory_allow_move(lua_State *L,
|
||||||
|
const std::string &name,
|
||||||
|
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 scriptapi_detached_inventory_allow_put(lua_State *L,
|
||||||
|
const std::string &name,
|
||||||
|
const std::string &listname, int index, ItemStack &stack,
|
||||||
|
ServerActiveObject *player);
|
||||||
|
// Return number of accepted items to be taken
|
||||||
|
int scriptapi_detached_inventory_allow_take(lua_State *L,
|
||||||
|
const std::string &name,
|
||||||
|
const std::string &listname, int index, int count,
|
||||||
|
ServerActiveObject *player);
|
||||||
|
// Report moved items
|
||||||
|
void scriptapi_detached_inventory_on_move(lua_State *L,
|
||||||
|
const std::string &name,
|
||||||
|
const std::string &from_list, int from_index,
|
||||||
|
const std::string &to_list, int to_index,
|
||||||
|
int count, ServerActiveObject *player);
|
||||||
|
// Report put items
|
||||||
|
void scriptapi_detached_inventory_on_put(lua_State *L,
|
||||||
|
const std::string &name,
|
||||||
|
const std::string &listname, int index, ItemStack &stack,
|
||||||
|
ServerActiveObject *player);
|
||||||
|
// Report taken items
|
||||||
|
void scriptapi_detached_inventory_on_take(lua_State *L,
|
||||||
|
const std::string &name,
|
||||||
const std::string &listname, int index, int count,
|
const std::string &listname, int index, int count,
|
||||||
ServerActiveObject *player);
|
ServerActiveObject *player);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue