1
0
mirror of https://github.com/luanti-org/luanti.git synced 2025-11-05 09:45:30 +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").."/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")

View File

@@ -16,4 +16,11 @@ 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
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) function minetest.item_place_node(itemstack, placer, pointed_thing)
local item = itemstack:peek_item() local item = itemstack:peek_item()
local def = itemstack:get_definition() local def = itemstack:get_definition()
if def.type == "node" and pointed_thing.type == "node" then if def.type ~= "node" or pointed_thing.type ~= "node" then
local pos = pointed_thing.above return itemstack
local oldnode = minetest.env:get_node(pos) end
local olddef = ItemStack({name=oldnode.name}):get_definition()
if not olddef.buildable_to then 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" minetest.log("info", placer:get_player_name() .. " tried to place"
.. " node in invalid position " .. minetest.pos_to_string(pos) .. " node in invalid position " .. minetest.pos_to_string(above)
.. ", replacing " .. oldnode.name) .. ", replacing " .. oldnode_above.name)
return return
end end
minetest.log("action", placer:get_player_name() .. " places node " -- Place above pointed node
.. def.name .. " at " .. minetest.pos_to_string(pos)) 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} local newnode = {name = def.name, param1 = 0, param2 = 0}
-- Calculate direction for wall mounted stuff like torches and signs -- Calculate direction for wall mounted stuff like torches and signs
if def.paramtype2 == 'wallmounted' then if def.paramtype2 == 'wallmounted' then
local under = pointed_thing.under local dir = {
local above = pointed_thing.above x = under.x - above.x,
local dir = {x = under.x - above.x, y = under.y - above.y, z = under.z - above.z} y = under.y - above.y,
z = under.z - above.z
}
newnode.param2 = minetest.dir_to_wallmounted(dir) newnode.param2 = minetest.dir_to_wallmounted(dir)
-- Calculate the direction for furnaces and chests and stuff -- Calculate the direction for furnaces and chests and stuff
elseif def.paramtype2 == 'facedir' then elseif def.paramtype2 == 'facedir' then
local placer_pos = placer:getpos() local placer_pos = placer:getpos()
if placer_pos then if placer_pos then
local dir = {x = pos.x - placer_pos.x, y = pos.y - placer_pos.y, z = pos.z - placer_pos.z} 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) newnode.param2 = minetest.dir_to_facedir(dir)
minetest.log("action", "facedir: " .. newnode.param2) minetest.log("action", "facedir: " .. newnode.param2)
end end
end end
-- Add node and update -- Add node and update
minetest.env:add_node(pos, newnode) minetest.env:add_node(place_to, newnode)
-- Run callback -- Run callback
if def.after_place_node then if def.after_place_node then
def.after_place_node(pos, placer) -- 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 end
-- Run script hook (deprecated) -- Run script hook
local _, callback local _, callback
for _, callback in ipairs(minetest.registered_on_placenodes) do for _, callback in ipairs(minetest.registered_on_placenodes) do
callback(pos, newnode, placer) -- 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 end
itemstack:take_item() itemstack:take_item()
end
return itemstack return itemstack
end end
@@ -222,9 +251,11 @@ function minetest.node_punch(pos, node, puncher)
-- Run script hook -- Run script hook
local _, callback local _, callback
for _, callback in ipairs(minetest.registered_on_punchnodes) do 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
end end
function minetest.node_dig(pos, node, digger) function minetest.node_dig(pos, node, digger)
@@ -242,13 +273,12 @@ function minetest.node_dig(pos, node, digger)
minetest.log('action', digger:get_player_name() .. " digs " minetest.log('action', digger:get_player_name() .. " digs "
.. node.name .. " at " .. minetest.pos_to_string(pos)) .. node.name .. " at " .. minetest.pos_to_string(pos))
if not minetest.setting_getbool("creative_mode") then
local wielded = digger:get_wielded_item() local wielded = digger:get_wielded_item()
local drops = minetest.get_node_drops(node.name, wielded:get_name()) local drops = minetest.get_node_drops(node.name, wielded:get_name())
-- Wear out tool -- Wear out tool
tp = wielded:get_tool_capabilities() local tp = wielded:get_tool_capabilities()
dp = minetest.get_dig_params(def.groups, tp) local dp = minetest.get_dig_params(def.groups, tp)
wielded:add_wear(dp.wear) wielded:add_wear(dp.wear)
digger:set_wielded_item(wielded) digger:set_wielded_item(wielded)
@@ -259,12 +289,9 @@ function minetest.node_dig(pos, node, digger)
digger:get_inventory():add_item("main", dropped_item) digger:get_inventory():add_item("main", dropped_item)
end end
end end
end
local oldnode = nil
local oldmetadata = nil local oldmetadata = nil
if def.after_dig_node then if def.after_dig_node then
oldnode = node;
oldmetadata = minetest.env:get_meta(pos):to_table() oldmetadata = minetest.env:get_meta(pos):to_table()
end end
@@ -273,51 +300,22 @@ function minetest.node_dig(pos, node, digger)
-- Run callback -- Run callback
if def.after_dig_node then 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 end
-- Run script hook (deprecated) -- Run script hook
local _, callback local _, callback
for _, callback in ipairs(minetest.registered_on_dignodes) do 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
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

View File

@@ -244,6 +244,7 @@ minetest.register_item(":unknown", {
inventory_image = "unknown_item.png", inventory_image = "unknown_item.png",
on_place = minetest.item_place, on_place = minetest.item_place,
on_drop = minetest.item_drop, on_drop = minetest.item_drop,
groups = {not_in_creative_inventory=1},
}) })
minetest.register_node(":air", { minetest.register_node(":air", {
@@ -258,6 +259,7 @@ minetest.register_node(":air", {
diggable = false, diggable = false,
buildable_to = true, buildable_to = true,
air_equivalent = true, air_equivalent = true,
groups = {not_in_creative_inventory=1},
}) })
minetest.register_node(":ignore", { minetest.register_node(":ignore", {
@@ -272,23 +274,15 @@ minetest.register_node(":ignore", {
diggable = false, diggable = false,
buildable_to = true, -- A way to remove accidentally placed ignores buildable_to = true, -- A way to remove accidentally placed ignores
air_equivalent = true, air_equivalent = true,
groups = {not_in_creative_inventory=1},
}) })
-- The hand (bare definition) -- The hand (bare definition)
minetest.register_item(":", { minetest.register_item(":", {
type = "none", 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 -- Callback registration
-- --

View File

@@ -677,6 +677,7 @@ size[<W>,<H>]
^ deprecated: invsize[<W>,<H>;] ^ deprecated: invsize[<W>,<H>;]
list[<inventory location>;<list name>;<X>,<Y>;<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 ^ Show an inventory list
image[<X>,<Y>;<W>,<H>;<texture name>] 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. ^ When clicked, fields will be sent and the form will quit.
Inventory location: Inventory location:
- "context": Selected node metadata (deprecated: "current_name") - "context": Selected node metadata (deprecated: "current_name")
- "current_player": Player to whom the menu is shown - "current_player": Player to whom the menu is shown
- "player:<name>": Any player - "player:<name>": Any player
- "nodemeta:<X>,<Y>,<Z>": Any node metadata - "nodemeta:<X>,<Y>,<Z>": Any node metadata
- "detached:<name>": A detached inventory
Helper functions Helper functions
----------------- -----------------
@@ -774,11 +777,11 @@ minetest.register_craft(recipe)
Global callback registration functions: (Call these only at load time) Global callback registration functions: (Call these only at load time)
minetest.register_globalstep(func(dtime)) minetest.register_globalstep(func(dtime))
^ Called every server step, usually interval of 0.05s ^ 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 ^ Called when a node has been placed
^ Deprecated: Use on_construct or after_place_node in node definition instead ^ Deprecated: Use on_construct or after_place_node in node definition instead
minetest.register_on_dignode(func(pos, oldnode, digger)) 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 ^ Deprecated: Use on_destruct or after_dig_node in node definition instead
minetest.register_on_punchnode(func(pos, node, puncher)) minetest.register_on_punchnode(func(pos, node, puncher))
^ Called when a node is punched ^ Called when a node is punched
@@ -847,6 +850,10 @@ Inventory:
minetest.get_inventory(location) -> InvRef 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"}
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: Item handling:
minetest.inventorycube(img1, img2, img3) minetest.inventorycube(img1, img2, img3)
@@ -1280,30 +1287,29 @@ Node definition (register_node)
drawtype = "normal", -- See "Node drawtypes" drawtype = "normal", -- See "Node drawtypes"
visual_scale = 1.0, visual_scale = 1.0,
tiles = {tile definition 1, def2, def3, def4, def5, def6}, 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 ^ List can be shortened to needed length
^ Old field name: tile_images
special_tiles = {tile definition 1, Tile definition 2}, 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 ^ List can be shortened to needed length
^ Old field name: special_materials
alpha = 255, alpha = 255,
post_effect_color = {a=0, r=0, g=0, b=0}, post_effect_color = {a=0, r=0, g=0, b=0}, -- If player is inside node
paramtype = "none", paramtype = "none", -- See "Nodes"
paramtype2 = "none", paramtype2 = "none", -- See "Nodes"
is_ground_content = false, is_ground_content = false, -- Currently not used for anything
sunlight_propagates = false, sunlight_propagates = false, -- If true, sunlight will go infinitely through this
walkable = true, walkable = true, -- If true, objects collide with node
pointable = true, pointable = true, -- If true, can be pointed at
diggable = true, diggable = true, -- If false, can never be dug
climbable = false, climbable = false, -- If true, can be climbed on (ladder)
buildable_to = false, buildable_to = false, -- If true, placed nodes can replace this node
drop = "", drop = "", -- alternatively drop = { max_items = ..., items = { ... } }
-- alternatively drop = { max_items = ..., items = { ... } } liquidtype = "none", -- "none"/"source"/"flowing"
liquidtype = "none", liquid_alternative_flowing = "", -- Flowing version of source liquid
liquid_alternative_flowing = "", liquid_alternative_source = "", -- Source version of flowing liquid
liquid_alternative_source = "", liquid_viscosity = 0, -- Higher viscosity = slower flow (max. 7)
liquid_viscosity = 0, light_source = 0, -- Amount of light emitted by node
light_source = 0, damage_per_second = 0, -- If player is inside node, this damage is caused
damage_per_second = 0,
node_box = {type="regular"}, -- See "Node boxes" node_box = {type="regular"}, -- See "Node boxes"
selection_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 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 ^ 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
^ 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_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 on_metadata_inventory_take = func(pos, listname, index, stack, player),
nothing. ^ Called after the actual action has happened, according to what was allowed.
^ The engine ensures the action is valid, i.e. the stack fits at the ^ No return value
given position
^ default: minetest.node_metadata_inventory_move_allow_all
on_metadata_inventory_offer = func(pos, listname, index, stack, player),
^ Called when a player wants to put something into the metadata
inventory
^ Should check if the action is permitted (the engine ensures the
action is valid, i.e. the stack fits at the given position)
^ If permitted, modify the metadata inventory and return the
"leftover" stack (normally nil).
^ If not permitted, return itemstack.
^ default: minetest.node_metadata_inventory_offer_allow_all
on_metadata_inventory_take = func(pos, listname, index, count, player),
^ Called when a player wants to take something out of the metadata
inventory
^ Should check if the action is permitted (the engine ensures the
action is valid, i.e. there's a stack of at least “count” items at
that position)
^ If permitted, modify the metadata inventory and return the
stack of items
^ If not permitted, return nil.
^ default: minetest.node_metadata_inventory_take_allow_all
} }
Recipe for register_craft: (shaped) Recipe for register_craft: (shaped)
@@ -1441,3 +1439,26 @@ 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
^ 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 This applies to a world format carrying the block serialization version
22...23, used at least in 22...25, used at least in
- 0.4.dev-20120322 ... 0.4.dev-20120606 - 0.4.dev-20120322 ... 0.4.dev-20120606 (22...23)
- 0.4.0. - 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 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 format; if compliance with this format is to be checked, it needs to be
@@ -262,17 +263,26 @@ u8 flags
u8 content_width u8 content_width
- Number of bytes in the content (param0) fields of nodes - 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 u8 params_width
- Number of bytes used for parameters per node - Number of bytes used for parameters per node
- Always 2 - Always 2
zlib-compressed node data: zlib-compressed node data:
- content: if content_width == 1:
- content:
u8[4096]: param0 fields u8[4096]: param0 fields
u8[4096]: param1 fields u8[4096]: param1 fields
u8[4096]: param2 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). - The location of a node in each of those arrays is (z*16*16 + y*16 + x).
zlib-compressed node metadata list zlib-compressed node metadata list
@@ -285,9 +295,19 @@ zlib-compressed node metadata list
u16 content_size u16 content_size
u8[content_size] (content of metadata) u8[content_size] (content of metadata)
- unused node timers (version will be 24 when they are actually used): - Node timers
if version == 23: if map format version == 23:
u8 unused version (always 0) 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: u8 static object version:
- Always 0 - Always 0
@@ -317,17 +337,29 @@ foreach num_name_id_mappings
u16 name_len u16 name_len
u8[name_len] name 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. EOF.
Format of nodes Format of nodes
---------------- ----------------
A node is composed of the u8 fields param0, param1 and param2. A node is composed of the u8 fields param0, param1 and param2.
The content id of a node is determined as so: if map format version <= 23:
- If param0 < 0x80, The content id of a node is determined as so:
- If param0 < 0x80,
content_id = param0 content_id = param0
- Otherwise - Otherwise
content_id = (param0<<4) + (param2>>4) 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. The purpose of param1 and param2 depend on the definition of the node.

View File

@@ -14,6 +14,14 @@ default = {}
-- Load other files -- Load other files
dofile(minetest.get_modpath("default").."/mapgen.lua") 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 -- Tool definition
-- --
@@ -1150,7 +1158,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 +1170,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 +1196,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 +1209,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, 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().. 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, 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
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 +1396,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;]"..
@@ -1572,40 +1563,6 @@ minetest.register_craftitem("default:scorched_stuff", {
inventory_image = "default_scorched_stuff.png", 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 -- Aliases for the current map generator outputs
-- --

View File

@@ -443,7 +443,7 @@ minetest.register_abm({
})--]] })--]]
minetest.register_node("experimental:tester_node_1", { minetest.register_node("experimental:tester_node_1", {
description = "Tester Node 1", description = "Tester Node 1 (construct/destruct/timer)",
tile_images = {"wieldhand.png"}, tile_images = {"wieldhand.png"},
groups = {oddly_breakable_by_hand=2}, groups = {oddly_breakable_by_hand=2},
sounds = default.node_sound_wood_defaults(), 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)..")") experimental.print_to_everything("experimental:tester_node_1:on_construct("..minetest.pos_to_string(pos)..")")
local meta = minetest.env:get_meta(pos) local meta = minetest.env:get_meta(pos)
meta:set_string("mine", "test") meta:set_string("mine", "test")
local timer = minetest.env:get_node_timer(pos)
timer:start(4, 3)
end, end,
after_place_node = function(pos, placer) 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) after_dig_node = function(pos, oldnode, oldmetadata, digger)
experimental.print_to_everything("experimental:tester_node_1:after_dig_node("..minetest.pos_to_string(pos)..")") experimental.print_to_everything("experimental:tester_node_1:after_dig_node("..minetest.pos_to_string(pos)..")")
end, 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", { minetest.register_craftitem("experimental:tester_tool_1", {
@@ -509,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;]"..
@@ -517,6 +524,34 @@ minetest.register_craft({
end) end)
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", { minetest.register_chatcommand("test1", {
params = "", params = "",
description = "Test 1: Modify player's inventory view", 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;main;5,3.5;8,4;]"..
"list[current_player;craft;8,0;3,3;]".. "list[current_player;craft;8,0;3,3;]"..
"list[current_player;craftpreview;12,1;1,1;]".. "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[0.5,7;2,1;button1;Button 1]"..
"button_exit[2.5,7;2,1;button2;Exit Button]" "button_exit[2.5,7;2,1;button2;Exit Button]"
) )

View File

@@ -304,6 +304,15 @@ Client::~Client()
sleep_ms(100); sleep_ms(100);
delete m_inventory_from_server; 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) void Client::connect(Address address)
@@ -1698,6 +1707,24 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
assert(player != NULL); assert(player != NULL);
player->inventory_formspec = deSerializeLongString(is); 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 else
{ {
infostream<<"Client: Ignoring unknown command " infostream<<"Client: Ignoring unknown command "
@@ -2090,6 +2117,13 @@ Inventory* Client::getInventory(const InventoryLocation &loc)
return meta->getInventory(); return meta->getInventory();
} }
break; break;
case InventoryLocation::DETACHED:
{
if(m_detached_inventories.count(loc.name) == 0)
return NULL;
return m_detached_inventories[loc.name];
}
break;
default: default:
assert(0); assert(0);
} }

View File

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

View File

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

View File

@@ -292,13 +292,6 @@ public:
ServerActiveObject *puncher, ServerActiveObject *puncher,
float time_from_last_punch) 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 // Take item into inventory
ItemStack item = createItemStack(); ItemStack item = createItemStack();
Inventory *inv = puncher->getInventory(); 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() std::string PlayerSAO::getPropertyPacket()
{ {
m_prop.is_visible = (getHP() != 0); m_prop.is_visible = (getHP() != 0);

View File

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

View File

@@ -2304,6 +2304,13 @@ void the_game(
<<playeritem.name<<" is " <<playeritem.name<<" is "
<<def.node_placement_prediction<<std::endl; <<def.node_placement_prediction<<std::endl;
v3s16 p = neighbourpos; 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; content_t id;
bool found = bool found =
nodedef->getId(def.node_placement_prediction, id); nodedef->getId(def.node_placement_prediction, id);

View File

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

View File

@@ -86,11 +86,12 @@ class GUIFormSpecMenu : public GUIModalMenu
} }
ListDrawSpec(const InventoryLocation &a_inventoryloc, ListDrawSpec(const InventoryLocation &a_inventoryloc,
const std::string &a_listname, 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), inventoryloc(a_inventoryloc),
listname(a_listname), listname(a_listname),
pos(a_pos), 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; std::string listname;
v2s32 pos; v2s32 pos;
v2s32 geom; v2s32 geom;
s32 start_item_i;
}; };
struct ImageDrawSpec struct ImageDrawSpec

View File

@@ -43,24 +43,19 @@ void InventoryLocation::serialize(std::ostream &os) const
{ {
switch(type){ switch(type){
case InventoryLocation::UNDEFINED: case InventoryLocation::UNDEFINED:
{
os<<"undefined"; os<<"undefined";
}
break; break;
case InventoryLocation::CURRENT_PLAYER: case InventoryLocation::CURRENT_PLAYER:
{
os<<"current_player"; os<<"current_player";
}
break; break;
case InventoryLocation::PLAYER: case InventoryLocation::PLAYER:
{
os<<"player:"<<name; os<<"player:"<<name;
}
break; break;
case InventoryLocation::NODEMETA: case InventoryLocation::NODEMETA:
{
os<<"nodemeta:"<<p.X<<","<<p.Y<<","<<p.Z; os<<"nodemeta:"<<p.X<<","<<p.Y<<","<<p.Z;
} break;
case InventoryLocation::DETACHED:
os<<"detached:"<<name;
break; break;
default: default:
assert(0); assert(0);
@@ -94,6 +89,11 @@ void InventoryLocation::deSerialize(std::istream &is)
p.Y = stoi(fn.next(",")); p.Y = stoi(fn.next(","));
p.Z = stoi(fn.next(",")); p.Z = stoi(fn.next(","));
} }
else if(tname == "detached")
{
type = InventoryLocation::DETACHED;
std::getline(is, name, '\n');
}
else else
{ {
infostream<<"Unknown InventoryLocation type=\""<<tname<<"\""<<std::endl; infostream<<"Unknown InventoryLocation type=\""<<tname<<"\""<<std::endl;
@@ -199,76 +199,141 @@ 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();
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 && 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();
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);
}
}
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
<<" to inv=\""<<to_inv.dump()<<"\""
<<" 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);
/* /*
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
*/ */
list_from->moveItem(from_i, list_to, to_i, count); list_from->moveItem(from_i, list_to, to_i, count);
infostream<<"IMoveAction::apply(): moved " // 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 <<" count="<<count
<<" from inv=\""<<from_inv.dump()<<"\"" <<" from inv=\""<<from_inv.dump()<<"\""
<<" list=\""<<from_list<<"\"" <<" list=\""<<from_list<<"\""
@@ -277,6 +342,68 @@ 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();
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); mgr->setInventoryModified(from_inv);
@@ -361,54 +488,93 @@ 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();
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) if(from_inv.type == InventoryLocation::NODEMETA)
{ {
lua_State *L = player->getEnv()->getLua(); lua_State *L = player->getEnv()->getLua();
int count0 = count; ItemStack src_item = list_from->getItem(from_i);
if(count0 == 0) src_item.count = take_count;
count0 = list_from->getItem(from_i).count; src_can_take_count = scriptapi_nodemeta_inventory_allow_take(
infostream<<player->getDescription()<<" dropping "<<count0 L, from_inv.p, from_list, from_i, src_item, player);
<<" 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 != -1 && 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;
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))) player->getBasePosition() + v3f(0,1,0)))
{ {
if(g_settings->getBool("creative_mode") == true actually_dropped_count = take_count - item1.count;
&& from_inv.type == InventoryLocation::PLAYER)
item2 = item1; // creative mode
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); 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;
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) void IDropAction::clientApply(InventoryManager *mgr, IGameDef *gamedef)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -4567,6 +4567,9 @@ static int l_get_inventory(lua_State *L)
lua_getfield(L, 1, "pos"); lua_getfield(L, 1, "pos");
v3s16 pos = check_v3s16(L, -1); v3s16 pos = check_v3s16(L, -1);
loc.setNodeMeta(pos); loc.setNodeMeta(pos);
} else if(type == "detached"){
std::string name = checkstringfield(L, 1, "name");
loc.setDetached(name);
} }
if(get_server(L)->getInventory(loc) != NULL) if(get_server(L)->getInventory(loc) != NULL)
@@ -4576,6 +4579,20 @@ static int l_get_inventory(lua_State *L)
return 1; 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]) // get_dig_params(groups, tool_capabilities[, time_from_last_punch])
static int l_get_dig_params(lua_State *L) 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}, {"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_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},
@@ -5308,21 +5326,6 @@ void scriptapi_on_leaveplayer(lua_State *L, ServerActiveObject *player)
scriptapi_run_callbacks(L, 1, RUN_CALLBACKS_MODE_FIRST); 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) static void get_auth_handler(lua_State *L)
{ {
lua_getglobal(L, "minetest"); 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)); 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 &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)
@@ -5738,18 +5868,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)
{ {
@@ -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 // 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
const std::string &listname, int index, int count, void scriptapi_nodemeta_inventory_on_take(lua_State *L, v3s16 p,
const std::string &listname, int index, ItemStack &stack,
ServerActiveObject *player) ServerActiveObject *player)
{ {
realitycheck(L); 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 // 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, 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);
// 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); 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); 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); 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); bool scriptapi_on_respawnplayer(lua_State *L, ServerActiveObject *player);
void scriptapi_on_joinplayer(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_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, bool scriptapi_get_auth(lua_State *L, const std::string &playername,
std::string *dst_password, std::set<std::string> *dst_privs); std::string *dst_password, std::set<std::string> *dst_privs);
void scriptapi_create_auth(lua_State *L, const std::string &playername, 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::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, 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); ServerActiveObject *player);
/* luaentity */ /* luaentity */

View File

@@ -59,12 +59,13 @@ with this program; if not, write to the Free Software Foundation, Inc.,
21: dynamic content type allocation 21: dynamic content type allocation
22: minerals removed, facedir & wallmounted changed 22: minerals removed, facedir & wallmounted changed
23: new node metadata format 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 // This represents an uninitialized or invalid format
#define SER_FMT_VER_INVALID 255 #define SER_FMT_VER_INVALID 255
// Highest supported serialization version // Highest supported serialization version
#define SER_FMT_VER_HIGHEST 24 #define SER_FMT_VER_HIGHEST 25
// Lowest supported serialization version // Lowest supported serialization version
#define SER_FMT_VER_LOWEST 0 #define SER_FMT_VER_LOWEST 0

View File

@@ -1160,6 +1160,15 @@ Server::~Server()
// Deinitialize scripting // Deinitialize scripting
infostream<<"Server: Deinitializing scripting"<<std::endl; infostream<<"Server: Deinitializing scripting"<<std::endl;
script_deinit(m_lua); 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) void Server::start(unsigned short port)
@@ -2254,6 +2263,9 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
// Send HP // Send HP
SendPlayerHP(peer_id); SendPlayerHP(peer_id);
// Send detached inventories
sendDetachedInventories(peer_id);
// Show death screen if necessary // Show death screen if necessary
if(player->hp == 0) if(player->hp == 0)
SendDeathscreen(m_con, peer_id, false, v3f(0,0,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; delete a;
return; 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 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; delete a;
return; 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 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; delete a;
return; 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 // Do the action
@@ -3170,7 +3131,6 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
// Placement was handled in lua // Placement was handled in lua
// Apply returned ItemStack // Apply returned ItemStack
if(g_settings->getBool("creative_mode") == false)
playersao->setWieldedItem(item); playersao->setWieldedItem(item);
} }
@@ -3197,7 +3157,6 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
item, playersao, pointed)) item, playersao, pointed))
{ {
// Apply returned ItemStack // Apply returned ItemStack
if(g_settings->getBool("creative_mode") == false)
playersao->setWieldedItem(item); playersao->setWieldedItem(item);
} }
@@ -3318,6 +3277,13 @@ Inventory* Server::getInventory(const InventoryLocation &loc)
return meta->getInventory(); return meta->getInventory();
} }
break; break;
case InventoryLocation::DETACHED:
{
if(m_detached_inventories.count(loc.name) == 0)
return NULL;
return m_detached_inventories[loc.name];
}
break;
default: default:
assert(0); assert(0);
} }
@@ -3352,6 +3318,11 @@ void Server::setInventoryModified(const InventoryLocation &loc)
setBlockNotSent(blockpos); setBlockNotSent(blockpos);
} }
break; break;
case InventoryLocation::DETACHED:
{
sendDetachedInventoryToAll(loc.name);
}
break;
default: default:
assert(0); assert(0);
} }
@@ -4016,7 +3987,7 @@ void Server::SendBlocks(float dtime)
RemoteClient *client = getClient(q.peer_id); 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); 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 Something random
*/ */
@@ -4362,8 +4378,6 @@ void Server::UpdateCrafting(u16 peer_id)
// Get a preview for crafting // Get a preview for crafting
ItemStack preview; 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 // Put the new preview in
@@ -4493,6 +4507,21 @@ void Server::queueBlockEmerge(v3s16 blockpos, bool allow_generate)
m_emerge_queue.addBlock(PEER_ID_INEXISTENT, blockpos, flags); 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 // IGameDef interface
// Under envlock // Under envlock
IItemDefManager* Server::getItemDefManager() IItemDefManager* Server::getItemDefManager()
@@ -4684,10 +4713,6 @@ PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
scriptapi_on_joinplayer(m_lua, playersao); scriptapi_on_joinplayer(m_lua, playersao);
/* Creative mode */
if(g_settings->getBool("creative_mode"))
playersao->createCreativeInventory();
return playersao; return playersao;
} }

View File

@@ -538,6 +538,9 @@ public:
void queueBlockEmerge(v3s16 blockpos, bool allow_generate); 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 // Envlock and conlock should be locked when using Lua
lua_State *getLua(){ return m_lua; } lua_State *getLua(){ return m_lua; }
@@ -628,6 +631,10 @@ private:
void sendRequestedMedia(u16 peer_id, void sendRequestedMedia(u16 peer_id,
const core::list<MediaRequest> &tosend); 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 Something random
*/ */
@@ -828,6 +835,12 @@ private:
*/ */
std::map<s32, ServerPlayingSound> m_playing_sounds; std::map<s32, ServerPlayingSound> m_playing_sounds;
s32 m_next_sound_id; 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"] return d in [126, 127, 254, "air"]
def read_content(mapdata, version, datapos): 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: if mapdata[datapos] < 0x80:
return mapdata[datapos] return mapdata[datapos]
else: 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" #print("unknown node: %s/%s/%s x: %d y: %d z: %d block id: %x"
# % (xhex, zhex, yhex, x, y, z, content)) # % (xhex, zhex, yhex, x, y, z, content))
# Go through all sectors. # Go through all sectors.
for n in range(len(xlist)): for n in range(len(xlist)):
#if n > 500: #if n > 500:
@@ -546,6 +549,14 @@ for n in range(len(xlist)):
if version == 23: if version == 23:
readU8(f) # Unused node timer version (always 0) 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_version = readU8(f)
static_object_count = readU16(f) static_object_count = readU16(f)
@@ -578,6 +589,15 @@ for n in range(len(xlist)):
#print(str(node_id)+" = "+name) #print(str(node_id)+" = "+name)
id_to_name[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) 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 # After finding all the pixels in the sector, we can move on to