The huge item definition and item namespace unification patch (itemdef), see http://c55.me/minetest/wiki/doku.php?id=changes:itemdef

This commit is contained in:
Kahrl 2012-01-12 06:10:39 +01:00
parent 569156b013
commit 6a76c226e1
65 changed files with 7232 additions and 7282 deletions

@ -80,15 +80,91 @@ function dump(o, dumped)
end end
-- --
-- Built-in node definitions. Also defined in C. -- Item definition helpers
-- --
minetest.register_nodedef_defaults({ minetest.inventorycube = function(img1, img2, img3)
img2 = img2 or img1
img3 = img3 or img1
return "[inventorycube"
.. "{" .. img1:gsub("%^", "&")
.. "{" .. img2:gsub("%^", "&")
.. "{" .. img3:gsub("%^", "&")
end
minetest.get_pointed_thing_position = function(pointed_thing, above)
if pointed_thing.type == "node" then
if above then
-- The position where a node would be placed
return pointed_thing.above
else
-- The position where a node would be dug
return pointed_thing.under
end
elseif pointed_thing.type == "object" then
obj = pointed.thing.ref
if obj ~= nil then
return obj:getpos()
else
return nil
end
else
return nil
end
end
function minetest.item_place(itemstack, placer, pointed_thing)
pos = minetest.get_pointed_thing_position(pointed_thing, true)
if pos ~= nil then
item = itemstack:take_item()
if item ~= nil then
minetest.env:add_item(pos, item)
end
end
return itemstack
end
function minetest.item_drop(itemstack, dropper, pos)
minetest.env:add_item(pos, itemstack)
return ""
end
function minetest.item_eat(hp_change)
return function(itemstack, user, pointed_thing) -- closure
if itemstack:take_item() ~= nil then
user:set_hp(user:get_hp() + hp_change)
end
return itemstack
end
end
--
-- Item definition defaults
--
minetest.nodedef_default = {
-- Item properties
type="node",
-- name intentionally not defined here -- name intentionally not defined here
description = "",
inventory_image = "",
wield_image = "",
wield_scale = {x=1,y=1,z=1},
stack_max = 99,
dropcount = -1,
usable = false,
liquids_pointable = false,
tool_digging_properties = nil,
-- Interaction callbacks
on_place = nil, -- let C handle node placement for now
on_drop = minetest.item_drop,
on_use = nil,
-- Node properties
drawtype = "normal", drawtype = "normal",
visual_scale = 1.0, visual_scale = 1.0,
tile_images = {"unknown_block.png"}, tile_images = {""},
inventory_image = "unknown_block.png",
special_materials = { special_materials = {
{image="", backface_culling=true}, {image="", backface_culling=true},
{image="", backface_culling=true}, {image="", backface_culling=true},
@ -104,8 +180,7 @@ minetest.register_nodedef_defaults({
climbable = false, climbable = false,
buildable_to = false, buildable_to = false,
wall_mounted = false, wall_mounted = false,
often_contains_mineral = false, --dug_item intentionally not defined here
dug_item = "",
extra_dug_item = "", extra_dug_item = "",
extra_dug_item_rarity = 2, extra_dug_item_rarity = 2,
metadata_name = "", metadata_name = "",
@ -124,12 +199,325 @@ minetest.register_nodedef_defaults({
cuttability = 0, cuttability = 0,
flammability = 0, flammability = 0,
}, },
cookresult_item = "", -- Cannot be cooked }
furnace_cooktime = 3.0,
furnace_burntime = -1, -- Cannot be used as fuel minetest.craftitemdef_default = {
type="craft",
-- name intentionally not defined here
description = "",
inventory_image = "",
wield_image = "",
wield_scale = {x=1,y=1,z=1},
stack_max = 99,
liquids_pointable = false,
tool_digging_properties = nil,
-- Interaction callbacks
on_place = minetest.item_place,
on_drop = minetest.item_drop,
on_use = nil,
}
minetest.tooldef_default = {
type="tool",
-- name intentionally not defined here
description = "",
inventory_image = "",
wield_image = "",
wield_scale = {x=1,y=1,z=1},
stack_max = 1,
liquids_pointable = false,
tool_digging_properties = nil,
-- Interaction callbacks
on_place = minetest.item_place,
on_drop = minetest.item_drop,
on_use = nil,
}
minetest.noneitemdef_default = { -- This is used for the hand and unknown items
type="none",
-- name intentionally not defined here
description = "",
inventory_image = "",
wield_image = "",
wield_scale = {x=1,y=1,z=1},
stack_max = 99,
liquids_pointable = false,
tool_digging_properties = nil,
-- Interaction callbacks
on_place = nil,
on_drop = nil,
on_use = nil,
}
--
-- Make raw registration functions inaccessible to anyone except builtin.lua
--
local register_item_raw = minetest.register_item_raw
minetest.register_item_raw = nil
local register_alias_raw = minetest.register_alias_raw
minetest.register_item_raw = nil
--
-- Item / entity / ABM registration functions
--
minetest.registered_abms = {}
minetest.registered_entities = {}
minetest.registered_items = {}
minetest.registered_nodes = {}
minetest.registered_craftitems = {}
minetest.registered_tools = {}
minetest.registered_aliases = {}
-- For tables that are indexed by item name:
-- If table[X] does not exist, default to table[minetest.registered_aliases[X]]
local function set_alias_metatable(table)
setmetatable(table, {
__index = function(name)
return rawget(table, minetest.registered_aliases[name])
end
})
end
set_alias_metatable(minetest.registered_items)
set_alias_metatable(minetest.registered_nodes)
set_alias_metatable(minetest.registered_craftitems)
set_alias_metatable(minetest.registered_tools)
-- These item names may not be used because they would interfere
-- with legacy itemstrings
local forbidden_item_names = {
MaterialItem = true,
MaterialItem2 = true,
MaterialItem3 = true,
NodeItem = true,
node = true,
CraftItem = true,
craft = true,
MBOItem = true,
ToolItem = true,
tool = true,
}
local function check_modname_prefix(name)
if name:sub(1,1) == ":" then
-- Escape the modname prefix enforcement mechanism
return name:sub(2)
else
-- Modname prefix enforcement
local expected_prefix = minetest.get_current_modname() .. ":"
if name:sub(1, #expected_prefix) ~= expected_prefix then
error("Name " .. name .. " does not follow naming conventions: " ..
"\"modname:\" or \":\" prefix required")
end
local subname = name:sub(#expected_prefix+1)
if subname:find("[^abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_]") then
error("Name " .. name .. " does not follow naming conventions: " ..
"contains unallowed characters")
end
return name
end
end
function minetest.register_abm(spec)
-- Add to minetest.registered_abms
minetest.registered_abms[#minetest.registered_abms+1] = spec
end
function minetest.register_entity(name, prototype)
-- Check name
if name == nil then
error("Unable to register entity: Name is nil")
end
name = check_modname_prefix(tostring(name))
prototype.name = name
prototype.__index = prototype -- so that it can be used as a metatable
-- Add to minetest.registered_entities
minetest.registered_entities[name] = prototype
end
function minetest.register_item(name, itemdef)
-- Check name
if name == nil then
error("Unable to register item: Name is nil")
end
name = check_modname_prefix(tostring(name))
if forbidden_item_names[name] then
error("Unable to register item: Name is forbidden: " .. name)
end
itemdef.name = name
-- Apply defaults and add to registered_* table
if itemdef.type == "node" then
setmetatable(itemdef, {__index = minetest.nodedef_default})
minetest.registered_nodes[itemdef.name] = itemdef
elseif itemdef.type == "craft" then
setmetatable(itemdef, {__index = minetest.craftitemdef_default})
minetest.registered_craftitems[itemdef.name] = itemdef
elseif itemdef.type == "tool" then
setmetatable(itemdef, {__index = minetest.tooldef_default})
minetest.registered_tools[itemdef.name] = itemdef
elseif itemdef.type == "none" then
setmetatable(itemdef, {__index = minetest.noneitemdef_default})
else
error("Unable to register item: Type is invalid: " .. dump(itemdef))
end
-- Default dug item
if itemdef.type == "node" and itemdef.dug_item == nil then
itemdef.dug_item = ItemStack({name=itemdef.name}):to_string()
end
-- Legacy stuff
if itemdef.cookresult_itemstring ~= nil and itemdef.cookresult_itemstring ~= "" then
minetest.register_craft({
type="cooking",
output=itemdef.cookresult_itemstring,
recipe=itemdef.name,
cooktime=itemdef.furnace_cooktime
})
end
if itemdef.furnace_burntime ~= nil and itemdef.furnace_burntime >= 0 then
minetest.register_craft({
type="fuel",
recipe=itemdef.name,
burntime=itemdef.furnace_burntime
})
end
-- Disable all further modifications
getmetatable(itemdef).__newindex = {}
--minetest.log("Registering item: " .. itemdef.name)
minetest.registered_items[itemdef.name] = itemdef
minetest.registered_aliases[itemdef.name] = nil
register_item_raw(itemdef)
end
function minetest.register_node(name, nodedef)
nodedef.type = "node"
minetest.register_item(name, nodedef)
end
function minetest.register_craftitem(name, craftitemdef)
craftitemdef.type = "craft"
-- Legacy stuff
if craftitemdef.inventory_image == nil and craftitemdef.image ~= nil then
craftitemdef.inventory_image = craftitemdef.image
end
minetest.register_item(name, craftitemdef)
end
function minetest.register_tool(name, tooldef)
tooldef.type = "tool"
tooldef.stack_max = 1
-- Legacy stuff
if tooldef.inventory_image == nil and tooldef.image ~= nil then
tooldef.inventory_image = tooldef.image
end
if tooldef.tool_digging_properties == nil and
(tooldef.full_punch_interval ~= nil or
tooldef.basetime ~= nil or
tooldef.dt_weight ~= nil or
tooldef.dt_crackiness ~= nil or
tooldef.dt_crumbliness ~= nil or
tooldef.dt_cuttability ~= nil or
tooldef.basedurability ~= nil or
tooldef.dd_weight ~= nil or
tooldef.dd_crackiness ~= nil or
tooldef.dd_crumbliness ~= nil or
tooldef.dd_cuttability ~= nil) then
tooldef.tool_digging_properties = {
full_punch_interval = tooldef.full_punch_interval,
basetime = tooldef.basetime,
dt_weight = tooldef.dt_weight,
dt_crackiness = tooldef.dt_crackiness,
dt_crumbliness = tooldef.dt_crumbliness,
dt_cuttability = tooldef.dt_cuttability,
basedurability = tooldef.basedurability,
dd_weight = tooldef.dd_weight,
dd_crackiness = tooldef.dd_crackiness,
dd_crumbliness = tooldef.dd_crumbliness,
dd_cuttability = tooldef.dd_cuttability,
}
end
minetest.register_item(name, tooldef)
end
function minetest.register_alias(name, convert_to)
if forbidden_item_names[name] then
error("Unable to register alias: Name is forbidden: " .. name)
end
if minetest.registered_items[name] ~= nil then
minetest.log("WARNING: Not registering alias, item with same name" ..
" is already defined: " .. name .. " -> " .. convert_to)
else
--minetest.log("Registering alias: " .. name .. " -> " .. convert_to)
minetest.registered_aliases[name] = convert_to
register_alias_raw(name, convert_to)
end
end
-- Alias the forbidden item names to "" so they can't be
-- created via itemstrings (e.g. /give)
local name
for name in pairs(forbidden_item_names) do
minetest.registered_aliases[name] = ""
register_alias_raw(name, "")
end
-- Deprecated:
-- Aliases for minetest.register_alias (how ironic...)
--minetest.alias_node = minetest.register_alias
--minetest.alias_tool = minetest.register_alias
--minetest.alias_craftitem = minetest.register_alias
--
-- Built-in node definitions. Also defined in C.
--
minetest.register_item(":", {
type = "none",
wield_image = "wieldhand.png",
wield_scale = {x=1,y=1,z=2.5},
tool_digging_properties = {
full_punch_interval = 2.0,
basetime = 0.5,
dt_weight = 1,
dt_crackiness = 0,
dt_crumbliness = -1,
dt_cuttability = 0,
basedurability = 50,
dd_weight = 0,
dd_crackiness = 0,
dd_crumbliness = 0,
dd_cuttability = 0,
}
}) })
minetest.register_node("air", { minetest.register_item(":unknown", {
type = "none",
description = "Unknown Item",
inventory_image = "unknown_item.png",
on_place = minetest.item_place,
on_drop = minetest.item_drop,
})
minetest.register_node(":air", {
description = "Air (you hacker you!)",
inventory_image = "unknown_block.png",
wield_image = "unknown_block.png",
drawtype = "airlike", drawtype = "airlike",
paramtype = "light", paramtype = "light",
sunlight_propagates = true, sunlight_propagates = true,
@ -140,7 +528,10 @@ minetest.register_node("air", {
air_equivalent = true, air_equivalent = true,
}) })
minetest.register_node("ignore", { minetest.register_node(":ignore", {
description = "Ignore (you hacker you!)",
inventory_image = "unknown_block.png",
wield_image = "unknown_block.png",
drawtype = "airlike", drawtype = "airlike",
paramtype = "none", paramtype = "none",
sunlight_propagates = false, sunlight_propagates = false,
@ -151,192 +542,6 @@ minetest.register_node("ignore", {
air_equivalent = true, air_equivalent = true,
}) })
--
-- stackstring manipulation functions
-- example stackstring: 'craft "apple" 4'
-- example item: {type="craft", name="apple"}
-- example item: {type="tool", name="SteelPick", wear="23272"}
--
function stackstring_take_item(stackstring)
if stackstring == nil then
return '', nil
end
local stacktype = nil
stacktype = string.match(stackstring,
'([%a%d]+)')
if stacktype == "node" or stacktype == "craft" then
local itemtype = nil
local itemname = nil
local itemcount = nil
itemtype, itemname, itemcount = string.match(stackstring,
'([%a%d]+) "([^"]*)" (%d+)')
itemcount = tonumber(itemcount)
if itemcount == 0 then
return '', nil
elseif itemcount == 1 then
return '', {type=itemtype, name=itemname}
else
return itemtype.." \""..itemname.."\" "..(itemcount-1),
{type=itemtype, name=itemname}
end
elseif stacktype == "tool" then
local itemtype = nil
local itemname = nil
local itemwear = nil
itemtype, itemname, itemwear = string.match(stackstring,
'([%a%d]+) "([^"]*)" (%d+)')
itemwear = tonumber(itemwear)
return '', {type=itemtype, name=itemname, wear=itemwear}
end
end
function stackstring_put_item(stackstring, item)
if item == nil then
return stackstring, false
end
stackstring = stackstring or ''
local stacktype = nil
stacktype = string.match(stackstring,
'([%a%d]+)')
stacktype = stacktype or ''
if stacktype ~= '' and stacktype ~= item.type then
return stackstring, false
end
if item.type == "node" or item.type == "craft" then
local itemtype = nil
local itemname = nil
local itemcount = nil
itemtype, itemname, itemcount = string.match(stackstring,
'([%a%d]+) "([^"]*)" (%d+)')
itemtype = itemtype or item.type
itemname = itemname or item.name
if itemcount == nil then
itemcount = 0
end
itemcount = itemcount + 1
return itemtype.." \""..itemname.."\" "..itemcount, true
elseif item.type == "tool" then
if stacktype ~= nil then
return stackstring, false
end
local itemtype = nil
local itemname = nil
local itemwear = nil
itemtype, itemname, itemwear = string.match(stackstring,
'([%a%d]+) "([^"]*)" (%d+)')
itemwear = tonumber(itemwear)
return itemtype.." \""..itemname.."\" "..itemwear, true
end
return stackstring, false
end
function stackstring_put_stackstring(stackstring, src)
while src ~= '' do
--print("src="..dump(src))
src, item = stackstring_take_item(src)
--print("src="..dump(src).." item="..dump(item))
local success
stackstring, success = stackstring_put_item(stackstring, item)
if not success then
return stackstring, false
end
end
return stackstring, true
end
function test_stackstring()
local stack
local item
local success
stack, item = stackstring_take_item('node "TNT" 3')
assert(stack == 'node "TNT" 2')
assert(item.type == 'node')
assert(item.name == 'TNT')
stack, item = stackstring_take_item('craft "with spaces" 2')
assert(stack == 'craft "with spaces" 1')
assert(item.type == 'craft')
assert(item.name == 'with spaces')
stack, item = stackstring_take_item('craft "with spaces" 1')
assert(stack == '')
assert(item.type == 'craft')
assert(item.name == 'with spaces')
stack, item = stackstring_take_item('craft "s8df2kj3" 0')
assert(stack == '')
assert(item == nil)
stack, item = stackstring_take_item('tool "With Spaces" 32487')
assert(stack == '')
assert(item.type == 'tool')
assert(item.name == 'With Spaces')
assert(item.wear == 32487)
stack, success = stackstring_put_item('node "With Spaces" 40',
{type='node', name='With Spaces'})
assert(stack == 'node "With Spaces" 41')
assert(success == true)
stack, success = stackstring_put_item('craft "With Spaces" 40',
{type='craft', name='With Spaces'})
assert(stack == 'craft "With Spaces" 41')
assert(success == true)
stack, success = stackstring_put_item('tool "With Spaces" 32487',
{type='tool', name='With Spaces'})
assert(stack == 'tool "With Spaces" 32487')
assert(success == false)
stack, success = stackstring_put_item('node "With Spaces" 40',
{type='tool', name='With Spaces'})
assert(stack == 'node "With Spaces" 40')
assert(success == false)
assert(stackstring_put_stackstring('node "With Spaces" 2',
'node "With Spaces" 1') == 'node "With Spaces" 3')
end
test_stackstring()
--
-- NodeItem helpers
--
minetest.inventorycube = function(img1, img2, img3)
img2 = img2 or img1
img3 = img3 or img1
return "[inventorycube"
.. "{" .. img1:gsub("%^", "&")
.. "{" .. img2:gsub("%^", "&")
.. "{" .. img3:gsub("%^", "&")
end
--
-- CraftItem helpers
--
minetest.craftitem_place_item = function(item, placer, pos)
--print("craftitem_place_item")
--print("item: " .. dump(item))
--print("placer: " .. dump(placer))
--print("pos: " .. dump(pos))
minetest.env:add_item(pos, 'craft "' .. item .. '" 1')
return true
end
minetest.craftitem_eat = function(hp_change)
return function(item, user, pointed_thing) -- closure
--print("craftitem_eat(" .. hp_change .. ")")
--print("item: " .. dump(item))
--print("user: " .. dump(user))
--print("pointed_thing: " .. dump(pointed_thing))
user:set_hp(user:get_hp() + hp_change)
return true
end
end
-- --
-- Default material types -- Default material types
-- --
@ -422,7 +627,7 @@ end
-- Callback registration -- Callback registration
-- --
function make_registration() local function make_registration()
local t = {} local t = {}
local registerfunc = function(func) table.insert(t, func) end local registerfunc = function(func) table.insert(t, func) end
return t, registerfunc return t, registerfunc

Binary file not shown.

After

Width:  |  Height:  |  Size: 710 B

@ -1,80 +1,95 @@
-- bucket (Minetest 0.4 mod) -- bucket (Minetest 0.4 mod)
-- A bucket, which can pick up water and lava -- A bucket, which can pick up water and lava
minetest.alias_craftitem("bucket", "bucket:bucket_empty") minetest.register_alias("bucket", "bucket:bucket_empty")
minetest.alias_craftitem("bucket_water", "bucket:bucket_water") minetest.register_alias("bucket_water", "bucket:bucket_water")
minetest.alias_craftitem("bucket_lava", "bucket:bucket_lava") minetest.register_alias("bucket_lava", "bucket:bucket_lava")
minetest.register_craft({ minetest.register_craft({
output = 'craft "bucket:bucket_empty" 1', output = 'bucket:bucket_empty 1',
recipe = { recipe = {
{'craft "steel_ingot"', '', 'craft "steel_ingot"'}, {'default:steel_ingot', '', 'default:steel_ingot'},
{'', 'craft "steel_ingot"', ''}, {'', 'default:steel_ingot', ''},
} }
}) })
bucket = {}
bucket.liquids = {}
-- Register a new liquid
-- source = name of the source node
-- flowing = name of the flowing node
-- itemname = name of the new bucket item (or nil if liquid is not takeable)
-- inventory_image = texture of the new bucket item (ignored if itemname == nil)
-- This function can be called from any mod (that depends on bucket).
function bucket.register_liquid(source, flowing, itemname, inventory_image)
bucket.liquids[source] = {
source = source,
flowing = flowing,
itemname = itemname,
}
bucket.liquids[flowing] = bucket.liquids[source]
if itemname ~= nil then
minetest.register_craftitem(itemname, {
inventory_image = inventory_image,
stack_max = 1,
liquids_pointable = true,
on_use = function(itemstack, user, pointed_thing)
-- Must be pointing to node
if pointed_thing.type ~= "node" then
return
end
-- Check if pointing to a liquid
n = minetest.env:get_node(pointed_thing.under)
if bucket.liquids[n.name] == nil then
-- Not a liquid
minetest.env:add_node(pointed_thing.above, {name=source})
elseif n.name ~= source then
-- It's a liquid
minetest.env:add_node(pointed_thing.under, {name=source})
end
return {name="bucket:bucket_empty"}
end
})
end
end
minetest.register_craftitem("bucket:bucket_empty", { minetest.register_craftitem("bucket:bucket_empty", {
image = "bucket.png", inventory_image = "bucket.png",
stack_max = 1, stack_max = 1,
liquids_pointable = true, liquids_pointable = true,
on_place_on_ground = minetest.craftitem_place_item, on_use = function(itemstack, user, pointed_thing)
on_use = function(item, player, pointed_thing) -- Must be pointing to node
if pointed_thing.type == "node" then if pointed_thing.type ~= "node" then
n = minetest.env:get_node(pointed_thing.under) return
if n.name == "default:water_source" then end
minetest.env:add_node(pointed_thing.under, {name="air"}) -- Check if pointing to a liquid source
player:add_to_inventory_later('craft "bucket:bucket_water" 1') n = minetest.env:get_node(pointed_thing.under)
return true liquiddef = bucket.liquids[n.name]
elseif n.name == "default:lava_source" then if liquiddef ~= nil and liquiddef.source == n.name and liquiddef.itemname ~= nil then
minetest.env:add_node(pointed_thing.under, {name="air"}) minetest.env:add_node(pointed_thing.under, {name="air"})
player:add_to_inventory_later('craft "bucket:bucket_lava" 1') return {name=liquiddef.itemname}
return true
end
end end
return false
end, end,
}) })
minetest.register_craftitem("bucket:bucket_water", { bucket.register_liquid(
image = "bucket_water.png", "default:water_source",
stack_max = 1, "default:water_flowing",
liquids_pointable = true, "bucket:bucket_water",
on_place_on_ground = minetest.craftitem_place_item, "bucket_water.png"
on_use = function(item, player, pointed_thing) )
if pointed_thing.type == "node" then
n = minetest.env:get_node(pointed_thing.under)
if n.name == "default:water_source" then
-- unchanged
elseif n.name == "default:water_flowing" or n.name == "default:lava_source" or n.name == "default:lava_flowing" then
minetest.env:add_node(pointed_thing.under, {name="default:water_source"})
else
minetest.env:add_node(pointed_thing.above, {name="default:water_source"})
end
player:add_to_inventory_later('craft "bucket:bucket_empty" 1')
return true
end
return false
end,
})
minetest.register_craftitem("bucket:bucket_lava", { bucket.register_liquid(
image = "bucket_lava.png", "default:lava_source",
stack_max = 1, "default:lava_flowing",
liquids_pointable = true, "bucket:bucket_lava",
on_place_on_ground = minetest.craftitem_place_item, "bucket_lava.png"
on_use = function(item, player, pointed_thing) )
if pointed_thing.type == "node" then
n = minetest.env:get_node(pointed_thing.under) minetest.register_craft({
if n.name == "default:lava_source" then type = "fuel",
-- unchanged recipe = "default:bucket_lava",
elseif n.name == "default:water_source" or n.name == "default:water_flowing" or n.name == "default:lava_flowing" then burntime = 60,
minetest.env:add_node(pointed_thing.under, {name="default:lava_source"})
else
minetest.env:add_node(pointed_thing.above, {name="default:lava_source"})
end
player:add_to_inventory_later('craft "bucket:bucket_empty" 1')
return true
end
return false
end,
}) })

File diff suppressed because it is too large Load Diff

@ -25,6 +25,7 @@ minetest.register_globalstep(on_step)
-- An example furnace-thing implemented in Lua -- An example furnace-thing implemented in Lua
--[[
minetest.register_node("experimental:luafurnace", { minetest.register_node("experimental:luafurnace", {
tile_images = {"default_lava.png", "default_furnace_side.png", tile_images = {"default_lava.png", "default_furnace_side.png",
"default_furnace_side.png", "default_furnace_side.png", "default_furnace_side.png", "default_furnace_side.png",
@ -56,15 +57,6 @@ minetest.register_on_placenode(function(pos, newnode, placer)
end end
end) end)
local get_item_definition = function(item)
if not item then return nil end
if item.type == "node" then
return minetest.registered_nodes[item.name]
elseif item.type == "craft" then
return minetest.registered_craftitems[item.name]
end
end
minetest.register_abm({ minetest.register_abm({
nodenames = {"experimental:luafurnace"}, nodenames = {"experimental:luafurnace"},
interval = 1.0, interval = 1.0,
@ -176,7 +168,6 @@ minetest.register_abm({
inv:set_stack("fuel", 1, stack) inv:set_stack("fuel", 1, stack)
end, end,
}) })
--[[
minetest.register_abm({ minetest.register_abm({
nodenames = {"experimental:luafurnace"}, nodenames = {"experimental:luafurnace"},
interval = 1.0, interval = 1.0,
@ -231,7 +222,6 @@ minetest.register_abm({
meta:set_infotext("Lua Furnace: total cooked: "..total_cooked) meta:set_infotext("Lua Furnace: total cooked: "..total_cooked)
end, end,
}) })
--]]
minetest.register_craft({ minetest.register_craft({
output = 'node "experimental:luafurnace" 1', output = 'node "experimental:luafurnace" 1',
recipe = { recipe = {
@ -240,6 +230,7 @@ minetest.register_craft({
{'node "default:cobble"', 'node "default:cobble"', 'node "default:cobble"'}, {'node "default:cobble"', 'node "default:cobble"', 'node "default:cobble"'},
} }
}) })
--]]
-- --
-- Random stuff -- Random stuff
@ -261,38 +252,16 @@ minetest.register_tool("experimental:horribletool", {
}) })
--]] --]]
--[[minetest.register_craft({
output = 'node "somenode" 4',
recipe = {
{'craft "default_tick" 1'},
}
})
minetest.register_node("experimental:somenode", {
tile_images = {"lava.png", "mese.png", "stone.png", "grass.png", "cobble.png", "tree_top.png"},
inventory_image = minetest.inventorycube("lava.png", "mese.png", "stone.png"),
--inventory_image = "treeprop.png",
material = {
diggability = "normal",
weight = 0,
crackiness = 0,
crumbliness = 0,
cuttability = 0,
flammability = 0
},
metadata_name = "chest",
})]]
-- --
-- TNT (not functional) -- TNT (not functional)
-- --
minetest.register_craft({ minetest.register_craft({
output = 'node "experimental:tnt" 4', output = 'experimental:tnt',
recipe = { recipe = {
{'node "default:wood" 1'}, {'default:wood'},
{'craft "default:coal_lump" 1'}, {'default:coal_lump'},
{'node "default:wood" 1'} {'default:wood'}
} }
}) })
@ -363,7 +332,7 @@ function TNT:on_punch(hitter)
self.health = self.health - 1 self.health = self.health - 1
if self.health <= 0 then if self.health <= 0 then
self.object:remove() self.object:remove()
hitter:add_to_inventory("node TNT 1") hitter:get_inventory():add_item("main", "experimental:tnt")
hitter:set_hp(hitter:get_hp() - 1) hitter:set_hp(hitter:get_hp() - 1)
end end
end end
@ -380,7 +349,7 @@ end
minetest.register_entity("experimental:tnt", TNT) minetest.register_entity("experimental:tnt", TNT)
-- Add TNT's old name also -- Add TNT's old name also
minetest.alias_node("TNT", "experimental:tnt") minetest.register_alias("TNT", "experimental:tnt")
-- --
-- A test entity for testing animated and yaw-modulated sprites -- A test entity for testing animated and yaw-modulated sprites
@ -547,6 +516,7 @@ minetest.register_abm({
end, end,
})--]] })--]]
print("experimental modname="..dump(minetest.get_current_modname()))
print("experimental modpath="..dump(minetest.get_modpath("experimental"))) print("experimental modpath="..dump(minetest.get_modpath("experimental")))
-- END -- END

@ -5,97 +5,126 @@
-- Aliases to support loading 0.3 and old 0.4 worlds and inventories -- Aliases to support loading 0.3 and old 0.4 worlds and inventories
-- --
minetest.alias_node("stone", "default:stone") minetest.register_alias("stone", "default:stone")
minetest.alias_node("dirt_with_grass", "default:dirt_with_grass") minetest.register_alias("dirt_with_grass", "default:dirt_with_grass")
minetest.alias_node("dirt_with_grass_footsteps", "default:dirt_with_grass_footsteps") minetest.register_alias("dirt_with_grass_footsteps", "default:dirt_with_grass_footsteps")
minetest.alias_node("dirt", "default:dirt") minetest.register_alias("dirt", "default:dirt")
minetest.alias_node("sand", "default:sand") minetest.register_alias("sand", "default:sand")
minetest.alias_node("gravel", "default:gravel") minetest.register_alias("gravel", "default:gravel")
minetest.alias_node("sandstone", "default:sandstone") minetest.register_alias("sandstone", "default:sandstone")
minetest.alias_node("clay", "default:clay") minetest.register_alias("clay", "default:clay")
minetest.alias_node("brick", "default:brick") minetest.register_alias("brick", "default:brick")
minetest.alias_node("tree", "default:tree") minetest.register_alias("tree", "default:tree")
minetest.alias_node("jungletree", "default:jungletree") minetest.register_alias("jungletree", "default:jungletree")
minetest.alias_node("junglegrass", "default:junglegrass") minetest.register_alias("junglegrass", "default:junglegrass")
minetest.alias_node("leaves", "default:leaves") minetest.register_alias("leaves", "default:leaves")
minetest.alias_node("cactus", "default:cactus") minetest.register_alias("cactus", "default:cactus")
minetest.alias_node("papyrus", "default:papyrus") minetest.register_alias("papyrus", "default:papyrus")
minetest.alias_node("bookshelf", "default:bookshelf") minetest.register_alias("bookshelf", "default:bookshelf")
minetest.alias_node("glass", "default:glass") minetest.register_alias("glass", "default:glass")
minetest.alias_node("wooden_fence", "default:fence_wood") minetest.register_alias("wooden_fence", "default:fence_wood")
minetest.alias_node("rail", "default:rail") minetest.register_alias("rail", "default:rail")
minetest.alias_node("ladder", "default:ladder") minetest.register_alias("ladder", "default:ladder")
minetest.alias_node("wood", "default:wood") minetest.register_alias("wood", "default:wood")
minetest.alias_node("mese", "default:mese") minetest.register_alias("mese", "default:mese")
minetest.alias_node("cloud", "default:cloud") minetest.register_alias("cloud", "default:cloud")
minetest.alias_node("water_flowing", "default:water_flowing") minetest.register_alias("water_flowing", "default:water_flowing")
minetest.alias_node("water_source", "default:water_source") minetest.register_alias("water_source", "default:water_source")
minetest.alias_node("lava_flowing", "default:lava_flowing") minetest.register_alias("lava_flowing", "default:lava_flowing")
minetest.alias_node("lava_source", "default:lava_source") minetest.register_alias("lava_source", "default:lava_source")
minetest.alias_node("torch", "default:torch") minetest.register_alias("torch", "default:torch")
minetest.alias_node("sign_wall", "default:sign_wall") minetest.register_alias("sign_wall", "default:sign_wall")
minetest.alias_node("furnace", "default:furnace") minetest.register_alias("furnace", "default:furnace")
minetest.alias_node("chest", "default:chest") minetest.register_alias("chest", "default:chest")
minetest.alias_node("locked_chest", "default:chest_locked") minetest.register_alias("locked_chest", "default:chest_locked")
minetest.alias_node("cobble", "default:cobble") minetest.register_alias("cobble", "default:cobble")
minetest.alias_node("mossycobble", "default:mossycobble") minetest.register_alias("mossycobble", "default:mossycobble")
minetest.alias_node("steelblock", "default:steelblock") minetest.register_alias("steelblock", "default:steelblock")
minetest.alias_node("nyancat", "default:nyancat") minetest.register_alias("nyancat", "default:nyancat")
minetest.alias_node("nyancat_rainbow", "default:nyancat_rainbow") minetest.register_alias("nyancat_rainbow", "default:nyancat_rainbow")
minetest.alias_node("sapling", "default:sapling") minetest.register_alias("sapling", "default:sapling")
minetest.alias_node("apple", "default:apple") minetest.register_alias("apple", "default:apple")
minetest.alias_tool("WPick", "default:pick_wood") minetest.register_alias("WPick", "default:pick_wood")
minetest.alias_tool("STPick", "default:pick_stone") minetest.register_alias("STPick", "default:pick_stone")
minetest.alias_tool("SteelPick", "default:pick_steel") minetest.register_alias("SteelPick", "default:pick_steel")
minetest.alias_tool("MesePick", "default:pick_mese") minetest.register_alias("MesePick", "default:pick_mese")
minetest.alias_tool("WShovel", "default:shovel_wood") minetest.register_alias("WShovel", "default:shovel_wood")
minetest.alias_tool("STShovel", "default:shovel_stone") minetest.register_alias("STShovel", "default:shovel_stone")
minetest.alias_tool("SteelShovel", "default:shovel_steel") minetest.register_alias("SteelShovel", "default:shovel_steel")
minetest.alias_tool("WAxe", "default:axe_wood") minetest.register_alias("WAxe", "default:axe_wood")
minetest.alias_tool("STAxe", "default:axe_stone") minetest.register_alias("STAxe", "default:axe_stone")
minetest.alias_tool("SteelAxe", "default:axe_steel") minetest.register_alias("SteelAxe", "default:axe_steel")
minetest.alias_tool("WSword", "default:sword_wood") minetest.register_alias("WSword", "default:sword_wood")
minetest.alias_tool("STSword", "default:sword_stone") minetest.register_alias("STSword", "default:sword_stone")
minetest.alias_tool("SteelSword", "default:sword_steel") minetest.register_alias("SteelSword", "default:sword_steel")
minetest.alias_craftitem("Stick", "default:stick") minetest.register_alias("Stick", "default:stick")
minetest.alias_craftitem("paper", "default:paper") minetest.register_alias("paper", "default:paper")
minetest.alias_craftitem("book", "default:book") minetest.register_alias("book", "default:book")
minetest.alias_craftitem("lump_of_coal", "default:coal_lump") minetest.register_alias("lump_of_coal", "default:coal_lump")
minetest.alias_craftitem("lump_of_iron", "default:iron_lump") minetest.register_alias("lump_of_iron", "default:iron_lump")
minetest.alias_craftitem("lump_of_clay", "default:clay_lump") minetest.register_alias("lump_of_clay", "default:clay_lump")
minetest.alias_craftitem("steel_ingot", "default:steel_ingot") minetest.register_alias("steel_ingot", "default:steel_ingot")
minetest.alias_craftitem("clay_brick", "default:clay_brick") minetest.register_alias("clay_brick", "default:clay_brick")
minetest.alias_craftitem("scorched_stuff", "default:scorched_stuff") minetest.register_alias("scorched_stuff", "default:scorched_stuff")
minetest.alias_craftitem("apple", "default:apple")
-- --
-- Old items -- Old items
-- --
minetest.register_craftitem(":rat", { minetest.register_craftitem(":rat", {
image = "rat.png", description = "Rat",
cookresult_itemstring = 'craft "cooked_rat" 1', inventory_image = "rat.png",
on_drop = function(item, dropper, pos) on_drop = function(item, dropper, pos)
minetest.env:add_rat(pos) minetest.env:add_rat(pos)
return true item:take_item()
return item
end, end,
on_place = function(item, dropped, pointed)
pos = minetest.get_pointed_thing_position(pointed, true)
if pos ~= nil then
minetest.env:add_rat(pos)
item:take_item()
return item
end
end
}) })
minetest.register_craftitem(":cooked_rat", { minetest.register_craftitem(":cooked_rat", {
image = "cooked_rat.png", description = "Cooked rat",
cookresult_itemstring = 'craft "scorched_stuff" 1', inventory_image = "cooked_rat.png",
on_place_on_ground = minetest.craftitem_place_item, on_use = minetest.item_eat(6),
on_use = minetest.craftitem_eat(6),
}) })
minetest.register_craftitem(":firefly", { minetest.register_craftitem(":firefly", {
image = "firefly.png", description = "Firefly",
inventory_image = "firefly.png",
on_drop = function(item, dropper, pos) on_drop = function(item, dropper, pos)
minetest.env:add_firefly(pos) minetest.env:add_firefly(pos)
return true item:take_item()
return item
end, end,
on_place = function(item, dropped, pointed)
pos = minetest.get_pointed_thing_position(pointed, true)
if pos ~= nil then
minetest.env:add_firefly(pos)
item:take_item()
return item
end
end
})
minetest.register_craft({
type = "cooking",
output = "cooked_rat",
recipe = "rat",
})
minetest.register_craft({
type = "cooking",
output = "scorched_stuff",
recipe = "cooked_rat",
}) })
-- END -- END

@ -100,9 +100,8 @@ set(common_SRCS
content_abm.cpp content_abm.cpp
craftdef.cpp craftdef.cpp
nameidmapping.cpp nameidmapping.cpp
tooldef.cpp itemdef.cpp
nodedef.cpp nodedef.cpp
craftitemdef.cpp
luaentity_common.cpp luaentity_common.cpp
scriptapi.cpp scriptapi.cpp
script.cpp script.cpp

@ -27,7 +27,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "tile.h" #include "tile.h"
#include <cmath> #include <cmath>
#include "settings.h" #include "settings.h"
#include "nodedef.h" // For wield visualization #include "itemdef.h" // For wield visualization
Camera::Camera(scene::ISceneManager* smgr, MapDrawControl& draw_control): Camera::Camera(scene::ISceneManager* smgr, MapDrawControl& draw_control):
m_smgr(smgr), m_smgr(smgr),
@ -37,6 +37,7 @@ Camera::Camera(scene::ISceneManager* smgr, MapDrawControl& draw_control):
m_wieldmgr(NULL), m_wieldmgr(NULL),
m_wieldnode(NULL), m_wieldnode(NULL),
m_wieldlight(0),
m_draw_control(draw_control), m_draw_control(draw_control),
m_viewing_range_min(5.0), m_viewing_range_min(5.0),
@ -77,15 +78,15 @@ Camera::Camera(scene::ISceneManager* smgr, MapDrawControl& draw_control):
// all other 3D scene nodes and before the GUI. // all other 3D scene nodes and before the GUI.
m_wieldmgr = smgr->createNewSceneManager(); m_wieldmgr = smgr->createNewSceneManager();
m_wieldmgr->addCameraSceneNode(); m_wieldmgr->addCameraSceneNode();
m_wieldnode = new ExtrudedSpriteSceneNode(m_wieldmgr->getRootSceneNode(), m_wieldmgr); m_wieldnode = m_wieldmgr->addMeshSceneNode(createCubeMesh(v3f(1,1,1)), NULL); // need a dummy mesh
updateSettings(); updateSettings();
} }
Camera::~Camera() Camera::~Camera()
{ {
m_wieldnode->setMesh(NULL);
m_wieldmgr->drop(); m_wieldmgr->drop();
m_wieldnode->drop();
} }
bool Camera::successfullyCreated(std::wstring& error_message) bool Camera::successfullyCreated(std::wstring& error_message)
@ -292,7 +293,7 @@ void Camera::update(LocalPlayer* player, f32 frametime, v2u32 screensize)
} }
m_wieldnode->setPosition(wield_position); m_wieldnode->setPosition(wield_position);
m_wieldnode->setRotation(wield_rotation); m_wieldnode->setRotation(wield_rotation);
m_wieldnode->updateLight(player->light); m_wieldlight = player->light;
// Render distance feedback loop // Render distance feedback loop
updateViewingRange(frametime); updateViewingRange(frametime);
@ -449,62 +450,38 @@ void Camera::updateSettings()
m_wanted_frametime = 1.0 / wanted_fps; m_wanted_frametime = 1.0 / wanted_fps;
} }
void Camera::wield(const InventoryItem* item, IGameDef *gamedef)
{
//ITextureSource *tsrc = gamedef->tsrc();
INodeDefManager *ndef = gamedef->ndef();
if (item != NULL)
{
bool isCube = false;
// Try to make a MaterialItem cube.
if (std::string(item->getName()) == "MaterialItem")
{
// A block-type material
MaterialItem* mat_item = (MaterialItem*) item;
content_t content = mat_item->getMaterial();
switch(ndef->get(content).drawtype){
case NDT_NORMAL:
case NDT_LIQUID:
case NDT_FLOWINGLIQUID:
case NDT_GLASSLIKE:
case NDT_ALLFACES:
case NDT_ALLFACES_OPTIONAL:
m_wieldnode->setCube(ndef->get(content).tiles);
isCube = true;
break;
default:
break;
}
}
// If that failed, make an extruded sprite.
if (!isCube)
{
m_wieldnode->setSprite(item->getImageRaw());
}
m_wieldnode->setVisible(true);
}
else
{
// Bare hands
m_wieldnode->setSprite(gamedef->tsrc()->getTextureRaw("wieldhand.png"));
m_wieldnode->setVisible(true);
}
}
void Camera::setDigging(s32 button) void Camera::setDigging(s32 button)
{ {
if (m_digging_button == -1) if (m_digging_button == -1)
m_digging_button = button; m_digging_button = button;
} }
void Camera::wield(const ItemStack &item, IGameDef *gamedef)
{
IItemDefManager *idef = gamedef->idef();
scene::IMesh *wield_mesh = item.getDefinition(idef).wield_mesh;
if(wield_mesh)
{
m_wieldnode->setMesh(wield_mesh);
m_wieldnode->setVisible(true);
}
else
{
m_wieldnode->setVisible(false);
}
}
void Camera::drawWieldedTool() void Camera::drawWieldedTool()
{ {
// Set vertex colors of wield mesh according to light level
u8 li = decode_light(m_wieldlight);
video::SColor color(255,li,li,li);
setMeshColor(m_wieldnode->getMesh(), color);
// Clear Z buffer
m_wieldmgr->getVideoDriver()->clearZBuffer(); m_wieldmgr->getVideoDriver()->clearZBuffer();
// Draw the wielded node (in a separate scene manager)
scene::ICameraSceneNode* cam = m_wieldmgr->getActiveCamera(); scene::ICameraSceneNode* cam = m_wieldmgr->getActiveCamera();
cam->setAspectRatio(m_cameranode->getAspectRatio()); cam->setAspectRatio(m_cameranode->getAspectRatio());
cam->setFOV(m_cameranode->getFOV()); cam->setFOV(m_cameranode->getFOV());
@ -512,145 +489,3 @@ void Camera::drawWieldedTool()
cam->setFarValue(100); cam->setFarValue(100);
m_wieldmgr->drawAll(); m_wieldmgr->drawAll();
} }
ExtrudedSpriteSceneNode::ExtrudedSpriteSceneNode(
scene::ISceneNode* parent,
scene::ISceneManager* mgr,
s32 id,
const v3f& position,
const v3f& rotation,
const v3f& scale
):
ISceneNode(parent, mgr, id, position, rotation, scale)
{
m_meshnode = mgr->addMeshSceneNode(NULL, this, -1, v3f(0,0,0), v3f(0,0,0), v3f(1,1,1), true);
m_cubemesh = NULL;
m_is_cube = false;
m_light = LIGHT_MAX;
}
ExtrudedSpriteSceneNode::~ExtrudedSpriteSceneNode()
{
removeChild(m_meshnode);
if (m_cubemesh)
m_cubemesh->drop();
}
void ExtrudedSpriteSceneNode::setSprite(video::ITexture* texture)
{
const v3f sprite_scale(40.0, 40.0, 4.0); // width, height, thickness
if (texture == NULL)
{
m_meshnode->setVisible(false);
return;
}
io::path name = getExtrudedName(texture);
scene::IMeshCache* cache = SceneManager->getMeshCache();
scene::IAnimatedMesh* mesh = cache->getMeshByName(name);
if (mesh != NULL)
{
// Extruded texture has been found in cache.
m_meshnode->setMesh(mesh);
}
else
{
// Texture was not yet extruded, do it now and save in cache
mesh = createExtrudedMesh(texture,
SceneManager->getVideoDriver(),
sprite_scale);
if (mesh == NULL)
{
dstream << "Warning: failed to extrude sprite" << std::endl;
m_meshnode->setVisible(false);
return;
}
cache->addMesh(name, mesh);
m_meshnode->setMesh(mesh);
mesh->drop();
}
m_meshnode->getMaterial(0).setTexture(0, texture);
m_meshnode->getMaterial(0).setFlag(video::EMF_LIGHTING, false);
m_meshnode->getMaterial(0).setFlag(video::EMF_BILINEAR_FILTER, false);
m_meshnode->getMaterial(0).MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
m_meshnode->setVisible(true);
m_is_cube = false;
updateLight(m_light);
}
void ExtrudedSpriteSceneNode::setCube(const TileSpec tiles[6])
{
const v3f cube_scale(30.0, 30.0, 30.0);
if (m_cubemesh == NULL)
{
m_cubemesh = createCubeMesh(cube_scale);
}
m_meshnode->setMesh(m_cubemesh);
for (int i = 0; i < 6; ++i)
{
// Get the tile texture and atlas transformation
video::ITexture* atlas = tiles[i].texture.atlas;
v2f pos = tiles[i].texture.pos;
v2f size = tiles[i].texture.size;
// Set material flags and texture
video::SMaterial& material = m_meshnode->getMaterial(i);
material.setFlag(video::EMF_LIGHTING, false);
material.setFlag(video::EMF_BILINEAR_FILTER, false);
tiles[i].applyMaterialOptions(material);
material.setTexture(0, atlas);
material.getTextureMatrix(0).setTextureTranslate(pos.X, pos.Y);
material.getTextureMatrix(0).setTextureScale(size.X, size.Y);
}
m_meshnode->setVisible(true);
m_is_cube = true;
updateLight(m_light);
}
void ExtrudedSpriteSceneNode::updateLight(u8 light)
{
m_light = light;
u8 li = decode_light(light);
// Set brightness one lower than incoming light
diminish_light(li);
video::SColor color(255,li,li,li);
setMeshColor(m_meshnode->getMesh(), color);
}
void ExtrudedSpriteSceneNode::removeSpriteFromCache(video::ITexture* texture)
{
scene::IMeshCache* cache = SceneManager->getMeshCache();
scene::IAnimatedMesh* mesh = cache->getMeshByName(getExtrudedName(texture));
if (mesh != NULL)
cache->removeMesh(mesh);
}
const core::aabbox3d<f32>& ExtrudedSpriteSceneNode::getBoundingBox() const
{
return m_meshnode->getBoundingBox();
}
void ExtrudedSpriteSceneNode::OnRegisterSceneNode()
{
if (IsVisible)
SceneManager->registerNodeForRendering(this);
ISceneNode::OnRegisterSceneNode();
}
void ExtrudedSpriteSceneNode::render()
{
// do nothing
}
io::path ExtrudedSpriteSceneNode::getExtrudedName(video::ITexture* texture)
{
io::path path = texture->getName();
path.append("/[extruded]");
return path;
}

@ -26,12 +26,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "tile.h" #include "tile.h"
#include "utility.h" #include "utility.h"
#include <ICameraSceneNode.h> #include <ICameraSceneNode.h>
#include <IMeshCache.h>
#include <IAnimatedMesh.h>
class LocalPlayer; class LocalPlayer;
struct MapDrawControl; struct MapDrawControl;
class ExtrudedSpriteSceneNode;
class IGameDef; class IGameDef;
/* /*
@ -116,13 +113,13 @@ public:
// Update settings from g_settings // Update settings from g_settings
void updateSettings(); void updateSettings();
// Replace the wielded item mesh
void wield(const InventoryItem* item, IGameDef *gamedef);
// Start digging animation // Start digging animation
// Pass 0 for left click, 1 for right click // Pass 0 for left click, 1 for right click
void setDigging(s32 button); void setDigging(s32 button);
// Replace the wielded item mesh
void wield(const ItemStack &item, IGameDef *gamedef);
// Draw the wielded tool. // Draw the wielded tool.
// This has to happen *after* the main scene is drawn. // This has to happen *after* the main scene is drawn.
// Warning: This clears the Z buffer. // Warning: This clears the Z buffer.
@ -136,7 +133,8 @@ private:
scene::ICameraSceneNode* m_cameranode; scene::ICameraSceneNode* m_cameranode;
scene::ISceneManager* m_wieldmgr; scene::ISceneManager* m_wieldmgr;
ExtrudedSpriteSceneNode* m_wieldnode; scene::IMeshSceneNode* m_wieldnode;
u8 m_wieldlight;
// draw control // draw control
MapDrawControl& m_draw_control; MapDrawControl& m_draw_control;
@ -182,46 +180,4 @@ private:
s32 m_digging_button; s32 m_digging_button;
}; };
/*
A scene node that displays a 2D mesh extruded into the third dimension,
to add an illusion of depth.
Since this class was created to display the wielded tool of the local
player, and only tools and items are rendered like this (but not solid
content like stone and mud, which are shown as cubes), the option to
draw a textured cube instead is provided.
*/
class ExtrudedSpriteSceneNode: public scene::ISceneNode
{
public:
ExtrudedSpriteSceneNode(
scene::ISceneNode* parent,
scene::ISceneManager* mgr,
s32 id = -1,
const v3f& position = v3f(0,0,0),
const v3f& rotation = v3f(0,0,0),
const v3f& scale = v3f(1,1,1));
~ExtrudedSpriteSceneNode();
void setSprite(video::ITexture* texture);
void setCube(const TileSpec tiles[6]);
void updateLight(u8 light);
void removeSpriteFromCache(video::ITexture* texture);
virtual const core::aabbox3d<f32>& getBoundingBox() const;
virtual void OnRegisterSceneNode();
virtual void render();
private:
scene::IMeshSceneNode* m_meshnode;
scene::IMesh* m_cubemesh;
bool m_is_cube;
u8 m_light;
io::path getExtrudedName(video::ITexture* texture);
};
#endif #endif

@ -33,8 +33,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "log.h" #include "log.h"
#include "nodemetadata.h" #include "nodemetadata.h"
#include "nodedef.h" #include "nodedef.h"
#include "tooldef.h" #include "itemdef.h"
#include "craftitemdef.h"
#include <IFileSystem.h> #include <IFileSystem.h>
#include "sha1.h" #include "sha1.h"
#include "base64.h" #include "base64.h"
@ -207,14 +206,12 @@ Client::Client(
std::string password, std::string password,
MapDrawControl &control, MapDrawControl &control,
IWritableTextureSource *tsrc, IWritableTextureSource *tsrc,
IWritableToolDefManager *tooldef, IWritableItemDefManager *itemdef,
IWritableNodeDefManager *nodedef, IWritableNodeDefManager *nodedef
IWritableCraftItemDefManager *craftitemdef
): ):
m_tsrc(tsrc), m_tsrc(tsrc),
m_tooldef(tooldef), m_itemdef(itemdef),
m_nodedef(nodedef), m_nodedef(nodedef),
m_craftitemdef(craftitemdef),
m_mesh_update_thread(this), m_mesh_update_thread(this),
m_env( m_env(
new ClientMap(this, this, control, new ClientMap(this, this, control,
@ -234,9 +231,8 @@ Client::Client(
m_access_denied(false), m_access_denied(false),
m_texture_receive_progress(0), m_texture_receive_progress(0),
m_textures_received(false), m_textures_received(false),
m_tooldef_received(false), m_itemdef_received(false),
m_nodedef_received(false), m_nodedef_received(false)
m_craftitemdef_received(false)
{ {
m_packetcounter_timer = 0.0; m_packetcounter_timer = 0.0;
//m_delete_unused_sectors_timer = 0.0; //m_delete_unused_sectors_timer = 0.0;
@ -251,12 +247,6 @@ Client::Client(
else else
infostream<<"Not building texture atlas."<<std::endl; infostream<<"Not building texture atlas."<<std::endl;
// Update node textures
m_nodedef->updateTextures(m_tsrc);
// Start threads after setting up content definitions
m_mesh_update_thread.Start();
/* /*
Add local player Add local player
*/ */
@ -266,9 +256,6 @@ Client::Client(
player->updateName(playername); player->updateName(playername);
m_env.addPlayer(player); m_env.addPlayer(player);
// Initialize player in the inventory context
m_inventory_context.current_player = player;
} }
} }
@ -983,7 +970,7 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
//t4.stop(); //t4.stop();
//TimeTaker t1("inventory.deSerialize()", m_device); //TimeTaker t1("inventory.deSerialize()", m_device);
player->inventory.deSerialize(is, this); player->inventory.deSerialize(is);
//t1.stop(); //t1.stop();
m_inventory_updated = true; m_inventory_updated = true;
@ -1216,18 +1203,18 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
} else { } else {
InventoryList *inv = player->inventory.getList("main"); InventoryList *inv = player->inventory.getList("main");
std::string itemstring(deSerializeString(is)); std::string itemstring(deSerializeString(is));
if (itemstring.empty()) { ItemStack item;
inv->deleteItem(0); item.deSerialize(itemstring, m_itemdef);
infostream inv->changeItem(0, item);
<<"Client: empty player item for peer " if(itemstring.empty())
<< peer_id << std::endl; {
} else { infostream<<"Client: empty player item for peer "
std::istringstream iss(itemstring); <<peer_id<<std::endl;
delete inv->changeItem(0, }
InventoryItem::deSerialize(iss, this)); else
infostream<<"Client: player item for peer " << peer_id << ": "; {
player->getWieldItem()->serialize(infostream); infostream<<"Client: player item for peer "
infostream<<std::endl; <<peer_id<<": "<<itemstring<<std::endl;
} }
} }
} }
@ -1256,14 +1243,9 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
std::string datastring((char*)&data[2], datasize-2); std::string datastring((char*)&data[2], datasize-2);
std::istringstream is(datastring, std::ios_base::binary); std::istringstream is(datastring, std::ios_base::binary);
// Mesh update thread must be stopped while
// Stop threads while updating content definitions // updating content definitions
m_mesh_update_thread.setRun(false); assert(!m_mesh_update_thread.IsRunning());
// Process the remaining TextureSource queue to let MeshUpdateThread
// get it's remaining textures and thus let it stop
while(m_mesh_update_thread.IsRunning()){
m_tsrc->processQueue();
}
int num_textures = readU16(is); int num_textures = readU16(is);
@ -1362,9 +1344,6 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
} }
} }
// Resume threads
m_mesh_update_thread.setRun(true);
m_mesh_update_thread.Start();
ClientEvent event; ClientEvent event;
event.type = CE_TEXTURES_UPDATED; event.type = CE_TEXTURES_UPDATED;
@ -1412,14 +1391,10 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
std::string datastring((char*)&data[2], datasize-2); std::string datastring((char*)&data[2], datasize-2);
std::istringstream is(datastring, std::ios_base::binary); std::istringstream is(datastring, std::ios_base::binary);
// Stop threads while updating content definitions // Mesh update thread must be stopped while
m_mesh_update_thread.setRun(false); // updating content definitions
// Process the remaining TextureSource queue to let MeshUpdateThread assert(!m_mesh_update_thread.IsRunning());
// get it's remaining textures and thus let it stop
while(m_mesh_update_thread.IsRunning()){
m_tsrc->processQueue();
}
/* /*
u16 command u16 command
u16 total number of texture bunches u16 total number of texture bunches
@ -1484,22 +1459,6 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
img->drop(); img->drop();
rfile->drop(); rfile->drop();
} }
if(m_nodedef_received && m_textures_received){
// Rebuild inherited images and recreate textures
m_tsrc->rebuildImagesAndTextures();
// Update texture atlas
if(g_settings->getBool("enable_texture_atlas"))
m_tsrc->buildMainAtlas(this);
// Update node textures
m_nodedef->updateTextures(m_tsrc);
}
// Resume threads
m_mesh_update_thread.setRun(true);
m_mesh_update_thread.Start();
ClientEvent event; ClientEvent event;
event.type = CE_TEXTURES_UPDATED; event.type = CE_TEXTURES_UPDATED;
@ -1507,82 +1466,53 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
} }
else if(command == TOCLIENT_TOOLDEF) else if(command == TOCLIENT_TOOLDEF)
{ {
infostream<<"Client: Received tool definitions: packet size: " infostream<<"Client: WARNING: Ignoring TOCLIENT_TOOLDEF"<<std::endl;
<<datasize<<std::endl;
std::string datastring((char*)&data[2], datasize-2);
std::istringstream is(datastring, std::ios_base::binary);
m_tooldef_received = true;
// Stop threads while updating content definitions
m_mesh_update_thread.setRun(false);
// Process the remaining TextureSource queue to let MeshUpdateThread
// get it's remaining textures and thus let it stop
while(m_mesh_update_thread.IsRunning()){
m_tsrc->processQueue();
}
std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
m_tooldef->deSerialize(tmp_is);
// Resume threads
m_mesh_update_thread.setRun(true);
m_mesh_update_thread.Start();
} }
else if(command == TOCLIENT_NODEDEF) else if(command == TOCLIENT_NODEDEF)
{ {
infostream<<"Client: Received node definitions: packet size: " infostream<<"Client: Received node definitions: packet size: "
<<datasize<<std::endl; <<datasize<<std::endl;
// Mesh update thread must be stopped while
// updating content definitions
assert(!m_mesh_update_thread.IsRunning());
// Decompress node definitions
std::string datastring((char*)&data[2], datasize-2); std::string datastring((char*)&data[2], datasize-2);
std::istringstream is(datastring, std::ios_base::binary); std::istringstream is(datastring, std::ios_base::binary);
m_nodedef_received = true;
// Stop threads while updating content definitions
m_mesh_update_thread.stop();
std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary); std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
m_nodedef->deSerialize(tmp_is, this); std::ostringstream tmp_os;
decompressZlib(tmp_is, tmp_os);
if(m_textures_received){
// Update texture atlas
if(g_settings->getBool("enable_texture_atlas"))
m_tsrc->buildMainAtlas(this);
// Update node textures
m_nodedef->updateTextures(m_tsrc);
}
// Resume threads // Deserialize node definitions
m_mesh_update_thread.setRun(true); std::istringstream tmp_is2(tmp_os.str());
m_mesh_update_thread.Start(); m_nodedef->deSerialize(tmp_is2);
m_nodedef_received = true;
} }
else if(command == TOCLIENT_CRAFTITEMDEF) else if(command == TOCLIENT_CRAFTITEMDEF)
{ {
infostream<<"Client: Received CraftItem definitions: packet size: " infostream<<"Client: WARNING: Ignoring TOCLIENT_CRAFTITEMDEF"<<std::endl;
}
else if(command == TOCLIENT_ITEMDEF)
{
infostream<<"Client: Received item definitions: packet size: "
<<datasize<<std::endl; <<datasize<<std::endl;
// Mesh update thread must be stopped while
// updating content definitions
assert(!m_mesh_update_thread.IsRunning());
// Decompress item definitions
std::string datastring((char*)&data[2], datasize-2); std::string datastring((char*)&data[2], datasize-2);
std::istringstream is(datastring, std::ios_base::binary); std::istringstream is(datastring, std::ios_base::binary);
m_craftitemdef_received = true;
// Stop threads while updating content definitions
m_mesh_update_thread.setRun(false);
// Process the remaining TextureSource queue to let MeshUpdateThread
// get it's remaining textures and thus let it stop
while(m_mesh_update_thread.IsRunning()){
m_tsrc->processQueue();
}
std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary); std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
m_craftitemdef->deSerialize(tmp_is); std::ostringstream tmp_os;
decompressZlib(tmp_is, tmp_os);
// Resume threads
m_mesh_update_thread.setRun(true); // Deserialize node definitions
m_mesh_update_thread.Start(); std::istringstream tmp_is2(tmp_os.str());
m_itemdef->deSerialize(tmp_is2);
m_itemdef_received = true;
} }
else else
{ {
@ -1943,11 +1873,6 @@ void Client::selectPlayerItem(u16 item)
//JMutexAutoLock envlock(m_env_mutex); //bulk comment-out //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
m_playeritem = item; m_playeritem = item;
m_inventory_updated = true; m_inventory_updated = true;
LocalPlayer *player = m_env.getLocalPlayer();
assert(player != NULL);
player->wieldItem(item);
sendPlayerItem(item); sendPlayerItem(item);
} }
@ -1971,17 +1896,19 @@ void Client::getLocalInventory(Inventory &dst)
dst = player->inventory; dst = player->inventory;
} }
InventoryContext *Client::getInventoryContext()
{
return &m_inventory_context;
}
Inventory* Client::getInventory(const InventoryLocation &loc) Inventory* Client::getInventory(const InventoryLocation &loc)
{ {
switch(loc.type){ switch(loc.type){
case InventoryLocation::UNDEFINED: case InventoryLocation::UNDEFINED:
{} {}
break; break;
case InventoryLocation::CURRENT_PLAYER:
{
Player *player = m_env.getLocalPlayer();
assert(player != NULL);
return &player->inventory;
}
break;
case InventoryLocation::PLAYER: case InventoryLocation::PLAYER:
{ {
Player *player = m_env.getPlayer(loc.name.c_str()); Player *player = m_env.getPlayer(loc.name.c_str());
@ -2003,36 +1930,6 @@ Inventory* Client::getInventory(const InventoryLocation &loc)
} }
return NULL; return NULL;
} }
#if 0
Inventory* Client::getInventory(InventoryContext *c, std::string id)
{
if(id == "current_player")
{
assert(c->current_player);
return &(c->current_player->inventory);
}
Strfnd fn(id);
std::string id0 = fn.next(":");
if(id0 == "nodemeta")
{
v3s16 p;
p.X = stoi(fn.next(","));
p.Y = stoi(fn.next(","));
p.Z = stoi(fn.next(","));
NodeMetadata* meta = getNodeMetadata(p);
if(meta)
return meta->getInventory();
infostream<<"nodemeta at ("<<p.X<<","<<p.Y<<","<<p.Z<<"): "
<<"no metadata found"<<std::endl;
return NULL;
}
infostream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
return NULL;
}
#endif
void Client::inventoryAction(InventoryAction *a) void Client::inventoryAction(InventoryAction *a)
{ {
sendInventoryAction(a); sendInventoryAction(a);
@ -2234,6 +2131,32 @@ ClientEvent Client::getClientEvent()
return m_client_event_queue.pop_front(); return m_client_event_queue.pop_front();
} }
void Client::afterContentReceived()
{
assert(m_itemdef_received);
assert(m_nodedef_received);
assert(m_textures_received);
// Rebuild inherited images and recreate textures
m_tsrc->rebuildImagesAndTextures();
// Update texture atlas
if(g_settings->getBool("enable_texture_atlas"))
m_tsrc->buildMainAtlas(this);
// Update node aliases
m_nodedef->updateAliases(m_itemdef);
// Update node textures
m_nodedef->updateTextures(m_tsrc);
// Update item textures and meshes
m_itemdef->updateTexturesAndMeshes(this);
// Start mesh update thread after setting up content definitions
m_mesh_update_thread.Start();
}
float Client::getRTT(void) float Client::getRTT(void)
{ {
try{ try{
@ -2245,9 +2168,9 @@ float Client::getRTT(void)
// IGameDef interface // IGameDef interface
// Under envlock // Under envlock
IToolDefManager* Client::getToolDefManager() IItemDefManager* Client::getItemDefManager()
{ {
return m_tooldef; return m_itemdef;
} }
INodeDefManager* Client::getNodeDefManager() INodeDefManager* Client::getNodeDefManager()
{ {
@ -2258,10 +2181,6 @@ ICraftDefManager* Client::getCraftDefManager()
return NULL; return NULL;
//return m_craftdef; //return m_craftdef;
} }
ICraftItemDefManager* Client::getCraftItemDefManager()
{
return m_craftitemdef;
}
ITextureSource* Client::getTextureSource() ITextureSource* Client::getTextureSource()
{ {
return m_tsrc; return m_tsrc;

@ -36,10 +36,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
struct MeshMakeData; struct MeshMakeData;
class IGameDef; class IGameDef;
class IWritableTextureSource; class IWritableTextureSource;
class IWritableToolDefManager; class IWritableItemDefManager;
class IWritableNodeDefManager; class IWritableNodeDefManager;
//class IWritableCraftDefManager; //class IWritableCraftDefManager;
class IWritableCraftItemDefManager;
class ClientNotReadyException : public BaseException class ClientNotReadyException : public BaseException
{ {
@ -167,9 +166,8 @@ public:
std::string password, std::string password,
MapDrawControl &control, MapDrawControl &control,
IWritableTextureSource *tsrc, IWritableTextureSource *tsrc,
IWritableToolDefManager *tooldef, IWritableItemDefManager *itemdef,
IWritableNodeDefManager *nodedef, IWritableNodeDefManager *nodedef
IWritableCraftItemDefManager *craftitemdef
); );
~Client(); ~Client();
@ -245,11 +243,8 @@ public:
// Copies the inventory of the local player to parameter // Copies the inventory of the local player to parameter
void getLocalInventory(Inventory &dst); void getLocalInventory(Inventory &dst);
InventoryContext *getInventoryContext();
/* InventoryManager interface */ /* InventoryManager interface */
Inventory* getInventory(const InventoryLocation &loc); Inventory* getInventory(const InventoryLocation &loc);
//Inventory* getInventory(InventoryContext *c, std::string id);
void inventoryAction(InventoryAction *a); void inventoryAction(InventoryAction *a);
// Gets closest object pointed by the shootline // Gets closest object pointed by the shootline
@ -323,20 +318,19 @@ public:
bool texturesReceived() bool texturesReceived()
{ return m_textures_received; } { return m_textures_received; }
bool tooldefReceived() bool itemdefReceived()
{ return m_tooldef_received; } { return m_itemdef_received; }
bool nodedefReceived() bool nodedefReceived()
{ return m_nodedef_received; } { return m_nodedef_received; }
bool craftitemdefReceived()
{ return m_craftitemdef_received; }
void afterContentReceived();
float getRTT(void); float getRTT(void);
// IGameDef interface // IGameDef interface
virtual IToolDefManager* getToolDefManager(); virtual IItemDefManager* getItemDefManager();
virtual INodeDefManager* getNodeDefManager(); virtual INodeDefManager* getNodeDefManager();
virtual ICraftDefManager* getCraftDefManager(); virtual ICraftDefManager* getCraftDefManager();
virtual ICraftItemDefManager* getCraftItemDefManager();
virtual ITextureSource* getTextureSource(); virtual ITextureSource* getTextureSource();
virtual u16 allocateUnknownNodeId(const std::string &name); virtual u16 allocateUnknownNodeId(const std::string &name);
@ -363,9 +357,8 @@ private:
IntervalLimiter m_map_timer_and_unload_interval; IntervalLimiter m_map_timer_and_unload_interval;
IWritableTextureSource *m_tsrc; IWritableTextureSource *m_tsrc;
IWritableToolDefManager *m_tooldef; IWritableItemDefManager *m_itemdef;
IWritableNodeDefManager *m_nodedef; IWritableNodeDefManager *m_nodedef;
IWritableCraftItemDefManager *m_craftitemdef;
MeshUpdateThread m_mesh_update_thread; MeshUpdateThread m_mesh_update_thread;
ClientEnvironment m_env; ClientEnvironment m_env;
con::Connection m_con; con::Connection m_con;
@ -387,13 +380,11 @@ private:
std::string m_password; std::string m_password;
bool m_access_denied; bool m_access_denied;
std::wstring m_access_denied_reason; std::wstring m_access_denied_reason;
InventoryContext m_inventory_context;
Queue<ClientEvent> m_client_event_queue; Queue<ClientEvent> m_client_event_queue;
float m_texture_receive_progress; float m_texture_receive_progress;
bool m_textures_received; bool m_textures_received;
bool m_tooldef_received; bool m_itemdef_received;
bool m_nodedef_received; bool m_nodedef_received;
bool m_craftitemdef_received;
friend class FarMesh; friend class FarMesh;
}; };

@ -39,9 +39,14 @@ with this program; if not, write to the Free Software Foundation, Inc.,
Make players to be handled mostly as ActiveObjects Make players to be handled mostly as ActiveObjects
PROTOCOL_VERSION 6: PROTOCOL_VERSION 6:
Only non-cached textures are sent Only non-cached textures are sent
PROTOCOL_VERSION 7:
Add TOCLIENT_ITEMDEF
Obsolete TOCLIENT_TOOLDEF
Obsolete TOCLIENT_CRAFTITEMDEF
Compress the contents of TOCLIENT_ITEMDEF and TOCLIENT_NODEDEF
*/ */
#define PROTOCOL_VERSION 6 #define PROTOCOL_VERSION 7
#define PROTOCOL_ID 0x4f457403 #define PROTOCOL_ID 0x4f457403
@ -252,6 +257,14 @@ enum ToClientCommand
string sha1_digest string sha1_digest
} }
*/ */
TOCLIENT_ITEMDEF = 0x3d,
/*
u16 command
u32 length of next item
serialized ItemDefManager
*/
}; };
enum ToServerCommand enum ToServerCommand

@ -666,7 +666,7 @@ void Connection::send(float dtime)
// Receive packets from the network and buffers and create ConnectionEvents // Receive packets from the network and buffers and create ConnectionEvents
void Connection::receive() void Connection::receive()
{ {
u32 datasize = 100000; u32 datasize = m_max_packet_size * 2; // Double it just to be safe
// TODO: We can not know how many layers of header there are. // TODO: We can not know how many layers of header there are.
// For now, just assume there are no other than the base headers. // For now, just assume there are no other than the base headers.
u32 packet_maxsize = datasize + BASE_HEADER_SIZE; u32 packet_maxsize = datasize + BASE_HEADER_SIZE;
@ -854,10 +854,6 @@ void Connection::receive()
dout_con<<"ProcessPacket returned data of size " dout_con<<"ProcessPacket returned data of size "
<<resultdata.getSize()<<std::endl; <<resultdata.getSize()<<std::endl;
if(datasize < resultdata.getSize())
throw InvalidIncomingDataException
("Buffer too small for received data");
ConnectionEvent e; ConnectionEvent e;
e.dataReceived(peer_id, resultdata); e.dataReceived(peer_id, resultdata);
putEvent(e); putEvent(e);

@ -20,6 +20,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "content_cao.h" #include "content_cao.h"
#include "tile.h" #include "tile.h"
#include "environment.h" #include "environment.h"
#include "collision.h"
#include "settings.h" #include "settings.h"
#include <ICameraSceneNode.h> #include <ICameraSceneNode.h>
#include <ITextSceneNode.h> #include <ITextSceneNode.h>
@ -172,6 +173,8 @@ public:
void updateLight(u8 light_at_pos); void updateLight(u8 light_at_pos);
v3s16 getLightPosition(); v3s16 getLightPosition();
void updateNodePos(); void updateNodePos();
void updateInfoText();
void updateTexture();
void step(float dtime, ClientEnvironment *env); void step(float dtime, ClientEnvironment *env);
@ -191,7 +194,7 @@ private:
core::aabbox3d<f32> m_selection_box; core::aabbox3d<f32> m_selection_box;
scene::IMeshSceneNode *m_node; scene::IMeshSceneNode *m_node;
v3f m_position; v3f m_position;
std::string m_inventorystring; std::string m_itemstring;
std::string m_infotext; std::string m_infotext;
}; };
@ -595,39 +598,13 @@ void ItemCAO::addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc,
buf->drop(); buf->drop();
m_node = smgr->addMeshSceneNode(mesh, NULL); m_node = smgr->addMeshSceneNode(mesh, NULL);
mesh->drop(); mesh->drop();
// Set it to use the materials of the meshbuffers directly.
// This is needed for changing the texture in the future
m_node->setReadOnlyMaterials(true);
updateNodePos(); updateNodePos();
/* /*
Update image of node Update image of node
*/ */
// Create an inventory item to see what is its image updateTexture();
std::istringstream is(m_inventorystring, std::ios_base::binary);
video::ITexture *texture = NULL;
try{
InventoryItem *item = NULL;
item = InventoryItem::deSerialize(is, m_gamedef);
infostream<<__FUNCTION_NAME<<": m_inventorystring=\""
<<m_inventorystring<<"\" -> item="<<item
<<std::endl;
if(item)
{
texture = item->getImage();
delete item;
}
}
catch(SerializationError &e)
{
infostream<<"WARNING: "<<__FUNCTION_NAME
<<": error deSerializing inventorystring \""
<<m_inventorystring<<"\""<<std::endl;
}
// Set meshbuffer texture
buf->getMaterial().setTexture(0, texture);
} }
void ItemCAO::removeFromScene() void ItemCAO::removeFromScene()
@ -662,6 +639,51 @@ void ItemCAO::updateNodePos()
m_node->setPosition(m_position); m_node->setPosition(m_position);
} }
void ItemCAO::updateInfoText()
{
try{
IItemDefManager *idef = m_gamedef->idef();
ItemStack item;
item.deSerialize(m_itemstring, idef);
if(item.isKnown(idef))
m_infotext = item.getDefinition(idef).description;
else
m_infotext = "Unknown item: '" + m_itemstring + "'";
if(item.count >= 2)
m_infotext += " (" + itos(item.count) + ")";
}
catch(SerializationError &e)
{
m_infotext = "Unknown item: '" + m_itemstring + "'";
}
}
void ItemCAO::updateTexture()
{
if(m_node == NULL)
return;
// Create an inventory item to see what is its image
std::istringstream is(m_itemstring, std::ios_base::binary);
video::ITexture *texture = NULL;
try{
IItemDefManager *idef = m_gamedef->idef();
ItemStack item;
item.deSerialize(is, idef);
texture = item.getDefinition(idef).inventory_texture;
}
catch(SerializationError &e)
{
infostream<<"WARNING: "<<__FUNCTION_NAME
<<": error deSerializing itemstring \""
<<m_itemstring<<std::endl;
}
// Set meshbuffer texture
m_node->getMaterial(0).setTexture(0, texture);
}
void ItemCAO::step(float dtime, ClientEnvironment *env) void ItemCAO::step(float dtime, ClientEnvironment *env)
{ {
if(m_node) if(m_node)
@ -689,6 +711,13 @@ void ItemCAO::processMessage(const std::string &data)
m_position = readV3F1000(is); m_position = readV3F1000(is);
updateNodePos(); updateNodePos();
} }
if(cmd == 1)
{
// itemstring
m_itemstring = deSerializeString(is);
updateInfoText();
updateTexture();
}
} }
void ItemCAO::initialize(const std::string &data) void ItemCAO::initialize(const std::string &data)
@ -704,28 +733,12 @@ void ItemCAO::initialize(const std::string &data)
return; return;
// pos // pos
m_position = readV3F1000(is); m_position = readV3F1000(is);
// inventorystring // itemstring
m_inventorystring = deSerializeString(is); m_itemstring = deSerializeString(is);
} }
updateNodePos(); updateNodePos();
updateInfoText();
/*
Set infotext to item name if item cannot be deserialized
*/
try{
InventoryItem *item = NULL;
item = InventoryItem::deSerialize(m_inventorystring, m_gamedef);
if(item){
if(!item->isKnown())
m_infotext = "Unknown item: '" + m_inventorystring + "'";
}
delete item;
}
catch(SerializationError &e)
{
m_infotext = "Unknown item: '" + m_inventorystring + "'";
}
} }
/* /*

@ -20,112 +20,105 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "content_mapblock.h" #include "content_mapblock.h"
#include "main.h" // For g_settings #include "main.h" // For g_settings
#include "mineral.h" #include "mapblock_mesh.h" // For MapBlock_LightColor() and MeshCollector
#include "mapblock_mesh.h" // For MapBlock_LightColor()
#include "settings.h" #include "settings.h"
#include "nodedef.h" #include "nodedef.h"
#include "tile.h"
#include "gamedef.h" #include "gamedef.h"
#ifndef SERVER
// Create a cuboid. // Create a cuboid.
// material - the material to use (for all 6 faces)
// collector - the MeshCollector for the resulting polygons // collector - the MeshCollector for the resulting polygons
// pa - texture atlas pointer for the material // box - the position and size of the box
// materials - the materials to use (for all 6 faces)
// pa - texture atlas pointers for the materials
// matcount - number of entries in "materials" and "pa", 1<=matcount<=6
// c - vertex colour - used for all // c - vertex colour - used for all
// pos - the position of the centre of the cuboid
// rz,ry,rz - the radius of the cuboid in each dimension
// txc - texture coordinates - this is a list of texture coordinates // txc - texture coordinates - this is a list of texture coordinates
// for the opposite corners of each face - therefore, there // for the opposite corners of each face - therefore, there
// should be (2+2)*6=24 values in the list. Alternatively, pass // should be (2+2)*6=24 values in the list. Alternatively, pass
// NULL to use the entire texture for each face. The order of // NULL to use the entire texture for each face. The order of
// the faces in the list is top-backi-right-front-left-bottom // the faces in the list is up-down-right-left-back-front
// If you specified 0,0,1,1 for each face, that would be the // (compatible with ContentFeatures). If you specified 0,0,1,1
// same as passing NULL. // for each face, that would be the same as passing NULL.
void makeCuboid(video::SMaterial &material, MeshCollector *collector, void makeCuboid(MeshCollector *collector, const aabb3f &box,
AtlasPointer* pa, video::SColor &c, const video::SMaterial *materials, const AtlasPointer *pa, int matcount,
v3f &pos, f32 rx, f32 ry, f32 rz, f32* txc) video::SColor &c, const f32* txc)
{ {
f32 tu0=pa->x0(); assert(matcount >= 1);
f32 tu1=pa->x1();
f32 tv0=pa->y0();
f32 tv1=pa->y1();
f32 txus=tu1-tu0;
f32 txvs=tv1-tv0;
video::S3DVertex v[4] = v3f min = box.MinEdge;
v3f max = box.MaxEdge;
if(txc == NULL)
{ {
video::S3DVertex(0,0,0, 0,0,0, c, tu0, tv1), static const f32 txc_default[24] = {
video::S3DVertex(0,0,0, 0,0,0, c, tu1, tv1), 0,0,1,1,
video::S3DVertex(0,0,0, 0,0,0, c, tu1, tv0), 0,0,1,1,
video::S3DVertex(0,0,0, 0,0,0, c, tu0, tv0) 0,0,1,1,
}; 0,0,1,1,
0,0,1,1,
for(int i=0;i<6;i++) 0,0,1,1
{ };
switch(i) txc = txc_default;
{
case 0: // top
v[0].Pos.X=-rx; v[0].Pos.Y= ry; v[0].Pos.Z=-rz;
v[1].Pos.X=-rx; v[1].Pos.Y= ry; v[1].Pos.Z= rz;
v[2].Pos.X= rx; v[2].Pos.Y= ry; v[2].Pos.Z= rz;
v[3].Pos.X= rx; v[3].Pos.Y= ry, v[3].Pos.Z=-rz;
break;
case 1: // back
v[0].Pos.X=-rx; v[0].Pos.Y= ry; v[0].Pos.Z=-rz;
v[1].Pos.X= rx; v[1].Pos.Y= ry; v[1].Pos.Z=-rz;
v[2].Pos.X= rx; v[2].Pos.Y=-ry; v[2].Pos.Z=-rz;
v[3].Pos.X=-rx; v[3].Pos.Y=-ry, v[3].Pos.Z=-rz;
break;
case 2: //right
v[0].Pos.X= rx; v[0].Pos.Y= ry; v[0].Pos.Z=-rz;
v[1].Pos.X= rx; v[1].Pos.Y= ry; v[1].Pos.Z= rz;
v[2].Pos.X= rx; v[2].Pos.Y=-ry; v[2].Pos.Z= rz;
v[3].Pos.X= rx; v[3].Pos.Y=-ry, v[3].Pos.Z=-rz;
break;
case 3: // front
v[0].Pos.X= rx; v[0].Pos.Y= ry; v[0].Pos.Z= rz;
v[1].Pos.X=-rx; v[1].Pos.Y= ry; v[1].Pos.Z= rz;
v[2].Pos.X=-rx; v[2].Pos.Y=-ry; v[2].Pos.Z= rz;
v[3].Pos.X= rx; v[3].Pos.Y=-ry, v[3].Pos.Z= rz;
break;
case 4: // left
v[0].Pos.X=-rx; v[0].Pos.Y= ry; v[0].Pos.Z= rz;
v[1].Pos.X=-rx; v[1].Pos.Y= ry; v[1].Pos.Z=-rz;
v[2].Pos.X=-rx; v[2].Pos.Y=-ry; v[2].Pos.Z=-rz;
v[3].Pos.X=-rx; v[3].Pos.Y=-ry, v[3].Pos.Z= rz;
break;
case 5: // bottom
v[0].Pos.X= rx; v[0].Pos.Y=-ry; v[0].Pos.Z= rz;
v[1].Pos.X=-rx; v[1].Pos.Y=-ry; v[1].Pos.Z= rz;
v[2].Pos.X=-rx; v[2].Pos.Y=-ry; v[2].Pos.Z=-rz;
v[3].Pos.X= rx; v[3].Pos.Y=-ry, v[3].Pos.Z=-rz;
break;
}
if(txc!=NULL)
{
v[0].TCoords.X=tu0+txus*txc[0]; v[0].TCoords.Y=tv0+txvs*txc[3];
v[1].TCoords.X=tu0+txus*txc[2]; v[1].TCoords.Y=tv0+txvs*txc[3];
v[2].TCoords.X=tu0+txus*txc[2]; v[2].TCoords.Y=tv0+txvs*txc[1];
v[3].TCoords.X=tu0+txus*txc[0]; v[3].TCoords.Y=tv0+txvs*txc[1];
txc+=4;
}
for(u16 i=0; i<4; i++)
v[i].Pos += pos;
u16 indices[] = {0,1,2,2,3,0};
collector->append(material, v, 4, indices, 6);
} }
} video::S3DVertex vertices[24] =
#endif {
// up
video::S3DVertex(min.X,max.Y,max.Z, 0,1,0, c, txc[0],txc[1]),
video::S3DVertex(max.X,max.Y,max.Z, 0,1,0, c, txc[2],txc[1]),
video::S3DVertex(max.X,max.Y,min.Z, 0,1,0, c, txc[2],txc[3]),
video::S3DVertex(min.X,max.Y,min.Z, 0,1,0, c, txc[0],txc[3]),
// down
video::S3DVertex(min.X,min.Y,min.Z, 0,-1,0, c, txc[4],txc[5]),
video::S3DVertex(max.X,min.Y,min.Z, 0,-1,0, c, txc[6],txc[5]),
video::S3DVertex(max.X,min.Y,max.Z, 0,-1,0, c, txc[6],txc[7]),
video::S3DVertex(min.X,min.Y,max.Z, 0,-1,0, c, txc[4],txc[7]),
// right
video::S3DVertex(max.X,max.Y,min.Z, 1,0,0, c, txc[ 8],txc[9]),
video::S3DVertex(max.X,max.Y,max.Z, 1,0,0, c, txc[10],txc[9]),
video::S3DVertex(max.X,min.Y,max.Z, 1,0,0, c, txc[10],txc[11]),
video::S3DVertex(max.X,min.Y,min.Z, 1,0,0, c, txc[ 8],txc[11]),
// left
video::S3DVertex(min.X,max.Y,max.Z, -1,0,0, c, txc[12],txc[13]),
video::S3DVertex(min.X,max.Y,min.Z, -1,0,0, c, txc[14],txc[13]),
video::S3DVertex(min.X,min.Y,min.Z, -1,0,0, c, txc[14],txc[15]),
video::S3DVertex(min.X,min.Y,max.Z, -1,0,0, c, txc[12],txc[15]),
// back
video::S3DVertex(min.X,max.Y,min.Z, 0,0,-1, c, txc[16],txc[17]),
video::S3DVertex(max.X,max.Y,min.Z, 0,0,-1, c, txc[18],txc[17]),
video::S3DVertex(max.X,min.Y,min.Z, 0,0,-1, c, txc[18],txc[19]),
video::S3DVertex(min.X,min.Y,min.Z, 0,0,-1, c, txc[16],txc[19]),
// front
video::S3DVertex(max.X,max.Y,max.Z, 0,0,1, c, txc[20],txc[21]),
video::S3DVertex(min.X,max.Y,max.Z, 0,0,1, c, txc[22],txc[21]),
video::S3DVertex(min.X,min.Y,max.Z, 0,0,1, c, txc[22],txc[23]),
video::S3DVertex(max.X,min.Y,max.Z, 0,0,1, c, txc[20],txc[23]),
};
for(s32 j=0; j<24; j++)
{
int matindex = MYMIN(j/4, matcount-1);
vertices[j].TCoords *= pa[matindex].size;
vertices[j].TCoords += pa[matindex].pos;
}
u16 indices[] = {0,1,2,2,3,0};
// Add to mesh collector
for(s32 j=0; j<24; j+=4)
{
int matindex = MYMIN(j/4, matcount-1);
collector->append(materials[matindex],
vertices+j, 4, indices, 6);
}
}
#ifndef SERVER
void mapblock_mesh_generate_special(MeshMakeData *data, void mapblock_mesh_generate_special(MeshMakeData *data,
MeshCollector &collector, IGameDef *gamedef) MeshCollector &collector, IGameDef *gamedef)
{ {
INodeDefManager *nodedef = gamedef->ndef(); INodeDefManager *nodedef = gamedef->ndef();
ITextureSource *tsrc = gamedef->getTextureSource();
// 0ms // 0ms
//TimeTaker timer("mapblock_mesh_generate_special()"); //TimeTaker timer("mapblock_mesh_generate_special()");
@ -521,7 +514,9 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
material_glass.setFlag(video::EMF_BILINEAR_FILTER, false); material_glass.setFlag(video::EMF_BILINEAR_FILTER, false);
material_glass.setFlag(video::EMF_FOG_ENABLE, true); material_glass.setFlag(video::EMF_FOG_ENABLE, true);
material_glass.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF; material_glass.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
AtlasPointer pa_glass = f.tiles[0].texture; TileSpec tile_glass = getNodeTile(n, p, v3s16(0,0,0),
&data->m_temp_mods, tsrc, nodedef);
AtlasPointer pa_glass = tile_glass.texture;
material_glass.setTexture(0, pa_glass.atlas); material_glass.setTexture(0, pa_glass.atlas);
u8 l = decode_light(undiminish_light(n.getLightBlend(data->m_daynight_ratio, nodedef))); u8 l = decode_light(undiminish_light(n.getLightBlend(data->m_daynight_ratio, nodedef)));
@ -585,54 +580,21 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
material_leaves1.setFlag(video::EMF_BILINEAR_FILTER, false); material_leaves1.setFlag(video::EMF_BILINEAR_FILTER, false);
material_leaves1.setFlag(video::EMF_FOG_ENABLE, true); material_leaves1.setFlag(video::EMF_FOG_ENABLE, true);
material_leaves1.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF; material_leaves1.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
AtlasPointer pa_leaves1 = f.tiles[0].texture; TileSpec tile_leaves1 = getNodeTile(n, p, v3s16(0,0,0),
&data->m_temp_mods, tsrc, nodedef);
AtlasPointer pa_leaves1 = tile_leaves1.texture;
material_leaves1.setTexture(0, pa_leaves1.atlas); material_leaves1.setTexture(0, pa_leaves1.atlas);
u8 l = decode_light(undiminish_light(n.getLightBlend(data->m_daynight_ratio, nodedef))); u8 l = decode_light(undiminish_light(n.getLightBlend(data->m_daynight_ratio, nodedef)));
video::SColor c = MapBlock_LightColor(255, l); video::SColor c = MapBlock_LightColor(255, l);
for(u32 j=0; j<6; j++) v3f pos = intToFloat(p+blockpos_nodes, BS);
{ aabb3f box(-BS/2,-BS/2,-BS/2,BS/2,BS/2,BS/2);
video::S3DVertex vertices[4] = box.MinEdge += pos;
{ box.MaxEdge += pos;
video::S3DVertex(-BS/2,-BS/2,BS/2, 0,0,0, c, makeCuboid(&collector, box,
pa_leaves1.x0(), pa_leaves1.y1()), &material_leaves1, &pa_leaves1, 1,
video::S3DVertex(BS/2,-BS/2,BS/2, 0,0,0, c, c, NULL);
pa_leaves1.x1(), pa_leaves1.y1()),
video::S3DVertex(BS/2,BS/2,BS/2, 0,0,0, c,
pa_leaves1.x1(), pa_leaves1.y0()),
video::S3DVertex(-BS/2,BS/2,BS/2, 0,0,0, c,
pa_leaves1.x0(), pa_leaves1.y0()),
};
// Rotations in the g_6dirs format
if(j == 0) // Z+
for(u16 i=0; i<4; i++)
vertices[i].Pos.rotateXZBy(0);
else if(j == 1) // Y+
for(u16 i=0; i<4; i++)
vertices[i].Pos.rotateYZBy(-90);
else if(j == 2) // X+
for(u16 i=0; i<4; i++)
vertices[i].Pos.rotateXZBy(-90);
else if(j == 3) // Z-
for(u16 i=0; i<4; i++)
vertices[i].Pos.rotateXZBy(180);
else if(j == 4) // Y-
for(u16 i=0; i<4; i++)
vertices[i].Pos.rotateYZBy(90);
else if(j == 5) // X-
for(u16 i=0; i<4; i++)
vertices[i].Pos.rotateXZBy(90);
for(u16 i=0; i<4; i++){
vertices[i].Pos += intToFloat(p + blockpos_nodes, BS);
}
u16 indices[] = {0,1,2,2,3,0};
// Add to mesh collector
collector.append(material_leaves1, vertices, 4, indices, 6);
}
break;} break;}
case NDT_ALLFACES_OPTIONAL: case NDT_ALLFACES_OPTIONAL:
// This is always pre-converted to something else // This is always pre-converted to something else
@ -824,9 +786,22 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
material_wood.setFlag(video::EMF_BILINEAR_FILTER, false); material_wood.setFlag(video::EMF_BILINEAR_FILTER, false);
material_wood.setFlag(video::EMF_FOG_ENABLE, true); material_wood.setFlag(video::EMF_FOG_ENABLE, true);
material_wood.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF; material_wood.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
AtlasPointer pa_wood = f.tiles[0].texture; TileSpec tile_wood = getNodeTile(n, p, v3s16(0,0,0),
&data->m_temp_mods, tsrc, nodedef);
AtlasPointer pa_wood = tile_wood.texture;
material_wood.setTexture(0, pa_wood.atlas); material_wood.setTexture(0, pa_wood.atlas);
video::SMaterial material_wood_nomod;
material_wood_nomod.setFlag(video::EMF_LIGHTING, false);
material_wood_nomod.setFlag(video::EMF_BILINEAR_FILTER, false);
material_wood_nomod.setFlag(video::EMF_FOG_ENABLE, true);
material_wood_nomod.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
TileSpec tile_wood_nomod = getNodeTile(n, p, v3s16(0,0,0),
NULL, tsrc, nodedef);
AtlasPointer pa_wood_nomod = tile_wood_nomod.texture;
material_wood_nomod.setTexture(0, pa_wood_nomod.atlas);
u8 l = decode_light(undiminish_light(n.getLightBlend(data->m_daynight_ratio, nodedef))); u8 l = decode_light(undiminish_light(n.getLightBlend(data->m_daynight_ratio, nodedef)));
video::SColor c = MapBlock_LightColor(255, l); video::SColor c = MapBlock_LightColor(255, l);
@ -834,18 +809,21 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
const f32 bar_rad=(f32)BS/20; const f32 bar_rad=(f32)BS/20;
const f32 bar_len=(f32)(BS/2)-post_rad; const f32 bar_len=(f32)(BS/2)-post_rad;
// The post - always present
v3f pos = intToFloat(p+blockpos_nodes, BS); v3f pos = intToFloat(p+blockpos_nodes, BS);
// The post - always present
aabb3f post(-post_rad,-BS/2,-post_rad,post_rad,BS/2,post_rad);
post.MinEdge += pos;
post.MaxEdge += pos;
f32 postuv[24]={ f32 postuv[24]={
0.4,0.4,0.6,0.6,
0.4,0.4,0.6,0.6, 0.4,0.4,0.6,0.6,
0.35,0,0.65,1, 0.35,0,0.65,1,
0.35,0,0.65,1, 0.35,0,0.65,1,
0.35,0,0.65,1, 0.35,0,0.65,1,
0.35,0,0.65,1, 0.35,0,0.65,1};
0.4,0.4,0.6,0.6}; makeCuboid(&collector, post, &material_wood,
makeCuboid(material_wood, &collector, &pa_wood, 1, c, postuv);
&pa_wood, c, pos,
post_rad,BS/2,post_rad, postuv);
// Now a section of fence, +X, if there's a post there // Now a section of fence, +X, if there's a post there
v3s16 p2 = p; v3s16 p2 = p;
@ -854,9 +832,10 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
const ContentFeatures *f2 = &nodedef->get(n2); const ContentFeatures *f2 = &nodedef->get(n2);
if(f2->drawtype == NDT_FENCELIKE) if(f2->drawtype == NDT_FENCELIKE)
{ {
pos = intToFloat(p+blockpos_nodes, BS); aabb3f bar(-bar_len+BS/2,-bar_rad+BS/4,-bar_rad,
pos.X += BS/2; bar_len+BS/2,bar_rad+BS/4,bar_rad);
pos.Y += BS/4; bar.MinEdge += pos;
bar.MaxEdge += pos;
f32 xrailuv[24]={ f32 xrailuv[24]={
0,0.4,1,0.6, 0,0.4,1,0.6,
0,0.4,1,0.6, 0,0.4,1,0.6,
@ -864,14 +843,12 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
0,0.4,1,0.6, 0,0.4,1,0.6,
0,0.4,1,0.6, 0,0.4,1,0.6,
0,0.4,1,0.6}; 0,0.4,1,0.6};
makeCuboid(material_wood, &collector, makeCuboid(&collector, bar, &material_wood_nomod,
&pa_wood, c, pos, &pa_wood_nomod, 1, c, xrailuv);
bar_len,bar_rad,bar_rad, xrailuv); bar.MinEdge.Y -= BS/2;
bar.MaxEdge.Y -= BS/2;
pos.Y -= BS/2; makeCuboid(&collector, bar, &material_wood_nomod,
makeCuboid(material_wood, &collector, &pa_wood_nomod, 1, c, xrailuv);
&pa_wood, c, pos,
bar_len,bar_rad,bar_rad, xrailuv);
} }
// Now a section of fence, +Z, if there's a post there // Now a section of fence, +Z, if there's a post there
@ -881,9 +858,10 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
f2 = &nodedef->get(n2); f2 = &nodedef->get(n2);
if(f2->drawtype == NDT_FENCELIKE) if(f2->drawtype == NDT_FENCELIKE)
{ {
pos = intToFloat(p+blockpos_nodes, BS); aabb3f bar(-bar_rad,-bar_rad+BS/4,-bar_len+BS/2,
pos.Z += BS/2; bar_rad,bar_rad+BS/4,bar_len+BS/2);
pos.Y += BS/4; bar.MinEdge += pos;
bar.MaxEdge += pos;
f32 zrailuv[24]={ f32 zrailuv[24]={
0,0.4,1,0.6, 0,0.4,1,0.6,
0,0.4,1,0.6, 0,0.4,1,0.6,
@ -891,14 +869,13 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
0,0.4,1,0.6, 0,0.4,1,0.6,
0,0.4,1,0.6, 0,0.4,1,0.6,
0,0.4,1,0.6}; 0,0.4,1,0.6};
makeCuboid(material_wood, &collector,
&pa_wood, c, pos,
bar_rad,bar_rad,bar_len, zrailuv);
pos.Y -= BS/2;
makeCuboid(material_wood, &collector,
&pa_wood, c, pos,
bar_rad,bar_rad,bar_len, zrailuv);
makeCuboid(&collector, bar, &material_wood_nomod,
&pa_wood_nomod, 1, c, zrailuv);
bar.MinEdge.Y -= BS/2;
bar.MaxEdge.Y -= BS/2;
makeCuboid(&collector, bar, &material_wood_nomod,
&pa_wood_nomod, 1, c, zrailuv);
} }
break;} break;}
case NDT_RAILLIKE: case NDT_RAILLIKE:
@ -1011,5 +988,4 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
} }
} }
} }
#endif

@ -26,75 +26,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "nameidmapping.h" #include "nameidmapping.h"
#include <map> #include <map>
/*
Legacy node definitions
*/
#define WATER_ALPHA 160
#define WATER_VISC 1
#define LAVA_VISC 7
void setConstantMaterialProperties(MaterialProperties &mprop, float time)
{
mprop.diggability = DIGGABLE_CONSTANT;
mprop.constant_time = time;
}
void setStoneLikeMaterialProperties(MaterialProperties &mprop, float toughness)
{
mprop.diggability = DIGGABLE_NORMAL;
mprop.weight = 5.0 * toughness;
mprop.crackiness = 1.0;
mprop.crumbliness = -0.1;
mprop.cuttability = -0.2;
}
void setDirtLikeMaterialProperties(MaterialProperties &mprop, float toughness)
{
mprop.diggability = DIGGABLE_NORMAL;
mprop.weight = toughness * 1.2;
mprop.crackiness = 0;
mprop.crumbliness = 1.2;
mprop.cuttability = -0.4;
}
void setGravelLikeMaterialProperties(MaterialProperties &mprop, float toughness)
{
mprop.diggability = DIGGABLE_NORMAL;
mprop.weight = toughness * 2.0;
mprop.crackiness = 0.2;
mprop.crumbliness = 1.5;
mprop.cuttability = -1.0;
}
void setWoodLikeMaterialProperties(MaterialProperties &mprop, float toughness)
{
mprop.diggability = DIGGABLE_NORMAL;
mprop.weight = toughness * 1.0;
mprop.crackiness = 0.75;
mprop.crumbliness = -1.0;
mprop.cuttability = 1.5;
}
void setLeavesLikeMaterialProperties(MaterialProperties &mprop, float toughness)
{
mprop.diggability = DIGGABLE_NORMAL;
mprop.weight = -0.5 * toughness;
mprop.crackiness = 0;
mprop.crumbliness = 0;
mprop.cuttability = 2.0;
}
void setGlassLikeMaterialProperties(MaterialProperties &mprop, float toughness)
{
mprop.diggability = DIGGABLE_NORMAL;
mprop.weight = 0.1 * toughness;
mprop.crackiness = 2.0;
mprop.crumbliness = -1.0;
mprop.cuttability = -1.0;
}
/* /*
Legacy node content type IDs Legacy node content type IDs
Ranges: Ranges:
@ -209,46 +140,46 @@ MapNode mapnode_translate_to_internal(MapNode n_from, u8 version)
void content_mapnode_get_name_id_mapping(NameIdMapping *nimap) void content_mapnode_get_name_id_mapping(NameIdMapping *nimap)
{ {
nimap->set(0, "stone"); nimap->set(0, "default:stone");
nimap->set(2, "water_flowing"); nimap->set(2, "default:water_flowing");
nimap->set(3, "torch"); nimap->set(3, "default:torch");
nimap->set(9, "water_source"); nimap->set(9, "default:water_source");
nimap->set(14, "sign_wall"); nimap->set(14, "default:sign_wall");
nimap->set(15, "chest"); nimap->set(15, "default:chest");
nimap->set(16, "furnace"); nimap->set(16, "default:furnace");
nimap->set(17, "locked_chest"); nimap->set(17, "default:chest_locked");
nimap->set(21, "wooden_fence"); nimap->set(21, "default:fence_wood");
nimap->set(30, "rail"); nimap->set(30, "default:rail");
nimap->set(31, "ladder"); nimap->set(31, "default:ladder");
nimap->set(32, "lava_flowing"); nimap->set(32, "default:lava_flowing");
nimap->set(33, "lava_source"); nimap->set(33, "default:lava_source");
nimap->set(0x800, "dirt_with_grass"); nimap->set(0x800, "default:dirt_with_grass");
nimap->set(0x801, "tree"); nimap->set(0x801, "default:tree");
nimap->set(0x802, "leaves"); nimap->set(0x802, "default:leaves");
nimap->set(0x803, "dirt_with_grass_footsteps"); nimap->set(0x803, "default:dirt_with_grass_footsteps");
nimap->set(0x804, "mese"); nimap->set(0x804, "default:mese");
nimap->set(0x805, "dirt"); nimap->set(0x805, "default:dirt");
nimap->set(0x806, "cloud"); nimap->set(0x806, "default:cloud");
nimap->set(0x807, "coalstone"); nimap->set(0x807, "default:coalstone");
nimap->set(0x808, "wood"); nimap->set(0x808, "default:wood");
nimap->set(0x809, "sand"); nimap->set(0x809, "default:sand");
nimap->set(0x80a, "cobble"); nimap->set(0x80a, "default:cobble");
nimap->set(0x80b, "steel"); nimap->set(0x80b, "default:steelblock");
nimap->set(0x80c, "glass"); nimap->set(0x80c, "default:glass");
nimap->set(0x80d, "mossycobble"); nimap->set(0x80d, "default:mossycobble");
nimap->set(0x80e, "gravel"); nimap->set(0x80e, "default:gravel");
nimap->set(0x80f, "sandstone"); nimap->set(0x80f, "default:sandstone");
nimap->set(0x810, "cactus"); nimap->set(0x810, "default:cactus");
nimap->set(0x811, "brick"); nimap->set(0x811, "default:brick");
nimap->set(0x812, "clay"); nimap->set(0x812, "default:clay");
nimap->set(0x813, "papyrus"); nimap->set(0x813, "default:papyrus");
nimap->set(0x814, "bookshelf"); nimap->set(0x814, "default:bookshelf");
nimap->set(0x815, "jungletree"); nimap->set(0x815, "default:jungletree");
nimap->set(0x816, "junglegrass"); nimap->set(0x816, "default:junglegrass");
nimap->set(0x817, "nyancat"); nimap->set(0x817, "default:nyancat");
nimap->set(0x818, "nyancat_rainbow"); nimap->set(0x818, "default:nyancat_rainbow");
nimap->set(0x819, "apple"); nimap->set(0x819, "default:apple");
nimap->set(0x820, "sapling"); nimap->set(0x820, "default:sapling");
// Static types // Static types
nimap->set(CONTENT_IGNORE, "ignore"); nimap->set(CONTENT_IGNORE, "ignore");
nimap->set(CONTENT_AIR, "air"); nimap->set(CONTENT_AIR, "air");
@ -259,46 +190,46 @@ class NewNameGetter
public: public:
NewNameGetter() NewNameGetter()
{ {
old_to_new["CONTENT_STONE"] = "stone"; old_to_new["CONTENT_STONE"] = "default:stone";
old_to_new["CONTENT_WATER"] = "water_flowing"; old_to_new["CONTENT_WATER"] = "default:water_flowing";
old_to_new["CONTENT_TORCH"] = "torch"; old_to_new["CONTENT_TORCH"] = "default:torch";
old_to_new["CONTENT_WATERSOURCE"] = "water_source"; old_to_new["CONTENT_WATERSOURCE"] = "default:water_source";
old_to_new["CONTENT_SIGN_WALL"] = "sign_wall"; old_to_new["CONTENT_SIGN_WALL"] = "default:sign_wall";
old_to_new["CONTENT_CHEST"] = "chest"; old_to_new["CONTENT_CHEST"] = "default:chest";
old_to_new["CONTENT_FURNACE"] = "furnace"; old_to_new["CONTENT_FURNACE"] = "default:furnace";
old_to_new["CONTENT_LOCKABLE_CHEST"] = "locked_chest"; old_to_new["CONTENT_LOCKABLE_CHEST"] = "default:locked_chest";
old_to_new["CONTENT_FENCE"] = "wooden_fence"; old_to_new["CONTENT_FENCE"] = "default:wooden_fence";
old_to_new["CONTENT_RAIL"] = "rail"; old_to_new["CONTENT_RAIL"] = "default:rail";
old_to_new["CONTENT_LADDER"] = "ladder"; old_to_new["CONTENT_LADDER"] = "default:ladder";
old_to_new["CONTENT_LAVA"] = "lava_flowing"; old_to_new["CONTENT_LAVA"] = "default:lava_flowing";
old_to_new["CONTENT_LAVASOURCE"] = "lava_source"; old_to_new["CONTENT_LAVASOURCE"] = "default:lava_source";
old_to_new["CONTENT_GRASS"] = "dirt_with_grass"; old_to_new["CONTENT_GRASS"] = "default:dirt_with_grass";
old_to_new["CONTENT_TREE"] = "tree"; old_to_new["CONTENT_TREE"] = "default:tree";
old_to_new["CONTENT_LEAVES"] = "leaves"; old_to_new["CONTENT_LEAVES"] = "default:leaves";
old_to_new["CONTENT_GRASS_FOOTSTEPS"] = "dirt_with_grass_footsteps"; old_to_new["CONTENT_GRASS_FOOTSTEPS"] = "default:dirt_with_grass_footsteps";
old_to_new["CONTENT_MESE"] = "mese"; old_to_new["CONTENT_MESE"] = "default:mese";
old_to_new["CONTENT_MUD"] = "dirt"; old_to_new["CONTENT_MUD"] = "default:dirt";
old_to_new["CONTENT_CLOUD"] = "cloud"; old_to_new["CONTENT_CLOUD"] = "default:cloud";
old_to_new["CONTENT_COALSTONE"] = "coalstone"; old_to_new["CONTENT_COALSTONE"] = "default:coalstone";
old_to_new["CONTENT_WOOD"] = "wood"; old_to_new["CONTENT_WOOD"] = "default:wood";
old_to_new["CONTENT_SAND"] = "sand"; old_to_new["CONTENT_SAND"] = "default:sand";
old_to_new["CONTENT_COBBLE"] = "cobble"; old_to_new["CONTENT_COBBLE"] = "default:cobble";
old_to_new["CONTENT_STEEL"] = "steel"; old_to_new["CONTENT_STEEL"] = "default:steel";
old_to_new["CONTENT_GLASS"] = "glass"; old_to_new["CONTENT_GLASS"] = "default:glass";
old_to_new["CONTENT_MOSSYCOBBLE"] = "mossycobble"; old_to_new["CONTENT_MOSSYCOBBLE"] = "default:mossycobble";
old_to_new["CONTENT_GRAVEL"] = "gravel"; old_to_new["CONTENT_GRAVEL"] = "default:gravel";
old_to_new["CONTENT_SANDSTONE"] = "sandstone"; old_to_new["CONTENT_SANDSTONE"] = "default:sandstone";
old_to_new["CONTENT_CACTUS"] = "cactus"; old_to_new["CONTENT_CACTUS"] = "default:cactus";
old_to_new["CONTENT_BRICK"] = "brick"; old_to_new["CONTENT_BRICK"] = "default:brick";
old_to_new["CONTENT_CLAY"] = "clay"; old_to_new["CONTENT_CLAY"] = "default:clay";
old_to_new["CONTENT_PAPYRUS"] = "papyrus"; old_to_new["CONTENT_PAPYRUS"] = "default:papyrus";
old_to_new["CONTENT_BOOKSHELF"] = "bookshelf"; old_to_new["CONTENT_BOOKSHELF"] = "default:bookshelf";
old_to_new["CONTENT_JUNGLETREE"] = "jungletree"; old_to_new["CONTENT_JUNGLETREE"] = "default:jungletree";
old_to_new["CONTENT_JUNGLEGRASS"] = "junglegrass"; old_to_new["CONTENT_JUNGLEGRASS"] = "default:junglegrass";
old_to_new["CONTENT_NC"] = "nyancat"; old_to_new["CONTENT_NC"] = "default:nyancat";
old_to_new["CONTENT_NC_RB"] = "nyancat_rainbow"; old_to_new["CONTENT_NC_RB"] = "default:nyancat_rainbow";
old_to_new["CONTENT_APPLE"] = "apple"; old_to_new["CONTENT_APPLE"] = "default:apple";
old_to_new["CONTENT_SAPLING"] = "sapling"; old_to_new["CONTENT_SAPLING"] = "default:sapling";
// Just in case // Just in case
old_to_new["CONTENT_IGNORE"] = "ignore"; old_to_new["CONTENT_IGNORE"] = "ignore";
old_to_new["CONTENT_AIR"] = "air"; old_to_new["CONTENT_AIR"] = "air";
@ -334,605 +265,3 @@ content_t legacy_get_id(const std::string &oldname, INodeDefManager *ndef)
return id; return id;
} }
// Initialize default (legacy) node definitions
void content_mapnode_init(IWritableNodeDefManager *nodemgr)
{
content_t i;
ContentFeatures f;
i = CONTENT_STONE;
f = ContentFeatures();
f.name = "stone";
f.setAllTextures("stone.png");
f.setInventoryTextureCube("stone.png", "stone.png", "stone.png");
f.param_type = CPT_MINERAL;
f.is_ground_content = true;
f.often_contains_mineral = true;
f.dug_item = std::string("MaterialItem2 ")+itos(CONTENT_COBBLE)+" 1";
setStoneLikeMaterialProperties(f.material, 1.0);
nodemgr->set(i, f);
i = CONTENT_GRASS;
f = ContentFeatures();
f.name = "dirt_with_grass";
f.setAllTextures("mud.png^grass_side.png");
f.setTexture(0, "grass.png");
f.setTexture(1, "mud.png");
f.param_type = CPT_MINERAL;
f.is_ground_content = true;
f.dug_item = std::string("MaterialItem2 ")+itos(CONTENT_MUD)+" 1";
setDirtLikeMaterialProperties(f.material, 1.0);
nodemgr->set(i, f);
i = CONTENT_GRASS_FOOTSTEPS;
f = ContentFeatures();
f.name = "dirt_with_grass_footsteps";
f.setAllTextures("mud.png^grass_side.png");
f.setTexture(0, "grass_footsteps.png");
f.setTexture(1, "mud.png");
f.param_type = CPT_MINERAL;
f.is_ground_content = true;
f.dug_item = std::string("MaterialItem2 ")+itos(CONTENT_MUD)+" 1";
setDirtLikeMaterialProperties(f.material, 1.0);
nodemgr->set(i, f);
i = CONTENT_MUD;
f = ContentFeatures();
f.name = "dirt";
f.setAllTextures("mud.png");
f.setInventoryTextureCube("mud.png", "mud.png", "mud.png");
f.param_type = CPT_MINERAL;
f.is_ground_content = true;
f.dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
setDirtLikeMaterialProperties(f.material, 1.0);
nodemgr->set(i, f);
i = CONTENT_SAND;
f = ContentFeatures();
f.name = "sand";
f.setAllTextures("sand.png");
f.setInventoryTextureCube("sand.png", "sand.png", "sand.png");
f.param_type = CPT_MINERAL;
f.is_ground_content = true;
f.dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
f.cookresult_item = std::string("MaterialItem2 ")+itos(CONTENT_GLASS)+" 1";
setDirtLikeMaterialProperties(f.material, 1.0);
nodemgr->set(i, f);
i = CONTENT_GRAVEL;
f = ContentFeatures();
f.name = "gravel";
f.setAllTextures("gravel.png");
f.setInventoryTextureCube("gravel.png", "gravel.png", "gravel.png");
f.param_type = CPT_MINERAL;
f.is_ground_content = true;
f.dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
setGravelLikeMaterialProperties(f.material, 1.0);
nodemgr->set(i, f);
i = CONTENT_SANDSTONE;
f = ContentFeatures();
f.name = "sandstone";
f.setAllTextures("sandstone.png");
f.setInventoryTextureCube("sandstone.png", "sandstone.png", "sandstone.png");
f.param_type = CPT_MINERAL;
f.is_ground_content = true;
f.dug_item = std::string("MaterialItem2 ")+itos(CONTENT_SAND)+" 1";
setDirtLikeMaterialProperties(f.material, 1.0);
nodemgr->set(i, f);
i = CONTENT_CLAY;
f = ContentFeatures();
f.name = "clay";
f.setAllTextures("clay.png");
f.setInventoryTextureCube("clay.png", "clay.png", "clay.png");
f.param_type = CPT_MINERAL;
f.is_ground_content = true;
f.dug_item = std::string("CraftItem lump_of_clay 4");
setDirtLikeMaterialProperties(f.material, 1.0);
nodemgr->set(i, f);
i = CONTENT_BRICK;
f = ContentFeatures();
f.name = "brick";
f.setAllTextures("brick.png");
f.setInventoryTextureCube("brick.png", "brick.png", "brick.png");
f.param_type = CPT_MINERAL;
f.is_ground_content = true;
f.dug_item = std::string("CraftItem clay_brick 4");
setStoneLikeMaterialProperties(f.material, 1.0);
nodemgr->set(i, f);
i = CONTENT_TREE;
f = ContentFeatures();
f.name = "tree";
f.setAllTextures("tree.png");
f.setTexture(0, "tree_top.png");
f.setTexture(1, "tree_top.png");
f.param_type = CPT_MINERAL;
f.is_ground_content = true;
f.dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
f.cookresult_item = "CraftItem lump_of_coal 1";
f.furnace_burntime = 30;
setWoodLikeMaterialProperties(f.material, 1.0);
nodemgr->set(i, f);
i = CONTENT_JUNGLETREE;
f = ContentFeatures();
f.name = "jungletree";
f.setAllTextures("jungletree.png");
f.setTexture(0, "jungletree_top.png");
f.setTexture(1, "jungletree_top.png");
f.param_type = CPT_MINERAL;
f.dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
f.furnace_burntime = 30;
setWoodLikeMaterialProperties(f.material, 1.0);
nodemgr->set(i, f);
i = CONTENT_JUNGLEGRASS;
f = ContentFeatures();
f.name = "junglegrass";
f.drawtype = NDT_PLANTLIKE;
f.visual_scale = 1.3;
f.setAllTextures("junglegrass.png");
f.setInventoryTexture("junglegrass.png");
f.light_propagates = true;
f.param_type = CPT_LIGHT;
f.dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
f.walkable = false;
setLeavesLikeMaterialProperties(f.material, 1.0);
f.furnace_burntime = 2;
nodemgr->set(i, f);
i = CONTENT_LEAVES;
f = ContentFeatures();
f.name = "leaves";
f.drawtype = NDT_ALLFACES_OPTIONAL;
f.setAllTextures("leaves.png");
//f.setAllTextures("[noalpha:leaves.png");
f.light_propagates = true;
f.param_type = CPT_LIGHT;
f.extra_dug_item = std::string("MaterialItem2 ")+itos(CONTENT_SAPLING)+" 1";
f.extra_dug_item_rarity = 20;
f.dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
setLeavesLikeMaterialProperties(f.material, 1.0);
f.furnace_burntime = 1.0;
nodemgr->set(i, f);
i = CONTENT_CACTUS;
f = ContentFeatures();
f.name = "cactus";
f.setAllTextures("cactus_side.png");
f.setTexture(0, "cactus_top.png");
f.setTexture(1, "cactus_top.png");
f.setInventoryTextureCube("cactus_top.png", "cactus_side.png", "cactus_side.png");
f.param_type = CPT_MINERAL;
f.is_ground_content = true;
f.dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
setWoodLikeMaterialProperties(f.material, 0.75);
f.furnace_burntime = 15;
nodemgr->set(i, f);
i = CONTENT_PAPYRUS;
f = ContentFeatures();
f.name = "papyrus";
f.drawtype = NDT_PLANTLIKE;
f.setAllTextures("papyrus.png");
f.setInventoryTexture("papyrus.png");
f.light_propagates = true;
f.param_type = CPT_LIGHT;
f.is_ground_content = true;
f.dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
f.walkable = false;
setLeavesLikeMaterialProperties(f.material, 0.5);
f.furnace_burntime = 1;
nodemgr->set(i, f);
i = CONTENT_BOOKSHELF;
f = ContentFeatures();
f.name = "bookshelf";
f.setAllTextures("bookshelf.png");
f.setTexture(0, "wood.png");
f.setTexture(1, "wood.png");
// FIXME: setInventoryTextureCube() only cares for the first texture
f.setInventoryTextureCube("bookshelf.png", "bookshelf.png", "bookshelf.png");
//f.setInventoryTextureCube("wood.png", "bookshelf.png", "bookshelf.png");
f.param_type = CPT_MINERAL;
f.is_ground_content = true;
setWoodLikeMaterialProperties(f.material, 0.75);
f.furnace_burntime = 30;
nodemgr->set(i, f);
i = CONTENT_GLASS;
f = ContentFeatures();
f.name = "glass";
f.drawtype = NDT_GLASSLIKE;
f.setAllTextures("glass.png");
f.light_propagates = true;
f.sunlight_propagates = true;
f.param_type = CPT_LIGHT;
f.is_ground_content = true;
f.dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
f.setInventoryTextureCube("glass.png", "glass.png", "glass.png");
setGlassLikeMaterialProperties(f.material, 1.0);
nodemgr->set(i, f);
i = CONTENT_FENCE;
f = ContentFeatures();
f.name = "wooden_fence";
f.drawtype = NDT_FENCELIKE;
f.setInventoryTexture("fence.png");
f.setTexture(0, "wood.png");
f.light_propagates = true;
f.param_type = CPT_LIGHT;
f.is_ground_content = true;
f.dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
f.selection_box.type = NODEBOX_FIXED;
f.selection_box.fixed = core::aabbox3d<f32>(
-BS/7, -BS/2, -BS/7, BS/7, BS/2, BS/7);
f.furnace_burntime = 30/2;
setWoodLikeMaterialProperties(f.material, 0.75);
nodemgr->set(i, f);
i = CONTENT_RAIL;
f = ContentFeatures();
f.name = "rail";
f.drawtype = NDT_RAILLIKE;
f.setInventoryTexture("rail.png");
f.setTexture(0, "rail.png");
f.setTexture(1, "rail_curved.png");
f.setTexture(2, "rail_t_junction.png");
f.setTexture(3, "rail_crossing.png");
f.light_propagates = true;
f.param_type = CPT_LIGHT;
f.is_ground_content = true;
f.dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
f.walkable = false;
f.selection_box.type = NODEBOX_FIXED;
f.furnace_burntime = 5;
setDirtLikeMaterialProperties(f.material, 0.75);
nodemgr->set(i, f);
i = CONTENT_LADDER;
f = ContentFeatures();
f.name = "ladder";
f.drawtype = NDT_SIGNLIKE;
f.setAllTextures("ladder.png");
f.setInventoryTexture("ladder.png");
f.light_propagates = true;
f.param_type = CPT_LIGHT;
f.is_ground_content = true;
f.dug_item = std::string("MaterialItem ")+itos(i)+" 1";
f.wall_mounted = true;
f.walkable = false;
f.climbable = true;
f.selection_box.type = NODEBOX_WALLMOUNTED;
f.furnace_burntime = 5;
setWoodLikeMaterialProperties(f.material, 0.5);
nodemgr->set(i, f);
i = CONTENT_COALSTONE;
f = ContentFeatures();
f.name = "coalstone";
f.setAllTextures("stone.png^mineral_coal.png");
f.is_ground_content = true;
setStoneLikeMaterialProperties(f.material, 1.5);
nodemgr->set(i, f);
i = CONTENT_WOOD;
f = ContentFeatures();
f.name = "wood";
f.setAllTextures("wood.png");
f.setInventoryTextureCube("wood.png", "wood.png", "wood.png");
f.is_ground_content = true;
f.dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
f.furnace_burntime = 30/4;
setWoodLikeMaterialProperties(f.material, 0.75);
nodemgr->set(i, f);
i = CONTENT_MESE;
f = ContentFeatures();
f.name = "mese";
f.setAllTextures("mese.png");
f.setInventoryTextureCube("mese.png", "mese.png", "mese.png");
f.is_ground_content = true;
f.dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
f.furnace_burntime = 30;
setStoneLikeMaterialProperties(f.material, 0.5);
nodemgr->set(i, f);
i = CONTENT_CLOUD;
f = ContentFeatures();
f.name = "cloud";
f.setAllTextures("cloud.png");
f.setInventoryTextureCube("cloud.png", "cloud.png", "cloud.png");
f.is_ground_content = true;
f.dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
nodemgr->set(i, f);
i = CONTENT_AIR;
f = ContentFeatures();
f.name = "air";
f.param_type = CPT_LIGHT;
f.light_propagates = true;
f.sunlight_propagates = true;
f.walkable = false;
f.pointable = false;
f.diggable = false;
f.buildable_to = true;
nodemgr->set(i, f);
i = CONTENT_WATER;
f = ContentFeatures();
f.name = "water_flowing";
f.drawtype = NDT_FLOWINGLIQUID;
f.setAllTextures("water.png");
f.alpha = WATER_ALPHA;
f.setInventoryTextureCube("water.png", "water.png", "water.png");
f.param_type = CPT_LIGHT;
f.light_propagates = true;
f.walkable = false;
f.pointable = false;
f.diggable = false;
f.buildable_to = true;
f.liquid_type = LIQUID_FLOWING;
f.liquid_alternative_flowing = "water_flowing";
f.liquid_alternative_source = "water_source";
f.liquid_viscosity = WATER_VISC;
f.post_effect_color = video::SColor(64, 100, 100, 200);
f.setSpecialMaterial(0, MaterialSpec("water.png", false));
f.setSpecialMaterial(1, MaterialSpec("water.png", true));
nodemgr->set(i, f);
i = CONTENT_WATERSOURCE;
f = ContentFeatures();
f.name = "water_source";
f.drawtype = NDT_LIQUID;
f.setAllTextures("water.png");
f.alpha = WATER_ALPHA;
f.setInventoryTextureCube("water.png", "water.png", "water.png");
f.param_type = CPT_LIGHT;
f.light_propagates = true;
f.walkable = false;
f.pointable = false;
f.diggable = false;
f.buildable_to = true;
f.liquid_type = LIQUID_SOURCE;
f.dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
f.liquid_alternative_flowing = "water_flowing";
f.liquid_alternative_source = "water_source";
f.liquid_viscosity = WATER_VISC;
f.post_effect_color = video::SColor(64, 100, 100, 200);
// New-style water source material (mostly unused)
f.setSpecialMaterial(0, MaterialSpec("water.png", false));
nodemgr->set(i, f);
i = CONTENT_LAVA;
f = ContentFeatures();
f.name = "lava_flowing";
f.drawtype = NDT_FLOWINGLIQUID;
f.setAllTextures("lava.png");
f.setInventoryTextureCube("lava.png", "lava.png", "lava.png");
f.param_type = CPT_LIGHT;
f.light_propagates = false;
f.light_source = LIGHT_MAX-1;
f.walkable = false;
f.pointable = false;
f.diggable = false;
f.buildable_to = true;
f.liquid_type = LIQUID_FLOWING;
f.liquid_alternative_flowing = "lava_flowing";
f.liquid_alternative_source = "lava_source";
f.liquid_viscosity = LAVA_VISC;
f.damage_per_second = 4*2;
f.post_effect_color = video::SColor(192, 255, 64, 0);
f.setSpecialMaterial(0, MaterialSpec("lava.png", false));
f.setSpecialMaterial(1, MaterialSpec("lava.png", true));
nodemgr->set(i, f);
i = CONTENT_LAVASOURCE;
f = ContentFeatures();
f.name = "lava_source";
f.drawtype = NDT_LIQUID;
f.setAllTextures("lava.png");
f.setInventoryTextureCube("lava.png", "lava.png", "lava.png");
f.param_type = CPT_LIGHT;
f.light_propagates = false;
f.light_source = LIGHT_MAX-1;
f.walkable = false;
f.pointable = false;
f.diggable = false;
f.buildable_to = true;
f.liquid_type = LIQUID_SOURCE;
f.dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
f.liquid_alternative_flowing = "lava_flowing";
f.liquid_alternative_source = "lava_source";
f.liquid_viscosity = LAVA_VISC;
f.damage_per_second = 4*2;
f.post_effect_color = video::SColor(192, 255, 64, 0);
// New-style lava source material (mostly unused)
f.setSpecialMaterial(0, MaterialSpec("lava.png", false));
f.furnace_burntime = 60;
nodemgr->set(i, f);
i = CONTENT_TORCH;
f = ContentFeatures();
f.name = "torch";
f.drawtype = NDT_TORCHLIKE;
f.setTexture(0, "torch_on_floor.png");
f.setTexture(1, "torch_on_ceiling.png");
f.setTexture(2, "torch.png");
f.setInventoryTexture("torch_on_floor.png");
f.param_type = CPT_LIGHT;
f.light_propagates = true;
f.sunlight_propagates = true;
f.walkable = false;
f.wall_mounted = true;
f.dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
f.light_source = LIGHT_MAX-1;
f.selection_box.type = NODEBOX_WALLMOUNTED;
f.selection_box.wall_top = core::aabbox3d<f32>(
-BS/10, BS/2-BS/3.333*2, -BS/10, BS/10, BS/2, BS/10);
f.selection_box.wall_bottom = core::aabbox3d<f32>(
-BS/10, -BS/2, -BS/10, BS/10, -BS/2+BS/3.333*2, BS/10);
f.selection_box.wall_side = core::aabbox3d<f32>(
-BS/2, -BS/3.333, -BS/10, -BS/2+BS/3.333, BS/3.333, BS/10);
setConstantMaterialProperties(f.material, 0.0);
f.furnace_burntime = 4;
nodemgr->set(i, f);
i = CONTENT_SIGN_WALL;
f = ContentFeatures();
f.name = "sign_wall";
f.drawtype = NDT_SIGNLIKE;
f.setAllTextures("sign_wall.png");
f.setInventoryTexture("sign_wall.png");
f.param_type = CPT_LIGHT;
f.light_propagates = true;
f.sunlight_propagates = true;
f.walkable = false;
f.wall_mounted = true;
f.dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
f.metadata_name = "sign";
setConstantMaterialProperties(f.material, 0.5);
f.selection_box.type = NODEBOX_WALLMOUNTED;
f.furnace_burntime = 10;
nodemgr->set(i, f);
i = CONTENT_CHEST;
f = ContentFeatures();
f.name = "chest";
f.param_type = CPT_FACEDIR_SIMPLE;
f.setAllTextures("chest_side.png");
f.setTexture(0, "chest_top.png");
f.setTexture(1, "chest_top.png");
f.setTexture(5, "chest_front.png"); // Z-
f.setInventoryTexture("chest_top.png");
//f.setInventoryTextureCube("chest_top.png", "chest_side.png", "chest_side.png");
f.dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
f.metadata_name = "chest";
setWoodLikeMaterialProperties(f.material, 1.0);
f.furnace_burntime = 30;
nodemgr->set(i, f);
i = CONTENT_LOCKABLE_CHEST;
f = ContentFeatures();
f.name = "locked_chest";
f.param_type = CPT_FACEDIR_SIMPLE;
f.setAllTextures("chest_side.png");
f.setTexture(0, "chest_top.png");
f.setTexture(1, "chest_top.png");
f.setTexture(5, "chest_lock.png"); // Z-
f.setInventoryTexture("chest_lock.png");
//f.setInventoryTextureCube("chest_top.png", "chest_side.png", "chest_side.png");
f.dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
f.metadata_name = "locked_chest";
setWoodLikeMaterialProperties(f.material, 1.0);
f.furnace_burntime = 30;
nodemgr->set(i, f);
i = CONTENT_FURNACE;
f = ContentFeatures();
f.name = "furnace";
f.param_type = CPT_FACEDIR_SIMPLE;
f.setAllTextures("furnace_side.png");
f.setTexture(5, "furnace_front.png"); // Z-
f.setInventoryTexture("furnace_front.png");
//f.dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
f.dug_item = std::string("MaterialItem2 ")+itos(CONTENT_COBBLE)+" 6";
f.metadata_name = "furnace";
setStoneLikeMaterialProperties(f.material, 3.0);
nodemgr->set(i, f);
i = CONTENT_COBBLE;
f = ContentFeatures();
f.name = "cobble";
f.setAllTextures("cobble.png");
f.setInventoryTextureCube("cobble.png", "cobble.png", "cobble.png");
f.param_type = CPT_NONE;
f.is_ground_content = true;
f.dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
f.cookresult_item = std::string("MaterialItem2 ")+itos(CONTENT_STONE)+" 1";
setStoneLikeMaterialProperties(f.material, 0.9);
nodemgr->set(i, f);
i = CONTENT_MOSSYCOBBLE;
f = ContentFeatures();
f.name = "mossycobble";
f.setAllTextures("mossycobble.png");
f.setInventoryTextureCube("mossycobble.png", "mossycobble.png", "mossycobble.png");
f.param_type = CPT_NONE;
f.is_ground_content = true;
f.dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
setStoneLikeMaterialProperties(f.material, 0.8);
nodemgr->set(i, f);
i = CONTENT_STEEL;
f = ContentFeatures();
f.name = "steelblock";
f.setAllTextures("steel_block.png");
f.setInventoryTextureCube("steel_block.png", "steel_block.png",
"steel_block.png");
f.param_type = CPT_NONE;
f.is_ground_content = true;
f.dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
setStoneLikeMaterialProperties(f.material, 5.0);
nodemgr->set(i, f);
i = CONTENT_NC;
f = ContentFeatures();
f.name = "nyancat";
f.param_type = CPT_FACEDIR_SIMPLE;
f.setAllTextures("nc_side.png");
f.setTexture(5, "nc_front.png"); // Z-
f.setTexture(4, "nc_back.png"); // Z+
f.setInventoryTexture("nc_front.png");
f.dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
setStoneLikeMaterialProperties(f.material, 3.0);
f.furnace_burntime = 1;
nodemgr->set(i, f);
i = CONTENT_NC_RB;
f = ContentFeatures();
f.name = "nyancat_rainbow";
f.setAllTextures("nc_rb.png");
f.setInventoryTexture("nc_rb.png");
f.dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
setStoneLikeMaterialProperties(f.material, 3.0);
f.furnace_burntime = 1;
nodemgr->set(i, f);
i = CONTENT_SAPLING;
f = ContentFeatures();
f.name = "sapling";
f.drawtype = NDT_PLANTLIKE;
f.visual_scale = 1.0;
f.setAllTextures("sapling.png");
f.setInventoryTexture("sapling.png");
f.param_type = CPT_LIGHT;
f.dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
f.light_propagates = true;
f.walkable = false;
setConstantMaterialProperties(f.material, 0.0);
f.furnace_burntime = 10;
nodemgr->set(i, f);
i = CONTENT_APPLE;
f = ContentFeatures();
f.name = "apple";
f.drawtype = NDT_PLANTLIKE;
f.visual_scale = 1.0;
f.setAllTextures("apple.png");
f.setInventoryTexture("apple.png");
f.param_type = CPT_LIGHT;
f.light_propagates = true;
f.sunlight_propagates = true;
f.walkable = false;
f.dug_item = std::string("CraftItem apple 1");
setConstantMaterialProperties(f.material, 0.0);
f.furnace_burntime = 3;
nodemgr->set(i, f);
}

@ -26,12 +26,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
Legacy node definitions Legacy node definitions
*/ */
class IWritableNodeDefManager;
// Initialize legacy node definitions
// Not used used anywhere else than in test.cpp (and SHALL NOT BE)
void content_mapnode_init(IWritableNodeDefManager *nodemgr);
// Backwards compatibility for non-extended content types in v19 // Backwards compatibility for non-extended content types in v19
extern content_t trans_table_19[21][2]; extern content_t trans_table_19[21][2];
MapNode mapnode_translate_from_internal(MapNode n_from, u8 version); MapNode mapnode_translate_from_internal(MapNode n_from, u8 version);

@ -23,6 +23,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "inventory.h" #include "inventory.h"
#include "log.h" #include "log.h"
#include "utility.h" #include "utility.h"
#include "craftdef.h"
#include "gamedef.h"
class Inventory; class Inventory;
@ -125,9 +127,14 @@ public:
virtual bool step(float dtime); virtual bool step(float dtime);
virtual bool nodeRemovalDisabled(); virtual bool nodeRemovalDisabled();
virtual std::string getInventoryDrawSpecString(); virtual std::string getInventoryDrawSpecString();
protected:
bool getCookResult(bool remove, std::string &cookresult, float &cooktime);
bool getBurnResult(bool remove, float &burntime);
private: private:
Inventory *m_inventory; Inventory *m_inventory;
std::string m_infotext;
float m_step_accumulator; float m_step_accumulator;
float m_fuel_totaltime; float m_fuel_totaltime;
float m_fuel_time; float m_fuel_time;
@ -185,9 +192,7 @@ ChestNodeMetadata::ChestNodeMetadata(IGameDef *gamedef):
NodeMetadata(gamedef) NodeMetadata(gamedef)
{ {
NodeMetadata::registerType(typeId(), typeName(), create, create); NodeMetadata::registerType(typeId(), typeName(), create, create);
m_inventory = NULL;
m_inventory = new Inventory();
m_inventory->addList("0", 8*4);
} }
ChestNodeMetadata::~ChestNodeMetadata() ChestNodeMetadata::~ChestNodeMetadata()
{ {
@ -200,18 +205,21 @@ u16 ChestNodeMetadata::typeId() const
NodeMetadata* ChestNodeMetadata::create(std::istream &is, IGameDef *gamedef) NodeMetadata* ChestNodeMetadata::create(std::istream &is, IGameDef *gamedef)
{ {
ChestNodeMetadata *d = new ChestNodeMetadata(gamedef); ChestNodeMetadata *d = new ChestNodeMetadata(gamedef);
d->m_inventory->deSerialize(is, gamedef); d->m_inventory = new Inventory(gamedef->idef());
d->m_inventory->deSerialize(is);
return d; return d;
} }
NodeMetadata* ChestNodeMetadata::create(IGameDef *gamedef) NodeMetadata* ChestNodeMetadata::create(IGameDef *gamedef)
{ {
ChestNodeMetadata *d = new ChestNodeMetadata(gamedef); ChestNodeMetadata *d = new ChestNodeMetadata(gamedef);
d->m_inventory = new Inventory(gamedef->idef());
d->m_inventory->addList("0", 8*4);
return d; return d;
} }
NodeMetadata* ChestNodeMetadata::clone(IGameDef *gamedef) NodeMetadata* ChestNodeMetadata::clone(IGameDef *gamedef)
{ {
ChestNodeMetadata *d = new ChestNodeMetadata(gamedef); ChestNodeMetadata *d = new ChestNodeMetadata(gamedef);
*d->m_inventory = *m_inventory; d->m_inventory = new Inventory(*m_inventory);
return d; return d;
} }
void ChestNodeMetadata::serializeBody(std::ostream &os) void ChestNodeMetadata::serializeBody(std::ostream &os)
@ -253,9 +261,7 @@ LockingChestNodeMetadata::LockingChestNodeMetadata(IGameDef *gamedef):
NodeMetadata(gamedef) NodeMetadata(gamedef)
{ {
NodeMetadata::registerType(typeId(), typeName(), create, create); NodeMetadata::registerType(typeId(), typeName(), create, create);
m_inventory = NULL;
m_inventory = new Inventory();
m_inventory->addList("0", 8*4);
} }
LockingChestNodeMetadata::~LockingChestNodeMetadata() LockingChestNodeMetadata::~LockingChestNodeMetadata()
{ {
@ -269,18 +275,21 @@ NodeMetadata* LockingChestNodeMetadata::create(std::istream &is, IGameDef *gamed
{ {
LockingChestNodeMetadata *d = new LockingChestNodeMetadata(gamedef); LockingChestNodeMetadata *d = new LockingChestNodeMetadata(gamedef);
d->setOwner(deSerializeString(is)); d->setOwner(deSerializeString(is));
d->m_inventory->deSerialize(is, gamedef); d->m_inventory = new Inventory(gamedef->idef());
d->m_inventory->deSerialize(is);
return d; return d;
} }
NodeMetadata* LockingChestNodeMetadata::create(IGameDef *gamedef) NodeMetadata* LockingChestNodeMetadata::create(IGameDef *gamedef)
{ {
LockingChestNodeMetadata *d = new LockingChestNodeMetadata(gamedef); LockingChestNodeMetadata *d = new LockingChestNodeMetadata(gamedef);
d->m_inventory = new Inventory(gamedef->idef());
d->m_inventory->addList("0", 8*4);
return d; return d;
} }
NodeMetadata* LockingChestNodeMetadata::clone(IGameDef *gamedef) NodeMetadata* LockingChestNodeMetadata::clone(IGameDef *gamedef)
{ {
LockingChestNodeMetadata *d = new LockingChestNodeMetadata(gamedef); LockingChestNodeMetadata *d = new LockingChestNodeMetadata(gamedef);
*d->m_inventory = *m_inventory; d->m_inventory = new Inventory(*m_inventory);
return d; return d;
} }
void LockingChestNodeMetadata::serializeBody(std::ostream &os) void LockingChestNodeMetadata::serializeBody(std::ostream &os)
@ -324,10 +333,9 @@ FurnaceNodeMetadata::FurnaceNodeMetadata(IGameDef *gamedef):
{ {
NodeMetadata::registerType(typeId(), typeName(), create, create); NodeMetadata::registerType(typeId(), typeName(), create, create);
m_inventory = new Inventory(); m_inventory = NULL;
m_inventory->addList("fuel", 1);
m_inventory->addList("src", 1); m_infotext = "Furnace is inactive";
m_inventory->addList("dst", 4);
m_step_accumulator = 0; m_step_accumulator = 0;
m_fuel_totaltime = 0; m_fuel_totaltime = 0;
@ -346,26 +354,52 @@ u16 FurnaceNodeMetadata::typeId() const
NodeMetadata* FurnaceNodeMetadata::clone(IGameDef *gamedef) NodeMetadata* FurnaceNodeMetadata::clone(IGameDef *gamedef)
{ {
FurnaceNodeMetadata *d = new FurnaceNodeMetadata(m_gamedef); FurnaceNodeMetadata *d = new FurnaceNodeMetadata(m_gamedef);
*d->m_inventory = *m_inventory; d->m_inventory = new Inventory(*m_inventory);
return d; return d;
} }
NodeMetadata* FurnaceNodeMetadata::create(std::istream &is, IGameDef *gamedef) NodeMetadata* FurnaceNodeMetadata::create(std::istream &is, IGameDef *gamedef)
{ {
FurnaceNodeMetadata *d = new FurnaceNodeMetadata(gamedef); FurnaceNodeMetadata *d = new FurnaceNodeMetadata(gamedef);
d->m_inventory->deSerialize(is, gamedef); d->m_inventory = new Inventory(gamedef->idef());
d->m_inventory->deSerialize(is);
int temp; int temp = 0;
is>>temp; is>>temp;
d->m_fuel_totaltime = (float)temp/10; d->m_fuel_totaltime = (float)temp/10;
temp = 0;
is>>temp; is>>temp;
d->m_fuel_time = (float)temp/10; d->m_fuel_time = (float)temp/10;
temp = 0;
is>>temp;
d->m_src_totaltime = (float)temp/10;
temp = 0;
is>>temp;
d->m_src_time = (float)temp/10;
if(is.eof())
{
// Old furnaces didn't serialize src_totaltime and src_time
d->m_src_totaltime = 0;
d->m_src_time = 0;
d->m_infotext = "";
}
else
{
// New furnaces also serialize the infotext (so that the
// client doesn't need to have the list of cooking recipes).
d->m_infotext = deSerializeJsonString(is);
}
return d; return d;
} }
NodeMetadata* FurnaceNodeMetadata::create(IGameDef *gamedef) NodeMetadata* FurnaceNodeMetadata::create(IGameDef *gamedef)
{ {
FurnaceNodeMetadata *d = new FurnaceNodeMetadata(gamedef); FurnaceNodeMetadata *d = new FurnaceNodeMetadata(gamedef);
d->m_inventory = new Inventory(gamedef->idef());
d->m_inventory->addList("fuel", 1);
d->m_inventory->addList("src", 1);
d->m_inventory->addList("dst", 4);
return d; return d;
} }
void FurnaceNodeMetadata::serializeBody(std::ostream &os) void FurnaceNodeMetadata::serializeBody(std::ostream &os)
@ -373,36 +407,13 @@ void FurnaceNodeMetadata::serializeBody(std::ostream &os)
m_inventory->serialize(os); m_inventory->serialize(os);
os<<itos(m_fuel_totaltime*10)<<" "; os<<itos(m_fuel_totaltime*10)<<" ";
os<<itos(m_fuel_time*10)<<" "; os<<itos(m_fuel_time*10)<<" ";
os<<itos(m_src_totaltime*10)<<" ";
os<<itos(m_src_time*10)<<" ";
os<<serializeJsonString(m_infotext);
} }
std::string FurnaceNodeMetadata::infoText() std::string FurnaceNodeMetadata::infoText()
{ {
//return "Furnace"; return m_infotext;
if(m_fuel_time >= m_fuel_totaltime)
{
const InventoryList *src_list = m_inventory->getList("src");
assert(src_list);
const InventoryItem *src_item = src_list->getItem(0);
if(src_item && src_item->isCookable()) {
InventoryList *dst_list = m_inventory->getList("dst");
if(!dst_list->roomForCookedItem(src_item))
return "Furnace is overloaded";
return "Furnace is out of fuel";
}
else
return "Furnace is inactive";
}
else
{
std::string s = "Furnace is active";
// Do this so it doesn't always show (0%) for weak fuel
if(m_fuel_totaltime > 3) {
s += " (";
s += itos(m_fuel_time/m_fuel_totaltime*100);
s += "%)";
}
return s;
}
} }
bool FurnaceNodeMetadata::nodeRemovalDisabled() bool FurnaceNodeMetadata::nodeRemovalDisabled()
{ {
@ -440,86 +451,107 @@ bool FurnaceNodeMetadata::step(float dtime)
dtime = interval; dtime = interval;
//infostream<<"Furnace step dtime="<<dtime<<std::endl; //infostream<<"Furnace step dtime="<<dtime<<std::endl;
InventoryList *dst_list = m_inventory->getList("dst"); InventoryList *dst_list = m_inventory->getList("dst");
assert(dst_list); assert(dst_list);
InventoryList *src_list = m_inventory->getList("src"); // Check
assert(src_list); // 1. if the source item is cookable
InventoryItem *src_item = src_list->getItem(0); // 2. if there is room for the cooked item
std::string cookresult;
float cooktime;
bool cookable = getCookResult(false, cookresult, cooktime);
ItemStack cookresult_item;
bool room_available = false; bool room_available = false;
if(cookable)
if(src_item && src_item->isCookable()) {
room_available = dst_list->roomForCookedItem(src_item); cookresult_item.deSerialize(cookresult, m_gamedef->idef());
room_available = dst_list->roomForItem(cookresult_item);
// Start only if there are free slots in dst, so that it can }
// accomodate any result item
// Step fuel time
bool burning = (m_fuel_time < m_fuel_totaltime);
if(burning)
{
changed = true;
m_fuel_time += dtime;
}
std::string infotext;
if(room_available) if(room_available)
{ {
m_src_totaltime = src_item->getCookTime(); float burntime;
if(burning)
{
changed = true;
m_src_time += dtime;
m_src_totaltime = cooktime;
infotext = "Furnace is cooking";
}
else if(getBurnResult(true, burntime))
{
// Fuel inserted
changed = true;
m_fuel_time = 0;
m_fuel_totaltime = burntime;
//m_src_time += dtime;
//m_src_totaltime = cooktime;
infotext = "Furnace is cooking";
}
else
{
m_src_time = 0;
m_src_totaltime = 0;
infotext = "Furnace is out of fuel";
}
if(m_src_totaltime > 0.001 && m_src_time >= m_src_totaltime)
{
// One item fully cooked
changed = true;
dst_list->addItem(cookresult_item);
getCookResult(true, cookresult, cooktime); // decrement source
m_src_totaltime = 0;
m_src_time = 0;
}
} }
else else
{ {
m_src_time = 0; // Not cookable or no room available
m_src_totaltime = 0; m_src_totaltime = 0;
} m_src_time = 0;
if(cookable)
/* infotext = "Furnace is overloaded";
If fuel is burning, increment the burn counters. else if(burning)
If item finishes cooking, move it to result. infotext = "Furnace is active";
*/ else
if(m_fuel_time < m_fuel_totaltime)
{
//infostream<<"Furnace is active"<<std::endl;
m_fuel_time += dtime;
m_src_time += dtime;
if(m_src_time >= m_src_totaltime && m_src_totaltime > 0.001
&& src_item)
{ {
InventoryItem *cookresult = src_item->createCookResult(); infotext = "Furnace is inactive";
dst_list->addItem(cookresult); m_fuel_totaltime = 0;
src_list->decrementMaterials(1); m_fuel_time = 0;
m_src_time = 0;
m_src_totaltime = 0;
} }
changed = true;
// If the fuel was not used up this step, just keep burning it
if(m_fuel_time < m_fuel_totaltime)
continue;
} }
/* // Do this so it doesn't always show (0%) for weak fuel
Get the source again in case it has all burned if(m_fuel_totaltime > 3) {
*/ infotext += " (";
src_item = src_list->getItem(0); infotext += itos(m_fuel_time/m_fuel_totaltime*100);
infotext += "%)";
/* }
If there is no source item, or the source item is not cookable,
or the furnace is still cooking, or the furnace became overloaded, stop loop. if(infotext != m_infotext)
*/
if(src_item == NULL || !room_available || m_fuel_time < m_fuel_totaltime ||
dst_list->roomForCookedItem(src_item) == false)
{ {
m_step_accumulator = 0; m_infotext = infotext;
break;
}
//infostream<<"Furnace is out of fuel"<<std::endl;
InventoryList *fuel_list = m_inventory->getList("fuel");
assert(fuel_list);
const InventoryItem *fuel_item = fuel_list->getItem(0);
if(fuel_item && fuel_item->getBurnTime() >= 0){
m_fuel_totaltime = fuel_item->getBurnTime();
m_fuel_time = 0;
fuel_list->decrementMaterials(1);
changed = true; changed = true;
} else { }
//infostream<<"No fuel found"<<std::endl;
// No fuel, stop loop. if(burning && m_fuel_time >= m_fuel_totaltime)
{
m_fuel_time = 0;
m_fuel_totaltime = 0;
}
if(!changed)
{
m_step_accumulator = 0; m_step_accumulator = 0;
break; break;
} }
@ -535,6 +567,43 @@ std::string FurnaceNodeMetadata::getInventoryDrawSpecString()
"list[current_name;dst;5,1;2,2;]" "list[current_name;dst;5,1;2,2;]"
"list[current_player;main;0,5;8,4;]"; "list[current_player;main;0,5;8,4;]";
} }
bool FurnaceNodeMetadata::getCookResult(bool remove,
std::string &cookresult, float &cooktime)
{
std::vector<ItemStack> items;
InventoryList *src_list = m_inventory->getList("src");
assert(src_list);
items.push_back(src_list->getItem(0));
CraftInput ci(CRAFT_METHOD_COOKING, 1, items);
CraftOutput co;
bool found = m_gamedef->getCraftDefManager()->getCraftResult(
ci, co, remove, m_gamedef);
if(remove)
src_list->changeItem(0, ci.items[0]);
cookresult = co.item;
cooktime = co.time;
return found;
}
bool FurnaceNodeMetadata::getBurnResult(bool remove, float &burntime)
{
std::vector<ItemStack> items;
InventoryList *fuel_list = m_inventory->getList("fuel");
assert(fuel_list);
items.push_back(fuel_list->getItem(0));
CraftInput ci(CRAFT_METHOD_FUEL, 1, items);
CraftOutput co;
bool found = m_gamedef->getCraftDefManager()->getCraftResult(
ci, co, remove, m_gamedef);
if(remove)
fuel_list->changeItem(0, ci.items[0]);
burntime = co.time;
return found;
}
/* /*
GenericNodeMetadata GenericNodeMetadata
@ -571,7 +640,7 @@ public:
GenericNodeMetadata(IGameDef *gamedef): GenericNodeMetadata(IGameDef *gamedef):
NodeMetadata(gamedef), NodeMetadata(gamedef),
m_inventory(new Inventory()), m_inventory(NULL),
m_text(""), m_text(""),
m_owner(""), m_owner(""),
@ -594,7 +663,7 @@ public:
{ {
GenericNodeMetadata *d = new GenericNodeMetadata(m_gamedef); GenericNodeMetadata *d = new GenericNodeMetadata(m_gamedef);
*d->m_inventory = *m_inventory; d->m_inventory = new Inventory(*m_inventory);
d->m_text = m_text; d->m_text = m_text;
d->m_owner = m_owner; d->m_owner = m_owner;
@ -610,13 +679,15 @@ public:
static NodeMetadata* create(IGameDef *gamedef) static NodeMetadata* create(IGameDef *gamedef)
{ {
GenericNodeMetadata *d = new GenericNodeMetadata(gamedef); GenericNodeMetadata *d = new GenericNodeMetadata(gamedef);
d->m_inventory = new Inventory(gamedef->idef());
return d; return d;
} }
static NodeMetadata* create(std::istream &is, IGameDef *gamedef) static NodeMetadata* create(std::istream &is, IGameDef *gamedef)
{ {
GenericNodeMetadata *d = new GenericNodeMetadata(gamedef); GenericNodeMetadata *d = new GenericNodeMetadata(gamedef);
d->m_inventory->deSerialize(is, gamedef); d->m_inventory = new Inventory(gamedef->idef());
d->m_inventory->deSerialize(is);
d->m_text = deSerializeLongString(is); d->m_text = deSerializeLongString(is);
d->m_owner = deSerializeString(is); d->m_owner = deSerializeString(is);

@ -24,8 +24,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "main.h" // For g_profiler #include "main.h" // For g_profiler
#include "profiler.h" #include "profiler.h"
#include "serialization.h" // For compressZlib #include "serialization.h" // For compressZlib
#include "materials.h" // For MaterialProperties #include "materials.h" // For MaterialProperties and ToolDiggingProperties
#include "tooldef.h" // ToolDiggingProperties #include "gamedef.h"
core::map<u16, ServerActiveObject::Factory> ServerActiveObject::m_types; core::map<u16, ServerActiveObject::Factory> ServerActiveObject::m_types;
@ -114,9 +114,10 @@ void TestSAO::step(float dtime, bool send_recommended)
ItemSAO proto_ItemSAO(NULL, v3f(0,0,0), ""); ItemSAO proto_ItemSAO(NULL, v3f(0,0,0), "");
ItemSAO::ItemSAO(ServerEnvironment *env, v3f pos, ItemSAO::ItemSAO(ServerEnvironment *env, v3f pos,
const std::string inventorystring): const std::string itemstring):
ServerActiveObject(env, pos), ServerActiveObject(env, pos),
m_inventorystring(inventorystring), m_itemstring(itemstring),
m_itemstring_changed(false),
m_speed_f(0,0,0), m_speed_f(0,0,0),
m_last_sent_position(0,0,0) m_last_sent_position(0,0,0)
{ {
@ -134,10 +135,10 @@ ServerActiveObject* ItemSAO::create(ServerEnvironment *env, v3f pos,
// check if version is supported // check if version is supported
if(version != 0) if(version != 0)
return NULL; return NULL;
std::string inventorystring = deSerializeString(is); std::string itemstring = deSerializeString(is);
infostream<<"ItemSAO::create(): Creating item \"" infostream<<"ItemSAO::create(): Creating item \""
<<inventorystring<<"\""<<std::endl; <<itemstring<<"\""<<std::endl;
return new ItemSAO(env, pos, inventorystring); return new ItemSAO(env, pos, itemstring);
} }
void ItemSAO::step(float dtime, bool send_recommended) void ItemSAO::step(float dtime, bool send_recommended)
@ -175,17 +176,23 @@ void ItemSAO::step(float dtime, bool send_recommended)
m_last_sent_position = pos_f; m_last_sent_position = pos_f;
std::ostringstream os(std::ios::binary); std::ostringstream os(std::ios::binary);
char buf[6];
// command (0 = update position) // command (0 = update position)
buf[0] = 0; writeU8(os, 0);
os.write(buf, 1);
// pos // pos
writeS32((u8*)buf, m_base_position.X*1000); writeV3F1000(os, m_base_position);
os.write(buf, 4); // create message and add to list
writeS32((u8*)buf, m_base_position.Y*1000); ActiveObjectMessage aom(getId(), false, os.str());
os.write(buf, 4); m_messages_out.push_back(aom);
writeS32((u8*)buf, m_base_position.Z*1000); }
os.write(buf, 4); if(m_itemstring_changed)
{
m_itemstring_changed = false;
std::ostringstream os(std::ios::binary);
// command (1 = update itemstring)
writeU8(os, 1);
// itemstring
os<<serializeString(m_itemstring);
// create message and add to list // create message and add to list
ActiveObjectMessage aom(getId(), false, os.str()); ActiveObjectMessage aom(getId(), false, os.str());
m_messages_out.push_back(aom); m_messages_out.push_back(aom);
@ -195,19 +202,12 @@ void ItemSAO::step(float dtime, bool send_recommended)
std::string ItemSAO::getClientInitializationData() std::string ItemSAO::getClientInitializationData()
{ {
std::ostringstream os(std::ios::binary); std::ostringstream os(std::ios::binary);
char buf[6];
// version // version
buf[0] = 0; writeU8(os, 0);
os.write(buf, 1);
// pos // pos
writeS32((u8*)buf, m_base_position.X*1000); writeV3F1000(os, m_base_position);
os.write(buf, 4); // itemstring
writeS32((u8*)buf, m_base_position.Y*1000); os<<serializeString(m_itemstring);
os.write(buf, 4);
writeS32((u8*)buf, m_base_position.Z*1000);
os.write(buf, 4);
// inventorystring
os<<serializeString(m_inventorystring);
return os.str(); return os.str();
} }
@ -215,42 +215,58 @@ std::string ItemSAO::getStaticData()
{ {
infostream<<__FUNCTION_NAME<<std::endl; infostream<<__FUNCTION_NAME<<std::endl;
std::ostringstream os(std::ios::binary); std::ostringstream os(std::ios::binary);
char buf[1];
// version // version
buf[0] = 0; writeU8(os, 0);
os.write(buf, 1); // itemstring
// inventorystring os<<serializeString(m_itemstring);
os<<serializeString(m_inventorystring);
return os.str(); return os.str();
} }
InventoryItem * ItemSAO::createInventoryItem() ItemStack ItemSAO::createItemStack()
{ {
try{ try{
std::istringstream is(m_inventorystring, std::ios_base::binary); IItemDefManager *idef = m_env->getGameDef()->idef();
IGameDef *gamedef = m_env->getGameDef(); ItemStack item;
InventoryItem *item = InventoryItem::deSerialize(is, gamedef); item.deSerialize(m_itemstring, idef);
infostream<<__FUNCTION_NAME<<": m_inventorystring=\"" infostream<<__FUNCTION_NAME<<": m_itemstring=\""<<m_itemstring
<<m_inventorystring<<"\" -> item="<<item <<"\" -> item=\""<<item.getItemString()<<"\""
<<std::endl; <<std::endl;
return item; return item;
} }
catch(SerializationError &e) catch(SerializationError &e)
{ {
infostream<<__FUNCTION_NAME<<": serialization error: " infostream<<__FUNCTION_NAME<<": serialization error: "
<<"m_inventorystring=\""<<m_inventorystring<<"\""<<std::endl; <<"m_itemstring=\""<<m_itemstring<<"\""<<std::endl;
return NULL; return ItemStack();
} }
} }
void ItemSAO::punch(ServerActiveObject *puncher, float time_from_last_punch) void ItemSAO::punch(ServerActiveObject *puncher, float time_from_last_punch)
{ {
InventoryItem *item = createInventoryItem(); // Allow removing items in creative mode
bool fits = puncher->addToInventory(item); if(g_settings->getBool("creative_mode") == true)
if(fits) {
m_removed = true; m_removed = true;
else return;
delete item; }
ItemStack item = createItemStack();
Inventory *inv = puncher->getInventory();
if(inv != NULL)
{
std::string wieldlist = puncher->getWieldList();
ItemStack leftover = inv->addItem(wieldlist, item);
puncher->setInventoryModified();
if(leftover.empty())
{
m_removed = true;
}
else
{
m_itemstring = leftover.getItemString();
m_itemstring_changed = true;
}
}
} }
/* /*
@ -436,14 +452,24 @@ std::string RatSAO::getStaticData()
void RatSAO::punch(ServerActiveObject *puncher, float time_from_last_punch) void RatSAO::punch(ServerActiveObject *puncher, float time_from_last_punch)
{ {
std::istringstream is("CraftItem rat 1", std::ios_base::binary); // Allow removing rats in creative mode
IGameDef *gamedef = m_env->getGameDef(); if(g_settings->getBool("creative_mode") == true)
InventoryItem *item = InventoryItem::deSerialize(is, gamedef); {
bool fits = puncher->addToInventory(item);
if(fits)
m_removed = true; m_removed = true;
else return;
delete item; }
IItemDefManager *idef = m_env->getGameDef()->idef();
ItemStack item("rat", 1, 0, "", idef);
Inventory *inv = puncher->getInventory();
if(inv != NULL)
{
std::string wieldlist = puncher->getWieldList();
ItemStack leftover = inv->addItem(wieldlist, item);
puncher->setInventoryModified();
if(leftover.empty())
m_removed = true;
}
} }
/* /*
@ -703,14 +729,20 @@ void Oerkki1SAO::punch(ServerActiveObject *puncher, float time_from_last_punch)
mp.crackiness = -1.0; mp.crackiness = -1.0;
mp.cuttability = 1.0; mp.cuttability = 1.0;
ToolDiggingProperties tp; IItemDefManager *idef = m_env->getGameDef()->idef();
puncher->getWieldDiggingProperties(&tp); ItemStack punchitem = puncher->getWieldedItem();
ToolDiggingProperties tp =
punchitem.getToolDiggingProperties(idef);
HittingProperties hitprop = getHittingProperties(&mp, &tp, HittingProperties hitprop = getHittingProperties(&mp, &tp,
time_from_last_punch); time_from_last_punch);
doDamage(hitprop.hp); doDamage(hitprop.hp);
puncher->damageWieldedItem(hitprop.wear); if(g_settings->getBool("creative_mode") == false)
{
punchitem.addWear(hitprop.wear, idef);
puncher->setWieldedItem(punchitem);
}
} }
void Oerkki1SAO::doDamage(u16 d) void Oerkki1SAO::doDamage(u16 d)
@ -1393,14 +1425,20 @@ void MobV2SAO::punch(ServerActiveObject *puncher, float time_from_last_punch)
mp.crackiness = -1.0; mp.crackiness = -1.0;
mp.cuttability = 1.0; mp.cuttability = 1.0;
ToolDiggingProperties tp; IItemDefManager *idef = m_env->getGameDef()->idef();
puncher->getWieldDiggingProperties(&tp); ItemStack punchitem = puncher->getWieldedItem();
ToolDiggingProperties tp =
punchitem.getToolDiggingProperties(idef);
HittingProperties hitprop = getHittingProperties(&mp, &tp, HittingProperties hitprop = getHittingProperties(&mp, &tp,
time_from_last_punch); time_from_last_punch);
doDamage(hitprop.hp); doDamage(hitprop.hp);
puncher->damageWieldedItem(hitprop.wear); if(g_settings->getBool("creative_mode") == false)
{
punchitem.addWear(hitprop.wear, idef);
puncher->setWieldedItem(punchitem);
}
} }
bool MobV2SAO::isPeaceful() bool MobV2SAO::isPeaceful()

@ -40,8 +40,7 @@ private:
class ItemSAO : public ServerActiveObject class ItemSAO : public ServerActiveObject
{ {
public: public:
ItemSAO(ServerEnvironment *env, v3f pos, ItemSAO(ServerEnvironment *env, v3f pos, const std::string itemstring);
const std::string inventorystring);
u8 getType() const u8 getType() const
{return ACTIVEOBJECT_TYPE_ITEM;} {return ACTIVEOBJECT_TYPE_ITEM;}
static ServerActiveObject* create(ServerEnvironment *env, v3f pos, static ServerActiveObject* create(ServerEnvironment *env, v3f pos,
@ -49,11 +48,12 @@ public:
void step(float dtime, bool send_recommended); void step(float dtime, bool send_recommended);
std::string getClientInitializationData(); std::string getClientInitializationData();
std::string getStaticData(); std::string getStaticData();
InventoryItem* createInventoryItem(); ItemStack createItemStack();
void punch(ServerActiveObject *puncher, float time_from_last_punch); void punch(ServerActiveObject *puncher, float time_from_last_punch);
float getMinimumSavedMovement(){ return 0.1*BS; } float getMinimumSavedMovement(){ return 0.1*BS; }
private: private:
std::string m_inventorystring; std::string m_itemstring;
bool m_itemstring_changed;
v3f m_speed_f; v3f m_speed_f;
v3f m_last_sent_position; v3f m_last_sent_position;
IntervalLimiter m_move_interval; IntervalLimiter m_move_interval;

@ -22,88 +22,738 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "irrlichttypes.h" #include "irrlichttypes.h"
#include "log.h" #include "log.h"
#include <sstream> #include <sstream>
#include <set>
#include "utility.h" #include "utility.h"
#include "gamedef.h" #include "gamedef.h"
#include "inventory.h" #include "inventory.h"
#include "inventorymanager.h" // checkItemCombination
CraftPointerInput::~CraftPointerInput()
// Deserialize an itemstring then return the name of the item
static std::string craftGetItemName(const std::string &itemstring, IGameDef *gamedef)
{ {
for(u32 i=0; i<items.size(); i++) ItemStack item;
delete items[i]; item.deSerialize(itemstring, gamedef->idef());
return item.name;
} }
CraftPointerInput createPointerInput(const CraftInput &ci, IGameDef *gamedef) // (mapcar craftGetItemName itemstrings)
static std::vector<std::string> craftGetItemNames(
const std::vector<std::string> &itemstrings, IGameDef *gamedef)
{ {
std::vector<InventoryItem*> items; std::vector<std::string> result;
for(u32 i=0; i<ci.items.size(); i++){ for(std::vector<std::string>::const_iterator
InventoryItem *item = NULL; i = itemstrings.begin();
if(ci.items[i] != ""){ i != itemstrings.end(); i++)
std::istringstream iss(ci.items[i], std::ios::binary); {
item = InventoryItem::deSerialize(iss, gamedef); result.push_back(craftGetItemName(*i, gamedef));
}
items.push_back(item);
} }
return CraftPointerInput(ci.width, items); return result;
} }
CraftInput createInput(const CraftPointerInput &cpi) // Get name of each item, and return them as a new list.
static std::vector<std::string> craftGetItemNames(
const std::vector<ItemStack> &items, IGameDef *gamedef)
{ {
std::vector<std::string> items; std::vector<std::string> result;
for(u32 i=0; i<cpi.items.size(); i++){ for(std::vector<ItemStack>::const_iterator
if(cpi.items[i] == NULL) i = items.begin();
items.push_back(""); i != items.end(); i++)
else{ {
std::ostringstream oss(std::ios::binary); result.push_back(i->name);
cpi.items[i]->serialize(oss); }
items.push_back(oss.str()); return result;
}
// Compute bounding rectangle given a matrix of items
// Returns false if every item is ""
static bool craftGetBounds(const std::vector<std::string> &items, unsigned int width,
unsigned int &min_x, unsigned int &max_x,
unsigned int &min_y, unsigned int &max_y)
{
bool success = false;
unsigned int x = 0;
unsigned int y = 0;
for(std::vector<std::string>::const_iterator
i = items.begin();
i != items.end(); i++)
{
if(*i != "") // Is this an actual item?
{
if(!success)
{
// This is the first nonempty item
min_x = max_x = x;
min_y = max_y = y;
success = true;
}
else
{
if(x < min_x) min_x = x;
if(x > max_x) max_x = x;
if(y < min_y) min_y = y;
if(y > max_y) max_y = y;
}
}
// Step coordinate
x++;
if(x == width)
{
x = 0;
y++;
} }
} }
return CraftInput(cpi.width, items); return success;
} }
// Convert a list of item names to a multiset
static std::multiset<std::string> craftMakeMultiset(const std::vector<std::string> &names)
{
std::multiset<std::string> set;
for(std::vector<std::string>::const_iterator
i = names.begin();
i != names.end(); i++)
{
if(*i != "")
set.insert(*i);
}
return set;
}
// Removes 1 from each item stack
static void craftDecrementInput(CraftInput &input, IGameDef *gamedef)
{
for(std::vector<ItemStack>::iterator
i = input.items.begin();
i != input.items.end(); i++)
{
if(i->count != 0)
i->remove(1);
}
}
// Removes 1 from each item stack with replacement support
// Example: if replacements contains the pair ("bucket:bucket_water", "bucket:bucket_empty"),
// a water bucket will not be removed but replaced by an empty bucket.
static void craftDecrementOrReplaceInput(CraftInput &input,
const CraftReplacements &replacements,
IGameDef *gamedef)
{
if(replacements.pairs.empty())
{
craftDecrementInput(input, gamedef);
return;
}
// Make a copy of the replacements pair list
std::vector<std::pair<std::string, std::string> > pairs = replacements.pairs;
for(std::vector<ItemStack>::iterator
i = input.items.begin();
i != input.items.end(); i++)
{
if(i->count == 1)
{
// Find an appropriate replacement
bool found_replacement = false;
for(std::vector<std::pair<std::string, std::string> >::iterator
j = pairs.begin();
j != pairs.end(); j++)
{
ItemStack from_item;
from_item.deSerialize(j->first, gamedef->idef());
if(i->name == from_item.name)
{
i->deSerialize(j->second, gamedef->idef());
found_replacement = true;
pairs.erase(j);
break;
}
}
// No replacement was found, simply decrement count to zero
if(!found_replacement)
i->remove(1);
}
else if(i->count >= 2)
{
// Ignore replacements for items with count >= 2
i->remove(1);
}
}
}
// Dump an itemstring matrix
static std::string craftDumpMatrix(const std::vector<std::string> &items,
unsigned int width)
{
std::ostringstream os(std::ios::binary);
os<<"{ ";
unsigned int x = 0;
for(std::vector<std::string>::const_iterator
i = items.begin();
i != items.end(); i++, x++)
{
if(x == width)
{
os<<"; ";
x = 0;
}
else if(x != 0)
{
os<<",";
}
os<<"\""<<(*i)<<"\"";
}
os<<" }";
return os.str();
}
// Dump an item matrix
std::string craftDumpMatrix(const std::vector<ItemStack> &items,
unsigned int width)
{
std::ostringstream os(std::ios::binary);
os<<"{ ";
unsigned int x = 0;
for(std::vector<ItemStack>::const_iterator
i = items.begin();
i != items.end(); i++, x++)
{
if(x == width)
{
os<<"; ";
x = 0;
}
else if(x != 0)
{
os<<",";
}
os<<"\""<<(i->getItemString())<<"\"";
}
os<<" }";
return os.str();
}
/*
CraftInput
*/
std::string CraftInput::dump() const std::string CraftInput::dump() const
{ {
std::ostringstream os(std::ios::binary); std::ostringstream os(std::ios::binary);
os<<"(width="<<width<<"){"; os<<"(method="<<((int)method)<<", items="<<craftDumpMatrix(items, width)<<")";
for(u32 i=0; i<items.size(); i++) return os.str();
os<<"\""<<items[i]<<"\","; }
/*
CraftOutput
*/
std::string CraftOutput::dump() const
{
std::ostringstream os(std::ios::binary);
os<<"(item=\""<<item<<"\", time="<<time<<")";
return os.str();
}
/*
CraftReplacements
*/
std::string CraftReplacements::dump() const
{
std::ostringstream os(std::ios::binary);
os<<"{";
const char *sep = "";
for(std::vector<std::pair<std::string, std::string> >::const_iterator
i = pairs.begin();
i != pairs.end(); i++)
{
os<<sep<<"\""<<(i->first)<<"\"=>\""<<(i->second)<<"\"";
sep = ",";
}
os<<"}"; os<<"}";
return os.str(); return os.str();
} }
std::string CraftDefinition::dump() const
{ /*
std::ostringstream os(std::ios::binary); CraftDefinition
os<<"{output=\""<<output<<"\", input={"; */
for(u32 i=0; i<input.items.size(); i++)
os<<"\""<<input.items[i]<<"\",";
os<<"}, (input.width="<<input.width<<")}";
return os.str();
}
void CraftDefinition::serialize(std::ostream &os) const void CraftDefinition::serialize(std::ostream &os) const
{ {
writeU8(os, 0); // version writeU8(os, 1); // version
os<<serializeString(output); os<<serializeString(getName());
writeU8(os, input.width); serializeBody(os);
writeU16(os, input.items.size());
for(u32 i=0; i<input.items.size(); i++)
os<<serializeString(input.items[i]);
} }
void CraftDefinition::deSerialize(std::istream &is) CraftDefinition* CraftDefinition::deSerialize(std::istream &is)
{ {
int version = readU8(is); int version = readU8(is);
if(version != 0) throw SerializationError( if(version != 1) throw SerializationError(
"unsupported CraftDefinition version"); "unsupported CraftDefinition version");
std::string name = deSerializeString(is);
CraftDefinition *def = NULL;
if(name == "shaped")
{
def = new CraftDefinitionShaped;
}
else if(name == "shapeless")
{
def = new CraftDefinitionShapeless;
}
else if(name == "toolrepair")
{
def = new CraftDefinitionToolRepair;
}
else if(name == "cooking")
{
def = new CraftDefinitionCooking;
}
else if(name == "fuel")
{
def = new CraftDefinitionFuel;
}
else
{
infostream<<"Unknown CraftDefinition name=\""<<name<<"\""<<std::endl;
throw SerializationError("Unknown CraftDefinition name");
}
def->deSerializeBody(is, version);
return def;
}
/*
CraftDefinitionShaped
*/
std::string CraftDefinitionShaped::getName() const
{
return "shaped";
}
bool CraftDefinitionShaped::check(const CraftInput &input, IGameDef *gamedef) const
{
if(input.method != CRAFT_METHOD_NORMAL)
return false;
// Get input item matrix
std::vector<std::string> inp_names = craftGetItemNames(input.items, gamedef);
unsigned int inp_width = input.width;
if(inp_width == 0)
return false;
while(inp_names.size() % inp_width != 0)
inp_names.push_back("");
// Get input bounds
unsigned int inp_min_x=0, inp_max_x=0, inp_min_y=0, inp_max_y=0;
if(!craftGetBounds(inp_names, inp_width, inp_min_x, inp_max_x, inp_min_y, inp_max_y))
return false; // it was empty
// Get recipe item matrix
std::vector<std::string> rec_names = craftGetItemNames(recipe, gamedef);
unsigned int rec_width = width;
if(rec_width == 0)
return false;
while(rec_names.size() % rec_width != 0)
rec_names.push_back("");
// Get recipe bounds
unsigned int rec_min_x=0, rec_max_x=0, rec_min_y=0, rec_max_y=0;
if(!craftGetBounds(rec_names, rec_width, rec_min_x, rec_max_x, rec_min_y, rec_max_y))
return false; // it was empty
// Different sizes?
if(inp_max_x - inp_min_x != rec_max_x - rec_min_x)
return false;
if(inp_max_y - inp_min_y != rec_max_y - rec_min_y)
return false;
// Verify that all item names in the bounding box are equal
unsigned int w = inp_max_x - inp_min_x + 1;
unsigned int h = inp_max_y - inp_min_y + 1;
for(unsigned int y=0; y<h; y++)
for(unsigned int x=0; x<w; x++)
{
unsigned int inp_x = inp_min_x + x;
unsigned int inp_y = inp_min_y + y;
unsigned int rec_x = rec_min_x + x;
unsigned int rec_y = rec_min_y + y;
if(
inp_names[inp_y * inp_width + inp_x] !=
rec_names[rec_y * rec_width + rec_x]
){
return false;
}
}
return true;
}
CraftOutput CraftDefinitionShaped::getOutput(const CraftInput &input, IGameDef *gamedef) const
{
return CraftOutput(output, 0);
}
void CraftDefinitionShaped::decrementInput(CraftInput &input, IGameDef *gamedef) const
{
craftDecrementOrReplaceInput(input, replacements, gamedef);
}
std::string CraftDefinitionShaped::dump() const
{
std::ostringstream os(std::ios::binary);
os<<"(shaped, output=\""<<output
<<"\", recipe="<<craftDumpMatrix(recipe, width)
<<", replacements="<<replacements.dump()<<")";
return os.str();
}
void CraftDefinitionShaped::serializeBody(std::ostream &os) const
{
os<<serializeString(output);
writeU16(os, width);
writeU16(os, recipe.size());
for(u32 i=0; i<recipe.size(); i++)
os<<serializeString(recipe[i]);
writeU16(os, replacements.pairs.size());
for(u32 i=0; i<replacements.pairs.size(); i++)
{
os<<serializeString(replacements.pairs[i].first);
os<<serializeString(replacements.pairs[i].second);
}
}
void CraftDefinitionShaped::deSerializeBody(std::istream &is, int version)
{
if(version != 1) throw SerializationError(
"unsupported CraftDefinitionShaped version");
output = deSerializeString(is); output = deSerializeString(is);
input.width = readU8(is); width = readU16(is);
recipe.clear();
u32 count = readU16(is); u32 count = readU16(is);
for(u32 i=0; i<count; i++) for(u32 i=0; i<count; i++)
input.items.push_back(deSerializeString(is)); recipe.push_back(deSerializeString(is));
replacements.pairs.clear();
count = readU16(is);
for(u32 i=0; i<count; i++)
{
std::string first = deSerializeString(is);
std::string second = deSerializeString(is);
replacements.pairs.push_back(std::make_pair(first, second));
}
} }
/*
CraftDefinitionShapeless
*/
std::string CraftDefinitionShapeless::getName() const
{
return "shapeless";
}
bool CraftDefinitionShapeless::check(const CraftInput &input, IGameDef *gamedef) const
{
if(input.method != CRAFT_METHOD_NORMAL)
return false;
// Get input item multiset
std::vector<std::string> inp_names = craftGetItemNames(input.items, gamedef);
std::multiset<std::string> inp_names_multiset = craftMakeMultiset(inp_names);
// Get recipe item multiset
std::vector<std::string> rec_names = craftGetItemNames(recipe, gamedef);
std::multiset<std::string> rec_names_multiset = craftMakeMultiset(rec_names);
// Recipe is matched when the multisets coincide
return inp_names_multiset == rec_names_multiset;
}
CraftOutput CraftDefinitionShapeless::getOutput(const CraftInput &input, IGameDef *gamedef) const
{
return CraftOutput(output, 0);
}
void CraftDefinitionShapeless::decrementInput(CraftInput &input, IGameDef *gamedef) const
{
craftDecrementOrReplaceInput(input, replacements, gamedef);
}
std::string CraftDefinitionShapeless::dump() const
{
std::ostringstream os(std::ios::binary);
os<<"(shapeless, output=\""<<output
<<"\", recipe="<<craftDumpMatrix(recipe, recipe.size())
<<", replacements="<<replacements.dump()<<")";
return os.str();
}
void CraftDefinitionShapeless::serializeBody(std::ostream &os) const
{
os<<serializeString(output);
writeU16(os, recipe.size());
for(u32 i=0; i<recipe.size(); i++)
os<<serializeString(recipe[i]);
writeU16(os, replacements.pairs.size());
for(u32 i=0; i<replacements.pairs.size(); i++)
{
os<<serializeString(replacements.pairs[i].first);
os<<serializeString(replacements.pairs[i].second);
}
}
void CraftDefinitionShapeless::deSerializeBody(std::istream &is, int version)
{
if(version != 1) throw SerializationError(
"unsupported CraftDefinitionShapeless version");
output = deSerializeString(is);
recipe.clear();
u32 count = readU16(is);
for(u32 i=0; i<count; i++)
recipe.push_back(deSerializeString(is));
replacements.pairs.clear();
count = readU16(is);
for(u32 i=0; i<count; i++)
{
std::string first = deSerializeString(is);
std::string second = deSerializeString(is);
replacements.pairs.push_back(std::make_pair(first, second));
}
}
/*
CraftDefinitionToolRepair
*/
static ItemStack craftToolRepair(
const ItemStack &item1,
const ItemStack &item2,
float additional_wear,
IGameDef *gamedef)
{
IItemDefManager *idef = gamedef->idef();
if(item1.count != 1 || item2.count != 1 || item1.name != item2.name
|| idef->get(item1.name).type != ITEM_TOOL
|| idef->get(item2.name).type != ITEM_TOOL)
{
// Failure
return ItemStack();
}
s32 item1_uses = 65536 - (u32) item1.wear;
s32 item2_uses = 65536 - (u32) item2.wear;
s32 new_uses = item1_uses + item2_uses;
s32 new_wear = 65536 - new_uses + floor(additional_wear * 65536 + 0.5);
if(new_wear >= 65536)
return ItemStack();
if(new_wear < 0)
new_wear = 0;
ItemStack repaired = item1;
repaired.wear = new_wear;
return repaired;
}
std::string CraftDefinitionToolRepair::getName() const
{
return "toolrepair";
}
bool CraftDefinitionToolRepair::check(const CraftInput &input, IGameDef *gamedef) const
{
if(input.method != CRAFT_METHOD_NORMAL)
return false;
ItemStack item1;
ItemStack item2;
for(std::vector<ItemStack>::const_iterator
i = input.items.begin();
i != input.items.end(); i++)
{
if(!i->empty())
{
if(item1.empty())
item1 = *i;
else if(item2.empty())
item2 = *i;
else
return false;
}
}
ItemStack repaired = craftToolRepair(item1, item2, additional_wear, gamedef);
return !repaired.empty();
}
CraftOutput CraftDefinitionToolRepair::getOutput(const CraftInput &input, IGameDef *gamedef) const
{
ItemStack item1;
ItemStack item2;
for(std::vector<ItemStack>::const_iterator
i = input.items.begin();
i != input.items.end(); i++)
{
if(!i->empty())
{
if(item1.empty())
item1 = *i;
else if(item2.empty())
item2 = *i;
}
}
ItemStack repaired = craftToolRepair(item1, item2, additional_wear, gamedef);
return CraftOutput(repaired.getItemString(), 0);
}
void CraftDefinitionToolRepair::decrementInput(CraftInput &input, IGameDef *gamedef) const
{
craftDecrementInput(input, gamedef);
}
std::string CraftDefinitionToolRepair::dump() const
{
std::ostringstream os(std::ios::binary);
os<<"(toolrepair, additional_wear="<<additional_wear<<")";
return os.str();
}
void CraftDefinitionToolRepair::serializeBody(std::ostream &os) const
{
writeF1000(os, additional_wear);
}
void CraftDefinitionToolRepair::deSerializeBody(std::istream &is, int version)
{
if(version != 1) throw SerializationError(
"unsupported CraftDefinitionToolRepair version");
additional_wear = readF1000(is);
}
/*
CraftDefinitionCooking
*/
std::string CraftDefinitionCooking::getName() const
{
return "cooking";
}
bool CraftDefinitionCooking::check(const CraftInput &input, IGameDef *gamedef) const
{
if(input.method != CRAFT_METHOD_COOKING)
return false;
// Get input item multiset
std::vector<std::string> inp_names = craftGetItemNames(input.items, gamedef);
std::multiset<std::string> inp_names_multiset = craftMakeMultiset(inp_names);
// Get recipe item multiset
std::multiset<std::string> rec_names_multiset;
rec_names_multiset.insert(craftGetItemName(recipe, gamedef));
// Recipe is matched when the multisets coincide
return inp_names_multiset == rec_names_multiset;
}
CraftOutput CraftDefinitionCooking::getOutput(const CraftInput &input, IGameDef *gamedef) const
{
return CraftOutput(output, cooktime);
}
void CraftDefinitionCooking::decrementInput(CraftInput &input, IGameDef *gamedef) const
{
craftDecrementInput(input, gamedef);
}
std::string CraftDefinitionCooking::dump() const
{
std::ostringstream os(std::ios::binary);
os<<"(cooking, output=\""<<output
<<"\", recipe=\""<<recipe
<<"\", cooktime="<<cooktime<<")";
return os.str();
}
void CraftDefinitionCooking::serializeBody(std::ostream &os) const
{
os<<serializeString(output);
os<<serializeString(recipe);
writeF1000(os, cooktime);
}
void CraftDefinitionCooking::deSerializeBody(std::istream &is, int version)
{
if(version != 1) throw SerializationError(
"unsupported CraftDefinitionCooking version");
output = deSerializeString(is);
recipe = deSerializeString(is);
cooktime = readF1000(is);
}
/*
CraftDefinitionFuel
*/
std::string CraftDefinitionFuel::getName() const
{
return "fuel";
}
bool CraftDefinitionFuel::check(const CraftInput &input, IGameDef *gamedef) const
{
if(input.method != CRAFT_METHOD_FUEL)
return false;
// Get input item multiset
std::vector<std::string> inp_names = craftGetItemNames(input.items, gamedef);
std::multiset<std::string> inp_names_multiset = craftMakeMultiset(inp_names);
// Get recipe item multiset
std::multiset<std::string> rec_names_multiset;
rec_names_multiset.insert(craftGetItemName(recipe, gamedef));
// Recipe is matched when the multisets coincide
return inp_names_multiset == rec_names_multiset;
}
CraftOutput CraftDefinitionFuel::getOutput(const CraftInput &input, IGameDef *gamedef) const
{
return CraftOutput("", burntime);
}
void CraftDefinitionFuel::decrementInput(CraftInput &input, IGameDef *gamedef) const
{
craftDecrementInput(input, gamedef);
}
std::string CraftDefinitionFuel::dump() const
{
std::ostringstream os(std::ios::binary);
os<<"(fuel, recipe=\""<<recipe
<<"\", burntime="<<burntime<<")";
return os.str();
}
void CraftDefinitionFuel::serializeBody(std::ostream &os) const
{
os<<serializeString(recipe);
writeF1000(os, burntime);
}
void CraftDefinitionFuel::deSerializeBody(std::istream &is, int version)
{
if(version != 1) throw SerializationError(
"unsupported CraftDefinitionFuel version");
recipe = deSerializeString(is);
burntime = readF1000(is);
}
/*
Craft definition manager
*/
class CCraftDefManager: public IWritableCraftDefManager class CCraftDefManager: public IWritableCraftDefManager
{ {
public: public:
@ -111,58 +761,46 @@ public:
{ {
clear(); clear();
} }
virtual InventoryItem* getCraftResult(const CraftPointerInput &input_cpi, virtual bool getCraftResult(CraftInput &input, CraftOutput &output,
IGameDef *gamedef) const bool decrementInput, IGameDef *gamedef) const
{ {
if(input_cpi.width > 3){ output.item = "";
errorstream<<"getCraftResult(): ERROR: " output.time = 0;
<<"input_cpi.width > 3; Failing to craft."<<std::endl;
return NULL; // If all input items are empty, abort.
} bool all_empty = true;
InventoryItem *input_items[9]; for(std::vector<ItemStack>::const_iterator
for(u32 y=0; y<3; y++) i = input.items.begin();
for(u32 x=0; x<3; x++) i != input.items.end(); i++)
{ {
u32 i=y*3+x; if(!i->empty())
if(x >= input_cpi.width || y >= input_cpi.height()) {
input_items[i] = NULL; all_empty = false;
else break;
input_items[i] = input_cpi.items[y*input_cpi.width+x]; }
} }
for(core::list<CraftDefinition*>::ConstIterator if(all_empty)
i = m_craft_definitions.begin(); return false;
i != m_craft_definitions.end(); i++)
// Walk crafting definitions from back to front, so that later
// definitions can override earlier ones.
for(std::vector<CraftDefinition*>::const_reverse_iterator
i = m_craft_definitions.rbegin();
i != m_craft_definitions.rend(); i++)
{ {
CraftDefinition *def = *i; CraftDefinition *def = *i;
/*infostream<<"Checking "<<createInput(input_cpi).dump()<<std::endl /*infostream<<"Checking "<<input.dump()<<std::endl
<<" against "<<def->input.dump() <<" against "<<def->dump()<<std::endl;*/
<<" (output=\""<<def->output<<"\")"<<std::endl;*/
try { try {
CraftPointerInput spec_cpi = createPointerInput(def->input, gamedef); if(def->check(input, gamedef))
if(spec_cpi.width > 3){
errorstream<<"getCraftResult: ERROR: "
<<"spec_cpi.width > 3 in recipe "
<<def->dump()<<std::endl;
continue;
}
InventoryItem *spec_items[9];
for(u32 y=0; y<3; y++)
for(u32 x=0; x<3; x++)
{ {
u32 i=y*3+x; // Get output, then decrement input (if requested)
if(x >= spec_cpi.width || y >= spec_cpi.height()) output = def->getOutput(input, gamedef);
spec_items[i] = NULL; if(decrementInput)
else def->decrementInput(input, gamedef);
spec_items[i] = spec_cpi.items[y*spec_cpi.width+x]; return true;
}
bool match = checkItemCombination(input_items, spec_items);
if(match){
std::istringstream iss(def->output, std::ios::binary);
return InventoryItem::deSerialize(iss, gamedef);
} }
} }
catch(SerializationError &e) catch(SerializationError &e)
@ -173,34 +811,41 @@ public:
// then go on with the next craft definition // then go on with the next craft definition
} }
} }
return NULL; return false;
} }
virtual void registerCraft(const CraftDefinition &def) virtual std::string dump() const
{
std::ostringstream os(std::ios::binary);
os<<"Crafting definitions:\n";
for(std::vector<CraftDefinition*>::const_iterator
i = m_craft_definitions.begin();
i != m_craft_definitions.end(); i++)
{
os<<(*i)->dump()<<"\n";
}
return os.str();
}
virtual void registerCraft(CraftDefinition *def)
{ {
infostream<<"registerCraft: registering craft definition: " infostream<<"registerCraft: registering craft definition: "
<<def.dump()<<std::endl; <<def->dump()<<std::endl;
if(def.input.width > 3 || def.input.height() > 3){ m_craft_definitions.push_back(def);
errorstream<<"registerCraft: input size is larger than 3x3,"
<<" ignoring"<<std::endl;
return;
}
m_craft_definitions.push_back(new CraftDefinition(def));
} }
virtual void clear() virtual void clear()
{ {
for(core::list<CraftDefinition*>::Iterator for(std::vector<CraftDefinition*>::iterator
i = m_craft_definitions.begin(); i = m_craft_definitions.begin();
i != m_craft_definitions.end(); i++){ i != m_craft_definitions.end(); i++){
delete *i; delete *i;
} }
m_craft_definitions.clear(); m_craft_definitions.clear();
} }
virtual void serialize(std::ostream &os) virtual void serialize(std::ostream &os) const
{ {
writeU8(os, 0); // version writeU8(os, 0); // version
u16 count = m_craft_definitions.size(); u16 count = m_craft_definitions.size();
writeU16(os, count); writeU16(os, count);
for(core::list<CraftDefinition*>::Iterator for(std::vector<CraftDefinition*>::const_iterator
i = m_craft_definitions.begin(); i = m_craft_definitions.begin();
i != m_craft_definitions.end(); i++){ i != m_craft_definitions.end(); i++){
CraftDefinition *def = *i; CraftDefinition *def = *i;
@ -222,14 +867,13 @@ public:
for(u16 i=0; i<count; i++){ for(u16 i=0; i<count; i++){
// Deserialize a string and grab a CraftDefinition from it // Deserialize a string and grab a CraftDefinition from it
std::istringstream tmp_is(deSerializeString(is), std::ios::binary); std::istringstream tmp_is(deSerializeString(is), std::ios::binary);
CraftDefinition def; CraftDefinition *def = CraftDefinition::deSerialize(tmp_is);
def.deSerialize(tmp_is);
// Register // Register
registerCraft(def); registerCraft(def);
} }
} }
private: private:
core::list<CraftDefinition*> m_craft_definitions; std::vector<CraftDefinition*> m_craft_definitions;
}; };
IWritableCraftDefManager* createCraftDefManager() IWritableCraftDefManager* createCraftDefManager()

@ -23,71 +23,328 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <string> #include <string>
#include <iostream> #include <iostream>
#include <vector> #include <vector>
class IGameDef; #include <utility>
class InventoryItem; #include "gamedef.h"
#include "inventory.h"
struct CraftPointerInput /*
Crafting methods.
The crafting method depends on the inventory list
that the crafting input comes from.
*/
enum CraftMethod
{ {
unsigned int width; // Crafting grid
std::vector<InventoryItem*> items; CRAFT_METHOD_NORMAL,
// Cooking something in a furnace
CraftPointerInput(unsigned int width_, const std::vector<InventoryItem*> &items_): CRAFT_METHOD_COOKING,
width(width_), // Using something as fuel for a furnace
items(items_) CRAFT_METHOD_FUEL,
{}
CraftPointerInput():
width(0)
{}
~CraftPointerInput();
unsigned int height() const{
return (items.size() + width - 1) / width;
}
}; };
/*
Input: The contents of the crafting slots, arranged in matrix form
*/
struct CraftInput struct CraftInput
{ {
CraftMethod method;
unsigned int width; unsigned int width;
std::vector<std::string> items; std::vector<ItemStack> items;
CraftInput(unsigned int width_, const std::vector<std::string> &items_):
width(width_),
items(items_)
{}
CraftInput(): CraftInput():
width(0) method(CRAFT_METHOD_NORMAL), width(0), items()
{}
CraftInput(CraftMethod method_, unsigned int width_,
const std::vector<ItemStack> &items_):
method(method_), width(width_), items(items_)
{} {}
unsigned int height() const{
return (items.size() + width - 1) / width;
}
std::string dump() const; std::string dump() const;
}; };
struct CraftDefinition /*
Output: Result of crafting operation
*/
struct CraftOutput
{ {
std::string output; // Used for normal crafting and cooking, itemstring
CraftInput input; std::string item;
// Used for cooking (cook time) and fuel (burn time), seconds
float time;
CraftDefinition(){} CraftOutput():
CraftDefinition(const std::string &output_, unsigned int width_, item(""), time(0)
const std::vector<std::string> &input_): {}
output(output_), CraftOutput(std::string item_, float time_):
input(width_, input_) item(item_), time(time_)
{} {}
std::string dump() const; std::string dump() const;
void serialize(std::ostream &os) const;
void deSerialize(std::istream &is);
}; };
/*
A list of replacements. A replacement indicates that a specific
input item should not be deleted (when crafting) but replaced with
a different item. Each replacements is a pair (itemstring to remove,
itemstring to replace with)
Example: If ("bucket:bucket_water", "bucket:bucket_empty") is a
replacement pair, the crafting input slot that contained a water
bucket will contain an empty bucket after crafting.
Note: replacements only work correctly when stack_max of the item
to be replaced is 1. It is up to the mod writer to ensure this.
*/
struct CraftReplacements
{
// List of replacements
std::vector<std::pair<std::string, std::string> > pairs;
CraftReplacements():
pairs()
{}
CraftReplacements(std::vector<std::pair<std::string, std::string> > pairs_):
pairs(pairs_)
{}
std::string dump() const;
};
/*
Crafting definition base class
*/
class CraftDefinition
{
public:
CraftDefinition(){}
virtual ~CraftDefinition(){}
void serialize(std::ostream &os) const;
static CraftDefinition* deSerialize(std::istream &is);
// Returns type of crafting definition
virtual std::string getName() const=0;
// Checks whether the recipe is applicable
virtual bool check(const CraftInput &input, IGameDef *gamedef) const=0;
// Returns the output structure, meaning depends on crafting method
// The implementation can assume that check(input) returns true
virtual CraftOutput getOutput(const CraftInput &input, IGameDef *gamedef) const=0;
// Decreases count of every input item
virtual void decrementInput(CraftInput &input, IGameDef *gamedef) const=0;
virtual std::string dump() const=0;
protected:
virtual void serializeBody(std::ostream &os) const=0;
virtual void deSerializeBody(std::istream &is, int version)=0;
};
/*
A plain-jane (shaped) crafting definition
Supported crafting method: CRAFT_METHOD_NORMAL.
Requires the input items to be arranged exactly like in the recipe.
*/
class CraftDefinitionShaped: public CraftDefinition
{
public:
CraftDefinitionShaped():
output(""), width(1), recipe(), replacements()
{}
CraftDefinitionShaped(
const std::string &output_,
unsigned int width_,
const std::vector<std::string> &recipe_,
const CraftReplacements &replacements_):
output(output_), width(width_), recipe(recipe_), replacements(replacements_)
{}
virtual ~CraftDefinitionShaped(){}
virtual std::string getName() const;
virtual bool check(const CraftInput &input, IGameDef *gamedef) const;
virtual CraftOutput getOutput(const CraftInput &input, IGameDef *gamedef) const;
virtual void decrementInput(CraftInput &input, IGameDef *gamedef) const;
virtual std::string dump() const;
protected:
virtual void serializeBody(std::ostream &os) const;
virtual void deSerializeBody(std::istream &is, int version);
private:
// Output itemstring
std::string output;
// Width of recipe
unsigned int width;
// Recipe matrix (itemstrings)
std::vector<std::string> recipe;
// Replacement items for decrementInput()
CraftReplacements replacements;
};
/*
A shapeless crafting definition
Supported crafting method: CRAFT_METHOD_NORMAL.
Input items can arranged in any way.
*/
class CraftDefinitionShapeless: public CraftDefinition
{
public:
CraftDefinitionShapeless():
output(""), recipe(), replacements()
{}
CraftDefinitionShapeless(
const std::string &output_,
const std::vector<std::string> &recipe_,
const CraftReplacements &replacements_):
output(output_), recipe(recipe_), replacements(replacements_)
{}
virtual ~CraftDefinitionShapeless(){}
virtual std::string getName() const;
virtual bool check(const CraftInput &input, IGameDef *gamedef) const;
virtual CraftOutput getOutput(const CraftInput &input, IGameDef *gamedef) const;
virtual void decrementInput(CraftInput &input, IGameDef *gamedef) const;
virtual std::string dump() const;
protected:
virtual void serializeBody(std::ostream &os) const;
virtual void deSerializeBody(std::istream &is, int version);
private:
// Output itemstring
std::string output;
// Recipe list (itemstrings)
std::vector<std::string> recipe;
// Replacement items for decrementInput()
CraftReplacements replacements;
};
/*
Tool repair crafting definition
Supported crafting method: CRAFT_METHOD_NORMAL.
Put two damaged tools into the crafting grid, get one tool back.
There should only be one crafting definition of this type.
*/
class CraftDefinitionToolRepair: public CraftDefinition
{
public:
CraftDefinitionToolRepair():
additional_wear(0)
{}
CraftDefinitionToolRepair(float additional_wear_):
additional_wear(additional_wear_)
{}
virtual ~CraftDefinitionToolRepair(){}
virtual std::string getName() const;
virtual bool check(const CraftInput &input, IGameDef *gamedef) const;
virtual CraftOutput getOutput(const CraftInput &input, IGameDef *gamedef) const;
virtual void decrementInput(CraftInput &input, IGameDef *gamedef) const;
virtual std::string dump() const;
protected:
virtual void serializeBody(std::ostream &os) const;
virtual void deSerializeBody(std::istream &is, int version);
private:
// This is a constant that is added to the wear of the result.
// May be positive or negative, allowed range [-1,1].
// 1 = new tool is completely broken
// 0 = simply add remaining uses of both input tools
// -1 = new tool is completely pristine
float additional_wear;
};
/*
A cooking (in furnace) definition
Supported crafting method: CRAFT_METHOD_COOKING.
*/
class CraftDefinitionCooking: public CraftDefinition
{
public:
CraftDefinitionCooking():
output(""), recipe(""), cooktime()
{}
CraftDefinitionCooking(
const std::string &output_,
const std::string &recipe_,
float cooktime_):
output(output_), recipe(recipe_), cooktime(cooktime_)
{}
virtual ~CraftDefinitionCooking(){}
virtual std::string getName() const;
virtual bool check(const CraftInput &input, IGameDef *gamedef) const;
virtual CraftOutput getOutput(const CraftInput &input, IGameDef *gamedef) const;
virtual void decrementInput(CraftInput &input, IGameDef *gamedef) const;
virtual std::string dump() const;
protected:
virtual void serializeBody(std::ostream &os) const;
virtual void deSerializeBody(std::istream &is, int version);
private:
// Output itemstring
std::string output;
// Recipe itemstring
std::string recipe;
// Time in seconds
float cooktime;
};
/*
A fuel (for furnace) definition
Supported crafting method: CRAFT_METHOD_FUEL.
*/
class CraftDefinitionFuel: public CraftDefinition
{
public:
CraftDefinitionFuel():
recipe(""), burntime()
{}
CraftDefinitionFuel(std::string recipe_, float burntime_):
recipe(recipe_), burntime(burntime_)
{}
virtual ~CraftDefinitionFuel(){}
virtual std::string getName() const;
virtual bool check(const CraftInput &input, IGameDef *gamedef) const;
virtual CraftOutput getOutput(const CraftInput &input, IGameDef *gamedef) const;
virtual void decrementInput(CraftInput &input, IGameDef *gamedef) const;
virtual std::string dump() const;
protected:
virtual void serializeBody(std::ostream &os) const;
virtual void deSerializeBody(std::istream &is, int version);
private:
// Recipe itemstring
std::string recipe;
// Time in seconds
float burntime;
};
/*
Crafting definition manager
*/
class ICraftDefManager class ICraftDefManager
{ {
public: public:
ICraftDefManager(){} ICraftDefManager(){}
virtual ~ICraftDefManager(){} virtual ~ICraftDefManager(){}
virtual InventoryItem* getCraftResult(const CraftPointerInput &input_cpi,
IGameDef *gamedef) const=0; // The main crafting function
virtual bool getCraftResult(CraftInput &input, CraftOutput &output,
bool decrementInput, IGameDef *gamedef) const=0;
virtual void serialize(std::ostream &os)=0; // Print crafting recipes for debugging
virtual std::string dump() const=0;
virtual void serialize(std::ostream &os) const=0;
}; };
class IWritableCraftDefManager : public ICraftDefManager class IWritableCraftDefManager : public ICraftDefManager
@ -95,13 +352,21 @@ class IWritableCraftDefManager : public ICraftDefManager
public: public:
IWritableCraftDefManager(){} IWritableCraftDefManager(){}
virtual ~IWritableCraftDefManager(){} virtual ~IWritableCraftDefManager(){}
virtual InventoryItem* getCraftResult(const CraftPointerInput &input_cpi,
IGameDef *gamedef) const=0; // The main crafting function
virtual bool getCraftResult(CraftInput &input, CraftOutput &output,
virtual void registerCraft(const CraftDefinition &def)=0; bool decrementInput, IGameDef *gamedef) const=0;
// Print crafting recipes for debugging
virtual std::string dump() const=0;
// Add a crafting definition.
// After calling this, the pointer belongs to the manager.
virtual void registerCraft(CraftDefinition *def)=0;
// Delete all crafting definitions
virtual void clear()=0; virtual void clear()=0;
virtual void serialize(std::ostream &os)=0; virtual void serialize(std::ostream &os) const=0;
virtual void deSerialize(std::istream &is)=0; virtual void deSerialize(std::istream &is)=0;
}; };

@ -1,214 +0,0 @@
/*
Minetest-c55
Copyright (C) 2011 celeron55, Perttu Ahola <celeron55@gmail.com>
Copyright (C) 2011 Kahrl <kahrl@gmx.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "craftitemdef.h"
#include "irrlichttypes.h"
#include "log.h"
#include <sstream>
#include "utility.h"
#include <map>
CraftItemDefinition::CraftItemDefinition():
imagename(""),
cookresult_item(""),
furnace_cooktime(3.0),
furnace_burntime(-1.0),
usable(false),
liquids_pointable(false),
dropcount(-1),
stack_max(99)
{}
std::string CraftItemDefinition::dump()
{
std::ostringstream os(std::ios::binary);
os<<"imagename="<<imagename;
os<<", cookresult_item="<<cookresult_item;
os<<", furnace_cooktime="<<furnace_cooktime;
os<<", furnace_burntime="<<furnace_burntime;
os<<", usable="<<usable;
os<<", liquids_pointable="<<liquids_pointable;
os<<", dropcount="<<dropcount;
os<<", stack_max="<<stack_max;
return os.str();
}
void CraftItemDefinition::serialize(std::ostream &os)
{
writeU8(os, 0); // version
os<<serializeString(imagename);
os<<serializeString(cookresult_item);
writeF1000(os, furnace_cooktime);
writeF1000(os, furnace_burntime);
writeU8(os, usable);
writeU8(os, liquids_pointable);
writeS16(os, dropcount);
writeS16(os, stack_max);
}
void CraftItemDefinition::deSerialize(std::istream &is)
{
int version = readU8(is);
if(version != 0) throw SerializationError(
"unsupported CraftItemDefinition version");
imagename = deSerializeString(is);
cookresult_item = deSerializeString(is);
furnace_cooktime = readF1000(is);
furnace_burntime = readF1000(is);
usable = readU8(is);
liquids_pointable = readU8(is);
dropcount = readS16(is);
stack_max = readS16(is);
}
class CCraftItemDefManager: public IWritableCraftItemDefManager
{
public:
virtual ~CCraftItemDefManager()
{
clear();
}
virtual const CraftItemDefinition* getCraftItemDefinition(const std::string &itemname_) const
{
// Convert name according to possible alias
std::string itemname = getAlias(itemname_);
// Get the definition
core::map<std::string, CraftItemDefinition*>::Node *n;
n = m_item_definitions.find(itemname);
if(n == NULL)
return NULL;
return n->getValue();
}
virtual std::string getImagename(const std::string &itemname) const
{
const CraftItemDefinition *def = getCraftItemDefinition(itemname);
if(def == NULL)
return "";
return def->imagename;
}
virtual std::string getAlias(const std::string &name) const
{
std::map<std::string, std::string>::const_iterator i;
i = m_aliases.find(name);
if(i != m_aliases.end())
return i->second;
return name;
}
virtual bool registerCraftItem(std::string itemname, const CraftItemDefinition &def)
{
infostream<<"registerCraftItem: registering CraftItem \""<<itemname<<"\""<<std::endl;
m_item_definitions[itemname] = new CraftItemDefinition(def);
// Remove conflicting alias if it exists
bool alias_removed = (m_aliases.erase(itemname) != 0);
if(alias_removed)
infostream<<"cidef: erased alias "<<itemname
<<" because item was defined"<<std::endl;
return true;
}
virtual void clear()
{
for(core::map<std::string, CraftItemDefinition*>::Iterator
i = m_item_definitions.getIterator();
i.atEnd() == false; i++){
delete i.getNode()->getValue();
}
m_item_definitions.clear();
m_aliases.clear();
}
virtual void setAlias(const std::string &name,
const std::string &convert_to)
{
if(getCraftItemDefinition(name) != NULL){
infostream<<"nidef: not setting alias "<<name<<" -> "<<convert_to
<<": "<<name<<" is already defined"<<std::endl;
return;
}
infostream<<"nidef: setting alias "<<name<<" -> "<<convert_to
<<std::endl;
m_aliases[name] = convert_to;
}
virtual void serialize(std::ostream &os)
{
writeU8(os, 0); // version
u16 count = m_item_definitions.size();
writeU16(os, count);
for(core::map<std::string, CraftItemDefinition*>::Iterator
i = m_item_definitions.getIterator();
i.atEnd() == false; i++){
std::string name = i.getNode()->getKey();
CraftItemDefinition *def = i.getNode()->getValue();
// Serialize name
os<<serializeString(name);
// Serialize CraftItemDefinition and write wrapped in a string
std::ostringstream tmp_os(std::ios::binary);
def->serialize(tmp_os);
os<<serializeString(tmp_os.str());
}
writeU16(os, m_aliases.size());
for(std::map<std::string, std::string>::const_iterator
i = m_aliases.begin(); i != m_aliases.end(); i++)
{
os<<serializeString(i->first);
os<<serializeString(i->second);
}
}
virtual void deSerialize(std::istream &is)
{
// Clear everything
clear();
// Deserialize
int version = readU8(is);
if(version != 0) throw SerializationError(
"unsupported CraftItemDefManager version");
u16 count = readU16(is);
for(u16 i=0; i<count; i++){
// Deserialize name
std::string name = deSerializeString(is);
// Deserialize a string and grab a CraftItemDefinition from it
std::istringstream tmp_is(deSerializeString(is), std::ios::binary);
CraftItemDefinition def;
def.deSerialize(tmp_is);
// Register
registerCraftItem(name, def);
}
u16 num_aliases = readU16(is);
if(!is.eof()){
for(u16 i=0; i<num_aliases; i++){
std::string name = deSerializeString(is);
std::string convert_to = deSerializeString(is);
m_aliases[name] = convert_to;
}
}
}
private:
// Key is name
core::map<std::string, CraftItemDefinition*> m_item_definitions;
// Aliases
std::map<std::string, std::string> m_aliases;
};
IWritableCraftItemDefManager* createCraftItemDefManager()
{
return new CCraftItemDefManager();
}

@ -1,79 +0,0 @@
/*
Minetest-c55
Copyright (C) 2011 celeron55, Perttu Ahola <celeron55@gmail.com>
Copyright (C) 2011 Kahrl <kahrl@gmx.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef CRAFTITEMDEF_HEADER
#define CRAFTITEMDEF_HEADER
#include "common_irrlicht.h"
#include <string>
#include <iostream>
struct CraftItemDefinition
{
std::string imagename;
std::string cookresult_item;
float furnace_cooktime;
float furnace_burntime;
bool usable;
bool liquids_pointable;
s16 dropcount;
s16 stack_max;
CraftItemDefinition();
std::string dump();
void serialize(std::ostream &os);
void deSerialize(std::istream &is);
};
class ICraftItemDefManager
{
public:
ICraftItemDefManager(){}
virtual ~ICraftItemDefManager(){}
virtual const CraftItemDefinition* getCraftItemDefinition(const std::string &itemname) const=0;
virtual std::string getImagename(const std::string &itemname) const =0;
virtual std::string getAlias(const std::string &name) const =0;
virtual void serialize(std::ostream &os)=0;
};
class IWritableCraftItemDefManager : public ICraftItemDefManager
{
public:
IWritableCraftItemDefManager(){}
virtual ~IWritableCraftItemDefManager(){}
virtual const CraftItemDefinition* getCraftItemDefinition(const std::string &itemname) const=0;
virtual std::string getImagename(const std::string &itemname) const =0;
virtual bool registerCraftItem(std::string itemname, const CraftItemDefinition &def)=0;
virtual void clear()=0;
// Set an alias so that entries named <name> will load as <convert_to>.
// Alias is not set if <name> has already been defined.
// Alias will be removed if <name> is defined at a later point of time.
virtual void setAlias(const std::string &name,
const std::string &convert_to)=0;
virtual void serialize(std::ostream &os)=0;
virtual void deSerialize(std::istream &is)=0;
};
IWritableCraftItemDefManager* createCraftItemDefManager();
#endif

@ -39,6 +39,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "activeobject.h" #include "activeobject.h"
class Server; class Server;
class ServerEnvironment;
class ActiveBlockModifier; class ActiveBlockModifier;
class ServerActiveObject; class ServerActiveObject;
typedef struct lua_State lua_State; typedef struct lua_State lua_State;

@ -40,7 +40,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "settings.h" #include "settings.h"
#include "profiler.h" #include "profiler.h"
#include "mainmenumanager.h" #include "mainmenumanager.h"
#include "craftitemdef.h"
#include "gettext.h" #include "gettext.h"
#include "log.h" #include "log.h"
#include "filesys.h" #include "filesys.h"
@ -48,7 +47,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "nodedef.h" #include "nodedef.h"
#include "nodemetadata.h" #include "nodemetadata.h"
#include "main.h" // For g_settings #include "main.h" // For g_settings
#include "tooldef.h" #include "itemdef.h"
#include "tile.h" // For TextureSource #include "tile.h" // For TextureSource
#include "logoutputbuffer.h" #include "logoutputbuffer.h"
@ -79,15 +78,6 @@ struct ChatLine
std::wstring text; std::wstring text;
}; };
/*
Inventory stuff
*/
// Inventory actions from the menu are buffered here before sending
Queue<InventoryAction*> inventory_action_queue;
// This is a copy of the inventory that the client's environment has
Inventory local_inventory;
/* /*
Text input system Text input system
*/ */
@ -156,7 +146,7 @@ private:
Hotbar draw routine Hotbar draw routine
*/ */
void draw_hotbar(video::IVideoDriver *driver, gui::IGUIFont *font, void draw_hotbar(video::IVideoDriver *driver, gui::IGUIFont *font,
ITextureSource *tsrc, IGameDef *gamedef,
v2s32 centerlowerpos, s32 imgsize, s32 itemcount, v2s32 centerlowerpos, s32 imgsize, s32 itemcount,
Inventory *inventory, s32 halfheartcount, u16 playeritem) Inventory *inventory, s32 halfheartcount, u16 playeritem)
{ {
@ -184,7 +174,7 @@ void draw_hotbar(video::IVideoDriver *driver, gui::IGUIFont *font,
for(s32 i=0; i<itemcount; i++) for(s32 i=0; i<itemcount; i++)
{ {
InventoryItem *item = mainlist->getItem(i); const ItemStack &item = mainlist->getItem(i);
core::rect<s32> rect = imgrect + pos core::rect<s32> rect = imgrect + pos
+ v2s32(padding+i*(imgsize+padding*2), padding); + v2s32(padding+i*(imgsize+padding*2), padding);
@ -245,17 +235,14 @@ void draw_hotbar(video::IVideoDriver *driver, gui::IGUIFont *font,
video::SColor bgcolor2(128,0,0,0); video::SColor bgcolor2(128,0,0,0);
driver->draw2DRectangle(bgcolor2, rect, NULL); driver->draw2DRectangle(bgcolor2, rect, NULL);
drawItemStack(driver, font, item, rect, NULL, gamedef);
if(item != NULL)
{
drawInventoryItem(driver, font, item, rect, NULL, tsrc);
}
} }
/* /*
Draw hearts Draw hearts
*/ */
video::ITexture *heart_texture = tsrc->getTextureRaw("heart.png"); video::ITexture *heart_texture =
gamedef->getTextureSource()->getTextureRaw("heart.png");
if(heart_texture) if(heart_texture)
{ {
v2s32 p = pos + v2s32(0, -20); v2s32 p = pos + v2s32(0, -20);
@ -691,12 +678,10 @@ void the_game(
IWritableTextureSource *tsrc = createTextureSource(device); IWritableTextureSource *tsrc = createTextureSource(device);
// These will be filled by data received from the server // These will be filled by data received from the server
// Create tool definition manager // Create item definition manager
IWritableToolDefManager *tooldef = createToolDefManager(); IWritableItemDefManager *itemdef = createItemDefManager();
// Create node definition manager // Create node definition manager
IWritableNodeDefManager *nodedef = createNodeDefManager(); IWritableNodeDefManager *nodedef = createNodeDefManager();
// Create CraftItem definition manager
IWritableCraftItemDefManager *craftitemdef = createCraftItemDefManager();
// Add chat log output for errors to be shown in chat // Add chat log output for errors to be shown in chat
LogOutputBuffer chat_log_error_buf(LMT_ERROR); LogOutputBuffer chat_log_error_buf(LMT_ERROR);
@ -725,7 +710,7 @@ void the_game(
MapDrawControl draw_control; MapDrawControl draw_control;
Client client(device, playername.c_str(), password, draw_control, Client client(device, playername.c_str(), password, draw_control,
tsrc, tooldef, nodedef, craftitemdef); tsrc, itemdef, nodedef);
// Client acts as our GameDef // Client acts as our GameDef
IGameDef *gamedef = &client; IGameDef *gamedef = &client;
@ -835,9 +820,8 @@ void the_game(
// End condition // End condition
if(client.texturesReceived() && if(client.texturesReceived() &&
client.tooldefReceived() && client.itemdefReceived() &&
client.nodedefReceived() && client.nodedefReceived()){
client.craftitemdefReceived()){
got_content = true; got_content = true;
break; break;
} }
@ -853,12 +837,10 @@ void the_game(
ss<<(int)(timeout - time_counter + 1.0); ss<<(int)(timeout - time_counter + 1.0);
ss<<L" seconds)\n"; ss<<L" seconds)\n";
ss<<(client.tooldefReceived()?L"[X]":L"[ ]"); ss<<(client.itemdefReceived()?L"[X]":L"[ ]");
ss<<L" Tool definitions\n"; ss<<L" Item definitions\n";
ss<<(client.nodedefReceived()?L"[X]":L"[ ]"); ss<<(client.nodedefReceived()?L"[X]":L"[ ]");
ss<<L" Node definitions\n"; ss<<L" Node definitions\n";
ss<<(client.craftitemdefReceived()?L"[X]":L"[ ]");
ss<<L" Item definitions\n";
//ss<<(client.texturesReceived()?L"[X]":L"[ ]"); //ss<<(client.texturesReceived()?L"[X]":L"[ ]");
ss<<L"["<<(int)(client.textureReceiveProgress()*100+0.5)<<L"%] "; ss<<L"["<<(int)(client.textureReceiveProgress()*100+0.5)<<L"%] ";
ss<<L" Textures\n"; ss<<L" Textures\n";
@ -871,6 +853,12 @@ void the_game(
} }
} }
/*
After all content has been received:
Update cached textures, meshes and materials
*/
client.afterContentReceived();
/* /*
Create skybox Create skybox
*/ */
@ -910,6 +898,11 @@ void the_game(
farmesh = new FarMesh(smgr->getRootSceneNode(), smgr, -1, client.getMapSeed(), &client); farmesh = new FarMesh(smgr->getRootSceneNode(), smgr, -1, client.getMapSeed(), &client);
} }
/*
A copy of the local inventory
*/
Inventory local_inventory(itemdef);
/* /*
Move into game Move into game
*/ */
@ -1289,7 +1282,7 @@ void the_game(
// drop selected item // drop selected item
IDropAction *a = new IDropAction(); IDropAction *a = new IDropAction();
a->count = 0; a->count = 0;
a->from_inv = "current_player"; a->from_inv.setCurrentPlayer();
a->from_list = "main"; a->from_list = "main";
a->from_i = client.getPlayerItem(); a->from_i = client.getPlayerItem();
client.inventoryAction(a); client.inventoryAction(a);
@ -1302,18 +1295,20 @@ void the_game(
GUIInventoryMenu *menu = GUIInventoryMenu *menu =
new GUIInventoryMenu(guienv, guiroot, -1, new GUIInventoryMenu(guienv, guiroot, -1,
&g_menumgr, v2s16(8,7), &g_menumgr, v2s16(8,7),
client.getInventoryContext(), &client, gamedef);
&client, tsrc);
InventoryLocation inventoryloc;
inventoryloc.setCurrentPlayer();
core::array<GUIInventoryMenu::DrawSpec> draw_spec; core::array<GUIInventoryMenu::DrawSpec> draw_spec;
draw_spec.push_back(GUIInventoryMenu::DrawSpec( draw_spec.push_back(GUIInventoryMenu::DrawSpec(
"list", "current_player", "main", "list", inventoryloc, "main",
v2s32(0, 3), v2s32(8, 4))); v2s32(0, 3), v2s32(8, 4)));
draw_spec.push_back(GUIInventoryMenu::DrawSpec( draw_spec.push_back(GUIInventoryMenu::DrawSpec(
"list", "current_player", "craft", "list", inventoryloc, "craft",
v2s32(3, 0), v2s32(3, 3))); v2s32(3, 0), v2s32(3, 3)));
draw_spec.push_back(GUIInventoryMenu::DrawSpec( draw_spec.push_back(GUIInventoryMenu::DrawSpec(
"list", "current_player", "craftresult", "list", inventoryloc, "craftresult",
v2s32(7, 1), v2s32(1, 1))); v2s32(7, 1), v2s32(1, 1)));
menu->setDrawSpec(draw_spec); menu->setDrawSpec(draw_spec);
@ -1691,31 +1686,20 @@ void the_game(
/* /*
For interaction purposes, get info about the held item For interaction purposes, get info about the held item
- Is it a tool, and what is the toolname? - What item is it?
- Is it a usable item? - Is it a usable item?
- Can it point to liquids? - Can it point to liquids?
*/ */
std::string playeritem_toolname = ""; ItemStack playeritem;
bool playeritem_usable = false; bool playeritem_usable = false;
bool playeritem_liquids_pointable = false; bool playeritem_liquids_pointable = false;
{ {
InventoryList *mlist = local_inventory.getList("main"); InventoryList *mlist = local_inventory.getList("main");
if(mlist != NULL) if(mlist != NULL)
{ {
InventoryItem *item = mlist->getItem(client.getPlayerItem()); playeritem = mlist->getItem(client.getPlayerItem());
if(item) playeritem_usable = playeritem.getDefinition(itemdef).usable;
{ playeritem_liquids_pointable = playeritem.getDefinition(itemdef).liquids_pointable;
if((std::string)item->getName() == "ToolItem")
{
ToolItem *titem = (ToolItem*)item;
playeritem_toolname = titem->getToolName();
}
playeritem_usable = item->isUsable();
playeritem_liquids_pointable =
item->areLiquidsPointable();
}
} }
} }
@ -1845,7 +1829,7 @@ void the_game(
// Get digging properties for material and tool // Get digging properties for material and tool
content_t material = n.getContent(); content_t material = n.getContent();
ToolDiggingProperties tp = ToolDiggingProperties tp =
tooldef->getDiggingProperties(playeritem_toolname); playeritem.getToolDiggingProperties(itemdef);
DiggingProperties prop = DiggingProperties prop =
getDiggingProperties(material, &tp, nodedef); getDiggingProperties(material, &tp, nodedef);
@ -1853,9 +1837,6 @@ void the_game(
if(prop.diggable == false) if(prop.diggable == false)
{ {
/*infostream<<"Material "<<(int)material
<<" not diggable with \""
<<playeritem_toolname<<"\""<<std::endl;*/
// I guess nobody will wait for this long // I guess nobody will wait for this long
dig_time_complete = 10000000.0; dig_time_complete = 10000000.0;
} }
@ -1922,17 +1903,11 @@ void the_game(
if(meta && meta->getInventoryDrawSpecString() != "" && !random_input) if(meta && meta->getInventoryDrawSpecString() != "" && !random_input)
{ {
infostream<<"Launching custom inventory view"<<std::endl; infostream<<"Launching custom inventory view"<<std::endl;
/*
Construct the unique identification string of the node InventoryLocation inventoryloc;
*/ inventoryloc.setNodeMeta(nodepos);
std::string current_name;
current_name += "nodemeta:";
current_name += itos(nodepos.X);
current_name += ",";
current_name += itos(nodepos.Y);
current_name += ",";
current_name += itos(nodepos.Z);
/* /*
Create menu Create menu
*/ */
@ -1942,13 +1917,12 @@ void the_game(
GUIInventoryMenu::makeDrawSpecArrayFromString( GUIInventoryMenu::makeDrawSpecArrayFromString(
draw_spec, draw_spec,
meta->getInventoryDrawSpecString(), meta->getInventoryDrawSpecString(),
current_name); inventoryloc);
GUIInventoryMenu *menu = GUIInventoryMenu *menu =
new GUIInventoryMenu(guienv, guiroot, -1, new GUIInventoryMenu(guienv, guiroot, -1,
&g_menumgr, invsize, &g_menumgr, invsize,
client.getInventoryContext(), &client, gamedef);
&client, tsrc);
menu->setDrawSpec(draw_spec); menu->setDrawSpec(draw_spec);
menu->drop(); menu->drop();
} }
@ -2001,7 +1975,7 @@ void the_game(
v3f objpos = selected_object->getPosition(); v3f objpos = selected_object->getPosition();
v3f dir = (objpos - player_position).normalize(); v3f dir = (objpos - player_position).normalize();
bool disable_send = selected_object->directReportPunch(playeritem_toolname, dir); bool disable_send = selected_object->directReportPunch(playeritem.name, dir);
if(!disable_send) if(!disable_send)
client.interact(0, pointed); client.interact(0, pointed);
} }
@ -2285,24 +2259,12 @@ void the_game(
update_wielded_item_trigger = false; update_wielded_item_trigger = false;
// Update wielded tool // Update wielded tool
InventoryList *mlist = local_inventory.getList("main"); InventoryList *mlist = local_inventory.getList("main");
InventoryItem *item = NULL; ItemStack item;
if(mlist != NULL) if(mlist != NULL)
item = mlist->getItem(client.getPlayerItem()); item = mlist->getItem(client.getPlayerItem());
camera.wield(item, gamedef); camera.wield(item, gamedef);
} }
/*
Send actions returned by the inventory menu
*/
while(inventory_action_queue.size() != 0)
{
InventoryAction *a = inventory_action_queue.pop_front();
client.sendInventoryAction(a);
// Eat it
delete a;
}
/* /*
Drawing begins Drawing begins
*/ */
@ -2411,7 +2373,7 @@ void the_game(
Draw hotbar Draw hotbar
*/ */
{ {
draw_hotbar(driver, font, tsrc, draw_hotbar(driver, font, gamedef,
v2s32(displaycenter.X, screensize.Y), v2s32(displaycenter.X, screensize.Y),
hotbar_imagesize, hotbar_itemcount, &local_inventory, hotbar_imagesize, hotbar_itemcount, &local_inventory,
client.getHP(), client.getPlayerItem()); client.getHP(), client.getPlayerItem());
@ -2482,9 +2444,9 @@ void the_game(
} // Client scope (must be destructed before destructing *def and tsrc } // Client scope (must be destructed before destructing *def and tsrc
delete tooldef;
delete tsrc; delete tsrc;
delete nodedef; delete nodedef;
delete itemdef;
} }

@ -21,11 +21,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define GAMEDEF_HEADER #define GAMEDEF_HEADER
#include <string> #include <string>
#include "irrlichttypes.h"
class IToolDefManager; class IItemDefManager;
class INodeDefManager; class INodeDefManager;
class ICraftDefManager; class ICraftDefManager;
class ICraftItemDefManager;
// Mineral too? // Mineral too?
class ITextureSource; class ITextureSource;
@ -39,10 +39,9 @@ class IGameDef
public: public:
// These are thread-safe IF they are not edited while running threads. // These are thread-safe IF they are not edited while running threads.
// Thus, first they are set up and then they are only read. // Thus, first they are set up and then they are only read.
virtual IToolDefManager* getToolDefManager()=0; virtual IItemDefManager* getItemDefManager()=0;
virtual INodeDefManager* getNodeDefManager()=0; virtual INodeDefManager* getNodeDefManager()=0;
virtual ICraftDefManager* getCraftDefManager()=0; virtual ICraftDefManager* getCraftDefManager()=0;
virtual ICraftItemDefManager* getCraftItemDefManager()=0;
// This is always thread-safe, but referencing the irrlicht texture // This is always thread-safe, but referencing the irrlicht texture
// pointers in other threads than main thread will make things explode. // pointers in other threads than main thread will make things explode.
@ -52,10 +51,9 @@ public:
virtual u16 allocateUnknownNodeId(const std::string &name)=0; virtual u16 allocateUnknownNodeId(const std::string &name)=0;
// Shorthands // Shorthands
IToolDefManager* tdef(){return getToolDefManager();} IItemDefManager* idef(){return getItemDefManager();}
INodeDefManager* ndef(){return getNodeDefManager();} INodeDefManager* ndef(){return getNodeDefManager();}
ICraftDefManager* cdef(){return getCraftDefManager();} ICraftDefManager* cdef(){return getCraftDefManager();}
ICraftItemDefManager* cidef(){return getCraftItemDefManager();}
ITextureSource* tsrc(){return getTextureSource();} ITextureSource* tsrc(){return getTextureSource();}
}; };

@ -20,6 +20,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "guiInventoryMenu.h" #include "guiInventoryMenu.h"
#include "constants.h" #include "constants.h"
#include "gamedef.h"
#include "keycode.h" #include "keycode.h"
#include "strfnd.h" #include "strfnd.h"
#include <IGUICheckBox.h> #include <IGUICheckBox.h>
@ -28,20 +29,21 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <IGUIStaticText.h> #include <IGUIStaticText.h>
#include <IGUIFont.h> #include <IGUIFont.h>
#include "log.h" #include "log.h"
#include "inventorymanager.h"
void drawInventoryItem(video::IVideoDriver *driver, void drawItemStack(video::IVideoDriver *driver,
gui::IGUIFont *font, gui::IGUIFont *font,
InventoryItem *item, core::rect<s32> rect, const ItemStack &item,
const core::rect<s32> &rect,
const core::rect<s32> *clip, const core::rect<s32> *clip,
ITextureSource *tsrc) IGameDef *gamedef)
{ {
if(item == NULL) if(item.empty())
return; return;
video::ITexture *texture = NULL; const ItemDefinition &def = item.getDefinition(gamedef->idef());
texture = item->getImage(); video::ITexture *texture = def.inventory_texture;
// Draw the inventory texture
if(texture != NULL) if(texture != NULL)
{ {
const video::SColor color(255,255,255,255); const video::SColor color(255,255,255,255);
@ -51,34 +53,59 @@ void drawInventoryItem(video::IVideoDriver *driver,
core::dimension2di(texture->getOriginalSize())), core::dimension2di(texture->getOriginalSize())),
clip, colors, true); clip, colors, true);
} }
else
if(def.type == ITEM_TOOL && item.wear != 0)
{ {
video::SColor bgcolor(255,50,50,128); // Draw a progressbar
driver->draw2DRectangle(bgcolor, rect, clip); float barheight = rect.getHeight()/16;
float barpad_x = rect.getWidth()/16;
float barpad_y = rect.getHeight()/16;
core::rect<s32> progressrect(
rect.UpperLeftCorner.X + barpad_x,
rect.LowerRightCorner.Y - barpad_y - barheight,
rect.LowerRightCorner.X - barpad_x,
rect.LowerRightCorner.Y - barpad_y);
// Shrink progressrect by amount of tool damage
float wear = item.wear / 65535.0;
progressrect.LowerRightCorner.X =
wear * progressrect.UpperLeftCorner.X +
(1-wear) * progressrect.LowerRightCorner.X;
// Compute progressbar color
// wear = 0.0: green
// wear = 0.5: yellow
// wear = 1.0: red
video::SColor color(255,255,255,255);
int wear_i = floor(wear * 511);
wear_i = MYMIN(wear_i + 10, 511);
if(wear_i <= 255)
color.set(255, wear_i, 255, 0);
else
color.set(255, 255, 511-wear_i, 0);
driver->draw2DRectangle(color, progressrect, clip);
} }
if(font != NULL) if(font != NULL && item.count >= 2)
{ {
std::string text = item->getText(); // Get the item count as a string
if(font && text != "") std::string text = itos(item.count);
{ v2u32 dim = font->getDimension(narrow_to_wide(text).c_str());
v2u32 dim = font->getDimension(narrow_to_wide(text).c_str()); v2s32 sdim(dim.X,dim.Y);
v2s32 sdim(dim.X,dim.Y);
core::rect<s32> rect2( core::rect<s32> rect2(
/*rect.UpperLeftCorner, /*rect.UpperLeftCorner,
core::dimension2d<u32>(rect.getWidth(), 15)*/ core::dimension2d<u32>(rect.getWidth(), 15)*/
rect.LowerRightCorner - sdim, rect.LowerRightCorner - sdim,
sdim sdim
); );
video::SColor bgcolor(128,0,0,0); video::SColor bgcolor(128,0,0,0);
driver->draw2DRectangle(bgcolor, rect2, clip); driver->draw2DRectangle(bgcolor, rect2, clip);
font->draw(text.c_str(), rect2, video::SColor color(255,255,255,255);
video::SColor(255,255,255,255), false, false, font->draw(text.c_str(), rect2, color, false, false, clip);
clip);
}
} }
} }
@ -90,15 +117,13 @@ GUIInventoryMenu::GUIInventoryMenu(gui::IGUIEnvironment* env,
gui::IGUIElement* parent, s32 id, gui::IGUIElement* parent, s32 id,
IMenuManager *menumgr, IMenuManager *menumgr,
v2s16 menu_size, v2s16 menu_size,
InventoryContext *c,
InventoryManager *invmgr, InventoryManager *invmgr,
ITextureSource *tsrc IGameDef *gamedef
): ):
GUIModalMenu(env, parent, id, menumgr), GUIModalMenu(env, parent, id, menumgr),
m_menu_size(menu_size), m_menu_size(menu_size),
m_c(c),
m_invmgr(invmgr), m_invmgr(invmgr),
m_tsrc(tsrc) m_gamedef(gamedef)
{ {
m_selected_item = NULL; m_selected_item = NULL;
} }
@ -214,15 +239,15 @@ GUIInventoryMenu::ItemSpec GUIInventoryMenu::getItemAtPos(v2s32 p) const
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.inventoryname, s.listname, i); return ItemSpec(s.inventoryloc, s.listname, i);
} }
} }
} }
return ItemSpec("", "", -1); return ItemSpec(InventoryLocation(), "", -1);
} }
void GUIInventoryMenu::drawList(const ListDrawSpec &s, ITextureSource *tsrc) void GUIInventoryMenu::drawList(const ListDrawSpec &s)
{ {
video::IVideoDriver* driver = Environment->getVideoDriver(); video::IVideoDriver* driver = Environment->getVideoDriver();
@ -232,7 +257,7 @@ void GUIInventoryMenu::drawList(const ListDrawSpec &s, ITextureSource *tsrc)
if (skin) if (skin)
font = skin->getFont(); font = skin->getFont();
Inventory *inv = m_invmgr->getInventory(m_c, s.inventoryname); Inventory *inv = m_invmgr->getInventory(s.inventoryloc);
assert(inv); assert(inv);
InventoryList *ilist = inv->getList(s.listname); InventoryList *ilist = inv->getList(s.listname);
@ -244,7 +269,7 @@ void GUIInventoryMenu::drawList(const ListDrawSpec &s, ITextureSource *tsrc)
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;
InventoryItem *item = NULL; ItemStack item;
if(ilist) if(ilist)
item = ilist->getItem(i); item = ilist->getItem(i);
@ -278,10 +303,10 @@ void GUIInventoryMenu::drawList(const ListDrawSpec &s, ITextureSource *tsrc)
driver->draw2DRectangle(bgcolor, rect, &AbsoluteClippingRect); driver->draw2DRectangle(bgcolor, rect, &AbsoluteClippingRect);
} }
if(item) if(!item.empty())
{ {
drawInventoryItem(driver, font, item, drawItemStack(driver, font, item,
rect, &AbsoluteClippingRect, tsrc); rect, &AbsoluteClippingRect, m_gamedef);
} }
} }
@ -303,8 +328,7 @@ void GUIInventoryMenu::drawMenu()
for(u32 i=0; i<m_draw_spec.size(); i++) for(u32 i=0; i<m_draw_spec.size(); i++)
{ {
ListDrawSpec &s = m_draw_spec[i]; drawList(m_draw_spec[i]);
drawList(s, m_tsrc);
} }
/* /*
@ -352,14 +376,14 @@ bool GUIInventoryMenu::OnEvent(const SEvent& event)
//infostream<<"Mouse action at p=("<<p.X<<","<<p.Y<<")"<<std::endl; //infostream<<"Mouse action at p=("<<p.X<<","<<p.Y<<")"<<std::endl;
if(s.isValid()) if(s.isValid())
{ {
infostream<<"Mouse action on "<<s.inventoryname infostream<<"Mouse action on "<<s.inventoryloc.dump()
<<"/"<<s.listname<<" "<<s.i<<std::endl; <<"/"<<s.listname<<" "<<s.i<<std::endl;
if(m_selected_item) if(m_selected_item)
{ {
Inventory *inv_from = m_invmgr->getInventory(m_c, Inventory *inv_from = m_invmgr->getInventory(
m_selected_item->inventoryname); m_selected_item->inventoryloc);
Inventory *inv_to = m_invmgr->getInventory(m_c, Inventory *inv_to = m_invmgr->getInventory(
s.inventoryname); s.inventoryloc);
assert(inv_from); assert(inv_from);
assert(inv_to); assert(inv_to);
InventoryList *list_from = InventoryList *list_from =
@ -373,21 +397,21 @@ bool GUIInventoryMenu::OnEvent(const SEvent& event)
// Indicates whether source slot completely empties // Indicates whether source slot completely empties
bool source_empties = false; bool source_empties = false;
if(list_from && list_to if(list_from && list_to
&& list_from->getItem(m_selected_item->i) != NULL) && !list_from->getItem(m_selected_item->i).empty())
{ {
infostream<<"Handing IACTION_MOVE to manager"<<std::endl; infostream<<"Handing IACTION_MOVE to manager"<<std::endl;
IMoveAction *a = new IMoveAction(); IMoveAction *a = new IMoveAction();
a->count = amount; a->count = amount;
a->from_inv = m_selected_item->inventoryname; a->from_inv = m_selected_item->inventoryloc;
a->from_list = m_selected_item->listname; a->from_list = m_selected_item->listname;
a->from_i = m_selected_item->i; a->from_i = m_selected_item->i;
a->to_inv = s.inventoryname; a->to_inv = s.inventoryloc;
a->to_list = s.listname; a->to_list = s.listname;
a->to_i = s.i; a->to_i = s.i;
//ispec.actions->push_back(a); //ispec.actions->push_back(a);
m_invmgr->inventoryAction(a); m_invmgr->inventoryAction(a);
if(list_from->getItem(m_selected_item->i)->getCount()<=amount) if(list_from->getItem(m_selected_item->i).count<=amount)
source_empties = true; source_empties = true;
} }
// Remove selection if target was left-clicked or source // Remove selection if target was left-clicked or source
@ -401,13 +425,13 @@ bool GUIInventoryMenu::OnEvent(const SEvent& event)
else else
{ {
/* /*
Select if non-NULL Select if nonempty
*/ */
Inventory *inv = m_invmgr->getInventory(m_c, Inventory *inv = m_invmgr->getInventory(
s.inventoryname); s.inventoryloc);
assert(inv); assert(inv);
InventoryList *list = inv->getList(s.listname); InventoryList *list = inv->getList(s.listname);
if(list->getItem(s.i) != NULL) if(!list->getItem(s.i).empty())
{ {
m_selected_item = new ItemSpec(s); m_selected_item = new ItemSpec(s);
} }
@ -489,7 +513,7 @@ bool GUIInventoryMenu::OnEvent(const SEvent& event)
v2s16 GUIInventoryMenu::makeDrawSpecArrayFromString( v2s16 GUIInventoryMenu::makeDrawSpecArrayFromString(
core::array<GUIInventoryMenu::DrawSpec> &draw_spec, core::array<GUIInventoryMenu::DrawSpec> &draw_spec,
const std::string &data, const std::string &data,
const std::string &current_name) const InventoryLocation &current_location)
{ {
v2s16 invsize(8,9); v2s16 invsize(8,9);
Strfnd f(data); Strfnd f(data);
@ -500,8 +524,11 @@ v2s16 GUIInventoryMenu::makeDrawSpecArrayFromString(
if(type == "list") if(type == "list")
{ {
std::string name = f.next(";"); std::string name = f.next(";");
InventoryLocation loc;
if(name == "current_name") if(name == "current_name")
name = current_name; loc = current_location;
else
loc.deSerialize(name);
std::string subname = f.next(";"); std::string subname = f.next(";");
s32 pos_x = stoi(f.next(",")); s32 pos_x = stoi(f.next(","));
s32 pos_y = stoi(f.next(";")); s32 pos_y = stoi(f.next(";"));
@ -512,7 +539,7 @@ v2s16 GUIInventoryMenu::makeDrawSpecArrayFromString(
<<", geom=("<<geom_x<<","<<geom_y<<")" <<", geom=("<<geom_x<<","<<geom_y<<")"
<<std::endl; <<std::endl;
draw_spec.push_back(GUIInventoryMenu::DrawSpec( draw_spec.push_back(GUIInventoryMenu::DrawSpec(
type, name, subname, type, loc, subname,
v2s32(pos_x,pos_y),v2s32(geom_x,geom_y))); v2s32(pos_x,pos_y),v2s32(geom_x,geom_y)));
f.next("]"); f.next("]");
} }

@ -23,18 +23,19 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "common_irrlicht.h" #include "common_irrlicht.h"
#include "inventory.h" #include "inventory.h"
#include "inventorymanager.h"
#include "utility.h" #include "utility.h"
#include "modalMenu.h" #include "modalMenu.h"
class ITextureSource; class IGameDef;
class InventoryContext;
class InventoryManager; class InventoryManager;
void drawInventoryItem(video::IVideoDriver *driver, void drawItemStack(video::IVideoDriver *driver,
gui::IGUIFont *font, gui::IGUIFont *font,
InventoryItem *item, core::rect<s32> rect, const ItemStack &item,
const core::rect<s32> &rect,
const core::rect<s32> *clip, const core::rect<s32> *clip,
ITextureSource *tsrc); IGameDef *gamedef);
class GUIInventoryMenu : public GUIModalMenu class GUIInventoryMenu : public GUIModalMenu
{ {
@ -44,11 +45,11 @@ class GUIInventoryMenu : public GUIModalMenu
{ {
i = -1; i = -1;
} }
ItemSpec(const std::string &a_inventoryname, ItemSpec(const InventoryLocation &a_inventoryloc,
const std::string &a_listname, const std::string &a_listname,
s32 a_i) s32 a_i)
{ {
inventoryname = a_inventoryname; inventoryloc = a_inventoryloc;
listname = a_listname; listname = a_listname;
i = a_i; i = a_i;
} }
@ -57,7 +58,7 @@ class GUIInventoryMenu : public GUIModalMenu
return i != -1; return i != -1;
} }
std::string inventoryname; InventoryLocation inventoryloc;
std::string listname; std::string listname;
s32 i; s32 i;
}; };
@ -67,17 +68,17 @@ class GUIInventoryMenu : public GUIModalMenu
ListDrawSpec() ListDrawSpec()
{ {
} }
ListDrawSpec(const std::string &a_inventoryname, 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)
{ {
inventoryname = a_inventoryname; inventoryloc = a_inventoryloc;
listname = a_listname; listname = a_listname;
pos = a_pos; pos = a_pos;
geom = a_geom; geom = a_geom;
} }
std::string inventoryname; InventoryLocation inventoryloc;
std::string listname; std::string listname;
v2s32 pos; v2s32 pos;
v2s32 geom; v2s32 geom;
@ -89,7 +90,7 @@ public:
{ {
} }
DrawSpec(const std::string &a_type, DrawSpec(const std::string &a_type,
const std::string &a_name, const InventoryLocation &a_name,
const std::string &a_subname, const std::string &a_subname,
v2s32 a_pos, v2s32 a_pos,
v2s32 a_geom) v2s32 a_geom)
@ -102,7 +103,7 @@ public:
} }
std::string type; std::string type;
std::string name; InventoryLocation name;
std::string subname; std::string subname;
v2s32 pos; v2s32 pos;
v2s32 geom; v2s32 geom;
@ -112,15 +113,14 @@ public:
static v2s16 makeDrawSpecArrayFromString( static v2s16 makeDrawSpecArrayFromString(
core::array<GUIInventoryMenu::DrawSpec> &draw_spec, core::array<GUIInventoryMenu::DrawSpec> &draw_spec,
const std::string &data, const std::string &data,
const std::string &current_name); const InventoryLocation &current_location);
GUIInventoryMenu(gui::IGUIEnvironment* env, GUIInventoryMenu(gui::IGUIEnvironment* env,
gui::IGUIElement* parent, s32 id, gui::IGUIElement* parent, s32 id,
IMenuManager *menumgr, IMenuManager *menumgr,
v2s16 menu_size, v2s16 menu_size,
InventoryContext *c,
InventoryManager *invmgr, InventoryManager *invmgr,
ITextureSource *tsrc IGameDef *gamedef
); );
~GUIInventoryMenu(); ~GUIInventoryMenu();
@ -136,7 +136,7 @@ public:
void regenerateGui(v2u32 screensize); void regenerateGui(v2u32 screensize);
ItemSpec getItemAtPos(v2s32 p) const; ItemSpec getItemAtPos(v2s32 p) const;
void drawList(const ListDrawSpec &s, ITextureSource *tsrc); void drawList(const ListDrawSpec &s);
void drawMenu(); void drawMenu();
bool OnEvent(const SEvent& event); bool OnEvent(const SEvent& event);
@ -153,9 +153,8 @@ protected:
v2s32 spacing; v2s32 spacing;
v2s32 imgsize; v2s32 imgsize;
InventoryContext *m_c;
InventoryManager *m_invmgr; InventoryManager *m_invmgr;
ITextureSource *m_tsrc; IGameDef *m_gamedef;
core::array<DrawSpec> m_init_draw_spec; core::array<DrawSpec> m_init_draw_spec;
core::array<ListDrawSpec> m_draw_spec; core::array<ListDrawSpec> m_draw_spec;

File diff suppressed because it is too large Load Diff

@ -23,460 +23,221 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
#include <string> #include <string>
#include <vector>
#include "common_irrlicht.h" #include "common_irrlicht.h"
#include "debug.h" #include "debug.h"
#include "mapnode.h" // For content_t #include "itemdef.h"
#define QUANTITY_ITEM_MAX_COUNT 99 struct ToolDiggingProperties;
class ServerActiveObject; struct ItemStack
class ServerEnvironment;
struct PointedThing;
class ITextureSource;
class IGameDef;
class InventoryItem
{ {
public: ItemStack(): name(""), count(0), wear(0), metadata("") {}
InventoryItem(IGameDef *gamedef, u16 count); ItemStack(std::string name_, u16 count_,
virtual ~InventoryItem(); u16 wear, std::string metadata_,
IItemDefManager *itemdef);
static InventoryItem* deSerialize(std::istream &is, IGameDef *gamedef); ~ItemStack() {}
static InventoryItem* deSerialize(const std::string &str,
IGameDef *gamedef); // Serialization
void serialize(std::ostream &os) const;
virtual const char* getName() const = 0; void deSerialize(std::istream &is, IItemDefManager *itemdef);
// Shall write the name and the parameters void deSerialize(const std::string &s, IItemDefManager *itemdef);
virtual void serialize(std::ostream &os) const = 0;
// Shall make an exact clone of the item
virtual InventoryItem* clone() = 0;
// Return the name of the image for this item
virtual std::string getImageBasename() const { return ""; }
#ifndef SERVER
// Shall return an image of the item (or NULL)
virtual video::ITexture * getImage() const
{ return NULL; }
// Shall return an image of the item without embellishments (or NULL)
virtual video::ITexture * getImageRaw() const
{ return getImage(); }
#endif
// Shall return a text to show in the GUI
virtual std::string getText() { return ""; }
// Returns the string used for inventory // Returns the string used for inventory
virtual std::string getItemString(); std::string getItemString() const;
// Shall return false if item is not known and cannot be used
virtual bool isKnown() const { return true; }
/* /*
Quantity methods Quantity methods
*/ */
// Return true if the item can be add()ed to the other bool empty() const
virtual bool addableTo(const InventoryItem *other) const
{ return false; }
// Return true if the other item contains this item
virtual bool isSubsetOf(const InventoryItem *other) const
{ return false; }
// Remove the other item from this one if possible and return true
// Return false if not possible
virtual bool removeOther(const InventoryItem *other)
{ return false; }
u16 getCount() const
{ return m_count; }
void setCount(u16 count)
{ m_count = count; }
u16 freeSpace() const
{ {
u16 max = getStackMax(); return count == 0;
if(m_count > max)
return 0;
return max - m_count;
} }
void add(u16 count) void clear()
{ {
m_count += count; name = "";
} count = 0;
void remove(u16 count) wear = 0;
{ metadata = "";
assert(m_count >= count);
m_count -= count;
} }
/* void add(u16 n)
Other properties {
*/ count += n;
}
void remove(u16 n)
{
assert(count >= n);
count -= n;
if(count == 0)
clear(); // reset name, wear and metadata too
}
// Maximum size of a stack // Maximum size of a stack
virtual u16 getStackMax() const {return 1;} u16 getStackMax(IItemDefManager *itemdef) const
// Whether it can be used
virtual bool isUsable() const {return false;}
// Whether it can be cooked
virtual bool isCookable() const {return false;}
// Result of cooking (can randomize)
virtual InventoryItem *createCookResult() const {return NULL;}
// Time of cooking
virtual float getCookTime() const {return 3.0;}
// Whether it can be burned (<0 = cannot be burned)
virtual float getBurnTime() const {return -1;}
// Gets amount of items that dropping one ItemSAO will decrement
// -1 means as many as possible
virtual s16 getDropCount() const { return -1; }
// Whether this item can point to liquids
virtual bool areLiquidsPointable() const { return false; }
// Creates an object from the item and places it in the world.
// If return value is true, item should be removed.
virtual bool dropOrPlace(ServerEnvironment *env,
ServerActiveObject *dropper,
v3f pos, bool place, s16 count);
// Eat, press, activate, whatever.
// Called when item is left-clicked while in hand.
// If returns true, item shall be deleted.
virtual bool use(ServerEnvironment *env,
ServerActiveObject *user,
const PointedThing& pointed){return false;}
protected:
IGameDef *m_gamedef;
u16 m_count;
};
class MaterialItem : public InventoryItem
{
public:
MaterialItem(IGameDef *gamedef, std::string nodename, u16 count);
// Legacy constructor
MaterialItem(IGameDef *gamedef, content_t content, u16 count);
/*
Implementation interface
*/
virtual const char* getName() const
{ {
return "MaterialItem"; s16 max = itemdef->get(name).stack_max;
} return (max >= 0) ? max : 0;
virtual void serialize(std::ostream &os) const
{
os<<"node";
os<<" \"";
os<<m_nodename;
os<<"\" ";
os<<m_count;
}
virtual InventoryItem* clone()
{
return new MaterialItem(m_gamedef, m_nodename, m_count);
}
#ifndef SERVER
video::ITexture * getImage() const;
#endif
std::string getText()
{
std::ostringstream os;
os<<m_count;
return os.str();
} }
virtual bool addableTo(const InventoryItem *other) const // Number of items that can be added to this stack
u16 freeSpace(IItemDefManager *itemdef) const
{ {
if(std::string(other->getName()) != "MaterialItem") u16 max = getStackMax(itemdef);
return false; if(count > max)
MaterialItem *m = (MaterialItem*)other; return 0;
if(m->m_nodename != m_nodename) return max - count;
return false;
return true;
}
virtual bool isSubsetOf(const InventoryItem *other) const
{
if(std::string(other->getName()) != "MaterialItem")
return false;
MaterialItem *m = (MaterialItem*)other;
if(m->m_nodename != m_nodename)
return false;
return m_count <= m->m_count;
}
virtual bool removeOther(const InventoryItem *other)
{
if(!other->isSubsetOf(this))
return false;
MaterialItem *m = (MaterialItem*)other;
m_count += m->m_count;
return true;
} }
u16 getStackMax() const // Returns false if item is not known and cannot be used
bool isKnown(IItemDefManager *itemdef) const
{ {
return QUANTITY_ITEM_MAX_COUNT; return itemdef->isKnown(name);
} }
/* // Returns a pointer to the item definition struct,
Other properties // or a fallback one (name="unknown") if the item is unknown.
*/ const ItemDefinition& getDefinition(
bool isCookable() const; IItemDefManager *itemdef) const
InventoryItem *createCookResult() const;
float getCookTime() const;
float getBurnTime() const;
/*
Special properties (not part of virtual interface)
*/
std::string getNodeName() const
{ return m_nodename; }
content_t getMaterial() const;
private:
std::string m_nodename;
};
/*
An item that is used as a mid-product when crafting.
Subnames:
- Stick
*/
class CraftItem : public InventoryItem
{
public:
CraftItem(IGameDef *gamedef, std::string subname, u16 count);
/*
Implementation interface
*/
virtual const char* getName() const
{ {
return "CraftItem"; return itemdef->get(name);
}
virtual void serialize(std::ostream &os) const
{
os<<"craft";
os<<" \"";
os<<m_subname;
os<<"\" ";
os<<m_count;
}
virtual InventoryItem* clone()
{
return new CraftItem(m_gamedef, m_subname, m_count);
}
#ifndef SERVER
video::ITexture * getImage() const;
#endif
std::string getText()
{
std::ostringstream os;
os<<m_count;
return os.str();
} }
virtual bool isKnown() const; // Get tool digging properties, or those of the hand if not a tool
const ToolDiggingProperties& getToolDiggingProperties(
virtual bool addableTo(const InventoryItem *other) const IItemDefManager *itemdef) const
{ {
if(std::string(other->getName()) != "CraftItem") ToolDiggingProperties *prop;
return false; prop = itemdef->get(name).tool_digging_properties;
CraftItem *m = (CraftItem*)other; if(prop == NULL)
if(m->m_subname != m_subname) prop = itemdef->get("").tool_digging_properties;
return false; assert(prop != NULL);
return true; return *prop;
}
virtual bool isSubsetOf(const InventoryItem *other) const
{
if(std::string(other->getName()) != "CraftItem")
return false;
CraftItem *m = (CraftItem*)other;
if(m->m_subname != m_subname)
return false;
return m_count <= m->m_count;
}
virtual bool removeOther(const InventoryItem *other)
{
if(!other->isSubsetOf(this))
return false;
CraftItem *m = (CraftItem*)other;
m_count += m->m_count;
return true;
} }
/* // Wear out (only tools)
Other properties // Returns true if the item is (was) a tool
*/ bool addWear(s32 amount, IItemDefManager *itemdef)
u16 getStackMax() const;
bool isUsable() const;
bool isCookable() const;
InventoryItem *createCookResult() const;
float getCookTime() const;
float getBurnTime() const;
s16 getDropCount() const;
bool areLiquidsPointable() const;
bool dropOrPlace(ServerEnvironment *env,
ServerActiveObject *dropper,
v3f pos, bool place, s16 count);
bool use(ServerEnvironment *env,
ServerActiveObject *user,
const PointedThing& pointed);
/*
Special methods
*/
std::string getSubName()
{ {
return m_subname; if(getDefinition(itemdef).type == ITEM_TOOL)
}
private:
std::string m_subname;
};
class ToolItem : public InventoryItem
{
public:
ToolItem(IGameDef *gamedef, std::string toolname, u16 wear);
/*
Implementation interface
*/
virtual const char* getName() const
{
return "ToolItem";
}
virtual void serialize(std::ostream &os) const
{
os<<"tool";
os<<" \"";
os<<m_toolname;
os<<"\" ";
os<<m_wear;
}
virtual InventoryItem* clone()
{
return new ToolItem(m_gamedef, m_toolname, m_wear);
}
std::string getImageBasename() const;
#ifndef SERVER
video::ITexture * getImage() const;
video::ITexture * getImageRaw() const;
#endif
std::string getText()
{
return "";
}
virtual bool isKnown() const;
virtual bool isSubsetOf(const InventoryItem *other) const
{
if(std::string(other->getName()) != "ToolItem")
return false;
ToolItem *m = (ToolItem*)other;
if(m->m_toolname != m_toolname)
return false;
return m_wear <= m->m_wear;
}
virtual bool removeOther(const InventoryItem *other)
{
if(!other->isSubsetOf(this))
return false;
ToolItem *m = (ToolItem*)other;
m_wear -= m->m_wear;
return true;
}
/*
Special methods
*/
std::string getToolName()
{
return m_toolname;
}
u16 getWear()
{
return m_wear;
}
// Returns true if weared out
bool addWear(u16 add)
{
if(m_wear >= 65535 - add)
{ {
m_wear = 65535; if(amount > 65535 - wear)
clear();
else if(amount < -wear)
wear = 0;
else
wear += amount;
return true; return true;
} }
else else
{ {
m_wear += add;
return false; return false;
} }
} }
private:
std::string m_toolname; // If possible, adds newitem to this item.
u16 m_wear; // If cannot be added at all, returns the item back.
// If can be added partly, decremented item is returned back.
// If can be added fully, empty item is returned.
ItemStack addItem(const ItemStack &newitem,
IItemDefManager *itemdef);
// Checks whether newitem could be added.
// If restitem is non-NULL, it receives the part of newitem that
// would be left over after adding.
bool itemFits(const ItemStack &newitem,
ItemStack *restitem, // may be NULL
IItemDefManager *itemdef) const;
// Takes some items.
// If there are not enough, takes as many as it can.
// Returns empty item if couldn't take any.
ItemStack takeItem(u32 takecount);
// Similar to takeItem, but keeps this ItemStack intact.
ItemStack peekItem(u32 peekcount) const;
/*
Properties
*/
std::string name;
u16 count;
u16 wear;
std::string metadata;
}; };
class InventoryList class InventoryList
{ {
public: public:
InventoryList(std::string name, u32 size); InventoryList(std::string name, u32 size, IItemDefManager *itemdef);
~InventoryList(); ~InventoryList();
void clearItems(); void clearItems();
void setSize(u32 newsize); void setSize(u32 newsize);
void serialize(std::ostream &os) const; void serialize(std::ostream &os) const;
void deSerialize(std::istream &is, IGameDef *gamedef); void deSerialize(std::istream &is);
InventoryList(const InventoryList &other); InventoryList(const InventoryList &other);
InventoryList & operator = (const InventoryList &other); InventoryList & operator = (const InventoryList &other);
const std::string &getName() const; const std::string &getName() const;
u32 getSize(); u32 getSize() const;
// Count used slots // Count used slots
u32 getUsedSlots(); u32 getUsedSlots() const;
u32 getFreeSlots(); u32 getFreeSlots() const;
/*bool getDirty(){ return m_dirty; } // Get reference to item
void setDirty(bool dirty=true){ m_dirty = dirty; }*/ const ItemStack& getItem(u32 i) const;
ItemStack& getItem(u32 i);
// Get pointer to item // Returns old item. Parameter can be an empty item.
const InventoryItem * getItem(u32 i) const; ItemStack changeItem(u32 i, const ItemStack &newitem);
InventoryItem * getItem(u32 i);
// Returns old item (or NULL). Parameter can be NULL.
InventoryItem * changeItem(u32 i, InventoryItem *newitem);
// Delete item // Delete item
void deleteItem(u32 i); void deleteItem(u32 i);
// Adds an item to a suitable place. Returns leftover item. // Adds an item to a suitable place. Returns leftover item (possibly empty).
// If all went into the list, returns NULL. ItemStack addItem(const ItemStack &newitem);
InventoryItem * addItem(InventoryItem *newitem);
// If possible, adds item to given slot. // If possible, adds item to given slot.
// If cannot be added at all, returns the item back. // If cannot be added at all, returns the item back.
// If can be added partly, decremented item is returned back. // If can be added partly, decremented item is returned back.
// If can be added fully, NULL is returned. // If can be added fully, empty item is returned.
InventoryItem * addItem(u32 i, InventoryItem *newitem); ItemStack addItem(u32 i, const ItemStack &newitem);
// Checks whether the item could be added to the given slot // Checks whether the item could be added to the given slot
bool itemFits(const u32 i, const InventoryItem *newitem); // If restitem is non-NULL, it receives the part of newitem that
// would be left over after adding.
bool itemFits(const u32 i, const ItemStack &newitem,
ItemStack *restitem = NULL) const;
// Checks whether there is room for a given item // Checks whether there is room for a given item
bool roomForItem(const InventoryItem *item); bool roomForItem(const ItemStack &item) const;
// Checks whether there is room for a given item aftr it has been cooked // Checks whether the given count of the given item name
bool roomForCookedItem(const InventoryItem *item); // exists in this inventory list.
bool containsItem(const ItemStack &item) const;
// Removes the given count of the given item name from
// this inventory list. Walks the list in reverse order.
// If not as many items exist as requested, removes as
// many as possible.
// Returns the items that were actually removed.
ItemStack removeItem(const ItemStack &item);
// Takes some items from a slot. // Takes some items from a slot.
// If there are not enough, takes as many as it can. // If there are not enough, takes as many as it can.
// Returns NULL if couldn't take any. // Returns empty item if couldn't take any.
InventoryItem * takeItem(u32 i, u32 count); ItemStack takeItem(u32 i, u32 takecount);
// Decrements amount of every material item // Similar to takeItem, but keeps the slot intact.
void decrementMaterials(u16 count); ItemStack peekItem(u32 i, u32 peekcount) const;
void print(std::ostream &o);
private: private:
core::array<InventoryItem*> m_items; std::vector<ItemStack> m_items;
u32 m_size; u32 m_size;
std::string m_name; std::string m_name;
//bool m_dirty; IItemDefManager *m_itemdef;
}; };
class Inventory class Inventory
@ -486,20 +247,19 @@ public:
void clear(); void clear();
Inventory(); Inventory(IItemDefManager *itemdef);
Inventory(const Inventory &other); Inventory(const Inventory &other);
Inventory & operator = (const Inventory &other); Inventory & operator = (const Inventory &other);
void serialize(std::ostream &os) const; void serialize(std::ostream &os) const;
void deSerialize(std::istream &is, IGameDef *gamedef); void deSerialize(std::istream &is);
InventoryList * addList(const std::string &name, u32 size); InventoryList * addList(const std::string &name, u32 size);
InventoryList * getList(const std::string &name); InventoryList * getList(const std::string &name);
const InventoryList * getList(const std::string &name) const; const InventoryList * getList(const std::string &name) const;
bool deleteList(const std::string &name); bool deleteList(const std::string &name);
// A shorthand for adding items. // A shorthand for adding items. Returns leftover item (possibly empty).
// Returns NULL if the item was fully added, leftover otherwise. ItemStack addItem(const std::string &listname, const ItemStack &newitem)
InventoryItem * addItem(const std::string &listname, InventoryItem *newitem)
{ {
InventoryList *list = getList(listname); InventoryList *list = getList(listname);
if(list == NULL) if(list == NULL)
@ -511,7 +271,8 @@ private:
// -1 if not found // -1 if not found
const s32 getListIndex(const std::string &name) const; const s32 getListIndex(const std::string &name) const;
core::array<InventoryList*> m_lists; std::vector<InventoryList*> m_lists;
IItemDefManager *m_itemdef;
}; };
#endif #endif

@ -18,73 +18,91 @@ with this program; if not, write to the Free Software Foundation, Inc.,
*/ */
#include "inventorymanager.h" #include "inventorymanager.h"
#include "serverremoteplayer.h"
#include "log.h" #include "log.h"
#include "mapblock.h" // getNodeBlockPos #include "environment.h"
#include "scriptapi.h"
#include "serverobject.h"
#include "main.h" // for g_settings
#include "settings.h"
#include "utility.h"
/* /*
InventoryManager InventoryLocation
*/ */
// Wrapper for old code std::string InventoryLocation::dump() const
Inventory* InventoryManager::getInventory(InventoryContext *c, std::string id)
{ {
if(id == "current_player") std::ostringstream os(std::ios::binary);
{ serialize(os);
assert(c->current_player); return os.str();
InventoryLocation loc;
loc.setPlayer(c->current_player->getName());
return getInventory(loc);
}
Strfnd fn(id);
std::string id0 = fn.next(":");
if(id0 == "nodemeta")
{
v3s16 p;
p.X = stoi(fn.next(","));
p.Y = stoi(fn.next(","));
p.Z = stoi(fn.next(","));
InventoryLocation loc;
loc.setNodeMeta(p);
return getInventory(loc);
}
errorstream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
return NULL;
} }
// Wrapper for old code
void InventoryManager::inventoryModified(InventoryContext *c, std::string id)
{
if(id == "current_player")
{
assert(c->current_player);
InventoryLocation loc;
loc.setPlayer(c->current_player->getName());
setInventoryModified(loc);
return;
}
Strfnd fn(id);
std::string id0 = fn.next(":");
if(id0 == "nodemeta") void InventoryLocation::serialize(std::ostream &os) const
{
switch(type){
case InventoryLocation::UNDEFINED:
{
os<<"undefined";
}
break;
case InventoryLocation::CURRENT_PLAYER:
{
os<<"current_player";
}
break;
case InventoryLocation::PLAYER:
{
os<<"player:"<<name;
}
break;
case InventoryLocation::NODEMETA:
{
os<<"nodemeta:"<<p.X<<","<<p.Y<<","<<p.Z;
}
break;
default:
assert(0);
}
}
void InventoryLocation::deSerialize(std::istream &is)
{
std::string tname;
std::getline(is, tname, ':');
if(tname == "undefined")
{ {
v3s16 p; type = InventoryLocation::UNDEFINED;
}
else if(tname == "current_player")
{
type = InventoryLocation::CURRENT_PLAYER;
}
else if(tname == "player")
{
type = InventoryLocation::PLAYER;
std::getline(is, name, '\n');
}
else if(tname == "nodemeta")
{
type = InventoryLocation::NODEMETA;
std::string pos;
std::getline(is, pos, '\n');
Strfnd fn(pos);
p.X = stoi(fn.next(",")); p.X = stoi(fn.next(","));
p.Y = stoi(fn.next(",")); p.Y = stoi(fn.next(","));
p.Z = stoi(fn.next(",")); p.Z = stoi(fn.next(","));
v3s16 blockpos = getNodeBlockPos(p);
InventoryLocation loc;
loc.setNodeMeta(p);
setInventoryModified(loc);
return;
} }
else
{
infostream<<"Unknown InventoryLocation type=\""<<tname<<"\""<<std::endl;
throw SerializationError("Unknown InventoryLocation type");
}
}
errorstream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl; void InventoryLocation::deSerialize(std::string s)
{
std::istringstream is(s, std::ios::binary);
deSerialize(is);
} }
/* /*
@ -110,14 +128,6 @@ InventoryAction * InventoryAction::deSerialize(std::istream &is)
return a; return a;
} }
static std::string describeC(const struct InventoryContext *c)
{
if(c->current_player == NULL)
return "current_player=NULL";
else
return std::string("current_player=") + c->current_player->getName();
}
IMoveAction::IMoveAction(std::istream &is) IMoveAction::IMoveAction(std::istream &is)
{ {
std::string ts; std::string ts;
@ -125,14 +135,16 @@ IMoveAction::IMoveAction(std::istream &is)
std::getline(is, ts, ' '); std::getline(is, ts, ' ');
count = stoi(ts); count = stoi(ts);
std::getline(is, from_inv, ' '); std::getline(is, ts, ' ');
from_inv.deSerialize(ts);
std::getline(is, from_list, ' '); std::getline(is, from_list, ' ');
std::getline(is, ts, ' '); std::getline(is, ts, ' ');
from_i = stoi(ts); from_i = stoi(ts);
std::getline(is, to_inv, ' '); std::getline(is, ts, ' ');
to_inv.deSerialize(ts);
std::getline(is, to_list, ' '); std::getline(is, to_list, ' ');
@ -140,22 +152,21 @@ IMoveAction::IMoveAction(std::istream &is)
to_i = stoi(ts); to_i = stoi(ts);
} }
void IMoveAction::apply(InventoryContext *c, InventoryManager *mgr, void IMoveAction::apply(InventoryManager *mgr, ServerActiveObject *player)
ServerEnvironment *env)
{ {
Inventory *inv_from = mgr->getInventory(c, from_inv); Inventory *inv_from = mgr->getInventory(from_inv);
Inventory *inv_to = mgr->getInventory(c, to_inv); Inventory *inv_to = mgr->getInventory(to_inv);
if(!inv_from){ if(!inv_from){
infostream<<"IMoveAction::apply(): FAIL: source inventory not found: " infostream<<"IMoveAction::apply(): FAIL: source inventory not found: "
<<"context=["<<describeC(c)<<"], from_inv=\""<<from_inv<<"\"" <<"from_inv=\""<<from_inv.dump()<<"\""
<<", to_inv=\""<<to_inv<<"\""<<std::endl; <<", to_inv=\""<<to_inv.dump()<<"\""<<std::endl;
return; return;
} }
if(!inv_to){ if(!inv_to){
infostream<<"IMoveAction::apply(): FAIL: destination inventory not found: " infostream<<"IMoveAction::apply(): FAIL: destination inventory not found: "
"context=["<<describeC(c)<<"], from_inv=\""<<from_inv<<"\"" <<"from_inv=\""<<from_inv.dump()<<"\""
<<", to_inv=\""<<to_inv<<"\""<<std::endl; <<", to_inv=\""<<to_inv.dump()<<"\""<<std::endl;
return; return;
} }
@ -167,20 +178,20 @@ void IMoveAction::apply(InventoryContext *c, InventoryManager *mgr,
*/ */
if(!list_from){ if(!list_from){
infostream<<"IMoveAction::apply(): FAIL: source list not found: " infostream<<"IMoveAction::apply(): FAIL: source list not found: "
<<"context=["<<describeC(c)<<"], from_inv=\""<<from_inv<<"\"" <<"from_inv=\""<<from_inv.dump()<<"\""
<<", from_list=\""<<from_list<<"\""<<std::endl; <<", from_list=\""<<from_list<<"\""<<std::endl;
return; return;
} }
if(!list_to){ if(!list_to){
infostream<<"IMoveAction::apply(): FAIL: destination list not found: " infostream<<"IMoveAction::apply(): FAIL: destination list not found: "
<<"context=["<<describeC(c)<<"], to_inv=\""<<to_inv<<"\"" <<"to_inv=\""<<to_inv.dump()<<"\""
<<", to_list=\""<<to_list<<"\""<<std::endl; <<", to_list=\""<<to_list<<"\""<<std::endl;
return; return;
} }
if(list_from->getItem(from_i) == NULL) if(list_from->getItem(from_i).empty())
{ {
infostream<<"IMoveAction::apply(): FAIL: source item not found: " infostream<<"IMoveAction::apply(): FAIL: source item not found: "
<<"context=["<<describeC(c)<<"], from_inv=\""<<from_inv<<"\"" <<"from_inv=\""<<from_inv.dump()<<"\""
<<", from_list=\""<<from_list<<"\"" <<", from_list=\""<<from_list<<"\""
<<" from_i="<<from_i<<std::endl; <<" from_i="<<from_i<<std::endl;
return; return;
@ -191,27 +202,28 @@ void IMoveAction::apply(InventoryContext *c, InventoryManager *mgr,
if(inv_from == inv_to && list_from == list_to && from_i == to_i) if(inv_from == inv_to && list_from == list_to && from_i == to_i)
{ {
infostream<<"IMoveAction::apply(): FAIL: source and destination slots " infostream<<"IMoveAction::apply(): FAIL: source and destination slots "
<<"are the same: inv=\""<<from_inv<<"\" list=\""<<from_list <<"are the same: inv=\""<<from_inv.dump()
<<"\" list=\""<<from_list
<<"\" i="<<from_i<<std::endl; <<"\" i="<<from_i<<std::endl;
return; return;
} }
// Take item from source list // Take item from source list
InventoryItem *item1 = NULL; ItemStack item1;
if(count == 0) if(count == 0)
item1 = list_from->changeItem(from_i, NULL); item1 = list_from->changeItem(from_i, ItemStack());
else else
item1 = list_from->takeItem(from_i, count); item1 = list_from->takeItem(from_i, count);
// Try to add the item to destination list // Try to add the item to destination list
InventoryItem *olditem = item1; int oldcount = item1.count;
item1 = list_to->addItem(to_i, item1); item1 = list_to->addItem(to_i, item1);
// If something is returned, the item was not fully added // If something is returned, the item was not fully added
if(item1 != NULL) if(!item1.empty())
{ {
// If olditem is returned, nothing was added. // If olditem is returned, nothing was added.
bool nothing_added = (item1 == olditem); bool nothing_added = (item1.count == oldcount);
// If something else is returned, part of the item was left unadded. // If something else is returned, part of the item was left unadded.
// Add the other part back to the source item // Add the other part back to the source item
@ -222,24 +234,24 @@ void IMoveAction::apply(InventoryContext *c, InventoryManager *mgr,
if(nothing_added) if(nothing_added)
{ {
// Take item from source list // Take item from source list
item1 = list_from->changeItem(from_i, NULL); item1 = list_from->changeItem(from_i, ItemStack());
// Adding was not possible, swap the items. // Adding was not possible, swap the items.
InventoryItem *item2 = list_to->changeItem(to_i, item1); ItemStack item2 = list_to->changeItem(to_i, item1);
// Put item from destination list to the source list // Put item from destination list to the source list
list_from->changeItem(from_i, item2); list_from->changeItem(from_i, item2);
} }
} }
mgr->inventoryModified(c, from_inv); mgr->setInventoryModified(from_inv);
if(from_inv != to_inv) if(inv_from != inv_to)
mgr->inventoryModified(c, to_inv); mgr->setInventoryModified(to_inv);
infostream<<"IMoveAction::apply(): moved at " infostream<<"IMoveAction::apply(): moved at "
<<"["<<describeC(c)<<"]" <<" count="<<count<<"\""
<<" from inv=\""<<from_inv<<"\"" <<" from inv=\""<<from_inv.dump()<<"\""
<<" list=\""<<from_list<<"\"" <<" list=\""<<from_list<<"\""
<<" i="<<from_i <<" i="<<from_i
<<" to inv=\""<<to_inv<<"\"" <<" to inv=\""<<to_inv.dump()<<"\""
<<" list=\""<<to_list<<"\"" <<" list=\""<<to_list<<"\""
<<" i="<<to_i <<" i="<<to_i
<<std::endl; <<std::endl;
@ -252,7 +264,8 @@ IDropAction::IDropAction(std::istream &is)
std::getline(is, ts, ' '); std::getline(is, ts, ' ');
count = stoi(ts); count = stoi(ts);
std::getline(is, from_inv, ' '); std::getline(is, ts, ' ');
from_inv.deSerialize(ts);
std::getline(is, from_list, ' '); std::getline(is, from_list, ' ');
@ -260,27 +273,13 @@ IDropAction::IDropAction(std::istream &is)
from_i = stoi(ts); from_i = stoi(ts);
} }
void IDropAction::apply(InventoryContext *c, InventoryManager *mgr, void IDropAction::apply(InventoryManager *mgr, ServerActiveObject *player)
ServerEnvironment *env)
{ {
if(c->current_player == NULL){ Inventory *inv_from = mgr->getInventory(from_inv);
infostream<<"IDropAction::apply(): FAIL: current_player is NULL"<<std::endl;
return;
}
// Do NOT cast directly to ServerActiveObject*, it breaks
// because of multiple inheritance.
ServerActiveObject *dropper =
static_cast<ServerActiveObject*>(
static_cast<ServerRemotePlayer*>(
c->current_player
));
Inventory *inv_from = mgr->getInventory(c, from_inv);
if(!inv_from){ if(!inv_from){
infostream<<"IDropAction::apply(): FAIL: source inventory not found: " infostream<<"IDropAction::apply(): FAIL: source inventory not found: "
<<"context=["<<describeC(c)<<"], from_inv=\""<<from_inv<<"\""<<std::endl; <<"from_inv=\""<<from_inv.dump()<<"\""<<std::endl;
return; return;
} }
@ -291,254 +290,35 @@ void IDropAction::apply(InventoryContext *c, InventoryManager *mgr,
*/ */
if(!list_from){ if(!list_from){
infostream<<"IDropAction::apply(): FAIL: source list not found: " infostream<<"IDropAction::apply(): FAIL: source list not found: "
<<"context=["<<describeC(c)<<"], from_inv=\""<<from_inv<<"\"" <<"from_inv=\""<<from_inv.dump()<<"\""<<std::endl;
<<", from_list=\""<<from_list<<"\""<<std::endl;
return; return;
} }
InventoryItem *item = list_from->getItem(from_i); if(list_from->getItem(from_i).empty())
if(item == NULL)
{ {
infostream<<"IDropAction::apply(): FAIL: source item not found: " infostream<<"IDropAction::apply(): FAIL: source item not found: "
<<"context=["<<describeC(c)<<"], from_inv=\""<<from_inv<<"\"" <<"from_inv=\""<<from_inv.dump()<<"\""
<<", from_list=\""<<from_list<<"\"" <<", from_list=\""<<from_list<<"\""
<<" from_i="<<from_i<<std::endl; <<" from_i="<<from_i<<std::endl;
return; return;
} }
v3f pos = dropper->getBasePosition();
pos.Y += 0.5*BS;
s16 count2 = count;
if(count2 == 0)
count2 = -1;
/* /*
Drop the item Drop the item
*/ */
bool remove = item->dropOrPlace(env, dropper, pos, false, count2); ItemStack item = list_from->getItem(from_i);
if(remove) if(scriptapi_item_on_drop(player->getEnv()->getLua(), item, player,
list_from->deleteItem(from_i); player->getBasePosition() + v3f(0,1,0)))
{
mgr->inventoryModified(c, from_inv); // Apply returned ItemStack
if(g_settings->getBool("creative_mode") == false
|| from_inv.type != InventoryLocation::PLAYER)
list_from->changeItem(from_i, item);
mgr->setInventoryModified(from_inv);
}
infostream<<"IDropAction::apply(): dropped " infostream<<"IDropAction::apply(): dropped "
<<"["<<describeC(c)<<"]" <<" from inv=\""<<from_inv.dump()<<"\""
<<" from inv=\""<<from_inv<<"\""
<<" list=\""<<from_list<<"\"" <<" list=\""<<from_list<<"\""
<<" i="<<from_i <<" i="<<from_i
<<std::endl; <<std::endl;
} }
/*
Craft checking system
*/
bool ItemSpec::checkItem(const InventoryItem *item) const
{
if(type == ITEM_NONE)
{
// Has to be no item
if(item != NULL)
return false;
return true;
}
// There should be an item
if(item == NULL)
return false;
std::string itemname = item->getName();
if(type == ITEM_MATERIAL)
{
if(itemname != "MaterialItem")
return false;
MaterialItem *mitem = (MaterialItem*)item;
if(num != 65535){
if(mitem->getMaterial() != num)
return false;
} else {
if(mitem->getNodeName() != name)
return false;
}
}
else if(type == ITEM_CRAFT)
{
if(itemname != "CraftItem")
return false;
CraftItem *mitem = (CraftItem*)item;
if(mitem->getSubName() != name)
return false;
}
else if(type == ITEM_TOOL)
{
// Not supported yet
assert(0);
}
else if(type == ITEM_MBO)
{
// Not supported yet
assert(0);
}
else
{
// Not supported yet
assert(0);
}
return true;
}
bool checkItemCombination(InventoryItem const * const *items, const ItemSpec *specs)
{
u16 items_min_x = 100;
u16 items_max_x = 100;
u16 items_min_y = 100;
u16 items_max_y = 100;
for(u16 y=0; y<3; y++)
for(u16 x=0; x<3; x++)
{
if(items[y*3 + x] == NULL)
continue;
if(items_min_x == 100 || x < items_min_x)
items_min_x = x;
if(items_min_y == 100 || y < items_min_y)
items_min_y = y;
if(items_max_x == 100 || x > items_max_x)
items_max_x = x;
if(items_max_y == 100 || y > items_max_y)
items_max_y = y;
}
// No items at all, just return false
if(items_min_x == 100)
return false;
u16 items_w = items_max_x - items_min_x + 1;
u16 items_h = items_max_y - items_min_y + 1;
u16 specs_min_x = 100;
u16 specs_max_x = 100;
u16 specs_min_y = 100;
u16 specs_max_y = 100;
for(u16 y=0; y<3; y++)
for(u16 x=0; x<3; x++)
{
if(specs[y*3 + x].type == ITEM_NONE)
continue;
if(specs_min_x == 100 || x < specs_min_x)
specs_min_x = x;
if(specs_min_y == 100 || y < specs_min_y)
specs_min_y = y;
if(specs_max_x == 100 || x > specs_max_x)
specs_max_x = x;
if(specs_max_y == 100 || y > specs_max_y)
specs_max_y = y;
}
// No specs at all, just return false
if(specs_min_x == 100)
return false;
u16 specs_w = specs_max_x - specs_min_x + 1;
u16 specs_h = specs_max_y - specs_min_y + 1;
// Different sizes
if(items_w != specs_w || items_h != specs_h)
return false;
for(u16 y=0; y<specs_h; y++)
for(u16 x=0; x<specs_w; x++)
{
u16 items_x = items_min_x + x;
u16 items_y = items_min_y + y;
u16 specs_x = specs_min_x + x;
u16 specs_y = specs_min_y + y;
const InventoryItem *item = items[items_y * 3 + items_x];
const ItemSpec &spec = specs[specs_y * 3 + specs_x];
if(spec.checkItem(item) == false)
return false;
}
return true;
}
bool checkItemCombination(const InventoryItem * const * items,
const InventoryItem * const * specs)
{
u16 items_min_x = 100;
u16 items_max_x = 100;
u16 items_min_y = 100;
u16 items_max_y = 100;
for(u16 y=0; y<3; y++)
for(u16 x=0; x<3; x++)
{
if(items[y*3 + x] == NULL)
continue;
if(items_min_x == 100 || x < items_min_x)
items_min_x = x;
if(items_min_y == 100 || y < items_min_y)
items_min_y = y;
if(items_max_x == 100 || x > items_max_x)
items_max_x = x;
if(items_max_y == 100 || y > items_max_y)
items_max_y = y;
}
// No items at all, just return false
if(items_min_x == 100)
return false;
u16 items_w = items_max_x - items_min_x + 1;
u16 items_h = items_max_y - items_min_y + 1;
u16 specs_min_x = 100;
u16 specs_max_x = 100;
u16 specs_min_y = 100;
u16 specs_max_y = 100;
for(u16 y=0; y<3; y++)
for(u16 x=0; x<3; x++)
{
if(specs[y*3 + x] == NULL)
continue;
if(specs_min_x == 100 || x < specs_min_x)
specs_min_x = x;
if(specs_min_y == 100 || y < specs_min_y)
specs_min_y = y;
if(specs_max_x == 100 || x > specs_max_x)
specs_max_x = x;
if(specs_max_y == 100 || y > specs_max_y)
specs_max_y = y;
}
// No specs at all, just return false
if(specs_min_x == 100)
return false;
u16 specs_w = specs_max_x - specs_min_x + 1;
u16 specs_h = specs_max_y - specs_min_y + 1;
// Different sizes
if(items_w != specs_w || items_h != specs_h)
return false;
for(u16 y=0; y<specs_h; y++)
for(u16 x=0; x<specs_w; x++)
{
u16 items_x = items_min_x + x;
u16 items_y = items_min_y + y;
u16 specs_x = specs_min_x + x;
u16 specs_y = specs_min_y + y;
const InventoryItem *item = items[items_y * 3 + items_x];
const InventoryItem *spec = specs[specs_y * 3 + specs_x];
if(item == NULL && spec == NULL)
continue;
if(item == NULL && spec != NULL)
return false;
if(item != NULL && spec == NULL)
return false;
if(!spec->isSubsetOf(item))
return false;
}
return true;
}

@ -21,19 +21,34 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define INVENTORYMANAGER_HEADER #define INVENTORYMANAGER_HEADER
#include "inventory.h" #include "inventory.h"
#include <iostream>
#include <string>
class ServerActiveObject;
// Should probably somehow replace InventoryContext over time
struct InventoryLocation struct InventoryLocation
{ {
enum Type{ enum Type{
UNDEFINED, UNDEFINED,
CURRENT_PLAYER,
PLAYER, PLAYER,
NODEMETA NODEMETA,
} type; } type;
std::string name; // PLAYER std::string name; // PLAYER
v3s16 p; // NODEMETA v3s16 p; // NODEMETA
InventoryLocation()
{
setUndefined();
}
void setUndefined()
{
type = UNDEFINED;
}
void setCurrentPlayer()
{
type = CURRENT_PLAYER;
}
void setPlayer(const std::string &name_) void setPlayer(const std::string &name_)
{ {
type = PLAYER; type = PLAYER;
@ -44,17 +59,17 @@ struct InventoryLocation
type = NODEMETA; type = NODEMETA;
p = p_; p = p_;
} }
};
class Player; void applyCurrentPlayer(const std::string &name_)
{
if(type == CURRENT_PLAYER)
setPlayer(name_);
}
struct InventoryContext std::string dump() const;
{ void serialize(std::ostream &os) const;
Player *current_player; void deSerialize(std::istream &is);
void deSerialize(std::string s);
InventoryContext():
current_player(NULL)
{}
}; };
struct InventoryAction; struct InventoryAction;
@ -68,18 +83,11 @@ public:
// Get an inventory or set it modified (so it will be updated over // Get an inventory or set it modified (so it will be updated over
// network or so) // 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 "";}
virtual void setInventoryModified(const InventoryLocation &loc){} virtual void setInventoryModified(const InventoryLocation &loc){}
// Used on the client to send an action to the server // Used on the client to send an action to the server
virtual void inventoryAction(InventoryAction *a){} virtual void inventoryAction(InventoryAction *a){}
// (Deprecated; these wrap to the latter ones)
// Get a pointer to an inventory specified by id. id can be:
// - "current_player"
// - "nodemeta:X,Y,Z"
Inventory* getInventory(InventoryContext *c, std::string id);
// Used on the server by InventoryAction::apply and other stuff
void inventoryModified(InventoryContext *c, std::string id);
}; };
#define IACTION_MOVE 0 #define IACTION_MOVE 0
@ -91,18 +99,17 @@ struct InventoryAction
virtual u16 getType() const = 0; virtual u16 getType() const = 0;
virtual void serialize(std::ostream &os) const = 0; virtual void serialize(std::ostream &os) const = 0;
virtual void apply(InventoryContext *c, InventoryManager *mgr, virtual void apply(InventoryManager *mgr, ServerActiveObject *player) = 0;
ServerEnvironment *env) = 0;
}; };
struct IMoveAction : public InventoryAction struct IMoveAction : public InventoryAction
{ {
// count=0 means "everything" // count=0 means "everything"
u16 count; u16 count;
std::string from_inv; InventoryLocation from_inv;
std::string from_list; std::string from_list;
s16 from_i; s16 from_i;
std::string to_inv; InventoryLocation to_inv;
std::string to_list; std::string to_list;
s16 to_i; s16 to_i;
@ -124,23 +131,22 @@ struct IMoveAction : public InventoryAction
{ {
os<<"Move "; os<<"Move ";
os<<count<<" "; os<<count<<" ";
os<<from_inv<<" "; os<<from_inv.dump()<<" ";
os<<from_list<<" "; os<<from_list<<" ";
os<<from_i<<" "; os<<from_i<<" ";
os<<to_inv<<" "; os<<to_inv.dump()<<" ";
os<<to_list<<" "; os<<to_list<<" ";
os<<to_i; os<<to_i;
} }
void apply(InventoryContext *c, InventoryManager *mgr, void apply(InventoryManager *mgr, ServerActiveObject *player);
ServerEnvironment *env);
}; };
struct IDropAction : public InventoryAction struct IDropAction : public InventoryAction
{ {
// count=0 means "everything" // count=0 means "everything"
u16 count; u16 count;
std::string from_inv; InventoryLocation from_inv;
std::string from_list; std::string from_list;
s16 from_i; s16 from_i;
@ -161,68 +167,13 @@ struct IDropAction : public InventoryAction
{ {
os<<"Drop "; os<<"Drop ";
os<<count<<" "; os<<count<<" ";
os<<from_inv<<" "; os<<from_inv.dump()<<" ";
os<<from_list<<" "; os<<from_list<<" ";
os<<from_i; os<<from_i;
} }
void apply(InventoryContext *c, InventoryManager *mgr, void apply(InventoryManager *mgr, ServerActiveObject *player);
ServerEnvironment *env);
}; };
/*
Craft checking system
*/
enum ItemSpecType
{
ITEM_NONE,
ITEM_MATERIAL,
ITEM_CRAFT,
ITEM_TOOL,
ITEM_MBO
};
struct ItemSpec
{
enum ItemSpecType type;
// Only other one of these is used
std::string name;
u16 num;
ItemSpec():
type(ITEM_NONE)
{
}
ItemSpec(enum ItemSpecType a_type, std::string a_name):
type(a_type),
name(a_name),
num(65535)
{
}
ItemSpec(enum ItemSpecType a_type, u16 a_num):
type(a_type),
name(""),
num(a_num)
{
}
bool checkItem(const InventoryItem *item) const;
};
/*
items: a pointer to an array of 9 pointers to items
specs: a pointer to an array of 9 ItemSpecs
*/
bool checkItemCombination(const InventoryItem * const*items, const ItemSpec *specs);
/*
items: a pointer to an array of 9 pointers to items
specs: a pointer to an array of 9 pointers to items
*/
bool checkItemCombination(const InventoryItem * const * items,
const InventoryItem * const * specs);
#endif #endif

@ -39,6 +39,8 @@ typedef core::vector2d<s32> v2s32;
typedef core::vector2d<u32> v2u32; typedef core::vector2d<u32> v2u32;
typedef core::vector2d<f32> v2f32; typedef core::vector2d<f32> v2f32;
typedef core::aabbox3d<f32> aabb3f;
#ifdef _MSC_VER #ifdef _MSC_VER
// Windows // Windows
typedef unsigned long long u64; typedef unsigned long long u64;

502
src/itemdef.cpp Normal file

@ -0,0 +1,502 @@
/*
Minetest-c55
Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
Copyright (C) 2011 Kahrl <kahrl@gmx.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "itemdef.h"
#include "gamedef.h"
#include "nodedef.h"
#include "materials.h"
#include "inventory.h"
#ifndef SERVER
#include "mapblock_mesh.h"
#include "mesh.h"
#include "tile.h"
#endif
#include "log.h"
#include "utility.h"
#include <map>
#include <set>
/*
ItemDefinition
*/
ItemDefinition::ItemDefinition()
{
resetInitial();
}
ItemDefinition::ItemDefinition(const ItemDefinition &def)
{
resetInitial();
*this = def;
}
ItemDefinition& ItemDefinition::operator=(const ItemDefinition &def)
{
if(this == &def)
return *this;
reset();
type = def.type;
name = def.name;
description = def.description;
inventory_image = def.inventory_image;
wield_image = def.wield_image;
wield_scale = def.wield_scale;
stack_max = def.stack_max;
usable = def.usable;
liquids_pointable = def.liquids_pointable;
if(def.tool_digging_properties)
{
tool_digging_properties = new ToolDiggingProperties(
*def.tool_digging_properties);
}
#ifndef SERVER
inventory_texture = def.inventory_texture;
if(def.wield_mesh)
{
wield_mesh = def.wield_mesh;
wield_mesh->grab();
}
#endif
return *this;
}
ItemDefinition::~ItemDefinition()
{
reset();
}
void ItemDefinition::resetInitial()
{
// Initialize pointers to NULL so reset() does not delete undefined pointers
tool_digging_properties = NULL;
#ifndef SERVER
inventory_texture = NULL;
wield_mesh = NULL;
#endif
reset();
}
void ItemDefinition::reset()
{
type = ITEM_NONE;
name = "";
description = "";
inventory_image = "";
wield_image = "";
wield_scale = v3f(1.0, 1.0, 1.0);
stack_max = 99;
usable = false;
liquids_pointable = false;
if(tool_digging_properties)
{
delete tool_digging_properties;
tool_digging_properties = NULL;
}
#ifndef SERVER
inventory_texture = NULL;
if(wield_mesh)
{
wield_mesh->drop();
wield_mesh = NULL;
}
#endif
}
void ItemDefinition::serialize(std::ostream &os) const
{
writeU8(os, 0); // version
writeU8(os, type);
os<<serializeString(name);
os<<serializeString(description);
os<<serializeString(inventory_image);
os<<serializeString(wield_image);
writeV3F1000(os, wield_scale);
writeS16(os, stack_max);
writeU8(os, usable);
writeU8(os, liquids_pointable);
std::string tool_digging_properties_s = "";
if(tool_digging_properties)
{
std::ostringstream tmp_os(std::ios::binary);
tool_digging_properties->serialize(tmp_os);
tool_digging_properties_s = tmp_os.str();
}
os<<serializeString(tool_digging_properties_s);
}
void ItemDefinition::deSerialize(std::istream &is)
{
// Reset everything
reset();
// Deserialize
int version = readU8(is);
if(version != 0)
throw SerializationError("unsupported ItemDefinition version");
type = (enum ItemType)readU8(is);
name = deSerializeString(is);
description = deSerializeString(is);
inventory_image = deSerializeString(is);
wield_image = deSerializeString(is);
wield_scale = readV3F1000(is);
stack_max = readS16(is);
usable = readU8(is);
liquids_pointable = readU8(is);
std::string tool_digging_properties_s = deSerializeString(is);
if(!tool_digging_properties_s.empty())
{
std::istringstream tmp_is(tool_digging_properties_s, std::ios::binary);
tool_digging_properties = new ToolDiggingProperties;
tool_digging_properties->deSerialize(tmp_is);
}
}
/*
CItemDefManager
*/
// SUGG: Support chains of aliases?
class CItemDefManager: public IWritableItemDefManager
{
public:
CItemDefManager()
{
clear();
}
virtual ~CItemDefManager()
{
}
virtual const ItemDefinition& get(const std::string &name_) const
{
// Convert name according to possible alias
std::string name = getAlias(name_);
// Get the definition
std::map<std::string, ItemDefinition*>::const_iterator i;
i = m_item_definitions.find(name);
if(i == m_item_definitions.end())
i = m_item_definitions.find("unknown");
assert(i != m_item_definitions.end());
return *(i->second);
}
virtual std::string getAlias(const std::string &name) const
{
std::map<std::string, std::string>::const_iterator i;
i = m_aliases.find(name);
if(i != m_aliases.end())
return i->second;
return name;
}
virtual std::set<std::string> getAll() const
{
std::set<std::string> result;
for(std::map<std::string, ItemDefinition*>::const_iterator
i = m_item_definitions.begin();
i != m_item_definitions.end(); i++)
{
result.insert(i->first);
}
for(std::map<std::string, std::string>::const_iterator
i = m_aliases.begin();
i != m_aliases.end(); i++)
{
result.insert(i->first);
}
return result;
}
virtual bool isKnown(const std::string &name_) const
{
// Convert name according to possible alias
std::string name = getAlias(name_);
// Get the definition
std::map<std::string, ItemDefinition*>::const_iterator i;
return m_item_definitions.find(name) != m_item_definitions.end();
}
void clear()
{
for(std::map<std::string, ItemDefinition*>::const_iterator
i = m_item_definitions.begin();
i != m_item_definitions.end(); i++)
{
delete i->second;
}
m_item_definitions.clear();
m_aliases.clear();
// Add the four builtin items:
// "" is the hand
// "unknown" is returned whenever an undefined item is accessed
// "air" is the air node
// "ignore" is the ignore node
ItemDefinition* hand_def = new ItemDefinition;
hand_def->name = "";
hand_def->wield_image = "wieldhand.png";
hand_def->tool_digging_properties = new ToolDiggingProperties;
m_item_definitions.insert(std::make_pair("", hand_def));
ItemDefinition* unknown_def = new ItemDefinition;
unknown_def->name = "unknown";
m_item_definitions.insert(std::make_pair("unknown", unknown_def));
ItemDefinition* air_def = new ItemDefinition;
air_def->type = ITEM_NODE;
air_def->name = "air";
m_item_definitions.insert(std::make_pair("air", air_def));
ItemDefinition* ignore_def = new ItemDefinition;
ignore_def->type = ITEM_NODE;
ignore_def->name = "ignore";
m_item_definitions.insert(std::make_pair("ignore", ignore_def));
}
virtual void registerItem(const ItemDefinition &def)
{
infostream<<"ItemDefManager: registering \""<<def.name<<"\""<<std::endl;
// Ensure that the "" item (the hand) always has ToolDiggingProperties
if(def.name == "")
assert(def.tool_digging_properties != NULL);
m_item_definitions[def.name] = new ItemDefinition(def);
// Remove conflicting alias if it exists
bool alias_removed = (m_aliases.erase(def.name) != 0);
if(alias_removed)
infostream<<"ItemDefManager: erased alias "<<def.name
<<" because item was defined"<<std::endl;
}
virtual void registerAlias(const std::string &name,
const std::string &convert_to)
{
if(m_item_definitions.find(name) == m_item_definitions.end())
{
infostream<<"ItemDefManager: setting alias "<<name
<<" -> "<<convert_to<<std::endl;
m_aliases[name] = convert_to;
}
}
virtual void updateTexturesAndMeshes(IGameDef *gamedef)
{
#ifndef SERVER
infostream<<"ItemDefManager::updateTexturesAndMeshes(): Updating "
<<"textures and meshes in item definitions"<<std::endl;
ITextureSource *tsrc = gamedef->getTextureSource();
INodeDefManager *nodedef = gamedef->getNodeDefManager();
IrrlichtDevice *device = tsrc->getDevice();
video::IVideoDriver *driver = device->getVideoDriver();
for(std::map<std::string, ItemDefinition*>::iterator
i = m_item_definitions.begin();
i != m_item_definitions.end(); i++)
{
ItemDefinition *def = i->second;
bool need_node_mesh = false;
// Create an inventory texture
def->inventory_texture = NULL;
if(def->inventory_image != "")
{
def->inventory_texture = tsrc->getTextureRaw(def->inventory_image);
}
else if(def->type == ITEM_NODE)
{
need_node_mesh = true;
}
// Create a wield mesh
if(def->wield_mesh != NULL)
{
def->wield_mesh->drop();
def->wield_mesh = NULL;
}
if(def->type == ITEM_NODE && def->wield_image == "")
{
need_node_mesh = true;
}
else if(def->wield_image != "" || def->inventory_image != "")
{
// Extrude the wield image into a mesh
std::string imagename;
if(def->wield_image != "")
imagename = def->wield_image;
else
imagename = def->inventory_image;
def->wield_mesh = createExtrudedMesh(
tsrc->getTextureRaw(imagename),
driver,
def->wield_scale * v3f(40.0, 40.0, 4.0));
if(def->wield_mesh == NULL)
{
infostream<<"ItemDefManager: WARNING: "
<<"updateTexturesAndMeshes(): "
<<"Unable to create extruded mesh for item "
<<def->name<<std::endl;
}
}
if(need_node_mesh)
{
/*
Get node properties
*/
content_t id = nodedef->getId(def->name);
const ContentFeatures &f = nodedef->get(id);
/*
Make a mesh from the node
*/
MeshMakeData mesh_make_data;
MapNode mesh_make_node(
id,
(f.param_type == CPT_LIGHT) ? 0xee : 0,
0);
mesh_make_data.fillSingleNode(1000, &mesh_make_node);
scene::IMesh *node_mesh =
makeMapBlockMesh(&mesh_make_data, gamedef);
setMeshColor(node_mesh, video::SColor(255, 255, 255, 255));
/*
Scale and translate the mesh so it's a unit cube
centered on the origin
*/
scaleMesh(node_mesh, v3f(1.0/BS, 1.0/BS, 1.0/BS));
translateMesh(node_mesh, v3f(-1.0, -1.0, -1.0));
/*
Draw node mesh into a render target texture
*/
if(def->inventory_texture == NULL && node_mesh != NULL)
{
core::dimension2d<u32> dim(64,64);
std::string rtt_texture_name = "INVENTORY_"
+ def->name + "_RTT";
v3f camera_position(0, 1.0, -1.5);
camera_position.rotateXZBy(45);
v3f camera_lookat(0, 0, 0);
core::CMatrix4<f32> camera_projection_matrix;
// Set orthogonal projection
camera_projection_matrix.buildProjectionMatrixOrthoLH(
1.65, 1.65, 0, 100);
video::SColorf ambient_light(0.2,0.2,0.2);
v3f light_position(10, 100, -50);
video::SColorf light_color(0.5,0.5,0.5);
f32 light_radius = 1000;
def->inventory_texture = generateTextureFromMesh(
node_mesh, device, dim, rtt_texture_name,
camera_position,
camera_lookat,
camera_projection_matrix,
ambient_light,
light_position,
light_color,
light_radius);
// Note: might have returned NULL
}
/*
Use the node mesh as the wield mesh
*/
if(def->wield_mesh == NULL && node_mesh != NULL)
{
// Scale to proper wield mesh proportions
scaleMesh(node_mesh, v3f(30.0, 30.0, 30.0)
* def->wield_scale);
def->wield_mesh = node_mesh;
def->wield_mesh->grab();
}
if(node_mesh != NULL)
node_mesh->drop();
}
}
#endif
}
void serialize(std::ostream &os)
{
writeU8(os, 0); // version
u16 count = m_item_definitions.size();
writeU16(os, count);
for(std::map<std::string, ItemDefinition*>::const_iterator
i = m_item_definitions.begin();
i != m_item_definitions.end(); i++)
{
ItemDefinition *def = i->second;
// Serialize ItemDefinition and write wrapped in a string
std::ostringstream tmp_os(std::ios::binary);
def->serialize(tmp_os);
os<<serializeString(tmp_os.str());
}
writeU16(os, m_aliases.size());
for(std::map<std::string, std::string>::const_iterator
i = m_aliases.begin(); i != m_aliases.end(); i++)
{
os<<serializeString(i->first);
os<<serializeString(i->second);
}
}
void deSerialize(std::istream &is)
{
// Clear everything
clear();
// Deserialize
int version = readU8(is);
if(version != 0)
throw SerializationError("unsupported ItemDefManager version");
u16 count = readU16(is);
for(u16 i=0; i<count; i++)
{
// Deserialize a string and grab an ItemDefinition from it
std::istringstream tmp_is(deSerializeString(is), std::ios::binary);
ItemDefinition def;
def.deSerialize(tmp_is);
// Register
registerItem(def);
}
u16 num_aliases = readU16(is);
for(u16 i=0; i<num_aliases; i++)
{
std::string name = deSerializeString(is);
std::string convert_to = deSerializeString(is);
registerAlias(name, convert_to);
}
}
private:
// Key is name
std::map<std::string, ItemDefinition*> m_item_definitions;
// Aliases
std::map<std::string, std::string> m_aliases;
};
IWritableItemDefManager* createItemDefManager()
{
return new CItemDefManager();
}

147
src/itemdef.h Normal file

@ -0,0 +1,147 @@
/*
Minetest-c55
Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
Copyright (C) 2011 Kahrl <kahrl@gmx.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef ITEMDEF_HEADER
#define ITEMDEF_HEADER
#include "common_irrlicht.h"
#include <string>
#include <iostream>
#include <set>
class IGameDef;
struct ToolDiggingProperties;
/*
Base item definition
*/
enum ItemType
{
ITEM_NONE,
ITEM_NODE,
ITEM_CRAFT,
ITEM_TOOL,
};
struct ItemDefinition
{
/*
Basic item properties
*/
ItemType type;
std::string name; // "" = hand
std::string description; // Shown in tooltip.
/*
Visual properties
*/
std::string inventory_image; // Optional for nodes, mandatory for tools/craftitems
std::string wield_image; // If empty, inventory_image or mesh (only nodes) is used
v3f wield_scale;
/*
Item stack and interaction properties
*/
s16 stack_max;
bool usable;
bool liquids_pointable;
// May be NULL. If non-NULL, deleted by destructor
ToolDiggingProperties *tool_digging_properties;
/*
Cached stuff
*/
#ifndef SERVER
video::ITexture *inventory_texture;
scene::IMesh *wield_mesh;
#endif
/*
Some helpful methods
*/
ItemDefinition();
ItemDefinition(const ItemDefinition &def);
ItemDefinition& operator=(const ItemDefinition &def);
~ItemDefinition();
void reset();
void serialize(std::ostream &os) const;
void deSerialize(std::istream &is);
private:
void resetInitial();
};
class IItemDefManager
{
public:
IItemDefManager(){}
virtual ~IItemDefManager(){}
// Get item definition
virtual const ItemDefinition& get(const std::string &name) const=0;
// Get alias definition
virtual std::string getAlias(const std::string &name) const=0;
// Get set of all defined item names and aliases
virtual std::set<std::string> getAll() const=0;
// Check if item is known
virtual bool isKnown(const std::string &name) const=0;
virtual void serialize(std::ostream &os)=0;
};
class IWritableItemDefManager : public IItemDefManager
{
public:
IWritableItemDefManager(){}
virtual ~IWritableItemDefManager(){}
// Get item definition
virtual const ItemDefinition& get(const std::string &name) const=0;
// Get alias definition
virtual std::string getAlias(const std::string &name) const=0;
// Get set of all defined item names and aliases
virtual std::set<std::string> getAll() const=0;
// Check if item is known
virtual bool isKnown(const std::string &name) const=0;
// Remove all registered item and node definitions and aliases
// Then re-add the builtin item definitions
virtual void clear()=0;
// Register item definition
virtual void registerItem(const ItemDefinition &def)=0;
// Set an alias so that items named <name> will load as <convert_to>.
// Alias is not set if <name> has already been defined.
// Alias will be removed if <name> is defined at a later point of time.
virtual void registerAlias(const std::string &name,
const std::string &convert_to)=0;
/*
Update inventory textures and wield meshes to latest
return values of ITextureSource and INodeDefManager.
Call after updating the texture atlas of a texture source.
*/
virtual void updateTexturesAndMeshes(IGameDef *gamedef)=0;
virtual void serialize(std::ostream &os)=0;
virtual void deSerialize(std::istream &is)=0;
};
IWritableItemDefManager* createItemDefManager();
#endif

@ -30,6 +30,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "log.h" #include "log.h"
#include "nameidmapping.h" #include "nameidmapping.h"
#include "content_mapnode.h" // For legacy name-id mapping #include "content_mapnode.h" // For legacy name-id mapping
#ifndef SERVER
#include "mapblock_mesh.h"
#endif
/* /*
MapBlock MapBlock

@ -32,9 +32,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "voxel.h" #include "voxel.h"
#include "staticobject.h" #include "staticobject.h"
#include "mapblock_nodemod.h" #include "mapblock_nodemod.h"
#ifndef SERVER
#include "mapblock_mesh.h"
#endif
#include "modifiedstate.h" #include "modifiedstate.h"
class Map; class Map;

@ -25,7 +25,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "settings.h" #include "settings.h"
#include "profiler.h" #include "profiler.h"
#include "nodedef.h" #include "nodedef.h"
#include "tile.h"
#include "gamedef.h" #include "gamedef.h"
#include "content_mapblock.h" #include "content_mapblock.h"
#include "mineral.h" // For mineral_block_texture #include "mineral.h" // For mineral_block_texture
@ -83,6 +82,39 @@ void MeshMakeData::fill(u32 daynight_ratio, MapBlock *block)
} }
} }
void MeshMakeData::fillSingleNode(u32 daynight_ratio, MapNode *node)
{
m_daynight_ratio = daynight_ratio;
m_blockpos = v3s16(0,0,0);
m_temp_mods.clear();
v3s16 blockpos_nodes = v3s16(0,0,0);
VoxelArea area(blockpos_nodes-v3s16(1,1,1)*MAP_BLOCKSIZE,
blockpos_nodes+v3s16(1,1,1)*MAP_BLOCKSIZE*2-v3s16(1,1,1));
s32 volume = area.getVolume();
s32 our_node_index = area.index(1,1,1);
// Allocate this block + neighbors
m_vmanip.clear();
m_vmanip.addArea(area);
// Fill in data
MapNode *data = new MapNode[volume];
for(s32 i = 0; i < volume; i++)
{
if(i == our_node_index)
{
data[i] = *node;
}
else
{
data[i] = MapNode(CONTENT_AIR, LIGHT_MAX, 0);
}
}
m_vmanip.copyFrom(data, area, area.MinEdge, area.MinEdge, area.getExtent());
delete[] data;
}
/* /*
vertex_dirs: v3s16[4] vertex_dirs: v3s16[4]
*/ */
@ -207,8 +239,8 @@ static void makeFastFace(TileSpec tile, u8 li0, u8 li1, u8 li2, u8 li3, v3f p,
else if(scale.Y < 0.999 || scale.Y > 1.001) abs_scale = scale.Y; else if(scale.Y < 0.999 || scale.Y > 1.001) abs_scale = scale.Y;
else if(scale.Z < 0.999 || scale.Z > 1.001) abs_scale = scale.Z; else if(scale.Z < 0.999 || scale.Z > 1.001) abs_scale = scale.Z;
v3f zerovector = v3f(0,0,0); v3f normal(dir.X, dir.Y, dir.Z);
u8 alpha = tile.alpha; u8 alpha = tile.alpha;
/*u8 alpha = 255; /*u8 alpha = 255;
if(tile.id == TILE_WATER) if(tile.id == TILE_WATER)
@ -230,16 +262,16 @@ static void makeFastFace(TileSpec tile, u8 li0, u8 li1, u8 li2, u8 li3, v3f p,
face.vertices[3] = video::S3DVertex(vertex_pos[3], v3f(0,1,0), c, face.vertices[3] = video::S3DVertex(vertex_pos[3], v3f(0,1,0), c,
core::vector2d<f32>(x0+w*abs_scale, y0));*/ core::vector2d<f32>(x0+w*abs_scale, y0));*/
face.vertices[0] = video::S3DVertex(vertex_pos[0], v3f(0,1,0), face.vertices[0] = video::S3DVertex(vertex_pos[0], normal,
MapBlock_LightColor(alpha, li0), MapBlock_LightColor(alpha, li0),
core::vector2d<f32>(x0+w*abs_scale, y0+h)); core::vector2d<f32>(x0+w*abs_scale, y0+h));
face.vertices[1] = video::S3DVertex(vertex_pos[1], v3f(0,1,0), face.vertices[1] = video::S3DVertex(vertex_pos[1], normal,
MapBlock_LightColor(alpha, li1), MapBlock_LightColor(alpha, li1),
core::vector2d<f32>(x0, y0+h)); core::vector2d<f32>(x0, y0+h));
face.vertices[2] = video::S3DVertex(vertex_pos[2], v3f(0,1,0), face.vertices[2] = video::S3DVertex(vertex_pos[2], normal,
MapBlock_LightColor(alpha, li2), MapBlock_LightColor(alpha, li2),
core::vector2d<f32>(x0, y0)); core::vector2d<f32>(x0, y0));
face.vertices[3] = video::S3DVertex(vertex_pos[3], v3f(0,1,0), face.vertices[3] = video::S3DVertex(vertex_pos[3], normal,
MapBlock_LightColor(alpha, li3), MapBlock_LightColor(alpha, li3),
core::vector2d<f32>(x0+w*abs_scale, y0)); core::vector2d<f32>(x0+w*abs_scale, y0));
@ -309,8 +341,8 @@ static TileSpec getTile(const MapNode &node, v3s16 dir,
Gets node tile from any place relative to block. Gets node tile from any place relative to block.
Returns TILE_NODE if doesn't exist or should not be drawn. Returns TILE_NODE if doesn't exist or should not be drawn.
*/ */
static TileSpec getNodeTile(MapNode mn, v3s16 p, v3s16 face_dir, TileSpec getNodeTile(MapNode mn, v3s16 p, v3s16 face_dir,
NodeModMap &temp_mods, ITextureSource *tsrc, INodeDefManager *ndef) NodeModMap *temp_mods, ITextureSource *tsrc, INodeDefManager *ndef)
{ {
TileSpec spec; TileSpec spec;
spec = getTile(mn, face_dir, tsrc, ndef); spec = getTile(mn, face_dir, tsrc, ndef);
@ -325,13 +357,15 @@ static TileSpec getNodeTile(MapNode mn, v3s16 p, v3s16 face_dir,
{ {
struct NodeMod mod = n->getValue();*/ struct NodeMod mod = n->getValue();*/
NodeMod mod; NodeMod mod;
if(temp_mods.get(p, &mod)) if(temp_mods && temp_mods->get(p, &mod))
{ {
#if 0 // NODEMOD_CHANGECONTENT isn't used at the moment
if(mod.type == NODEMOD_CHANGECONTENT) if(mod.type == NODEMOD_CHANGECONTENT)
{ {
MapNode mn2(mod.param); MapNode mn2(mod.param);
spec = getTile(mn2, face_dir, tsrc, ndef); spec = getTile(mn2, face_dir, tsrc, ndef);
} }
#endif
if(mod.type == NODEMOD_CRACK) if(mod.type == NODEMOD_CRACK)
{ {
/* /*
@ -361,19 +395,14 @@ static TileSpec getNodeTile(MapNode mn, v3s16 p, v3s16 face_dir,
return spec; return spec;
} }
static content_t getNodeContent(v3s16 p, MapNode mn, NodeModMap &temp_mods) static content_t getNodeContent(v3s16 p, MapNode mn, NodeModMap *temp_mods)
{ {
/* /*
Check temporary modifications on this node Check temporary modifications on this node
*/ */
/*core::map<v3s16, NodeMod>::Node *n; #if 0 // NODEMOD_CHANGECONTENT isn't used at the moment
n = m_temp_mods.find(p);
// If modified
if(n != NULL)
{
struct NodeMod mod = n->getValue();*/
NodeMod mod; NodeMod mod;
if(temp_mods.get(p, &mod)) if(temp_mods && temp_mods->get(p, &mod))
{ {
if(mod.type == NODEMOD_CHANGECONTENT) if(mod.type == NODEMOD_CHANGECONTENT)
{ {
@ -395,6 +424,7 @@ static content_t getNodeContent(v3s16 p, MapNode mn, NodeModMap &temp_mods)
*/ */
} }
} }
#endif
return mn.getContent(); return mn.getContent();
} }
@ -469,7 +499,7 @@ static void getTileInfo(
v3s16 face_dir, v3s16 face_dir,
u32 daynight_ratio, u32 daynight_ratio,
VoxelManipulator &vmanip, VoxelManipulator &vmanip,
NodeModMap &temp_mods, NodeModMap *temp_mods,
bool smooth_lighting, bool smooth_lighting,
IGameDef *gamedef, IGameDef *gamedef,
// Output: // Output:
@ -553,7 +583,7 @@ static void updateFastFaceRow(
v3s16 face_dir, v3s16 face_dir,
v3f face_dir_f, v3f face_dir_f,
core::array<FastFace> &dest, core::array<FastFace> &dest,
NodeModMap &temp_mods, NodeModMap *temp_mods,
VoxelManipulator &vmanip, VoxelManipulator &vmanip,
v3s16 blockpos_nodes, v3s16 blockpos_nodes,
bool smooth_lighting, bool smooth_lighting,
@ -749,7 +779,7 @@ scene::SMesh* makeMapBlockMesh(MeshMakeData *data, IGameDef *gamedef)
v3s16(0,1,0), //face dir v3s16(0,1,0), //face dir
v3f (0,1,0), v3f (0,1,0),
fastfaces_new, fastfaces_new,
data->m_temp_mods, &data->m_temp_mods,
data->m_vmanip, data->m_vmanip,
blockpos_nodes, blockpos_nodes,
smooth_lighting, smooth_lighting,
@ -768,7 +798,7 @@ scene::SMesh* makeMapBlockMesh(MeshMakeData *data, IGameDef *gamedef)
v3s16(1,0,0), v3s16(1,0,0),
v3f (1,0,0), v3f (1,0,0),
fastfaces_new, fastfaces_new,
data->m_temp_mods, &data->m_temp_mods,
data->m_vmanip, data->m_vmanip,
blockpos_nodes, blockpos_nodes,
smooth_lighting, smooth_lighting,
@ -787,7 +817,7 @@ scene::SMesh* makeMapBlockMesh(MeshMakeData *data, IGameDef *gamedef)
v3s16(0,0,1), v3s16(0,0,1),
v3f (0,0,1), v3f (0,0,1),
fastfaces_new, fastfaces_new,
data->m_temp_mods, &data->m_temp_mods,
data->m_vmanip, data->m_vmanip,
blockpos_nodes, blockpos_nodes,
smooth_lighting, smooth_lighting,

@ -22,6 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "common_irrlicht.h" #include "common_irrlicht.h"
#include "mapblock_nodemod.h" #include "mapblock_nodemod.h"
#include "tile.h"
#include "voxel.h" #include "voxel.h"
class IGameDef; class IGameDef;
@ -125,6 +126,8 @@ private:
// Helper functions // Helper functions
video::SColor MapBlock_LightColor(u8 alpha, u8 light); video::SColor MapBlock_LightColor(u8 alpha, u8 light);
TileSpec getNodeTile(MapNode mn, v3s16 p, v3s16 face_dir,
NodeModMap *temp_mods, ITextureSource *tsrc, INodeDefManager *ndef);
class MapBlock; class MapBlock;
@ -140,6 +143,11 @@ struct MeshMakeData
parent of block. parent of block.
*/ */
void fill(u32 daynight_ratio, MapBlock *block); void fill(u32 daynight_ratio, MapBlock *block);
/*
Set up with only a single node at (1,1,1)
*/
void fillSingleNode(u32 daynight_ratio, MapNode *node);
}; };
// This is the highest-level function in here // This is the highest-level function in here

@ -20,7 +20,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "materials.h" #include "materials.h"
#include "mapnode.h" #include "mapnode.h"
#include "nodedef.h" #include "nodedef.h"
#include "tooldef.h"
#include "utility.h" #include "utility.h"
void MaterialProperties::serialize(std::ostream &os) void MaterialProperties::serialize(std::ostream &os)
@ -49,6 +48,56 @@ void MaterialProperties::deSerialize(std::istream &is)
flammability = readF1000(is); flammability = readF1000(is);
} }
ToolDiggingProperties::ToolDiggingProperties(float full_punch_interval_,
float a, float b, float c, float d, float e,
float f, float g, float h, float i, float j):
full_punch_interval(full_punch_interval_),
basetime(a),
dt_weight(b),
dt_crackiness(c),
dt_crumbliness(d),
dt_cuttability(e),
basedurability(f),
dd_weight(g),
dd_crackiness(h),
dd_crumbliness(i),
dd_cuttability(j)
{}
void ToolDiggingProperties::serialize(std::ostream &os)
{
writeU8(os, 0); // version
writeF1000(os, full_punch_interval);
writeF1000(os, basetime);
writeF1000(os, dt_weight);
writeF1000(os, dt_crackiness);
writeF1000(os, dt_crumbliness);
writeF1000(os, dt_cuttability);
writeF1000(os, basedurability);
writeF1000(os, dd_weight);
writeF1000(os, dd_crackiness);
writeF1000(os, dd_crumbliness);
writeF1000(os, dd_cuttability);
}
void ToolDiggingProperties::deSerialize(std::istream &is)
{
int version = readU8(is);
if(version != 0) throw SerializationError(
"unsupported ToolDiggingProperties version");
full_punch_interval = readF1000(is);
basetime = readF1000(is);
dt_weight = readF1000(is);
dt_crackiness = readF1000(is);
dt_crumbliness = readF1000(is);
dt_cuttability = readF1000(is);
basedurability = readF1000(is);
dd_weight = readF1000(is);
dd_crackiness = readF1000(is);
dd_crumbliness = readF1000(is);
dd_cuttability = readF1000(is);
}
DiggingProperties getDiggingProperties(const MaterialProperties *mp, DiggingProperties getDiggingProperties(const MaterialProperties *mp,
const ToolDiggingProperties *tp, float time_from_last_punch) const ToolDiggingProperties *tp, float time_from_last_punch)
{ {

@ -72,6 +72,29 @@ struct MaterialProperties
void deSerialize(std::istream &is); void deSerialize(std::istream &is);
}; };
struct ToolDiggingProperties
{
// time = basetime + sum(feature here * feature in MaterialProperties)
float full_punch_interval;
float basetime;
float dt_weight;
float dt_crackiness;
float dt_crumbliness;
float dt_cuttability;
float basedurability;
float dd_weight;
float dd_crackiness;
float dd_crumbliness;
float dd_cuttability;
ToolDiggingProperties(float full_punch_interval_=2.0,
float a=0.75, float b=0, float c=0, float d=0, float e=0,
float f=50, float g=0, float h=0, float i=0, float j=0);
void serialize(std::ostream &os);
void deSerialize(std::istream &is);
};
struct DiggingProperties struct DiggingProperties
{ {
bool diggable; bool diggable;
@ -87,7 +110,6 @@ struct DiggingProperties
{} {}
}; };
struct ToolDiggingProperties;
class INodeDefManager; class INodeDefManager;
DiggingProperties getDiggingProperties(const MaterialProperties *mp, DiggingProperties getDiggingProperties(const MaterialProperties *mp,

@ -18,8 +18,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
*/ */
#include "mesh.h" #include "mesh.h"
#include "log.h"
#include <cassert>
#include <iostream>
#include <IAnimatedMesh.h> #include <IAnimatedMesh.h>
#include <SAnimatedMesh.h> #include <SAnimatedMesh.h>
#include <ICameraSceneNode.h>
// In Irrlicht 1.8 the signature of ITexture::lock was changed from // In Irrlicht 1.8 the signature of ITexture::lock was changed from
// (bool, u32) to (E_TEXTURE_LOCK_MODE, u32). // (bool, u32) to (E_TEXTURE_LOCK_MODE, u32).
@ -73,9 +77,15 @@ scene::IAnimatedMesh* createCubeMesh(v3f scale)
{ {
scene::IMeshBuffer *buf = new scene::SMeshBuffer(); scene::IMeshBuffer *buf = new scene::SMeshBuffer();
buf->append(vertices + 4 * i, 4, indices, 6); buf->append(vertices + 4 * i, 4, indices, 6);
// Set default material
buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
// Add mesh buffer to mesh
mesh->addMeshBuffer(buf); mesh->addMeshBuffer(buf);
buf->drop(); buf->drop();
} }
scene::SAnimatedMesh *anim_mesh = new scene::SAnimatedMesh(mesh); scene::SAnimatedMesh *anim_mesh = new scene::SAnimatedMesh(mesh);
mesh->drop(); mesh->drop();
scaleMesh(anim_mesh, scale); // also recalculates bounding box scaleMesh(anim_mesh, scale); // also recalculates bounding box
@ -280,6 +290,13 @@ scene::IAnimatedMesh* createExtrudedMesh(video::ITexture *texture,
} }
img1->drop(); img1->drop();
} }
// Set default material
mesh->getMeshBuffer(0)->getMaterial().setTexture(0, texture);
mesh->getMeshBuffer(0)->getMaterial().setFlag(video::EMF_LIGHTING, false);
mesh->getMeshBuffer(0)->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
mesh->getMeshBuffer(0)->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
scaleMesh(mesh, scale); // also recalculates bounding box scaleMesh(mesh, scale); // also recalculates bounding box
return mesh; return mesh;
} }
@ -313,6 +330,35 @@ void scaleMesh(scene::IMesh *mesh, v3f scale)
mesh->setBoundingBox(bbox); mesh->setBoundingBox(bbox);
} }
void translateMesh(scene::IMesh *mesh, v3f vec)
{
if(mesh == NULL)
return;
core::aabbox3d<f32> bbox;
bbox.reset(0,0,0);
u16 mc = mesh->getMeshBufferCount();
for(u16 j=0; j<mc; j++)
{
scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
video::S3DVertex *vertices = (video::S3DVertex*)buf->getVertices();
u16 vc = buf->getVertexCount();
for(u16 i=0; i<vc; i++)
{
vertices[i].Pos += vec;
}
buf->recalculateBoundingBox();
// calculate total bounding box
if(j == 0)
bbox = buf->getBoundingBox();
else
bbox.addInternalBox(buf->getBoundingBox());
}
mesh->setBoundingBox(bbox);
}
void setMeshColor(scene::IMesh *mesh, const video::SColor &color) void setMeshColor(scene::IMesh *mesh, const video::SColor &color)
{ {
if(mesh == NULL) if(mesh == NULL)
@ -360,3 +406,74 @@ void setMeshColorByNormalXYZ(scene::IMesh *mesh,
} }
} }
} }
video::ITexture *generateTextureFromMesh(scene::IMesh *mesh,
IrrlichtDevice *device,
core::dimension2d<u32> dim,
std::string texture_name,
v3f camera_position,
v3f camera_lookat,
core::CMatrix4<f32> camera_projection_matrix,
video::SColorf ambient_light,
v3f light_position,
video::SColorf light_color,
f32 light_radius)
{
video::IVideoDriver *driver = device->getVideoDriver();
if(driver->queryFeature(video::EVDF_RENDER_TO_TARGET) == false)
{
errorstream<<"generateTextureFromMesh(): EVDF_RENDER_TO_TARGET"
" not supported."<<std::endl;
return NULL;
}
// Create render target texture
video::ITexture *rtt = driver->addRenderTargetTexture(
dim, texture_name.c_str(), video::ECF_A8R8G8B8);
if(rtt == NULL)
{
errorstream<<"generateTextureFromMesh(): addRenderTargetTexture"
" returned NULL."<<std::endl;
return NULL;
}
// Set render target
driver->setRenderTarget(rtt, true, true, video::SColor(0,0,0,0));
// Get a scene manager
scene::ISceneManager *smgr_main = device->getSceneManager();
assert(smgr_main);
scene::ISceneManager *smgr = smgr_main->createNewSceneManager();
assert(smgr);
scene::IMeshSceneNode* meshnode = smgr->addMeshSceneNode(mesh, NULL, -1, v3f(0,0,0), v3f(0,0,0), v3f(1,1,1), true);
meshnode->setMaterialFlag(video::EMF_LIGHTING, true);
meshnode->setMaterialFlag(video::EMF_ANTI_ALIASING, true);
meshnode->setMaterialFlag(video::EMF_BILINEAR_FILTER, true);
scene::ICameraSceneNode* camera = smgr->addCameraSceneNode(0,
camera_position, camera_lookat);
// second parameter of setProjectionMatrix (isOrthogonal) is ignored
camera->setProjectionMatrix(camera_projection_matrix, false);
smgr->setAmbientLight(ambient_light);
smgr->addLightSceneNode(0, light_position, light_color, light_radius);
// Render scene
driver->beginScene(true, true, video::SColor(0,0,0,0));
smgr->drawAll();
driver->endScene();
// NOTE: The scene nodes should not be dropped, otherwise
// smgr->drop() segfaults
/*cube->drop();
camera->drop();
light->drop();*/
// Drop scene manager
smgr->drop();
// Unset render target
driver->setRenderTarget(0, true, true, 0);
return rtt;
}

@ -21,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define MESH_HEADER #define MESH_HEADER
#include "common_irrlicht.h" #include "common_irrlicht.h"
#include <string>
/* /*
Create a new cube mesh. Create a new cube mesh.
@ -47,6 +48,11 @@ scene::IAnimatedMesh* createExtrudedMesh(video::ITexture *texture,
*/ */
void scaleMesh(scene::IMesh *mesh, v3f scale); void scaleMesh(scene::IMesh *mesh, v3f scale);
/*
Translate each vertex coordinate by the specified vector.
*/
void translateMesh(scene::IMesh *mesh, v3f vec);
/* /*
Set a constant color for all vertices in the mesh Set a constant color for all vertices in the mesh
*/ */
@ -63,4 +69,20 @@ void setMeshColorByNormalXYZ(scene::IMesh *mesh,
const video::SColor &colorY, const video::SColor &colorY,
const video::SColor &colorZ); const video::SColor &colorZ);
/*
Render a mesh to a texture.
Returns NULL if render-to-texture failed.
*/
video::ITexture *generateTextureFromMesh(scene::IMesh *mesh,
IrrlichtDevice *device,
core::dimension2d<u32> dim,
std::string texture_name,
v3f camera_position,
v3f camera_lookat,
core::CMatrix4<f32> camera_projection_matrix,
video::SColorf ambient_light,
v3f light_position,
video::SColorf light_color,
f32 light_radius);
#endif #endif

@ -18,6 +18,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
*/ */
#include "mineral.h" #include "mineral.h"
#include "gamedef.h"
const char *mineral_filenames[MINERAL_COUNT] = const char *mineral_filenames[MINERAL_COUNT] =
@ -47,5 +48,15 @@ std::string mineral_block_texture(u8 mineral)
return mineral_textures[mineral]; return mineral_textures[mineral];
} }
ItemStack getDiggedMineralItem(u8 mineral, IGameDef *gamedef)
{
if(mineral == MINERAL_COAL)
return ItemStack("default:coal_lump", 1, 0, "", gamedef->idef());
else if(mineral == MINERAL_IRON)
return ItemStack("default:iron_lump", 1, 0, "", gamedef->idef());
else
return ItemStack();
}

@ -38,19 +38,10 @@ void init_mineral();
#define MINERAL_COUNT 3 #define MINERAL_COUNT 3
std::string mineral_block_texture(u8 mineral);
class IGameDef; class IGameDef;
inline CraftItem * getDiggedMineralItem(u8 mineral, IGameDef *gamedef) std::string mineral_block_texture(u8 mineral);
{ ItemStack getDiggedMineralItem(u8 mineral, IGameDef *gamedef);
if(mineral == MINERAL_COAL)
return new CraftItem(gamedef, "lump_of_coal", 1);
else if(mineral == MINERAL_IRON)
return new CraftItem(gamedef, "lump_of_iron", 1);
return NULL;
}
#endif #endif

@ -20,7 +20,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "nodedef.h" #include "nodedef.h"
#include "main.h" // For g_settings #include "main.h" // For g_settings
#include "nodemetadata.h" #include "itemdef.h"
#ifndef SERVER #ifndef SERVER
#include "tile.h" #include "tile.h"
#endif #endif
@ -103,8 +103,6 @@ void ContentFeatures::reset()
Cached stuff Cached stuff
*/ */
#ifndef SERVER #ifndef SERVER
inventory_texture = NULL;
for(u16 j=0; j<CF_SPECIAL_COUNT; j++){ for(u16 j=0; j<CF_SPECIAL_COUNT; j++){
special_materials[j] = NULL; special_materials[j] = NULL;
special_aps[j] = NULL; special_aps[j] = NULL;
@ -113,7 +111,6 @@ void ContentFeatures::reset()
visual_solidness = 0; visual_solidness = 0;
backface_culling = true; backface_culling = true;
#endif #endif
used_texturenames.clear();
/* /*
Actual data Actual data
@ -127,7 +124,6 @@ void ContentFeatures::reset()
tname_tiles[i] = ""; tname_tiles[i] = "";
for(u16 j=0; j<CF_SPECIAL_COUNT; j++) for(u16 j=0; j<CF_SPECIAL_COUNT; j++)
mspec_special[j] = MaterialSpec(); mspec_special[j] = MaterialSpec();
tname_inventory = "";
alpha = 255; alpha = 255;
post_effect_color = video::SColor(0, 0, 0, 0); post_effect_color = video::SColor(0, 0, 0, 0);
param_type = CPT_NONE; param_type = CPT_NONE;
@ -140,7 +136,6 @@ void ContentFeatures::reset()
climbable = false; climbable = false;
buildable_to = false; buildable_to = false;
wall_mounted = false; wall_mounted = false;
often_contains_mineral = false;
dug_item = ""; dug_item = "";
extra_dug_item = ""; extra_dug_item = "";
extra_dug_item_rarity = 2; extra_dug_item_rarity = 2;
@ -153,21 +148,20 @@ void ContentFeatures::reset()
damage_per_second = 0; damage_per_second = 0;
selection_box = NodeBox(); selection_box = NodeBox();
material = MaterialProperties(); material = MaterialProperties();
cookresult_item = ""; // Cannot be cooked // Make unknown blocks diggable
furnace_cooktime = 3.0; material.diggability = DIGGABLE_CONSTANT;
furnace_burntime = -1.0; // Cannot be burned material.constant_time = 0.5;
} }
void ContentFeatures::serialize(std::ostream &os) void ContentFeatures::serialize(std::ostream &os)
{ {
writeU8(os, 0); // version writeU8(os, 1); // version
os<<serializeString(name); os<<serializeString(name);
writeU8(os, drawtype); writeU8(os, drawtype);
writeF1000(os, visual_scale); writeF1000(os, visual_scale);
writeU8(os, 6); writeU8(os, 6);
for(u32 i=0; i<6; i++) for(u32 i=0; i<6; i++)
os<<serializeString(tname_tiles[i]); os<<serializeString(tname_tiles[i]);
os<<serializeString(tname_inventory);
writeU8(os, CF_SPECIAL_COUNT); writeU8(os, CF_SPECIAL_COUNT);
for(u32 i=0; i<CF_SPECIAL_COUNT; i++){ for(u32 i=0; i<CF_SPECIAL_COUNT; i++){
mspec_special[i].serialize(os); mspec_special[i].serialize(os);
@ -187,7 +181,6 @@ void ContentFeatures::serialize(std::ostream &os)
writeU8(os, climbable); writeU8(os, climbable);
writeU8(os, buildable_to); writeU8(os, buildable_to);
writeU8(os, wall_mounted); writeU8(os, wall_mounted);
writeU8(os, often_contains_mineral);
os<<serializeString(dug_item); os<<serializeString(dug_item);
os<<serializeString(extra_dug_item); os<<serializeString(extra_dug_item);
writeS32(os, extra_dug_item_rarity); writeS32(os, extra_dug_item_rarity);
@ -200,15 +193,12 @@ void ContentFeatures::serialize(std::ostream &os)
writeU32(os, damage_per_second); writeU32(os, damage_per_second);
selection_box.serialize(os); selection_box.serialize(os);
material.serialize(os); material.serialize(os);
os<<serializeString(cookresult_item);
writeF1000(os, furnace_cooktime);
writeF1000(os, furnace_burntime);
} }
void ContentFeatures::deSerialize(std::istream &is, IGameDef *gamedef) void ContentFeatures::deSerialize(std::istream &is)
{ {
int version = readU8(is); int version = readU8(is);
if(version != 0) if(version != 1)
throw SerializationError("unsupported ContentFeatures version"); throw SerializationError("unsupported ContentFeatures version");
name = deSerializeString(is); name = deSerializeString(is);
drawtype = (enum NodeDrawType)readU8(is); drawtype = (enum NodeDrawType)readU8(is);
@ -216,9 +206,7 @@ void ContentFeatures::deSerialize(std::istream &is, IGameDef *gamedef)
if(readU8(is) != 6) if(readU8(is) != 6)
throw SerializationError("unsupported tile count"); throw SerializationError("unsupported tile count");
for(u32 i=0; i<6; i++) for(u32 i=0; i<6; i++)
setTexture(i, deSerializeString(is)); tname_tiles[i] = deSerializeString(is);
//tname_tiles[i] = deSerializeString(is);
tname_inventory = deSerializeString(is);
if(readU8(is) != CF_SPECIAL_COUNT) if(readU8(is) != CF_SPECIAL_COUNT)
throw SerializationError("unsupported CF_SPECIAL_COUNT"); throw SerializationError("unsupported CF_SPECIAL_COUNT");
for(u32 i=0; i<CF_SPECIAL_COUNT; i++){ for(u32 i=0; i<CF_SPECIAL_COUNT; i++){
@ -239,7 +227,6 @@ void ContentFeatures::deSerialize(std::istream &is, IGameDef *gamedef)
climbable = readU8(is); climbable = readU8(is);
buildable_to = readU8(is); buildable_to = readU8(is);
wall_mounted = readU8(is); wall_mounted = readU8(is);
often_contains_mineral = readU8(is);
dug_item = deSerializeString(is); dug_item = deSerializeString(is);
extra_dug_item = deSerializeString(is); extra_dug_item = deSerializeString(is);
extra_dug_item_rarity = readS32(is); extra_dug_item_rarity = readS32(is);
@ -252,53 +239,6 @@ void ContentFeatures::deSerialize(std::istream &is, IGameDef *gamedef)
damage_per_second = readU32(is); damage_per_second = readU32(is);
selection_box.deSerialize(is); selection_box.deSerialize(is);
material.deSerialize(is); material.deSerialize(is);
cookresult_item = deSerializeString(is);
furnace_cooktime = readF1000(is);
furnace_burntime = readF1000(is);
}
void ContentFeatures::setTexture(u16 i, std::string name)
{
used_texturenames.insert(name);
tname_tiles[i] = name;
if(tname_inventory == "")
tname_inventory = name;
}
void ContentFeatures::setAllTextures(std::string name)
{
for(u16 i=0; i<6; i++)
setTexture(i, name);
// Force inventory texture too
setInventoryTexture(name);
}
void ContentFeatures::setSpecialMaterial(u16 i, const MaterialSpec &mspec)
{
assert(i < CF_SPECIAL_COUNT);
mspec_special[i] = mspec;
}
void ContentFeatures::setInventoryTexture(std::string imgname)
{
tname_inventory = imgname;
}
void ContentFeatures::setInventoryTextureCube(std::string top,
std::string left, std::string right)
{
str_replace_char(top, '^', '&');
str_replace_char(left, '^', '&');
str_replace_char(right, '^', '&');
std::string imgname_full;
imgname_full += "[inventorycube{";
imgname_full += top;
imgname_full += "{";
imgname_full += left;
imgname_full += "{";
imgname_full += right;
tname_inventory = imgname_full;
} }
/* /*
@ -311,14 +251,12 @@ public:
void clear() void clear()
{ {
m_name_id_mapping.clear(); m_name_id_mapping.clear();
m_name_id_mapping_with_aliases.clear();
m_aliases.clear();
for(u16 i=0; i<=MAX_CONTENT; i++) for(u16 i=0; i<=MAX_CONTENT; i++)
{ {
ContentFeatures &f = m_content_features[i]; ContentFeatures &f = m_content_features[i];
f.reset(); // Reset to defaults f.reset(); // Reset to defaults
f.setAllTextures("unknown_block.png");
} }
// Set CONTENT_AIR // Set CONTENT_AIR
@ -336,7 +274,7 @@ public:
// Insert directly into containers // Insert directly into containers
content_t c = CONTENT_AIR; content_t c = CONTENT_AIR;
m_content_features[c] = f; m_content_features[c] = f;
m_name_id_mapping.set(c, f.name); addNameIdMapping(c, f.name);
} }
// Set CONTENT_IGNORE // Set CONTENT_IGNORE
{ {
@ -354,7 +292,7 @@ public:
// Insert directly into containers // Insert directly into containers
content_t c = CONTENT_IGNORE; content_t c = CONTENT_IGNORE;
m_content_features[c] = f; m_content_features[c] = f;
m_name_id_mapping.set(c, f.name); addNameIdMapping(c, f.name);
} }
} }
// CONTENT_IGNORE = not found // CONTENT_IGNORE = not found
@ -401,12 +339,14 @@ public:
{ {
return get(n.getContent()); return get(n.getContent());
} }
virtual bool getId(const std::string &name_, content_t &result) const virtual bool getId(const std::string &name, content_t &result) const
{ {
// Convert name according to possible alias std::map<std::string, content_t>::const_iterator
std::string name = getAlias(name_); i = m_name_id_mapping_with_aliases.find(name);
// Get id if(i == m_name_id_mapping_with_aliases.end())
return m_name_id_mapping.getId(name, result); return false;
result = i->second;
return true;
} }
virtual content_t getId(const std::string &name) const virtual content_t getId(const std::string &name) const
{ {
@ -420,14 +360,6 @@ public:
getId(name, id); getId(name, id);
return get(id); return get(id);
} }
virtual std::string getAlias(const std::string &name) const
{
std::map<std::string, std::string>::const_iterator i;
i = m_aliases.find(name);
if(i != m_aliases.end())
return i->second;
return name;
}
// IWritableNodeDefManager // IWritableNodeDefManager
virtual void set(content_t c, const ContentFeatures &def) virtual void set(content_t c, const ContentFeatures &def)
{ {
@ -451,20 +383,14 @@ public:
} }
m_content_features[c] = def; m_content_features[c] = def;
if(def.name != "") if(def.name != "")
m_name_id_mapping.set(c, def.name); addNameIdMapping(c, def.name);
// Remove conflicting alias if it exists
bool alias_removed = (m_aliases.erase(def.name) != 0);
if(alias_removed)
infostream<<"ndef: erased alias "<<def.name
<<" because node was defined"<<std::endl;
} }
virtual content_t set(const std::string &name, virtual content_t set(const std::string &name,
const ContentFeatures &def) const ContentFeatures &def)
{ {
assert(name == def.name); assert(name == def.name);
u16 id = CONTENT_IGNORE; u16 id = CONTENT_IGNORE;
bool found = m_name_id_mapping.getId(name, id); bool found = m_name_id_mapping.getId(name, id); // ignore aliases
if(!found){ if(!found){
// Determine if full param2 is required // Determine if full param2 is required
bool require_full_param2 = ( bool require_full_param2 = (
@ -481,7 +407,7 @@ public:
if(id == CONTENT_IGNORE) if(id == CONTENT_IGNORE)
return CONTENT_IGNORE; return CONTENT_IGNORE;
if(name != "") if(name != "")
m_name_id_mapping.set(id, name); addNameIdMapping(id, name);
} }
set(id, def); set(id, def);
return id; return id;
@ -491,23 +417,27 @@ public:
assert(name != ""); assert(name != "");
ContentFeatures f; ContentFeatures f;
f.name = name; f.name = name;
f.setAllTextures("unknown_block.png");
// Make unknown blocks diggable // Make unknown blocks diggable
f.material.diggability = DIGGABLE_NORMAL; f.material.diggability = DIGGABLE_CONSTANT;
f.material.constant_time = 0.5;
return set(name, f); return set(name, f);
} }
virtual void setAlias(const std::string &name, virtual void updateAliases(IItemDefManager *idef)
const std::string &convert_to)
{ {
content_t id; std::set<std::string> all = idef->getAll();
if(getId(name, id)){ m_name_id_mapping_with_aliases.clear();
infostream<<"ndef: not setting alias "<<name<<" -> "<<convert_to for(std::set<std::string>::iterator
<<": "<<name<<" is already defined"<<std::endl; i = all.begin(); i != all.end(); i++)
return; {
std::string name = *i;
std::string convert_to = idef->getAlias(name);
content_t id;
if(m_name_id_mapping.getId(convert_to, id))
{
m_name_id_mapping_with_aliases.insert(
std::make_pair(name, id));
}
} }
infostream<<"ndef: setting alias "<<name<<" -> "<<convert_to
<<std::endl;
m_aliases[name] = convert_to;
} }
virtual void updateTextures(ITextureSource *tsrc) virtual void updateTextures(ITextureSource *tsrc)
{ {
@ -523,6 +453,14 @@ public:
{ {
ContentFeatures *f = &m_content_features[i]; ContentFeatures *f = &m_content_features[i];
std::string tname_tiles[6];
for(u32 j=0; j<6; j++)
{
tname_tiles[j] = f->tname_tiles[j];
if(tname_tiles[j] == "")
tname_tiles[j] = "unknown_block.png";
}
switch(f->drawtype){ switch(f->drawtype){
default: default:
case NDT_NORMAL: case NDT_NORMAL:
@ -567,8 +505,7 @@ public:
f->drawtype = NDT_NORMAL; f->drawtype = NDT_NORMAL;
f->solidness = 2; f->solidness = 2;
for(u32 i=0; i<6; i++){ for(u32 i=0; i<6; i++){
f->setTexture(i, f->tname_tiles[i] tname_tiles[i] += std::string("^[noalpha");
+ std::string("^[noalpha"));
} }
} }
break; break;
@ -581,16 +518,9 @@ public:
break; break;
} }
// Inventory texture
if(f->tname_inventory != "")
f->inventory_texture = tsrc->getTextureRaw(f->tname_inventory);
else
f->inventory_texture = NULL;
// Tile textures // Tile textures
for(u16 j=0; j<6; j++){ for(u16 j=0; j<6; j++){
if(f->tname_tiles[j] == "") f->tiles[j].texture = tsrc->getTexture(tname_tiles[j]);
continue;
f->tiles[j].texture = tsrc->getTexture(f->tname_tiles[j]);
f->tiles[j].alpha = f->alpha; f->tiles[j].alpha = f->alpha;
if(f->alpha == 255) if(f->alpha == 255)
f->tiles[j].material_type = MATERIAL_ALPHA_SIMPLE; f->tiles[j].material_type = MATERIAL_ALPHA_SIMPLE;
@ -649,16 +579,8 @@ public:
} }
writeU16(os, count); writeU16(os, count);
os<<serializeLongString(tmp_os.str()); os<<serializeLongString(tmp_os.str());
writeU16(os, m_aliases.size());
for(std::map<std::string, std::string>::const_iterator
i = m_aliases.begin(); i != m_aliases.end(); i++)
{
os<<serializeString(i->first);
os<<serializeString(i->second);
}
} }
void deSerialize(std::istream &is, IGameDef *gamedef) void deSerialize(std::istream &is)
{ {
clear(); clear();
u16 count = readU16(is); u16 count = readU16(is);
@ -674,27 +596,26 @@ public:
if(i == CONTENT_IGNORE || i == CONTENT_AIR) if(i == CONTENT_IGNORE || i == CONTENT_AIR)
continue;*/ continue;*/
ContentFeatures *f = &m_content_features[i]; ContentFeatures *f = &m_content_features[i];
f->deSerialize(tmp_is, gamedef); f->deSerialize(tmp_is);
if(f->name != "") if(f->name != "")
m_name_id_mapping.set(i, f->name); addNameIdMapping(i, f->name);
}
u16 num_aliases = readU16(is);
if(!is.eof()){
for(u16 i=0; i<num_aliases; i++){
std::string name = deSerializeString(is);
std::string convert_to = deSerializeString(is);
m_aliases[name] = convert_to;
}
} }
} }
private:
void addNameIdMapping(content_t i, std::string name)
{
m_name_id_mapping.set(i, name);
m_name_id_mapping_with_aliases.insert(std::make_pair(name, i));
}
private: private:
// Features indexed by id // Features indexed by id
ContentFeatures m_content_features[MAX_CONTENT+1]; ContentFeatures m_content_features[MAX_CONTENT+1];
// A mapping for fast converting back and forth between names and ids // A mapping for fast converting back and forth between names and ids
NameIdMapping m_name_id_mapping; NameIdMapping m_name_id_mapping;
// Aliases // Like m_name_id_mapping, but only from names to ids, and includes
std::map<std::string, std::string> m_aliases; // item aliases too. Updated by updateAliases()
// Note: Not serialized.
std::map<std::string, content_t> m_name_id_mapping_with_aliases;
}; };
IWritableNodeDefManager* createNodeDefManager() IWritableNodeDefManager* createNodeDefManager()

@ -29,6 +29,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "tile.h" #include "tile.h"
#endif #endif
#include "materials.h" // MaterialProperties #include "materials.h" // MaterialProperties
class IItemDefManager;
class ITextureSource; class ITextureSource;
class IGameDef; class IGameDef;
@ -124,7 +125,6 @@ struct ContentFeatures
// 0 1 2 3 4 5 // 0 1 2 3 4 5
// up down right left back front // up down right left back front
TileSpec tiles[6]; TileSpec tiles[6];
video::ITexture *inventory_texture;
// Special material/texture // Special material/texture
// - Currently used for flowing liquids // - Currently used for flowing liquids
video::SMaterial *special_materials[CF_SPECIAL_COUNT]; video::SMaterial *special_materials[CF_SPECIAL_COUNT];
@ -133,11 +133,7 @@ struct ContentFeatures
u8 visual_solidness; // When solidness=0, this tells how it looks like u8 visual_solidness; // When solidness=0, this tells how it looks like
bool backface_culling; bool backface_culling;
#endif #endif
// List of textures that are used and are wanted to be included in
// the texture atlas
std::set<std::string> used_texturenames;
/* /*
Actual data Actual data
*/ */
@ -148,7 +144,6 @@ struct ContentFeatures
enum NodeDrawType drawtype; enum NodeDrawType drawtype;
float visual_scale; // Misc. scale parameter float visual_scale; // Misc. scale parameter
std::string tname_tiles[6]; std::string tname_tiles[6];
std::string tname_inventory;
MaterialSpec mspec_special[CF_SPECIAL_COUNT]; // Use setter methods MaterialSpec mspec_special[CF_SPECIAL_COUNT]; // Use setter methods
u8 alpha; u8 alpha;
@ -174,10 +169,6 @@ struct ContentFeatures
// If true, param2 is set to direction when placed. Used for torches. // If true, param2 is set to direction when placed. Used for torches.
// NOTE: the direction format is quite inefficient and should be changed // NOTE: the direction format is quite inefficient and should be changed
bool wall_mounted; bool wall_mounted;
// Whether this content type often contains mineral.
// Used for texture atlas creation.
// Currently only enabled for CONTENT_STONE.
bool often_contains_mineral;
// Inventory item string as which the node appears in inventory when dug. // Inventory item string as which the node appears in inventory when dug.
// Mineral overrides this. // Mineral overrides this.
std::string dug_item; std::string dug_item;
@ -202,9 +193,6 @@ struct ContentFeatures
u32 damage_per_second; u32 damage_per_second;
NodeBox selection_box; NodeBox selection_box;
MaterialProperties material; MaterialProperties material;
std::string cookresult_item;
float furnace_cooktime;
float furnace_burntime;
/* /*
Methods Methods
@ -214,22 +202,8 @@ struct ContentFeatures
~ContentFeatures(); ~ContentFeatures();
void reset(); void reset();
void serialize(std::ostream &os); void serialize(std::ostream &os);
void deSerialize(std::istream &is, IGameDef *gamedef); void deSerialize(std::istream &is);
/*
Texture setters.
*/
// Texture setters. They also add stuff to used_texturenames.
void setTexture(u16 i, std::string name);
void setAllTextures(std::string name);
void setSpecialMaterial(u16 i, const MaterialSpec &mspec);
void setInventoryTexture(std::string imgname);
void setInventoryTextureCube(std::string top,
std::string left, std::string right);
/* /*
Some handy methods Some handy methods
*/ */
@ -253,7 +227,6 @@ public:
virtual bool getId(const std::string &name, content_t &result) const=0; virtual bool getId(const std::string &name, content_t &result) const=0;
virtual content_t getId(const std::string &name) const=0; virtual content_t getId(const std::string &name) const=0;
virtual const ContentFeatures& get(const std::string &name) const=0; virtual const ContentFeatures& get(const std::string &name) const=0;
virtual std::string getAlias(const std::string &name) const =0;
virtual void serialize(std::ostream &os)=0; virtual void serialize(std::ostream &os)=0;
}; };
@ -271,8 +244,7 @@ public:
virtual content_t getId(const std::string &name) const=0; virtual content_t getId(const std::string &name) const=0;
// If not found, returns the features of CONTENT_IGNORE // If not found, returns the features of CONTENT_IGNORE
virtual const ContentFeatures& get(const std::string &name) const=0; virtual const ContentFeatures& get(const std::string &name) const=0;
virtual std::string getAlias(const std::string &name) const =0;
// Register node definition // Register node definition
virtual void set(content_t c, const ContentFeatures &def)=0; virtual void set(content_t c, const ContentFeatures &def)=0;
// Register node definition by name (allocate an id) // Register node definition by name (allocate an id)
@ -281,11 +253,12 @@ public:
const ContentFeatures &def)=0; const ContentFeatures &def)=0;
// If returns CONTENT_IGNORE, could not allocate id // If returns CONTENT_IGNORE, could not allocate id
virtual content_t allocateDummy(const std::string &name)=0; virtual content_t allocateDummy(const std::string &name)=0;
// Set an alias so that nodes named <name> will load as <convert_to>.
// Alias is not set if <name> has already been defined. /*
// Alias will be removed if <name> is defined at a later point of time. Update item alias mapping.
virtual void setAlias(const std::string &name, Call after updating item definitions.
const std::string &convert_to)=0; */
virtual void updateAliases(IItemDefManager *idef)=0;
/* /*
Update tile textures to latest return values of TextueSource. Update tile textures to latest return values of TextueSource.
@ -294,7 +267,7 @@ public:
virtual void updateTextures(ITextureSource *tsrc)=0; virtual void updateTextures(ITextureSource *tsrc)=0;
virtual void serialize(std::ostream &os)=0; virtual void serialize(std::ostream &os)=0;
virtual void deSerialize(std::istream &is, IGameDef *gamedef)=0; virtual void deSerialize(std::istream &is)=0;
}; };
IWritableNodeDefManager* createNodeDefManager(); IWritableNodeDefManager* createNodeDefManager();

@ -28,6 +28,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "main.h" // For g_settings #include "main.h" // For g_settings
#include "settings.h" #include "settings.h"
#include "nodedef.h" #include "nodedef.h"
#include "collision.h"
#include "environment.h" #include "environment.h"
#include "gamedef.h" #include "gamedef.h"
@ -37,13 +38,13 @@ Player::Player(IGameDef *gamedef):
in_water_stable(false), in_water_stable(false),
is_climbing(false), is_climbing(false),
swimming_up(false), swimming_up(false),
inventory(gamedef->idef()),
inventory_backup(NULL), inventory_backup(NULL),
craftresult_is_preview(true), craftresult_is_preview(true),
hp(20), hp(20),
peer_id(PEER_ID_INEXISTENT), peer_id(PEER_ID_INEXISTENT),
// protected // protected
m_gamedef(gamedef), m_gamedef(gamedef),
m_selected_item(0),
m_pitch(0), m_pitch(0),
m_yaw(0), m_yaw(0),
m_speed(0,0,0), m_speed(0,0,0),
@ -58,11 +59,6 @@ Player::~Player()
delete inventory_backup; delete inventory_backup;
} }
void Player::wieldItem(u16 item)
{
m_selected_item = item;
}
void Player::resetInventory() void Player::resetInventory()
{ {
inventory.clear(); inventory.clear();
@ -172,7 +168,7 @@ void Player::deSerialize(std::istream &is)
hp = 20; hp = 20;
} }
inventory.deSerialize(is, m_gamedef); inventory.deSerialize(is);
} }
#ifndef SERVER #ifndef SERVER

@ -22,7 +22,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "common_irrlicht.h" #include "common_irrlicht.h"
#include "inventory.h" #include "inventory.h"
#include "collision.h"
#define PLAYERNAME_SIZE 20 #define PLAYERNAME_SIZE 20
@ -31,6 +30,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
class Map; class Map;
class IGameDef; class IGameDef;
class CollisionInfo;
class Player class Player
{ {
@ -117,16 +117,7 @@ public:
snprintf(m_name, PLAYERNAME_SIZE, "%s", name); snprintf(m_name, PLAYERNAME_SIZE, "%s", name);
} }
virtual void wieldItem(u16 item); const char * getName() const
virtual const InventoryItem *getWieldItem() const
{
const InventoryList *list = inventory.getList("main");
if (list)
return list->getItem(m_selected_item);
return NULL;
}
const char * getName()
{ {
return m_name; return m_name;
} }
@ -174,7 +165,6 @@ protected:
IGameDef *m_gamedef; IGameDef *m_gamedef;
char m_name[PLAYERNAME_SIZE]; char m_name[PLAYERNAME_SIZE];
u16 m_selected_item;
f32 m_pitch; f32 m_pitch;
f32 m_yaw; f32 m_yaw;
v3f m_speed; v3f m_speed;

File diff suppressed because it is too large Load Diff

@ -27,11 +27,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
class Server; class Server;
class ServerEnvironment; class ServerEnvironment;
class ServerActiveObject; class ServerActiveObject;
class ServerRemotePlayer;
typedef struct lua_State lua_State; typedef struct lua_State lua_State;
struct LuaEntityProperties; struct LuaEntityProperties;
class ItemStack;
struct PointedThing; struct PointedThing;
//class IGameDef; //class IGameDef;
class ServerRemotePlayer;
void scriptapi_export(lua_State *L, Server *server); void scriptapi_export(lua_State *L, Server *server);
bool scriptapi_loadmod(lua_State *L, const std::string &scriptpath, bool scriptapi_loadmod(lua_State *L, const std::string &scriptpath,
@ -66,17 +67,13 @@ 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_get_creative_inventory(lua_State *L, ServerRemotePlayer *player); void scriptapi_get_creative_inventory(lua_State *L, ServerRemotePlayer *player);
/* craftitem */ /* item callbacks */
void scriptapi_add_craftitem(lua_State *L, const char *name); bool scriptapi_item_on_drop(lua_State *L, ItemStack &item,
bool scriptapi_craftitem_on_drop(lua_State *L, const char *name, ServerActiveObject *dropper, v3f pos);
ServerActiveObject *dropper, v3f pos, bool scriptapi_item_on_place(lua_State *L, ItemStack &item,
bool &callback_exists); ServerActiveObject *placer, const PointedThing &pointed);
bool scriptapi_craftitem_on_place_on_ground(lua_State *L, const char *name, bool scriptapi_item_on_use(lua_State *L, ItemStack &item,
ServerActiveObject *placer, v3f pos, ServerActiveObject *user, const PointedThing &pointed);
bool &callback_exists);
bool scriptapi_craftitem_on_use(lua_State *L, const char *name,
ServerActiveObject *user, const PointedThing& pointed,
bool &callback_exists);
/* luaentity */ /* luaentity */
// Returns true if succesfully added into Lua; false otherwise. // Returns true if succesfully added into Lua; false otherwise.

File diff suppressed because it is too large Load Diff

@ -36,10 +36,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "inventorymanager.h" #include "inventorymanager.h"
struct LuaState; struct LuaState;
typedef struct lua_State lua_State; typedef struct lua_State lua_State;
class IWritableToolDefManager; class IWritableItemDefManager;
class IWritableNodeDefManager; class IWritableNodeDefManager;
class IWritableCraftDefManager; class IWritableCraftDefManager;
class IWritableCraftItemDefManager;
/* /*
Some random functions Some random functions
@ -437,6 +436,7 @@ public:
Shall be called with the environment and the connection locked. Shall be called with the environment and the connection locked.
*/ */
Inventory* getInventory(const InventoryLocation &loc); Inventory* getInventory(const InventoryLocation &loc);
std::string getInventoryOwner(const InventoryLocation &loc);
void setInventoryModified(const InventoryLocation &loc); void setInventoryModified(const InventoryLocation &loc);
// Connection must be locked when called // Connection must be locked when called
@ -514,17 +514,15 @@ public:
// IGameDef interface // IGameDef interface
// Under envlock // Under envlock
virtual IToolDefManager* getToolDefManager(); virtual IItemDefManager* getItemDefManager();
virtual INodeDefManager* getNodeDefManager(); virtual INodeDefManager* getNodeDefManager();
virtual ICraftDefManager* getCraftDefManager(); virtual ICraftDefManager* getCraftDefManager();
virtual ICraftItemDefManager* getCraftItemDefManager();
virtual ITextureSource* getTextureSource(); virtual ITextureSource* getTextureSource();
virtual u16 allocateUnknownNodeId(const std::string &name); virtual u16 allocateUnknownNodeId(const std::string &name);
IWritableToolDefManager* getWritableToolDefManager(); IWritableItemDefManager* getWritableItemDefManager();
IWritableNodeDefManager* getWritableNodeDefManager(); IWritableNodeDefManager* getWritableNodeDefManager();
IWritableCraftDefManager* getWritableCraftDefManager(); IWritableCraftDefManager* getWritableCraftDefManager();
IWritableCraftItemDefManager* getWritableCraftItemDefManager();
const ModSpec* getModSpec(const std::string &modname); const ModSpec* getModSpec(const std::string &modname);
@ -545,12 +543,10 @@ private:
const std::wstring &reason); const std::wstring &reason);
static void SendDeathscreen(con::Connection &con, u16 peer_id, static void SendDeathscreen(con::Connection &con, u16 peer_id,
bool set_camera_point_target, v3f camera_point_target); bool set_camera_point_target, v3f camera_point_target);
static void SendToolDef(con::Connection &con, u16 peer_id, static void SendItemDef(con::Connection &con, u16 peer_id,
IToolDefManager *tooldef); IItemDefManager *itemdef);
static void SendNodeDef(con::Connection &con, u16 peer_id, static void SendNodeDef(con::Connection &con, u16 peer_id,
INodeDefManager *nodedef); INodeDefManager *nodedef);
static void SendCraftItemDef(con::Connection &con, u16 peer_id,
ICraftItemDefManager *nodedef);
/* /*
Non-static send methods. Non-static send methods.
@ -562,7 +558,7 @@ private:
// Envlock and conlock should be locked when calling these // Envlock and conlock should be locked when calling these
void SendInventory(u16 peer_id); void SendInventory(u16 peer_id);
// send wielded item info about player to all // send wielded item info about player to all
void SendWieldedItem(const Player *player); void SendWieldedItem(const ServerRemotePlayer *srp);
// send wielded item info about all players to all players // send wielded item info about all players to all players
void SendPlayerItems(); void SendPlayerItems();
void SendChatMessage(u16 peer_id, const std::wstring &message); void SendChatMessage(u16 peer_id, const std::wstring &message);
@ -599,6 +595,7 @@ private:
void HandlePlayerHP(Player *player, s16 damage); void HandlePlayerHP(Player *player, s16 damage);
void RespawnPlayer(Player *player); void RespawnPlayer(Player *player);
bool GetCraftingResult(u16 peer_id, ItemStack &result, bool decrementInput);
void UpdateCrafting(u16 peer_id); void UpdateCrafting(u16 peer_id);
// When called, connection mutex should be locked // When called, connection mutex should be locked
@ -664,8 +661,8 @@ private:
// Envlock and conlock should be locked when using Lua // Envlock and conlock should be locked when using Lua
lua_State *m_lua; lua_State *m_lua;
// Tool definition manager // Item definition manager
IWritableToolDefManager *m_toolmgr; IWritableItemDefManager *m_itemdef;
// Node definition manager // Node definition manager
IWritableNodeDefManager *m_nodedef; IWritableNodeDefManager *m_nodedef;
@ -673,9 +670,6 @@ private:
// Craft definition manager // Craft definition manager
IWritableCraftDefManager *m_craftdef; IWritableCraftDefManager *m_craftdef;
// CraftItem definition manager
IWritableCraftItemDefManager *m_craftitemdef;
// Mods // Mods
core::list<ModSpec> m_mods; core::list<ModSpec> m_mods;
@ -740,7 +734,7 @@ private:
core::list<std::string> m_modspaths; core::list<std::string> m_modspaths;
bool m_shutdown_requested; bool m_shutdown_requested;
/* /*
Map edit event queue. Automatically receives all map edits. Map edit event queue. Automatically receives all map edits.
The constructor of this class registers us to receive them through The constructor of this class registers us to receive them through

@ -20,7 +20,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "serverobject.h" #include "serverobject.h"
#include <fstream> #include <fstream>
#include "inventory.h" #include "inventory.h"
#include "tooldef.h" #include "materials.h"
ServerActiveObject::ServerActiveObject(ServerEnvironment *env, v3f pos): ServerActiveObject::ServerActiveObject(ServerEnvironment *env, v3f pos):
ActiveObject(0), ActiveObject(0),
@ -67,10 +67,31 @@ void ServerActiveObject::registerType(u16 type, Factory f)
m_types.insert(type, f); m_types.insert(type, f);
} }
void ServerActiveObject::getWieldDiggingProperties(ToolDiggingProperties *dst) ItemStack ServerActiveObject::getWieldedItem() const
{ {
*dst = ToolDiggingProperties(); const Inventory *inv = getInventory();
if(inv)
{
const InventoryList *list = inv->getList(getWieldList());
if(list)
return list->getItem(getWieldIndex());
}
return ItemStack();
} }
bool ServerActiveObject::setWieldedItem(const ItemStack &item)
{
Inventory *inv = getInventory();
if(inv)
{
InventoryList *list = inv->getList(getWieldList());
if (list)
{
list->changeItem(getWieldIndex(), item);
setInventoryModified();
return true;
}
}
return false;
}

@ -23,6 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "irrlichttypes.h" #include "irrlichttypes.h"
#include "activeobject.h" #include "activeobject.h"
#include "utility.h" #include "utility.h"
#include "inventorymanager.h"
/* /*
@ -41,7 +42,7 @@ Some planning
*/ */
class ServerEnvironment; class ServerEnvironment;
class InventoryItem; class ItemStack;
class Player; class Player;
struct ToolDiggingProperties; struct ToolDiggingProperties;
@ -138,19 +139,27 @@ public:
{} {}
virtual void rightClick(ServerActiveObject *clicker) virtual void rightClick(ServerActiveObject *clicker)
{} {}
virtual void getWieldDiggingProperties(ToolDiggingProperties *dst);
virtual void damageWieldedItem(u16 amount)
{}
// If all fits, eats item and returns true. Otherwise returns false.
virtual bool addToInventory(InventoryItem *item)
{ return false; }
virtual void addToInventoryLater(InventoryItem *item)
{}
virtual void setHP(s16 hp) virtual void setHP(s16 hp)
{} {}
virtual s16 getHP() virtual s16 getHP()
{ return 0; } { return 0; }
// Inventory and wielded item
virtual Inventory* getInventory()
{ return NULL; }
virtual const Inventory* getInventory() const
{ return NULL; }
virtual InventoryLocation getInventoryLocation() const
{ return InventoryLocation(); }
virtual void setInventoryModified()
{}
virtual std::string getWieldList() const
{ return ""; }
virtual int getWieldIndex() const
{ return 0; }
virtual ItemStack getWieldedItem() const;
virtual bool setWieldedItem(const ItemStack &item);
/* /*
Number of players which know about this object. Object won't be Number of players which know about this object. Object won't be
deleted until this is 0 to keep the id preserved for the right deleted until this is 0 to keep the id preserved for the right

@ -22,7 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "settings.h" #include "settings.h"
#include "log.h" #include "log.h"
#include "gamedef.h" #include "gamedef.h"
#include "tooldef.h" #include "inventory.h"
#include "environment.h" #include "environment.h"
#include "materials.h" #include "materials.h"
@ -31,6 +31,7 @@ ServerRemotePlayer::ServerRemotePlayer(ServerEnvironment *env):
ServerActiveObject(env, v3f(0,0,0)), ServerActiveObject(env, v3f(0,0,0)),
m_last_good_position(0,0,0), m_last_good_position(0,0,0),
m_last_good_position_age(0), m_last_good_position_age(0),
m_wield_index(0),
m_inventory_not_sent(false), m_inventory_not_sent(false),
m_hp_not_sent(false), m_hp_not_sent(false),
m_respawn_active(false), m_respawn_active(false),
@ -57,7 +58,6 @@ ServerRemotePlayer::ServerRemotePlayer(ServerEnvironment *env, v3f pos_, u16 pee
} }
ServerRemotePlayer::~ServerRemotePlayer() ServerRemotePlayer::~ServerRemotePlayer()
{ {
clearAddToInventoryLater();
} }
void ServerRemotePlayer::setPosition(const v3f &position) void ServerRemotePlayer::setPosition(const v3f &position)
@ -67,12 +67,41 @@ void ServerRemotePlayer::setPosition(const v3f &position)
m_position_not_sent = true; m_position_not_sent = true;
} }
InventoryItem* ServerRemotePlayer::getWieldedItem() Inventory* ServerRemotePlayer::getInventory()
{ {
InventoryList *list = inventory.getList("main"); return &inventory;
if (list) }
return list->getItem(m_selected_item);
return NULL; const Inventory* ServerRemotePlayer::getInventory() const
{
return &inventory;
}
InventoryLocation ServerRemotePlayer::getInventoryLocation() const
{
InventoryLocation loc;
loc.setPlayer(getName());
return loc;
}
void ServerRemotePlayer::setInventoryModified()
{
m_inventory_not_sent = true;
}
std::string ServerRemotePlayer::getWieldList() const
{
return "main";
}
int ServerRemotePlayer::getWieldIndex() const
{
return m_wield_index;
}
void ServerRemotePlayer::setWieldIndex(int i)
{
m_wield_index = i;
} }
/* ServerActiveObject interface */ /* ServerActiveObject interface */
@ -156,8 +185,10 @@ void ServerRemotePlayer::punch(ServerActiveObject *puncher,
mp.crackiness = -0.5; mp.crackiness = -0.5;
mp.cuttability = 0.5; mp.cuttability = 0.5;
ToolDiggingProperties tp; IItemDefManager *idef = m_env->getGameDef()->idef();
puncher->getWieldDiggingProperties(&tp); ItemStack punchitem = puncher->getWieldedItem();
ToolDiggingProperties tp =
punchitem.getToolDiggingProperties(idef);
HittingProperties hitprop = getHittingProperties(&mp, &tp, HittingProperties hitprop = getHittingProperties(&mp, &tp,
time_from_last_punch); time_from_last_punch);
@ -167,7 +198,8 @@ void ServerRemotePlayer::punch(ServerActiveObject *puncher,
<<" HP"<<std::endl; <<" HP"<<std::endl;
setHP(getHP() - hitprop.hp); setHP(getHP() - hitprop.hp);
puncher->damageWieldedItem(hitprop.wear); punchitem.addWear(hitprop.wear, idef);
puncher->setWieldedItem(punchitem);
if(hitprop.hp != 0) if(hitprop.hp != 0)
{ {
@ -201,109 +233,6 @@ void ServerRemotePlayer::moveTo(v3f pos, bool continuous)
m_last_good_position_age = 0; m_last_good_position_age = 0;
} }
void ServerRemotePlayer::getWieldDiggingProperties(ToolDiggingProperties *dst)
{
IGameDef *gamedef = m_env->getGameDef();
IToolDefManager *tdef = gamedef->tdef();
InventoryItem *item = getWieldedItem();
if(item == NULL || std::string(item->getName()) != "ToolItem"){
*dst = ToolDiggingProperties();
return;
}
ToolItem *titem = (ToolItem*)item;
*dst = tdef->getDiggingProperties(titem->getToolName());
}
void ServerRemotePlayer::damageWieldedItem(u16 amount)
{
infostream<<"Damaging "<<getName()<<"'s wielded item for amount="
<<amount<<std::endl;
InventoryList *list = inventory.getList("main");
if(!list)
return;
InventoryItem *item = list->getItem(m_selected_item);
if(item && (std::string)item->getName() == "ToolItem"){
ToolItem *titem = (ToolItem*)item;
bool weared_out = titem->addWear(amount);
if(weared_out)
list->deleteItem(m_selected_item);
}
}
bool ServerRemotePlayer::addToInventory(InventoryItem *item)
{
infostream<<"Adding "<<item->getName()<<" into "<<getName()
<<"'s inventory"<<std::endl;
InventoryList *ilist = inventory.getList("main");
if(ilist == NULL)
return false;
// In creative mode, just delete the item
if(g_settings->getBool("creative_mode")){
return false;
}
// Skip if inventory has no free space
if(ilist->roomForItem(item) == false)
{
infostream<<"Player inventory has no free space"<<std::endl;
return false;
}
// Add to inventory
InventoryItem *leftover = ilist->addItem(item);
assert(!leftover);
m_inventory_not_sent = true;
return true;
}
void ServerRemotePlayer::addToInventoryLater(InventoryItem *item)
{
infostream<<"Adding (later) "<<item->getName()<<" into "<<getName()
<<"'s inventory"<<std::endl;
m_additional_items.push_back(item);
}
void ServerRemotePlayer::clearAddToInventoryLater()
{
for (std::vector<InventoryItem*>::iterator
i = m_additional_items.begin();
i != m_additional_items.end(); i++)
{
delete *i;
}
m_additional_items.clear();
}
void ServerRemotePlayer::completeAddToInventoryLater(u16 preferred_index)
{
InventoryList *ilist = inventory.getList("main");
if(ilist == NULL)
{
clearAddToInventoryLater();
return;
}
// In creative mode, just delete the items
if(g_settings->getBool("creative_mode"))
{
clearAddToInventoryLater();
return;
}
for (std::vector<InventoryItem*>::iterator
i = m_additional_items.begin();
i != m_additional_items.end(); i++)
{
InventoryItem *item = *i;
InventoryItem *leftover = item;
leftover = ilist->addItem(preferred_index, leftover);
leftover = ilist->addItem(leftover);
delete leftover;
}
m_additional_items.clear();
m_inventory_not_sent = true;
}
void ServerRemotePlayer::setHP(s16 hp_) void ServerRemotePlayer::setHP(s16 hp_)
{ {
s16 oldhp = hp; s16 oldhp = hp;

@ -46,9 +46,6 @@ public:
virtual void setPosition(const v3f &position); virtual void setPosition(const v3f &position);
// Returns a reference
virtual InventoryItem* getWieldedItem();
/* ServerActiveObject interface */ /* ServerActiveObject interface */
u8 getType() const u8 getType() const
@ -77,19 +74,20 @@ public:
virtual std::string getDescription() virtual std::string getDescription()
{return std::string("player ")+getName();} {return std::string("player ")+getName();}
virtual void getWieldDiggingProperties(ToolDiggingProperties *dst); virtual Inventory* getInventory();
virtual void damageWieldedItem(u16 amount); virtual const Inventory* getInventory() const;
// If all fits, eats item and returns true. Otherwise returns false. virtual InventoryLocation getInventoryLocation() const;
virtual bool addToInventory(InventoryItem *item); virtual void setInventoryModified();
virtual void addToInventoryLater(InventoryItem *item); virtual std::string getWieldList() const;
void clearAddToInventoryLater(); virtual int getWieldIndex() const;
void completeAddToInventoryLater(u16 preferred_index); virtual void setWieldIndex(int i);
virtual void setHP(s16 hp_); virtual void setHP(s16 hp_);
virtual s16 getHP(); virtual s16 getHP();
v3f m_last_good_position; v3f m_last_good_position;
float m_last_good_position_age; float m_last_good_position_age;
std::vector<InventoryItem*> m_additional_items; int m_wield_index;
bool m_inventory_not_sent; bool m_inventory_not_sent;
bool m_hp_not_sent; bool m_hp_not_sent;
bool m_respawn_active; bool m_respawn_active;

@ -47,6 +47,75 @@ with this program; if not, write to the Free Software Foundation, Inc.,
assert(exception_thrown);\ assert(exception_thrown);\
} }
/*
A few item and node definitions for those tests that need them
*/
#define CONTENT_STONE 0
#define CONTENT_GRASS 0x800
void define_some_nodes(IWritableItemDefManager *idef, IWritableNodeDefManager *ndef)
{
content_t i;
ItemDefinition itemdef;
ContentFeatures f;
/*
Stone
*/
i = CONTENT_STONE;
itemdef = ItemDefinition();
itemdef.type = ITEM_NODE;
itemdef.name = "default:stone";
itemdef.description = "Stone";
itemdef.inventory_image = "[inventorycube"
"{default_stone.png"
"{default_stone.png"
"{default_stone.png";
f = ContentFeatures();
f.name = itemdef.name;
for(int i = 0; i < 6; i++)
f.tname_tiles[i] = "default_stone.png";
f.param_type = CPT_MINERAL;
f.is_ground_content = true;
f.dug_item = itemdef.name;
f.material.diggability = DIGGABLE_NORMAL;
f.material.weight = 5.0;
f.material.crackiness = 1.0;
f.material.crumbliness = -0.1;
f.material.cuttability = -0.2;
idef->registerItem(itemdef);
ndef->set(i, f);
/*
Grass
*/
i = CONTENT_GRASS;
itemdef = ItemDefinition();
itemdef.type = ITEM_NODE;
itemdef.name = "default:dirt_with_grass";
itemdef.description = "Dirt with grass";
itemdef.inventory_image = "[inventorycube"
"{default_grass.png"
"{default_dirt.png&default_grass_side.png"
"{default_dirt.png&default_grass_side.png";
f = ContentFeatures();
f.name = itemdef.name;
f.tname_tiles[0] = "default_grass.png";
f.tname_tiles[1] = "default_dirt.png";
for(int i = 2; i < 6; i++)
f.tname_tiles[i] = "default_dirt.png^default_grass_side.png";
f.is_ground_content = true;
f.dug_item = itemdef.name;
f.material.diggability = DIGGABLE_NORMAL;
f.material.weight = 1.2;
f.material.crackiness = 0.0;
f.material.crumbliness = 1.2;
f.material.cuttability = -0.4;
idef->registerItem(itemdef);
ndef->set(i, f);
}
struct TestUtilities struct TestUtilities
{ {
void Run() void Run()
@ -96,7 +165,118 @@ struct TestSettings
assert(fabs(s.getV3F("coord2").Z - 3.3) < 0.001); assert(fabs(s.getV3F("coord2").Z - 3.3) < 0.001);
} }
}; };
struct TestSerialization
{
// To be used like this:
// mkstr("Some\0string\0with\0embedded\0nuls")
// since std::string("...") doesn't work as expected in that case.
template<size_t N> std::string mkstr(const char (&s)[N])
{
return std::string(s, N - 1);
}
void Run()
{
// Tests some serialization primitives
assert(serializeString("") == mkstr("\0\0"));
assert(serializeWideString(L"") == mkstr("\0\0"));
assert(serializeLongString("") == mkstr("\0\0\0\0"));
assert(serializeJsonString("") == "\"\"");
std::string teststring = "Hello world!";
assert(serializeString(teststring) ==
mkstr("\0\14Hello world!"));
assert(serializeWideString(narrow_to_wide(teststring)) ==
mkstr("\0\14\0H\0e\0l\0l\0o\0 \0w\0o\0r\0l\0d\0!"));
assert(serializeLongString(teststring) ==
mkstr("\0\0\0\14Hello world!"));
assert(serializeJsonString(teststring) ==
"\"Hello world!\"");
std::string teststring2;
std::wstring teststring2_w;
std::string teststring2_w_encoded;
{
std::ostringstream tmp_os;
std::wostringstream tmp_os_w;
std::ostringstream tmp_os_w_encoded;
for(int i = 0; i < 256; i++)
{
tmp_os<<(char)i;
tmp_os_w<<(wchar_t)i;
tmp_os_w_encoded<<(char)0<<(char)i;
}
teststring2 = tmp_os.str();
teststring2_w = tmp_os_w.str();
teststring2_w_encoded = tmp_os_w_encoded.str();
}
assert(serializeString(teststring2) ==
mkstr("\1\0") + teststring2);
assert(serializeWideString(teststring2_w) ==
mkstr("\1\0") + teststring2_w_encoded);
assert(serializeLongString(teststring2) ==
mkstr("\0\0\1\0") + teststring2);
assert(serializeJsonString(teststring2) ==
mkstr("\"") +
"\\u0000\\u0001\\u0002\\u0003\\u0004\\u0005\\u0006\\u0007" +
"\\b\\t\\n\\u000b\\f\\r\\u000e\\u000f" +
"\\u0010\\u0011\\u0012\\u0013\\u0014\\u0015\\u0016\\u0017" +
"\\u0018\\u0019\\u001a\\u001b\\u001c\\u001d\\u001e\\u001f" +
" !\\\"" + teststring2.substr(0x23, 0x2f-0x23) +
"\\/" + teststring2.substr(0x30, 0x5c-0x30) +
"\\\\" + teststring2.substr(0x5d, 0x7f-0x5d) + "\\u007f" +
"\\u0080\\u0081\\u0082\\u0083\\u0084\\u0085\\u0086\\u0087" +
"\\u0088\\u0089\\u008a\\u008b\\u008c\\u008d\\u008e\\u008f" +
"\\u0090\\u0091\\u0092\\u0093\\u0094\\u0095\\u0096\\u0097" +
"\\u0098\\u0099\\u009a\\u009b\\u009c\\u009d\\u009e\\u009f" +
"\\u00a0\\u00a1\\u00a2\\u00a3\\u00a4\\u00a5\\u00a6\\u00a7" +
"\\u00a8\\u00a9\\u00aa\\u00ab\\u00ac\\u00ad\\u00ae\\u00af" +
"\\u00b0\\u00b1\\u00b2\\u00b3\\u00b4\\u00b5\\u00b6\\u00b7" +
"\\u00b8\\u00b9\\u00ba\\u00bb\\u00bc\\u00bd\\u00be\\u00bf" +
"\\u00c0\\u00c1\\u00c2\\u00c3\\u00c4\\u00c5\\u00c6\\u00c7" +
"\\u00c8\\u00c9\\u00ca\\u00cb\\u00cc\\u00cd\\u00ce\\u00cf" +
"\\u00d0\\u00d1\\u00d2\\u00d3\\u00d4\\u00d5\\u00d6\\u00d7" +
"\\u00d8\\u00d9\\u00da\\u00db\\u00dc\\u00dd\\u00de\\u00df" +
"\\u00e0\\u00e1\\u00e2\\u00e3\\u00e4\\u00e5\\u00e6\\u00e7" +
"\\u00e8\\u00e9\\u00ea\\u00eb\\u00ec\\u00ed\\u00ee\\u00ef" +
"\\u00f0\\u00f1\\u00f2\\u00f3\\u00f4\\u00f5\\u00f6\\u00f7" +
"\\u00f8\\u00f9\\u00fa\\u00fb\\u00fc\\u00fd\\u00fe\\u00ff" +
"\"");
{
std::istringstream is(serializeString(teststring2), std::ios::binary);
assert(deSerializeString(is) == teststring2);
assert(!is.eof());
is.get();
assert(is.eof());
}
{
std::istringstream is(serializeWideString(teststring2_w), std::ios::binary);
assert(deSerializeWideString(is) == teststring2_w);
assert(!is.eof());
is.get();
assert(is.eof());
}
{
std::istringstream is(serializeLongString(teststring2), std::ios::binary);
assert(deSerializeLongString(is) == teststring2);
assert(!is.eof());
is.get();
assert(is.eof());
}
{
std::istringstream is(serializeJsonString(teststring2), std::ios::binary);
//dstream<<serializeJsonString(deSerializeJsonString(is));
assert(deSerializeJsonString(is) == teststring2);
assert(!is.eof());
is.get();
assert(is.eof());
}
}
};
struct TestCompress struct TestCompress
{ {
void Run() void Run()
@ -283,11 +463,11 @@ struct TestVoxelManipulator
infostream<<"*** Setting (-1,0,-1)=2 ***"<<std::endl; infostream<<"*** Setting (-1,0,-1)=2 ***"<<std::endl;
v.setNodeNoRef(v3s16(-1,0,-1), MapNode(2)); v.setNodeNoRef(v3s16(-1,0,-1), MapNode(CONTENT_GRASS));
v.print(infostream, nodedef); v.print(infostream, nodedef);
assert(v.getNode(v3s16(-1,0,-1)).getContent() == 2); assert(v.getNode(v3s16(-1,0,-1)).getContent() == CONTENT_GRASS);
infostream<<"*** Reading from inexistent (0,0,-1) ***"<<std::endl; infostream<<"*** Reading from inexistent (0,0,-1) ***"<<std::endl;
@ -301,7 +481,7 @@ struct TestVoxelManipulator
v.print(infostream, nodedef); v.print(infostream, nodedef);
assert(v.getNode(v3s16(-1,0,-1)).getContent() == 2); assert(v.getNode(v3s16(-1,0,-1)).getContent() == CONTENT_GRASS);
EXCEPTION_CHECK(InvalidPositionException, v.getNode(v3s16(0,1,1))); EXCEPTION_CHECK(InvalidPositionException, v.getNode(v3s16(0,1,1)));
} }
}; };
@ -1086,16 +1266,18 @@ void run_tests()
{ {
DSTACK(__FUNCTION_NAME); DSTACK(__FUNCTION_NAME);
// Create node definitions // Create item and node definitions
IWritableNodeDefManager *nodedef = createNodeDefManager(); IWritableItemDefManager *idef = createItemDefManager();
content_mapnode_init(nodedef); IWritableNodeDefManager *ndef = createNodeDefManager();
define_some_nodes(idef, ndef);
infostream<<"run_tests() started"<<std::endl; infostream<<"run_tests() started"<<std::endl;
TEST(TestUtilities); TEST(TestUtilities);
TEST(TestSettings); TEST(TestSettings);
TEST(TestCompress); TEST(TestCompress);
TESTPARAMS(TestMapNode, nodedef); TEST(TestSerialization);
TESTPARAMS(TestVoxelManipulator, nodedef); TESTPARAMS(TestMapNode, ndef);
TESTPARAMS(TestVoxelManipulator, ndef);
//TEST(TestMapBlock); //TEST(TestMapBlock);
//TEST(TestMapSector); //TEST(TestMapSector);
if(INTERNET_SIMULATOR == false){ if(INTERNET_SIMULATOR == false){

@ -337,6 +337,12 @@ public:
return ap.atlas; return ap.atlas;
} }
// Returns a pointer to the irrlicht device
virtual IrrlichtDevice* getDevice()
{
return m_device;
}
// Update new texture pointer and texture coordinates to an // Update new texture pointer and texture coordinates to an
// AtlasPointer based on it's texture id // AtlasPointer based on it's texture id
void updateAP(AtlasPointer &ap); void updateAP(AtlasPointer &ap);
@ -469,8 +475,6 @@ u32 TextureSource::getTextureId(const std::string &name)
return 0; return 0;
} }
// Draw a progress bar on the image
void make_progressbar(float value, video::IImage *image);
// Brighten image // Brighten image
void brighten(video::IImage *image); void brighten(video::IImage *image);
@ -816,14 +820,12 @@ void TextureSource::buildMainAtlas(class IGameDef *gamedef)
if(j == CONTENT_IGNORE || j == CONTENT_AIR) if(j == CONTENT_IGNORE || j == CONTENT_AIR)
continue; continue;
const ContentFeatures &f = ndef->get(j); const ContentFeatures &f = ndef->get(j);
for(std::set<std::string>::const_iterator for(u32 i=0; i<6; i++)
i = f.used_texturenames.begin();
i != f.used_texturenames.end(); i++)
{ {
std::string name = *i; std::string name = f.tname_tiles[i];
sourcelist[name] = true; sourcelist[name] = true;
if(f.often_contains_mineral){ if(f.param_type == CPT_MINERAL){
for(int k=1; k<MINERAL_COUNT; k++){ for(int k=1; k<MINERAL_COUNT; k++){
std::string mineraltexture = mineral_block_texture(k); std::string mineraltexture = mineral_block_texture(k);
std::string fulltexture = name + "^" + mineraltexture; std::string fulltexture = name + "^" + mineraltexture;
@ -1316,23 +1318,6 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
} }
} }
} }
/*
[progressbarN
Adds a progress bar, 0.0 <= N <= 1.0
*/
else if(part_of_name.substr(0,12) == "[progressbar")
{
if(baseimg == NULL)
{
errorstream<<"generate_image(): baseimg==NULL "
<<"for part_of_name=\""<<part_of_name
<<"\", cancelling."<<std::endl;
return false;
}
float value = stof(part_of_name.substr(12));
make_progressbar(value, baseimg);
}
/* /*
"[brighten" "[brighten"
*/ */
@ -1442,23 +1427,6 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
std::string imagename_left = sf.next("{"); std::string imagename_left = sf.next("{");
std::string imagename_right = sf.next("{"); std::string imagename_right = sf.next("{");
#if 1
// TODO: Create cube with different textures on different sides
if(driver->queryFeature(video::EVDF_RENDER_TO_TARGET) == false)
{
errorstream<<"generate_image(): EVDF_RENDER_TO_TARGET"
" not supported. Creating fallback image"<<std::endl;
baseimg = generate_image_from_scratch(
imagename_top, device, sourcecache);
return true;
}
u32 w0 = 64;
u32 h0 = 64;
//infostream<<"inventorycube w="<<w0<<" h="<<h0<<std::endl;
core::dimension2d<u32> dim(w0,h0);
// Generate images for the faces of the cube // Generate images for the faces of the cube
video::IImage *img_top = generate_image_from_scratch( video::IImage *img_top = generate_image_from_scratch(
imagename_top, device, sourcecache); imagename_top, device, sourcecache);
@ -1482,84 +1450,65 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
img_left->drop(); img_left->drop();
img_right->drop(); img_right->drop();
// Create render target texture
video::ITexture *rtt = NULL;
std::string rtt_name = part_of_name + "_RTT";
rtt = driver->addRenderTargetTexture(dim, rtt_name.c_str(),
video::ECF_A8R8G8B8);
assert(rtt);
// Set render target
driver->setRenderTarget(rtt, true, true,
video::SColor(0,0,0,0));
// Get a scene manager
scene::ISceneManager *smgr_main = device->getSceneManager();
assert(smgr_main);
scene::ISceneManager *smgr = smgr_main->createNewSceneManager();
assert(smgr);
/* /*
Create scene: Draw a cube mesh into a render target texture
- An unit cube is centered at 0,0,0
- Camera looks at cube from Y+, Z- towards Y-, Z+
*/ */
scene::IMesh* cube = createCubeMesh(v3f(1, 1, 1)); scene::IMesh* cube = createCubeMesh(v3f(1, 1, 1));
setMeshColor(cube, video::SColor(255, 255, 255, 255)); setMeshColor(cube, video::SColor(255, 255, 255, 255));
cube->getMeshBuffer(0)->getMaterial().setTexture(0, texture_top);
cube->getMeshBuffer(1)->getMaterial().setTexture(0, texture_top);
cube->getMeshBuffer(2)->getMaterial().setTexture(0, texture_right);
cube->getMeshBuffer(3)->getMaterial().setTexture(0, texture_right);
cube->getMeshBuffer(4)->getMaterial().setTexture(0, texture_left);
cube->getMeshBuffer(5)->getMaterial().setTexture(0, texture_left);
scene::IMeshSceneNode* cubenode = smgr->addMeshSceneNode(cube, NULL, -1, v3f(0,0,0), v3f(0,45,0), v3f(1,1,1), true); core::dimension2d<u32> dim(64,64);
cube->drop(); std::string rtt_texture_name = part_of_name + "_RTT";
// Set texture of cube v3f camera_position(0, 1.0, -1.5);
cubenode->getMaterial(0).setTexture(0, texture_top); camera_position.rotateXZBy(45);
cubenode->getMaterial(1).setTexture(0, texture_top); v3f camera_lookat(0, 0, 0);
cubenode->getMaterial(2).setTexture(0, texture_right); core::CMatrix4<f32> camera_projection_matrix;
cubenode->getMaterial(3).setTexture(0, texture_right);
cubenode->getMaterial(4).setTexture(0, texture_left);
cubenode->getMaterial(5).setTexture(0, texture_left);
cubenode->setMaterialFlag(video::EMF_LIGHTING, true);
cubenode->setMaterialFlag(video::EMF_ANTI_ALIASING, true);
cubenode->setMaterialFlag(video::EMF_BILINEAR_FILTER, true);
scene::ICameraSceneNode* camera = smgr->addCameraSceneNode(0,
v3f(0, 1.0, -1.5), v3f(0, 0, 0));
// Set orthogonal projection // Set orthogonal projection
core::CMatrix4<f32> pm; camera_projection_matrix.buildProjectionMatrixOrthoLH(
pm.buildProjectionMatrixOrthoLH(1.65, 1.65, 0, 100); 1.65, 1.65, 0, 100);
camera->setProjectionMatrix(pm, true);
/*scene::ILightSceneNode *light =*/ smgr->addLightSceneNode(0, video::SColorf ambient_light(0.2,0.2,0.2);
v3f(-50, 100, -75), video::SColorf(0.5,0.5,0.5), 1000); v3f light_position(10, 100, -50);
video::SColorf light_color(0.5,0.5,0.5);
f32 light_radius = 1000;
smgr->setAmbientLight(video::SColorf(0.2,0.2,0.2)); video::ITexture *rtt = generateTextureFromMesh(
cube, device, dim, rtt_texture_name,
// Render scene camera_position,
driver->beginScene(true, true, video::SColor(0,0,0,0)); camera_lookat,
smgr->drawAll(); camera_projection_matrix,
driver->endScene(); ambient_light,
light_position,
light_color,
light_radius);
// NOTE: The scene nodes should not be dropped, otherwise // Drop mesh
// smgr->drop() segfaults cube->drop();
/*cube->drop();
camera->drop();
light->drop();*/
// Drop scene manager
smgr->drop();
// Unset render target
driver->setRenderTarget(0, true, true, 0);
// Free textures of images // Free textures of images
driver->removeTexture(texture_top); driver->removeTexture(texture_top);
driver->removeTexture(texture_left); driver->removeTexture(texture_left);
driver->removeTexture(texture_right); driver->removeTexture(texture_right);
if(rtt == NULL)
{
errorstream<<"generate_image(): render to texture failed."
" Creating fallback image"<<std::endl;
baseimg = generate_image_from_scratch(
imagename_top, device, sourcecache);
return true;
}
// Create image of render target // Create image of render target
video::IImage *image = driver->createImage(rtt, v2s32(0,0), dim); video::IImage *image = driver->createImage(rtt, v2s32(0,0), dim);
assert(image); assert(image);
baseimg = driver->createImage(video::ECF_A8R8G8B8, dim); baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
if(image) if(image)
@ -1567,7 +1516,6 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
image->copyTo(baseimg); image->copyTo(baseimg);
image->drop(); image->drop();
} }
#endif
} }
else else
{ {
@ -1579,38 +1527,6 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
return true; return true;
} }
void make_progressbar(float value, video::IImage *image)
{
if(image == NULL)
return;
core::dimension2d<u32> size = image->getDimension();
u32 barheight = size.Height/16;
u32 barpad_x = size.Width/16;
u32 barpad_y = size.Height/16;
u32 barwidth = size.Width - barpad_x*2;
v2u32 barpos(barpad_x, size.Height - barheight - barpad_y);
u32 barvalue_i = (u32)(((float)barwidth * value) + 0.5);
video::SColor active(255,255,0,0);
video::SColor inactive(255,0,0,0);
for(u32 x0=0; x0<barwidth; x0++)
{
video::SColor *c;
if(x0 < barvalue_i)
c = &active;
else
c = &inactive;
u32 x = x0 + barpos.X;
for(u32 y=barpos.Y; y<barpos.Y+barheight; y++)
{
image->setPixel(x,y, *c);
}
}
}
void brighten(video::IImage *image) void brighten(video::IImage *image)
{ {
if(image == NULL) if(image == NULL)

@ -110,6 +110,8 @@ public:
{return AtlasPointer(0);} {return AtlasPointer(0);}
virtual video::ITexture* getTextureRaw(const std::string &name) virtual video::ITexture* getTextureRaw(const std::string &name)
{return NULL;} {return NULL;}
virtual IrrlichtDevice* getDevice()
{return NULL;}
virtual void updateAP(AtlasPointer &ap){}; virtual void updateAP(AtlasPointer &ap){};
}; };
@ -126,6 +128,8 @@ public:
{return AtlasPointer(0);} {return AtlasPointer(0);}
virtual video::ITexture* getTextureRaw(const std::string &name) virtual video::ITexture* getTextureRaw(const std::string &name)
{return NULL;} {return NULL;}
virtual IrrlichtDevice* getDevice()
{return NULL;}
virtual void updateAP(AtlasPointer &ap){}; virtual void updateAP(AtlasPointer &ap){};
virtual void processQueue()=0; virtual void processQueue()=0;

@ -1,238 +0,0 @@
/*
Minetest-c55
Copyright (C) 2011 celeron55, Perttu Ahola <celeron55@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "tooldef.h"
#include "irrlichttypes.h"
#include "log.h"
#include <sstream>
#include "utility.h"
#include <map>
ToolDiggingProperties::ToolDiggingProperties(float full_punch_interval_,
float a, float b, float c, float d, float e,
float f, float g, float h, float i, float j):
full_punch_interval(full_punch_interval_),
basetime(a),
dt_weight(b),
dt_crackiness(c),
dt_crumbliness(d),
dt_cuttability(e),
basedurability(f),
dd_weight(g),
dd_crackiness(h),
dd_crumbliness(i),
dd_cuttability(j)
{}
std::string ToolDefinition::dump()
{
std::ostringstream os(std::ios::binary);
os<<"[ToolDefinition::dump() not implemented due to lazyness]"
<<std::endl;
return os.str();
}
void ToolDefinition::serialize(std::ostream &os)
{
writeU8(os, 0); // version
os<<serializeString(imagename);
writeF1000(os, properties.basetime);
writeF1000(os, properties.dt_weight);
writeF1000(os, properties.dt_crackiness);
writeF1000(os, properties.dt_crumbliness);
writeF1000(os, properties.dt_cuttability);
writeF1000(os, properties.basedurability);
writeF1000(os, properties.dd_weight);
writeF1000(os, properties.dd_crackiness);
writeF1000(os, properties.dd_crumbliness);
writeF1000(os, properties.dd_cuttability);
writeF1000(os, properties.full_punch_interval);
}
void ToolDefinition::deSerialize(std::istream &is)
{
int version = readU8(is);
if(version != 0) throw SerializationError(
"unsupported ToolDefinition version");
imagename = deSerializeString(is);
properties.basetime = readF1000(is);
properties.dt_weight = readF1000(is);
properties.dt_crackiness = readF1000(is);
properties.dt_crumbliness = readF1000(is);
properties.dt_cuttability = readF1000(is);
properties.basedurability = readF1000(is);
properties.dd_weight = readF1000(is);
properties.dd_crackiness = readF1000(is);
properties.dd_crumbliness = readF1000(is);
properties.dd_cuttability = readF1000(is);
try{
properties.full_punch_interval = readF1000(is);
}catch(SerializationError &e){} // Temporary for 0.4.dev
}
class CToolDefManager: public IWritableToolDefManager
{
public:
virtual ~CToolDefManager()
{
clear();
}
virtual const ToolDefinition* getToolDefinition(const std::string &toolname_) const
{
// Convert name according to possible alias
std::string toolname = getAlias(toolname_);
// Get the definition
core::map<std::string, ToolDefinition*>::Node *n;
n = m_tool_definitions.find(toolname);
if(n == NULL)
return NULL;
return n->getValue();
}
virtual std::string getImagename(const std::string &toolname) const
{
const ToolDefinition *def = getToolDefinition(toolname);
if(def == NULL)
return "";
return def->imagename;
}
virtual ToolDiggingProperties getDiggingProperties(
const std::string &toolname) const
{
const ToolDefinition *def = getToolDefinition(toolname);
// If tool does not exist, just return an impossible
if(def == NULL){
// If tool does not exist, try empty name
const ToolDefinition *def = getToolDefinition("");
if(def == NULL) // If that doesn't exist either, return default
return ToolDiggingProperties();
return def->properties;
}
return def->properties;
}
virtual std::string getAlias(const std::string &name) const
{
std::map<std::string, std::string>::const_iterator i;
i = m_aliases.find(name);
if(i != m_aliases.end())
return i->second;
return name;
}
// IWritableToolDefManager
virtual bool registerTool(std::string toolname, const ToolDefinition &def)
{
infostream<<"registerTool: registering tool \""<<toolname<<"\""<<std::endl;
m_tool_definitions[toolname] = new ToolDefinition(def);
// Remove conflicting alias if it exists
bool alias_removed = (m_aliases.erase(toolname) != 0);
if(alias_removed)
infostream<<"tdef: erased alias "<<toolname
<<" because tool was defined"<<std::endl;
return true;
}
virtual void clear()
{
for(core::map<std::string, ToolDefinition*>::Iterator
i = m_tool_definitions.getIterator();
i.atEnd() == false; i++){
delete i.getNode()->getValue();
}
m_tool_definitions.clear();
m_aliases.clear();
}
virtual void setAlias(const std::string &name,
const std::string &convert_to)
{
if(getToolDefinition(name) != NULL){
infostream<<"tdef: not setting alias "<<name<<" -> "<<convert_to
<<": "<<name<<" is already defined"<<std::endl;
return;
}
infostream<<"tdef: setting alias "<<name<<" -> "<<convert_to
<<std::endl;
m_aliases[name] = convert_to;
}
virtual void serialize(std::ostream &os)
{
writeU8(os, 0); // version
u16 count = m_tool_definitions.size();
writeU16(os, count);
for(core::map<std::string, ToolDefinition*>::Iterator
i = m_tool_definitions.getIterator();
i.atEnd() == false; i++){
std::string name = i.getNode()->getKey();
ToolDefinition *def = i.getNode()->getValue();
// Serialize name
os<<serializeString(name);
// Serialize ToolDefinition and write wrapped in a string
std::ostringstream tmp_os(std::ios::binary);
def->serialize(tmp_os);
os<<serializeString(tmp_os.str());
}
writeU16(os, m_aliases.size());
for(std::map<std::string, std::string>::const_iterator
i = m_aliases.begin(); i != m_aliases.end(); i++)
{
os<<serializeString(i->first);
os<<serializeString(i->second);
}
}
virtual void deSerialize(std::istream &is)
{
// Clear everything
clear();
// Deserialize
int version = readU8(is);
if(version != 0) throw SerializationError(
"unsupported ToolDefManager version");
u16 count = readU16(is);
for(u16 i=0; i<count; i++){
// Deserialize name
std::string name = deSerializeString(is);
// Deserialize a string and grab a ToolDefinition from it
std::istringstream tmp_is(deSerializeString(is), std::ios::binary);
ToolDefinition def;
def.deSerialize(tmp_is);
// Register
registerTool(name, def);
}
u16 num_aliases = readU16(is);
if(!is.eof()){
for(u16 i=0; i<num_aliases; i++){
std::string name = deSerializeString(is);
std::string convert_to = deSerializeString(is);
m_aliases[name] = convert_to;
}
}
}
private:
// Key is name
core::map<std::string, ToolDefinition*> m_tool_definitions;
// Aliases
std::map<std::string, std::string> m_aliases;
};
IWritableToolDefManager* createToolDefManager()
{
return new CToolDefManager();
}

@ -1,103 +0,0 @@
/*
Minetest-c55
Copyright (C) 2011 celeron55, Perttu Ahola <celeron55@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef TOOLDEF_HEADER
#define TOOLDEF_HEADER
#include <string>
#include <iostream>
struct ToolDiggingProperties
{
// time = basetime + sum(feature here * feature in MaterialProperties)
float full_punch_interval;
float basetime;
float dt_weight;
float dt_crackiness;
float dt_crumbliness;
float dt_cuttability;
float basedurability;
float dd_weight;
float dd_crackiness;
float dd_crumbliness;
float dd_cuttability;
ToolDiggingProperties(float full_punch_interval_=2.0,
float a=0.75, float b=0, float c=0, float d=0, float e=0,
float f=50, float g=0, float h=0, float i=0, float j=0);
};
struct ToolDefinition
{
std::string imagename;
ToolDiggingProperties properties;
ToolDefinition(){}
ToolDefinition(const std::string &imagename_,
ToolDiggingProperties properties_):
imagename(imagename_),
properties(properties_)
{}
std::string dump();
void serialize(std::ostream &os);
void deSerialize(std::istream &is);
};
class IToolDefManager
{
public:
IToolDefManager(){}
virtual ~IToolDefManager(){}
virtual const ToolDefinition* getToolDefinition(const std::string &toolname) const=0;
virtual std::string getImagename(const std::string &toolname) const =0;
virtual ToolDiggingProperties getDiggingProperties(
const std::string &toolname) const =0;
virtual std::string getAlias(const std::string &name) const =0;
virtual void serialize(std::ostream &os)=0;
};
class IWritableToolDefManager : public IToolDefManager
{
public:
IWritableToolDefManager(){}
virtual ~IWritableToolDefManager(){}
virtual const ToolDefinition* getToolDefinition(const std::string &toolname) const=0;
virtual std::string getImagename(const std::string &toolname) const =0;
virtual ToolDiggingProperties getDiggingProperties(
const std::string &toolname) const =0;
virtual std::string getAlias(const std::string &name) const =0;
virtual bool registerTool(std::string toolname, const ToolDefinition &def)=0;
virtual void clear()=0;
// Set an alias so that entries named <name> will load as <convert_to>.
// Alias is not set if <name> has already been defined.
// Alias will be removed if <name> is defined at a later point of time.
virtual void setAlias(const std::string &name,
const std::string &convert_to)=0;
virtual void serialize(std::ostream &os)=0;
virtual void deSerialize(std::istream &is)=0;
};
IWritableToolDefManager* createToolDefManager();
#endif

@ -26,6 +26,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "sha1.h" #include "sha1.h"
#include "base64.h" #include "base64.h"
#include "log.h" #include "log.h"
#include <iomanip>
TimeTaker::TimeTaker(const char *name, u32 *result) TimeTaker::TimeTaker(const char *name, u32 *result)
{ {
@ -234,6 +235,100 @@ bool isBlockInSight(v3s16 blockpos_b, v3f camera_pos, v3f camera_dir,
return true; return true;
} }
// Creates a string encoded in JSON format (almost equivalent to a C string literal)
std::string serializeJsonString(const std::string &plain)
{
std::ostringstream os(std::ios::binary);
os<<"\"";
for(size_t i = 0; i < plain.size(); i++)
{
char c = plain[i];
switch(c)
{
case '"': os<<"\\\""; break;
case '\\': os<<"\\\\"; break;
case '/': os<<"\\/"; break;
case '\b': os<<"\\b"; break;
case '\f': os<<"\\f"; break;
case '\n': os<<"\\n"; break;
case '\r': os<<"\\r"; break;
case '\t': os<<"\\t"; break;
default:
{
if(c >= 32 && c <= 126)
{
os<<c;
}
else
{
u32 cnum = (u32) (u8) c;
os<<"\\u"<<std::hex<<std::setw(4)<<std::setfill('0')<<cnum;
}
break;
}
}
}
os<<"\"";
return os.str();
}
// Reads a string encoded in JSON format
std::string deSerializeJsonString(std::istream &is)
{
std::ostringstream os(std::ios::binary);
char c, c2;
// Parse initial doublequote
is >> c;
if(c != '"')
throw SerializationError("JSON string must start with doublequote");
// Parse characters
for(;;)
{
c = is.get();
if(is.eof())
throw SerializationError("JSON string ended prematurely");
if(c == '"')
{
return os.str();
}
else if(c == '\\')
{
c2 = is.get();
if(is.eof())
throw SerializationError("JSON string ended prematurely");
switch(c2)
{
default: os<<c2; break;
case 'b': os<<'\b'; break;
case 'f': os<<'\f'; break;
case 'n': os<<'\n'; break;
case 'r': os<<'\r'; break;
case 't': os<<'\t'; break;
case 'u':
{
char hexdigits[4+1];
is.read(hexdigits, 4);
if(is.eof())
throw SerializationError("JSON string ended prematurely");
hexdigits[4] = 0;
std::istringstream tmp_is(hexdigits, std::ios::binary);
int hexnumber;
tmp_is >> std::hex >> hexnumber;
os<<((char)hexnumber);
break;
}
}
}
else
{
os<<c;
}
}
return os.str();
}
// Get an sha-1 hash of the player's name combined with // Get an sha-1 hash of the player's name combined with
// the password entered. That's what the server uses as // the password entered. That's what the server uses as
// their password. (Exception : if the password field is // their password. (Exception : if the password field is

@ -1694,6 +1694,12 @@ inline std::string deSerializeLongString(std::istream &is)
return s; return s;
} }
// Creates a string encoded in JSON format (almost equivalent to a C string literal)
std::string serializeJsonString(const std::string &plain);
// Reads a string encoded in JSON format
std::string deSerializeJsonString(std::istream &is);
// //
inline u32 time_to_daynight_ratio(u32 time_of_day) inline u32 time_to_daynight_ratio(u32 time_of_day)