1
0
mirror of https://github.com/luanti-org/luanti.git synced 2025-11-01 07:45:26 +01:00

Merge remote-tracking branch 'upstream/master'

This commit is contained in:
sfan5
2012-07-25 23:09:18 +02:00
30 changed files with 1360 additions and 551 deletions

View File

@@ -21,4 +21,5 @@ dofile(minetest.get_modpath("__builtin").."/privileges.lua")
dofile(minetest.get_modpath("__builtin").."/auth.lua")
dofile(minetest.get_modpath("__builtin").."/chatcommands.lua")
dofile(minetest.get_modpath("__builtin").."/static_spawn.lua")
dofile(minetest.get_modpath("__builtin").."/detached_inventory.lua")

View File

@@ -16,4 +16,11 @@ minetest.digprop_woodlike = digprop_err
minetest.digprop_leaveslike = 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
minetest.add_to_creative_inventory = function(itemstring)
minetest.log('info', "WARNING: minetest.add_to_creative_inventory: This function is deprecated and does nothing.")
end

View File

@@ -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

View File

@@ -124,55 +124,84 @@ end
function minetest.item_place_node(itemstack, placer, pointed_thing)
local item = itemstack:peek_item()
local def = itemstack:get_definition()
if def.type == "node" and pointed_thing.type == "node" then
local pos = pointed_thing.above
local oldnode = minetest.env:get_node(pos)
local olddef = ItemStack({name=oldnode.name}):get_definition()
if not olddef.buildable_to then
minetest.log("info", placer:get_player_name() .. " tried to place"
.. " node in invalid position " .. minetest.pos_to_string(pos)
.. ", replacing " .. oldnode.name)
return
end
minetest.log("action", placer:get_player_name() .. " places node "
.. def.name .. " at " .. minetest.pos_to_string(pos))
local newnode = {name = def.name, param1 = 0, param2 = 0}
-- Calculate direction for wall mounted stuff like torches and signs
if def.paramtype2 == 'wallmounted' then
local under = pointed_thing.under
local above = pointed_thing.above
local dir = {x = under.x - above.x, y = under.y - above.y, z = under.z - above.z}
newnode.param2 = minetest.dir_to_wallmounted(dir)
-- Calculate the direction for furnaces and chests and stuff
elseif def.paramtype2 == 'facedir' then
local placer_pos = placer:getpos()
if placer_pos then
local dir = {x = pos.x - placer_pos.x, y = pos.y - placer_pos.y, z = pos.z - placer_pos.z}
newnode.param2 = minetest.dir_to_facedir(dir)
minetest.log("action", "facedir: " .. newnode.param2)
end
end
-- Add node and update
minetest.env:add_node(pos, newnode)
-- Run callback
if def.after_place_node then
def.after_place_node(pos, placer)
end
-- Run script hook (deprecated)
local _, callback
for _, callback in ipairs(minetest.registered_on_placenodes) do
callback(pos, newnode, placer)
end
itemstack:take_item()
if def.type ~= "node" or pointed_thing.type ~= "node" then
return itemstack
end
local under = pointed_thing.under
local oldnode_under = minetest.env:get_node(under)
local olddef_under = ItemStack({name=oldnode_under.name}):get_definition()
olddef_under = olddef_under or minetest.nodedef_default
local above = pointed_thing.above
local oldnode_above = minetest.env:get_node(above)
local olddef_above = ItemStack({name=oldnode_above.name}):get_definition()
olddef_above = olddef_above or minetest.nodedef_default
if not olddef_above.buildable_to and not olddef_under.buildable_to then
minetest.log("info", placer:get_player_name() .. " tried to place"
.. " node in invalid position " .. minetest.pos_to_string(above)
.. ", replacing " .. oldnode_above.name)
return
end
-- Place above pointed node
local place_to = {x = above.x, y = above.y, z = above.z}
-- If node under is buildable_to, place into it instead (eg. snow)
if olddef_under.buildable_to then
minetest.log("info", "node under is buildable to")
place_to = {x = under.x, y = under.y, z = under.z}
end
minetest.log("action", placer:get_player_name() .. " places node "
.. def.name .. " at " .. minetest.pos_to_string(place_to))
local oldnode = minetest.env:get_node(place_to)
local newnode = {name = def.name, param1 = 0, param2 = 0}
-- Calculate direction for wall mounted stuff like torches and signs
if def.paramtype2 == 'wallmounted' then
local dir = {
x = under.x - above.x,
y = under.y - above.y,
z = under.z - above.z
}
newnode.param2 = minetest.dir_to_wallmounted(dir)
-- Calculate the direction for furnaces and chests and stuff
elseif def.paramtype2 == 'facedir' then
local placer_pos = placer:getpos()
if placer_pos then
local dir = {
x = above.x - placer_pos.x,
y = above.y - placer_pos.y,
z = above.z - placer_pos.z
}
newnode.param2 = minetest.dir_to_facedir(dir)
minetest.log("action", "facedir: " .. newnode.param2)
end
end
-- Add node and update
minetest.env:add_node(place_to, newnode)
-- Run callback
if def.after_place_node then
-- Copy place_to because callback can modify it
local place_to_copy = {x=place_to.x, y=place_to.y, z=place_to.z}
def.after_place_node(place_to_copy, placer)
end
-- Run script hook
local _, callback
for _, callback in ipairs(minetest.registered_on_placenodes) do
-- Copy pos and node because callback can modify them
local place_to_copy = {x=place_to.x, y=place_to.y, z=place_to.z}
local newnode_copy = {name=newnode.name, param1=newnode.param1, param2=newnode.param2}
local oldnode_copy = {name=oldnode.name, param1=oldnode.param1, param2=oldnode.param2}
callback(place_to_copy, newnode_copy, placer, oldnode_copy)
end
itemstack:take_item()
return itemstack
end
@@ -222,9 +251,11 @@ function minetest.node_punch(pos, node, puncher)
-- Run script hook
local _, callback
for _, callback in ipairs(minetest.registered_on_punchnodes) do
callback(pos, node, puncher)
-- Copy pos and node because callback can modify them
local pos_copy = {x=pos.x, y=pos.y, z=pos.z}
local node_copy = {name=node.name, param1=node.param1, param2=node.param2}
callback(pos_copy, node_copy, puncher)
end
end
function minetest.node_dig(pos, node, digger)
@@ -242,29 +273,25 @@ function minetest.node_dig(pos, node, digger)
minetest.log('action', digger:get_player_name() .. " digs "
.. node.name .. " at " .. minetest.pos_to_string(pos))
if not minetest.setting_getbool("creative_mode") then
local wielded = digger:get_wielded_item()
local drops = minetest.get_node_drops(node.name, wielded:get_name())
local wielded = digger:get_wielded_item()
local drops = minetest.get_node_drops(node.name, wielded:get_name())
-- Wear out tool
tp = wielded:get_tool_capabilities()
dp = minetest.get_dig_params(def.groups, tp)
wielded:add_wear(dp.wear)
digger:set_wielded_item(wielded)
-- Wear out tool
local tp = wielded:get_tool_capabilities()
local dp = minetest.get_dig_params(def.groups, tp)
wielded:add_wear(dp.wear)
digger:set_wielded_item(wielded)
-- Add dropped items to object's inventory
if digger:get_inventory() then
local _, dropped_item
for _, dropped_item in ipairs(drops) do
digger:get_inventory():add_item("main", dropped_item)
end
-- Add dropped items to object's inventory
if digger:get_inventory() then
local _, dropped_item
for _, dropped_item in ipairs(drops) do
digger:get_inventory():add_item("main", dropped_item)
end
end
local oldnode = nil
local oldmetadata = nil
if def.after_dig_node then
oldnode = node;
oldmetadata = minetest.env:get_meta(pos):to_table()
end
@@ -273,51 +300,22 @@ function minetest.node_dig(pos, node, digger)
-- Run callback
if def.after_dig_node then
def.after_dig_node(pos, oldnode, oldmetadata, digger)
-- Copy pos and node because callback can modify them
local pos_copy = {x=pos.x, y=pos.y, z=pos.z}
local node_copy = {name=node.name, param1=node.param1, param2=node.param2}
def.after_dig_node(pos_copy, node_copy, oldmetadata, digger)
end
-- Run script hook (deprecated)
-- Run script hook
local _, callback
for _, callback in ipairs(minetest.registered_on_dignodes) do
callback(pos, node, digger)
-- Copy pos and node because callback can modify them
local pos_copy = {x=pos.x, y=pos.y, z=pos.z}
local node_copy = {name=node.name, param1=node.param1, param2=node.param2}
callback(pos_copy, node_copy, digger)
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
-- NOTE: This is not the preferred way. Preferred way is to provide enough
-- callbacks to not require redefining global functions. -celeron55

View File

@@ -244,6 +244,7 @@ minetest.register_item(":unknown", {
inventory_image = "unknown_item.png",
on_place = minetest.item_place,
on_drop = minetest.item_drop,
groups = {not_in_creative_inventory=1},
})
minetest.register_node(":air", {
@@ -258,6 +259,7 @@ minetest.register_node(":air", {
diggable = false,
buildable_to = true,
air_equivalent = true,
groups = {not_in_creative_inventory=1},
})
minetest.register_node(":ignore", {
@@ -272,23 +274,15 @@ minetest.register_node(":ignore", {
diggable = false,
buildable_to = true, -- A way to remove accidentally placed ignores
air_equivalent = true,
groups = {not_in_creative_inventory=1},
})
-- The hand (bare definition)
minetest.register_item(":", {
type = "none",
groups = {not_in_creative_inventory=1},
})
--
-- Creative inventory
--
minetest.creative_inventory = {}
minetest.add_to_creative_inventory = function(itemstring)
table.insert(minetest.creative_inventory, itemstring)
end
--
-- Callback registration
--

View File

@@ -677,6 +677,7 @@ size[<W>,<H>]
^ deprecated: invsize[<W>,<H>;]
list[<inventory location>;<list name>;<X>,<Y>;<W>,<H>;]
list[<inventory location>;<list name>;<X>,<Y>;<W>,<H>;<starting item index>]
^ Show an inventory list
image[<X>,<Y>;<W>,<H>;<texture name>]
@@ -726,10 +727,12 @@ image_button_exit[<X>,<Y>;<W>,<H>;<texture name>;<name>;<label>]
^ When clicked, fields will be sent and the form will quit.
Inventory location:
- "context": Selected node metadata (deprecated: "current_name")
- "current_player": Player to whom the menu is shown
- "player:<name>": Any player
- "nodemeta:<X>,<Y>,<Z>": Any node metadata
- "detached:<name>": A detached inventory
Helper functions
-----------------
@@ -774,11 +777,11 @@ minetest.register_craft(recipe)
Global callback registration functions: (Call these only at load time)
minetest.register_globalstep(func(dtime))
^ Called every server step, usually interval of 0.05s
minetest.register_on_placenode(func(pos, newnode, placer))
minetest.register_on_placenode(func(pos, newnode, placer, oldnode))
^ Called when a node has been placed
^ Deprecated: Use on_construct or after_place_node in node definition instead
minetest.register_on_dignode(func(pos, oldnode, digger))
^ Called when a node has been dug. digger can be nil.
^ Called when a node has been dug.
^ Deprecated: Use on_destruct or after_dig_node in node definition instead
minetest.register_on_punchnode(func(pos, node, puncher))
^ Called when a node is punched
@@ -847,6 +850,10 @@ Inventory:
minetest.get_inventory(location) -> InvRef
^ location = eg. {type="player", name="celeron55"}
{type="node", pos={x=, y=, z=}}
{type="detached", name="creative"}
minetest.create_detached_inventory(name, callbacks) -> InvRef
^ callbacks: See "Detached inventory callbacks"
^ Creates a detached inventory. If it already exists, it is cleared.
Item handling:
minetest.inventorycube(img1, img2, img3)
@@ -1280,30 +1287,29 @@ Node definition (register_node)
drawtype = "normal", -- See "Node drawtypes"
visual_scale = 1.0,
tiles = {tile definition 1, def2, def3, def4, def5, def6},
^ Textures of node; +Y, -Y, +X, -X, +Z, -Z (old field name: tile_images)
^ List can be shortened to needed length
^ Old field name: tile_images
special_tiles = {tile definition 1, Tile definition 2},
^ Special textures of node; used rarely (old field name: special_materials)
^ List can be shortened to needed length
^ Old field name: special_materials
alpha = 255,
post_effect_color = {a=0, r=0, g=0, b=0},
paramtype = "none",
paramtype2 = "none",
is_ground_content = false,
sunlight_propagates = false,
walkable = true,
pointable = true,
diggable = true,
climbable = false,
buildable_to = false,
drop = "",
-- alternatively drop = { max_items = ..., items = { ... } }
liquidtype = "none",
liquid_alternative_flowing = "",
liquid_alternative_source = "",
liquid_viscosity = 0,
light_source = 0,
damage_per_second = 0,
post_effect_color = {a=0, r=0, g=0, b=0}, -- If player is inside node
paramtype = "none", -- See "Nodes"
paramtype2 = "none", -- See "Nodes"
is_ground_content = false, -- Currently not used for anything
sunlight_propagates = false, -- If true, sunlight will go infinitely through this
walkable = true, -- If true, objects collide with node
pointable = true, -- If true, can be pointed at
diggable = true, -- If false, can never be dug
climbable = false, -- If true, can be climbed on (ladder)
buildable_to = false, -- If true, placed nodes can replace this node
drop = "", -- alternatively drop = { max_items = ..., items = { ... } }
liquidtype = "none", -- "none"/"source"/"flowing"
liquid_alternative_flowing = "", -- Flowing version of source liquid
liquid_alternative_source = "", -- Source version of flowing liquid
liquid_viscosity = 0, -- Higher viscosity = slower flow (max. 7)
light_source = 0, -- Amount of light emitted by node
damage_per_second = 0, -- If player is inside node, this damage is caused
node_box = {type="regular"}, -- See "Node boxes"
selection_box = {type="regular"}, -- See "Node boxes"
legacy_facedir_simple = false, -- Support maps made in and before January 2012
@@ -1356,35 +1362,27 @@ Node definition (register_node)
^ Called when an UI form (eg. sign text input) returns data
^ 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
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
^ Return value: -1: Allow and don't modify item count in inventory
allow_metadata_inventory_take = func(pos, listname, index, stack, player),
^ Called when a player wants to take something out of the inventory
^ Return value: number of items allowed to take
^ Return value: -1: Allow and don't modify item count in inventory
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
on_metadata_inventory_move = func(pos, from_list, from_index,
to_list, to_index, count, player),
on_metadata_inventory_put = func(pos, listname, index, stack, player),
on_metadata_inventory_take = func(pos, listname, index, stack, player),
^ Called after the actual action has happened, according to what was allowed.
^ No return value
}
Recipe for register_craft: (shaped)
@@ -1441,3 +1439,26 @@ Chatcommand definition (register_chatcommand)
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
^ Return value: -1: Allow and don't modify item count in inventory
allow_take = func(inv, listname, index, stack, player),
^ Called when a player wants to take something out of the inventory
^ Return value: number of items allowed to take
^ Return value: -1: Allow and don't modify item count in inventory
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, stack, player),
^ Called after the actual action has happened, according to what was allowed.
^ No return value
}

View File

@@ -1,11 +1,12 @@
=============================
Minetest World Format 22...23
Minetest World Format 22...25
=============================
This applies to a world format carrying the block serialization version
22...23, used at least in
- 0.4.dev-20120322 ... 0.4.dev-20120606
- 0.4.0.
22...25, used at least in
- 0.4.dev-20120322 ... 0.4.dev-20120606 (22...23)
- 0.4.0 (23)
- 24 was never released as stable and existed for ~2 days
The block serialization version does not fully specify every aspect of this
format; if compliance with this format is to be checked, it needs to be
@@ -262,17 +263,26 @@ u8 flags
u8 content_width
- Number of bytes in the content (param0) fields of nodes
- Always 1
if map format version <= 23:
- Always 1
if map format version >= 24:
- Always 2
u8 params_width
- Number of bytes used for parameters per node
- Always 2
zlib-compressed node data:
- content:
u8[4096]: param0 fields
u8[4096]: param1 fields
u8[4096]: param2 fields
if content_width == 1:
- content:
u8[4096]: param0 fields
u8[4096]: param1 fields
u8[4096]: param2 fields
if content_width == 2:
- content:
u16[4096]: param0 fields
u8[4096]: param1 fields
u8[4096]: param2 fields
- The location of a node in each of those arrays is (z*16*16 + y*16 + x).
zlib-compressed node metadata list
@@ -285,9 +295,19 @@ zlib-compressed node metadata list
u16 content_size
u8[content_size] (content of metadata)
- unused node timers (version will be 24 when they are actually used):
if version == 23:
- Node timers
if map format version == 23:
u8 unused version (always 0)
if map format version == 24: (NOTE: Not released as stable)
u8 nodetimer_version
if nodetimer_version == 0:
(nothing else)
if nodetimer_version == 1:
u16 num_of_timers
foreach num_of_timers:
u16 timer position (z*16*16 + y*16 + x)
s32 timeout*1000
s32 elapsed*1000
u8 static object version:
- Always 0
@@ -317,17 +337,29 @@ foreach num_name_id_mappings
u16 name_len
u8[name_len] name
- Node timers
if map format version == 25:
u8 length of the data of a single timer (always 2+4+4=10)
u16 num_of_timers
foreach num_of_timers:
u16 timer position (z*16*16 + y*16 + x)
s32 timeout*1000
s32 elapsed*1000
EOF.
Format of nodes
----------------
A node is composed of the u8 fields param0, param1 and param2.
The content id of a node is determined as so:
- If param0 < 0x80,
content_id = param0
- Otherwise
content_id = (param0<<4) + (param2>>4)
if map format version <= 23:
The content id of a node is determined as so:
- If param0 < 0x80,
content_id = param0
- Otherwise
content_id = (param0<<4) + (param2>>4)
if map format version >= 24:
The content id of a node is param0.
The purpose of param1 and param2 depend on the definition of the node.

View File

@@ -14,6 +14,14 @@ default = {}
-- Load other files
dofile(minetest.get_modpath("default").."/mapgen.lua")
-- Set a noticeable inventory formspec for players
minetest.register_on_joinplayer(function(player)
local cb = function(player)
minetest.chat_send_player(player:get_player_name(), "This is the [minimal] \"Minimal Development Test\" game. Use [minetest_game] for the real thing.")
end
minetest.after(2.0, cb, player)
end)
--
-- Tool definition
--
@@ -1150,7 +1158,7 @@ minetest.register_node("default:chest", {
on_construct = function(pos)
local meta = minetest.env:get_meta(pos)
meta:set_string("formspec",
"invsize[8,9;]"..
"size[8,9]"..
"list[current_name;main;0,0;8,4;]"..
"list[current_player;main;0,5;8,4;]")
meta:set_string("infotext", "Chest")
@@ -1162,25 +1170,6 @@ minetest.register_node("default:chest", {
local inv = meta:get_inventory()
return inv:is_empty("main")
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)
@@ -1207,7 +1196,7 @@ minetest.register_node("default:chest_locked", {
on_construct = function(pos)
local meta = minetest.env:get_meta(pos)
meta:set_string("formspec",
"invsize[8,9;]"..
"size[8,9]"..
"list[current_name;main;0,0;8,4;]"..
"list[current_player;main;0,5;8,4;]")
meta:set_string("infotext", "Locked Chest")
@@ -1220,53 +1209,55 @@ minetest.register_node("default:chest_locked", {
local inv = meta:get_inventory()
return inv:is_empty("main")
end,
on_metadata_inventory_move = function(pos, from_list, from_index,
to_list, to_index, count, player)
allow_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_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
return 0
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, 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,
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 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,
on_metadata_inventory_offer = 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
on_metadata_inventory_put = function(pos, listname, index, stack, player)
minetest.log("action", player:get_player_name()..
" 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,
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
on_metadata_inventory_take = function(pos, listname, index, stack, player)
minetest.log("action", player:get_player_name()..
" 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,
})
default.furnace_inactive_formspec =
"invsize[8,9;]"..
"size[8,9]"..
"image[2,2;1,1;default_furnace_fire_bg.png]"..
"list[current_name;fuel;2,3;1,1;]"..
"list[current_name;src;2,1;1,1;]"..
@@ -1405,7 +1396,7 @@ minetest.register_abm({
meta:set_string("infotext","Furnace active: "..percent.."%")
hacky_swap_node(pos,"default:furnace_active")
meta:set_string("formspec",
"invsize[8,9;]"..
"size[8,9]"..
"image[2,2;1,1;default_furnace_fire_bg.png^[lowpart:"..
(100-percent)..":default_furnace_fire_fg.png]"..
"list[current_name;fuel;2,3;1,1;]"..
@@ -1572,40 +1563,6 @@ minetest.register_craftitem("default:scorched_stuff", {
inventory_image = "default_scorched_stuff.png",
})
--
-- Creative inventory
--
minetest.add_to_creative_inventory('default:pick_mese')
minetest.add_to_creative_inventory('default:pick_steel')
minetest.add_to_creative_inventory('default:axe_steel')
minetest.add_to_creative_inventory('default:shovel_steel')
minetest.add_to_creative_inventory('default:torch')
minetest.add_to_creative_inventory('default:cobble')
minetest.add_to_creative_inventory('default:dirt')
minetest.add_to_creative_inventory('default:stone')
minetest.add_to_creative_inventory('default:sand')
minetest.add_to_creative_inventory('default:sandstone')
minetest.add_to_creative_inventory('default:clay')
minetest.add_to_creative_inventory('default:brick')
minetest.add_to_creative_inventory('default:tree')
minetest.add_to_creative_inventory('default:wood')
minetest.add_to_creative_inventory('default:leaves')
minetest.add_to_creative_inventory('default:cactus')
minetest.add_to_creative_inventory('default:papyrus')
minetest.add_to_creative_inventory('default:bookshelf')
minetest.add_to_creative_inventory('default:glass')
minetest.add_to_creative_inventory('default:fence_wood')
minetest.add_to_creative_inventory('default:rail')
minetest.add_to_creative_inventory('default:mese')
minetest.add_to_creative_inventory('default:chest')
minetest.add_to_creative_inventory('default:furnace')
minetest.add_to_creative_inventory('default:sign_wall')
minetest.add_to_creative_inventory('default:water_source')
minetest.add_to_creative_inventory('default:lava_source')
minetest.add_to_creative_inventory('default:ladder')
--
-- Aliases for the current map generator outputs
--

View File

@@ -443,7 +443,7 @@ minetest.register_abm({
})--]]
minetest.register_node("experimental:tester_node_1", {
description = "Tester Node 1",
description = "Tester Node 1 (construct/destruct/timer)",
tile_images = {"wieldhand.png"},
groups = {oddly_breakable_by_hand=2},
sounds = default.node_sound_wood_defaults(),
@@ -455,6 +455,8 @@ minetest.register_node("experimental:tester_node_1", {
experimental.print_to_everything("experimental:tester_node_1:on_construct("..minetest.pos_to_string(pos)..")")
local meta = minetest.env:get_meta(pos)
meta:set_string("mine", "test")
local timer = minetest.env:get_node_timer(pos)
timer:start(4, 3)
end,
after_place_node = function(pos, placer)
@@ -478,6 +480,11 @@ minetest.register_node("experimental:tester_node_1", {
after_dig_node = function(pos, oldnode, oldmetadata, digger)
experimental.print_to_everything("experimental:tester_node_1:after_dig_node("..minetest.pos_to_string(pos)..")")
end,
on_timer = function(pos, elapsed)
experimental.print_to_everything("on_timer(): elapsed="..dump(elapsed))
return true
end,
})
minetest.register_craftitem("experimental:tester_tool_1", {
@@ -509,7 +516,7 @@ minetest.register_craft({
--[[minetest.register_on_joinplayer(function(player)
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]"..
"list[current_player;main;0,3.5;8,4;]"..
"list[current_player;craft;3,0;3,3;]"..
@@ -517,6 +524,34 @@ minetest.register_craft({
end)
end)]]
-- Create a detached 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, stack, 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, stack, player)
experimental.print_to_everything(player:get_player_name().." took items")
end,
})
inv:set_size("main", 4*6)
inv:add_item("main", "experimental:tester_tool_1")
inv:add_item("main", "experimental:tnt 5")
minetest.register_chatcommand("test1", {
params = "",
description = "Test 1: Modify player's inventory view",
@@ -531,6 +566,7 @@ minetest.register_chatcommand("test1", {
"list[current_player;main;5,3.5;8,4;]"..
"list[current_player;craft;8,0;3,3;]"..
"list[current_player;craftpreview;12,1;1,1;]"..
"list[detached:test_inventory;main;0,0;4,6;0]"..
"button[0.5,7;2,1;button1;Button 1]"..
"button_exit[2.5,7;2,1;button2;Exit Button]"
)

View File

@@ -304,6 +304,15 @@ Client::~Client()
sleep_ms(100);
delete m_inventory_from_server;
// Delete detached inventories
{
for(std::map<std::string, Inventory*>::iterator
i = m_detached_inventories.begin();
i != m_detached_inventories.end(); i++){
delete i->second;
}
}
}
void Client::connect(Address address)
@@ -1698,6 +1707,24 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
assert(player != NULL);
player->inventory_formspec = deSerializeLongString(is);
}
else if(command == TOCLIENT_DETACHED_INVENTORY)
{
std::string datastring((char*)&data[2], datasize-2);
std::istringstream is(datastring, std::ios_base::binary);
std::string name = deSerializeString(is);
infostream<<"Client: Detached inventory update: \""<<name<<"\""<<std::endl;
Inventory *inv = NULL;
if(m_detached_inventories.count(name) > 0)
inv = m_detached_inventories[name];
else{
inv = new Inventory(m_itemdef);
m_detached_inventories[name] = inv;
}
inv->deSerialize(is);
}
else
{
infostream<<"Client: Ignoring unknown command "
@@ -2090,6 +2117,13 @@ Inventory* Client::getInventory(const InventoryLocation &loc)
return meta->getInventory();
}
break;
case InventoryLocation::DETACHED:
{
if(m_detached_inventories.count(loc.name) == 0)
return NULL;
return m_detached_inventories[loc.name];
}
break;
default:
assert(0);
}

View File

@@ -393,6 +393,10 @@ private:
// Privileges
std::set<std::string> m_privileges;
// Detached inventories
// key = name
std::map<std::string, Inventory*> m_detached_inventories;
};
#endif // !CLIENT_HEADER

View File

@@ -64,6 +64,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
PROTOCOL_VERSION 12:
TOSERVER_INVENTORY_FIELDS
16-bit node ids
TOCLIENT_DETACHED_INVENTORY
*/
#define PROTOCOL_VERSION 12
@@ -321,6 +322,14 @@ enum ToClientCommand
u32 len
u8[len] formspec
*/
TOCLIENT_DETACHED_INVENTORY = 0x43,
/*
[0] u16 command
u16 len
u8[len] name
[2] serialized inventory
*/
};
enum ToServerCommand

View File

@@ -292,13 +292,6 @@ public:
ServerActiveObject *puncher,
float time_from_last_punch)
{
// Directly delete item in creative mode
if(g_settings->getBool("creative_mode") == true)
{
m_removed = true;
return 0;
}
// Take item into inventory
ItemStack item = createItemStack();
Inventory *inv = puncher->getInventory();
@@ -1143,16 +1136,6 @@ void PlayerSAO::disconnected()
}
}
void PlayerSAO::createCreativeInventory()
{
if(m_inventory != &m_player->inventory)
delete m_inventory;
m_inventory = new Inventory(m_player->inventory);
m_inventory->clearContents();
scriptapi_get_creative_inventory(m_env->getLua(), this);
}
std::string PlayerSAO::getPropertyPacket()
{
m_prop.is_visible = (getHP() != 0);

View File

@@ -163,8 +163,6 @@ public:
void disconnected();
void createCreativeInventory();
Player* getPlayer()
{
return m_player;

View File

@@ -2304,6 +2304,13 @@ void the_game(
<<playeritem.name<<" is "
<<def.node_placement_prediction<<std::endl;
v3s16 p = neighbourpos;
// Place inside node itself if buildable_to
try{
MapNode n_under = map.getNode(nodepos);
if(nodedef->get(n_under).buildable_to)
p = nodepos;
}catch(InvalidPositionException &e){}
// Find id of predicted node
content_t id;
bool found =
nodedef->getId(def.node_placement_prediction, id);

View File

@@ -215,10 +215,9 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
}
else{
invsize.Y = stof(f.next(";"));
errorstream<<"WARNING: invsize is deprecated, use size"<<std::endl;
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);
spacing = v2s32(screensize.Y/12, screensize.Y/13);
@@ -257,10 +256,13 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
<<", pos=("<<pos.X<<","<<pos.Y<<")"
<<", geom=("<<geom.X<<","<<geom.Y<<")"
<<std::endl;
f.next("]");
std::string start_i_s = f.next("]");
s32 start_i = 0;
if(start_i_s != "")
start_i = stoi(start_i_s);
if(bp_set != 2)
errorstream<<"WARNING: invalid use of button without a size[] element"<<std::endl;
m_inventorylists.push_back(ListDrawSpec(loc, listname, pos, geom));
errorstream<<"WARNING: invalid use of list without a size[] element"<<std::endl;
m_inventorylists.push_back(ListDrawSpec(loc, listname, pos, geom, start_i));
}
else if(type == "image")
{
@@ -380,9 +382,9 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
}
else if(type == "label")
{
v2s32 pos;
pos.X = stof(f.next(",")) * (float)spacing.X;
pos.Y = stof(f.next(";")) * (float)spacing.Y;
v2s32 pos = padding;
pos.X += stof(f.next(",")) * (float)spacing.X;
pos.Y += stof(f.next(";")) * (float)spacing.Y;
rect = core::rect<s32>(pos.X, pos.Y+((imgsize.Y/2)-15), pos.X+300, pos.Y+((imgsize.Y/2)+15));
@@ -401,9 +403,9 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
}
else if(type == "button" || type == "button_exit")
{
v2s32 pos;
pos.X = stof(f.next(",")) * (float)spacing.X;
pos.Y = stof(f.next(";")) * (float)spacing.Y;
v2s32 pos = padding;
pos.X += stof(f.next(",")) * (float)spacing.X;
pos.Y += stof(f.next(";")) * (float)spacing.Y;
v2s32 geom;
geom.X = (stof(f.next(",")) * (float)spacing.X)-(spacing.X-imgsize.X);
pos.Y += (stof(f.next(";")) * (float)imgsize.Y)/2;
@@ -429,9 +431,9 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
}
else if(type == "image_button" || type == "image_button_exit")
{
v2s32 pos;
pos.X = stof(f.next(",")) * (float)spacing.X;
pos.Y = stof(f.next(";")) * (float)spacing.Y;
v2s32 pos = padding;
pos.X += stof(f.next(",")) * (float)spacing.X;
pos.Y += stof(f.next(";")) * (float)spacing.Y;
v2s32 geom;
geom.X = (stof(f.next(",")) * (float)spacing.X)-(spacing.X-imgsize.X);
geom.Y = (stof(f.next(";")) * (float)spacing.Y)-(spacing.Y-imgsize.Y);
@@ -531,13 +533,14 @@ GUIFormSpecMenu::ItemSpec GUIFormSpecMenu::getItemAtPos(v2s32 p) const
for(s32 i=0; i<s.geom.X*s.geom.Y; i++)
{
s32 item_i = i + s.start_item_i;
s32 x = (i%s.geom.X) * spacing.X;
s32 y = (i/s.geom.X) * spacing.Y;
v2s32 p0(x,y);
core::rect<s32> rect = imgrect + s.pos + p0;
if(rect.isPointInside(p))
{
return ItemSpec(s.inventoryloc, s.listname, i);
return ItemSpec(s.inventoryloc, s.listname, item_i);
}
}
}
@@ -576,13 +579,16 @@ void GUIFormSpecMenu::drawList(const ListDrawSpec &s, int phase)
for(s32 i=0; i<s.geom.X*s.geom.Y; i++)
{
u32 item_i = i + s.start_item_i;
if(item_i >= ilist->getSize())
break;
s32 x = (i%s.geom.X) * spacing.X;
s32 y = (i/s.geom.X) * spacing.Y;
v2s32 p(x,y);
core::rect<s32> rect = imgrect + s.pos + p;
ItemStack item;
if(ilist)
item = ilist->getItem(i);
item = ilist->getItem(item_i);
bool selected = m_selected_item
&& m_invmgr->getInventory(m_selected_item->inventoryloc) == inv
@@ -884,14 +890,14 @@ bool GUIFormSpecMenu::OnEvent(const SEvent& event)
InventoryList *list = inv_s->getList(s.listname);
if(list == NULL){
errorstream<<"InventoryMenu: The selected inventory list \""
verbosestream<<"InventoryMenu: The selected inventory list \""
<<s.listname<<"\" does not exist"<<std::endl;
s.i = -1; // make it invalid again
break;
}
if((u32)s.i >= list->getSize()){
errorstream<<"InventoryMenu: The selected inventory list \""
infostream<<"InventoryMenu: The selected inventory list \""
<<s.listname<<"\" is too small (i="<<s.i<<", size="
<<list->getSize()<<")"<<std::endl;
s.i = -1; // make it invalid again
@@ -1160,6 +1166,8 @@ bool GUIFormSpecMenu::OnEvent(const SEvent& event)
return true;
}else{
s.send = false;
// Restore focus to the full form
Environment->setFocus(this);
return true;
}
}

View File

@@ -86,11 +86,12 @@ class GUIFormSpecMenu : public GUIModalMenu
}
ListDrawSpec(const InventoryLocation &a_inventoryloc,
const std::string &a_listname,
v2s32 a_pos, v2s32 a_geom):
v2s32 a_pos, v2s32 a_geom, s32 a_start_item_i):
inventoryloc(a_inventoryloc),
listname(a_listname),
pos(a_pos),
geom(a_geom)
geom(a_geom),
start_item_i(a_start_item_i)
{
}
@@ -98,6 +99,7 @@ class GUIFormSpecMenu : public GUIModalMenu
std::string listname;
v2s32 pos;
v2s32 geom;
s32 start_item_i;
};
struct ImageDrawSpec

View File

@@ -41,30 +41,25 @@ std::string InventoryLocation::dump() const
void InventoryLocation::serialize(std::ostream &os) const
{
switch(type){
case InventoryLocation::UNDEFINED:
{
switch(type){
case InventoryLocation::UNDEFINED:
os<<"undefined";
}
break;
case InventoryLocation::CURRENT_PLAYER:
{
break;
case InventoryLocation::CURRENT_PLAYER:
os<<"current_player";
}
break;
case InventoryLocation::PLAYER:
{
break;
case InventoryLocation::PLAYER:
os<<"player:"<<name;
}
break;
case InventoryLocation::NODEMETA:
{
break;
case InventoryLocation::NODEMETA:
os<<"nodemeta:"<<p.X<<","<<p.Y<<","<<p.Z;
}
break;
default:
assert(0);
}
break;
case InventoryLocation::DETACHED:
os<<"detached:"<<name;
break;
default:
assert(0);
}
}
void InventoryLocation::deSerialize(std::istream &is)
@@ -94,6 +89,11 @@ void InventoryLocation::deSerialize(std::istream &is)
p.Y = stoi(fn.next(","));
p.Z = stoi(fn.next(","));
}
else if(tname == "detached")
{
type = InventoryLocation::DETACHED;
std::getline(is, name, '\n');
}
else
{
infostream<<"Unknown InventoryLocation type=\""<<tname<<"\""<<std::endl;
@@ -198,78 +198,106 @@ void IMoveAction::apply(InventoryManager *mgr, ServerActiveObject *player, IGame
<<", to_list=\""<<to_list<<"\""<<std::endl;
return;
}
/*
Collect information of endpoints
*/
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;
// Handle node metadata move
if(from_inv.type == InventoryLocation::NODEMETA &&
to_inv.type == InventoryLocation::NODEMETA &&
from_inv.p != to_inv.p)
/* 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 "
<<"disallowed."<<std::endl;
return;
lua_State *L = player->getEnv()->getLua();
src_can_take_count = scriptapi_detached_inventory_allow_move(
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();
ItemStack src_item = list_from->getItem(from_i);
src_item.count = try_take_count;
src_can_take_count = scriptapi_detached_inventory_allow_take(
L, from_inv.name, from_list, from_i, src_item, 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 &&
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);
src_can_take_count = scriptapi_nodemeta_inventory_allow_move(
L, from_inv.p, from_list, from_i,
to_list, to_i, try_take_count, player);
dst_can_put_count = src_can_take_count;
}
// 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
// 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();
ItemStack src_item = list_from->getItem(from_i);
src_item.count = try_take_count;
src_can_take_count = scriptapi_nodemeta_inventory_allow_take(
L, from_inv.p, from_list, from_i, src_item, player);
}
}
If something is wrong (source item is empty, destination is the
same as source), nothing happens
*/
list_from->moveItem(from_i, list_to, to_i, count);
infostream<<"IMoveAction::apply(): moved "
<<" count="<<count
int old_count = count;
/* Modify count according to collected data */
count = try_take_count;
if(src_can_take_count != -1 && count > src_can_take_count)
count = src_can_take_count;
if(dst_can_put_count != -1 && count > dst_can_put_count)
count = dst_can_put_count;
/* Limit according to source item count */
if(count > list_from->getItem(from_i).count)
count = list_from->getItem(from_i).count;
/* If no items will be moved, don't go further */
if(count == 0)
{
infostream<<"IMoveAction::apply(): move was completely disallowed:"
<<" count="<<old_count
<<" from inv=\""<<from_inv.dump()<<"\""
<<" list=\""<<from_list<<"\""
<<" i="<<from_i
@@ -277,6 +305,105 @@ void IMoveAction::apply(InventoryManager *mgr, ServerActiveObject *player, IGame
<<" list=\""<<to_list<<"\""
<<" i="<<to_i
<<std::endl;
return;
}
ItemStack src_item = list_from->getItem(from_i);
src_item.count = count;
ItemStack from_stack_was = list_from->getItem(from_i);
ItemStack to_stack_was = list_to->getItem(to_i);
/*
Perform actual move
If something is wrong (source item is empty, destination is the
same as source), nothing happens
*/
list_from->moveItem(from_i, list_to, to_i, count);
// If source is infinite, reset it's stack
if(src_can_take_count == -1){
list_from->deleteItem(from_i);
list_from->addItem(from_i, from_stack_was);
}
// If destination is infinite, reset it's stack and take count from source
if(dst_can_put_count == -1){
list_to->deleteItem(to_i);
list_to->addItem(to_i, to_stack_was);
list_from->takeItem(from_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;
/*
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();
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();
scriptapi_detached_inventory_on_take(
L, from_inv.name, from_list, from_i, src_item, 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();
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();
scriptapi_nodemeta_inventory_on_take(
L, from_inv.p, from_list, from_i, src_item, player);
}
}
mgr->setInventoryModified(from_inv);
@@ -361,47 +488,64 @@ void IDropAction::apply(InventoryManager *mgr, ServerActiveObject *player, IGame
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();
ItemStack src_item = list_from->getItem(from_i);
src_item.count = take_count;
src_can_take_count = scriptapi_detached_inventory_allow_take(
L, from_inv.name, from_list, from_i, src_item, player);
}
// Source is nodemeta
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()<<" 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);
ItemStack src_item = list_from->getItem(from_i);
src_item.count = take_count;
src_can_take_count = scriptapi_nodemeta_inventory_allow_take(
L, from_inv.p, from_list, from_i, src_item, player);
}
// Drop the item and apply the returned ItemStack
ItemStack item2 = item1;
if(scriptapi_item_on_drop(player->getEnv()->getLua(), item2, player,
if(src_can_take_count != -1 && src_can_take_count < take_count)
take_count = src_can_take_count;
int actually_dropped_count = 0;
ItemStack src_item = list_from->getItem(from_i);
// 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)))
{
if(g_settings->getBool("creative_mode") == true
&& from_inv.type == InventoryLocation::PLAYER)
item2 = item1; // creative mode
actually_dropped_count = take_count - item1.count;
list_from->addItem(from_i, item2);
if(actually_dropped_count == 0){
infostream<<"Actually dropped no items"<<std::endl;
return;
}
// If source isn't infinite
if(src_can_take_count != -1){
// Take item from source list
ItemStack item2 = list_from->takeItem(from_i, actually_dropped_count);
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);
}
}
infostream<<"IDropAction::apply(): dropped "
@@ -409,6 +553,28 @@ void IDropAction::apply(InventoryManager *mgr, ServerActiveObject *player, IGame
<<" list=\""<<from_list<<"\""
<<" i="<<from_i
<<std::endl;
src_item.count = actually_dropped_count;
/*
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, src_item, 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, src_item, player);
}
}
void IDropAction::clientApply(InventoryManager *mgr, IGameDef *gamedef)

View File

@@ -32,9 +32,10 @@ struct InventoryLocation
CURRENT_PLAYER,
PLAYER,
NODEMETA,
DETACHED,
} type;
std::string name; // PLAYER
std::string name; // PLAYER, DETACHED
v3s16 p; // NODEMETA
InventoryLocation()
@@ -59,6 +60,11 @@ struct InventoryLocation
type = NODEMETA;
p = p_;
}
void setDetached(const std::string &name_)
{
type = DETACHED;
name = name_;
}
void applyCurrentPlayer(const std::string &name_)
{
@@ -80,13 +86,11 @@ public:
InventoryManager(){}
virtual ~InventoryManager(){}
// Get an inventory or set it modified (so it will be updated over
// network or so)
// Get an inventory (server and client)
virtual Inventory* getInventory(const InventoryLocation &loc){return NULL;}
virtual std::string getInventoryOwner(const InventoryLocation &loc){return "";}
// Set modified (will be saved and sent over network; only on server)
virtual void setInventoryModified(const InventoryLocation &loc){}
// Used on the client to send an action to the server
// Send inventory action to server (only on client)
virtual void inventoryAction(InventoryAction *a){}
};

View File

@@ -612,8 +612,10 @@ void MapBlock::serialize(std::ostream &os, u8 version, bool disk)
*/
if(disk)
{
// Node timers
m_node_timers.serialize(os);
if(version <= 24){
// Node timers
m_node_timers.serialize(os, version);
}
// Static objects
m_static_objects.serialize(os);
@@ -623,6 +625,11 @@ void MapBlock::serialize(std::ostream &os, u8 version, bool disk)
// Write block-specific node definition id mapping
nimap.serialize(os);
if(version >= 25){
// Node timers
m_node_timers.serialize(os, version);
}
}
}
@@ -696,10 +703,10 @@ void MapBlock::deSerialize(std::istream &is, u8 version, bool disk)
// Read unused zero
readU8(is);
}
else if(version >= 24){
if(version == 24){
TRACESTREAM(<<"MapBlock::deSerialize "<<PP(getPos())
<<": Node timers"<<std::endl);
m_node_timers.deSerialize(is);
<<": Node timers (ver==24)"<<std::endl);
m_node_timers.deSerialize(is, version);
}
// Static objects
@@ -719,6 +726,12 @@ void MapBlock::deSerialize(std::istream &is, u8 version, bool disk)
NameIdMapping nimap;
nimap.deSerialize(is);
correctBlockNodeIds(&nimap, data, m_gamedef);
if(version >= 25){
TRACESTREAM(<<"MapBlock::deSerialize "<<PP(getPos())
<<": Node timers (ver>=25)"<<std::endl);
m_node_timers.deSerialize(is, version);
}
}
TRACESTREAM(<<"MapBlock::deSerialize "<<PP(getPos())

View File

@@ -234,8 +234,10 @@ u32 MapNode::serializedLength(u8 version)
return 1;
else if(version <= 9)
return 2;
else
else if(version <= 23)
return 3;
else
return 4;
}
void MapNode::serialize(u8 *dest, u8 version)
{

View File

@@ -42,19 +42,22 @@ void NodeTimer::deSerialize(std::istream &is)
NodeTimerList
*/
void NodeTimerList::serialize(std::ostream &os) const
void NodeTimerList::serialize(std::ostream &os, u8 map_format_version) const
{
/*
Version 0 is a placeholder for "nothing to see here; go away."
*/
if(m_data.size() == 0){
writeU8(os, 0); // version
return;
if(map_format_version == 24){
// Version 0 is a placeholder for "nothing to see here; go away."
if(m_data.size() == 0){
writeU8(os, 0); // version
return;
}
writeU8(os, 1); // version
writeU16(os, m_data.size());
}
writeU8(os, 1); // version
writeU16(os, m_data.size());
if(map_format_version >= 25){
writeU8(os, 2+4+4);
writeU16(os, m_data.size());
}
for(std::map<v3s16, NodeTimer>::const_iterator
i = m_data.begin();
@@ -68,15 +71,23 @@ void NodeTimerList::serialize(std::ostream &os) const
}
}
void NodeTimerList::deSerialize(std::istream &is)
void NodeTimerList::deSerialize(std::istream &is, u8 map_format_version)
{
m_data.clear();
if(map_format_version == 24){
u8 timer_version = readU8(is);
if(timer_version == 0)
return;
if(timer_version != 1)
throw SerializationError("unsupported NodeTimerList version");
}
u8 version = readU8(is);
if(version == 0)
return;
if(version != 1)
throw SerializationError("unsupported NodeTimerList version");
if(map_format_version >= 25){
u8 timer_data_len = readU8(is);
if(timer_data_len != 2+4+4)
throw SerializationError("unsupported NodeTimer data length");
}
u16 count = readU16(is);

View File

@@ -57,8 +57,8 @@ public:
NodeTimerList() {}
~NodeTimerList() {}
void serialize(std::ostream &os) const;
void deSerialize(std::istream &is);
void serialize(std::ostream &os, u8 map_format_version) const;
void deSerialize(std::istream &is, u8 map_format_version);
// Get timer
NodeTimer get(v3s16 p){

View File

@@ -150,7 +150,6 @@ public:
u8 light;
// In creative mode, this is the invisible backup inventory
Inventory inventory;
u16 hp;

View File

@@ -4567,6 +4567,9 @@ static int l_get_inventory(lua_State *L)
lua_getfield(L, 1, "pos");
v3s16 pos = check_v3s16(L, -1);
loc.setNodeMeta(pos);
} else if(type == "detached"){
std::string name = checkstringfield(L, 1, "name");
loc.setDetached(name);
}
if(get_server(L)->getInventory(loc) != NULL)
@@ -4576,6 +4579,20 @@ static int l_get_inventory(lua_State *L)
return 1;
}
// create_detached_inventory_raw(name)
static int l_create_detached_inventory_raw(lua_State *L)
{
const char *name = luaL_checkstring(L, 1);
if(get_server(L)->createDetachedInventory(name) != NULL){
InventoryLocation loc;
loc.setDetached(name);
InvRef::create(L, loc);
}else{
lua_pushnil(L);
}
return 1;
}
// get_dig_params(groups, tool_capabilities[, time_from_last_punch])
static int l_get_dig_params(lua_State *L)
{
@@ -4849,6 +4866,7 @@ static const struct luaL_Reg minetest_f [] = {
{"chat_send_player", l_chat_send_player},
{"get_player_privs", l_get_player_privs},
{"get_inventory", l_get_inventory},
{"create_detached_inventory_raw", l_create_detached_inventory_raw},
{"get_dig_params", l_get_dig_params},
{"get_hit_params", l_get_hit_params},
{"get_current_modname", l_get_current_modname},
@@ -5308,21 +5326,6 @@ void scriptapi_on_leaveplayer(lua_State *L, ServerActiveObject *player)
scriptapi_run_callbacks(L, 1, RUN_CALLBACKS_MODE_FIRST);
}
void scriptapi_get_creative_inventory(lua_State *L, ServerActiveObject *player)
{
realitycheck(L);
assert(lua_checkstack(L, 20));
StackUnroller stack_unroller(L);
Inventory *inv = player->getInventory();
assert(inv);
lua_getglobal(L, "minetest");
lua_getfield(L, -1, "creative_inventory");
luaL_checktype(L, -1, LUA_TTABLE);
inventory_set_list_from_lua(inv, "main", L, -1, PLAYER_INVENTORY_SIZE);
}
static void get_auth_handler(lua_State *L)
{
lua_getglobal(L, "minetest");
@@ -5716,7 +5719,134 @@ void scriptapi_node_on_receive_fields(lua_State *L, v3s16 p,
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));
if(!lua_isnumber(L, -1))
throw LuaError(L, "allow_metadata_inventory_move should return a number");
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));
if(!lua_isnumber(L, -1))
throw LuaError(L, "allow_metadata_inventory_put should return a number");
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, 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_take"))
return stack.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);
// 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));
if(!lua_isnumber(L, -1))
throw LuaError(L, "allow_metadata_inventory_take should return a number");
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 &to_list, int to_index,
int count, ServerActiveObject *player)
@@ -5738,18 +5868,26 @@ void scriptapi_node_on_metadata_inventory_move(lua_State *L, v3s16 p,
return;
// 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, 0, 0))
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,
ServerActiveObject *player)
{
@@ -5762,26 +5900,31 @@ 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
MapNode node = get_env(L)->getMap().getNodeNoEx(p);
if(node.getContent() == CONTENT_IGNORE)
return stack;
return;
// Push callback function on stack
if(!get_item_callback(L, ndef->get(node).name.c_str(),
"on_metadata_inventory_offer"))
return stack;
"on_metadata_inventory_put"))
return;
// 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))
if(lua_pcall(L, 5, 0, 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,
// Report taken items
void scriptapi_nodemeta_inventory_on_take(lua_State *L, v3s16 p,
const std::string &listname, int index, ItemStack &stack,
ServerActiveObject *player)
{
realitycheck(L);
@@ -5793,22 +5936,276 @@ 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
MapNode node = get_env(L)->getMap().getNodeNoEx(p);
if(node.getContent() == CONTENT_IGNORE)
return ItemStack();
return;
// Push callback function on stack
if(!get_item_callback(L, ndef->get(node).name.c_str(),
"on_metadata_inventory_take"))
return ItemStack();
return;
// Call function(pos, listname, index, count, player)
// 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, 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));
if(!lua_isnumber(L, -1))
throw LuaError(L, "allow_move should return a number");
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);
if(lua_pcall(L, 5, 1, 0))
script_error(L, "error: %s", lua_tostring(L, -1));
return read_item(L, -1);
if(!lua_isnumber(L, -1))
throw LuaError(L, "allow_put should return a number");
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, 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_take"))
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);
if(lua_pcall(L, 5, 1, 0))
script_error(L, "error: %s", lua_tostring(L, -1));
if(!lua_isnumber(L, -1))
throw LuaError(L, "allow_take should return a number");
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, 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_take"))
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));
}
/*

View File

@@ -61,7 +61,6 @@ void scriptapi_on_dieplayer(lua_State *L, ServerActiveObject *player);
bool scriptapi_on_respawnplayer(lua_State *L, ServerActiveObject *player);
void scriptapi_on_joinplayer(lua_State *L, ServerActiveObject *player);
void scriptapi_on_leaveplayer(lua_State *L, ServerActiveObject *player);
void scriptapi_get_creative_inventory(lua_State *L, ServerActiveObject *player);
bool scriptapi_get_auth(lua_State *L, const std::string &playername,
std::string *dst_password, std::set<std::string> *dst_privs);
void scriptapi_create_auth(lua_State *L, const std::string &playername,
@@ -101,18 +100,67 @@ void scriptapi_node_on_receive_fields(lua_State *L, v3s16 p,
const std::string &formname,
const std::map<std::string, std::string> &fields,
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 &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,
// 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);
// 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,
// 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, ItemStack &stack,
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, ItemStack &stack,
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, ItemStack &stack,
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, ItemStack &stack,
ServerActiveObject *player);
/* luaentity */

View File

@@ -59,12 +59,13 @@ with this program; if not, write to the Free Software Foundation, Inc.,
21: dynamic content type allocation
22: minerals removed, facedir & wallmounted changed
23: new node metadata format
24: 16-bit node ids and node timers
24: 16-bit node ids and node timers (never released as stable)
25: Improved node timer format
*/
// This represents an uninitialized or invalid format
#define SER_FMT_VER_INVALID 255
// Highest supported serialization version
#define SER_FMT_VER_HIGHEST 24
#define SER_FMT_VER_HIGHEST 25
// Lowest supported serialization version
#define SER_FMT_VER_LOWEST 0

View File

@@ -1160,6 +1160,15 @@ Server::~Server()
// Deinitialize scripting
infostream<<"Server: Deinitializing scripting"<<std::endl;
script_deinit(m_lua);
// Delete detached inventories
{
for(std::map<std::string, Inventory*>::iterator
i = m_detached_inventories.begin();
i != m_detached_inventories.end(); i++){
delete i->second;
}
}
}
void Server::start(unsigned short port)
@@ -2250,10 +2259,13 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
// Send inventory
UpdateCrafting(peer_id);
SendInventory(peer_id);
// Send HP
SendPlayerHP(peer_id);
// Send detached inventories
sendDetachedInventories(peer_id);
// Show death screen if necessary
if(player->hp == 0)
SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
@@ -2532,30 +2544,6 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
delete a;
return;
}
// If player is not an admin, check for ownership of src and dst
/*if(!checkPriv(player->getName(), "server"))
{
std::string owner_from = getInventoryOwner(ma->from_inv);
if(owner_from != "" && owner_from != player->getName())
{
infostream<<"WARNING: "<<player->getName()
<<" tried to access an inventory that"
<<" belongs to "<<owner_from<<std::endl;
delete a;
return;
}
std::string owner_to = getInventoryOwner(ma->to_inv);
if(owner_to != "" && owner_to != player->getName())
{
infostream<<"WARNING: "<<player->getName()
<<" tried to access an inventory that"
<<" belongs to "<<owner_to<<std::endl;
delete a;
return;
}
}*/
}
/*
Handle restrictions and special cases of the drop action
@@ -2574,19 +2562,6 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
delete a;
return;
}
// If player is not an admin, check for ownership
/*else if(!checkPriv(player->getName(), "server"))
{
std::string owner_from = getInventoryOwner(da->from_inv);
if(owner_from != "" && owner_from != player->getName())
{
infostream<<"WARNING: "<<player->getName()
<<" tried to access an inventory that"
<<" belongs to "<<owner_from<<std::endl;
delete a;
return;
}
}*/
}
/*
Handle restrictions and special cases of the craft action
@@ -2611,20 +2586,6 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
delete a;
return;
}
// If player is not an admin, check for ownership of inventory
/*if(!checkPriv(player->getName(), "server"))
{
std::string owner_craft = getInventoryOwner(ca->craft_inv);
if(owner_craft != "" && owner_craft != player->getName())
{
infostream<<"WARNING: "<<player->getName()
<<" tried to access an inventory that"
<<" belongs to "<<owner_craft<<std::endl;
delete a;
return;
}
}*/
}
// Do the action
@@ -3170,8 +3131,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
// Placement was handled in lua
// Apply returned ItemStack
if(g_settings->getBool("creative_mode") == false)
playersao->setWieldedItem(item);
playersao->setWieldedItem(item);
}
// If item has node placement prediction, always send the above
@@ -3197,8 +3157,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
item, playersao, pointed))
{
// Apply returned ItemStack
if(g_settings->getBool("creative_mode") == false)
playersao->setWieldedItem(item);
playersao->setWieldedItem(item);
}
} // action == 4
@@ -3318,6 +3277,13 @@ Inventory* Server::getInventory(const InventoryLocation &loc)
return meta->getInventory();
}
break;
case InventoryLocation::DETACHED:
{
if(m_detached_inventories.count(loc.name) == 0)
return NULL;
return m_detached_inventories[loc.name];
}
break;
default:
assert(0);
}
@@ -3352,6 +3318,11 @@ void Server::setInventoryModified(const InventoryLocation &loc)
setBlockNotSent(blockpos);
}
break;
case InventoryLocation::DETACHED:
{
sendDetachedInventoryToAll(loc.name);
}
break;
default:
assert(0);
}
@@ -4016,7 +3987,7 @@ void Server::SendBlocks(float dtime)
RemoteClient *client = getClient(q.peer_id);
SendBlockNoLock(q.peer_id, block, 24);//client->serialization_version);
SendBlockNoLock(q.peer_id, block, client->serialization_version);
client->SentBlock(q.pos);
@@ -4309,6 +4280,51 @@ void Server::sendRequestedMedia(u16 peer_id,
}
}
void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
{
if(m_detached_inventories.count(name) == 0){
errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
return;
}
Inventory *inv = m_detached_inventories[name];
std::ostringstream os(std::ios_base::binary);
writeU16(os, TOCLIENT_DETACHED_INVENTORY);
os<<serializeString(name);
inv->serialize(os);
// Make data buffer
std::string s = os.str();
SharedBuffer<u8> data((u8*)s.c_str(), s.size());
// Send as reliable
m_con.Send(peer_id, 0, data, true);
}
void Server::sendDetachedInventoryToAll(const std::string &name)
{
DSTACK(__FUNCTION_NAME);
for(core::map<u16, RemoteClient*>::Iterator
i = m_clients.getIterator();
i.atEnd() == false; i++){
RemoteClient *client = i.getNode()->getValue();
sendDetachedInventory(name, client->peer_id);
}
}
void Server::sendDetachedInventories(u16 peer_id)
{
DSTACK(__FUNCTION_NAME);
for(std::map<std::string, Inventory*>::iterator
i = m_detached_inventories.begin();
i != m_detached_inventories.end(); i++){
const std::string &name = i->first;
//Inventory *inv = i->second;
sendDetachedInventory(name, peer_id);
}
}
/*
Something random
*/
@@ -4362,9 +4378,7 @@ void Server::UpdateCrafting(u16 peer_id)
// Get a preview for crafting
ItemStack preview;
// No crafting in creative mode
if(g_settings->getBool("creative_mode") == false)
getCraftingResult(&player->inventory, preview, false, this);
getCraftingResult(&player->inventory, preview, false, this);
// Put the new preview in
InventoryList *plist = player->inventory.getList("craftpreview");
@@ -4493,6 +4507,21 @@ void Server::queueBlockEmerge(v3s16 blockpos, bool allow_generate)
m_emerge_queue.addBlock(PEER_ID_INEXISTENT, blockpos, flags);
}
Inventory* Server::createDetachedInventory(const std::string &name)
{
if(m_detached_inventories.count(name) > 0){
infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
delete m_detached_inventories[name];
} else {
infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
}
Inventory *inv = new Inventory(m_itemdef);
assert(inv);
m_detached_inventories[name] = inv;
sendDetachedInventoryToAll(name);
return inv;
}
// IGameDef interface
// Under envlock
IItemDefManager* Server::getItemDefManager()
@@ -4684,10 +4713,6 @@ PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
scriptapi_on_joinplayer(m_lua, playersao);
/* Creative mode */
if(g_settings->getBool("creative_mode"))
playersao->createCreativeInventory();
return playersao;
}

View File

@@ -538,6 +538,9 @@ public:
void queueBlockEmerge(v3s16 blockpos, bool allow_generate);
// Creates or resets inventory
Inventory* createDetachedInventory(const std::string &name);
// Envlock and conlock should be locked when using Lua
lua_State *getLua(){ return m_lua; }
@@ -627,6 +630,10 @@ private:
void sendMediaAnnouncement(u16 peer_id);
void sendRequestedMedia(u16 peer_id,
const core::list<MediaRequest> &tosend);
void sendDetachedInventory(const std::string &name, u16 peer_id);
void sendDetachedInventoryToAll(const std::string &name);
void sendDetachedInventories(u16 peer_id);
/*
Something random
@@ -828,6 +835,12 @@ private:
*/
std::map<s32, ServerPlayingSound> m_playing_sounds;
s32 m_next_sound_id;
/*
Detached inventories (behind m_env_mutex)
*/
// key = name
std::map<std::string, Inventory*> m_detached_inventories;
};
/*

View File

@@ -324,7 +324,9 @@ def content_is_air(d):
return d in [126, 127, 254, "air"]
def read_content(mapdata, version, datapos):
if version >= 20:
if version >= 24:
return (mapdata[datapos*2] << 8) | (mapdata[datapos*2 + 1])
elif version >= 20:
if mapdata[datapos] < 0x80:
return mapdata[datapos]
else:
@@ -387,6 +389,7 @@ def read_mapdata(mapdata, version, pixellist, water, day_night_differs, id_to_na
#print("unknown node: %s/%s/%s x: %d y: %d z: %d block id: %x"
# % (xhex, zhex, yhex, x, y, z, content))
# Go through all sectors.
for n in range(len(xlist)):
#if n > 500:
@@ -546,6 +549,14 @@ for n in range(len(xlist)):
if version == 23:
readU8(f) # Unused node timer version (always 0)
if version == 24:
ver = readU8(f)
if ver == 1:
num = readU16(f)
for i in range(0,num):
readU16(f)
readS32(f)
readS32(f)
static_object_version = readU8(f)
static_object_count = readU16(f)
@@ -578,6 +589,15 @@ for n in range(len(xlist)):
#print(str(node_id)+" = "+name)
id_to_name[node_id] = name
# Node timers
if version >= 25:
timer_size = readU8(f)
num = readU16(f)
for i in range(0,num):
readU16(f)
readS32(f)
readS32(f)
read_mapdata(mapdata, version, pixellist, water, day_night_differs, id_to_name)
# After finding all the pixels in the sector, we can move on to