summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsapier <sapier at gmx dot net>2012-02-04 12:41:25 +0100
committersapier <sapier at gmx dot net>2012-02-04 12:41:25 +0100
commit77df09540c4d7eadef760779e123af88a48aafaa (patch)
treefebf1009328d30c31a14a1a1ca1600e99b4c3e6b
parent3454e6779337d8523ae76c7fa16eb8c565aa2381 (diff)
parenta1eb2836c0764829ebad1462432bb3c5f32750df (diff)
downloadminetest-77df09540c4d7eadef760779e123af88a48aafaa.tar.xz
Merge remote branch 'upstream/master' into sapier_experimental
Conflicts: src/scriptapi.cpp
-rw-r--r--CMakeLists.txt2
-rw-r--r--data/builtin.lua829
-rw-r--r--data/clienttextures/unknown_item.pngbin0 -> 710 bytes
-rw-r--r--data/mods/bucket/init.lua139
-rw-r--r--data/mods/default/init.lua1328
-rw-r--r--data/mods/default/textures/default_mineral_coal.png (renamed from data/mods/legacy/textures/mineral_coal.png)bin952 -> 952 bytes
-rw-r--r--data/mods/default/textures/default_mineral_iron.png (renamed from data/mods/legacy/textures/mineral_iron.png)bin1614 -> 1614 bytes
-rw-r--r--data/mods/experimental/init.lua72
-rw-r--r--data/mods/give_initial_stuff/init.lua10
-rw-r--r--data/mods/legacy/init.lua173
-rw-r--r--src/CMakeLists.txt4
-rw-r--r--src/camera.cpp267
-rw-r--r--src/camera.h63
-rw-r--r--src/client.cpp308
-rw-r--r--src/client.h31
-rw-r--r--src/clientserver.h15
-rw-r--r--src/connection.cpp6
-rw-r--r--src/content_cao.cpp107
-rw-r--r--src/content_mapblock.cpp288
-rw-r--r--src/content_mapnode.cpp833
-rw-r--r--src/content_mapnode.h6
-rw-r--r--src/content_nodemeta.cpp296
-rw-r--r--src/content_sao.cpp154
-rw-r--r--src/content_sao.h8
-rw-r--r--src/craftdef.cpp844
-rw-r--r--src/craftdef.h349
-rw-r--r--src/craftitemdef.cpp214
-rw-r--r--src/craftitemdef.h79
-rw-r--r--src/defaultsettings.cpp18
-rw-r--r--src/environment.cpp13
-rw-r--r--src/environment.h1
-rw-r--r--src/game.cpp507
-rw-r--r--src/gamedef.h11
-rw-r--r--src/guiInventoryMenu.cpp640
-rw-r--r--src/guiInventoryMenu.h43
-rw-r--r--src/inventory.cpp1003
-rw-r--r--src/inventory.h521
-rw-r--r--src/inventorymanager.cpp627
-rw-r--r--src/inventorymanager.h139
-rw-r--r--src/irrlichttypes.h2
-rw-r--r--src/itemdef.cpp502
-rw-r--r--src/itemdef.h147
-rw-r--r--src/light.cpp54
-rw-r--r--src/light.h17
-rw-r--r--src/main.cpp31
-rw-r--r--src/map.cpp21
-rw-r--r--src/map.h2
-rw-r--r--src/mapblock.cpp536
-rw-r--r--src/mapblock.h34
-rw-r--r--src/mapblock_mesh.cpp159
-rw-r--r--src/mapblock_mesh.h8
-rw-r--r--src/mapgen.cpp300
-rw-r--r--src/mapnode.cpp404
-rw-r--r--src/mapnode.h110
-rw-r--r--src/materials.cpp66
-rw-r--r--src/materials.h32
-rw-r--r--src/mesh.cpp117
-rw-r--r--src/mesh.h22
-rw-r--r--src/mineral.cpp51
-rw-r--r--src/mineral.h56
-rw-r--r--src/nameidmapping.h3
-rw-r--r--src/nodedef.cpp232
-rw-r--r--src/nodedef.h82
-rw-r--r--src/player.cpp33
-rw-r--r--src/player.h16
-rw-r--r--src/profiler.h19
-rw-r--r--src/scriptapi.cpp2915
-rw-r--r--src/scriptapi.h36
-rw-r--r--src/serialization.h3
-rw-r--r--src/server.cpp1081
-rw-r--r--src/server.h27
-rw-r--r--src/servermain.cpp5
-rw-r--r--src/serverobject.cpp29
-rw-r--r--src/serverobject.h27
-rw-r--r--src/serverremoteplayer.cpp156
-rw-r--r--src/serverremoteplayer.h20
-rw-r--r--src/test.cpp201
-rw-r--r--src/tile.cpp201
-rw-r--r--src/tile.h4
-rw-r--r--src/tooldef.cpp238
-rw-r--r--src/tooldef.h103
-rw-r--r--src/utility.cpp95
-rw-r--r--src/utility.h50
83 files changed, 9587 insertions, 8608 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 68fffb012..ef9016526 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -10,7 +10,7 @@ project(minetest)
# Also remember to set PROTOCOL_VERSION in clientserver.h when releasing
set(VERSION_MAJOR 0)
set(VERSION_MINOR 4)
-set(VERSION_PATCH dev-20120106-1)
+set(VERSION_PATCH dev-20120122-1)
set(VERSION_STRING "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}")
MESSAGE(STATUS "*** Will build version ${VERSION_STRING} ***")
diff --git a/data/builtin.lua b/data/builtin.lua
index 1046e934e..3a38b60ad 100644
--- a/data/builtin.lua
+++ b/data/builtin.lua
@@ -80,15 +80,305 @@ function dump(o, dumped)
end
--
--- Built-in node definitions. Also defined in C.
+-- Item definition helpers
--
-minetest.register_nodedef_defaults({
+function minetest.inventorycube(img1, img2, img3)
+ img2 = img2 or img1
+ img3 = img3 or img1
+ return "[inventorycube"
+ .. "{" .. img1:gsub("%^", "&")
+ .. "{" .. img2:gsub("%^", "&")
+ .. "{" .. img3:gsub("%^", "&")
+end
+
+function minetest.pos_to_string(pos)
+ return "(" .. pos.x .. "," .. pos.y .. "," .. pos.z .. ")"
+end
+
+function minetest.get_pointed_thing_position(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.dir_to_facedir(dir)
+ if math.abs(dir.x) > math.abs(dir.z) then
+ if dir.x < 0 then
+ return 3
+ else
+ return 1
+ end
+ else
+ if dir.z < 0 then
+ return 2
+ else
+ return 0
+ end
+ end
+end
+
+function minetest.dir_to_wallmounted(dir)
+ if math.abs(dir.y) > math.max(math.abs(dir.x), math.abs(dir.z)) then
+ if dir.y < 0 then
+ return 1
+ else
+ return 0
+ end
+ elseif math.abs(dir.x) > math.abs(dir.z) then
+ if dir.x < 0 then
+ return 3
+ else
+ return 2
+ end
+ else
+ if dir.z < 0 then
+ return 5
+ else
+ return 4
+ end
+ end
+end
+
+function minetest.get_node_drops(nodename, toolname)
+ local drop = ItemStack({name=nodename}):get_definition().drop
+ if drop == nil then
+ -- default drop
+ return {ItemStack({name=nodename})}
+ elseif type(drop) == "string" then
+ -- itemstring drop
+ return {ItemStack(drop)}
+ elseif drop.items == nil then
+ -- drop = {} to disable default drop
+ return {}
+ end
+
+ -- Extended drop table
+ local got_items = {}
+ local got_count = 0
+ local _, item, tool
+ for _, item in ipairs(drop.items) do
+ local good_rarity = true
+ local good_tool = true
+ if item.rarity ~= nil then
+ good_rarity = item.rarity < 1 or math.random(item.rarity) == 1
+ end
+ if item.tools ~= nil then
+ good_tool = false
+ for _, tool in ipairs(item.tools) do
+ if tool:sub(1, 1) == '~' then
+ good_tool = toolname:find(tool:sub(2)) ~= nil
+ else
+ good_tool = toolname == tool
+ end
+ if good_tool then
+ break
+ end
+ end
+ end
+ if good_rarity and good_tool then
+ got_count = got_count + 1
+ for _, add_item in ipairs(item.items) do
+ got_items[#got_items+1] = add_item
+ end
+ if drop.max_items ~= nil and got_count == drop.max_items then
+ break
+ end
+ end
+ end
+ return got_items
+end
+
+function minetest.item_place_node(itemstack, placer, pointed_thing)
+ local item = itemstack:peek_item()
+ local def = itemstack:get_definition()
+ if def.type == "node" and pointed_thing.type == "node" then
+ local pos = pointed_thing.above
+ local oldnode = minetest.env:get_node(pos)
+ local olddef = ItemStack({name=oldnode.name}):get_definition()
+
+ if not olddef.buildable_to then
+ minetest.log("info", placer:get_player_name() .. " tried to place"
+ .. " node in invalid position " .. minetest.pos_to_string(pos)
+ .. ", replacing " .. oldnode.name)
+ return
+ end
+
+ minetest.log("action", placer:get_player_name() .. " places node "
+ .. def.name .. " at " .. minetest.pos_to_string(pos))
+
+ local newnode = {name = def.name, param1 = 0, param2 = 0}
+
+ -- Calculate direction for wall mounted stuff like torches and signs
+ if def.paramtype2 == 'wallmounted' then
+ local under = pointed_thing.under
+ local above = pointed_thing.above
+ local dir = {x = under.x - above.x, y = under.y - above.y, z = under.z - above.z}
+ newnode.param2 = minetest.dir_to_wallmounted(dir)
+ -- Calculate the direction for furnaces and chests and stuff
+ elseif def.paramtype2 == 'facedir' then
+ local playerpos = placer:getpos()
+ local dir = {x = pos.x - playerpos.x, y = pos.y - playerpos.y, z = pos.z - playerpos.z}
+ newnode.param2 = minetest.dir_to_facedir(dir)
+ minetest.log("action", "facedir: " .. newnode.param2)
+ end
+
+ -- Add node and update
+ minetest.env:add_node(pos, newnode)
+
+ -- Set metadata owner
+ if def.metadata_name ~= "" then
+ minetest.env:get_meta(pos):set_owner(placer:get_player_name())
+ end
+
+ -- Run script hook
+ local _, callback
+ for _, callback in ipairs(minetest.registered_on_placenodes) do
+ callback(pos, newnode, placer)
+ end
+
+ itemstack:take_item()
+ end
+ return itemstack
+end
+
+function minetest.item_place_object(itemstack, placer, pointed_thing)
+ local pos = minetest.get_pointed_thing_position(pointed_thing, true)
+ if pos ~= nil then
+ local item = itemstack:take_item()
+ minetest.env:add_item(pos, item)
+ end
+ return itemstack
+end
+
+function minetest.item_place(itemstack, placer, pointed_thing)
+ if itemstack:get_definition().type == "node" then
+ return minetest.item_place_node(itemstack, placer, pointed_thing)
+ else
+ return minetest.item_place_object(itemstack, placer, pointed_thing)
+ end
+end
+
+function minetest.item_drop(itemstack, dropper, pos)
+ minetest.env:add_item(pos, itemstack)
+ return ""
+end
+
+function minetest.item_eat(hp_change, replace_with_item)
+ return function(itemstack, user, pointed_thing) -- closure
+ if itemstack:take_item() ~= nil then
+ user:set_hp(user:get_hp() + hp_change)
+ itemstack:add_item(replace_with_item) -- note: replace_with_item is optional
+ end
+ return itemstack
+ end
+end
+
+function minetest.node_punch(pos, node, puncher)
+ -- Run script hook
+ local _, callback
+ for _, callback in ipairs(minetest.registered_on_punchnodes) do
+ callback(pos, node, puncher)
+ end
+
+end
+
+function minetest.node_dig(pos, node, digger)
+ minetest.debug("node_dig")
+
+ local def = ItemStack({name=node.name}):get_definition()
+ if not def.diggable then
+ minetest.debug("not diggable")
+ minetest.log("info", digger:get_player_name() .. " tried to dig "
+ .. node.name .. " which is not diggable "
+ .. minetest.pos_to_string(pos))
+ return
+ end
+
+ local meta = minetest.env:get_meta(pos)
+ if meta ~= nil and not meta:get_allow_removal() then
+ minetest.debug("dig prevented by metadata")
+ minetest.log("info", digger:get_player_name() .. " tried to dig "
+ .. node.name .. ", but removal is disabled by metadata "
+ .. minetest.pos_to_string(pos))
+ return
+ end
+
+ minetest.log('action', digger:get_player_name() .. " digs "
+ .. node.name .. " at " .. minetest.pos_to_string(pos))
+
+ if not minetest.setting_getbool("creative_mode") then
+ local wielded = digger:get_wielded_item()
+ local drops = minetest.get_node_drops(node.name, wielded:get_name())
+
+ -- Wear out tool
+ mp = def.material
+ tp = wielded:get_tool_digging_properties()
+ dp = minetest.get_digging_properties(mp, tp)
+ wielded:add_wear(dp.wear)
+ digger:set_wielded_item(wielded)
+
+ -- Add dropped items
+ local _, dropped_item
+ for _, dropped_item in ipairs(drops) do
+ digger:get_inventory():add_item("main", dropped_item)
+ end
+ end
+
+ -- Remove node and update
+ minetest.env:remove_node(pos)
+
+ -- Run script hook
+ local _, callback
+ for _, callback in ipairs(minetest.registered_on_dignodes) do
+ callback(pos, node, digger)
+ end
+end
+
+--
+-- Item definition defaults
+--
+
+minetest.nodedef_default = {
+ -- Item properties
+ type="node",
-- name intentionally not defined here
+ description = "",
+ inventory_image = "",
+ wield_image = "",
+ wield_scale = {x=1,y=1,z=1},
+ stack_max = 99,
+ usable = false,
+ liquids_pointable = false,
+ tool_digging_properties = nil,
+
+ -- Interaction callbacks
+ on_place = minetest.item_place,
+ on_drop = minetest.item_drop,
+ on_use = nil,
+
+ on_punch = minetest.node_punch,
+ on_dig = minetest.node_dig,
+
+ -- Node properties
drawtype = "normal",
visual_scale = 1.0,
- tile_images = {"unknown_block.png"},
- inventory_image = "unknown_block.png",
+ tile_images = {""},
special_materials = {
{image="", backface_culling=true},
{image="", backface_culling=true},
@@ -96,6 +386,7 @@ minetest.register_nodedef_defaults({
alpha = 255,
post_effect_color = {a=0, r=0, g=0, b=0},
paramtype = "none",
+ paramtype2 = "none",
is_ground_content = false,
sunlight_propagates = false,
walkable = true,
@@ -103,11 +394,6 @@ minetest.register_nodedef_defaults({
diggable = true,
climbable = false,
buildable_to = false,
- wall_mounted = false,
- often_contains_mineral = false,
- dug_item = "",
- extra_dug_item = "",
- extra_dug_item_rarity = 2,
metadata_name = "",
liquidtype = "none",
liquid_alternative_flowing = "",
@@ -124,219 +410,354 @@ minetest.register_nodedef_defaults({
cuttability = 0,
flammability = 0,
},
- cookresult_item = "", -- Cannot be cooked
- furnace_cooktime = 3.0,
- furnace_burntime = -1, -- Cannot be used as fuel
-})
+ legacy_facedir_simple = false,
+ legacy_wallmounted = false,
+}
-minetest.register_node("air", {
- drawtype = "airlike",
- paramtype = "light",
- sunlight_propagates = true,
- walkable = false,
- pointable = false,
- diggable = false,
- buildable_to = true,
- air_equivalent = true,
-})
+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,
+}
-minetest.register_node("ignore", {
- drawtype = "airlike",
- paramtype = "none",
- sunlight_propagates = false,
- walkable = false,
- pointable = false,
- diggable = false,
- buildable_to = true, -- A way to remove accidentally placed ignores
- air_equivalent = true,
-})
+--
+-- 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
--
--- stackstring manipulation functions
--- example stackstring: 'craft "apple" 4'
--- example item: {type="craft", name="apple"}
--- example item: {type="tool", name="SteelPick", wear="23272"}
+-- Item / entity / ABM registration functions
--
-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}
+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
- 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}
+ 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 stackstring_put_item(stackstring, item)
- if item == nil then
- return stackstring, false
+function minetest.register_item(name, itemdef)
+ -- Check name
+ if name == nil then
+ error("Unable to register item: Name is nil")
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
+ name = check_modname_prefix(tostring(name))
+ if forbidden_item_names[name] then
+ error("Unable to register item: Name is forbidden: " .. name)
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
+ 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
- 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
+
+ -- Flowing liquid uses param2
+ if itemdef.type == "node" and itemdef.liquidtype == "flowing" then
+ itemdef.paramtype2 = "flowingliquid"
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
---
+ -- BEGIN 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
+ -- END Legacy stuff
-minetest.inventorycube = function(img1, img2, img3)
- img2 = img2 or img1
- img3 = img3 or img1
- return "[inventorycube"
- .. "{" .. img1:gsub("%^", "&")
- .. "{" .. img2:gsub("%^", "&")
- .. "{" .. img3:gsub("%^", "&")
+ -- 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
---
--- CraftItem helpers
---
+function minetest.register_node(name, nodedef)
+ nodedef.type = "node"
+ minetest.register_item(name, nodedef)
+end
+
+function minetest.register_craftitem(name, craftitemdef)
+ craftitemdef.type = "craft"
-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
+ -- BEGIN Legacy stuff
+ if craftitemdef.inventory_image == nil and craftitemdef.image ~= nil then
+ craftitemdef.inventory_image = craftitemdef.image
end
+ -- END Legacy stuff
+
+ minetest.register_item(name, craftitemdef)
+end
+
+function minetest.register_tool(name, tooldef)
+ tooldef.type = "tool"
+ tooldef.stack_max = 1
+
+ -- BEGIN 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
+ -- END Legacy stuff
+
+ 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_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",
+ paramtype = "light",
+ sunlight_propagates = true,
+ walkable = false,
+ pointable = false,
+ diggable = false,
+ buildable_to = true,
+ air_equivalent = true,
+})
+
+minetest.register_node(":ignore", {
+ description = "Ignore (you hacker you!)",
+ inventory_image = "unknown_block.png",
+ wield_image = "unknown_block.png",
+ drawtype = "airlike",
+ paramtype = "none",
+ sunlight_propagates = false,
+ walkable = false,
+ pointable = false,
+ diggable = false,
+ buildable_to = true, -- A way to remove accidentally placed ignores
+ air_equivalent = true,
+})
+
--
-- Default material types
--
@@ -422,7 +843,7 @@ end
-- Callback registration
--
-function make_registration()
+local function make_registration()
local t = {}
local registerfunc = function(func) table.insert(t, func) end
return t, registerfunc
@@ -438,4 +859,10 @@ minetest.registered_on_newplayers, minetest.register_on_newplayer = make_registr
minetest.registered_on_dieplayers, minetest.register_on_dieplayer = make_registration()
minetest.registered_on_respawnplayers, minetest.register_on_respawnplayer = make_registration()
+--
+-- Set random seed
+--
+
+math.randomseed(os.time())
+
-- END
diff --git a/data/clienttextures/unknown_item.png b/data/clienttextures/unknown_item.png
new file mode 100644
index 000000000..35cabf0ad
--- /dev/null
+++ b/data/clienttextures/unknown_item.png
Binary files differ
diff --git a/data/mods/bucket/init.lua b/data/mods/bucket/init.lua
index 639a614d4..8ed9da522 100644
--- a/data/mods/bucket/init.lua
+++ b/data/mods/bucket/init.lua
@@ -1,80 +1,95 @@
-- bucket (Minetest 0.4 mod)
-- A bucket, which can pick up water and lava
-minetest.alias_craftitem("bucket", "bucket:bucket_empty")
-minetest.alias_craftitem("bucket_water", "bucket:bucket_water")
-minetest.alias_craftitem("bucket_lava", "bucket:bucket_lava")
+minetest.register_alias("bucket", "bucket:bucket_empty")
+minetest.register_alias("bucket_water", "bucket:bucket_water")
+minetest.register_alias("bucket_lava", "bucket:bucket_lava")
minetest.register_craft({
- output = 'craft "bucket:bucket_empty" 1',
+ output = 'bucket:bucket_empty 1',
recipe = {
- {'craft "steel_ingot"', '', 'craft "steel_ingot"'},
- {'', 'craft "steel_ingot"', ''},
+ {'default:steel_ingot', '', 'default:steel_ingot'},
+ {'', 'default:steel_ingot', ''},
}
})
-minetest.register_craftitem("bucket:bucket_empty", {
- image = "bucket.png",
- stack_max = 1,
- liquids_pointable = true,
- on_place_on_ground = minetest.craftitem_place_item,
- 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
- minetest.env:add_node(pointed_thing.under, {name="air"})
- player:add_to_inventory_later('craft "bucket:bucket_water" 1')
- return true
- elseif n.name == "default:lava_source" then
- minetest.env:add_node(pointed_thing.under, {name="air"})
- player:add_to_inventory_later('craft "bucket:bucket_lava" 1')
- return true
+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
- return false
- end,
-})
+ })
+ end
+end
-minetest.register_craftitem("bucket:bucket_water", {
- image = "bucket_water.png",
+minetest.register_craftitem("bucket:bucket_empty", {
+ inventory_image = "bucket.png",
stack_max = 1,
liquids_pointable = true,
- on_place_on_ground = minetest.craftitem_place_item,
- 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
+ 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 source
+ n = minetest.env:get_node(pointed_thing.under)
+ liquiddef = bucket.liquids[n.name]
+ if liquiddef ~= nil and liquiddef.source == n.name and liquiddef.itemname ~= nil then
+ minetest.env:add_node(pointed_thing.under, {name="air"})
+ return {name=liquiddef.itemname}
end
- return false
end,
})
-minetest.register_craftitem("bucket:bucket_lava", {
- image = "bucket_lava.png",
- stack_max = 1,
- liquids_pointable = true,
- on_place_on_ground = minetest.craftitem_place_item,
- 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:lava_source" then
- -- unchanged
- elseif n.name == "default:water_source" or n.name == "default:water_flowing" or n.name == "default:lava_flowing" then
- 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,
+bucket.register_liquid(
+ "default:water_source",
+ "default:water_flowing",
+ "bucket:bucket_water",
+ "bucket_water.png"
+)
+
+bucket.register_liquid(
+ "default:lava_source",
+ "default:lava_flowing",
+ "bucket:bucket_lava",
+ "bucket_lava.png"
+)
+
+minetest.register_craft({
+ type = "fuel",
+ recipe = "default:bucket_lava",
+ burntime = 60,
})
diff --git a/data/mods/default/init.lua b/data/mods/default/init.lua
index aa03eabe8..f0e6b6dc2 100644
--- a/data/mods/default/init.lua
+++ b/data/mods/default/init.lua
@@ -77,24 +77,25 @@
-- eg. 'tool "default:pick_wood" 21323'
-- eg. 'craft "default:apple" 2'
--
--- item: A single item in Lua table format.
--- eg. {type="node", name="default:dirt"}
+-- item: A stack of items in Lua table format.
+-- eg. {name="default:dirt", count=1, wear=0, metadata=""}
-- ^ a single dirt node
--- eg. {type="tool", name="default:pick_wood", wear=21323}
+-- eg. {name="default:pick_wood", count=1, wear=21323, metadata=""}
-- ^ a wooden pick about 1/3 weared out
--- eg. {type="craft", name="default:apple"}
+-- eg. {name="default:apple", count=1, wear=0, metadata=""}
-- ^ an apple.
--
+-- Any time an item must be passed to a function, it can be an
+-- ItemStack (see below), an itemstring or a table in the above format.
+--
-- Global functions:
-- minetest.register_entity(name, prototype table)
--- minetest.register_tool(name, tool definition)
+-- minetest.register_abm(abm definition)
-- minetest.register_node(name, node definition)
--- minetest.register_craftitem(name, craftitem definition)
+-- minetest.register_tool(name, item definition)
+-- minetest.register_craftitem(name, item definition)
+-- minetest.register_alias(name, convert_to)
-- minetest.register_craft(recipe)
--- minetest.register_abm(abm definition)
--- minetest.alias_node(name, convert_to)
--- minetest.alias_tool(name, convert_to)
--- minetest.alias_craftitem(name, convert_to)
-- minetest.register_globalstep(func(dtime))
-- minetest.register_on_placenode(func(pos, newnode, placer))
-- minetest.register_on_dignode(func(pos, oldnode, digger))
@@ -113,13 +114,16 @@
-- minetest.chat_send_player(name, text)
-- minetest.get_player_privs(name) -> set of privs
-- minetest.get_inventory(location) -> InvRef
--- minetest.get_modpath(modname) -> eg. "/home/user/.minetest/usermods/modname"
-- ^ location = eg. {type="player", name="celeron55"}
-- {type="node", pos={x=, y=, z=}}
+-- minetest.get_current_modname() -> string
+-- minetest.get_modpath(modname) -> eg. "/home/user/.minetest/usermods/modname"
--
--- stackstring_take_item(stackstring) -> stackstring, item
--- stackstring_put_item(stackstring, item) -> stackstring, success
--- stackstring_put_stackstring(stackstring, stackstring) -> stackstring, success
+-- minetest.debug(line)
+-- ^ Goes to dstream
+-- minetest.log(line)
+-- minetest.log(loglevel, line)
+-- ^ loglevel one of "error", "action", "info", "verbose"
--
-- minetest.digprop_constanttime(time)
-- minetest.digprop_stonelike(toughness)
@@ -133,10 +137,14 @@
-- minetest.env - environment reference
--
-- Global tables:
+-- minetest.registered_items
+-- ^ List of registered items, indexed by name
-- minetest.registered_nodes
-- ^ List of registered node definitions, indexed by name
-- minetest.registered_craftitems
-- ^ List of registered craft item definitions, indexed by name
+-- minetest.registered_tools
+-- ^ List of registered tool definitions, indexed by name
-- minetest.registered_entities
-- ^ List of registered entity prototypes, indexed by name
-- minetest.object_refs
@@ -161,6 +169,8 @@
-- - get_meta(pos) -- Get a NodeMetaRef at that position
-- - get_player_by_name(name) -- Get an ObjectRef to a player
-- - get_objects_inside_radius(pos, radius)
+-- - set_timeofday(val): val: 0...1; 0 = midnight, 0.5 = midday
+-- - get_timeofday()
--
-- NodeMetaRef (this stuff is subject to change in a future version)
-- - get_type()
@@ -168,11 +178,10 @@
-- - set_text(text) -- eg. set the text of a sign
-- - get_text()
-- - get_owner()
+-- - set_owner(string)
-- Generic node metadata specific:
-- - set_infotext(infotext)
-- - get_inventory() -> InvRef
--- - inventory_set_list(name, {item1, item2, ...})
--- - inventory_get_list(name)
-- - set_inventory_draw_spec(string)
-- - set_allow_text_input(bool)
-- - set_allow_removal(bool)
@@ -194,12 +203,13 @@
-- ^ puncher = an another ObjectRef,
-- ^ time_from_last_punch = time since last punch action of the puncher
-- - right_click(clicker); clicker = an another ObjectRef
--- - get_wield_digging_properties() -> digging property table
--- - damage_wielded_item(num) (item damage/wear range is 0-65535)
--- - add_to_inventory(itemstring): add an item to object inventory (actually only works for the player as of now)
--- - add_to_inventory_later(itemstring): like above, but after callback returns (only allowed for craftitem callbacks)
-- - get_hp(): returns number of hitpoints (2 * number of hearts)
-- - set_hp(hp): set number of hitpoints (2 * number of hearts)
+-- - get_inventory() -> InvRef
+-- - get_wield_list(): returns the name of the inventory list the wielded item is in
+-- - get_wield_index(): returns the index of the wielded item
+-- - get_wielded_item() -> ItemStack
+-- - set_wielded_item(item): replaces the wielded item, returns true if successful
-- LuaEntitySAO-only: (no-op for other objects)
-- - setvelocity({x=num, y=num, z=num})
-- - getvelocity() -> {x=num, y=num, z=num}
@@ -216,9 +226,6 @@
-- - get_luaentity()
-- Player-only: (no-op for other objects)
-- - get_player_name(): will return nil if is not a player
--- - get_inventory() -> InvRef
--- - inventory_set_list(name, {item1, item2, ...})
--- - inventory_get_list(name) -> {item1, item2, ...}
-- - get_look_dir(): get camera direction as a unit vector
-- - get_look_pitch(): pitch in radians
-- - get_look_yaw(): yaw in radians (wraps around pretty randomly as of now)
@@ -230,14 +237,41 @@
-- - set_stack(listname, i, stack): copy stack to index i in list
-- - get_list(listname): return full list
-- - set_list(listname, list): set full list (size will not change)
--- - autoinsert_stack(listname, stack): insert stack somewhere in list
--- - autoinsert_stackstring(listname, stackstring)
+-- - add_item(listname, stack): add item somewhere in list, returns leftover ItemStack
+-- - room_for_item(listname, stack): returns true if the stack of items
+-- can be fully added to the list
+-- - contains_item(listname, stack): returns true if the stack of items
+-- can be fully taken from the list
+-- remove_item(listname, stack): take as many items as specified from the list,
+-- returns the items that were actually removed (as an ItemStack)
--
-- ItemStack methods:
--- - peek_item(): return item from stack without removing it
--- - take_item(): remove item from stack and return it
--- - put_item(item): put item in stack; return false if not possible
--- - put_stackstring(stackstring): return false if not possible
+-- - is_empty(): return true if stack is empty
+-- - get_name(): returns item name (e.g. "default:stone")
+-- - get_count(): returns number of items on the stack
+-- - get_wear(): returns tool wear (0-65535), 0 for non-tools
+-- - get_metadata(): returns metadata (a string attached to an item stack)
+-- - clear(): removes all items from the stack, making it empty
+-- - replace(item): replace the contents of this stack (item can also
+-- be an itemstring or table)
+-- - to_string(): returns the stack in itemstring form
+-- - to_table(): returns the stack in Lua table form
+-- - get_stack_max(): returns the maximum size of the stack (depends on the item)
+-- - get_free_space(): returns get_stack_max() - get_count()
+-- - is_known(): returns true if the item name refers to a defined item type
+-- - get_definition(): returns the item definition table
+-- - get_tool_digging_properties(): returns the digging properties of the item,
+-- ^ or those of the hand if none are defined for this item type
+-- - add_wear(amount): increases wear by amount if the item is a tool
+-- - add_item(item): put some item or stack onto this stack,
+-- ^ returns leftover ItemStack
+-- - item_fits(item): returns true if item or stack can be fully added to this one
+-- - take_item(n): take (and remove) up to n items from this stack
+-- ^ returns taken ItemStack
+-- ^ if n is omitted, n=1 is used
+-- - peek_item(n): copy (don't remove) up to n items from this stack
+-- ^ returns copied ItemStack
+-- ^ if n is omitted, n=1 is used
--
-- Registered entities:
-- - Functions receive a "luaentity" as self:
@@ -271,29 +305,38 @@
-- myvariable = whatever,
-- }
--
--- Tool definition:
+-- Item definition options (register_node, register_craftitem, register_tool)
-- {
--- image = "default_tool_steelaxe.png",
--- full_punch_interval = 1.0,
--- basetime = 1.0,
--- dt_weight = 0.5,
--- dt_crackiness = -0.2,
--- dt_crumbliness = 1,
--- dt_cuttability = -0.5,
--- basedurability = 330,
--- dd_weight = 0,
--- dd_crackiness = 0,
--- dd_crumbliness = 0,
--- dd_cuttability = 0,
+-- description = "Steel Axe",
+-- inventory_image = "default_tool_steelaxe.png",
+-- wield_image = "",
+-- wield_scale = {x=1,y=1,z=1},
+-- stack_max = 99,
+-- liquids_pointable = false,
+-- tool_digging_properties = {
+-- full_punch_interval = 1.0,
+-- basetime = 1.0,
+-- dt_weight = 0.5,
+-- dt_crackiness = -0.2,
+-- dt_crumbliness = 1,
+-- dt_cuttability = -0.5,
+-- basedurability = 330,
+-- dd_weight = 0,
+-- dd_crackiness = 0,
+-- dd_crumbliness = 0,
+-- dd_cuttability = 0,
+-- }
+-- on_drop = func(item, dropper, pos),
+-- on_place = func(item, placer, pointed_thing),
+-- on_use = func(item, user, pointed_thing),
-- }
--
--- Node definition options:
+-- Node definition options (register_node):
-- {
--- name = "modname:somenode",
+-- <all fields allowed in item definitions>,
-- drawtype = "normal",
-- visual_scale = 1.0,
-- tile_images = {"default_unknown_block.png"},
--- inventory_image = "default_unknown_block.png",
-- special_materials = {
-- {image="", backface_culling=true},
-- {image="", backface_culling=true},
@@ -301,6 +344,7 @@
-- alpha = 255,
-- post_effect_color = {a=0, r=0, g=0, b=0},
-- paramtype = "none",
+-- paramtype2 = "none",
-- is_ground_content = false,
-- sunlight_propagates = false,
-- walkable = true,
@@ -308,11 +352,8 @@
-- diggable = true,
-- climbable = false,
-- buildable_to = false,
--- wall_mounted = false,
--- often_contains_mineral = false,
--- dug_item = "",
--- extra_dug_item = "",
--- extra_dug_item_rarity = 2,
+-- drop = "",
+-- -- alternatively drop = { max_items = ..., items = { ... } }
-- metadata_name = "",
-- liquidtype = "none",
-- liquid_alternative_flowing = "",
@@ -329,34 +370,54 @@
-- cuttability = 0,
-- flammability = 0,
-- },
--- cookresult_itemstring = "", -- Cannot be cooked
--- furnace_cooktime = 3.0,
--- furnace_burntime = -1, -- Cannot be used as fuel
+-- legacy_facedir_simple = false, -- Support maps made in and before January 2012
+-- legacy_wallmounted = false, -- Support maps made in and before January 2012
-- }
--
--- Craftitem definition options:
--- minetest.register_craftitem("modname_name", {
--- image = "default_image.png",
--- stack_max = <maximum number of items in stack>,
--- cookresult_itemstring = itemstring (result of cooking),
--- furnace_cooktime = <cooking time>,
--- furnace_burntime = <time to burn as fuel in furnace>,
--- usable = <uh... some boolean value>,
--- dropcount = <amount of items to drop using drop action>
--- liquids_pointable = <whether can point liquids>,
--- on_drop = func(item, dropper, pos),
--- on_place_on_ground = func(item, placer, pos),
--- on_use = func(item, player, pointed_thing),
--- })
---
-- Recipe:
-- {
--- output = 'tool "default:pick_stone"',
+-- output = 'default:pick_stone',
-- recipe = {
--- {'node "default:cobble"', 'node "default:cobble"', 'node "default:cobble"'},
--- {'', 'craft "default:stick"', ''},
--- {'', 'craft "default:stick"', ''},
--- }
+-- {'default:cobble', 'default:cobble', 'default:cobble'},
+-- {'', 'default:stick', ''},
+-- {'', 'default:stick', ''},
+-- },
+-- replacements = <optional list of item pairs,
+-- replace one input item with another item on crafting>
+-- }
+--
+-- Recipe (shapeless):
+-- {
+-- type = "shapeless",
+-- output = 'mushrooms:mushroom_stew',
+-- recipe = {
+-- "mushrooms:bowl",
+-- "mushrooms:mushroom_brown",
+-- "mushrooms:mushroom_red",
+-- },
+-- replacements = <optional list of item pairs,
+-- replace one input item with another item on crafting>
+-- }
+--
+-- Recipe (tool repair):
+-- {
+-- type = "toolrepair",
+-- additional_wear = -0.02,
+-- }
+--
+-- Recipe (cooking):
+-- {
+-- type = "cooking",
+-- output = "default:glass",
+-- recipe = "default:sand",
+-- cooktime = 3,
+-- }
+--
+-- Recipe (furnace fuel):
+-- {
+-- type = "fuel",
+-- recipe = "default:leaves",
+-- burntime = 1,
-- }
--
-- ABM (ActiveBlockModifier) definition:
@@ -382,189 +443,213 @@ default = {}
-- Tool definition
--
--- The hand
-minetest.register_tool(":", {
- image = "",
- 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_tool("default:pick_wood", {
- image = "default_tool_woodpick.png",
- basetime = 2.0,
- dt_weight = 0,
- dt_crackiness = -0.5,
- dt_crumbliness = 2,
- dt_cuttability = 0,
- basedurability = 30,
- dd_weight = 0,
- dd_crackiness = 0,
- dd_crumbliness = 0,
- dd_cuttability = 0,
+ description = "Wooden Pickaxe",
+ inventory_image = "default_tool_woodpick.png",
+ tool_digging_properties = {
+ basetime = 2.0,
+ dt_weight = 0,
+ dt_crackiness = -0.5,
+ dt_crumbliness = 2,
+ dt_cuttability = 0,
+ basedurability = 30,
+ dd_weight = 0,
+ dd_crackiness = 0,
+ dd_crumbliness = 0,
+ dd_cuttability = 0,
+ },
})
minetest.register_tool("default:pick_stone", {
- image = "default_tool_stonepick.png",
- basetime = 1.5,
- dt_weight = 0,
- dt_crackiness = -0.5,
- dt_crumbliness = 2,
- dt_cuttability = 0,
- basedurability = 100,
- dd_weight = 0,
- dd_crackiness = 0,
- dd_crumbliness = 0,
- dd_cuttability = 0,
+ description = "Stone Pickaxe",
+ inventory_image = "default_tool_stonepick.png",
+ tool_digging_properties = {
+ basetime = 1.5,
+ dt_weight = 0,
+ dt_crackiness = -0.5,
+ dt_crumbliness = 2,
+ dt_cuttability = 0,
+ basedurability = 100,
+ dd_weight = 0,
+ dd_crackiness = 0,
+ dd_crumbliness = 0,
+ dd_cuttability = 0,
+ },
})
minetest.register_tool("default:pick_steel", {
- image = "default_tool_steelpick.png",
- basetime = 1.0,
- dt_weight = 0,
- dt_crackiness = -0.5,
- dt_crumbliness = 2,
- dt_cuttability = 0,
- basedurability = 333,
- dd_weight = 0,
- dd_crackiness = 0,
- dd_crumbliness = 0,
- dd_cuttability = 0,
+ description = "Steel Pickaxe",
+ inventory_image = "default_tool_steelpick.png",
+ tool_digging_properties = {
+ basetime = 1.0,
+ dt_weight = 0,
+ dt_crackiness = -0.5,
+ dt_crumbliness = 2,
+ dt_cuttability = 0,
+ basedurability = 333,
+ dd_weight = 0,
+ dd_crackiness = 0,
+ dd_crumbliness = 0,
+ dd_cuttability = 0,
+ },
})
minetest.register_tool("default:pick_mese", {
- image = "default_tool_mesepick.png",
- basetime = 0,
- dt_weight = 0,
- dt_crackiness = 0,
- dt_crumbliness = 0,
- dt_cuttability = 0,
- basedurability = 1337,
- dd_weight = 0,
- dd_crackiness = 0,
- dd_crumbliness = 0,
- dd_cuttability = 0,
+ description = "Mese Pickaxe",
+ inventory_image = "default_tool_mesepick.png",
+ tool_digging_properties = {
+ basetime = 0,
+ dt_weight = 0,
+ dt_crackiness = 0,
+ dt_crumbliness = 0,
+ dt_cuttability = 0,
+ basedurability = 1337,
+ dd_weight = 0,
+ dd_crackiness = 0,
+ dd_crumbliness = 0,
+ dd_cuttability = 0,
+ },
})
minetest.register_tool("default:shovel_wood", {
- image = "default_tool_woodshovel.png",
- basetime = 2.0,
- dt_weight = 0.5,
- dt_crackiness = 2,
- dt_crumbliness = -1.5,
- dt_cuttability = 0.3,
- basedurability = 30,
- dd_weight = 0,
- dd_crackiness = 0,
- dd_crumbliness = 0,
- dd_cuttability = 0,
+ description = "Wooden Shovel",
+ inventory_image = "default_tool_woodshovel.png",
+ tool_digging_properties = {
+ basetime = 2.0,
+ dt_weight = 0.5,
+ dt_crackiness = 2,
+ dt_crumbliness = -1.5,
+ dt_cuttability = 0.3,
+ basedurability = 30,
+ dd_weight = 0,
+ dd_crackiness = 0,
+ dd_crumbliness = 0,
+ dd_cuttability = 0,
+ },
})
minetest.register_tool("default:shovel_stone", {
- image = "default_tool_stoneshovel.png",
- basetime = 1.5,
- dt_weight = 0.5,
- dt_crackiness = 2,
- dt_crumbliness = -1.5,
- dt_cuttability = 0.1,
- basedurability = 100,
- dd_weight = 0,
- dd_crackiness = 0,
- dd_crumbliness = 0,
- dd_cuttability = 0,
+ description = "Stone Shovel",
+ inventory_image = "default_tool_stoneshovel.png",
+ tool_digging_properties = {
+ basetime = 1.5,
+ dt_weight = 0.5,
+ dt_crackiness = 2,
+ dt_crumbliness = -1.5,
+ dt_cuttability = 0.1,
+ basedurability = 100,
+ dd_weight = 0,
+ dd_crackiness = 0,
+ dd_crumbliness = 0,
+ dd_cuttability = 0,
+ },
})
minetest.register_tool("default:shovel_steel", {
- image = "default_tool_steelshovel.png",
- basetime = 1.0,
- dt_weight = 0.5,
- dt_crackiness = 2,
- dt_crumbliness = -1.5,
- dt_cuttability = 0.0,
- basedurability = 330,
- dd_weight = 0,
- dd_crackiness = 0,
- dd_crumbliness = 0,
- dd_cuttability = 0,
+ description = "Steel Shovel",
+ inventory_image = "default_tool_steelshovel.png",
+ tool_digging_properties = {
+ basetime = 1.0,
+ dt_weight = 0.5,
+ dt_crackiness = 2,
+ dt_crumbliness = -1.5,
+ dt_cuttability = 0.0,
+ basedurability = 330,
+ dd_weight = 0,
+ dd_crackiness = 0,
+ dd_crumbliness = 0,
+ dd_cuttability = 0,
+ },
})
minetest.register_tool("default:axe_wood", {
- image = "default_tool_woodaxe.png",
- basetime = 2.0,
- dt_weight = 0.5,
- dt_crackiness = -0.2,
- dt_crumbliness = 1,
- dt_cuttability = -0.5,
- basedurability = 30,
- dd_weight = 0,
- dd_crackiness = 0,
- dd_crumbliness = 0,
- dd_cuttability = 0,
+ description = "Wooden Axe",
+ inventory_image = "default_tool_woodaxe.png",
+ tool_digging_properties = {
+ basetime = 2.0,
+ dt_weight = 0.5,
+ dt_crackiness = -0.2,
+ dt_crumbliness = 1,
+ dt_cuttability = -0.5,
+ basedurability = 30,
+ dd_weight = 0,
+ dd_crackiness = 0,
+ dd_crumbliness = 0,
+ dd_cuttability = 0,
+ },
})
minetest.register_tool("default:axe_stone", {
- image = "default_tool_stoneaxe.png",
- basetime = 1.5,
- dt_weight = 0.5,
- dt_crackiness = -0.2,
- dt_crumbliness = 1,
- dt_cuttability = -0.5,
- basedurability = 100,
- dd_weight = 0,
- dd_crackiness = 0,
- dd_crumbliness = 0,
- dd_cuttability = 0,
+ description = "Stone Axe",
+ inventory_image = "default_tool_stoneaxe.png",
+ tool_digging_properties = {
+ basetime = 1.5,
+ dt_weight = 0.5,
+ dt_crackiness = -0.2,
+ dt_crumbliness = 1,
+ dt_cuttability = -0.5,
+ basedurability = 100,
+ dd_weight = 0,
+ dd_crackiness = 0,
+ dd_crumbliness = 0,
+ dd_cuttability = 0,
+ },
})
minetest.register_tool("default:axe_steel", {
- image = "default_tool_steelaxe.png",
- basetime = 1.0,
- dt_weight = 0.5,
- dt_crackiness = -0.2,
- dt_crumbliness = 1,
- dt_cuttability = -0.5,
- basedurability = 330,
- dd_weight = 0,
- dd_crackiness = 0,
- dd_crumbliness = 0,
- dd_cuttability = 0,
+ description = "Steel Axe",
+ inventory_image = "default_tool_steelaxe.png",
+ tool_digging_properties = {
+ basetime = 1.0,
+ dt_weight = 0.5,
+ dt_crackiness = -0.2,
+ dt_crumbliness = 1,
+ dt_cuttability = -0.5,
+ basedurability = 330,
+ dd_weight = 0,
+ dd_crackiness = 0,
+ dd_crumbliness = 0,
+ dd_cuttability = 0,
+ },
})
minetest.register_tool("default:sword_wood", {
- image = "default_tool_woodsword.png",
- basetime = 3.0,
- dt_weight = 3,
- dt_crackiness = 0,
- dt_crumbliness = 1,
- dt_cuttability = -1,
- basedurability = 30,
- dd_weight = 0,
- dd_crackiness = 0,
- dd_crumbliness = 0,
- dd_cuttability = 0,
+ description = "Wooden Sword",
+ inventory_image = "default_tool_woodsword.png",
+ tool_digging_properties = {
+ basetime = 3.0,
+ dt_weight = 3,
+ dt_crackiness = 0,
+ dt_crumbliness = 1,
+ dt_cuttability = -1,
+ basedurability = 30,
+ dd_weight = 0,
+ dd_crackiness = 0,
+ dd_crumbliness = 0,
+ dd_cuttability = 0,
+ }
})
minetest.register_tool("default:sword_stone", {
- image = "default_tool_stonesword.png",
- basetime = 2.5,
- dt_weight = 3,
- dt_crackiness = 0,
- dt_crumbliness = 1,
- dt_cuttability = -1,
- basedurability = 100,
- dd_weight = 0,
- dd_crackiness = 0,
- dd_crumbliness = 0,
- dd_cuttability = 0,
+ description = "Stone Sword",
+ inventory_image = "default_tool_stonesword.png",
+ tool_digging_properties = {
+ basetime = 2.5,
+ dt_weight = 3,
+ dt_crackiness = 0,
+ dt_crumbliness = 1,
+ dt_cuttability = -1,
+ basedurability = 100,
+ dd_weight = 0,
+ dd_crackiness = 0,
+ dd_crumbliness = 0,
+ dd_cuttability = 0,
+ }
})
minetest.register_tool("default:sword_steel", {
- image = "default_tool_steelsword.png",
- basetime = 2.0,
- dt_weight = 3,
- dt_crackiness = 0,
- dt_crumbliness = 1,
- dt_cuttability = -1,
- basedurability = 330,
- dd_weight = 0,
- dd_crackiness = 0,
- dd_crumbliness = 0,
- dd_cuttability = 0,
+ description = "Steel Sword",
+ inventory_image = "default_tool_steelsword.png",
+ tool_digging_properties = {
+ basetime = 2.0,
+ dt_weight = 3,
+ dt_crackiness = 0,
+ dt_crumbliness = 1,
+ dt_cuttability = -1,
+ basedurability = 330,
+ dd_weight = 0,
+ dd_crackiness = 0,
+ dd_crumbliness = 0,
+ dd_cuttability = 0,
+ }
})
--
@@ -572,409 +657,610 @@ minetest.register_tool("default:sword_steel", {
--
minetest.register_craft({
- output = 'node "default:wood" 4',
+ output = 'default:wood 4',
recipe = {
- {'node "default:tree"'},
+ {'default:tree'},
}
})
minetest.register_craft({
- output = 'craft "default:stick" 4',
+ output = 'default:stick 4',
recipe = {
- {'node "default:wood"'},
+ {'default:wood'},
}
})
minetest.register_craft({
- output = 'node "default:fence_wood" 2',
+ output = 'default:fence_wood 2',
recipe = {
- {'craft "default:stick"', 'craft "default:stick"', 'craft "default:stick"'},
- {'craft "default:stick"', 'craft "default:stick"', 'craft "default:stick"'},
+ {'default:stick', 'default:stick', 'default:stick'},
+ {'default:stick', 'default:stick', 'default:stick'},
}
})
minetest.register_craft({
- output = 'node "default:sign_wall" 1',
+ output = 'default:sign_wall',
recipe = {
- {'node "default:wood"', 'node "default:wood"', 'node "default:wood"'},
- {'node "default:wood"', 'node "default:wood"', 'node "default:wood"'},
- {'', 'craft "default:stick"', ''},
+ {'default:wood', 'default:wood', 'default:wood'},
+ {'default:wood', 'default:wood', 'default:wood'},
+ {'', 'default:stick', ''},
}
})
minetest.register_craft({
- output = 'node "default:torch" 4',
+ output = 'default:torch 4',
recipe = {
- {'craft "default:coal_lump"'},
- {'craft "default:stick"'},
+ {'default:coal_lump'},
+ {'default:stick'},
}
})
minetest.register_craft({
- output = 'tool "default:pick_wood"',
+ output = 'default:pick_wood',
recipe = {
- {'node "default:wood"', 'node "default:wood"', 'node "default:wood"'},
- {'', 'craft "default:stick"', ''},
- {'', 'craft "default:stick"', ''},
+ {'default:wood', 'default:wood', 'default:wood'},
+ {'', 'default:stick', ''},
+ {'', 'default:stick', ''},
}
})
minetest.register_craft({
- output = 'tool "default:pick_stone"',
+ output = 'default:pick_stone',
recipe = {
- {'node "default:cobble"', 'node "default:cobble"', 'node "default:cobble"'},
- {'', 'craft "default:stick"', ''},
- {'', 'craft "default:stick"', ''},
+ {'default:cobble', 'default:cobble', 'default:cobble'},
+ {'', 'default:stick', ''},
+ {'', 'default:stick', ''},
}
})
minetest.register_craft({
- output = 'tool "default:pick_steel"',
+ output = 'default:pick_steel',
recipe = {
- {'craft "default:steel_ingot"', 'craft "default:steel_ingot"', 'craft "default:steel_ingot"'},
- {'', 'craft "default:stick"', ''},
- {'', 'craft "default:stick"', ''},
+ {'default:steel_ingot', 'default:steel_ingot', 'default:steel_ingot'},
+ {'', 'default:stick', ''},
+ {'', 'default:stick', ''},
}
})
minetest.register_craft({
- output = 'tool "default:pick_mese"',
+ output = 'default:pick_mese',
recipe = {
- {'node "default:mese"', 'node "default:mese"', 'node "default:mese"'},
- {'', 'craft "default:stick"', ''},
- {'', 'craft "default:stick"', ''},
+ {'default:mese', 'default:mese', 'default:mese'},
+ {'', 'default:stick', ''},
+ {'', 'default:stick', ''},
}
})
minetest.register_craft({
- output = 'tool "default:shovel_wood"',
+ output = 'default:shovel_wood',
recipe = {
- {'node "default:wood"'},
- {'craft "default:stick"'},
- {'craft "default:stick"'},
+ {'default:wood'},
+ {'default:stick'},
+ {'default:stick'},
}
})
minetest.register_craft({
- output = 'tool "default:shovel_stone"',
+ output = 'default:shovel_stone',
recipe = {
- {'node "default:cobble"'},
- {'craft "default:stick"'},
- {'craft "default:stick"'},
+ {'default:cobble'},
+ {'default:stick'},
+ {'default:stick'},
}
})
minetest.register_craft({
- output = 'tool "default:shovel_steel"',
+ output = 'default:shovel_steel',
recipe = {
- {'craft "default:steel_ingot"'},
- {'craft "default:stick"'},
- {'craft "default:stick"'},
+ {'default:steel_ingot'},
+ {'default:stick'},
+ {'default:stick'},
}
})
minetest.register_craft({
- output = 'tool "default:axe_wood"',
+ output = 'default:axe_wood',
recipe = {
- {'node "default:wood"', 'node "default:wood"'},
- {'node "default:wood"', 'craft "default:stick"'},
- {'', 'craft "default:stick"'},
+ {'default:wood', 'default:wood'},
+ {'default:wood', 'default:stick'},
+ {'', 'default:stick'},
}
})
minetest.register_craft({
- output = 'tool "default:axe_stone"',
+ output = 'default:axe_stone',
recipe = {
- {'node "default:cobble"', 'node "default:cobble"'},
- {'node "default:cobble"', 'craft "default:stick"'},
- {'', 'craft "default:stick"'},
+ {'default:cobble', 'default:cobble'},
+ {'default:cobble', 'default:stick'},
+ {'', 'default:stick'},
}
})
minetest.register_craft({
- output = 'tool "default:axe_steel"',
+ output = 'default:axe_steel',
recipe = {
- {'craft "default:steel_ingot"', 'craft "default:steel_ingot"'},
- {'craft "default:steel_ingot"', 'craft "default:stick"'},
- {'', 'craft "default:stick"'},
+ {'default:steel_ingot', 'default:steel_ingot'},
+ {'default:steel_ingot', 'default:stick'},
+ {'', 'default:stick'},
}
})
minetest.register_craft({
- output = 'tool "default:sword_wood"',
+ output = 'default:sword_wood',
recipe = {
- {'node "default:wood"'},
- {'node "default:wood"'},
- {'craft "default:stick"'},
+ {'default:wood'},
+ {'default:wood'},
+ {'default:stick'},
}
})
minetest.register_craft({
- output = 'tool "default:sword_stone"',
+ output = 'default:sword_stone',
recipe = {
- {'node "default:cobble"'},
- {'node "default:cobble"'},
- {'craft "default:stick"'},
+ {'default:cobble'},
+ {'default:cobble'},
+ {'default:stick'},
}
})
minetest.register_craft({
- output = 'tool "default:sword_steel"',
+ output = 'default:sword_steel',
recipe = {
- {'craft "default:steel_ingot"'},
- {'craft "default:steel_ingot"'},
- {'craft "default:stick"'},
+ {'default:steel_ingot'},
+ {'default:steel_ingot'},
+ {'default:stick'},
}
})
minetest.register_craft({
- output = 'node "default:rail" 15',
+ output = 'default:rail 15',
recipe = {
- {'craft "default:steel_ingot"', '', 'craft "default:steel_ingot"'},
- {'craft "default:steel_ingot"', 'craft "default:stick"', 'craft "default:steel_ingot"'},
- {'craft "default:steel_ingot"', '', 'craft "default:steel_ingot"'},
+ {'default:steel_ingot', '', 'default:steel_ingot'},
+ {'default:steel_ingot', 'default:stick', 'default:steel_ingot'},
+ {'default:steel_ingot', '', 'default:steel_ingot'},
}
})
minetest.register_craft({
- output = 'node "default:chest" 1',
+ output = 'default:chest',
recipe = {
- {'node "default:wood"', 'node "default:wood"', 'node "default:wood"'},
- {'node "default:wood"', '', 'node "default:wood"'},
- {'node "default:wood"', 'node "default:wood"', 'node "default:wood"'},
+ {'default:wood', 'default:wood', 'default:wood'},
+ {'default:wood', '', 'default:wood'},
+ {'default:wood', 'default:wood', 'default:wood'},
}
})
minetest.register_craft({
- output = 'node "default:chest_locked" 1',
+ output = 'default:chest_locked',
recipe = {
- {'node "default:wood"', 'node "default:wood"', 'node "default:wood"'},
- {'node "default:wood"', 'craft "default:steel_ingot"', 'node "default:wood"'},
- {'node "default:wood"', 'node "default:wood"', 'node "default:wood"'},
+ {'default:wood', 'default:wood', 'default:wood'},
+ {'default:wood', 'default:steel_ingot', 'default:wood'},
+ {'default:wood', 'default:wood', 'default:wood'},
}
})
minetest.register_craft({
- output = 'node "default:furnace" 1',
+ output = 'default:furnace',
recipe = {
- {'node "default:cobble"', 'node "default:cobble"', 'node "default:cobble"'},
- {'node "default:cobble"', '', 'node "default:cobble"'},
- {'node "default:cobble"', 'node "default:cobble"', 'node "default:cobble"'},
+ {'default:cobble', 'default:cobble', 'default:cobble'},
+ {'default:cobble', '', 'default:cobble'},
+ {'default:cobble', 'default:cobble', 'default:cobble'},
}
})
minetest.register_craft({
- output = 'node "default:steelblock" 1',
+ output = 'default:steelblock',
recipe = {
- {'craft "default:steel_ingot"', 'craft "default:steel_ingot"', 'craft "default:steel_ingot"'},
- {'craft "default:steel_ingot"', 'craft "default:steel_ingot"', 'craft "default:steel_ingot"'},
- {'craft "default:steel_ingot"', 'craft "default:steel_ingot"', 'craft "default:steel_ingot"'},
+ {'default:steel_ingot', 'default:steel_ingot', 'default:steel_ingot'},
+ {'default:steel_ingot', 'default:steel_ingot', 'default:steel_ingot'},
+ {'default:steel_ingot', 'default:steel_ingot', 'default:steel_ingot'},
}
})
minetest.register_craft({
- output = 'node "default:sandstone" 1',
+ output = 'default:sandstone',
recipe = {
- {'node "default:sand"', 'node "default:sand"'},
- {'node "default:sand"', 'node "default:sand"'},
+ {'default:sand', 'default:sand'},
+ {'default:sand', 'default:sand'},
}
})
minetest.register_craft({
- output = 'node "default:clay" 1',
+ output = 'default:clay',
recipe = {
- {'craft "default:clay_lump"', 'craft "default:clay_lump"'},
- {'craft "default:clay_lump"', 'craft "default:clay_lump"'},
+ {'default:clay_lump', 'default:clay_lump'},
+ {'default:clay_lump', 'default:clay_lump'},
}
})
minetest.register_craft({
- output = 'node "default:brick" 1',
+ output = 'default:brick',
recipe = {
- {'craft "default:clay_brick"', 'craft "default:clay_brick"'},
- {'craft "default:clay_brick"', 'craft "default:clay_brick"'},
+ {'default:clay_brick', 'default:clay_brick'},
+ {'default:clay_brick', 'default:clay_brick'},
}
})
minetest.register_craft({
- output = 'craft "default:paper" 1',
+ output = 'default:paper',
recipe = {
- {'node "default:papyrus"', 'node "default:papyrus"', 'node "default:papyrus"'},
+ {'default:papyrus', 'default:papyrus', 'default:papyrus'},
}
})
minetest.register_craft({
- output = 'craft "default:book" 1',
+ output = 'default:book',
recipe = {
- {'craft "default:paper"'},
- {'craft "default:paper"'},
- {'craft "default:paper"'},
+ {'default:paper'},
+ {'default:paper'},
+ {'default:paper'},
}
})
minetest.register_craft({
- output = 'node "default:bookshelf" 1',
+ output = 'default:bookshelf',
recipe = {
- {'node "default:wood"', 'node "default:wood"', 'node "default:wood"'},
- {'craft "default:book"', 'craft "default:book"', 'craft "default:book"'},
- {'node "default:wood"', 'node "default:wood"', 'node "default:wood"'},
+ {'default:wood', 'default:wood', 'default:wood'},
+ {'default:book', 'default:book', 'default:book'},
+ {'default:wood', 'default:wood', 'default:wood'},
}
})
minetest.register_craft({
- output = 'node "default:ladder" 1',
+ output = 'default:ladder',
recipe = {
- {'craft "default:stick"', '', 'craft "default:stick"'},
- {'craft "default:stick"', 'craft "default:stick"', 'craft "default:stick"'},
- {'craft "default:stick"', '', 'craft "default:stick"'},
+ {'default:stick', '', 'default:stick'},
+ {'default:stick', 'default:stick', 'default:stick'},
+ {'default:stick', '', 'default:stick'},
}
})
--
+-- Crafting (tool repair)
+--
+minetest.register_craft({
+ type = "toolrepair",
+ additional_wear = -0.02,
+})
+
+--
+-- Cooking recipes
+--
+
+minetest.register_craft({
+ type = "cooking",
+ output = "default:glass",
+ recipe = "default:sand",
+})
+
+minetest.register_craft({
+ type = "cooking",
+ output = "default:coal_lump",
+ recipe = "default:tree",
+})
+
+minetest.register_craft({
+ type = "cooking",
+ output = "default:coal_lump",
+ recipe = "default:jungletree",
+})
+
+minetest.register_craft({
+ type = "cooking",
+ output = "default:stone",
+ recipe = "default:cobble",
+})
+
+minetest.register_craft({
+ type = "cooking",
+ output = "default:steel_ingot",
+ recipe = "default:iron_lump",
+})
+
+minetest.register_craft({
+ type = "cooking",
+ output = "default:clay_brick",
+ recipe = "default:clay_lump",
+})
+
+--
+-- Fuels
+--
+
+minetest.register_craft({
+ type = "fuel",
+ recipe = "default:tree",
+ burntime = 30,
+})
+
+minetest.register_craft({
+ type = "fuel",
+ recipe = "default:jungletree",
+ burntime = 30,
+})
+
+minetest.register_craft({
+ type = "fuel",
+ recipe = "default:junglegrass",
+ burntime = 2,
+})
+
+minetest.register_craft({
+ type = "fuel",
+ recipe = "default:leaves",
+ burntime = 1,
+})
+
+minetest.register_craft({
+ type = "fuel",
+ recipe = "default:cactus",
+ burntime = 15,
+})
+
+minetest.register_craft({
+ type = "fuel",
+ recipe = "default:papyrus",
+ burntime = 1,
+})
+
+minetest.register_craft({
+ type = "fuel",
+ recipe = "default:bookshelf",
+ burntime = 30,
+})
+
+minetest.register_craft({
+ type = "fuel",
+ recipe = "default:fence_wood",
+ burntime = 15,
+})
+
+minetest.register_craft({
+ type = "fuel",
+ recipe = "default:ladder",
+ burntime = 5,
+})
+
+minetest.register_craft({
+ type = "fuel",
+ recipe = "default:wood",
+ burntime = 7,
+})
+
+minetest.register_craft({
+ type = "fuel",
+ recipe = "default:mese",
+ burntime = 30,
+})
+
+minetest.register_craft({
+ type = "fuel",
+ recipe = "default:lava_source",
+ burntime = 60,
+})
+
+minetest.register_craft({
+ type = "fuel",
+ recipe = "default:torch",
+ burntime = 4,
+})
+
+minetest.register_craft({
+ type = "fuel",
+ recipe = "default:sign_wall",
+ burntime = 10,
+})
+
+minetest.register_craft({
+ type = "fuel",
+ recipe = "default:chest",
+ burntime = 30,
+})
+
+minetest.register_craft({
+ type = "fuel",
+ recipe = "default:chest_locked",
+ burntime = 30,
+})
+
+minetest.register_craft({
+ type = "fuel",
+ recipe = "default:nyancat",
+ burntime = 1,
+})
+
+minetest.register_craft({
+ type = "fuel",
+ recipe = "default:nyancat_rainbow",
+ burntime = 1,
+})
+
+minetest.register_craft({
+ type = "fuel",
+ recipe = "default:sapling",
+ burntime = 10,
+})
+
+minetest.register_craft({
+ type = "fuel",
+ recipe = "default:apple",
+ burntime = 3,
+})
+
+minetest.register_craft({
+ type = "fuel",
+ recipe = "default:coal_lump",
+ burntime = 40,
+})
+
+--
-- Node definitions
--
minetest.register_node("default:stone", {
+ description = "Stone",
tile_images = {"default_stone.png"},
- inventory_image = minetest.inventorycube("default_stone.png"),
- paramtype = "mineral",
is_ground_content = true,
- often_contains_mineral = true, -- Texture atlas hint
material = minetest.digprop_stonelike(1.0),
- dug_item = 'node "default:cobble" 1',
+ drop = 'default:cobble',
+ legacy_mineral = true,
+})
+
+minetest.register_node("default:stone_with_coal", {
+ description = "Stone with coal",
+ tile_images = {"default_stone.png^default_mineral_coal.png"},
+ is_ground_content = true,
+ material = minetest.digprop_stonelike(1.0),
+ drop = 'default:coal_lump',
+})
+
+minetest.register_node("default:stone_with_iron", {
+ description = "Stone with iron",
+ tile_images = {"default_stone.png^default_mineral_iron.png"},
+ is_ground_content = true,
+ material = minetest.digprop_stonelike(1.0),
+ drop = 'default:iron_lump',
})
minetest.register_node("default:dirt_with_grass", {
+ description = "Dirt with grass",
tile_images = {"default_grass.png", "default_dirt.png", "default_dirt.png^default_grass_side.png"},
- inventory_image = minetest.inventorycube("default_dirt.png^default_grass_side.png"),
is_ground_content = true,
material = minetest.digprop_dirtlike(1.0),
- dug_item = 'node "default:dirt" 1',
+ drop = 'default:dirt',
})
minetest.register_node("default:dirt_with_grass_footsteps", {
+ description = "Dirt with grass and footsteps",
tile_images = {"default_grass_footsteps.png", "default_dirt.png", "default_dirt.png^default_grass_side.png"},
- inventory_image = "default_grass_footsteps.png",
is_ground_content = true,
material = minetest.digprop_dirtlike(1.0),
- dug_item = 'node "default:dirt" 1',
+ drop = 'default:dirt',
})
minetest.register_node("default:dirt", {
+ description = "Dirt",
tile_images = {"default_dirt.png"},
- inventory_image = minetest.inventorycube("default_dirt.png"),
is_ground_content = true,
material = minetest.digprop_dirtlike(1.0),
})
minetest.register_node("default:sand", {
+ description = "Sand",
tile_images = {"default_sand.png"},
- inventory_image = minetest.inventorycube("default_sand.png"),
is_ground_content = true,
material = minetest.digprop_dirtlike(1.0),
- cookresult_itemstring = 'node "default:glass" 1',
})
minetest.register_node("default:gravel", {
+ description = "Gravel",
tile_images = {"default_gravel.png"},
- inventory_image = minetest.inventorycube("default_gravel.png"),
is_ground_content = true,
material = minetest.digprop_gravellike(1.0),
})
minetest.register_node("default:sandstone", {
+ description = "Sandstone",
tile_images = {"default_sandstone.png"},
- inventory_image = minetest.inventorycube("default_sandstone.png"),
is_ground_content = true,
material = minetest.digprop_dirtlike(1.0), -- FIXME should this be stonelike?
- dug_item = 'node "default:sand" 1', -- FIXME is this intentional?
+ drop = 'default:sand',
})
minetest.register_node("default:clay", {
+ description = "Clay",
tile_images = {"default_clay.png"},
- inventory_image = minetest.inventorycube("default_clay.png"),
is_ground_content = true,
material = minetest.digprop_dirtlike(1.0),
- dug_item = 'craft "default:clay_lump" 4',
+ drop = 'default:clay_lump 4',
})
minetest.register_node("default:brick", {
+ description = "Brick",
tile_images = {"default_brick.png"},
- inventory_image = minetest.inventorycube("default_brick.png"),
is_ground_content = true,
material = minetest.digprop_stonelike(1.0),
- dug_item = 'craft "default:clay_brick" 4',
+ drop = 'default:clay_brick 4',
})
minetest.register_node("default:tree", {
+ description = "Tree",
tile_images = {"default_tree_top.png", "default_tree_top.png", "default_tree.png"},
- inventory_image = minetest.inventorycube("default_tree_top.png", "default_tree.png", "default_tree.png"),
is_ground_content = true,
material = minetest.digprop_woodlike(1.0),
- cookresult_itemstring = 'craft "default:coal_lump" 1',
- furnace_burntime = 30,
})
minetest.register_node("default:jungletree", {
+ description = "Jungle Tree",
tile_images = {"default_jungletree_top.png", "default_jungletree_top.png", "default_jungletree.png"},
- inventory_image = minetest.inventorycube("default_jungletree_top.png", "default_jungletree.png", "default_jungletree.png"),
is_ground_content = true,
material = minetest.digprop_woodlike(1.0),
- cookresult_itemstring = 'craft "default:coal_lump" 1',
- furnace_burntime = 30,
})
minetest.register_node("default:junglegrass", {
+ description = "Jungle Grass",
drawtype = "plantlike",
visual_scale = 1.3,
tile_images = {"default_junglegrass.png"},
inventory_image = "default_junglegrass.png",
+ wield_image = "default_junglegrass.png",
paramtype = "light",
walkable = false,
material = minetest.digprop_leaveslike(1.0),
- furnace_burntime = 2,
})
minetest.register_node("default:leaves", {
+ description = "Leaves",
drawtype = "allfaces_optional",
visual_scale = 1.3,
tile_images = {"default_leaves.png"},
- inventory_image = minetest.inventorycube("default_leaves.png"),
paramtype = "light",
material = minetest.digprop_leaveslike(1.0),
- extra_dug_item = 'node "default:sapling" 1',
- extra_dug_item_rarity = 20,
- furnace_burntime = 1,
+ drop = {
+ max_items = 1,
+ items = {
+ {
+ -- player will get sapling with 1/20 chance
+ items = {'default:sapling'},
+ rarity = 20,
+ },
+ {
+ -- player will get leaves only if he get no saplings,
+ -- this is because max_items is 1
+ items = {'default:leaves'},
+ }
+ }
+ },
})
minetest.register_node("default:cactus", {
+ description = "Cactus",
tile_images = {"default_cactus_top.png", "default_cactus_top.png", "default_cactus_side.png"},
- inventory_image = minetest.inventorycube("default_cactus_top.png", "default_cactus_side.png", "default_cactus_side.png"),
is_ground_content = true,
material = minetest.digprop_woodlike(0.75),
- furnace_burntime = 15,
})
minetest.register_node("default:papyrus", {
+ description = "Papyrus",
drawtype = "plantlike",
tile_images = {"default_papyrus.png"},
inventory_image = "default_papyrus.png",
+ wield_image = "default_papyrus.png",
paramtype = "light",
is_ground_content = true,
walkable = false,
material = minetest.digprop_leaveslike(0.5),
- furnace_burntime = 1,
})
minetest.register_node("default:bookshelf", {
+ description = "Bookshelf",
tile_images = {"default_wood.png", "default_wood.png", "default_bookshelf.png"},
- inventory_image = minetest.inventorycube("default_wood.png", "default_bookshelf.png", "default_bookshelf.png"),
is_ground_content = true,
material = minetest.digprop_woodlike(0.75),
- furnace_burntime = 30,
})
minetest.register_node("default:glass", {
+ description = "Glass",
drawtype = "glasslike",
tile_images = {"default_glass.png"},
inventory_image = minetest.inventorycube("default_glass.png"),
@@ -985,23 +1271,26 @@ minetest.register_node("default:glass", {
})
minetest.register_node("default:fence_wood", {
+ description = "Wooden Fence",
drawtype = "fencelike",
tile_images = {"default_wood.png"},
inventory_image = "default_fence.png",
+ wield_image = "default_fence.png",
paramtype = "light",
is_ground_content = true,
selection_box = {
type = "fixed",
fixed = {-1/7, -1/2, -1/7, 1/7, 1/2, 1/7},
},
- furnace_burntime = 15,
material = minetest.digprop_woodlike(0.75),
})
minetest.register_node("default:rail", {
+ description = "Rail",
drawtype = "raillike",
tile_images = {"default_rail.png", "default_rail_curved.png", "default_rail_t_junction.png", "default_rail_crossing.png"},
inventory_image = "default_rail.png",
+ wield_image = "default_rail.png",
paramtype = "light",
is_ground_content = true,
walkable = false,
@@ -1013,12 +1302,14 @@ minetest.register_node("default:rail", {
})
minetest.register_node("default:ladder", {
+ description = "Ladder",
drawtype = "signlike",
tile_images = {"default_ladder.png"},
inventory_image = "default_ladder.png",
+ wield_image = "default_ladder.png",
paramtype = "light",
+ paramtype2 = "wallmounted",
is_ground_content = true,
- wall_mounted = true,
walkable = false,
climbable = true,
selection_box = {
@@ -1027,37 +1318,36 @@ minetest.register_node("default:ladder", {
--wall_bottom = = <default>
--wall_side = = <default>
},
- furnace_burntime = 5,
material = minetest.digprop_woodlike(0.5),
+ legacy_wallmounted = true,
})
minetest.register_node("default:wood", {
+ description = "Wood",
tile_images = {"default_wood.png"},
- inventory_image = minetest.inventorycube("default_wood.png"),
is_ground_content = true,
- furnace_burntime = 7,
material = minetest.digprop_woodlike(0.75),
})
minetest.register_node("default:mese", {
+ description = "Mese",
tile_images = {"default_mese.png"},
- inventory_image = minetest.inventorycube("default_mese.png"),
is_ground_content = true,
- furnace_burntime = 30,
material = minetest.digprop_stonelike(0.5),
})
minetest.register_node("default:cloud", {
+ description = "Cloud",
tile_images = {"default_cloud.png"},
- inventory_image = minetest.inventorycube("default_cloud.png"),
is_ground_content = true,
})
minetest.register_node("default:water_flowing", {
+ description = "Water (flowing)",
+ inventory_image = minetest.inventorycube("default_water.png"),
drawtype = "flowingliquid",
tile_images = {"default_water.png"},
alpha = WATER_ALPHA,
- inventory_image = minetest.inventorycube("default_water.png"),
paramtype = "light",
walkable = false,
pointable = false,
@@ -1075,10 +1365,11 @@ minetest.register_node("default:water_flowing", {
})
minetest.register_node("default:water_source", {
+ description = "Water",
+ inventory_image = minetest.inventorycube("default_water.png"),
drawtype = "liquid",
tile_images = {"default_water.png"},
alpha = WATER_ALPHA,
- inventory_image = minetest.inventorycube("default_water.png"),
paramtype = "light",
walkable = false,
pointable = false,
@@ -1096,9 +1387,10 @@ minetest.register_node("default:water_source", {
})
minetest.register_node("default:lava_flowing", {
+ description = "Lava (flowing)",
+ inventory_image = minetest.inventorycube("default_lava.png"),
drawtype = "flowingliquid",
tile_images = {"default_lava.png"},
- inventory_image = minetest.inventorycube("default_lava.png"),
paramtype = "light",
light_source = LIGHT_MAX - 1,
walkable = false,
@@ -1118,9 +1410,10 @@ minetest.register_node("default:lava_flowing", {
})
minetest.register_node("default:lava_source", {
+ description = "Lava",
+ inventory_image = minetest.inventorycube("default_lava.png"),
drawtype = "liquid",
tile_images = {"default_lava.png"},
- inventory_image = minetest.inventorycube("default_lava.png"),
paramtype = "light",
light_source = LIGHT_MAX - 1,
walkable = false,
@@ -1137,17 +1430,18 @@ minetest.register_node("default:lava_source", {
-- New-style lava source material (mostly unused)
{image="default_lava.png", backface_culling=false},
},
- furnace_burntime = 60,
})
minetest.register_node("default:torch", {
+ description = "Torch",
drawtype = "torchlike",
tile_images = {"default_torch_on_floor.png", "default_torch_on_ceiling.png", "default_torch.png"},
inventory_image = "default_torch_on_floor.png",
+ wield_image = "default_torch_on_floor.png",
paramtype = "light",
+ paramtype2 = "wallmounted",
sunlight_propagates = true,
walkable = false,
- wall_mounted = true,
light_source = LIGHT_MAX-1,
selection_box = {
type = "wallmounted",
@@ -1156,17 +1450,19 @@ minetest.register_node("default:torch", {
wall_side = {-0.5, -0.3, -0.1, -0.5+0.3, 0.3, 0.1},
},
material = minetest.digprop_constanttime(0.0),
- furnace_burntime = 4,
+ legacy_wallmounted = true,
})
minetest.register_node("default:sign_wall", {
+ description = "Sign",
drawtype = "signlike",
tile_images = {"default_sign_wall.png"},
inventory_image = "default_sign_wall.png",
+ wield_image = "default_sign_wall.png",
paramtype = "light",
+ paramtype2 = "wallmounted",
sunlight_propagates = true,
walkable = false,
- wall_mounted = true,
metadata_name = "sign",
selection_box = {
type = "wallmounted",
@@ -1175,88 +1471,91 @@ minetest.register_node("default:sign_wall", {
--wall_side = <default>
},
material = minetest.digprop_constanttime(0.5),
- furnace_burntime = 10,
+ legacy_wallmounted = true,
})
minetest.register_node("default:chest", {
+ description = "Chest",
tile_images = {"default_chest_top.png", "default_chest_top.png", "default_chest_side.png",
"default_chest_side.png", "default_chest_side.png", "default_chest_front.png"},
- inventory_image = minetest.inventorycube("default_chest_top.png", "default_chest_front.png", "default_chest_side.png"),
- paramtype = "facedir_simple",
+ paramtype2 = "facedir",
metadata_name = "chest",
material = minetest.digprop_woodlike(1.0),
- furnace_burntime = 30,
+ legacy_facedir_simple = true,
})
minetest.register_node("default:chest_locked", {
+ description = "Locked Chest",
tile_images = {"default_chest_top.png", "default_chest_top.png", "default_chest_side.png",
"default_chest_side.png", "default_chest_side.png", "default_chest_lock.png"},
- inventory_image = minetest.inventorycube("default_chest_top.png", "default_chest_lock.png", "default_chest_side.png"),
- paramtype = "facedir_simple",
+ paramtype2 = "facedir",
metadata_name = "locked_chest",
material = minetest.digprop_woodlike(1.0),
- furnace_burntime = 30,
+ legacy_facedir_simple = true,
})
minetest.register_node("default:furnace", {
+ description = "Furnace",
tile_images = {"default_furnace_side.png", "default_furnace_side.png", "default_furnace_side.png",
"default_furnace_side.png", "default_furnace_side.png", "default_furnace_front.png"},
- inventory_image = minetest.inventorycube("default_furnace_side.png", "default_furnace_front.png", "default_furnace_side.png"),
- paramtype = "facedir_simple",
+ paramtype2 = "facedir",
metadata_name = "furnace",
material = minetest.digprop_stonelike(3.0),
+ legacy_facedir_simple = true,
})
minetest.register_node("default:cobble", {
+ description = "Cobble",
tile_images = {"default_cobble.png"},
- inventory_image = minetest.inventorycube("default_cobble.png"),
is_ground_content = true,
- cookresult_itemstring = 'node "default:stone" 1',
material = minetest.digprop_stonelike(0.9),
})
minetest.register_node("default:mossycobble", {
+ description = "Mossy Cobble",
tile_images = {"default_mossycobble.png"},
- inventory_image = minetest.inventorycube("default_mossycobble.png"),
is_ground_content = true,
material = minetest.digprop_stonelike(0.8),
})
minetest.register_node("default:steelblock", {
+ description = "Steel Block",
tile_images = {"default_steel_block.png"},
- inventory_image = minetest.inventorycube("default_steel_block.png"),
is_ground_content = true,
material = minetest.digprop_stonelike(5.0),
})
minetest.register_node("default:nyancat", {
+ description = "Nyancat",
tile_images = {"default_nc_side.png", "default_nc_side.png", "default_nc_side.png",
"default_nc_side.png", "default_nc_back.png", "default_nc_front.png"},
inventory_image = "default_nc_front.png",
- paramtype = "facedir_simple",
+ paramtype2 = "facedir",
material = minetest.digprop_stonelike(3.0),
- furnace_burntime = 1,
+ legacy_facedir_simple = true,
})
minetest.register_node("default:nyancat_rainbow", {
+ description = "Nyancat Rainbow",
tile_images = {"default_nc_rb.png"},
inventory_image = "default_nc_rb.png",
material = minetest.digprop_stonelike(3.0),
- furnace_burntime = 1,
})
minetest.register_node("default:sapling", {
+ description = "Sapling",
drawtype = "plantlike",
visual_scale = 1.0,
tile_images = {"default_sapling.png"},
inventory_image = "default_sapling.png",
+ wield_image = "default_sapling.png",
paramtype = "light",
walkable = false,
material = minetest.digprop_constanttime(0.0),
- furnace_burntime = 10,
})
minetest.register_node("default:apple", {
+ description = "Apple",
drawtype = "plantlike",
visual_scale = 1.0,
tile_images = {"default_apple.png"},
@@ -1264,9 +1563,8 @@ minetest.register_node("default:apple", {
paramtype = "light",
sunlight_propagates = true,
walkable = false,
- dug_item = 'craft "default:apple" 1',
material = minetest.digprop_constanttime(0.0),
- furnace_burntime = 3,
+ on_use = minetest.item_eat(4),
})
--
@@ -1274,93 +1572,84 @@ minetest.register_node("default:apple", {
--
minetest.register_craftitem("default:stick", {
- image = "default_stick.png",
- --furnace_burntime = ...,
- on_place_on_ground = minetest.craftitem_place_item,
+ description = "Stick",
+ inventory_image = "default_stick.png",
})
minetest.register_craftitem("default:paper", {
- image = "default_paper.png",
- on_place_on_ground = minetest.craftitem_place_item,
+ description = "Paper",
+ inventory_image = "default_paper.png",
})
minetest.register_craftitem("default:book", {
- image = "default_book.png",
- on_place_on_ground = minetest.craftitem_place_item,
+ description = "Book",
+ inventory_image = "default_book.png",
})
minetest.register_craftitem("default:coal_lump", {
- image = "default_coal_lump.png",
- furnace_burntime = 40;
- on_place_on_ground = minetest.craftitem_place_item,
+ description = "Lump of coal",
+ inventory_image = "default_coal_lump.png",
})
minetest.register_craftitem("default:iron_lump", {
- image = "default_iron_lump.png",
- cookresult_itemstring = 'craft "default:steel_ingot" 1',
- on_place_on_ground = minetest.craftitem_place_item,
+ description = "Lump of iron",
+ inventory_image = "default_iron_lump.png",
})
minetest.register_craftitem("default:clay_lump", {
- image = "default_clay_lump.png",
- cookresult_itemstring = 'craft "default:clay_brick" 1',
- on_place_on_ground = minetest.craftitem_place_item,
+ description = "Lump of clay",
+ inventory_image = "default_clay_lump.png",
})
minetest.register_craftitem("default:steel_ingot", {
- image = "default_steel_ingot.png",
- on_place_on_ground = minetest.craftitem_place_item,
+ description = "Steel ingot",
+ inventory_image = "default_steel_ingot.png",
})
minetest.register_craftitem("default:clay_brick", {
- image = "default_clay_brick.png",
- on_place_on_ground = minetest.craftitem_place_item,
+ description = "Clay brick",
+ inventory_image = "default_steel_ingot.png",
+ inventory_image = "default_clay_brick.png",
})
minetest.register_craftitem("default:scorched_stuff", {
- image = "default_scorched_stuff.png",
- on_place_on_ground = minetest.craftitem_place_item,
-})
-
-minetest.register_craftitem("default:apple", {
- image = "default_apple.png",
- on_place_on_ground = minetest.craftitem_place_item,
- on_use = minetest.craftitem_eat(4),
+ description = "Scorched stuff",
+ inventory_image = "default_scorched_stuff.png",
})
--
-- Creative inventory
--
-minetest.add_to_creative_inventory('tool "default:pick_mese" 0')
-minetest.add_to_creative_inventory('tool "default:pick_steel" 0')
-minetest.add_to_creative_inventory('tool "default:axe_steel" 0')
-minetest.add_to_creative_inventory('tool "default:shovel_steel" 0')
-
-minetest.add_to_creative_inventory('node "default:torch" 0')
-minetest.add_to_creative_inventory('node "default:cobble" 0')
-minetest.add_to_creative_inventory('node "default:dirt" 0')
-minetest.add_to_creative_inventory('node "default:stone" 0')
-minetest.add_to_creative_inventory('node "default:sand" 0')
-minetest.add_to_creative_inventory('node "default:sandstone" 0')
-minetest.add_to_creative_inventory('node "default:clay" 0')
-minetest.add_to_creative_inventory('node "default:brick" 0')
-minetest.add_to_creative_inventory('node "default:tree" 0')
-minetest.add_to_creative_inventory('node "default:wood" 0')
-minetest.add_to_creative_inventory('node "default:leaves" 0')
-minetest.add_to_creative_inventory('node "default:cactus" 0')
-minetest.add_to_creative_inventory('node "default:papyrus" 0')
-minetest.add_to_creative_inventory('node "default:bookshelf" 0')
-minetest.add_to_creative_inventory('node "default:glass" 0')
-minetest.add_to_creative_inventory('node "default:fence" 0')
-minetest.add_to_creative_inventory('node "default:rail" 0')
-minetest.add_to_creative_inventory('node "default:mese" 0')
-minetest.add_to_creative_inventory('node "default:chest" 0')
-minetest.add_to_creative_inventory('node "default:furnace" 0')
-minetest.add_to_creative_inventory('node "default:sign_wall" 0')
-minetest.add_to_creative_inventory('node "default:water_source" 0')
-minetest.add_to_creative_inventory('node "default:lava_source" 0')
-minetest.add_to_creative_inventory('node "default:ladder" 0')
+minetest.add_to_creative_inventory('default:pick_mese')
+minetest.add_to_creative_inventory('default:pick_steel')
+minetest.add_to_creative_inventory('default:axe_steel')
+minetest.add_to_creative_inventory('default:shovel_steel')
+
+minetest.add_to_creative_inventory('default:torch')
+minetest.add_to_creative_inventory('default:cobble')
+minetest.add_to_creative_inventory('default:dirt')
+minetest.add_to_creative_inventory('default:stone')
+minetest.add_to_creative_inventory('default:sand')
+minetest.add_to_creative_inventory('default:sandstone')
+minetest.add_to_creative_inventory('default:clay')
+minetest.add_to_creative_inventory('default:brick')
+minetest.add_to_creative_inventory('default:tree')
+minetest.add_to_creative_inventory('default:wood')
+minetest.add_to_creative_inventory('default:leaves')
+minetest.add_to_creative_inventory('default:cactus')
+minetest.add_to_creative_inventory('default:papyrus')
+minetest.add_to_creative_inventory('default:bookshelf')
+minetest.add_to_creative_inventory('default:glass')
+minetest.add_to_creative_inventory('default:fence')
+minetest.add_to_creative_inventory('default:rail')
+minetest.add_to_creative_inventory('default:mese')
+minetest.add_to_creative_inventory('default:chest')
+minetest.add_to_creative_inventory('default:furnace')
+minetest.add_to_creative_inventory('default:sign_wall')
+minetest.add_to_creative_inventory('default:water_source')
+minetest.add_to_creative_inventory('default:lava_source')
+minetest.add_to_creative_inventory('default:ladder')
--
-- Some common functions
@@ -1455,64 +1744,66 @@ function on_punchnode(p, node)
end
minetest.register_on_punchnode(on_punchnode)
+local function handle_give_command(cmd, giver, receiver, stackstring)
+ if not minetest.get_player_privs(giver)["give"] then
+ minetest.chat_send_player(giver, "error: you don't have permission to give")
+ return
+ end
+ minetest.debug("DEBUG: "..cmd..' invoked, stackstring="'..stackstring..'"')
+ minetest.log(cmd..' invoked, stackstring="'..stackstring..'"')
+ local itemstack = ItemStack(stackstring)
+ if itemstack:is_empty() then
+ minetest.chat_send_player(giver, 'error: cannot give an empty item')
+ return
+ elseif not itemstack:is_known() then
+ minetest.chat_send_player(giver, 'error: cannot give an unknown item')
+ return
+ end
+ local receiverref = minetest.env:get_player_by_name(receiver)
+ if receiverref == nil then
+ minetest.chat_send_player(giver, receiver..' is not a known player')
+ return
+ end
+ local leftover = receiverref:get_inventory():add_item("main", itemstack)
+ if leftover:is_empty() then
+ partiality = ""
+ elseif leftover:get_count() == itemstack:get_count() then
+ partiality = "could not be "
+ else
+ partiality = "partially "
+ end
+ if giver == receiver then
+ minetest.chat_send_player(giver, '"'..stackstring
+ ..'" '..partiality..'added to inventory.');
+ else
+ minetest.chat_send_player(giver, '"'..stackstring
+ ..'" '..partiality..'added to '..receiver..'\'s inventory.');
+ minetest.chat_send_player(receiver, '"'..stackstring
+ ..'" '..partiality..'added to inventory.');
+ end
+end
+
minetest.register_on_chat_message(function(name, message)
--print("default on_chat_message: name="..dump(name).." message="..dump(message))
local cmd = "/giveme"
if message:sub(0, #cmd) == cmd then
- if not minetest.get_player_privs(name)["give"] then
- minetest.chat_send_player(name, "you don't have permission to give")
- return true -- Handled chat message
- end
local stackstring = string.match(message, cmd.." (.*)")
if stackstring == nil then
minetest.chat_send_player(name, 'usage: '..cmd..' stackstring')
return true -- Handled chat message
end
- print(cmd..' invoked, stackstring="'..stackstring..'"')
- local player = minetest.env:get_player_by_name(name)
- if player == nil then
- minetest.chat_send_player(name, name2..' is not a known player')
- return true -- Handled chat message
- end
- local added, error_msg = player:add_to_inventory(stackstring)
- if added then
- minetest.chat_send_player(name, '"'..stackstring
- ..'" added to inventory.');
- else
- minetest.chat_send_player(name, 'Could not give "'..stackstring
- ..'": '..error_msg);
- end
- return true -- Handled chat message
+ handle_give_command(cmd, name, name, stackstring)
+ return true
end
local cmd = "/give"
if message:sub(0, #cmd) == cmd then
- if not minetest.get_player_privs(name)["give"] then
- minetest.chat_send_player(name, "you don't have permission to give")
- return true -- Handled chat message
- end
- local name2, stackstring = string.match(message, cmd.." ([%a%d_-]+) (.*)")
- if name == nil or stackstring == nil then
+ local receiver, stackstring = string.match(message, cmd.." ([%a%d_-]+) (.*)")
+ if receiver == nil or stackstring == nil then
minetest.chat_send_player(name, 'usage: '..cmd..' name stackstring')
return true -- Handled chat message
end
- print(cmd..' invoked, name2="'..name2
- ..'" stackstring="'..stackstring..'"')
- local player = minetest.env:get_player_by_name(name2)
- if player == nil then
- minetest.chat_send_player(name, name2..' is not a known player')
- return true -- Handled chat message
- end
- local added, error_msg = player:add_to_inventory(stackstring)
- if added then
- minetest.chat_send_player(name, '"'..stackstring
- ..'" added to '..name2..'\'s inventory.');
- minetest.chat_send_player(name2, '"'..stackstring
- ..'" added to inventory.');
- else
- minetest.chat_send_player(name, 'Could not give "'..stackstring
- ..'": '..error_msg);
- end
- return true -- Handled chat message
+ handle_give_command(cmd, name, receiver, stackstring)
+ return true
end
local cmd = "/spawnentity"
if message:sub(0, #cmd) == cmd then
@@ -1520,6 +1811,10 @@ minetest.register_on_chat_message(function(name, message)
minetest.chat_send_player(name, "you don't have permission to spawn (give)")
return true -- Handled chat message
end
+ if not minetest.get_player_privs(name)["interact"] then
+ minetest.chat_send_player(name, "you don't have permission to interact")
+ return true -- Handled chat message
+ end
local entityname = string.match(message, cmd.." (.*)")
if entityname == nil then
minetest.chat_send_player(name, 'usage: '..cmd..' entityname')
@@ -1538,6 +1833,21 @@ minetest.register_on_chat_message(function(name, message)
..'" spawned.');
return true -- Handled chat message
end
+ local cmd = "/pulverize"
+ if message:sub(0, #cmd) == cmd then
+ local player = minetest.env:get_player_by_name(name)
+ if player == nil then
+ print("Unable to pulverize, player is nil")
+ return true -- Handled chat message
+ end
+ if player:get_wielded_item():is_empty() then
+ minetest.chat_send_player(name, 'Unable to pulverize, no item in hand.')
+ else
+ player:set_wielded_item(nil)
+ minetest.chat_send_player(name, 'An item was pulverized.')
+ end
+ return true
+ end
end)
--
diff --git a/data/mods/legacy/textures/mineral_coal.png b/data/mods/default/textures/default_mineral_coal.png
index 3ff9692fb..3ff9692fb 100644
--- a/data/mods/legacy/textures/mineral_coal.png
+++ b/data/mods/default/textures/default_mineral_coal.png
Binary files differ
diff --git a/data/mods/legacy/textures/mineral_iron.png b/data/mods/default/textures/default_mineral_iron.png
index 51b15d95d..51b15d95d 100644
--- a/data/mods/legacy/textures/mineral_iron.png
+++ b/data/mods/default/textures/default_mineral_iron.png
Binary files differ
diff --git a/data/mods/experimental/init.lua b/data/mods/experimental/init.lua
index 2aae9b199..9a8f8868d 100644
--- a/data/mods/experimental/init.lua
+++ b/data/mods/experimental/init.lua
@@ -4,6 +4,8 @@
-- For testing random stuff
+experimental = {}
+
function on_step(dtime)
-- print("experimental on_step")
--[[
@@ -20,11 +22,32 @@ function on_step(dtime)
end
end
--]]
+ --[[
+ if experimental.t1 == nil then
+ experimental.t1 = 0
+ end
+ experimental.t1 = experimental.t1 + dtime
+ if experimental.t1 >= 2 then
+ experimental.t1 = experimental.t1 - 2
+ minetest.log("time of day is "..minetest.env:get_timeofday())
+ if experimental.day then
+ minetest.log("forcing day->night")
+ experimental.day = false
+ minetest.env:set_timeofday(0.0)
+ else
+ minetest.log("forcing night->day")
+ experimental.day = true
+ minetest.env:set_timeofday(0.5)
+ end
+ minetest.log("time of day is "..minetest.env:get_timeofday())
+ end
+ --]]
end
minetest.register_globalstep(on_step)
-- An example furnace-thing implemented in Lua
+--[[
minetest.register_node("experimental:luafurnace", {
tile_images = {"default_lava.png", "default_furnace_side.png",
"default_furnace_side.png", "default_furnace_side.png",
@@ -56,15 +79,6 @@ minetest.register_on_placenode(function(pos, newnode, placer)
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({
nodenames = {"experimental:luafurnace"},
interval = 1.0,
@@ -176,7 +190,6 @@ minetest.register_abm({
inv:set_stack("fuel", 1, stack)
end,
})
---[[
minetest.register_abm({
nodenames = {"experimental:luafurnace"},
interval = 1.0,
@@ -231,7 +244,6 @@ minetest.register_abm({
meta:set_infotext("Lua Furnace: total cooked: "..total_cooked)
end,
})
---]]
minetest.register_craft({
output = 'node "experimental:luafurnace" 1',
recipe = {
@@ -240,6 +252,7 @@ minetest.register_craft({
{'node "default:cobble"', 'node "default:cobble"', 'node "default:cobble"'},
}
})
+--]]
--
-- Random stuff
@@ -261,38 +274,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)
--
minetest.register_craft({
- output = 'node "experimental:tnt" 4',
+ output = 'experimental:tnt',
recipe = {
- {'node "default:wood" 1'},
- {'craft "default:coal_lump" 1'},
- {'node "default:wood" 1'}
+ {'default:wood'},
+ {'default:coal_lump'},
+ {'default:wood'}
}
})
@@ -302,7 +293,7 @@ minetest.register_node("experimental:tnt", {
"default_tnt_side.png", "default_tnt_side.png"},
inventory_image = minetest.inventorycube("default_tnt_top.png",
"default_tnt_side.png", "default_tnt_side.png"),
- dug_item = '', -- Get nothing
+ drop = '', -- Get nothing
material = {
diggability = "not",
},
@@ -363,7 +354,7 @@ function TNT:on_punch(hitter)
self.health = self.health - 1
if self.health <= 0 then
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)
end
end
@@ -380,7 +371,7 @@ end
minetest.register_entity("experimental:tnt", TNT)
-- 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
@@ -547,6 +538,7 @@ minetest.register_abm({
end,
})--]]
+print("experimental modname="..dump(minetest.get_current_modname()))
print("experimental modpath="..dump(minetest.get_modpath("experimental")))
-- END
diff --git a/data/mods/give_initial_stuff/init.lua b/data/mods/give_initial_stuff/init.lua
index e52784d64..9cf6b51b5 100644
--- a/data/mods/give_initial_stuff/init.lua
+++ b/data/mods/give_initial_stuff/init.lua
@@ -2,11 +2,11 @@ minetest.register_on_newplayer(function(player)
print("on_newplayer")
if minetest.setting_getbool("give_initial_stuff") then
print("giving give_initial_stuff to player")
- player:add_to_inventory('tool "SteelPick" 0')
- player:add_to_inventory('node "torch" 99')
- player:add_to_inventory('tool "SteelAxe" 0')
- player:add_to_inventory('tool "SteelShovel" 0')
- player:add_to_inventory('node "cobble" 99')
+ player:get_inventory():add_item('main', 'default:pick_steel')
+ player:get_inventory():add_item('main', 'default:torch 99')
+ player:get_inventory():add_item('main', 'default:axe_steel')
+ player:get_inventory():add_item('main', 'default:shovel_steel')
+ player:get_inventory():add_item('main', 'default:cobble 99')
end
end)
diff --git a/data/mods/legacy/init.lua b/data/mods/legacy/init.lua
index 3bd68f0bc..7f9088ce0 100644
--- a/data/mods/legacy/init.lua
+++ b/data/mods/legacy/init.lua
@@ -5,97 +5,128 @@
-- Aliases to support loading 0.3 and old 0.4 worlds and inventories
--
-minetest.alias_node("stone", "default:stone")
-minetest.alias_node("dirt_with_grass", "default:dirt_with_grass")
-minetest.alias_node("dirt_with_grass_footsteps", "default:dirt_with_grass_footsteps")
-minetest.alias_node("dirt", "default:dirt")
-minetest.alias_node("sand", "default:sand")
-minetest.alias_node("gravel", "default:gravel")
-minetest.alias_node("sandstone", "default:sandstone")
-minetest.alias_node("clay", "default:clay")
-minetest.alias_node("brick", "default:brick")
-minetest.alias_node("tree", "default:tree")
-minetest.alias_node("jungletree", "default:jungletree")
-minetest.alias_node("junglegrass", "default:junglegrass")
-minetest.alias_node("leaves", "default:leaves")
-minetest.alias_node("cactus", "default:cactus")
-minetest.alias_node("papyrus", "default:papyrus")
-minetest.alias_node("bookshelf", "default:bookshelf")
-minetest.alias_node("glass", "default:glass")
-minetest.alias_node("wooden_fence", "default:fence_wood")
-minetest.alias_node("rail", "default:rail")
-minetest.alias_node("ladder", "default:ladder")
-minetest.alias_node("wood", "default:wood")
-minetest.alias_node("mese", "default:mese")
-minetest.alias_node("cloud", "default:cloud")
-minetest.alias_node("water_flowing", "default:water_flowing")
-minetest.alias_node("water_source", "default:water_source")
-minetest.alias_node("lava_flowing", "default:lava_flowing")
-minetest.alias_node("lava_source", "default:lava_source")
-minetest.alias_node("torch", "default:torch")
-minetest.alias_node("sign_wall", "default:sign_wall")
-minetest.alias_node("furnace", "default:furnace")
-minetest.alias_node("chest", "default:chest")
-minetest.alias_node("locked_chest", "default:chest_locked")
-minetest.alias_node("cobble", "default:cobble")
-minetest.alias_node("mossycobble", "default:mossycobble")
-minetest.alias_node("steelblock", "default:steelblock")
-minetest.alias_node("nyancat", "default:nyancat")
-minetest.alias_node("nyancat_rainbow", "default:nyancat_rainbow")
-minetest.alias_node("sapling", "default:sapling")
-minetest.alias_node("apple", "default:apple")
+minetest.register_alias("stone", "default:stone")
+minetest.register_alias("stone_with_coal", "default:stone_with_coal")
+minetest.register_alias("stone_with_iron", "default:stone_with_iron")
+minetest.register_alias("dirt_with_grass", "default:dirt_with_grass")
+minetest.register_alias("dirt_with_grass_footsteps", "default:dirt_with_grass_footsteps")
+minetest.register_alias("dirt", "default:dirt")
+minetest.register_alias("sand", "default:sand")
+minetest.register_alias("gravel", "default:gravel")
+minetest.register_alias("sandstone", "default:sandstone")
+minetest.register_alias("clay", "default:clay")
+minetest.register_alias("brick", "default:brick")
+minetest.register_alias("tree", "default:tree")
+minetest.register_alias("jungletree", "default:jungletree")
+minetest.register_alias("junglegrass", "default:junglegrass")
+minetest.register_alias("leaves", "default:leaves")
+minetest.register_alias("cactus", "default:cactus")
+minetest.register_alias("papyrus", "default:papyrus")
+minetest.register_alias("bookshelf", "default:bookshelf")
+minetest.register_alias("glass", "default:glass")
+minetest.register_alias("wooden_fence", "default:fence_wood")
+minetest.register_alias("rail", "default:rail")
+minetest.register_alias("ladder", "default:ladder")
+minetest.register_alias("wood", "default:wood")
+minetest.register_alias("mese", "default:mese")
+minetest.register_alias("cloud", "default:cloud")
+minetest.register_alias("water_flowing", "default:water_flowing")
+minetest.register_alias("water_source", "default:water_source")
+minetest.register_alias("lava_flowing", "default:lava_flowing")
+minetest.register_alias("lava_source", "default:lava_source")
+minetest.register_alias("torch", "default:torch")
+minetest.register_alias("sign_wall", "default:sign_wall")
+minetest.register_alias("furnace", "default:furnace")
+minetest.register_alias("chest", "default:chest")
+minetest.register_alias("locked_chest", "default:chest_locked")
+minetest.register_alias("cobble", "default:cobble")
+minetest.register_alias("mossycobble", "default:mossycobble")
+minetest.register_alias("steelblock", "default:steelblock")
+minetest.register_alias("nyancat", "default:nyancat")
+minetest.register_alias("nyancat_rainbow", "default:nyancat_rainbow")
+minetest.register_alias("sapling", "default:sapling")
+minetest.register_alias("apple", "default:apple")
-minetest.alias_tool("WPick", "default:pick_wood")
-minetest.alias_tool("STPick", "default:pick_stone")
-minetest.alias_tool("SteelPick", "default:pick_steel")
-minetest.alias_tool("MesePick", "default:pick_mese")
-minetest.alias_tool("WShovel", "default:shovel_wood")
-minetest.alias_tool("STShovel", "default:shovel_stone")
-minetest.alias_tool("SteelShovel", "default:shovel_steel")
-minetest.alias_tool("WAxe", "default:axe_wood")
-minetest.alias_tool("STAxe", "default:axe_stone")
-minetest.alias_tool("SteelAxe", "default:axe_steel")
-minetest.alias_tool("WSword", "default:sword_wood")
-minetest.alias_tool("STSword", "default:sword_stone")
-minetest.alias_tool("SteelSword", "default:sword_steel")
+minetest.register_alias("WPick", "default:pick_wood")
+minetest.register_alias("STPick", "default:pick_stone")
+minetest.register_alias("SteelPick", "default:pick_steel")
+minetest.register_alias("MesePick", "default:pick_mese")
+minetest.register_alias("WShovel", "default:shovel_wood")
+minetest.register_alias("STShovel", "default:shovel_stone")
+minetest.register_alias("SteelShovel", "default:shovel_steel")
+minetest.register_alias("WAxe", "default:axe_wood")
+minetest.register_alias("STAxe", "default:axe_stone")
+minetest.register_alias("SteelAxe", "default:axe_steel")
+minetest.register_alias("WSword", "default:sword_wood")
+minetest.register_alias("STSword", "default:sword_stone")
+minetest.register_alias("SteelSword", "default:sword_steel")
-minetest.alias_craftitem("Stick", "default:stick")
-minetest.alias_craftitem("paper", "default:paper")
-minetest.alias_craftitem("book", "default:book")
-minetest.alias_craftitem("lump_of_coal", "default:coal_lump")
-minetest.alias_craftitem("lump_of_iron", "default:iron_lump")
-minetest.alias_craftitem("lump_of_clay", "default:clay_lump")
-minetest.alias_craftitem("steel_ingot", "default:steel_ingot")
-minetest.alias_craftitem("clay_brick", "default:clay_brick")
-minetest.alias_craftitem("scorched_stuff", "default:scorched_stuff")
-minetest.alias_craftitem("apple", "default:apple")
+minetest.register_alias("Stick", "default:stick")
+minetest.register_alias("paper", "default:paper")
+minetest.register_alias("book", "default:book")
+minetest.register_alias("lump_of_coal", "default:coal_lump")
+minetest.register_alias("lump_of_iron", "default:iron_lump")
+minetest.register_alias("lump_of_clay", "default:clay_lump")
+minetest.register_alias("steel_ingot", "default:steel_ingot")
+minetest.register_alias("clay_brick", "default:clay_brick")
+minetest.register_alias("scorched_stuff", "default:scorched_stuff")
--
-- Old items
--
minetest.register_craftitem(":rat", {
- image = "rat.png",
- cookresult_itemstring = 'craft "cooked_rat" 1',
+ description = "Rat",
+ inventory_image = "rat.png",
on_drop = function(item, dropper, pos)
minetest.env:add_rat(pos)
- return true
+ item:take_item()
+ return item
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", {
- image = "cooked_rat.png",
- cookresult_itemstring = 'craft "scorched_stuff" 1',
- on_place_on_ground = minetest.craftitem_place_item,
- on_use = minetest.craftitem_eat(6),
+ description = "Cooked rat",
+ inventory_image = "cooked_rat.png",
+ on_use = minetest.item_eat(6),
})
minetest.register_craftitem(":firefly", {
- image = "firefly.png",
+ description = "Firefly",
+ inventory_image = "firefly.png",
on_drop = function(item, dropper, pos)
minetest.env:add_firefly(pos)
- return true
+ item:take_item()
+ return item
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
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index baf9fed5a..a736991b4 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -100,9 +100,8 @@ set(common_SRCS
content_abm.cpp
craftdef.cpp
nameidmapping.cpp
- tooldef.cpp
+ itemdef.cpp
nodedef.cpp
- craftitemdef.cpp
luaentity_common.cpp
scriptapi.cpp
script.cpp
@@ -117,7 +116,6 @@ set(common_SRCS
serverobject.cpp
serverlinkableobject.cpp
noise.cpp
- mineral.cpp
porting.cpp
materials.cpp
defaultsettings.cpp
diff --git a/src/camera.cpp b/src/camera.cpp
index c0e171468..b36daf1d7 100644
--- a/src/camera.cpp
+++ b/src/camera.cpp
@@ -27,7 +27,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "tile.h"
#include <cmath>
#include "settings.h"
-#include "nodedef.h" // For wield visualization
+#include "itemdef.h" // For wield visualization
Camera::Camera(scene::ISceneManager* smgr, MapDrawControl& draw_control):
m_smgr(smgr),
@@ -37,10 +37,9 @@ Camera::Camera(scene::ISceneManager* smgr, MapDrawControl& draw_control):
m_wieldmgr(NULL),
m_wieldnode(NULL),
+ m_wieldlight(0),
m_draw_control(draw_control),
- m_viewing_range_min(5.0),
- m_viewing_range_max(5.0),
m_camera_position(0,0,0),
m_camera_direction(0,0,0),
@@ -49,7 +48,6 @@ Camera::Camera(scene::ISceneManager* smgr, MapDrawControl& draw_control):
m_fov_x(1.0),
m_fov_y(1.0),
- m_wanted_frametime(0.0),
m_added_frametime(0),
m_added_frames(0),
m_range_old(0),
@@ -77,15 +75,13 @@ Camera::Camera(scene::ISceneManager* smgr, MapDrawControl& draw_control):
// all other 3D scene nodes and before the GUI.
m_wieldmgr = smgr->createNewSceneManager();
m_wieldmgr->addCameraSceneNode();
- m_wieldnode = new ExtrudedSpriteSceneNode(m_wieldmgr->getRootSceneNode(), m_wieldmgr);
-
- updateSettings();
+ m_wieldnode = m_wieldmgr->addMeshSceneNode(createCubeMesh(v3f(1,1,1)), NULL); // need a dummy mesh
}
Camera::~Camera()
{
+ m_wieldnode->setMesh(NULL);
m_wieldmgr->drop();
- m_wieldnode->drop();
}
bool Camera::successfullyCreated(std::wstring& error_message)
@@ -258,14 +254,17 @@ void Camera::update(LocalPlayer* player, f32 frametime, v2u32 screensize)
// *100.0 helps in large map coordinates
m_cameranode->setTarget(m_camera_position + 100 * m_camera_direction);
- // FOV and and aspect ratio
+ // Get FOV setting
+ f32 fov_degrees = g_settings->getFloat("fov");
+ fov_degrees = MYMAX(fov_degrees, 10.0);
+ fov_degrees = MYMIN(fov_degrees, 170.0);
+
+ // FOV and aspect ratio
m_aspect = (f32)screensize.X / (f32) screensize.Y;
+ m_fov_y = fov_degrees * PI / 180.0;
m_fov_x = 2 * atan(0.5 * m_aspect * tan(m_fov_y));
m_cameranode->setAspectRatio(m_aspect);
m_cameranode->setFOV(m_fov_y);
- // Just so big a value that everything rendered is visible
- // Some more allowance that m_viewing_range_max * BS because of active objects etc.
- m_cameranode->setFarValue(m_viewing_range_max * BS * 10);
// Position the wielded item
v3f wield_position = v3f(45, -35, 65);
@@ -292,7 +291,7 @@ void Camera::update(LocalPlayer* player, f32 frametime, v2u32 screensize)
}
m_wieldnode->setPosition(wield_position);
m_wieldnode->setRotation(wield_rotation);
- m_wieldnode->updateLight(player->light);
+ m_wieldlight = player->light;
// Render distance feedback loop
updateViewingRange(frametime);
@@ -342,7 +341,18 @@ void Camera::updateViewingRange(f32 frametime_in)
<<m_draw_control.blocks_would_have_drawn
<<std::endl;*/
- m_draw_control.wanted_min_range = m_viewing_range_min;
+ // Get current viewing range and FPS settings
+ f32 viewing_range_min = g_settings->getS16("viewing_range_nodes_min");
+ viewing_range_min = MYMAX(5.0, viewing_range_min);
+
+ f32 viewing_range_max = g_settings->getS16("viewing_range_nodes_max");
+ viewing_range_max = MYMAX(viewing_range_min, viewing_range_max);
+
+ f32 wanted_fps = g_settings->getFloat("wanted_fps");
+ wanted_fps = MYMAX(wanted_fps, 1.0);
+ f32 wanted_frametime = 1.0 / wanted_fps;
+
+ m_draw_control.wanted_min_range = viewing_range_min;
m_draw_control.wanted_max_blocks = (2.0*m_draw_control.blocks_would_have_drawn)+1;
if (m_draw_control.wanted_max_blocks < 10)
m_draw_control.wanted_max_blocks = 10;
@@ -361,13 +371,13 @@ void Camera::updateViewingRange(f32 frametime_in)
m_added_frametime = 0.0;
m_added_frames = 0;
- f32 wanted_frametime_change = m_wanted_frametime - frametime;
+ f32 wanted_frametime_change = wanted_frametime - frametime;
//dstream<<"wanted_frametime_change="<<wanted_frametime_change<<std::endl;
// If needed frametime change is small, just return
// This value was 0.4 for many months until 2011-10-18 by c55;
// Let's see how this works out.
- if (fabs(wanted_frametime_change) < m_wanted_frametime*0.33)
+ if (fabs(wanted_frametime_change) < wanted_frametime*0.33)
{
//dstream<<"ignoring small wanted_frametime_change"<<std::endl;
return;
@@ -420,8 +430,8 @@ void Camera::updateViewingRange(f32 frametime_in)
new_range += wanted_range_change;
//f32 new_range_unclamped = new_range;
- new_range = MYMAX(new_range, m_viewing_range_min);
- new_range = MYMIN(new_range, m_viewing_range_max);
+ new_range = MYMAX(new_range, viewing_range_min);
+ new_range = MYMIN(new_range, viewing_range_max);
/*dstream<<"new_range="<<new_range_unclamped
<<", clamped to "<<new_range<<std::endl;*/
@@ -429,82 +439,45 @@ void Camera::updateViewingRange(f32 frametime_in)
m_range_old = new_range;
m_frametime_old = frametime;
-}
-void Camera::updateSettings()
-{
- m_viewing_range_min = g_settings->getS16("viewing_range_nodes_min");
- m_viewing_range_min = MYMAX(5.0, m_viewing_range_min);
-
- m_viewing_range_max = g_settings->getS16("viewing_range_nodes_max");
- m_viewing_range_max = MYMAX(m_viewing_range_min, m_viewing_range_max);
-
- f32 fov_degrees = g_settings->getFloat("fov");
- fov_degrees = MYMAX(fov_degrees, 10.0);
- fov_degrees = MYMIN(fov_degrees, 170.0);
- m_fov_y = fov_degrees * PI / 180.0;
+ // Just so big a value that everything rendered is visible
+ // Some more allowance than viewing_range_max * BS because of active objects etc.
+ m_cameranode->setFarValue(viewing_range_max * BS * 10);
- f32 wanted_fps = g_settings->getFloat("wanted_fps");
- wanted_fps = MYMAX(wanted_fps, 1.0);
- m_wanted_frametime = 1.0 / wanted_fps;
}
-void Camera::wield(const InventoryItem* item, IGameDef *gamedef)
+void Camera::setDigging(s32 button)
{
- //ITextureSource *tsrc = gamedef->tsrc();
- INodeDefManager *ndef = gamedef->ndef();
+ if (m_digging_button == -1)
+ m_digging_button = button;
+}
- if (item != NULL)
+void Camera::wield(const ItemStack &item, IGameDef *gamedef)
+{
+ IItemDefManager *idef = gamedef->idef();
+ scene::IMesh *wield_mesh = item.getDefinition(idef).wield_mesh;
+ if(wield_mesh)
{
- 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->setMesh(wield_mesh);
m_wieldnode->setVisible(true);
}
else
{
- // Bare hands
- m_wieldnode->setSprite(gamedef->tsrc()->getTextureRaw("wieldhand.png"));
- m_wieldnode->setVisible(true);
+ m_wieldnode->setVisible(false);
}
}
-void Camera::setDigging(s32 button)
-{
- if (m_digging_button == -1)
- m_digging_button = button;
-}
-
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();
+ // Draw the wielded node (in a separate scene manager)
scene::ICameraSceneNode* cam = m_wieldmgr->getActiveCamera();
cam->setAspectRatio(m_cameranode->getAspectRatio());
cam->setFOV(m_cameranode->getFOV());
@@ -512,145 +485,3 @@ void Camera::drawWieldedTool()
cam->setFarValue(100);
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;
-}
diff --git a/src/camera.h b/src/camera.h
index d5789d807..7be8162b5 100644
--- a/src/camera.h
+++ b/src/camera.h
@@ -26,12 +26,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "tile.h"
#include "utility.h"
#include <ICameraSceneNode.h>
-#include <IMeshCache.h>
-#include <IAnimatedMesh.h>
class LocalPlayer;
struct MapDrawControl;
-class ExtrudedSpriteSceneNode;
class IGameDef;
/*
@@ -113,16 +110,13 @@ public:
// Render distance feedback loop
void updateViewingRange(f32 frametime_in);
- // Update settings from g_settings
- void updateSettings();
-
- // Replace the wielded item mesh
- void wield(const InventoryItem* item, IGameDef *gamedef);
-
// Start digging animation
// Pass 0 for left click, 1 for right click
void setDigging(s32 button);
+ // Replace the wielded item mesh
+ void wield(const ItemStack &item, IGameDef *gamedef);
+
// Draw the wielded tool.
// This has to happen *after* the main scene is drawn.
// Warning: This clears the Z buffer.
@@ -136,16 +130,12 @@ private:
scene::ICameraSceneNode* m_cameranode;
scene::ISceneManager* m_wieldmgr;
- ExtrudedSpriteSceneNode* m_wieldnode;
+ scene::IMeshSceneNode* m_wieldnode;
+ u8 m_wieldlight;
// draw control
MapDrawControl& m_draw_control;
- // viewing_range_min_nodes setting
- f32 m_viewing_range_min;
- // viewing_range_max_nodes setting
- f32 m_viewing_range_max;
-
// Absolute camera position
v3f m_camera_position;
// Absolute camera direction
@@ -157,7 +147,6 @@ private:
f32 m_fov_y;
// Stuff for viewing range calculations
- f32 m_wanted_frametime;
f32 m_added_frametime;
s16 m_added_frames;
f32 m_range_old;
@@ -182,46 +171,4 @@ private:
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
diff --git a/src/client.cpp b/src/client.cpp
index 38ed14978..0463aa81c 100644
--- a/src/client.cpp
+++ b/src/client.cpp
@@ -33,8 +33,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "log.h"
#include "nodemetadata.h"
#include "nodedef.h"
-#include "tooldef.h"
-#include "craftitemdef.h"
+#include "itemdef.h"
#include <IFileSystem.h>
#include "sha1.h"
#include "base64.h"
@@ -207,14 +206,12 @@ Client::Client(
std::string password,
MapDrawControl &control,
IWritableTextureSource *tsrc,
- IWritableToolDefManager *tooldef,
- IWritableNodeDefManager *nodedef,
- IWritableCraftItemDefManager *craftitemdef
+ IWritableItemDefManager *itemdef,
+ IWritableNodeDefManager *nodedef
):
m_tsrc(tsrc),
- m_tooldef(tooldef),
+ m_itemdef(itemdef),
m_nodedef(nodedef),
- m_craftitemdef(craftitemdef),
m_mesh_update_thread(this),
m_env(
new ClientMap(this, this, control,
@@ -228,15 +225,16 @@ Client::Client(
m_server_ser_ver(SER_FMT_VER_INVALID),
m_playeritem(0),
m_inventory_updated(false),
+ m_inventory_from_server(NULL),
+ m_inventory_from_server_age(0.0),
m_time_of_day(0),
m_map_seed(0),
m_password(password),
m_access_denied(false),
m_texture_receive_progress(0),
m_textures_received(false),
- m_tooldef_received(false),
- m_nodedef_received(false),
- m_craftitemdef_received(false)
+ m_itemdef_received(false),
+ m_nodedef_received(false)
{
m_packetcounter_timer = 0.0;
//m_delete_unused_sectors_timer = 0.0;
@@ -251,12 +249,6 @@ Client::Client(
else
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
*/
@@ -266,9 +258,6 @@ Client::Client(
player->updateName(playername);
m_env.addPlayer(player);
-
- // Initialize player in the inventory context
- m_inventory_context.current_player = player;
}
}
@@ -282,6 +271,8 @@ Client::~Client()
m_mesh_update_thread.setRun(false);
while(m_mesh_update_thread.IsRunning())
sleep_ms(100);
+
+ delete m_inventory_from_server;
}
void Client::connect(Address address)
@@ -670,6 +661,30 @@ void Client::step(float dtime)
}
}
}
+
+ /*
+ If the server didn't update the inventory in a while, revert
+ the local inventory (so the player notices the lag problem
+ and knows something is wrong).
+ */
+ if(m_inventory_from_server)
+ {
+ float interval = 10.0;
+ float count_before = floor(m_inventory_from_server_age / interval);
+
+ m_inventory_from_server_age += dtime;
+
+ float count_after = floor(m_inventory_from_server_age / interval);
+
+ if(count_after != count_before)
+ {
+ // Do this every <interval> seconds after TOCLIENT_INVENTORY
+ // Reset the locally changed inventory to the authoritative inventory
+ Player *player = m_env.getLocalPlayer();
+ player->inventory = *m_inventory_from_server;
+ m_inventory_updated = true;
+ }
+ }
}
// Virtual methods from con::PeerHandler
@@ -912,7 +927,7 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
Update an existing block
*/
//infostream<<"Updating"<<std::endl;
- block->deSerialize(istr, ser_version);
+ block->deSerialize(istr, ser_version, false);
}
else
{
@@ -921,7 +936,7 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
*/
//infostream<<"Creating new"<<std::endl;
block = new MapBlock(&m_env.getMap(), p, this);
- block->deSerialize(istr, ser_version);
+ block->deSerialize(istr, ser_version, false);
sector->insertBlock(block);
}
@@ -983,11 +998,15 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
//t4.stop();
//TimeTaker t1("inventory.deSerialize()", m_device);
- player->inventory.deSerialize(is, this);
+ player->inventory.deSerialize(is);
//t1.stop();
m_inventory_updated = true;
+ delete m_inventory_from_server;
+ m_inventory_from_server = new Inventory(player->inventory);
+ m_inventory_from_server_age = 0.0;
+
//infostream<<"Client got player inventory:"<<std::endl;
//player->inventory.print(infostream);
}
@@ -1216,18 +1235,18 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
} else {
InventoryList *inv = player->inventory.getList("main");
std::string itemstring(deSerializeString(is));
- if (itemstring.empty()) {
- inv->deleteItem(0);
- infostream
- <<"Client: empty player item for peer "
- << peer_id << std::endl;
- } else {
- std::istringstream iss(itemstring);
- delete inv->changeItem(0,
- InventoryItem::deSerialize(iss, this));
- infostream<<"Client: player item for peer " << peer_id << ": ";
- player->getWieldItem()->serialize(infostream);
- infostream<<std::endl;
+ ItemStack item;
+ item.deSerialize(itemstring, m_itemdef);
+ inv->changeItem(0, item);
+ if(itemstring.empty())
+ {
+ infostream<<"Client: empty player item for peer "
+ <<peer_id<<std::endl;
+ }
+ else
+ {
+ infostream<<"Client: player item for peer "
+ <<peer_id<<": "<<itemstring<<std::endl;
}
}
}
@@ -1256,14 +1275,9 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
std::string datastring((char*)&data[2], datasize-2);
std::istringstream is(datastring, std::ios_base::binary);
-
- // 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();
- }
+ // Mesh update thread must be stopped while
+ // updating content definitions
+ assert(!m_mesh_update_thread.IsRunning());
int num_textures = readU16(is);
@@ -1362,9 +1376,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;
event.type = CE_TEXTURES_UPDATED;
@@ -1412,14 +1423,10 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
std::string datastring((char*)&data[2], datasize-2);
std::istringstream is(datastring, std::ios_base::binary);
- // 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();
- }
-
+ // Mesh update thread must be stopped while
+ // updating content definitions
+ assert(!m_mesh_update_thread.IsRunning());
+
/*
u16 command
u16 total number of texture bunches
@@ -1484,22 +1491,6 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
img->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;
event.type = CE_TEXTURES_UPDATED;
@@ -1507,82 +1498,53 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
}
else if(command == TOCLIENT_TOOLDEF)
{
- infostream<<"Client: Received tool definitions: packet size: "
- <<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();
+ infostream<<"Client: WARNING: Ignoring TOCLIENT_TOOLDEF"<<std::endl;
}
else if(command == TOCLIENT_NODEDEF)
{
infostream<<"Client: Received node definitions: packet size: "
<<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::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);
- m_nodedef->deSerialize(tmp_is, this);
-
- 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);
- }
+ std::ostringstream tmp_os;
+ decompressZlib(tmp_is, tmp_os);
- // Resume threads
- m_mesh_update_thread.setRun(true);
- m_mesh_update_thread.Start();
+ // Deserialize node definitions
+ std::istringstream tmp_is2(tmp_os.str());
+ m_nodedef->deSerialize(tmp_is2);
+ m_nodedef_received = true;
}
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;
+ // 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::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);
- m_craftitemdef->deSerialize(tmp_is);
-
- // Resume threads
- m_mesh_update_thread.setRun(true);
- m_mesh_update_thread.Start();
+ std::ostringstream tmp_os;
+ decompressZlib(tmp_is, tmp_os);
+
+ // Deserialize node definitions
+ std::istringstream tmp_is2(tmp_os.str());
+ m_itemdef->deSerialize(tmp_is2);
+ m_itemdef_received = true;
}
else
{
@@ -1886,8 +1848,7 @@ void Client::addNode(v3s16 p, MapNode n)
try
{
//TimeTaker timer3("Client::addNode(): addNodeAndUpdate");
- std::string st = std::string("");
- m_env.getMap().addNodeAndUpdate(p, n, modified_blocks, st);
+ m_env.getMap().addNodeAndUpdate(p, n, modified_blocks);
}
catch(InvalidPositionException &e)
{}
@@ -1943,11 +1904,6 @@ void Client::selectPlayerItem(u16 item)
//JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
m_playeritem = item;
m_inventory_updated = true;
-
- LocalPlayer *player = m_env.getLocalPlayer();
- assert(player != NULL);
- player->wieldItem(item);
-
sendPlayerItem(item);
}
@@ -1971,17 +1927,19 @@ void Client::getLocalInventory(Inventory &dst)
dst = player->inventory;
}
-InventoryContext *Client::getInventoryContext()
-{
- return &m_inventory_context;
-}
-
Inventory* Client::getInventory(const InventoryLocation &loc)
{
switch(loc.type){
case InventoryLocation::UNDEFINED:
{}
break;
+ case InventoryLocation::CURRENT_PLAYER:
+ {
+ Player *player = m_env.getLocalPlayer();
+ assert(player != NULL);
+ return &player->inventory;
+ }
+ break;
case InventoryLocation::PLAYER:
{
Player *player = m_env.getPlayer(loc.name.c_str());
@@ -2003,39 +1961,17 @@ Inventory* Client::getInventory(const InventoryLocation &loc)
}
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)
{
+ /*
+ Send it to the server
+ */
sendInventoryAction(a);
+
+ /*
+ Predict some local inventory changes
+ */
+ a->clientApply(this, this);
}
ClientActiveObject * Client::getSelectedActiveObject(
@@ -2234,6 +2170,32 @@ ClientEvent Client::getClientEvent()
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)
{
try{
@@ -2245,9 +2207,9 @@ float Client::getRTT(void)
// IGameDef interface
// Under envlock
-IToolDefManager* Client::getToolDefManager()
+IItemDefManager* Client::getItemDefManager()
{
- return m_tooldef;
+ return m_itemdef;
}
INodeDefManager* Client::getNodeDefManager()
{
@@ -2258,10 +2220,6 @@ ICraftDefManager* Client::getCraftDefManager()
return NULL;
//return m_craftdef;
}
-ICraftItemDefManager* Client::getCraftItemDefManager()
-{
- return m_craftitemdef;
-}
ITextureSource* Client::getTextureSource()
{
return m_tsrc;
diff --git a/src/client.h b/src/client.h
index 49794acf5..efdf315f7 100644
--- a/src/client.h
+++ b/src/client.h
@@ -36,10 +36,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
struct MeshMakeData;
class IGameDef;
class IWritableTextureSource;
-class IWritableToolDefManager;
+class IWritableItemDefManager;
class IWritableNodeDefManager;
//class IWritableCraftDefManager;
-class IWritableCraftItemDefManager;
class ClientNotReadyException : public BaseException
{
@@ -167,9 +166,8 @@ public:
std::string password,
MapDrawControl &control,
IWritableTextureSource *tsrc,
- IWritableToolDefManager *tooldef,
- IWritableNodeDefManager *nodedef,
- IWritableCraftItemDefManager *craftitemdef
+ IWritableItemDefManager *itemdef,
+ IWritableNodeDefManager *nodedef
);
~Client();
@@ -245,11 +243,8 @@ public:
// Copies the inventory of the local player to parameter
void getLocalInventory(Inventory &dst);
- InventoryContext *getInventoryContext();
-
/* InventoryManager interface */
Inventory* getInventory(const InventoryLocation &loc);
- //Inventory* getInventory(InventoryContext *c, std::string id);
void inventoryAction(InventoryAction *a);
// Gets closest object pointed by the shootline
@@ -323,20 +318,19 @@ public:
bool texturesReceived()
{ return m_textures_received; }
- bool tooldefReceived()
- { return m_tooldef_received; }
+ bool itemdefReceived()
+ { return m_itemdef_received; }
bool nodedefReceived()
{ return m_nodedef_received; }
- bool craftitemdefReceived()
- { return m_craftitemdef_received; }
+ void afterContentReceived();
+
float getRTT(void);
// IGameDef interface
- virtual IToolDefManager* getToolDefManager();
+ virtual IItemDefManager* getItemDefManager();
virtual INodeDefManager* getNodeDefManager();
virtual ICraftDefManager* getCraftDefManager();
- virtual ICraftItemDefManager* getCraftItemDefManager();
virtual ITextureSource* getTextureSource();
virtual u16 allocateUnknownNodeId(const std::string &name);
@@ -363,9 +357,8 @@ private:
IntervalLimiter m_map_timer_and_unload_interval;
IWritableTextureSource *m_tsrc;
- IWritableToolDefManager *m_tooldef;
+ IWritableItemDefManager *m_itemdef;
IWritableNodeDefManager *m_nodedef;
- IWritableCraftItemDefManager *m_craftitemdef;
MeshUpdateThread m_mesh_update_thread;
ClientEnvironment m_env;
con::Connection m_con;
@@ -374,6 +367,8 @@ private:
u8 m_server_ser_ver;
u16 m_playeritem;
bool m_inventory_updated;
+ Inventory *m_inventory_from_server;
+ float m_inventory_from_server_age;
core::map<v3s16, bool> m_active_blocks;
PacketCounter m_packetcounter;
// Received from the server. 0-23999
@@ -387,13 +382,11 @@ private:
std::string m_password;
bool m_access_denied;
std::wstring m_access_denied_reason;
- InventoryContext m_inventory_context;
Queue<ClientEvent> m_client_event_queue;
float m_texture_receive_progress;
bool m_textures_received;
- bool m_tooldef_received;
+ bool m_itemdef_received;
bool m_nodedef_received;
- bool m_craftitemdef_received;
friend class FarMesh;
};
diff --git a/src/clientserver.h b/src/clientserver.h
index 43de689e4..acb4f8530 100644
--- a/src/clientserver.h
+++ b/src/clientserver.h
@@ -39,9 +39,14 @@ with this program; if not, write to the Free Software Foundation, Inc.,
Make players to be handled mostly as ActiveObjects
PROTOCOL_VERSION 6:
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
@@ -252,6 +257,14 @@ enum ToClientCommand
string sha1_digest
}
*/
+
+ TOCLIENT_ITEMDEF = 0x3d,
+ /*
+ u16 command
+ u32 length of next item
+ serialized ItemDefManager
+ */
+
};
enum ToServerCommand
diff --git a/src/connection.cpp b/src/connection.cpp
index b9c5d2ac8..8f308c99f 100644
--- a/src/connection.cpp
+++ b/src/connection.cpp
@@ -666,7 +666,7 @@ void Connection::send(float dtime)
// Receive packets from the network and buffers and create ConnectionEvents
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.
// For now, just assume there are no other than the base headers.
u32 packet_maxsize = datasize + BASE_HEADER_SIZE;
@@ -854,10 +854,6 @@ void Connection::receive()
dout_con<<"ProcessPacket returned data of size "
<<resultdata.getSize()<<std::endl;
- if(datasize < resultdata.getSize())
- throw InvalidIncomingDataException
- ("Buffer too small for received data");
-
ConnectionEvent e;
e.dataReceived(peer_id, resultdata);
putEvent(e);
diff --git a/src/content_cao.cpp b/src/content_cao.cpp
index 83f1cedff..37da0f67d 100644
--- a/src/content_cao.cpp
+++ b/src/content_cao.cpp
@@ -20,6 +20,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "content_cao.h"
#include "tile.h"
#include "environment.h"
+#include "collision.h"
#include "settings.h"
#include <ICameraSceneNode.h>
#include <ITextSceneNode.h>
@@ -172,6 +173,8 @@ public:
void updateLight(u8 light_at_pos);
v3s16 getLightPosition();
void updateNodePos();
+ void updateInfoText();
+ void updateTexture();
void step(float dtime, ClientEnvironment *env);
@@ -191,7 +194,7 @@ private:
core::aabbox3d<f32> m_selection_box;
scene::IMeshSceneNode *m_node;
v3f m_position;
- std::string m_inventorystring;
+ std::string m_itemstring;
std::string m_infotext;
};
@@ -595,39 +598,13 @@ void ItemCAO::addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc,
buf->drop();
m_node = smgr->addMeshSceneNode(mesh, NULL);
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();
/*
Update image of node
*/
- // Create an inventory item to see what is its image
- 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);
+ updateTexture();
}
void ItemCAO::removeFromScene()
@@ -662,6 +639,51 @@ void ItemCAO::updateNodePos()
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)
{
if(m_node)
@@ -689,6 +711,13 @@ void ItemCAO::processMessage(const std::string &data)
m_position = readV3F1000(is);
updateNodePos();
}
+ if(cmd == 1)
+ {
+ // itemstring
+ m_itemstring = deSerializeString(is);
+ updateInfoText();
+ updateTexture();
+ }
}
void ItemCAO::initialize(const std::string &data)
@@ -704,28 +733,12 @@ void ItemCAO::initialize(const std::string &data)
return;
// pos
m_position = readV3F1000(is);
- // inventorystring
- m_inventorystring = deSerializeString(is);
+ // itemstring
+ m_itemstring = deSerializeString(is);
}
updateNodePos();
-
- /*
- 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 + "'";
- }
+ updateInfoText();
}
/*
diff --git a/src/content_mapblock.cpp b/src/content_mapblock.cpp
index e8e4fd231..dc1e1daed 100644
--- a/src/content_mapblock.cpp
+++ b/src/content_mapblock.cpp
@@ -20,112 +20,105 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "content_mapblock.h"
#include "main.h" // For g_settings
-#include "mineral.h"
-#include "mapblock_mesh.h" // For MapBlock_LightColor()
+#include "mapblock_mesh.h" // For MapBlock_LightColor() and MeshCollector
#include "settings.h"
#include "nodedef.h"
+#include "tile.h"
#include "gamedef.h"
-#ifndef SERVER
// Create a cuboid.
-// material - the material to use (for all 6 faces)
// 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
-// 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
// for the opposite corners of each face - therefore, there
// should be (2+2)*6=24 values in the list. Alternatively, pass
// NULL to use the entire texture for each face. The order of
-// the faces in the list is top-backi-right-front-left-bottom
-// If you specified 0,0,1,1 for each face, that would be the
-// same as passing NULL.
-void makeCuboid(video::SMaterial &material, MeshCollector *collector,
- AtlasPointer* pa, video::SColor &c,
- v3f &pos, f32 rx, f32 ry, f32 rz, f32* txc)
+// the faces in the list is up-down-right-left-back-front
+// (compatible with ContentFeatures). If you specified 0,0,1,1
+// for each face, that would be the same as passing NULL.
+void makeCuboid(MeshCollector *collector, const aabb3f &box,
+ const video::SMaterial *materials, const AtlasPointer *pa, int matcount,
+ video::SColor &c, const f32* txc)
{
- f32 tu0=pa->x0();
- f32 tu1=pa->x1();
- f32 tv0=pa->y0();
- f32 tv1=pa->y1();
- f32 txus=tu1-tu0;
- f32 txvs=tv1-tv0;
-
- video::S3DVertex v[4] =
+ assert(matcount >= 1);
+
+ v3f min = box.MinEdge;
+ v3f max = box.MaxEdge;
+
+ if(txc == NULL)
{
- video::S3DVertex(0,0,0, 0,0,0, c, tu0, tv1),
- video::S3DVertex(0,0,0, 0,0,0, c, tu1, tv1),
- video::S3DVertex(0,0,0, 0,0,0, c, tu1, tv0),
- video::S3DVertex(0,0,0, 0,0,0, c, tu0, tv0)
- };
+ static const f32 txc_default[24] = {
+ 0,0,1,1,
+ 0,0,1,1,
+ 0,0,1,1,
+ 0,0,1,1,
+ 0,0,1,1,
+ 0,0,1,1
+ };
+ txc = txc_default;
+ }
- for(int i=0;i<6;i++)
+ video::S3DVertex vertices[24] =
{
- switch(i)
- {
- 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;
- }
+ // 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(max.X,max.Y,max.Z, 0,0,1, c, txc[16],txc[17]),
+ video::S3DVertex(min.X,max.Y,max.Z, 0,0,1, c, txc[18],txc[17]),
+ video::S3DVertex(min.X,min.Y,max.Z, 0,0,1, c, txc[18],txc[19]),
+ video::S3DVertex(max.X,min.Y,max.Z, 0,0,1, c, txc[16],txc[19]),
+ // front
+ video::S3DVertex(min.X,max.Y,min.Z, 0,0,-1, c, txc[20],txc[21]),
+ video::S3DVertex(max.X,max.Y,min.Z, 0,0,-1, c, txc[22],txc[21]),
+ video::S3DVertex(max.X,min.Y,min.Z, 0,0,-1, c, txc[22],txc[23]),
+ video::S3DVertex(min.X,min.Y,min.Z, 0,0,-1, c, txc[20],txc[23]),
+ };
- 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(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;
+ }
- 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);
+ 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);
}
-
}
-#endif
-#ifndef SERVER
void mapblock_mesh_generate_special(MeshMakeData *data,
MeshCollector &collector, IGameDef *gamedef)
{
INodeDefManager *nodedef = gamedef->ndef();
+ ITextureSource *tsrc = gamedef->getTextureSource();
// 0ms
//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_FOG_ENABLE, true);
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);
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_FOG_ENABLE, true);
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);
u8 l = decode_light(undiminish_light(n.getLightBlend(data->m_daynight_ratio, nodedef)));
video::SColor c = MapBlock_LightColor(255, l);
- for(u32 j=0; j<6; j++)
- {
- video::S3DVertex vertices[4] =
- {
- video::S3DVertex(-BS/2,-BS/2,BS/2, 0,0,0, c,
- pa_leaves1.x0(), pa_leaves1.y1()),
- video::S3DVertex(BS/2,-BS/2,BS/2, 0,0,0, c,
- 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);
- }
+ v3f pos = intToFloat(p+blockpos_nodes, BS);
+ aabb3f box(-BS/2,-BS/2,-BS/2,BS/2,BS/2,BS/2);
+ box.MinEdge += pos;
+ box.MaxEdge += pos;
+ makeCuboid(&collector, box,
+ &material_leaves1, &pa_leaves1, 1,
+ c, NULL);
break;}
case NDT_ALLFACES_OPTIONAL:
// This is always pre-converted to something else
@@ -640,7 +602,7 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
break;
case NDT_TORCHLIKE:
{
- v3s16 dir = unpackDir(n.param2);
+ v3s16 dir = n.getWallMountedDir(nodedef);
AtlasPointer ap(0);
if(dir == v3s16(0,-1,0)){
@@ -732,7 +694,7 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
ap.x0(), ap.y1()),
};
- v3s16 dir = unpackDir(n.param2);
+ v3s16 dir = n.getWallMountedDir(nodedef);
for(s32 i=0; i<4; i++)
{
@@ -824,9 +786,22 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
material_wood.setFlag(video::EMF_BILINEAR_FILTER, false);
material_wood.setFlag(video::EMF_FOG_ENABLE, true);
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);
+ 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)));
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_len=(f32)(BS/2)-post_rad;
- // The post - always present
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]={
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.4,0.4,0.6,0.6};
- makeCuboid(material_wood, &collector,
- &pa_wood, c, pos,
- post_rad,BS/2,post_rad, postuv);
+ 0.35,0,0.65,1};
+ makeCuboid(&collector, post, &material_wood,
+ &pa_wood, 1, c, postuv);
// Now a section of fence, +X, if there's a post there
v3s16 p2 = p;
@@ -854,9 +832,10 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
const ContentFeatures *f2 = &nodedef->get(n2);
if(f2->drawtype == NDT_FENCELIKE)
{
- pos = intToFloat(p+blockpos_nodes, BS);
- pos.X += BS/2;
- pos.Y += BS/4;
+ aabb3f bar(-bar_len+BS/2,-bar_rad+BS/4,-bar_rad,
+ bar_len+BS/2,bar_rad+BS/4,bar_rad);
+ bar.MinEdge += pos;
+ bar.MaxEdge += pos;
f32 xrailuv[24]={
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};
- makeCuboid(material_wood, &collector,
- &pa_wood, c, pos,
- bar_len,bar_rad,bar_rad, xrailuv);
-
- pos.Y -= BS/2;
- makeCuboid(material_wood, &collector,
- &pa_wood, c, pos,
- bar_len,bar_rad,bar_rad, xrailuv);
+ makeCuboid(&collector, bar, &material_wood_nomod,
+ &pa_wood_nomod, 1, c, xrailuv);
+ bar.MinEdge.Y -= BS/2;
+ bar.MaxEdge.Y -= BS/2;
+ makeCuboid(&collector, bar, &material_wood_nomod,
+ &pa_wood_nomod, 1, c, xrailuv);
}
// 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);
if(f2->drawtype == NDT_FENCELIKE)
{
- pos = intToFloat(p+blockpos_nodes, BS);
- pos.Z += BS/2;
- pos.Y += BS/4;
+ aabb3f bar(-bar_rad,-bar_rad+BS/4,-bar_len+BS/2,
+ bar_rad,bar_rad+BS/4,bar_len+BS/2);
+ bar.MinEdge += pos;
+ bar.MaxEdge += pos;
f32 zrailuv[24]={
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};
- 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;}
case NDT_RAILLIKE:
@@ -1011,5 +988,4 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
}
}
}
-#endif
diff --git a/src/content_mapnode.cpp b/src/content_mapnode.cpp
index a74760ba3..ce7ee593f 100644
--- a/src/content_mapnode.cpp
+++ b/src/content_mapnode.cpp
@@ -27,80 +27,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#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
Ranges:
0x000...0x07f (0...127): param2 is fully usable
126 and 127 are reserved (CONTENT_AIR and CONTENT_IGNORE).
- 0x800...0xfff (2048...4095): higher 4 bytes of param2 are not usable
+ 0x800...0xfff (2048...4095): higher 4 bits of param2 are not usable
*/
#define CONTENT_STONE 0
#define CONTENT_WATER 2
@@ -209,46 +140,46 @@ MapNode mapnode_translate_to_internal(MapNode n_from, u8 version)
void content_mapnode_get_name_id_mapping(NameIdMapping *nimap)
{
- nimap->set(0, "stone");
- nimap->set(2, "water_flowing");
- nimap->set(3, "torch");
- nimap->set(9, "water_source");
- nimap->set(14, "sign_wall");
- nimap->set(15, "chest");
- nimap->set(16, "furnace");
- nimap->set(17, "locked_chest");
- nimap->set(21, "wooden_fence");
- nimap->set(30, "rail");
- nimap->set(31, "ladder");
- nimap->set(32, "lava_flowing");
- nimap->set(33, "lava_source");
- nimap->set(0x800, "dirt_with_grass");
- nimap->set(0x801, "tree");
- nimap->set(0x802, "leaves");
- nimap->set(0x803, "dirt_with_grass_footsteps");
- nimap->set(0x804, "mese");
- nimap->set(0x805, "dirt");
- nimap->set(0x806, "cloud");
- nimap->set(0x807, "coalstone");
- nimap->set(0x808, "wood");
- nimap->set(0x809, "sand");
- nimap->set(0x80a, "cobble");
- nimap->set(0x80b, "steel");
- nimap->set(0x80c, "glass");
- nimap->set(0x80d, "mossycobble");
- nimap->set(0x80e, "gravel");
- nimap->set(0x80f, "sandstone");
- nimap->set(0x810, "cactus");
- nimap->set(0x811, "brick");
- nimap->set(0x812, "clay");
- nimap->set(0x813, "papyrus");
- nimap->set(0x814, "bookshelf");
- nimap->set(0x815, "jungletree");
- nimap->set(0x816, "junglegrass");
- nimap->set(0x817, "nyancat");
- nimap->set(0x818, "nyancat_rainbow");
- nimap->set(0x819, "apple");
- nimap->set(0x820, "sapling");
+ nimap->set(0, "default:stone");
+ nimap->set(2, "default:water_flowing");
+ nimap->set(3, "default:torch");
+ nimap->set(9, "default:water_source");
+ nimap->set(14, "default:sign_wall");
+ nimap->set(15, "default:chest");
+ nimap->set(16, "default:furnace");
+ nimap->set(17, "default:chest_locked");
+ nimap->set(21, "default:fence_wood");
+ nimap->set(30, "default:rail");
+ nimap->set(31, "default:ladder");
+ nimap->set(32, "default:lava_flowing");
+ nimap->set(33, "default:lava_source");
+ nimap->set(0x800, "default:dirt_with_grass");
+ nimap->set(0x801, "default:tree");
+ nimap->set(0x802, "default:leaves");
+ nimap->set(0x803, "default:dirt_with_grass_footsteps");
+ nimap->set(0x804, "default:mese");
+ nimap->set(0x805, "default:dirt");
+ nimap->set(0x806, "default:cloud");
+ nimap->set(0x807, "default:coalstone");
+ nimap->set(0x808, "default:wood");
+ nimap->set(0x809, "default:sand");
+ nimap->set(0x80a, "default:cobble");
+ nimap->set(0x80b, "default:steelblock");
+ nimap->set(0x80c, "default:glass");
+ nimap->set(0x80d, "default:mossycobble");
+ nimap->set(0x80e, "default:gravel");
+ nimap->set(0x80f, "default:sandstone");
+ nimap->set(0x810, "default:cactus");
+ nimap->set(0x811, "default:brick");
+ nimap->set(0x812, "default:clay");
+ nimap->set(0x813, "default:papyrus");
+ nimap->set(0x814, "default:bookshelf");
+ nimap->set(0x815, "default:jungletree");
+ nimap->set(0x816, "default:junglegrass");
+ nimap->set(0x817, "default:nyancat");
+ nimap->set(0x818, "default:nyancat_rainbow");
+ nimap->set(0x819, "default:apple");
+ nimap->set(0x820, "default:sapling");
// Static types
nimap->set(CONTENT_IGNORE, "ignore");
nimap->set(CONTENT_AIR, "air");
@@ -259,46 +190,46 @@ class NewNameGetter
public:
NewNameGetter()
{
- old_to_new["CONTENT_STONE"] = "stone";
- old_to_new["CONTENT_WATER"] = "water_flowing";
- old_to_new["CONTENT_TORCH"] = "torch";
- old_to_new["CONTENT_WATERSOURCE"] = "water_source";
- old_to_new["CONTENT_SIGN_WALL"] = "sign_wall";
- old_to_new["CONTENT_CHEST"] = "chest";
- old_to_new["CONTENT_FURNACE"] = "furnace";
- old_to_new["CONTENT_LOCKABLE_CHEST"] = "locked_chest";
- old_to_new["CONTENT_FENCE"] = "wooden_fence";
- old_to_new["CONTENT_RAIL"] = "rail";
- old_to_new["CONTENT_LADDER"] = "ladder";
- old_to_new["CONTENT_LAVA"] = "lava_flowing";
- old_to_new["CONTENT_LAVASOURCE"] = "lava_source";
- old_to_new["CONTENT_GRASS"] = "dirt_with_grass";
- old_to_new["CONTENT_TREE"] = "tree";
- old_to_new["CONTENT_LEAVES"] = "leaves";
- old_to_new["CONTENT_GRASS_FOOTSTEPS"] = "dirt_with_grass_footsteps";
- old_to_new["CONTENT_MESE"] = "mese";
- old_to_new["CONTENT_MUD"] = "dirt";
- old_to_new["CONTENT_CLOUD"] = "cloud";
- old_to_new["CONTENT_COALSTONE"] = "coalstone";
- old_to_new["CONTENT_WOOD"] = "wood";
- old_to_new["CONTENT_SAND"] = "sand";
- old_to_new["CONTENT_COBBLE"] = "cobble";
- old_to_new["CONTENT_STEEL"] = "steel";
- old_to_new["CONTENT_GLASS"] = "glass";
- old_to_new["CONTENT_MOSSYCOBBLE"] = "mossycobble";
- old_to_new["CONTENT_GRAVEL"] = "gravel";
- old_to_new["CONTENT_SANDSTONE"] = "sandstone";
- old_to_new["CONTENT_CACTUS"] = "cactus";
- old_to_new["CONTENT_BRICK"] = "brick";
- old_to_new["CONTENT_CLAY"] = "clay";
- old_to_new["CONTENT_PAPYRUS"] = "papyrus";
- old_to_new["CONTENT_BOOKSHELF"] = "bookshelf";
- old_to_new["CONTENT_JUNGLETREE"] = "jungletree";
- old_to_new["CONTENT_JUNGLEGRASS"] = "junglegrass";
- old_to_new["CONTENT_NC"] = "nyancat";
- old_to_new["CONTENT_NC_RB"] = "nyancat_rainbow";
- old_to_new["CONTENT_APPLE"] = "apple";
- old_to_new["CONTENT_SAPLING"] = "sapling";
+ old_to_new["CONTENT_STONE"] = "default:stone";
+ old_to_new["CONTENT_WATER"] = "default:water_flowing";
+ old_to_new["CONTENT_TORCH"] = "default:torch";
+ old_to_new["CONTENT_WATERSOURCE"] = "default:water_source";
+ old_to_new["CONTENT_SIGN_WALL"] = "default:sign_wall";
+ old_to_new["CONTENT_CHEST"] = "default:chest";
+ old_to_new["CONTENT_FURNACE"] = "default:furnace";
+ old_to_new["CONTENT_LOCKABLE_CHEST"] = "default:locked_chest";
+ old_to_new["CONTENT_FENCE"] = "default:wooden_fence";
+ old_to_new["CONTENT_RAIL"] = "default:rail";
+ old_to_new["CONTENT_LADDER"] = "default:ladder";
+ old_to_new["CONTENT_LAVA"] = "default:lava_flowing";
+ old_to_new["CONTENT_LAVASOURCE"] = "default:lava_source";
+ old_to_new["CONTENT_GRASS"] = "default:dirt_with_grass";
+ old_to_new["CONTENT_TREE"] = "default:tree";
+ old_to_new["CONTENT_LEAVES"] = "default:leaves";
+ old_to_new["CONTENT_GRASS_FOOTSTEPS"] = "default:dirt_with_grass_footsteps";
+ old_to_new["CONTENT_MESE"] = "default:mese";
+ old_to_new["CONTENT_MUD"] = "default:dirt";
+ old_to_new["CONTENT_CLOUD"] = "default:cloud";
+ old_to_new["CONTENT_COALSTONE"] = "default:coalstone";
+ old_to_new["CONTENT_WOOD"] = "default:wood";
+ old_to_new["CONTENT_SAND"] = "default:sand";
+ old_to_new["CONTENT_COBBLE"] = "default:cobble";
+ old_to_new["CONTENT_STEEL"] = "default:steel";
+ old_to_new["CONTENT_GLASS"] = "default:glass";
+ old_to_new["CONTENT_MOSSYCOBBLE"] = "default:mossycobble";
+ old_to_new["CONTENT_GRAVEL"] = "default:gravel";
+ old_to_new["CONTENT_SANDSTONE"] = "default:sandstone";
+ old_to_new["CONTENT_CACTUS"] = "default:cactus";
+ old_to_new["CONTENT_BRICK"] = "default:brick";
+ old_to_new["CONTENT_CLAY"] = "default:clay";
+ old_to_new["CONTENT_PAPYRUS"] = "default:papyrus";
+ old_to_new["CONTENT_BOOKSHELF"] = "default:bookshelf";
+ old_to_new["CONTENT_JUNGLETREE"] = "default:jungletree";
+ old_to_new["CONTENT_JUNGLEGRASS"] = "default:junglegrass";
+ old_to_new["CONTENT_NC"] = "default:nyancat";
+ old_to_new["CONTENT_NC_RB"] = "default:nyancat_rainbow";
+ old_to_new["CONTENT_APPLE"] = "default:apple";
+ old_to_new["CONTENT_SAPLING"] = "default:sapling";
// Just in case
old_to_new["CONTENT_IGNORE"] = "ignore";
old_to_new["CONTENT_AIR"] = "air";
@@ -334,605 +265,3 @@ content_t legacy_get_id(const std::string &oldname, INodeDefManager *ndef)
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);
-}
-
-
diff --git a/src/content_mapnode.h b/src/content_mapnode.h
index b928e4407..003b7edd7 100644
--- a/src/content_mapnode.h
+++ b/src/content_mapnode.h
@@ -26,12 +26,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
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
extern content_t trans_table_19[21][2];
MapNode mapnode_translate_from_internal(MapNode n_from, u8 version);
diff --git a/src/content_nodemeta.cpp b/src/content_nodemeta.cpp
index 8666051a4..b36d57c89 100644
--- a/src/content_nodemeta.cpp
+++ b/src/content_nodemeta.cpp
@@ -23,6 +23,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "inventory.h"
#include "log.h"
#include "utility.h"
+#include "craftdef.h"
+#include "gamedef.h"
class Inventory;
@@ -125,9 +127,14 @@ public:
virtual bool step(float dtime);
virtual bool nodeRemovalDisabled();
virtual std::string getInventoryDrawSpecString();
+
+protected:
+ bool getCookResult(bool remove, std::string &cookresult, float &cooktime);
+ bool getBurnResult(bool remove, float &burntime);
private:
Inventory *m_inventory;
+ std::string m_infotext;
float m_step_accumulator;
float m_fuel_totaltime;
float m_fuel_time;
@@ -185,9 +192,7 @@ ChestNodeMetadata::ChestNodeMetadata(IGameDef *gamedef):
NodeMetadata(gamedef)
{
NodeMetadata::registerType(typeId(), typeName(), create, create);
-
- m_inventory = new Inventory();
- m_inventory->addList("0", 8*4);
+ m_inventory = NULL;
}
ChestNodeMetadata::~ChestNodeMetadata()
{
@@ -200,18 +205,21 @@ u16 ChestNodeMetadata::typeId() const
NodeMetadata* ChestNodeMetadata::create(std::istream &is, IGameDef *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;
}
NodeMetadata* ChestNodeMetadata::create(IGameDef *gamedef)
{
ChestNodeMetadata *d = new ChestNodeMetadata(gamedef);
+ d->m_inventory = new Inventory(gamedef->idef());
+ d->m_inventory->addList("0", 8*4);
return d;
}
NodeMetadata* ChestNodeMetadata::clone(IGameDef *gamedef)
{
ChestNodeMetadata *d = new ChestNodeMetadata(gamedef);
- *d->m_inventory = *m_inventory;
+ d->m_inventory = new Inventory(*m_inventory);
return d;
}
void ChestNodeMetadata::serializeBody(std::ostream &os)
@@ -253,9 +261,7 @@ LockingChestNodeMetadata::LockingChestNodeMetadata(IGameDef *gamedef):
NodeMetadata(gamedef)
{
NodeMetadata::registerType(typeId(), typeName(), create, create);
-
- m_inventory = new Inventory();
- m_inventory->addList("0", 8*4);
+ m_inventory = NULL;
}
LockingChestNodeMetadata::~LockingChestNodeMetadata()
{
@@ -269,18 +275,21 @@ NodeMetadata* LockingChestNodeMetadata::create(std::istream &is, IGameDef *gamed
{
LockingChestNodeMetadata *d = new LockingChestNodeMetadata(gamedef);
d->setOwner(deSerializeString(is));
- d->m_inventory->deSerialize(is, gamedef);
+ d->m_inventory = new Inventory(gamedef->idef());
+ d->m_inventory->deSerialize(is);
return d;
}
NodeMetadata* LockingChestNodeMetadata::create(IGameDef *gamedef)
{
LockingChestNodeMetadata *d = new LockingChestNodeMetadata(gamedef);
+ d->m_inventory = new Inventory(gamedef->idef());
+ d->m_inventory->addList("0", 8*4);
return d;
}
NodeMetadata* LockingChestNodeMetadata::clone(IGameDef *gamedef)
{
LockingChestNodeMetadata *d = new LockingChestNodeMetadata(gamedef);
- *d->m_inventory = *m_inventory;
+ d->m_inventory = new Inventory(*m_inventory);
return d;
}
void LockingChestNodeMetadata::serializeBody(std::ostream &os)
@@ -324,10 +333,9 @@ FurnaceNodeMetadata::FurnaceNodeMetadata(IGameDef *gamedef):
{
NodeMetadata::registerType(typeId(), typeName(), create, create);
- m_inventory = new Inventory();
- m_inventory->addList("fuel", 1);
- m_inventory->addList("src", 1);
- m_inventory->addList("dst", 4);
+ m_inventory = NULL;
+
+ m_infotext = "Furnace is inactive";
m_step_accumulator = 0;
m_fuel_totaltime = 0;
@@ -346,26 +354,52 @@ u16 FurnaceNodeMetadata::typeId() const
NodeMetadata* FurnaceNodeMetadata::clone(IGameDef *gamedef)
{
FurnaceNodeMetadata *d = new FurnaceNodeMetadata(m_gamedef);
- *d->m_inventory = *m_inventory;
+ d->m_inventory = new Inventory(*m_inventory);
return d;
}
NodeMetadata* FurnaceNodeMetadata::create(std::istream &is, IGameDef *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;
d->m_fuel_totaltime = (float)temp/10;
+ temp = 0;
is>>temp;
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;
}
NodeMetadata* FurnaceNodeMetadata::create(IGameDef *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;
}
void FurnaceNodeMetadata::serializeBody(std::ostream &os)
@@ -373,36 +407,13 @@ void FurnaceNodeMetadata::serializeBody(std::ostream &os)
m_inventory->serialize(os);
os<<itos(m_fuel_totaltime*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()
{
- //return "Furnace";
- 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;
- }
+ return m_infotext;
}
bool FurnaceNodeMetadata::nodeRemovalDisabled()
{
@@ -430,6 +441,10 @@ bool FurnaceNodeMetadata::step(float dtime)
{
if(dtime > 60.0)
infostream<<"Furnace stepping a long time ("<<dtime<<")"<<std::endl;
+
+ InventoryList *dst_list = m_inventory->getList("dst");
+ assert(dst_list);
+
// Update at a fixed frequency
const float interval = 2.0;
m_step_accumulator += dtime;
@@ -440,86 +455,110 @@ bool FurnaceNodeMetadata::step(float dtime)
dtime = interval;
//infostream<<"Furnace step dtime="<<dtime<<std::endl;
-
- InventoryList *dst_list = m_inventory->getList("dst");
- assert(dst_list);
- InventoryList *src_list = m_inventory->getList("src");
- assert(src_list);
- InventoryItem *src_item = src_list->getItem(0);
-
+ bool changed_this_loop = false;
+
+ // Check
+ // 1. if the source item is cookable
+ // 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;
-
- if(src_item && src_item->isCookable())
- room_available = dst_list->roomForCookedItem(src_item);
-
- // Start only if there are free slots in dst, so that it can
- // accomodate any result item
- if(room_available)
+ if(cookable)
{
- m_src_totaltime = src_item->getCookTime();
+ cookresult_item.deSerialize(cookresult, m_gamedef->idef());
+ room_available = dst_list->roomForItem(cookresult_item);
}
- else
+
+ // Step fuel time
+ bool burning = (m_fuel_time < m_fuel_totaltime);
+ if(burning)
{
- m_src_time = 0;
- m_src_totaltime = 0;
+ changed_this_loop = true;
+ m_fuel_time += dtime;
}
-
- /*
- If fuel is burning, increment the burn counters.
- If item finishes cooking, move it to result.
- */
- if(m_fuel_time < m_fuel_totaltime)
+
+ std::string infotext;
+ if(room_available)
{
- //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)
+ float burntime;
+ if(burning)
+ {
+ changed_this_loop = true;
+ m_src_time += dtime;
+ m_src_totaltime = cooktime;
+ infotext = "Furnace is cooking";
+ }
+ else if(getBurnResult(true, burntime))
+ {
+ // Fuel inserted
+ changed_this_loop = true;
+ m_fuel_time = 0;
+ m_fuel_totaltime = burntime;
+ //m_src_time += dtime;
+ //m_src_totaltime = cooktime;
+ infotext = "Furnace is cooking";
+ }
+ else
{
- InventoryItem *cookresult = src_item->createCookResult();
- dst_list->addItem(cookresult);
- src_list->decrementMaterials(1);
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_this_loop = true;
+ dst_list->addItem(cookresult_item);
+ getCookResult(true, cookresult, cooktime); // decrement source
+ m_src_totaltime = 0;
+ m_src_time = 0;
}
- changed = true;
-
- // If the fuel was not used up this step, just keep burning it
- if(m_fuel_time < m_fuel_totaltime)
- continue;
}
-
- /*
- Get the source again in case it has all burned
- */
- src_item = src_list->getItem(0);
-
- /*
- 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(src_item == NULL || !room_available || m_fuel_time < m_fuel_totaltime ||
- dst_list->roomForCookedItem(src_item) == false)
+ else
{
- m_step_accumulator = 0;
- break;
+ // Not cookable or no room available
+ m_src_totaltime = 0;
+ m_src_time = 0;
+ if(cookable)
+ infotext = "Furnace is overloaded";
+ else if(burning)
+ infotext = "Furnace is active";
+ else
+ {
+ infotext = "Furnace is inactive";
+ m_fuel_totaltime = 0;
+ m_fuel_time = 0;
+ }
}
-
- //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);
+ // Do this so it doesn't always show (0%) for weak fuel
+ if(m_fuel_totaltime > 3) {
+ infotext += " (";
+ infotext += itos(m_fuel_time/m_fuel_totaltime*100);
+ infotext += "%)";
+ }
- if(fuel_item && fuel_item->getBurnTime() >= 0){
- m_fuel_totaltime = fuel_item->getBurnTime();
+ if(infotext != m_infotext)
+ {
+ m_infotext = infotext;
+ changed_this_loop = true;
+ }
+
+ if(burning && m_fuel_time >= m_fuel_totaltime)
+ {
m_fuel_time = 0;
- fuel_list->decrementMaterials(1);
+ m_fuel_totaltime = 0;
+ }
+
+ if(changed_this_loop)
+ {
changed = true;
- } else {
- //infostream<<"No fuel found"<<std::endl;
- // No fuel, stop loop.
+ }
+ else
+ {
m_step_accumulator = 0;
break;
}
@@ -535,6 +574,43 @@ std::string FurnaceNodeMetadata::getInventoryDrawSpecString()
"list[current_name;dst;5,1;2,2;]"
"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
@@ -571,7 +647,7 @@ public:
GenericNodeMetadata(IGameDef *gamedef):
NodeMetadata(gamedef),
- m_inventory(new Inventory()),
+ m_inventory(NULL),
m_text(""),
m_owner(""),
@@ -594,7 +670,7 @@ public:
{
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_owner = m_owner;
@@ -610,13 +686,15 @@ public:
static NodeMetadata* create(IGameDef *gamedef)
{
GenericNodeMetadata *d = new GenericNodeMetadata(gamedef);
+ d->m_inventory = new Inventory(gamedef->idef());
return d;
}
static NodeMetadata* create(std::istream &is, IGameDef *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_owner = deSerializeString(is);
diff --git a/src/content_sao.cpp b/src/content_sao.cpp
index b8189b258..4a2bef872 100644
--- a/src/content_sao.cpp
+++ b/src/content_sao.cpp
@@ -24,8 +24,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "main.h" // For g_profiler
#include "profiler.h"
#include "serialization.h" // For compressZlib
-#include "materials.h" // For MaterialProperties
-#include "tooldef.h" // ToolDiggingProperties
+#include "materials.h" // For MaterialProperties and ToolDiggingProperties
+#include "gamedef.h"
/* Some helper functions */
@@ -112,9 +112,10 @@ void TestSAO::step(float dtime, bool send_recommended)
ItemSAO proto_ItemSAO(NULL, v3f(0,0,0), "");
ItemSAO::ItemSAO(ServerEnvironment *env, v3f pos,
- const std::string inventorystring):
+ const std::string itemstring):
ServerActiveObject(env, pos),
- m_inventorystring(inventorystring),
+ m_itemstring(itemstring),
+ m_itemstring_changed(false),
m_speed_f(0,0,0),
m_last_sent_position(0,0,0)
{
@@ -132,10 +133,10 @@ ServerActiveObject* ItemSAO::create(ServerEnvironment *env, v3f pos,
// check if version is supported
if(version != 0)
return NULL;
- std::string inventorystring = deSerializeString(is);
+ std::string itemstring = deSerializeString(is);
infostream<<"ItemSAO::create(): Creating item \""
- <<inventorystring<<"\""<<std::endl;
- return new ItemSAO(env, pos, inventorystring);
+ <<itemstring<<"\""<<std::endl;
+ return new ItemSAO(env, pos, itemstring);
}
void ItemSAO::step(float dtime, bool send_recommended)
@@ -173,17 +174,23 @@ void ItemSAO::step(float dtime, bool send_recommended)
m_last_sent_position = pos_f;
std::ostringstream os(std::ios::binary);
- char buf[6];
// command (0 = update position)
- buf[0] = 0;
- os.write(buf, 1);
+ writeU8(os, 0);
// pos
- writeS32((u8*)buf, m_base_position.X*1000);
- os.write(buf, 4);
- writeS32((u8*)buf, m_base_position.Y*1000);
- os.write(buf, 4);
- writeS32((u8*)buf, m_base_position.Z*1000);
- os.write(buf, 4);
+ writeV3F1000(os, m_base_position);
+ // create message and add to list
+ ActiveObjectMessage aom(getId(), false, os.str());
+ m_messages_out.push_back(aom);
+ }
+ 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
ActiveObjectMessage aom(getId(), false, os.str());
m_messages_out.push_back(aom);
@@ -193,19 +200,12 @@ void ItemSAO::step(float dtime, bool send_recommended)
std::string ItemSAO::getClientInitializationData()
{
std::ostringstream os(std::ios::binary);
- char buf[6];
// version
- buf[0] = 0;
- os.write(buf, 1);
+ writeU8(os, 0);
// pos
- writeS32((u8*)buf, m_base_position.X*1000);
- os.write(buf, 4);
- writeS32((u8*)buf, m_base_position.Y*1000);
- os.write(buf, 4);
- writeS32((u8*)buf, m_base_position.Z*1000);
- os.write(buf, 4);
- // inventorystring
- os<<serializeString(m_inventorystring);
+ writeV3F1000(os, m_base_position);
+ // itemstring
+ os<<serializeString(m_itemstring);
return os.str();
}
@@ -213,42 +213,58 @@ std::string ItemSAO::getStaticData()
{
infostream<<__FUNCTION_NAME<<std::endl;
std::ostringstream os(std::ios::binary);
- char buf[1];
// version
- buf[0] = 0;
- os.write(buf, 1);
- // inventorystring
- os<<serializeString(m_inventorystring);
+ writeU8(os, 0);
+ // itemstring
+ os<<serializeString(m_itemstring);
return os.str();
}
-InventoryItem * ItemSAO::createInventoryItem()
+ItemStack ItemSAO::createItemStack()
{
try{
- std::istringstream is(m_inventorystring, std::ios_base::binary);
- IGameDef *gamedef = m_env->getGameDef();
- InventoryItem *item = InventoryItem::deSerialize(is, gamedef);
- infostream<<__FUNCTION_NAME<<": m_inventorystring=\""
- <<m_inventorystring<<"\" -> item="<<item
+ IItemDefManager *idef = m_env->getGameDef()->idef();
+ ItemStack item;
+ item.deSerialize(m_itemstring, idef);
+ infostream<<__FUNCTION_NAME<<": m_itemstring=\""<<m_itemstring
+ <<"\" -> item=\""<<item.getItemString()<<"\""
<<std::endl;
return item;
}
catch(SerializationError &e)
{
infostream<<__FUNCTION_NAME<<": serialization error: "
- <<"m_inventorystring=\""<<m_inventorystring<<"\""<<std::endl;
- return NULL;
+ <<"m_itemstring=\""<<m_itemstring<<"\""<<std::endl;
+ return ItemStack();
}
}
void ItemSAO::punch(ServerActiveObject *puncher, float time_from_last_punch)
{
- InventoryItem *item = createInventoryItem();
- bool fits = puncher->addToInventory(item);
- if(fits)
+ // Allow removing items in creative mode
+ if(g_settings->getBool("creative_mode") == true)
+ {
m_removed = true;
- else
- delete item;
+ return;
+ }
+
+ 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;
+ }
+ }
}
/*
@@ -434,14 +450,24 @@ std::string RatSAO::getStaticData()
void RatSAO::punch(ServerActiveObject *puncher, float time_from_last_punch)
{
- std::istringstream is("CraftItem rat 1", std::ios_base::binary);
- IGameDef *gamedef = m_env->getGameDef();
- InventoryItem *item = InventoryItem::deSerialize(is, gamedef);
- bool fits = puncher->addToInventory(item);
- if(fits)
+ // Allow removing rats in creative mode
+ if(g_settings->getBool("creative_mode") == true)
+ {
m_removed = true;
- else
- delete item;
+ return;
+ }
+
+ 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;
+ }
}
/*
@@ -701,14 +727,20 @@ void Oerkki1SAO::punch(ServerActiveObject *puncher, float time_from_last_punch)
mp.crackiness = -1.0;
mp.cuttability = 1.0;
- ToolDiggingProperties tp;
- puncher->getWieldDiggingProperties(&tp);
+ IItemDefManager *idef = m_env->getGameDef()->idef();
+ ItemStack punchitem = puncher->getWieldedItem();
+ ToolDiggingProperties tp =
+ punchitem.getToolDiggingProperties(idef);
HittingProperties hitprop = getHittingProperties(&mp, &tp,
time_from_last_punch);
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)
@@ -1391,14 +1423,20 @@ void MobV2SAO::punch(ServerActiveObject *puncher, float time_from_last_punch)
mp.crackiness = -1.0;
mp.cuttability = 1.0;
- ToolDiggingProperties tp;
- puncher->getWieldDiggingProperties(&tp);
+ IItemDefManager *idef = m_env->getGameDef()->idef();
+ ItemStack punchitem = puncher->getWieldedItem();
+ ToolDiggingProperties tp =
+ punchitem.getToolDiggingProperties(idef);
HittingProperties hitprop = getHittingProperties(&mp, &tp,
time_from_last_punch);
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()
diff --git a/src/content_sao.h b/src/content_sao.h
index c2bb9c3f5..f0c9cea90 100644
--- a/src/content_sao.h
+++ b/src/content_sao.h
@@ -40,8 +40,7 @@ private:
class ItemSAO : public ServerActiveObject
{
public:
- ItemSAO(ServerEnvironment *env, v3f pos,
- const std::string inventorystring);
+ ItemSAO(ServerEnvironment *env, v3f pos, const std::string itemstring);
u8 getType() const
{return ACTIVEOBJECT_TYPE_ITEM;}
static ServerActiveObject* create(ServerEnvironment *env, v3f pos,
@@ -49,11 +48,12 @@ public:
void step(float dtime, bool send_recommended);
std::string getClientInitializationData();
std::string getStaticData();
- InventoryItem* createInventoryItem();
+ ItemStack createItemStack();
void punch(ServerActiveObject *puncher, float time_from_last_punch);
float getMinimumSavedMovement(){ return 0.1*BS; }
private:
- std::string m_inventorystring;
+ std::string m_itemstring;
+ bool m_itemstring_changed;
v3f m_speed_f;
v3f m_last_sent_position;
IntervalLimiter m_move_interval;
diff --git a/src/craftdef.cpp b/src/craftdef.cpp
index 0cbb74ea0..5bcbf6f94 100644
--- a/src/craftdef.cpp
+++ b/src/craftdef.cpp
@@ -22,88 +22,738 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "irrlichttypes.h"
#include "log.h"
#include <sstream>
+#include <set>
#include "utility.h"
#include "gamedef.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)
+{
+ ItemStack item;
+ item.deSerialize(itemstring, gamedef->idef());
+ return item.name;
+}
+
+// (mapcar craftGetItemName itemstrings)
+static std::vector<std::string> craftGetItemNames(
+ const std::vector<std::string> &itemstrings, IGameDef *gamedef)
+{
+ std::vector<std::string> result;
+ for(std::vector<std::string>::const_iterator
+ i = itemstrings.begin();
+ i != itemstrings.end(); i++)
+ {
+ result.push_back(craftGetItemName(*i, gamedef));
+ }
+ return result;
+}
+
+// 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)
{
- for(u32 i=0; i<items.size(); i++)
- delete items[i];
+ std::vector<std::string> result;
+ for(std::vector<ItemStack>::const_iterator
+ i = items.begin();
+ i != items.end(); i++)
+ {
+ result.push_back(i->name);
+ }
+ return result;
}
-CraftPointerInput createPointerInput(const CraftInput &ci, IGameDef *gamedef)
+// 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)
{
- std::vector<InventoryItem*> items;
- for(u32 i=0; i<ci.items.size(); i++){
- InventoryItem *item = NULL;
- if(ci.items[i] != ""){
- std::istringstream iss(ci.items[i], std::ios::binary);
- item = InventoryItem::deSerialize(iss, gamedef);
+ 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;
+ }
}
- items.push_back(item);
+
+ // Step coordinate
+ x++;
+ if(x == width)
+ {
+ x = 0;
+ y++;
+ }
+ }
+ 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 CraftPointerInput(ci.width, items);
+ return set;
}
-CraftInput createInput(const CraftPointerInput &cpi)
+// Removes 1 from each item stack
+static void craftDecrementInput(CraftInput &input, IGameDef *gamedef)
{
- std::vector<std::string> items;
- for(u32 i=0; i<cpi.items.size(); i++){
- if(cpi.items[i] == NULL)
- items.push_back("");
- else{
- std::ostringstream oss(std::ios::binary);
- cpi.items[i]->serialize(oss);
- items.push_back(oss.str());
+ 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())<<"\"";
}
- return CraftInput(cpi.width, items);
+ os<<" }";
+ return os.str();
}
+
+/*
+ CraftInput
+*/
+
std::string CraftInput::dump() const
{
std::ostringstream os(std::ios::binary);
- os<<"(width="<<width<<"){";
- for(u32 i=0; i<items.size(); i++)
- os<<"\""<<items[i]<<"\",";
- os<<"}";
+ os<<"(method="<<((int)method)<<", items="<<craftDumpMatrix(items, width)<<")";
return os.str();
}
-std::string CraftDefinition::dump() const
+/*
+ CraftOutput
+*/
+
+std::string CraftOutput::dump() const
{
std::ostringstream os(std::ios::binary);
- os<<"{output=\""<<output<<"\", input={";
- for(u32 i=0; i<input.items.size(); i++)
- os<<"\""<<input.items[i]<<"\",";
- os<<"}, (input.width="<<input.width<<")}";
+ 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<<"}";
+ return os.str();
+}
+
+
+/*
+ CraftDefinition
+*/
+
void CraftDefinition::serialize(std::ostream &os) const
{
- writeU8(os, 0); // version
- os<<serializeString(output);
- writeU8(os, input.width);
- writeU16(os, input.items.size());
- for(u32 i=0; i<input.items.size(); i++)
- os<<serializeString(input.items[i]);
+ writeU8(os, 1); // version
+ os<<serializeString(getName());
+ serializeBody(os);
}
-void CraftDefinition::deSerialize(std::istream &is)
+CraftDefinition* CraftDefinition::deSerialize(std::istream &is)
{
int version = readU8(is);
- if(version != 0) throw SerializationError(
+ if(version != 1) throw SerializationError(
"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);
+ width = readU16(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));
+ }
+}
+
+/*
+ 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);
- input.width = readU8(is);
+ recipe.clear();
u32 count = readU16(is);
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));
+ }
+}
+
+/*
+ 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
{
public:
@@ -111,58 +761,46 @@ public:
{
clear();
}
- virtual InventoryItem* getCraftResult(const CraftPointerInput &input_cpi,
- IGameDef *gamedef) const
+ virtual bool getCraftResult(CraftInput &input, CraftOutput &output,
+ bool decrementInput, IGameDef *gamedef) const
{
- if(input_cpi.width > 3){
- errorstream<<"getCraftResult(): ERROR: "
- <<"input_cpi.width > 3; Failing to craft."<<std::endl;
- return NULL;
- }
- InventoryItem *input_items[9];
- for(u32 y=0; y<3; y++)
- for(u32 x=0; x<3; x++)
+ output.item = "";
+ output.time = 0;
+
+ // If all input items are empty, abort.
+ bool all_empty = true;
+ for(std::vector<ItemStack>::const_iterator
+ i = input.items.begin();
+ i != input.items.end(); i++)
{
- u32 i=y*3+x;
- if(x >= input_cpi.width || y >= input_cpi.height())
- input_items[i] = NULL;
- else
- input_items[i] = input_cpi.items[y*input_cpi.width+x];
+ if(!i->empty())
+ {
+ all_empty = false;
+ break;
+ }
}
- for(core::list<CraftDefinition*>::ConstIterator
- i = m_craft_definitions.begin();
- i != m_craft_definitions.end(); i++)
+ if(all_empty)
+ return false;
+
+ // 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;
- /*infostream<<"Checking "<<createInput(input_cpi).dump()<<std::endl
- <<" against "<<def->input.dump()
- <<" (output=\""<<def->output<<"\")"<<std::endl;*/
+ /*infostream<<"Checking "<<input.dump()<<std::endl
+ <<" against "<<def->dump()<<std::endl;*/
try {
- CraftPointerInput spec_cpi = createPointerInput(def->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++)
+ if(def->check(input, gamedef))
{
- u32 i=y*3+x;
- if(x >= spec_cpi.width || y >= spec_cpi.height())
- spec_items[i] = NULL;
- else
- spec_items[i] = spec_cpi.items[y*spec_cpi.width+x];
- }
-
- bool match = checkItemCombination(input_items, spec_items);
-
- if(match){
- std::istringstream iss(def->output, std::ios::binary);
- return InventoryItem::deSerialize(iss, gamedef);
+ // Get output, then decrement input (if requested)
+ output = def->getOutput(input, gamedef);
+ if(decrementInput)
+ def->decrementInput(input, gamedef);
+ return true;
}
}
catch(SerializationError &e)
@@ -173,34 +811,41 @@ public:
// then go on with the next craft definition
}
}
- return NULL;
+ return false;
}
- virtual void registerCraft(const CraftDefinition &def)
+ virtual std::string dump() const
{
- infostream<<"registerCraft: registering craft definition: "
- <<def.dump()<<std::endl;
- if(def.input.width > 3 || def.input.height() > 3){
- errorstream<<"registerCraft: input size is larger than 3x3,"
- <<" ignoring"<<std::endl;
- return;
+ 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";
}
- m_craft_definitions.push_back(new CraftDefinition(def));
+ return os.str();
+ }
+ virtual void registerCraft(CraftDefinition *def)
+ {
+ infostream<<"registerCraft: registering craft definition: "
+ <<def->dump()<<std::endl;
+ m_craft_definitions.push_back(def);
}
virtual void clear()
{
- for(core::list<CraftDefinition*>::Iterator
+ for(std::vector<CraftDefinition*>::iterator
i = m_craft_definitions.begin();
i != m_craft_definitions.end(); i++){
delete *i;
}
m_craft_definitions.clear();
}
- virtual void serialize(std::ostream &os)
+ virtual void serialize(std::ostream &os) const
{
writeU8(os, 0); // version
u16 count = m_craft_definitions.size();
writeU16(os, count);
- for(core::list<CraftDefinition*>::Iterator
+ for(std::vector<CraftDefinition*>::const_iterator
i = m_craft_definitions.begin();
i != m_craft_definitions.end(); i++){
CraftDefinition *def = *i;
@@ -222,14 +867,13 @@ public:
for(u16 i=0; i<count; i++){
// Deserialize a string and grab a CraftDefinition from it
std::istringstream tmp_is(deSerializeString(is), std::ios::binary);
- CraftDefinition def;
- def.deSerialize(tmp_is);
+ CraftDefinition *def = CraftDefinition::deSerialize(tmp_is);
// Register
registerCraft(def);
}
}
private:
- core::list<CraftDefinition*> m_craft_definitions;
+ std::vector<CraftDefinition*> m_craft_definitions;
};
IWritableCraftDefManager* createCraftDefManager()
diff --git a/src/craftdef.h b/src/craftdef.h
index cfd58ad10..57f26f049 100644
--- a/src/craftdef.h
+++ b/src/craftdef.h
@@ -23,71 +23,328 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <string>
#include <iostream>
#include <vector>
-class IGameDef;
-class InventoryItem;
+#include <utility>
+#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
+{
+ // Crafting grid
+ CRAFT_METHOD_NORMAL,
+ // Cooking something in a furnace
+ CRAFT_METHOD_COOKING,
+ // Using something as fuel for a furnace
+ CRAFT_METHOD_FUEL,
+};
+
+/*
+ Input: The contents of the crafting slots, arranged in matrix form
+*/
+struct CraftInput
{
+ CraftMethod method;
unsigned int width;
- std::vector<InventoryItem*> items;
+ std::vector<ItemStack> items;
- CraftPointerInput(unsigned int width_, const std::vector<InventoryItem*> &items_):
- width(width_),
- items(items_)
+ CraftInput():
+ method(CRAFT_METHOD_NORMAL), width(0), items()
{}
- CraftPointerInput():
- width(0)
+ CraftInput(CraftMethod method_, unsigned int width_,
+ const std::vector<ItemStack> &items_):
+ method(method_), width(width_), items(items_)
{}
- ~CraftPointerInput();
- unsigned int height() const{
- return (items.size() + width - 1) / width;
- }
+ std::string dump() const;
};
-struct CraftInput
+/*
+ Output: Result of crafting operation
+*/
+struct CraftOutput
{
- unsigned int width;
- std::vector<std::string> items;
+ // Used for normal crafting and cooking, itemstring
+ std::string item;
+ // Used for cooking (cook time) and fuel (burn time), seconds
+ float time;
- CraftInput(unsigned int width_, const std::vector<std::string> &items_):
- width(width_),
- items(items_)
+ CraftOutput():
+ item(""), time(0)
{}
- CraftInput():
- width(0)
+ CraftOutput(std::string item_, float time_):
+ item(item_), time(time_)
{}
- unsigned int height() const{
- return (items.size() + width - 1) / width;
- }
std::string dump() const;
};
-struct CraftDefinition
+/*
+ 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
{
- std::string output;
- CraftInput input;
+ // List of replacements
+ std::vector<std::pair<std::string, std::string> > pairs;
- CraftDefinition(){}
- CraftDefinition(const std::string &output_, unsigned int width_,
- const std::vector<std::string> &input_):
- output(output_),
- input(width_, input_)
+ 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;
- void deSerialize(std::istream &is);
+ 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
{
public:
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
@@ -95,13 +352,21 @@ class IWritableCraftDefManager : public ICraftDefManager
public:
IWritableCraftDefManager(){}
virtual ~IWritableCraftDefManager(){}
- virtual InventoryItem* getCraftResult(const CraftPointerInput &input_cpi,
- IGameDef *gamedef) const=0;
-
- virtual void registerCraft(const CraftDefinition &def)=0;
+
+ // The main crafting function
+ virtual bool getCraftResult(CraftInput &input, CraftOutput &output,
+ 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 serialize(std::ostream &os)=0;
+ virtual void serialize(std::ostream &os) const=0;
virtual void deSerialize(std::istream &is)=0;
};
diff --git a/src/craftitemdef.cpp b/src/craftitemdef.cpp
deleted file mode 100644
index 4461e38a7..000000000
--- a/src/craftitemdef.cpp
+++ /dev/null
@@ -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();
-}
diff --git a/src/craftitemdef.h b/src/craftitemdef.h
deleted file mode 100644
index b5d4b9348..000000000
--- a/src/craftitemdef.h
+++ /dev/null
@@ -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
diff --git a/src/defaultsettings.cpp b/src/defaultsettings.cpp
index 1e48183fa..2b6cb7f53 100644
--- a/src/defaultsettings.cpp
+++ b/src/defaultsettings.cpp
@@ -43,14 +43,25 @@ void set_default_settings(Settings *settings)
settings->setDefault("keymap_rangeselect", "KEY_KEY_R");
settings->setDefault("keymap_freemove", "KEY_KEY_K");
settings->setDefault("keymap_fastmove", "KEY_KEY_J");
- settings->setDefault("keymap_frametime_graph", "KEY_F1");
settings->setDefault("keymap_screenshot", "KEY_F12");
- settings->setDefault("keymap_toggle_profiler", "KEY_F2");
+ settings->setDefault("keymap_toggle_hud", "KEY_F1");
+ settings->setDefault("keymap_toggle_chat", "KEY_F2");
settings->setDefault("keymap_toggle_force_fog_off", "KEY_F3");
settings->setDefault("keymap_toggle_update_camera", "KEY_F4");
+ settings->setDefault("keymap_toggle_debug", "KEY_F5");
+ settings->setDefault("keymap_toggle_profiler", "KEY_F6");
+ settings->setDefault("keymap_increase_viewing_range_min", "KEY_PRIOR");
+ settings->setDefault("keymap_decrease_viewing_range_min", "KEY_NEXT");
// Some (temporary) keys for debugging
settings->setDefault("keymap_print_debug_stacks", "KEY_KEY_P");
+ // Show debug info by default?
+ #ifdef NDEBUG
+ settings->setDefault("show_debug", "false");
+ #else
+ settings->setDefault("show_debug", "true");
+ #endif
+
settings->setDefault("wanted_fps", "30");
settings->setDefault("fps_max", "60");
settings->setDefault("viewing_range_nodes_max", "300");
@@ -66,7 +77,6 @@ void set_default_settings(Settings *settings)
settings->setDefault("new_style_water", "false");
settings->setDefault("new_style_leaves", "false");
settings->setDefault("smooth_lighting", "true");
- settings->setDefault("frametime_graph", "false");
settings->setDefault("enable_texture_atlas", "true");
settings->setDefault("texture_path", "");
settings->setDefault("video_driver", "opengl");
@@ -84,7 +94,7 @@ void set_default_settings(Settings *settings)
// Server stuff
// "map-dir" doesn't exist by default.
settings->setDefault("motd", "");
- settings->setDefault("max_users", "20");
+ settings->setDefault("max_users", "100");
settings->setDefault("strict_protocol_version_checking", "true");
settings->setDefault("creative_mode", "false");
settings->setDefault("enable_damage", "true");
diff --git a/src/environment.cpp b/src/environment.cpp
index a3d0950f0..d332e5d53 100644
--- a/src/environment.cpp
+++ b/src/environment.cpp
@@ -2072,7 +2072,9 @@ void ClientEnvironment::step(float dtime)
MapNode n = m_map->getNode(p);
light = n.getLightBlend(getDayNightRatio(), m_gamedef->ndef());
}
- catch(InvalidPositionException &e) {}
+ catch(InvalidPositionException &e){
+ light = blend_light(getDayNightRatio(), LIGHT_SUN, 0);
+ }
player->updateLight(light);
/*
@@ -2119,7 +2121,6 @@ void ClientEnvironment::step(float dtime)
if(m_active_object_light_update_interval.step(dtime, 0.21))
{
// Update lighting
- //u8 light = LIGHT_MAX;
u8 light = 0;
try{
// Get node at head
@@ -2127,7 +2128,9 @@ void ClientEnvironment::step(float dtime)
MapNode n = m_map->getNode(p);
light = n.getLightBlend(getDayNightRatio(), m_gamedef->ndef());
}
- catch(InvalidPositionException &e) {}
+ catch(InvalidPositionException &e){
+ light = blend_light(getDayNightRatio(), LIGHT_SUN, 0);
+ }
obj->updateLight(light);
}
}
@@ -2218,7 +2221,9 @@ u16 ClientEnvironment::addActiveObject(ClientActiveObject *object)
MapNode n = m_map->getNode(p);
light = n.getLightBlend(getDayNightRatio(), m_gamedef->ndef());
}
- catch(InvalidPositionException &e) {}
+ catch(InvalidPositionException &e){
+ light = blend_light(getDayNightRatio(), LIGHT_SUN, 0);
+ }
object->updateLight(light);
}
return object->getId();
diff --git a/src/environment.h b/src/environment.h
index dd8390c39..2391025ba 100644
--- a/src/environment.h
+++ b/src/environment.h
@@ -39,6 +39,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "activeobject.h"
class Server;
+class ServerEnvironment;
class ActiveBlockModifier;
class ServerActiveObject;
typedef struct lua_State lua_State;
diff --git a/src/game.cpp b/src/game.cpp
index 0d08074ad..a1f0fe07f 100644
--- a/src/game.cpp
+++ b/src/game.cpp
@@ -40,7 +40,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "settings.h"
#include "profiler.h"
#include "mainmenumanager.h"
-#include "craftitemdef.h"
#include "gettext.h"
#include "log.h"
#include "filesys.h"
@@ -48,7 +47,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "nodedef.h"
#include "nodemetadata.h"
#include "main.h" // For g_settings
-#include "tooldef.h"
+#include "itemdef.h"
#include "tile.h" // For TextureSource
#include "logoutputbuffer.h"
@@ -80,15 +79,6 @@ struct ChatLine
};
/*
- 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
*/
@@ -156,7 +146,7 @@ private:
Hotbar draw routine
*/
void draw_hotbar(video::IVideoDriver *driver, gui::IGUIFont *font,
- ITextureSource *tsrc,
+ IGameDef *gamedef,
v2s32 centerlowerpos, s32 imgsize, s32 itemcount,
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++)
{
- InventoryItem *item = mainlist->getItem(i);
+ const ItemStack &item = mainlist->getItem(i);
core::rect<s32> rect = imgrect + pos
+ 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);
driver->draw2DRectangle(bgcolor2, rect, NULL);
-
- if(item != NULL)
- {
- drawInventoryItem(driver, font, item, rect, NULL, tsrc);
- }
+ drawItemStack(driver, font, item, rect, NULL, gamedef);
}
/*
Draw hearts
*/
- video::ITexture *heart_texture = tsrc->getTextureRaw("heart.png");
+ video::ITexture *heart_texture =
+ gamedef->getTextureSource()->getTextureRaw("heart.png");
if(heart_texture)
{
v2s32 p = pos + v2s32(0, -20);
@@ -316,6 +303,8 @@ PointedThing getPointedThing(Client *client, v3f player_position,
should_show_hilightbox = false;
selected_object = NULL;
+ INodeDefManager *nodedef = client->getNodeDefManager();
+
// First try to find a pointed at active object
if(look_for_object)
{
@@ -391,7 +380,7 @@ PointedThing getPointedThing(Client *client, v3f player_position,
v3s16(-1,0,0), // left
};
- const ContentFeatures &f = client->getNodeDefManager()->get(n);
+ const ContentFeatures &f = nodedef->get(n);
if(f.selection_box.type == NODEBOX_FIXED)
{
@@ -460,7 +449,7 @@ PointedThing getPointedThing(Client *client, v3f player_position,
}
else if(f.selection_box.type == NODEBOX_WALLMOUNTED)
{
- v3s16 dir = unpackDir(n.param2);
+ v3s16 dir = n.getWallMountedDir(nodedef);
v3f dir_f = v3f(dir.X, dir.Y, dir.Z);
dir_f *= BS/2 - BS/6 - BS/20;
v3f cpf = npf + dir_f;
@@ -645,6 +634,36 @@ void draw_load_screen(const std::wstring &text,
//return guitext;
}
+/* Profiler display */
+
+void update_profiler_gui(gui::IGUIStaticText *guitext_profiler,
+ gui::IGUIFont *font, u32 text_height,
+ u32 show_profiler, u32 show_profiler_max)
+{
+ if(show_profiler == 0)
+ {
+ guitext_profiler->setVisible(false);
+ }
+ else
+ {
+
+ std::ostringstream os(std::ios_base::binary);
+ g_profiler->printPage(os, show_profiler, show_profiler_max);
+ std::wstring text = narrow_to_wide(os.str());
+ guitext_profiler->setText(text.c_str());
+ guitext_profiler->setVisible(true);
+
+ s32 w = font->getDimension(text.c_str()).Width;
+ if(w < 400)
+ w = 400;
+ core::rect<s32> rect(6, 4+(text_height+5)*2, 12+w,
+ 8+(text_height+5)*2 +
+ font->getDimension(text.c_str()).Height);
+ guitext_profiler->setRelativePosition(rect);
+ guitext_profiler->setVisible(true);
+ }
+}
+
void the_game(
bool &kill,
bool random_input,
@@ -691,12 +710,10 @@ void the_game(
IWritableTextureSource *tsrc = createTextureSource(device);
// These will be filled by data received from the server
- // Create tool definition manager
- IWritableToolDefManager *tooldef = createToolDefManager();
+ // Create item definition manager
+ IWritableItemDefManager *itemdef = createItemDefManager();
// Create node definition manager
IWritableNodeDefManager *nodedef = createNodeDefManager();
- // Create CraftItem definition manager
- IWritableCraftItemDefManager *craftitemdef = createCraftItemDefManager();
// Add chat log output for errors to be shown in chat
LogOutputBuffer chat_log_error_buf(LMT_ERROR);
@@ -725,7 +742,7 @@ void the_game(
MapDrawControl draw_control;
Client client(device, playername.c_str(), password, draw_control,
- tsrc, tooldef, nodedef, craftitemdef);
+ tsrc, itemdef, nodedef);
// Client acts as our GameDef
IGameDef *gamedef = &client;
@@ -835,9 +852,8 @@ void the_game(
// End condition
if(client.texturesReceived() &&
- client.tooldefReceived() &&
- client.nodedefReceived() &&
- client.craftitemdefReceived()){
+ client.itemdefReceived() &&
+ client.nodedefReceived()){
got_content = true;
break;
}
@@ -853,12 +869,10 @@ void the_game(
ss<<(int)(timeout - time_counter + 1.0);
ss<<L" seconds)\n";
- ss<<(client.tooldefReceived()?L"[X]":L"[ ]");
- ss<<L" Tool definitions\n";
+ ss<<(client.itemdefReceived()?L"[X]":L"[ ]");
+ ss<<L" Item definitions\n";
ss<<(client.nodedefReceived()?L"[X]":L"[ ]");
ss<<L" Node definitions\n";
- ss<<(client.craftitemdefReceived()?L"[X]":L"[ ]");
- ss<<L" Item definitions\n";
//ss<<(client.texturesReceived()?L"[X]":L"[ ]");
ss<<L"["<<(int)(client.textureReceiveProgress()*100+0.5)<<L"%] ";
ss<<L" Textures\n";
@@ -872,6 +886,12 @@ void the_game(
}
/*
+ After all content has been received:
+ Update cached textures, meshes and materials
+ */
+ client.afterContentReceived();
+
+ /*
Create skybox
*/
float old_brightness = 1.0;
@@ -911,6 +931,11 @@ void the_game(
}
/*
+ A copy of the local inventory
+ */
+ Inventory local_inventory(itemdef);
+
+ /*
Move into game
*/
@@ -937,6 +962,16 @@ void the_game(
core::rect<s32>(0,0,400,text_height+5) + v2s32(100,200),
false, false);
+ // Status text (displays info when showing and hiding GUI stuff, etc.)
+ gui::IGUIStaticText *guitext_status = guienv->addStaticText(
+ L"<Status>",
+ core::rect<s32>(0,0,0,0),
+ false, false);
+ guitext_status->setVisible(false);
+
+ std::wstring statustext;
+ float statustext_time = 0;
+
// Chat text
gui::IGUIStaticText *guitext_chat = guienv->addStaticText(
L"",
@@ -949,8 +984,7 @@ void the_game(
// Profiler text (size is updated when text is updated)
gui::IGUIStaticText *guitext_profiler = guienv->addStaticText(
L"<Profiler>",
- core::rect<s32>(6, 4+(text_height+5)*2, 400,
- (text_height+5)*2 + text_height*35),
+ core::rect<s32>(0,0,0,0),
false, false);
guitext_profiler->setBackgroundColor(video::SColor(80,0,0,0));
guitext_profiler->setVisible(false);
@@ -973,11 +1007,6 @@ void the_game(
(new GUIPauseMenu(guienv, guiroot, -1, g_gamecallback,
&g_menumgr))->drop();
- // Enable texts
- /*guitext2->setVisible(true);
- guitext_info->setVisible(true);
- guitext_chat->setVisible(true);*/
-
//s32 guitext_chat_pad_bottom = 70;
/*
@@ -1013,9 +1042,14 @@ void the_game(
bool respawn_menu_active = false;
bool update_wielded_item_trigger = false;
- bool show_profiler = false;
+ bool show_hud = true;
+ bool show_chat = true;
bool force_fog_off = false;
bool disable_camera_update = false;
+ bool show_debug = g_settings->getBool("show_debug");
+ bool show_debug_frametime = false;
+ u32 show_profiler = 0;
+ u32 show_profiler_max = 3; // Number of pages
/*
Main loop
@@ -1252,20 +1286,10 @@ void the_game(
g_profiler->print(infostream);
}
- std::ostringstream os(std::ios_base::binary);
- g_profiler->print(os);
- std::wstring text = narrow_to_wide(os.str());
- guitext_profiler->setText(text.c_str());
+ update_profiler_gui(guitext_profiler, font, text_height,
+ show_profiler, show_profiler_max);
g_profiler->clear();
-
- s32 w = font->getDimension(text.c_str()).Width;
- if(w < 400)
- w = 400;
- core::rect<s32> rect(6, 4+(text_height+5)*2, 12+w,
- 8+(text_height+5)*2 +
- font->getDimension(text.c_str()).Height);
- guitext_profiler->setRelativePosition(rect);
}
/*
@@ -1289,7 +1313,7 @@ void the_game(
// drop selected item
IDropAction *a = new IDropAction();
a->count = 0;
- a->from_inv = "current_player";
+ a->from_inv.setCurrentPlayer();
a->from_list = "main";
a->from_i = client.getPlayerItem();
client.inventoryAction(a);
@@ -1302,18 +1326,20 @@ void the_game(
GUIInventoryMenu *menu =
new GUIInventoryMenu(guienv, guiroot, -1,
&g_menumgr, v2s16(8,7),
- client.getInventoryContext(),
- &client, tsrc);
+ &client, gamedef);
+
+ InventoryLocation inventoryloc;
+ inventoryloc.setCurrentPlayer();
core::array<GUIInventoryMenu::DrawSpec> draw_spec;
draw_spec.push_back(GUIInventoryMenu::DrawSpec(
- "list", "current_player", "main",
+ "list", inventoryloc, "main",
v2s32(0, 3), v2s32(8, 4)));
draw_spec.push_back(GUIInventoryMenu::DrawSpec(
- "list", "current_player", "craft",
+ "list", inventoryloc, "craft",
v2s32(3, 0), v2s32(3, 3)));
draw_spec.push_back(GUIInventoryMenu::DrawSpec(
- "list", "current_player", "craftresult",
+ "list", inventoryloc, "craftpreview",
v2s32(7, 1), v2s32(1, 1)));
menu->setDrawSpec(draw_spec);
@@ -1352,12 +1378,14 @@ void the_game(
if(g_settings->getBool("free_move"))
{
g_settings->set("free_move","false");
- chat_lines.push_back(ChatLine(L"free_move disabled"));
+ statustext = L"free_move disabled";
+ statustext_time = 0;
}
else
{
g_settings->set("free_move","true");
- chat_lines.push_back(ChatLine(L"free_move enabled"));
+ statustext = L"free_move enabled";
+ statustext_time = 0;
}
}
else if(input->wasKeyDown(getKeySetting("keymap_fastmove")))
@@ -1365,25 +1393,14 @@ void the_game(
if(g_settings->getBool("fast_move"))
{
g_settings->set("fast_move","false");
- chat_lines.push_back(ChatLine(L"fast_move disabled"));
+ statustext = L"fast_move disabled";
+ statustext_time = 0;
}
else
{
g_settings->set("fast_move","true");
- chat_lines.push_back(ChatLine(L"fast_move enabled"));
- }
- }
- else if(input->wasKeyDown(getKeySetting("keymap_frametime_graph")))
- {
- if(g_settings->getBool("frametime_graph"))
- {
- g_settings->set("frametime_graph","false");
- chat_lines.push_back(ChatLine(L"frametime_graph disabled"));
- }
- else
- {
- g_settings->set("frametime_graph","true");
- chat_lines.push_back(ChatLine(L"frametime_graph enabled"));
+ statustext = L"fast_move enabled";
+ statustext_time = 0;
}
}
else if(input->wasKeyDown(getKeySetting("keymap_screenshot")))
@@ -1398,37 +1415,120 @@ void the_game(
std::wstringstream sstr;
sstr<<"Saved screenshot to '"<<filename<<"'";
infostream<<"Saved screenshot to '"<<filename<<"'"<<std::endl;
- chat_lines.push_back(ChatLine(sstr.str()));
+ statustext = sstr.str();
+ statustext_time = 0;
} else{
infostream<<"Failed to save screenshot '"<<filename<<"'"<<std::endl;
}
image->drop();
}
}
- else if(input->wasKeyDown(getKeySetting("keymap_toggle_profiler")))
+ else if(input->wasKeyDown(getKeySetting("keymap_toggle_hud")))
+ {
+ show_hud = !show_hud;
+ if(show_hud)
+ statustext = L"HUD shown";
+ else
+ statustext = L"HUD hidden";
+ statustext_time = 0;
+ }
+ else if(input->wasKeyDown(getKeySetting("keymap_toggle_chat")))
{
- show_profiler = !show_profiler;
- guitext_profiler->setVisible(show_profiler);
- if(show_profiler)
- chat_lines.push_back(ChatLine(L"Profiler disabled"));
+ show_chat = !show_chat;
+ if(show_chat)
+ statustext = L"Chat shown";
else
- chat_lines.push_back(ChatLine(L"Profiler enabled"));
+ statustext = L"Chat hidden";
+ statustext_time = 0;
}
else if(input->wasKeyDown(getKeySetting("keymap_toggle_force_fog_off")))
{
force_fog_off = !force_fog_off;
if(force_fog_off)
- chat_lines.push_back(ChatLine(L"Fog disabled"));
+ statustext = L"Fog disabled";
else
- chat_lines.push_back(ChatLine(L"Fog enabled"));
+ statustext = L"Fog enabled";
+ statustext_time = 0;
}
else if(input->wasKeyDown(getKeySetting("keymap_toggle_update_camera")))
{
disable_camera_update = !disable_camera_update;
if(disable_camera_update)
- chat_lines.push_back(ChatLine(L"Camera update disabled"));
+ statustext = L"Camera update disabled";
+ else
+ statustext = L"Camera update enabled";
+ statustext_time = 0;
+ }
+ else if(input->wasKeyDown(getKeySetting("keymap_toggle_debug")))
+ {
+ // Initial / 3x toggle: Chat only
+ // 1x toggle: Debug text with chat
+ // 2x toggle: Debug text with frametime
+ if(!show_debug)
+ {
+ show_debug = true;
+ show_debug_frametime = false;
+ statustext = L"Debug info shown";
+ statustext_time = 0;
+ }
+ else if(show_debug_frametime)
+ {
+ show_debug = false;
+ show_debug_frametime = false;
+ statustext = L"Debug info and frametime graph hidden";
+ statustext_time = 0;
+ }
+ else
+ {
+ show_debug_frametime = true;
+ statustext = L"Frametime graph shown";
+ statustext_time = 0;
+ }
+ }
+ else if(input->wasKeyDown(getKeySetting("keymap_toggle_profiler")))
+ {
+ show_profiler = (show_profiler + 1) % (show_profiler_max + 1);
+
+ // FIXME: This updates the profiler with incomplete values
+ update_profiler_gui(guitext_profiler, font, text_height,
+ show_profiler, show_profiler_max);
+
+ if(show_profiler != 0)
+ {
+ std::wstringstream sstr;
+ sstr<<"Profiler shown (page "<<show_profiler
+ <<" of "<<show_profiler_max<<")";
+ statustext = sstr.str();
+ statustext_time = 0;
+ }
else
- chat_lines.push_back(ChatLine(L"Camera update enabled"));
+ {
+ statustext = L"Profiler hidden";
+ statustext_time = 0;
+ }
+ }
+ else if(input->wasKeyDown(getKeySetting("keymap_increase_viewing_range_min")))
+ {
+ s16 range = g_settings->getS16("viewing_range_nodes_min");
+ s16 range_new = range + 10;
+ g_settings->set("viewing_range_nodes_min", itos(range_new));
+ statustext = narrow_to_wide(
+ "Minimum viewing range changed to "
+ + itos(range_new));
+ statustext_time = 0;
+ }
+ else if(input->wasKeyDown(getKeySetting("keymap_decrease_viewing_range_min")))
+ {
+ s16 range = g_settings->getS16("viewing_range_nodes_min");
+ s16 range_new = range - 10;
+ if(range_new < 0)
+ range_new = range;
+ g_settings->set("viewing_range_nodes_min",
+ itos(range_new));
+ statustext = narrow_to_wide(
+ "Minimum viewing range changed to "
+ + itos(range_new));
+ statustext_time = 0;
}
// Item selection with mouse wheel
@@ -1473,15 +1573,18 @@ void the_game(
// Viewing range selection
if(input->wasKeyDown(getKeySetting("keymap_rangeselect")))
{
+ draw_control.range_all = !draw_control.range_all;
if(draw_control.range_all)
{
- draw_control.range_all = false;
- infostream<<"Disabled full viewing range"<<std::endl;
+ infostream<<"Enabled full viewing range"<<std::endl;
+ statustext = L"Enabled full viewing range";
+ statustext_time = 0;
}
else
{
- draw_control.range_all = true;
- infostream<<"Enabled full viewing range"<<std::endl;
+ infostream<<"Disabled full viewing range"<<std::endl;
+ statustext = L"Disabled full viewing range";
+ statustext_time = 0;
}
}
@@ -1691,31 +1794,20 @@ void the_game(
/*
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?
- Can it point to liquids?
*/
- std::string playeritem_toolname = "";
+ ItemStack playeritem;
bool playeritem_usable = false;
bool playeritem_liquids_pointable = false;
{
InventoryList *mlist = local_inventory.getList("main");
if(mlist != NULL)
{
- InventoryItem *item = mlist->getItem(client.getPlayerItem());
- if(item)
- {
- if((std::string)item->getName() == "ToolItem")
- {
- ToolItem *titem = (ToolItem*)item;
- playeritem_toolname = titem->getToolName();
- }
-
- playeritem_usable = item->isUsable();
-
- playeritem_liquids_pointable =
- item->areLiquidsPointable();
- }
+ playeritem = mlist->getItem(client.getPlayerItem());
+ playeritem_usable = playeritem.getDefinition(itemdef).usable;
+ playeritem_liquids_pointable = playeritem.getDefinition(itemdef).liquids_pointable;
}
}
@@ -1843,19 +1935,15 @@ void the_game(
MapNode n = client.getNode(nodepos);
// Get digging properties for material and tool
- content_t material = n.getContent();
+ MaterialProperties mp = nodedef->get(n.getContent()).material;
ToolDiggingProperties tp =
- tooldef->getDiggingProperties(playeritem_toolname);
- DiggingProperties prop =
- getDiggingProperties(material, &tp, nodedef);
+ playeritem.getToolDiggingProperties(itemdef);
+ DiggingProperties prop = getDiggingProperties(&mp, &tp);
float dig_time_complete = 0.0;
if(prop.diggable == false)
{
- /*infostream<<"Material "<<(int)material
- <<" not diggable with \""
- <<playeritem_toolname<<"\""<<std::endl;*/
// I guess nobody will wait for this long
dig_time_complete = 10000000.0;
}
@@ -1922,17 +2010,11 @@ void the_game(
if(meta && meta->getInventoryDrawSpecString() != "" && !random_input)
{
infostream<<"Launching custom inventory view"<<std::endl;
- /*
- Construct the unique identification string of the node
- */
- 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);
+
+ InventoryLocation inventoryloc;
+ inventoryloc.setNodeMeta(nodepos);
+
/*
Create menu
*/
@@ -1942,13 +2024,12 @@ void the_game(
GUIInventoryMenu::makeDrawSpecArrayFromString(
draw_spec,
meta->getInventoryDrawSpecString(),
- current_name);
+ inventoryloc);
GUIInventoryMenu *menu =
new GUIInventoryMenu(guienv, guiroot, -1,
&g_menumgr, invsize,
- client.getInventoryContext(),
- &client, tsrc);
+ &client, gamedef);
menu->setDrawSpec(draw_spec);
menu->drop();
}
@@ -2001,7 +2082,7 @@ void the_game(
v3f objpos = selected_object->getPosition();
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)
client.interact(0, pointed);
}
@@ -2130,55 +2211,110 @@ void the_game(
//TimeTaker guiupdatetimer("Gui updating");
+ const char program_name_and_version[] =
+ "Minetest-c55 " VERSION_STRING;
+
+ if(show_debug)
{
static float drawtime_avg = 0;
drawtime_avg = drawtime_avg * 0.95 + (float)drawtime*0.05;
- static float beginscenetime_avg = 0;
+ /*static float beginscenetime_avg = 0;
beginscenetime_avg = beginscenetime_avg * 0.95 + (float)beginscenetime*0.05;
static float scenetime_avg = 0;
scenetime_avg = scenetime_avg * 0.95 + (float)scenetime*0.05;
static float endscenetime_avg = 0;
- endscenetime_avg = endscenetime_avg * 0.95 + (float)endscenetime*0.05;
+ endscenetime_avg = endscenetime_avg * 0.95 + (float)endscenetime*0.05;*/
char temptext[300];
- snprintf(temptext, 300, "Minetest-c55 %s ("
+ snprintf(temptext, 300, "%s ("
"R: range_all=%i"
")"
- " drawtime=%.0f, beginscenetime=%.0f"
- ", scenetime=%.0f, endscenetime=%.0f",
- VERSION_STRING,
+ " drawtime=%.0f, dtime_jitter = % .1f %%"
+ ", v_range = %.1f, RTT = %.3f",
+ program_name_and_version,
draw_control.range_all,
drawtime_avg,
- beginscenetime_avg,
- scenetime_avg,
- endscenetime_avg
+ dtime_jitter1_max_fraction * 100.0,
+ draw_control.wanted_range,
+ client.getRTT()
);
guitext->setText(narrow_to_wide(temptext).c_str());
+ guitext->setVisible(true);
+ }
+ else if(show_hud || show_chat)
+ {
+ guitext->setText(narrow_to_wide(program_name_and_version).c_str());
+ guitext->setVisible(true);
+ }
+ else
+ {
+ guitext->setVisible(false);
}
+ if(show_debug)
{
char temptext[300];
snprintf(temptext, 300,
"(% .1f, % .1f, % .1f)"
- " (% .3f < btime_jitter < % .3f"
- ", dtime_jitter = % .1f %%"
- ", v_range = %.1f, RTT = %.3f)",
+ " (yaw = %.1f)",
player_position.X/BS,
player_position.Y/BS,
player_position.Z/BS,
- busytime_jitter1_min_sample,
- busytime_jitter1_max_sample,
- dtime_jitter1_max_fraction * 100.0,
- draw_control.wanted_range,
- client.getRTT()
- );
+ wrapDegrees_0_360(camera_yaw));
guitext2->setText(narrow_to_wide(temptext).c_str());
+ guitext2->setVisible(true);
+ }
+ else
+ {
+ guitext2->setVisible(false);
}
{
guitext_info->setText(infotext.c_str());
+ guitext_info->setVisible(show_hud);
+ }
+
+ {
+ float statustext_time_max = 3.0;
+ if(!statustext.empty())
+ {
+ statustext_time += dtime;
+ if(statustext_time >= statustext_time_max)
+ {
+ statustext = L"";
+ statustext_time = 0;
+ }
+ }
+ guitext_status->setText(statustext.c_str());
+ guitext_status->setVisible(!statustext.empty());
+
+ if(!statustext.empty())
+ {
+ s32 status_y = screensize.Y - 130;
+ core::rect<s32> rect(
+ 10,
+ status_y - guitext_status->getTextHeight(),
+ screensize.X - 10,
+ status_y
+ );
+ guitext_status->setRelativePosition(rect);
+
+ // Fade out
+ video::SColor initial_color(255,0,0,0);
+ if(guienv->getSkin())
+ initial_color = guienv->getSkin()->getColor(gui::EGDC_BUTTON_TEXT);
+ video::SColor final_color = initial_color;
+ final_color.setAlpha(0);
+ video::SColor fade_color =
+ initial_color.getInterpolated_quadratic(
+ initial_color,
+ final_color,
+ statustext_time / (float) statustext_time_max);
+ guitext_status->setOverrideColor(fade_color);
+ guitext_status->enableOverrideColor(true);
+ }
}
/*
@@ -2249,20 +2385,22 @@ void the_game(
screensize.X - 10,
screensize.Y - guitext_chat_pad_bottom
);*/
+
+ s32 chat_y = 5+(text_height+5);
+ if(show_debug)
+ chat_y += (text_height+5);
core::rect<s32> rect(
10,
- 50,
+ chat_y,
screensize.X - 10,
- 50 + guitext_chat->getTextHeight()
+ chat_y + guitext_chat->getTextHeight()
);
guitext_chat->setRelativePosition(rect);
- // Don't show chat if empty or profiler is enabled
- if(chat_lines.size() == 0 || show_profiler)
- guitext_chat->setVisible(false);
- else
- guitext_chat->setVisible(true);
+ // Don't show chat if empty or profiler or debug is enabled
+ guitext_chat->setVisible(chat_lines.size() != 0
+ && show_chat && show_profiler == 0);
}
/*
@@ -2285,25 +2423,13 @@ void the_game(
update_wielded_item_trigger = false;
// Update wielded tool
InventoryList *mlist = local_inventory.getList("main");
- InventoryItem *item = NULL;
+ ItemStack item;
if(mlist != NULL)
item = mlist->getItem(client.getPlayerItem());
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
*/
@@ -2312,7 +2438,7 @@ void the_game(
{
TimeTaker timer("beginScene");
- driver->beginScene(true, true, bgcolor);
+ driver->beginScene(false, true, bgcolor);
//driver->beginScene(false, true, bgcolor);
beginscenetime = timer.stop(true);
}
@@ -2342,20 +2468,24 @@ void the_game(
driver->setTransform(video::ETS_WORLD, core::IdentityMatrix);
- for(core::list< core::aabbox3d<f32> >::Iterator i=hilightboxes.begin();
- i != hilightboxes.end(); i++)
+ if(show_hud)
{
- /*infostream<<"hilightbox min="
- <<"("<<i->MinEdge.X<<","<<i->MinEdge.Y<<","<<i->MinEdge.Z<<")"
- <<" max="
- <<"("<<i->MaxEdge.X<<","<<i->MaxEdge.Y<<","<<i->MaxEdge.Z<<")"
- <<std::endl;*/
- driver->draw3DBox(*i, video::SColor(255,0,0,0));
+ for(core::list<aabb3f>::Iterator i=hilightboxes.begin();
+ i != hilightboxes.end(); i++)
+ {
+ /*infostream<<"hilightbox min="
+ <<"("<<i->MinEdge.X<<","<<i->MinEdge.Y<<","<<i->MinEdge.Z<<")"
+ <<" max="
+ <<"("<<i->MaxEdge.X<<","<<i->MaxEdge.Y<<","<<i->MaxEdge.Z<<")"
+ <<std::endl;*/
+ driver->draw3DBox(*i, video::SColor(255,0,0,0));
+ }
}
/*
Wielded tool
*/
+ if(show_hud)
{
// Warning: This clears the Z buffer.
camera.drawWieldedTool();
@@ -2371,16 +2501,17 @@ void the_game(
/*
Frametime log
*/
- if(g_settings->getBool("frametime_graph") == true)
+ if(show_debug_frametime)
{
s32 x = 10;
+ s32 y = screensize.Y - 10;
for(core::list<float>::Iterator
i = frametime_log.begin();
i != frametime_log.end();
i++)
{
- driver->draw2DLine(v2s32(x,50),
- v2s32(x,50+(*i)*1000),
+ driver->draw2DLine(v2s32(x,y),
+ v2s32(x,y-(*i)*1000),
video::SColor(255,255,255,255));
x++;
}
@@ -2389,12 +2520,15 @@ void the_game(
/*
Draw crosshair
*/
- driver->draw2DLine(displaycenter - core::vector2d<s32>(10,0),
- displaycenter + core::vector2d<s32>(10,0),
- video::SColor(255,255,255,255));
- driver->draw2DLine(displaycenter - core::vector2d<s32>(0,10),
- displaycenter + core::vector2d<s32>(0,10),
- video::SColor(255,255,255,255));
+ if(show_hud)
+ {
+ driver->draw2DLine(displaycenter - core::vector2d<s32>(10,0),
+ displaycenter + core::vector2d<s32>(10,0),
+ video::SColor(255,255,255,255));
+ driver->draw2DLine(displaycenter - core::vector2d<s32>(0,10),
+ displaycenter + core::vector2d<s32>(0,10),
+ video::SColor(255,255,255,255));
+ }
} // timer
@@ -2410,8 +2544,9 @@ void the_game(
/*
Draw hotbar
*/
+ if(show_hud)
{
- draw_hotbar(driver, font, tsrc,
+ draw_hotbar(driver, font, gamedef,
v2s32(displaycenter.X, screensize.Y),
hotbar_imagesize, hotbar_itemcount, &local_inventory,
client.getHP(), client.getPlayerItem());
@@ -2482,9 +2617,9 @@ void the_game(
} // Client scope (must be destructed before destructing *def and tsrc
- delete tooldef;
delete tsrc;
delete nodedef;
+ delete itemdef;
}
diff --git a/src/gamedef.h b/src/gamedef.h
index c450568b7..10ab0b0bc 100644
--- a/src/gamedef.h
+++ b/src/gamedef.h
@@ -21,12 +21,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define GAMEDEF_HEADER
#include <string>
+#include "irrlichttypes.h"
-class IToolDefManager;
+class IItemDefManager;
class INodeDefManager;
class ICraftDefManager;
-class ICraftItemDefManager;
-// Mineral too?
class ITextureSource;
/*
@@ -39,10 +38,9 @@ class IGameDef
public:
// These are thread-safe IF they are not edited while running threads.
// 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 ICraftDefManager* getCraftDefManager()=0;
- virtual ICraftItemDefManager* getCraftItemDefManager()=0;
// This is always thread-safe, but referencing the irrlicht texture
// pointers in other threads than main thread will make things explode.
@@ -52,10 +50,9 @@ public:
virtual u16 allocateUnknownNodeId(const std::string &name)=0;
// Shorthands
- IToolDefManager* tdef(){return getToolDefManager();}
+ IItemDefManager* idef(){return getItemDefManager();}
INodeDefManager* ndef(){return getNodeDefManager();}
ICraftDefManager* cdef(){return getCraftDefManager();}
- ICraftItemDefManager* cidef(){return getCraftItemDefManager();}
ITextureSource* tsrc(){return getTextureSource();}
};
diff --git a/src/guiInventoryMenu.cpp b/src/guiInventoryMenu.cpp
index 552e10db2..f33460906 100644
--- a/src/guiInventoryMenu.cpp
+++ b/src/guiInventoryMenu.cpp
@@ -20,6 +20,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "guiInventoryMenu.h"
#include "constants.h"
+#include "gamedef.h"
#include "keycode.h"
#include "strfnd.h"
#include <IGUICheckBox.h>
@@ -28,20 +29,21 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <IGUIStaticText.h>
#include <IGUIFont.h>
#include "log.h"
-#include "inventorymanager.h"
-void drawInventoryItem(video::IVideoDriver *driver,
+void drawItemStack(video::IVideoDriver *driver,
gui::IGUIFont *font,
- InventoryItem *item, core::rect<s32> rect,
+ const ItemStack &item,
+ const core::rect<s32> &rect,
const core::rect<s32> *clip,
- ITextureSource *tsrc)
+ IGameDef *gamedef)
{
- if(item == NULL)
+ if(item.empty())
return;
- video::ITexture *texture = NULL;
- texture = item->getImage();
+ const ItemDefinition &def = item.getDefinition(gamedef->idef());
+ video::ITexture *texture = def.inventory_texture;
+ // Draw the inventory texture
if(texture != NULL)
{
const video::SColor color(255,255,255,255);
@@ -51,34 +53,66 @@ void drawInventoryItem(video::IVideoDriver *driver,
core::dimension2di(texture->getOriginalSize())),
clip, colors, true);
}
- else
+
+ if(def.type == ITEM_TOOL && item.wear != 0)
{
- video::SColor bgcolor(255,50,50,128);
- driver->draw2DRectangle(bgcolor, rect, clip);
+ // Draw a progressbar
+ 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;
+ int progressmid =
+ 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 = MYMIN(floor(wear * 600), 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);
+
+ core::rect<s32> progressrect2 = progressrect;
+ progressrect2.LowerRightCorner.X = progressmid;
+ driver->draw2DRectangle(color, progressrect2, clip);
+
+ color = video::SColor(255,0,0,0);
+ progressrect2 = progressrect;
+ progressrect2.UpperLeftCorner.X = progressmid;
+ driver->draw2DRectangle(color, progressrect2, clip);
}
- if(font != NULL)
+ if(font != NULL && item.count >= 2)
{
- std::string text = item->getText();
- if(font && text != "")
- {
- v2u32 dim = font->getDimension(narrow_to_wide(text).c_str());
- v2s32 sdim(dim.X,dim.Y);
-
- core::rect<s32> rect2(
- /*rect.UpperLeftCorner,
- core::dimension2d<u32>(rect.getWidth(), 15)*/
- rect.LowerRightCorner - sdim,
- sdim
- );
-
- video::SColor bgcolor(128,0,0,0);
- driver->draw2DRectangle(bgcolor, rect2, clip);
-
- font->draw(text.c_str(), rect2,
- video::SColor(255,255,255,255), false, false,
- clip);
- }
+ // Get the item count as a string
+ std::string text = itos(item.count);
+ v2u32 dim = font->getDimension(narrow_to_wide(text).c_str());
+ v2s32 sdim(dim.X,dim.Y);
+
+ core::rect<s32> rect2(
+ /*rect.UpperLeftCorner,
+ core::dimension2d<u32>(rect.getWidth(), 15)*/
+ rect.LowerRightCorner - sdim,
+ sdim
+ );
+
+ video::SColor bgcolor(128,0,0,0);
+ driver->draw2DRectangle(bgcolor, rect2, clip);
+
+ video::SColor color(255,255,255,255);
+ font->draw(text.c_str(), rect2, color, false, false, clip);
}
}
@@ -90,17 +124,18 @@ GUIInventoryMenu::GUIInventoryMenu(gui::IGUIEnvironment* env,
gui::IGUIElement* parent, s32 id,
IMenuManager *menumgr,
v2s16 menu_size,
- InventoryContext *c,
InventoryManager *invmgr,
- ITextureSource *tsrc
+ IGameDef *gamedef
):
GUIModalMenu(env, parent, id, menumgr),
m_menu_size(menu_size),
- m_c(c),
m_invmgr(invmgr),
- m_tsrc(tsrc)
+ m_gamedef(gamedef)
{
m_selected_item = NULL;
+ m_selected_amount = 0;
+ m_selected_dragging = false;
+ m_tooltip_element = NULL;
}
GUIInventoryMenu::~GUIInventoryMenu()
@@ -131,6 +166,11 @@ void GUIInventoryMenu::removeChildren()
if(e != NULL)
e->remove();
}*/
+ if(m_tooltip_element)
+ {
+ m_tooltip_element->remove();
+ m_tooltip_element = NULL;
+ }
}
void GUIInventoryMenu::regenerateGui(v2u32 screensize)
@@ -195,6 +235,17 @@ void GUIInventoryMenu::regenerateGui(v2u32 screensize)
const wchar_t *text =
L"Left click: Move all items, Right click: Move single item";
Environment->addStaticText(text, rect, false, true, this, 256);
+
+ // Add tooltip
+ // Note: parent != this so that the tooltip isn't clipped by the menu rectangle
+ m_tooltip_element = Environment->addStaticText(L"",core::rect<s32>(0,0,110,18));
+ m_tooltip_element->enableOverrideColor(true);
+ m_tooltip_element->setBackgroundColor(video::SColor(255,110,130,60));
+ m_tooltip_element->setDrawBackground(true);
+ m_tooltip_element->setDrawBorder(true);
+ m_tooltip_element->setOverrideColor(video::SColor(255,255,255,255));
+ m_tooltip_element->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_CENTER);
+ m_tooltip_element->setWordWrap(false);
}
}
@@ -214,15 +265,15 @@ GUIInventoryMenu::ItemSpec GUIInventoryMenu::getItemAtPos(v2s32 p) const
core::rect<s32> rect = imgrect + s.pos + p0;
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, int phase)
{
video::IVideoDriver* driver = Environment->getVideoDriver();
@@ -232,7 +283,7 @@ void GUIInventoryMenu::drawList(const ListDrawSpec &s, ITextureSource *tsrc)
if (skin)
font = skin->getFont();
- Inventory *inv = m_invmgr->getInventory(m_c, s.inventoryname);
+ Inventory *inv = m_invmgr->getInventory(s.inventoryloc);
assert(inv);
InventoryList *ilist = inv->getList(s.listname);
@@ -244,51 +295,93 @@ void GUIInventoryMenu::drawList(const ListDrawSpec &s, ITextureSource *tsrc)
s32 y = (i/s.geom.X) * spacing.Y;
v2s32 p(x,y);
core::rect<s32> rect = imgrect + s.pos + p;
- InventoryItem *item = NULL;
+ ItemStack item;
if(ilist)
item = ilist->getItem(i);
- if(m_selected_item != NULL && m_selected_item->listname == s.listname
- && m_selected_item->i == i)
- {
- /*s32 border = imgsize.X/12;
- driver->draw2DRectangle(video::SColor(255,192,192,192),
- core::rect<s32>(rect.UpperLeftCorner - v2s32(1,1)*border,
- rect.LowerRightCorner + v2s32(1,1)*border),
- NULL);
- driver->draw2DRectangle(video::SColor(255,0,0,0),
- core::rect<s32>(rect.UpperLeftCorner - v2s32(1,1)*((border+1)/2),
- rect.LowerRightCorner + v2s32(1,1)*((border+1)/2)),
- NULL);*/
- s32 border = 2;
- driver->draw2DRectangle(video::SColor(255,255,0,0),
- core::rect<s32>(rect.UpperLeftCorner - v2s32(1,1)*border,
- rect.LowerRightCorner + v2s32(1,1)*border),
- &AbsoluteClippingRect);
- }
-
- if(rect.isPointInside(m_pointer) && m_selected_item)
- {
- video::SColor bgcolor(255,192,192,192);
- driver->draw2DRectangle(bgcolor, rect, &AbsoluteClippingRect);
- }
- else
+ bool selected = m_selected_item
+ && m_invmgr->getInventory(m_selected_item->inventoryloc) == inv
+ && m_selected_item->listname == s.listname
+ && m_selected_item->i == i;
+ bool hovering = rect.isPointInside(m_pointer);
+
+ if(phase == 0)
{
- video::SColor bgcolor(255,128,128,128);
- driver->draw2DRectangle(bgcolor, rect, &AbsoluteClippingRect);
+ if(hovering && m_selected_item)
+ {
+ video::SColor bgcolor(255,192,192,192);
+ driver->draw2DRectangle(bgcolor, rect, &AbsoluteClippingRect);
+ }
+ else
+ {
+ video::SColor bgcolor(255,128,128,128);
+ driver->draw2DRectangle(bgcolor, rect, &AbsoluteClippingRect);
+ }
}
- if(item)
+ if(phase == 1)
{
- drawInventoryItem(driver, font, item,
- rect, &AbsoluteClippingRect, tsrc);
- }
+ // Draw item stack
+ if(selected)
+ {
+ item.takeItem(m_selected_amount);
+ }
+ if(!item.empty())
+ {
+ drawItemStack(driver, font, item,
+ rect, &AbsoluteClippingRect, m_gamedef);
+ }
+ // Draw tooltip
+ std::string tooltip_text = "";
+ if(hovering && !m_selected_item)
+ tooltip_text = item.getDefinition(m_gamedef->idef()).description;
+ if(tooltip_text != "")
+ {
+ m_tooltip_element->setVisible(true);
+ this->bringToFront(m_tooltip_element);
+ m_tooltip_element->setText(narrow_to_wide(tooltip_text).c_str());
+ s32 tooltip_x = m_pointer.X + 15;
+ s32 tooltip_y = m_pointer.Y + 15;
+ s32 tooltip_width = m_tooltip_element->getTextWidth() + 15;
+ s32 tooltip_height = m_tooltip_element->getTextHeight() + 5;
+ m_tooltip_element->setRelativePosition(core::rect<s32>(
+ core::position2d<s32>(tooltip_x, tooltip_y),
+ core::dimension2d<s32>(tooltip_width, tooltip_height)));
+ }
+ }
}
}
+void GUIInventoryMenu::drawSelectedItem()
+{
+ if(!m_selected_item)
+ return;
+
+ video::IVideoDriver* driver = Environment->getVideoDriver();
+
+ // Get font
+ gui::IGUIFont *font = NULL;
+ gui::IGUISkin* skin = Environment->getSkin();
+ if (skin)
+ font = skin->getFont();
+
+ Inventory *inv = m_invmgr->getInventory(m_selected_item->inventoryloc);
+ assert(inv);
+ InventoryList *list = inv->getList(m_selected_item->listname);
+ assert(list);
+ ItemStack stack = list->getItem(m_selected_item->i);
+ stack.count = m_selected_amount;
+
+ core::rect<s32> imgrect(0,0,imgsize.X,imgsize.Y);
+ core::rect<s32> rect = imgrect + (m_pointer - imgrect.getCenter());
+ drawItemStack(driver, font, stack, rect, NULL, m_gamedef);
+}
+
void GUIInventoryMenu::drawMenu()
{
+ updateSelectedItem();
+
gui::IGUISkin* skin = Environment->getSkin();
if (!skin)
return;
@@ -297,22 +390,98 @@ void GUIInventoryMenu::drawMenu()
video::SColor bgcolor(140,0,0,0);
driver->draw2DRectangle(bgcolor, AbsoluteRect, &AbsoluteClippingRect);
+ m_tooltip_element->setVisible(false);
+
/*
Draw items
+ Phase 0: Item slot rectangles
+ Phase 1: Item images; prepare tooltip
*/
+ for(int phase=0; phase<=1; phase++)
for(u32 i=0; i<m_draw_spec.size(); i++)
{
- ListDrawSpec &s = m_draw_spec[i];
- drawList(s, m_tsrc);
+ drawList(m_draw_spec[i], phase);
}
/*
+ Draw dragged item stack
+ */
+ drawSelectedItem();
+
+ /*
Call base class
*/
gui::IGUIElement::draw();
}
+void GUIInventoryMenu::updateSelectedItem()
+{
+ // If the selected stack has become empty for some reason, deselect it.
+ // If the selected stack has become smaller, adjust m_selected_amount.
+ if(m_selected_item)
+ {
+ bool selection_valid = false;
+ if(m_selected_item->isValid())
+ {
+ Inventory *inv = m_invmgr->getInventory(m_selected_item->inventoryloc);
+ if(inv)
+ {
+ InventoryList *list = inv->getList(m_selected_item->listname);
+ if(list && (u32) m_selected_item->i < list->getSize())
+ {
+ ItemStack stack = list->getItem(m_selected_item->i);
+ if(m_selected_amount > stack.count)
+ m_selected_amount = stack.count;
+ if(!stack.empty())
+ selection_valid = true;
+ }
+ }
+ }
+ if(!selection_valid)
+ {
+ delete m_selected_item;
+ m_selected_item = NULL;
+ m_selected_amount = 0;
+ m_selected_dragging = false;
+ }
+ }
+
+ // If craftresult is nonempty and nothing else is selected, select it now.
+ if(!m_selected_item)
+ {
+ for(u32 i=0; i<m_draw_spec.size(); i++)
+ {
+ const ListDrawSpec &s = m_draw_spec[i];
+ if(s.listname == "craftpreview")
+ {
+ Inventory *inv = m_invmgr->getInventory(s.inventoryloc);
+ InventoryList *list = inv->getList("craftresult");
+ if(list && list->getSize() >= 1 && !list->getItem(0).empty())
+ {
+ m_selected_item = new ItemSpec;
+ m_selected_item->inventoryloc = s.inventoryloc;
+ m_selected_item->listname = "craftresult";
+ m_selected_item->i = 0;
+ m_selected_amount = 0;
+ m_selected_dragging = false;
+ break;
+ }
+ }
+ }
+ }
+
+ // If craftresult is selected, keep the whole stack selected
+ if(m_selected_item && m_selected_item->listname == "craftresult")
+ {
+ Inventory *inv = m_invmgr->getInventory(m_selected_item->inventoryloc);
+ assert(inv);
+ InventoryList *list = inv->getList(m_selected_item->listname);
+ assert(list);
+ m_selected_amount = list->getItem(m_selected_item->i).count;
+ }
+}
+
bool GUIInventoryMenu::OnEvent(const SEvent& event)
{
if(event.EventType==EET_KEY_INPUT_EVENT)
@@ -325,102 +494,268 @@ bool GUIInventoryMenu::OnEvent(const SEvent& event)
return true;
}
}
- if(event.EventType==EET_MOUSE_INPUT_EVENT)
+ if(event.EventType==EET_MOUSE_INPUT_EVENT
+ && event.MouseInput.Event == EMIE_MOUSE_MOVED)
+ {
+ // Mouse moved
+ m_pointer = v2s32(event.MouseInput.X, event.MouseInput.Y);
+ }
+ if(event.EventType==EET_MOUSE_INPUT_EVENT
+ && event.MouseInput.Event != EMIE_MOUSE_MOVED)
{
- char amount = -1;
+ // Mouse event other than movement
v2s32 p(event.MouseInput.X, event.MouseInput.Y);
+ m_pointer = p;
+
+ // Get selected item and hovered/clicked item (s)
+
+ updateSelectedItem();
ItemSpec s = getItemAtPos(p);
- if(event.MouseInput.Event==EMIE_MOUSE_MOVED)
- m_pointer = v2s32(event.MouseInput.X, event.MouseInput.Y);
- else if(event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN)
- amount = 0;
+ Inventory *inv_selected = NULL;
+ Inventory *inv_s = NULL;
+
+ if(m_selected_item)
+ {
+ inv_selected = m_invmgr->getInventory(m_selected_item->inventoryloc);
+ assert(inv_selected);
+ assert(inv_selected->getList(m_selected_item->listname) != NULL);
+ }
+
+ u32 s_count = 0;
+
+ if(s.isValid())
+ {
+ inv_s = m_invmgr->getInventory(s.inventoryloc);
+ assert(inv_s);
+
+ InventoryList *list = inv_s->getList(s.listname);
+ if(list != NULL && (u32) s.i < list->getSize())
+ s_count = list->getItem(s.i).count;
+ else
+ s.i = -1; // make it invalid again
+ }
+
+ bool identical = (m_selected_item != NULL) && s.isValid() &&
+ (inv_selected == inv_s) &&
+ (m_selected_item->listname == s.listname) &&
+ (m_selected_item->i == s.i);
+
+ // buttons: 0 = left, 1 = right, 2 = middle
+ // up/down: 0 = down (press), 1 = up (release), 2 = unknown event
+ int button = 0;
+ int updown = 2;
+ if(event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN)
+ { button = 0; updown = 0; }
else if(event.MouseInput.Event == EMIE_RMOUSE_PRESSED_DOWN)
- amount = 1;
+ { button = 1; updown = 0; }
else if(event.MouseInput.Event == EMIE_MMOUSE_PRESSED_DOWN)
- amount = 10;
- else if(event.MouseInput.Event == EMIE_LMOUSE_LEFT_UP &&
- m_selected_item &&
- (m_selected_item->listname != s.listname
- || m_selected_item->i != s.i))
- amount = 0;
-
-
- if(amount >= 0)
+ { button = 2; updown = 0; }
+ else if(event.MouseInput.Event == EMIE_LMOUSE_LEFT_UP)
+ { button = 0; updown = 1; }
+ else if(event.MouseInput.Event == EMIE_RMOUSE_LEFT_UP)
+ { button = 1; updown = 1; }
+ else if(event.MouseInput.Event == EMIE_MMOUSE_LEFT_UP)
+ { button = 2; updown = 1; }
+
+ // Set this number to a positive value to generate a move action
+ // from m_selected_item to s.
+ u32 move_amount = 0;
+
+ // Set this number to a positive value to generate a drop action
+ // from m_selected_item.
+ u32 drop_amount = 0;
+
+ // Set this number to a positive value to generate a craft action at s.
+ u32 craft_amount = 0;
+
+ if(updown == 0)
{
- //infostream<<"Mouse action at p=("<<p.X<<","<<p.Y<<")"<<std::endl;
- if(s.isValid())
+ // Some mouse button has been pressed
+
+ //infostream<<"Mouse button "<<button<<" pressed at p=("
+ // <<p.X<<","<<p.Y<<")"<<std::endl;
+
+ m_selected_dragging = false;
+
+ if(s.isValid() && s.listname == "craftpreview")
+ {
+ // Craft preview has been clicked: craft
+ craft_amount = (button == 2 ? 10 : 1);
+ }
+ else if(m_selected_item == NULL)
{
- infostream<<"Mouse action on "<<s.inventoryname
- <<"/"<<s.listname<<" "<<s.i<<std::endl;
- if(m_selected_item)
+ if(s_count != 0)
{
- Inventory *inv_from = m_invmgr->getInventory(m_c,
- m_selected_item->inventoryname);
- Inventory *inv_to = m_invmgr->getInventory(m_c,
- s.inventoryname);
- assert(inv_from);
- assert(inv_to);
- InventoryList *list_from =
- inv_from->getList(m_selected_item->listname);
- InventoryList *list_to =
- inv_to->getList(s.listname);
- if(list_from == NULL)
- infostream<<"from list doesn't exist"<<std::endl;
- if(list_to == NULL)
- infostream<<"to list doesn't exist"<<std::endl;
- // Indicates whether source slot completely empties
- bool source_empties = false;
- if(list_from && list_to
- && list_from->getItem(m_selected_item->i) != NULL)
- {
- infostream<<"Handing IACTION_MOVE to manager"<<std::endl;
- IMoveAction *a = new IMoveAction();
- a->count = amount;
- a->from_inv = m_selected_item->inventoryname;
- a->from_list = m_selected_item->listname;
- a->from_i = m_selected_item->i;
- a->to_inv = s.inventoryname;
- a->to_list = s.listname;
- a->to_i = s.i;
- //ispec.actions->push_back(a);
- m_invmgr->inventoryAction(a);
-
- if(list_from->getItem(m_selected_item->i)->getCount()<=amount)
- source_empties = true;
- }
- // Remove selection if target was left-clicked or source
- // slot was emptied
- if(amount == 0 || source_empties)
+ // Non-empty stack has been clicked: select it
+ m_selected_item = new ItemSpec(s);
+
+ if(button == 1) // right
+ m_selected_amount = (s_count + 1) / 2;
+ else if(button == 2) // middle
+ m_selected_amount = MYMIN(s_count, 10);
+ else // left
+ m_selected_amount = s_count;
+
+ m_selected_dragging = true;
+ }
+ }
+ else // m_selected_item != NULL
+ {
+ assert(m_selected_amount >= 1);
+
+ if(s.isValid())
+ {
+ // Clicked a slot: move
+ if(button == 1) // right
+ move_amount = 1;
+ else if(button == 2) // middle
+ move_amount = MYMIN(m_selected_amount, 10);
+ else // left
+ move_amount = m_selected_amount;
+
+ if(identical)
{
- delete m_selected_item;
- m_selected_item = NULL;
+ if(move_amount >= m_selected_amount)
+ m_selected_amount = 0;
+ else
+ m_selected_amount -= move_amount;
+ move_amount = 0;
}
}
+ else if(getAbsoluteClippingRect().isPointInside(m_pointer))
+ {
+ // Clicked somewhere else: deselect
+ m_selected_amount = 0;
+ }
else
{
- /*
- Select if non-NULL
- */
- Inventory *inv = m_invmgr->getInventory(m_c,
- s.inventoryname);
- assert(inv);
- InventoryList *list = inv->getList(s.listname);
- if(list->getItem(s.i) != NULL)
- {
- m_selected_item = new ItemSpec(s);
- }
+ // Clicked outside of the window: drop
+ if(button == 1) // right
+ drop_amount = 1;
+ else if(button == 2) // middle
+ drop_amount = MYMIN(m_selected_amount, 10);
+ else // left
+ drop_amount = m_selected_amount;
}
}
- else
+ }
+ else if(updown == 1)
+ {
+ // Some mouse button has been released
+
+ //infostream<<"Mouse button "<<button<<" released at p=("
+ // <<p.X<<","<<p.Y<<")"<<std::endl;
+
+ if(m_selected_item != NULL && m_selected_dragging && s.isValid())
{
- if(m_selected_item)
+ if(!identical)
{
- delete m_selected_item;
- m_selected_item = NULL;
+ // Dragged to different slot: move all selected
+ move_amount = m_selected_amount;
}
}
+ else if(m_selected_item != NULL && m_selected_dragging &&
+ !(getAbsoluteClippingRect().isPointInside(m_pointer)))
+ {
+ // Dragged outside of window: drop all selected
+ drop_amount = m_selected_amount;
+ }
+
+ m_selected_dragging = false;
+ }
+
+ // Possibly send inventory action to server
+ if(move_amount > 0)
+ {
+ // Send IACTION_MOVE
+
+ assert(m_selected_item && m_selected_item->isValid());
+ assert(s.isValid());
+
+ assert(inv_selected && inv_s);
+ InventoryList *list_from = inv_selected->getList(m_selected_item->listname);
+ InventoryList *list_to = inv_s->getList(s.listname);
+ assert(list_from && list_to);
+ ItemStack stack_from = list_from->getItem(m_selected_item->i);
+ ItemStack stack_to = list_to->getItem(s.i);
+
+ // Check how many items can be moved
+ move_amount = stack_from.count = MYMIN(move_amount, stack_from.count);
+ ItemStack leftover = stack_to.addItem(stack_from, m_gamedef->idef());
+ if(leftover.count == stack_from.count)
+ {
+ // Swap the stacks
+ m_selected_amount -= stack_to.count;
+ }
+ else if(leftover.empty())
+ {
+ // Item fits
+ m_selected_amount -= move_amount;
+ }
+ else
+ {
+ // Item only fits partially
+ move_amount -= leftover.count;
+ m_selected_amount -= move_amount;
+ }
+
+ infostream<<"Handing IACTION_MOVE to manager"<<std::endl;
+ IMoveAction *a = new IMoveAction();
+ a->count = move_amount;
+ a->from_inv = m_selected_item->inventoryloc;
+ a->from_list = m_selected_item->listname;
+ a->from_i = m_selected_item->i;
+ a->to_inv = s.inventoryloc;
+ a->to_list = s.listname;
+ a->to_i = s.i;
+ m_invmgr->inventoryAction(a);
+ }
+ else if(drop_amount > 0)
+ {
+ // Send IACTION_DROP
+
+ assert(m_selected_item && m_selected_item->isValid());
+ assert(inv_selected);
+ InventoryList *list_from = inv_selected->getList(m_selected_item->listname);
+ assert(list_from);
+ ItemStack stack_from = list_from->getItem(m_selected_item->i);
+
+ // Check how many items can be dropped
+ drop_amount = stack_from.count = MYMIN(drop_amount, stack_from.count);
+ assert(drop_amount > 0 && drop_amount <= m_selected_amount);
+ m_selected_amount -= drop_amount;
+
+ infostream<<"Handing IACTION_DROP to manager"<<std::endl;
+ IDropAction *a = new IDropAction();
+ a->count = drop_amount;
+ a->from_inv = m_selected_item->inventoryloc;
+ a->from_list = m_selected_item->listname;
+ a->from_i = m_selected_item->i;
+ m_invmgr->inventoryAction(a);
+ }
+ else if(craft_amount > 0)
+ {
+ // Send IACTION_CRAFT
+
+ assert(s.isValid());
+ assert(inv_s);
+
+ infostream<<"Handing IACTION_CRAFT to manager"<<std::endl;
+ ICraftAction *a = new ICraftAction();
+ a->count = craft_amount;
+ a->craft_inv = s.inventoryloc;
+ m_invmgr->inventoryAction(a);
+ }
+
+ // If m_selected_amount has been decreased to zero, deselect
+ if(m_selected_amount == 0)
+ {
+ delete m_selected_item;
+ m_selected_item = NULL;
+ m_selected_amount = 0;
+ m_selected_dragging = false;
}
}
if(event.EventType==EET_GUI_EVENT)
@@ -489,7 +824,7 @@ bool GUIInventoryMenu::OnEvent(const SEvent& event)
v2s16 GUIInventoryMenu::makeDrawSpecArrayFromString(
core::array<GUIInventoryMenu::DrawSpec> &draw_spec,
const std::string &data,
- const std::string &current_name)
+ const InventoryLocation &current_location)
{
v2s16 invsize(8,9);
Strfnd f(data);
@@ -500,8 +835,11 @@ v2s16 GUIInventoryMenu::makeDrawSpecArrayFromString(
if(type == "list")
{
std::string name = f.next(";");
+ InventoryLocation loc;
if(name == "current_name")
- name = current_name;
+ loc = current_location;
+ else
+ loc.deSerialize(name);
std::string subname = f.next(";");
s32 pos_x = stoi(f.next(","));
s32 pos_y = stoi(f.next(";"));
@@ -512,7 +850,7 @@ v2s16 GUIInventoryMenu::makeDrawSpecArrayFromString(
<<", geom=("<<geom_x<<","<<geom_y<<")"
<<std::endl;
draw_spec.push_back(GUIInventoryMenu::DrawSpec(
- type, name, subname,
+ type, loc, subname,
v2s32(pos_x,pos_y),v2s32(geom_x,geom_y)));
f.next("]");
}
diff --git a/src/guiInventoryMenu.h b/src/guiInventoryMenu.h
index 359268687..ed8df88fc 100644
--- a/src/guiInventoryMenu.h
+++ b/src/guiInventoryMenu.h
@@ -23,18 +23,19 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "common_irrlicht.h"
#include "inventory.h"
+#include "inventorymanager.h"
#include "utility.h"
#include "modalMenu.h"
-class ITextureSource;
-class InventoryContext;
+class IGameDef;
class InventoryManager;
-void drawInventoryItem(video::IVideoDriver *driver,
+void drawItemStack(video::IVideoDriver *driver,
gui::IGUIFont *font,
- InventoryItem *item, core::rect<s32> rect,
+ const ItemStack &item,
+ const core::rect<s32> &rect,
const core::rect<s32> *clip,
- ITextureSource *tsrc);
+ IGameDef *gamedef);
class GUIInventoryMenu : public GUIModalMenu
{
@@ -44,11 +45,11 @@ class GUIInventoryMenu : public GUIModalMenu
{
i = -1;
}
- ItemSpec(const std::string &a_inventoryname,
+ ItemSpec(const InventoryLocation &a_inventoryloc,
const std::string &a_listname,
s32 a_i)
{
- inventoryname = a_inventoryname;
+ inventoryloc = a_inventoryloc;
listname = a_listname;
i = a_i;
}
@@ -57,7 +58,7 @@ class GUIInventoryMenu : public GUIModalMenu
return i != -1;
}
- std::string inventoryname;
+ InventoryLocation inventoryloc;
std::string listname;
s32 i;
};
@@ -67,17 +68,17 @@ class GUIInventoryMenu : public GUIModalMenu
ListDrawSpec()
{
}
- ListDrawSpec(const std::string &a_inventoryname,
+ ListDrawSpec(const InventoryLocation &a_inventoryloc,
const std::string &a_listname,
v2s32 a_pos, v2s32 a_geom)
{
- inventoryname = a_inventoryname;
+ inventoryloc = a_inventoryloc;
listname = a_listname;
pos = a_pos;
geom = a_geom;
}
- std::string inventoryname;
+ InventoryLocation inventoryloc;
std::string listname;
v2s32 pos;
v2s32 geom;
@@ -89,7 +90,7 @@ public:
{
}
DrawSpec(const std::string &a_type,
- const std::string &a_name,
+ const InventoryLocation &a_name,
const std::string &a_subname,
v2s32 a_pos,
v2s32 a_geom)
@@ -102,7 +103,7 @@ public:
}
std::string type;
- std::string name;
+ InventoryLocation name;
std::string subname;
v2s32 pos;
v2s32 geom;
@@ -112,15 +113,14 @@ public:
static v2s16 makeDrawSpecArrayFromString(
core::array<GUIInventoryMenu::DrawSpec> &draw_spec,
const std::string &data,
- const std::string &current_name);
+ const InventoryLocation &current_location);
GUIInventoryMenu(gui::IGUIEnvironment* env,
gui::IGUIElement* parent, s32 id,
IMenuManager *menumgr,
v2s16 menu_size,
- InventoryContext *c,
InventoryManager *invmgr,
- ITextureSource *tsrc
+ IGameDef *gamedef
);
~GUIInventoryMenu();
@@ -136,8 +136,10 @@ public:
void regenerateGui(v2u32 screensize);
ItemSpec getItemAtPos(v2s32 p) const;
- void drawList(const ListDrawSpec &s, ITextureSource *tsrc);
+ void drawList(const ListDrawSpec &s, int phase);
+ void drawSelectedItem();
void drawMenu();
+ void updateSelectedItem();
bool OnEvent(const SEvent& event);
@@ -153,15 +155,18 @@ protected:
v2s32 spacing;
v2s32 imgsize;
- InventoryContext *m_c;
InventoryManager *m_invmgr;
- ITextureSource *m_tsrc;
+ IGameDef *m_gamedef;
core::array<DrawSpec> m_init_draw_spec;
core::array<ListDrawSpec> m_draw_spec;
ItemSpec *m_selected_item;
+ u32 m_selected_amount;
+ bool m_selected_dragging;
+
v2s32 m_pointer;
+ gui::IGUIStaticText *m_tooltip_element;
};
#endif
diff --git a/src/inventory.cpp b/src/inventory.cpp
index 0d38bed78..056cf552d 100644
--- a/src/inventory.cpp
+++ b/src/inventory.cpp
@@ -22,545 +22,430 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "utility.h"
#include "debug.h"
#include <sstream>
-#include "main.h" // For tsrc, g_toolmanager
-#include "serverobject.h"
-#include "content_mapnode.h"
-#include "content_sao.h"
-#include "environment.h"
-#include "mapblock.h"
-#include "player.h"
#include "log.h"
-#include "nodedef.h"
-#include "tooldef.h"
-#include "craftitemdef.h"
-#include "gamedef.h"
-#include "scriptapi.h"
+#include "itemdef.h"
#include "strfnd.h"
+#include "content_mapnode.h" // For loading legacy MaterialItems
#include "nameidmapping.h" // For loading legacy MaterialItems
/*
- InventoryItem
+ ItemStack
*/
-InventoryItem::InventoryItem(IGameDef *gamedef, u16 count):
- m_gamedef(gamedef),
- m_count(count)
+static content_t content_translate_from_19_to_internal(content_t c_from)
{
- assert(m_gamedef);
+ for(u32 i=0; i<sizeof(trans_table_19)/sizeof(trans_table_19[0]); i++)
+ {
+ if(trans_table_19[i][1] == c_from)
+ {
+ return trans_table_19[i][0];
+ }
+ }
+ return c_from;
}
-InventoryItem::~InventoryItem()
+// If the string contains spaces, quotes or control characters, encodes as JSON.
+// Else returns the string unmodified.
+static std::string serializeJsonStringIfNeeded(const std::string &s)
{
+ for(size_t i = 0; i < s.size(); ++i)
+ {
+ if(s[i] <= 0x1f || s[i] >= 0x7f || s[i] == ' ' || s[i] == '\"')
+ return serializeJsonString(s);
+ }
+ return s;
}
-content_t content_translate_from_19_to_internal(content_t c_from)
+// Parses a string serialized by serializeJsonStringIfNeeded.
+static std::string deSerializeJsonStringIfNeeded(std::istream &is)
{
- for(u32 i=0; i<sizeof(trans_table_19)/sizeof(trans_table_19[0]); i++)
+ std::ostringstream tmp_os;
+ bool expect_initial_quote = true;
+ bool is_json = false;
+ bool was_backslash = false;
+ for(;;)
{
- if(trans_table_19[i][1] == c_from)
+ char c = is.get();
+ if(is.eof())
+ break;
+ if(expect_initial_quote && c == '"')
{
- return trans_table_19[i][0];
+ tmp_os << c;
+ is_json = true;
}
+ else if(is_json)
+ {
+ tmp_os << c;
+ if(was_backslash)
+ was_backslash = false;
+ else if(c == '\\')
+ was_backslash = true;
+ else if(c == '"')
+ break; // Found end of string
+ }
+ else
+ {
+ if(c == ' ')
+ {
+ // Found end of word
+ is.unget();
+ break;
+ }
+ else
+ {
+ tmp_os << c;
+ }
+ }
+ expect_initial_quote = false;
}
- return c_from;
+ if(is_json)
+ {
+ std::istringstream tmp_is(tmp_os.str(), std::ios::binary);
+ return deSerializeJsonString(tmp_is);
+ }
+ else
+ return tmp_os.str();
+}
+
+
+ItemStack::ItemStack(std::string name_, u16 count_,
+ u16 wear_, std::string metadata_,
+ IItemDefManager *itemdef)
+{
+ name = itemdef->getAlias(name_);
+ count = count_;
+ wear = wear_;
+ metadata = metadata_;
+
+ if(name.empty() || count == 0)
+ clear();
+ else if(itemdef->get(name).type == ITEM_TOOL)
+ count = 1;
}
-InventoryItem* InventoryItem::deSerialize(std::istream &is, IGameDef *gamedef)
+void ItemStack::serialize(std::ostream &os) const
{
DSTACK(__FUNCTION_NAME);
- //is.imbue(std::locale("C"));
+ if(empty())
+ return;
+
+ // Check how many parts of the itemstring are needed
+ int parts = 1;
+ if(count != 1)
+ parts = 2;
+ if(wear != 0)
+ parts = 3;
+ if(metadata != "")
+ parts = 4;
+
+ os<<serializeJsonStringIfNeeded(name);
+ if(parts >= 2)
+ os<<" "<<count;
+ if(parts >= 3)
+ os<<" "<<wear;
+ if(parts >= 4)
+ os<<" "<<serializeJsonStringIfNeeded(metadata);
+}
+
+void ItemStack::deSerialize(std::istream &is, IItemDefManager *itemdef)
+{
+ DSTACK(__FUNCTION_NAME);
+
+ clear();
+
// Read name
- std::string name;
- std::getline(is, name, ' ');
+ name = deSerializeJsonStringIfNeeded(is);
+
+ // Skip space
+ std::string tmp;
+ std::getline(is, tmp, ' ');
+ if(!tmp.empty())
+ throw SerializationError("Unexpected text after item name");
if(name == "MaterialItem")
{
- // u16 reads directly as a number (u8 doesn't)
+ // Obsoleted on 2011-07-30
+
u16 material;
is>>material;
- u16 count;
- is>>count;
+ u16 materialcount;
+ is>>materialcount;
// Convert old materials
if(material <= 0xff)
material = content_translate_from_19_to_internal(material);
if(material > MAX_CONTENT)
throw SerializationError("Too large material number");
- return new MaterialItem(gamedef, material, count);
+ // Convert old id to name
+ NameIdMapping legacy_nimap;
+ content_mapnode_get_name_id_mapping(&legacy_nimap);
+ legacy_nimap.getName(material, name);
+ if(name == "")
+ name = "unknown_block";
+ name = itemdef->getAlias(name);
+ count = materialcount;
}
else if(name == "MaterialItem2")
{
+ // Obsoleted on 2011-11-16
+
u16 material;
is>>material;
- u16 count;
- is>>count;
+ u16 materialcount;
+ is>>materialcount;
if(material > MAX_CONTENT)
throw SerializationError("Too large material number");
- return new MaterialItem(gamedef, material, count);
+ // Convert old id to name
+ NameIdMapping legacy_nimap;
+ content_mapnode_get_name_id_mapping(&legacy_nimap);
+ legacy_nimap.getName(material, name);
+ if(name == "")
+ name = "unknown_block";
+ name = itemdef->getAlias(name);
+ count = materialcount;
}
- else if(name == "node" || name == "NodeItem" || name == "MaterialItem3")
+ else if(name == "node" || name == "NodeItem" || name == "MaterialItem3"
+ || name == "craft" || name == "CraftItem")
{
+ // Obsoleted on 2012-01-07
+
std::string all;
std::getline(is, all, '\n');
- std::string nodename;
// First attempt to read inside ""
Strfnd fnd(all);
fnd.next("\"");
// If didn't skip to end, we have ""s
if(!fnd.atend()){
- nodename = fnd.next("\"");
+ name = fnd.next("\"");
} else { // No luck, just read a word then
fnd.start(all);
- nodename = fnd.next(" ");
+ name = fnd.next(" ");
}
fnd.skip_over(" ");
- u16 count = stoi(trim(fnd.next("")));
+ name = itemdef->getAlias(name);
+ count = stoi(trim(fnd.next("")));
if(count == 0)
count = 1;
- return new MaterialItem(gamedef, nodename, count);
}
else if(name == "MBOItem")
{
- std::string inventorystring;
- std::getline(is, inventorystring, '|');
+ // Obsoleted on 2011-10-14
throw SerializationError("MBOItem not supported anymore");
}
- else if(name == "craft" || name == "CraftItem")
- {
- std::string all;
- std::getline(is, all, '\n');
- std::string subname;
- // First attempt to read inside ""
- Strfnd fnd(all);
- fnd.next("\"");
- // If didn't skip to end, we have ""s
- if(!fnd.atend()){
- subname = fnd.next("\"");
- } else { // No luck, just read a word then
- fnd.start(all);
- subname = fnd.next(" ");
- }
- // Then read count
- fnd.skip_over(" ");
- u16 count = stoi(trim(fnd.next("")));
- if(count == 0)
- count = 1;
- return new CraftItem(gamedef, subname, count);
- }
else if(name == "tool" || name == "ToolItem")
{
+ // Obsoleted on 2012-01-07
+
std::string all;
std::getline(is, all, '\n');
- std::string toolname;
// First attempt to read inside ""
Strfnd fnd(all);
fnd.next("\"");
// If didn't skip to end, we have ""s
if(!fnd.atend()){
- toolname = fnd.next("\"");
+ name = fnd.next("\"");
} else { // No luck, just read a word then
fnd.start(all);
- toolname = fnd.next(" ");
+ name = fnd.next(" ");
}
+ count = 1;
// Then read wear
fnd.skip_over(" ");
- u16 wear = stoi(trim(fnd.next("")));
- return new ToolItem(gamedef, toolname, wear);
+ name = itemdef->getAlias(name);
+ wear = stoi(trim(fnd.next("")));
}
else
{
- infostream<<"Unknown InventoryItem name=\""<<name<<"\""<<std::endl;
- throw SerializationError("Unknown InventoryItem name");
- }
-}
-
-InventoryItem* InventoryItem::deSerialize(const std::string &str,
- IGameDef *gamedef)
-{
- std::istringstream is(str, std::ios_base::binary);
- return deSerialize(is, gamedef);
-}
-
-std::string InventoryItem::getItemString() {
- // Get item string
- std::ostringstream os(std::ios_base::binary);
- serialize(os);
- return os.str();
-}
-
-bool InventoryItem::dropOrPlace(ServerEnvironment *env,
- ServerActiveObject *dropper,
- v3f pos, bool place, s16 count)
-{
- /*
- Ensure that the block is loaded so that the item
- can properly be added to the static list too
- */
- v3s16 blockpos = getNodeBlockPos(floatToInt(pos, BS));
- MapBlock *block = env->getMap().emergeBlock(blockpos, false);
- if(block==NULL)
- {
- infostream<<"InventoryItem::dropOrPlace(): FAIL: block not found: "
- <<blockpos.X<<","<<blockpos.Y<<","<<blockpos.Z
- <<std::endl;
- return false;
- }
-
- /*
- Take specified number of items,
- but limit to getDropCount().
- */
- s16 dropcount = getDropCount();
- if(count < 0 || count > dropcount)
- count = dropcount;
- if(count < 0 || count > getCount())
- count = getCount();
- if(count > 0)
- {
- /*
- Create an ItemSAO
- */
- pos.Y -= BS*0.25; // let it drop a bit
- // Randomize a bit
- //pos.X += BS*0.2*(float)myrand_range(-1000,1000)/1000.0;
- //pos.Z += BS*0.2*(float)myrand_range(-1000,1000)/1000.0;
- // Create object
- ServerActiveObject *obj = new ItemSAO(env, pos, getItemString());
- // Add the object to the environment
- env->addActiveObject(obj);
- infostream<<"Dropped item"<<std::endl;
-
- setCount(getCount() - count);
- }
-
- return getCount() < 1; // delete the item?
-}
-
-/*
- MaterialItem
-*/
-
-MaterialItem::MaterialItem(IGameDef *gamedef, std::string nodename, u16 count):
- InventoryItem(gamedef, count)
-{
- if(nodename == "")
- nodename = "unknown_block";
-
- // Convert directly to the correct name through aliases
- m_nodename = gamedef->ndef()->getAlias(nodename);
-}
-// Legacy constructor
-MaterialItem::MaterialItem(IGameDef *gamedef, content_t content, u16 count):
- InventoryItem(gamedef, count)
-{
- NameIdMapping legacy_nimap;
- content_mapnode_get_name_id_mapping(&legacy_nimap);
- std::string nodename;
- legacy_nimap.getName(content, nodename);
- if(nodename == "")
- nodename = "unknown_block";
- m_nodename = nodename;
-}
-
-#ifndef SERVER
-video::ITexture * MaterialItem::getImage() const
-{
- return m_gamedef->getNodeDefManager()->get(m_nodename).inventory_texture;
-}
-#endif
-
-bool MaterialItem::isCookable() const
-{
- INodeDefManager *ndef = m_gamedef->ndef();
- const ContentFeatures &f = ndef->get(m_nodename);
- return (f.cookresult_item != "");
-}
-
-InventoryItem *MaterialItem::createCookResult() const
-{
- INodeDefManager *ndef = m_gamedef->ndef();
- const ContentFeatures &f = ndef->get(m_nodename);
- std::istringstream is(f.cookresult_item, std::ios::binary);
- return InventoryItem::deSerialize(is, m_gamedef);
-}
-
-float MaterialItem::getCookTime() const
-{
- INodeDefManager *ndef = m_gamedef->ndef();
- const ContentFeatures &f = ndef->get(m_nodename);
- return f.furnace_cooktime;
-}
-
-float MaterialItem::getBurnTime() const
-{
- INodeDefManager *ndef = m_gamedef->ndef();
- const ContentFeatures &f = ndef->get(m_nodename);
- return f.furnace_burntime;
-}
-
-content_t MaterialItem::getMaterial() const
-{
- INodeDefManager *ndef = m_gamedef->ndef();
- content_t id = CONTENT_IGNORE;
- ndef->getId(m_nodename, id);
- return id;
-}
-
-/*
- ToolItem
-*/
-
-ToolItem::ToolItem(IGameDef *gamedef, std::string toolname, u16 wear):
- InventoryItem(gamedef, 1)
-{
- // Convert directly to the correct name through aliases
- m_toolname = gamedef->tdef()->getAlias(toolname);
-
- m_wear = wear;
-}
-
-std::string ToolItem::getImageBasename() const
-{
- return m_gamedef->getToolDefManager()->getImagename(m_toolname);
-}
-
-#ifndef SERVER
-video::ITexture * ToolItem::getImage() const
-{
- ITextureSource *tsrc = m_gamedef->tsrc();
-
- std::string basename = getImageBasename();
-
- /*
- Calculate a progress value with sane amount of
- maximum states
- */
- u32 maxprogress = 30;
- u32 toolprogress = (65535-m_wear)/(65535/maxprogress);
-
- float value_f = (float)toolprogress / (float)maxprogress;
- std::ostringstream os;
- os<<basename<<"^[progressbar"<<value_f;
-
- return tsrc->getTextureRaw(os.str());
-}
-
-video::ITexture * ToolItem::getImageRaw() const
-{
- ITextureSource *tsrc = m_gamedef->tsrc();
-
- return tsrc->getTextureRaw(getImageBasename());
-}
-#endif
-
-bool ToolItem::isKnown() const
-{
- IToolDefManager *tdef = m_gamedef->tdef();
- const ToolDefinition *def = tdef->getToolDefinition(m_toolname);
- return (def != NULL);
-}
+ do // This loop is just to allow "break;"
+ {
+ // The real thing
-/*
- CraftItem
-*/
+ // Apply item aliases
+ name = itemdef->getAlias(name);
-CraftItem::CraftItem(IGameDef *gamedef, std::string subname, u16 count):
- InventoryItem(gamedef, count)
-{
- // Convert directly to the correct name through aliases
- m_subname = gamedef->cidef()->getAlias(subname);
-}
+ // Read the count
+ std::string count_str;
+ std::getline(is, count_str, ' ');
+ if(count_str.empty())
+ {
+ count = 1;
+ break;
+ }
+ else
+ count = stoi(count_str);
-#ifndef SERVER
-video::ITexture * CraftItem::getImage() const
-{
- ICraftItemDefManager *cidef = m_gamedef->cidef();
- ITextureSource *tsrc = m_gamedef->tsrc();
- std::string imagename = cidef->getImagename(m_subname);
- return tsrc->getTextureRaw(imagename);
-}
-#endif
+ // Read the wear
+ std::string wear_str;
+ std::getline(is, wear_str, ' ');
+ if(wear_str.empty())
+ break;
+ else
+ wear = stoi(wear_str);
-bool CraftItem::isKnown() const
-{
- ICraftItemDefManager *cidef = m_gamedef->cidef();
- const CraftItemDefinition *def = cidef->getCraftItemDefinition(m_subname);
- return (def != NULL);
-}
+ // Read metadata
+ metadata = deSerializeJsonStringIfNeeded(is);
-u16 CraftItem::getStackMax() const
-{
- ICraftItemDefManager *cidef = m_gamedef->cidef();
- const CraftItemDefinition *def = cidef->getCraftItemDefinition(m_subname);
- if(def == NULL)
- return InventoryItem::getStackMax();
- return def->stack_max;
-}
+ // In case fields are added after metadata, skip space here:
+ //std::getline(is, tmp, ' ');
+ //if(!tmp.empty())
+ // throw SerializationError("Unexpected text after metadata");
-bool CraftItem::isUsable() const
-{
- ICraftItemDefManager *cidef = m_gamedef->cidef();
- const CraftItemDefinition *def = cidef->getCraftItemDefinition(m_subname);
- return def != NULL && def->usable;
-}
+ } while(false);
+ }
-bool CraftItem::isCookable() const
-{
- ICraftItemDefManager *cidef = m_gamedef->cidef();
- const CraftItemDefinition *def = cidef->getCraftItemDefinition(m_subname);
- return def != NULL && def->cookresult_item != "";
+ if(name.empty() || count == 0)
+ clear();
+ else if(itemdef->get(name).type == ITEM_TOOL)
+ count = 1;
}
-InventoryItem *CraftItem::createCookResult() const
+void ItemStack::deSerialize(const std::string &str, IItemDefManager *itemdef)
{
- ICraftItemDefManager *cidef = m_gamedef->cidef();
- const CraftItemDefinition *def = cidef->getCraftItemDefinition(m_subname);
- if(def == NULL)
- return InventoryItem::createCookResult();
- std::istringstream is(def->cookresult_item, std::ios::binary);
- return InventoryItem::deSerialize(is, m_gamedef);
+ std::istringstream is(str, std::ios::binary);
+ deSerialize(is, itemdef);
}
-float CraftItem::getCookTime() const
+std::string ItemStack::getItemString() const
{
- ICraftItemDefManager *cidef = m_gamedef->cidef();
- const CraftItemDefinition *def = cidef->getCraftItemDefinition(m_subname);
- if (def == NULL)
- return InventoryItem::getCookTime();
- return def->furnace_cooktime;
+ // Get item string
+ std::ostringstream os(std::ios::binary);
+ serialize(os);
+ return os.str();
}
-float CraftItem::getBurnTime() const
+ItemStack ItemStack::addItem(const ItemStack &newitem_,
+ IItemDefManager *itemdef)
{
- ICraftItemDefManager *cidef = m_gamedef->cidef();
- const CraftItemDefinition *def = cidef->getCraftItemDefinition(m_subname);
- if (def == NULL)
- return InventoryItem::getBurnTime();
- return def->furnace_burntime;
-}
+ ItemStack newitem = newitem_;
-s16 CraftItem::getDropCount() const
-{
- // Special cases
- ICraftItemDefManager *cidef = m_gamedef->cidef();
- const CraftItemDefinition *def = cidef->getCraftItemDefinition(m_subname);
- if(def != NULL && def->dropcount >= 0)
- return def->dropcount;
- // Default
- return InventoryItem::getDropCount();
-}
+ // If the item is empty or the position invalid, bail out
+ if(newitem.empty())
+ {
+ // nothing can be added trivially
+ }
+ // If this is an empty item, it's an easy job.
+ else if(empty())
+ {
+ *this = newitem;
+ newitem.clear();
+ }
+ // If item name differs, bail out
+ else if(name != newitem.name)
+ {
+ // cannot be added
+ }
+ // If the item fits fully, add counter and delete it
+ else if(newitem.count <= freeSpace(itemdef))
+ {
+ add(newitem.count);
+ newitem.clear();
+ }
+ // Else the item does not fit fully. Add all that fits and return
+ // the rest.
+ else
+ {
+ u16 freespace = freeSpace(itemdef);
+ add(freespace);
+ newitem.remove(freespace);
+ }
-bool CraftItem::areLiquidsPointable() const
-{
- ICraftItemDefManager *cidef = m_gamedef->cidef();
- const CraftItemDefinition *def = cidef->getCraftItemDefinition(m_subname);
- return def != NULL && def->liquids_pointable;
+ return newitem;
}
-bool CraftItem::dropOrPlace(ServerEnvironment *env,
- ServerActiveObject *dropper,
- v3f pos, bool place, s16 count)
+bool ItemStack::itemFits(const ItemStack &newitem_,
+ ItemStack *restitem,
+ IItemDefManager *itemdef) const
{
- if(count == 0)
- return false;
+ ItemStack newitem = newitem_;
- bool callback_exists = false;
- bool result = false;
-
- if(place)
+ // If the item is empty or the position invalid, bail out
+ if(newitem.empty())
{
- result = scriptapi_craftitem_on_place_on_ground(
- env->getLua(),
- m_subname.c_str(), dropper, pos,
- callback_exists);
+ // nothing can be added trivially
}
-
- // note: on_drop is fallback for on_place_on_ground
-
- if(!callback_exists)
+ // If this is an empty item, it's an easy job.
+ else if(empty())
{
- result = scriptapi_craftitem_on_drop(
- env->getLua(),
- m_subname.c_str(), dropper, pos,
- callback_exists);
+ newitem.clear();
}
-
- if(callback_exists)
+ // If item name differs, bail out
+ else if(name != newitem.name)
{
- // If the callback returned true, drop one item
- if(result)
- setCount(getCount() - 1);
- return getCount() < 1;
+ // cannot be added
}
+ // If the item fits fully, delete it
+ else if(newitem.count <= freeSpace(itemdef))
+ {
+ newitem.clear();
+ }
+ // Else the item does not fit fully. Return the rest.
+ // the rest.
else
{
- // If neither on_place_on_ground (if place==true)
- // nor on_drop exists, call the base implementation
- return InventoryItem::dropOrPlace(env, dropper, pos, place, count);
+ u16 freespace = freeSpace(itemdef);
+ newitem.remove(freespace);
}
+
+ if(restitem)
+ *restitem = newitem;
+ return newitem.empty();
}
-bool CraftItem::use(ServerEnvironment *env,
- ServerActiveObject *user,
- const PointedThing& pointed)
+ItemStack ItemStack::takeItem(u32 takecount)
{
- bool callback_exists = false;
- bool result = false;
-
- result = scriptapi_craftitem_on_use(
- env->getLua(),
- m_subname.c_str(), user, pointed,
- callback_exists);
+ if(takecount == 0 || count == 0)
+ return ItemStack();
- if(callback_exists)
+ ItemStack result = *this;
+ if(takecount >= count)
{
- // If the callback returned true, drop one item
- if(result)
- setCount(getCount() - 1);
- return getCount() < 1;
+ // Take all
+ clear();
}
else
{
- // If neither on_place_on_ground (if place==true)
- // nor on_drop exists, call the base implementation
- return InventoryItem::use(env, user, pointed);
+ // Take part
+ remove(takecount);
+ result.count = takecount;
}
+ return result;
+}
+
+ItemStack ItemStack::peekItem(u32 peekcount) const
+{
+ if(peekcount == 0 || count == 0)
+ return ItemStack();
+
+ ItemStack result = *this;
+ if(peekcount < count)
+ result.count = peekcount;
+ return result;
}
/*
Inventory
*/
-InventoryList::InventoryList(std::string name, u32 size)
+InventoryList::InventoryList(std::string name, u32 size, IItemDefManager *itemdef)
{
m_name = name;
m_size = size;
+ m_itemdef = itemdef;
clearItems();
//m_dirty = false;
}
InventoryList::~InventoryList()
{
- for(u32 i=0; i<m_items.size(); i++)
- {
- if(m_items[i])
- delete m_items[i];
- }
}
void InventoryList::clearItems()
{
- for(u32 i=0; i<m_items.size(); i++)
- {
- if(m_items[i])
- delete m_items[i];
- }
-
m_items.clear();
for(u32 i=0; i<m_size; i++)
{
- m_items.push_back(NULL);
+ m_items.push_back(ItemStack());
}
//setDirty(true);
@@ -568,17 +453,8 @@ void InventoryList::clearItems()
void InventoryList::setSize(u32 newsize)
{
- if(newsize < m_items.size()){
- for(u32 i=newsize; i<m_items.size(); i++){
- if(m_items[i])
- delete m_items[i];
- }
- m_items.erase(newsize, m_items.size() - newsize);
- } else {
- for(u32 i=m_items.size(); i<newsize; i++){
- m_items.push_back(NULL);
- }
- }
+ if(newsize != m_items.size())
+ m_items.resize(newsize);
m_size = newsize;
}
@@ -588,15 +464,15 @@ void InventoryList::serialize(std::ostream &os) const
for(u32 i=0; i<m_items.size(); i++)
{
- InventoryItem *item = m_items[i];
- if(item != NULL)
+ const ItemStack &item = m_items[i];
+ if(item.empty())
{
- os<<"Item ";
- item->serialize(os);
+ os<<"Empty";
}
else
{
- os<<"Empty";
+ os<<"Item ";
+ item.serialize(os);
}
os<<"\n";
}
@@ -604,7 +480,7 @@ void InventoryList::serialize(std::ostream &os) const
os<<"EndInventoryList\n";
}
-void InventoryList::deSerialize(std::istream &is, IGameDef *gamedef)
+void InventoryList::deSerialize(std::istream &is)
{
//is.imbue(std::locale("C"));
@@ -635,14 +511,15 @@ void InventoryList::deSerialize(std::istream &is, IGameDef *gamedef)
{
if(item_i > getSize() - 1)
throw SerializationError("too many items");
- InventoryItem *item = InventoryItem::deSerialize(iss, gamedef);
+ ItemStack item;
+ item.deSerialize(iss, m_itemdef);
m_items[item_i++] = item;
}
else if(name == "Empty")
{
if(item_i > getSize() - 1)
throw SerializationError("too many items");
- m_items[item_i++] = NULL;
+ m_items[item_i++].clear();
}
else
{
@@ -653,26 +530,15 @@ void InventoryList::deSerialize(std::istream &is, IGameDef *gamedef)
InventoryList::InventoryList(const InventoryList &other)
{
- /*
- Do this so that the items get cloned. Otherwise the pointers
- in the array will just get copied.
- */
*this = other;
}
InventoryList & InventoryList::operator = (const InventoryList &other)
{
- m_name = other.m_name;
+ m_items = other.m_items;
m_size = other.m_size;
- clearItems();
- for(u32 i=0; i<other.m_items.size(); i++)
- {
- InventoryItem *item = other.m_items[i];
- if(item != NULL)
- {
- m_items[i] = item->clone();
- }
- }
+ m_name = other.m_name;
+ m_itemdef = other.m_itemdef;
//setDirty(true);
return *this;
@@ -683,48 +549,45 @@ const std::string &InventoryList::getName() const
return m_name;
}
-u32 InventoryList::getSize()
+u32 InventoryList::getSize() const
{
return m_items.size();
}
-u32 InventoryList::getUsedSlots()
+u32 InventoryList::getUsedSlots() const
{
u32 num = 0;
for(u32 i=0; i<m_items.size(); i++)
{
- InventoryItem *item = m_items[i];
- if(item != NULL)
+ if(!m_items[i].empty())
num++;
}
return num;
}
-u32 InventoryList::getFreeSlots()
+u32 InventoryList::getFreeSlots() const
{
return getSize() - getUsedSlots();
}
-const InventoryItem * InventoryList::getItem(u32 i) const
+const ItemStack& InventoryList::getItem(u32 i) const
{
- if(i >= m_items.size())
- return NULL;
+ assert(i < m_size);
return m_items[i];
}
-InventoryItem * InventoryList::getItem(u32 i)
+ItemStack& InventoryList::getItem(u32 i)
{
- if(i >= m_items.size())
- return NULL;
+ assert(i < m_size);
return m_items[i];
}
-InventoryItem * InventoryList::changeItem(u32 i, InventoryItem *newitem)
+ItemStack InventoryList::changeItem(u32 i, const ItemStack &newitem)
{
if(i >= m_items.size())
return newitem;
- InventoryItem *olditem = m_items[i];
+ ItemStack olditem = m_items[i];
m_items[i] = newitem;
//setDirty(true);
return olditem;
@@ -733,15 +596,15 @@ InventoryItem * InventoryList::changeItem(u32 i, InventoryItem *newitem)
void InventoryList::deleteItem(u32 i)
{
assert(i < m_items.size());
- InventoryItem *item = changeItem(i, NULL);
- if(item)
- delete item;
+ m_items[i].clear();
}
-InventoryItem * InventoryList::addItem(InventoryItem *newitem)
+ItemStack InventoryList::addItem(const ItemStack &newitem_)
{
- if(newitem == NULL)
- return NULL;
+ ItemStack newitem = newitem_;
+
+ if(newitem.empty())
+ return newitem;
/*
First try to find if it could be added to some existing items
@@ -749,12 +612,12 @@ InventoryItem * InventoryList::addItem(InventoryItem *newitem)
for(u32 i=0; i<m_items.size(); i++)
{
// Ignore empty slots
- if(m_items[i] == NULL)
+ if(m_items[i].empty())
continue;
// Try adding
newitem = addItem(i, newitem);
- if(newitem == NULL)
- return NULL; // All was eaten
+ if(newitem.empty())
+ return newitem; // All was eaten
}
/*
@@ -763,148 +626,153 @@ InventoryItem * InventoryList::addItem(InventoryItem *newitem)
for(u32 i=0; i<m_items.size(); i++)
{
// Ignore unempty slots
- if(m_items[i] != NULL)
+ if(!m_items[i].empty())
continue;
// Try adding
newitem = addItem(i, newitem);
- if(newitem == NULL)
- return NULL; // All was eaten
+ if(newitem.empty())
+ return newitem; // All was eaten
}
// Return leftover
return newitem;
}
-InventoryItem * InventoryList::addItem(u32 i, InventoryItem *newitem)
+ItemStack InventoryList::addItem(u32 i, const ItemStack &newitem)
{
- if(newitem == NULL)
- return NULL;
if(i >= m_items.size())
return newitem;
-
- //setDirty(true);
-
- // If it is an empty position, it's an easy job.
- InventoryItem *to_item = getItem(i);
- if(to_item == NULL)
- {
- m_items[i] = newitem;
- return NULL;
- }
-
- // If not addable, return the item
- if(newitem->addableTo(to_item) == false)
- return newitem;
-
- // If the item fits fully in the slot, add counter and delete it
- if(newitem->getCount() <= to_item->freeSpace())
- {
- to_item->add(newitem->getCount());
- delete newitem;
- return NULL;
- }
- // Else the item does not fit fully. Add all that fits and return
- // the rest.
- else
- {
- u16 freespace = to_item->freeSpace();
- to_item->add(freespace);
- newitem->remove(freespace);
- return newitem;
- }
+
+ ItemStack leftover = m_items[i].addItem(newitem, m_itemdef);
+ //if(leftover != newitem)
+ // setDirty(true);
+ return leftover;
}
-bool InventoryList::itemFits(const u32 i, const InventoryItem *newitem)
+bool InventoryList::itemFits(const u32 i, const ItemStack &newitem,
+ ItemStack *restitem) const
{
- // If it is an empty position, it's an easy job.
- const InventoryItem *to_item = getItem(i);
- if(to_item == NULL)
+ if(i >= m_items.size())
{
- return true;
- }
-
- // If not addable, fail
- if(newitem->addableTo(to_item) == false)
+ if(restitem)
+ *restitem = newitem;
return false;
-
- // If the item fits fully in the slot, pass
- if(newitem->getCount() <= to_item->freeSpace())
- {
- return true;
}
- return false;
+ return m_items[i].itemFits(newitem, restitem, m_itemdef);
}
-bool InventoryList::roomForItem(const InventoryItem *item)
+bool InventoryList::roomForItem(const ItemStack &item_) const
{
+ ItemStack item = item_;
+ ItemStack leftover;
for(u32 i=0; i<m_items.size(); i++)
- if(itemFits(i, item))
+ {
+ if(itemFits(i, item, &leftover))
return true;
+ item = leftover;
+ }
return false;
}
-bool InventoryList::roomForCookedItem(const InventoryItem *item)
-{
- if(!item)
- return false;
- const InventoryItem *cook = item->createCookResult();
- if(!cook)
- return false;
- bool room = roomForItem(cook);
- delete cook;
- return room;
-}
-
-InventoryItem * InventoryList::takeItem(u32 i, u32 count)
+bool InventoryList::containsItem(const ItemStack &item) const
{
+ u32 count = item.count;
if(count == 0)
- return NULL;
-
- //setDirty(true);
-
- InventoryItem *item = getItem(i);
- // If it is an empty position, return NULL
- if(item == NULL)
- return NULL;
-
- if(count >= item->getCount())
- {
- // Get the item by swapping NULL to its place
- return changeItem(i, NULL);
- }
- else
+ return true;
+ for(std::vector<ItemStack>::const_reverse_iterator
+ i = m_items.rbegin();
+ i != m_items.rend(); i++)
{
- InventoryItem *item2 = item->clone();
- item->remove(count);
- item2->setCount(count);
- return item2;
+ if(count == 0)
+ break;
+ if(i->name == item.name)
+ {
+ if(i->count >= count)
+ return true;
+ else
+ count -= i->count;
+ }
}
-
return false;
}
-void InventoryList::decrementMaterials(u16 count)
+ItemStack InventoryList::removeItem(const ItemStack &item)
{
- for(u32 i=0; i<m_items.size(); i++)
+ ItemStack removed;
+ for(std::vector<ItemStack>::reverse_iterator
+ i = m_items.rbegin();
+ i != m_items.rend(); i++)
{
- InventoryItem *item = takeItem(i, count);
- if(item)
- delete item;
+ if(i->name == item.name)
+ {
+ u32 still_to_remove = item.count - removed.count;
+ removed.addItem(i->takeItem(still_to_remove), m_itemdef);
+ if(removed.count == item.count)
+ break;
+ }
}
+ return removed;
}
-void InventoryList::print(std::ostream &o)
+ItemStack InventoryList::takeItem(u32 i, u32 takecount)
{
- o<<"InventoryList:"<<std::endl;
- for(u32 i=0; i<m_items.size(); i++)
+ if(i >= m_items.size())
+ return ItemStack();
+
+ ItemStack taken = m_items[i].takeItem(takecount);
+ //if(!taken.empty())
+ // setDirty(true);
+ return taken;
+}
+
+ItemStack InventoryList::peekItem(u32 i, u32 peekcount) const
+{
+ if(i >= m_items.size())
+ return ItemStack();
+
+ return m_items[i].peekItem(peekcount);
+}
+
+void InventoryList::moveItem(u32 i, InventoryList *dest, u32 dest_i, u32 count)
+{
+ if(this == dest && i == dest_i)
+ return;
+
+ // Take item from source list
+ ItemStack item1;
+ if(count == 0)
+ item1 = changeItem(i, ItemStack());
+ else
+ item1 = takeItem(i, count);
+
+ if(item1.empty())
+ return;
+
+ // Try to add the item to destination list
+ u32 oldcount = item1.count;
+ item1 = dest->addItem(dest_i, item1);
+
+ // If something is returned, the item was not fully added
+ if(!item1.empty())
{
- InventoryItem *item = m_items[i];
- if(item != NULL)
+ // If olditem is returned, nothing was added.
+ bool nothing_added = (item1.count == oldcount);
+
+ // If something else is returned, part of the item was left unadded.
+ // Add the other part back to the source item
+ addItem(i, item1);
+
+ // If olditem is returned, nothing was added.
+ // Swap the items
+ if(nothing_added)
{
- o<<i<<": ";
- item->serialize(o);
- o<<"\n";
+ // Take item from source list
+ item1 = changeItem(i, ItemStack());
+ // Adding was not possible, swap the items.
+ ItemStack item2 = dest->changeItem(dest_i, item1);
+ // Put item from destination list to the source list
+ changeItem(i, item2);
}
}
}
@@ -927,8 +795,9 @@ void Inventory::clear()
m_lists.clear();
}
-Inventory::Inventory()
+Inventory::Inventory(IItemDefManager *itemdef)
{
+ m_itemdef = itemdef;
}
Inventory::Inventory(const Inventory &other)
@@ -938,10 +807,15 @@ Inventory::Inventory(const Inventory &other)
Inventory & Inventory::operator = (const Inventory &other)
{
- clear();
- for(u32 i=0; i<other.m_lists.size(); i++)
+ // Gracefully handle self assignment
+ if(this != &other)
{
- m_lists.push_back(new InventoryList(*other.m_lists[i]));
+ clear();
+ m_itemdef = other.m_itemdef;
+ for(u32 i=0; i<other.m_lists.size(); i++)
+ {
+ m_lists.push_back(new InventoryList(*other.m_lists[i]));
+ }
}
return *this;
}
@@ -958,7 +832,7 @@ void Inventory::serialize(std::ostream &os) const
os<<"EndInventory\n";
}
-void Inventory::deSerialize(std::istream &is, IGameDef *gamedef)
+void Inventory::deSerialize(std::istream &is)
{
clear();
@@ -989,8 +863,8 @@ void Inventory::deSerialize(std::istream &is, IGameDef *gamedef)
std::getline(iss, listname, ' ');
iss>>listsize;
- InventoryList *list = new InventoryList(listname, listsize);
- list->deSerialize(is, gamedef);
+ InventoryList *list = new InventoryList(listname, listsize, m_itemdef);
+ list->deSerialize(is);
m_lists.push_back(list);
}
@@ -1009,14 +883,15 @@ InventoryList * Inventory::addList(const std::string &name, u32 size)
if(m_lists[i]->getSize() != size)
{
delete m_lists[i];
- m_lists[i] = new InventoryList(name, size);
+ m_lists[i] = new InventoryList(name, size, m_itemdef);
}
return m_lists[i];
}
else
{
- m_lists.push_back(new InventoryList(name, size));
- return m_lists.getLast();
+ InventoryList *list = new InventoryList(name, size, m_itemdef);
+ m_lists.push_back(list);
+ return list;
}
}
@@ -1034,7 +909,7 @@ bool Inventory::deleteList(const std::string &name)
if(i == -1)
return false;
delete m_lists[i];
- m_lists.erase(i);
+ m_lists.erase(m_lists.begin() + i);
return true;
}
diff --git a/src/inventory.h b/src/inventory.h
index 15de3c8e7..fcac5f647 100644
--- a/src/inventory.h
+++ b/src/inventory.h
@@ -23,460 +23,225 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <iostream>
#include <sstream>
#include <string>
+#include <vector>
#include "common_irrlicht.h"
#include "debug.h"
-#include "mapnode.h" // For content_t
+#include "itemdef.h"
-#define QUANTITY_ITEM_MAX_COUNT 99
+struct ToolDiggingProperties;
-class ServerActiveObject;
-class ServerEnvironment;
-struct PointedThing;
-class ITextureSource;
-class IGameDef;
-
-class InventoryItem
+struct ItemStack
{
-public:
- InventoryItem(IGameDef *gamedef, u16 count);
- virtual ~InventoryItem();
-
- static InventoryItem* deSerialize(std::istream &is, IGameDef *gamedef);
- static InventoryItem* deSerialize(const std::string &str,
- IGameDef *gamedef);
-
- virtual const char* getName() const = 0;
- // Shall write the name and the parameters
- 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 ""; }
+ ItemStack(): name(""), count(0), wear(0), metadata("") {}
+ ItemStack(std::string name_, u16 count_,
+ u16 wear, std::string metadata_,
+ IItemDefManager *itemdef);
+ ~ItemStack() {}
+
+ // Serialization
+ void serialize(std::ostream &os) const;
+ void deSerialize(std::istream &is, IItemDefManager *itemdef);
+ void deSerialize(const std::string &s, IItemDefManager *itemdef);
+
// Returns the string used for inventory
- virtual std::string getItemString();
-
- // Shall return false if item is not known and cannot be used
- virtual bool isKnown() const { return true; }
+ std::string getItemString() const;
/*
Quantity methods
*/
- // Return true if the item can be add()ed to the other
- 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
+ bool empty() const
{
- u16 max = getStackMax();
- if(m_count > max)
- return 0;
- return max - m_count;
+ return count == 0;
}
- void add(u16 count)
+ void clear()
{
- m_count += count;
- }
- void remove(u16 count)
- {
- assert(m_count >= count);
- m_count -= count;
+ name = "";
+ count = 0;
+ wear = 0;
+ metadata = "";
}
- /*
- Other properties
- */
-
- // Maximum size of a stack
- virtual u16 getStackMax() const {return 1;}
- // 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";
- }
- 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()
+ void add(u16 n)
{
- std::ostringstream os;
- os<<m_count;
- return os.str();
+ count += n;
}
- virtual bool addableTo(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 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
- {
- return QUANTITY_ITEM_MAX_COUNT;
- }
-
- /*
- Other properties
- */
- bool isCookable() 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";
- }
- virtual void serialize(std::ostream &os) const
+ void remove(u16 n)
{
- os<<"craft";
- os<<" \"";
- os<<m_subname;
- os<<"\" ";
- os<<m_count;
+ assert(count >= n);
+ count -= n;
+ if(count == 0)
+ clear(); // reset name, wear and metadata too
}
- 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;
- virtual bool addableTo(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 true;
- }
- 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)
+ // Maximum size of a stack
+ u16 getStackMax(IItemDefManager *itemdef) const
{
- if(!other->isSubsetOf(this))
- return false;
- CraftItem *m = (CraftItem*)other;
- m_count += m->m_count;
- return true;
+ s16 max = itemdef->get(name).stack_max;
+ return (max >= 0) ? max : 0;
}
- /*
- Other properties
- */
-
- 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()
+ // Number of items that can be added to this stack
+ u16 freeSpace(IItemDefManager *itemdef) const
{
- return m_subname;
+ u16 max = getStackMax(itemdef);
+ if(count > max)
+ return 0;
+ return max - count;
}
-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
+ // Returns false if item is not known and cannot be used
+ bool isKnown(IItemDefManager *itemdef) const
{
- os<<"tool";
- os<<" \"";
- os<<m_toolname;
- os<<"\" ";
- os<<m_wear;
+ return itemdef->isKnown(name);
}
- 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()
+ // Returns a pointer to the item definition struct,
+ // or a fallback one (name="unknown") if the item is unknown.
+ const ItemDefinition& getDefinition(
+ IItemDefManager *itemdef) const
{
- return "";
+ return itemdef->get(name);
}
-
- virtual bool isKnown() const;
- virtual bool isSubsetOf(const InventoryItem *other) const
+ // Get tool digging properties, or those of the hand if not a tool
+ const ToolDiggingProperties& getToolDiggingProperties(
+ IItemDefManager *itemdef) 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;
+ ToolDiggingProperties *prop;
+ prop = itemdef->get(name).tool_digging_properties;
+ if(prop == NULL)
+ prop = itemdef->get("").tool_digging_properties;
+ assert(prop != NULL);
+ return *prop;
}
- /*
- Special methods
- */
- std::string getToolName()
- {
- return m_toolname;
- }
- u16 getWear()
- {
- return m_wear;
- }
- // Returns true if weared out
- bool addWear(u16 add)
+ // Wear out (only tools)
+ // Returns true if the item is (was) a tool
+ bool addWear(s32 amount, IItemDefManager *itemdef)
{
- if(m_wear >= 65535 - add)
+ if(getDefinition(itemdef).type == ITEM_TOOL)
{
- m_wear = 65535;
+ if(amount > 65535 - wear)
+ clear();
+ else if(amount < -wear)
+ wear = 0;
+ else
+ wear += amount;
return true;
}
else
{
- m_wear += add;
return false;
}
}
-private:
- std::string m_toolname;
- u16 m_wear;
+
+ // If possible, adds newitem to this item.
+ // 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
{
public:
- InventoryList(std::string name, u32 size);
+ InventoryList(std::string name, u32 size, IItemDefManager *itemdef);
~InventoryList();
void clearItems();
void setSize(u32 newsize);
void serialize(std::ostream &os) const;
- void deSerialize(std::istream &is, IGameDef *gamedef);
+ void deSerialize(std::istream &is);
InventoryList(const InventoryList &other);
InventoryList & operator = (const InventoryList &other);
const std::string &getName() const;
- u32 getSize();
+ u32 getSize() const;
// Count used slots
- u32 getUsedSlots();
- u32 getFreeSlots();
-
- /*bool getDirty(){ return m_dirty; }
- void setDirty(bool dirty=true){ m_dirty = dirty; }*/
-
- // Get pointer to item
- const InventoryItem * getItem(u32 i) const;
- InventoryItem * getItem(u32 i);
- // Returns old item (or NULL). Parameter can be NULL.
- InventoryItem * changeItem(u32 i, InventoryItem *newitem);
+ u32 getUsedSlots() const;
+ u32 getFreeSlots() const;
+
+ // Get reference to item
+ const ItemStack& getItem(u32 i) const;
+ ItemStack& getItem(u32 i);
+ // Returns old item. Parameter can be an empty item.
+ ItemStack changeItem(u32 i, const ItemStack &newitem);
// Delete item
void deleteItem(u32 i);
- // Adds an item to a suitable place. Returns leftover item.
- // If all went into the list, returns NULL.
- InventoryItem * addItem(InventoryItem *newitem);
+ // Adds an item to a suitable place. Returns leftover item (possibly empty).
+ ItemStack addItem(const ItemStack &newitem);
// If possible, adds item to given slot.
// 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, NULL is returned.
- InventoryItem * addItem(u32 i, InventoryItem *newitem);
+ // If can be added fully, empty item is returned.
+ ItemStack addItem(u32 i, const ItemStack &newitem);
// 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
- 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
- bool roomForCookedItem(const InventoryItem *item);
+ // Checks whether the given count of the given item name
+ // 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.
// If there are not enough, takes as many as it can.
- // Returns NULL if couldn't take any.
- InventoryItem * takeItem(u32 i, u32 count);
+ // Returns empty item if couldn't take any.
+ ItemStack takeItem(u32 i, u32 takecount);
- // Decrements amount of every material item
- void decrementMaterials(u16 count);
+ // Similar to takeItem, but keeps the slot intact.
+ ItemStack peekItem(u32 i, u32 peekcount) const;
+
+ // Move an item to a different list (or a different stack in the same list)
+ // count is the maximum number of items to move (0 for everything)
+ void moveItem(u32 i, InventoryList *dest, u32 dest_i, u32 count = 0);
- void print(std::ostream &o);
-
private:
- core::array<InventoryItem*> m_items;
+ std::vector<ItemStack> m_items;
u32 m_size;
std::string m_name;
- //bool m_dirty;
+ IItemDefManager *m_itemdef;
};
class Inventory
@@ -486,20 +251,19 @@ public:
void clear();
- Inventory();
+ Inventory(IItemDefManager *itemdef);
Inventory(const Inventory &other);
Inventory & operator = (const Inventory &other);
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 * getList(const std::string &name);
const InventoryList * getList(const std::string &name) const;
bool deleteList(const std::string &name);
- // A shorthand for adding items.
- // Returns NULL if the item was fully added, leftover otherwise.
- InventoryItem * addItem(const std::string &listname, InventoryItem *newitem)
+ // A shorthand for adding items. Returns leftover item (possibly empty).
+ ItemStack addItem(const std::string &listname, const ItemStack &newitem)
{
InventoryList *list = getList(listname);
if(list == NULL)
@@ -511,7 +275,8 @@ private:
// -1 if not found
const s32 getListIndex(const std::string &name) const;
- core::array<InventoryList*> m_lists;
+ std::vector<InventoryList*> m_lists;
+ IItemDefManager *m_itemdef;
};
#endif
diff --git a/src/inventorymanager.cpp b/src/inventorymanager.cpp
index 195438d26..b04a1c177 100644
--- a/src/inventorymanager.cpp
+++ b/src/inventorymanager.cpp
@@ -18,73 +18,92 @@ with this program; if not, write to the Free Software Foundation, Inc.,
*/
#include "inventorymanager.h"
-#include "serverremoteplayer.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"
+#include "craftdef.h"
/*
- InventoryManager
+ InventoryLocation
*/
-// Wrapper for old code
-Inventory* InventoryManager::getInventory(InventoryContext *c, std::string id)
+std::string InventoryLocation::dump() const
{
- if(id == "current_player")
- {
- assert(c->current_player);
- 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(","));
+ std::ostringstream os(std::ios::binary);
+ serialize(os);
+ return os.str();
+}
- InventoryLocation loc;
- loc.setNodeMeta(p);
- return getInventory(loc);
+void InventoryLocation::serialize(std::ostream &os) const
+{
+ switch(type){
+ case InventoryLocation::UNDEFINED:
+ {
+ os<<"undefined";
}
-
- errorstream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
- return NULL;
+ 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);
+ }
}
-// Wrapper for old code
-void InventoryManager::inventoryModified(InventoryContext *c, std::string id)
+
+void InventoryLocation::deSerialize(std::istream &is)
{
- if(id == "current_player")
+ std::string tname;
+ std::getline(is, tname, ':');
+ if(tname == "undefined")
{
- assert(c->current_player);
- InventoryLocation loc;
- loc.setPlayer(c->current_player->getName());
- setInventoryModified(loc);
- return;
+ type = InventoryLocation::UNDEFINED;
}
-
- Strfnd fn(id);
- std::string id0 = fn.next(":");
-
- if(id0 == "nodemeta")
+ 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")
{
- v3s16 p;
+ type = InventoryLocation::NODEMETA;
+ std::string pos;
+ std::getline(is, pos, '\n');
+ Strfnd fn(pos);
p.X = stoi(fn.next(","));
p.Y = 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);
}
/*
@@ -106,17 +125,17 @@ InventoryAction * InventoryAction::deSerialize(std::istream &is)
{
a = new IDropAction(is);
}
+ else if(type == "Craft")
+ {
+ a = new ICraftAction(is);
+ }
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::IMoveAction(std::istream &is)
{
@@ -125,14 +144,16 @@ IMoveAction::IMoveAction(std::istream &is)
std::getline(is, 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, ts, ' ');
from_i = stoi(ts);
- std::getline(is, to_inv, ' ');
+ std::getline(is, ts, ' ');
+ to_inv.deSerialize(ts);
std::getline(is, to_list, ' ');
@@ -140,22 +161,21 @@ IMoveAction::IMoveAction(std::istream &is)
to_i = stoi(ts);
}
-void IMoveAction::apply(InventoryContext *c, InventoryManager *mgr,
- ServerEnvironment *env)
+void IMoveAction::apply(InventoryManager *mgr, ServerActiveObject *player, IGameDef *gamedef)
{
- Inventory *inv_from = mgr->getInventory(c, from_inv);
- Inventory *inv_to = mgr->getInventory(c, to_inv);
+ Inventory *inv_from = mgr->getInventory(from_inv);
+ Inventory *inv_to = mgr->getInventory(to_inv);
if(!inv_from){
infostream<<"IMoveAction::apply(): FAIL: source inventory not found: "
- <<"context=["<<describeC(c)<<"], from_inv=\""<<from_inv<<"\""
- <<", to_inv=\""<<to_inv<<"\""<<std::endl;
+ <<"from_inv=\""<<from_inv.dump()<<"\""
+ <<", to_inv=\""<<to_inv.dump()<<"\""<<std::endl;
return;
}
if(!inv_to){
infostream<<"IMoveAction::apply(): FAIL: destination inventory not found: "
- "context=["<<describeC(c)<<"], from_inv=\""<<from_inv<<"\""
- <<", to_inv=\""<<to_inv<<"\""<<std::endl;
+ <<"from_inv=\""<<from_inv.dump()<<"\""
+ <<", to_inv=\""<<to_inv.dump()<<"\""<<std::endl;
return;
}
@@ -167,84 +187,71 @@ void IMoveAction::apply(InventoryContext *c, InventoryManager *mgr,
*/
if(!list_from){
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;
return;
}
if(!list_to){
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;
return;
}
- if(list_from->getItem(from_i) == NULL)
- {
- infostream<<"IMoveAction::apply(): FAIL: source item not found: "
- <<"context=["<<describeC(c)<<"], from_inv=\""<<from_inv<<"\""
- <<", from_list=\""<<from_list<<"\""
- <<" from_i="<<from_i<<std::endl;
- return;
- }
/*
- If the source and the destination slots are the same
- */
- if(inv_from == inv_to && list_from == list_to && from_i == to_i)
- {
- infostream<<"IMoveAction::apply(): FAIL: source and destination slots "
- <<"are the same: inv=\""<<from_inv<<"\" list=\""<<from_list
- <<"\" i="<<from_i<<std::endl;
- return;
- }
-
- // Take item from source list
- InventoryItem *item1 = NULL;
- if(count == 0)
- item1 = list_from->changeItem(from_i, NULL);
- else
- item1 = list_from->takeItem(from_i, count);
-
- // Try to add the item to destination list
- InventoryItem *olditem = item1;
- item1 = list_to->addItem(to_i, item1);
+ This performs the actual movement
- // If something is returned, the item was not fully added
- if(item1 != NULL)
- {
- // If olditem is returned, nothing was added.
- bool nothing_added = (item1 == olditem);
-
- // If something else is returned, part of the item was left unadded.
- // Add the other part back to the source item
- list_from->addItem(from_i, item1);
-
- // If olditem is returned, nothing was added.
- // Swap the items
- if(nothing_added)
- {
- // Take item from source list
- item1 = list_from->changeItem(from_i, NULL);
- // Adding was not possible, swap the items.
- InventoryItem *item2 = list_to->changeItem(to_i, item1);
- // Put item from destination list to the source list
- list_from->changeItem(from_i, item2);
- }
- }
+ If something is wrong (source item is empty, destination is the
+ same as source), nothing happens
+ */
+ list_from->moveItem(from_i, list_to, to_i, count);
- mgr->inventoryModified(c, from_inv);
- if(from_inv != to_inv)
- mgr->inventoryModified(c, to_inv);
+ mgr->setInventoryModified(from_inv);
+ if(inv_from != inv_to)
+ mgr->setInventoryModified(to_inv);
infostream<<"IMoveAction::apply(): moved at "
- <<"["<<describeC(c)<<"]"
- <<" from inv=\""<<from_inv<<"\""
+ <<" count="<<count<<"\""
+ <<" from inv=\""<<from_inv.dump()<<"\""
<<" list=\""<<from_list<<"\""
<<" i="<<from_i
- <<" to inv=\""<<to_inv<<"\""
+ <<" to inv=\""<<to_inv.dump()<<"\""
<<" list=\""<<to_list<<"\""
<<" i="<<to_i
<<std::endl;
}
+void IMoveAction::clientApply(InventoryManager *mgr, IGameDef *gamedef)
+{
+ // Optional InventoryAction operation that is run on the client
+ // to make lag less apparent.
+
+ Inventory *inv_from = mgr->getInventory(from_inv);
+ Inventory *inv_to = mgr->getInventory(to_inv);
+ if(!inv_from || !inv_to)
+ return;
+
+ InventoryLocation current_player;
+ current_player.setCurrentPlayer();
+ Inventory *inv_player = mgr->getInventory(current_player);
+ if(inv_from != inv_player || inv_to != inv_player)
+ return;
+
+ InventoryList *list_from = inv_from->getList(from_list);
+ InventoryList *list_to = inv_to->getList(to_list);
+ if(!list_from || !list_to)
+ return;
+
+ list_from->moveItem(from_i, list_to, to_i, count);
+
+ mgr->setInventoryModified(from_inv);
+ if(inv_from != inv_to)
+ mgr->setInventoryModified(to_inv);
+}
+
+/*
+ IDropAction
+*/
+
IDropAction::IDropAction(std::istream &is)
{
std::string ts;
@@ -252,7 +259,8 @@ IDropAction::IDropAction(std::istream &is)
std::getline(is, ts, ' ');
count = stoi(ts);
- std::getline(is, from_inv, ' ');
+ std::getline(is, ts, ' ');
+ from_inv.deSerialize(ts);
std::getline(is, from_list, ' ');
@@ -260,27 +268,13 @@ IDropAction::IDropAction(std::istream &is)
from_i = stoi(ts);
}
-void IDropAction::apply(InventoryContext *c, InventoryManager *mgr,
- ServerEnvironment *env)
+void IDropAction::apply(InventoryManager *mgr, ServerActiveObject *player, IGameDef *gamedef)
{
- if(c->current_player == NULL){
- 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);
+ Inventory *inv_from = mgr->getInventory(from_inv);
if(!inv_from){
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;
}
@@ -291,254 +285,199 @@ void IDropAction::apply(InventoryContext *c, InventoryManager *mgr,
*/
if(!list_from){
infostream<<"IDropAction::apply(): FAIL: source list not found: "
- <<"context=["<<describeC(c)<<"], from_inv=\""<<from_inv<<"\""
- <<", from_list=\""<<from_list<<"\""<<std::endl;
+ <<"from_inv=\""<<from_inv.dump()<<"\""<<std::endl;
return;
}
- InventoryItem *item = list_from->getItem(from_i);
- if(item == NULL)
+ if(list_from->getItem(from_i).empty())
{
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_i="<<from_i<<std::endl;
return;
}
- v3f pos = dropper->getBasePosition();
- pos.Y += 0.5*BS;
+ // Take item from source list
+ ItemStack item1;
+ if(count == 0)
+ item1 = list_from->changeItem(from_i, ItemStack());
+ else
+ item1 = list_from->takeItem(from_i, count);
- s16 count2 = count;
- if(count2 == 0)
- count2 = -1;
+ // Drop the item and apply the returned ItemStack
+ ItemStack item2 = item1;
+ if(scriptapi_item_on_drop(player->getEnv()->getLua(), item2, player,
+ player->getBasePosition() + v3f(0,1,0)))
+ {
+ if(g_settings->getBool("creative_mode") == true
+ && from_inv.type == InventoryLocation::PLAYER)
+ item2 = item1; // creative mode
- /*
- Drop the item
- */
- bool remove = item->dropOrPlace(env, dropper, pos, false, count2);
- if(remove)
- list_from->deleteItem(from_i);
+ list_from->addItem(from_i, item2);
- mgr->inventoryModified(c, from_inv);
+ // Unless we have put the same amount back as we took in the first place,
+ // set inventory modified flag
+ if(item2.count != item1.count)
+ mgr->setInventoryModified(from_inv);
+ }
infostream<<"IDropAction::apply(): dropped "
- <<"["<<describeC(c)<<"]"
- <<" from inv=\""<<from_inv<<"\""
+ <<" from inv=\""<<from_inv.dump()<<"\""
<<" list=\""<<from_list<<"\""
<<" i="<<from_i
<<std::endl;
}
+void IDropAction::clientApply(InventoryManager *mgr, IGameDef *gamedef)
+{
+ // Optional InventoryAction operation that is run on the client
+ // to make lag less apparent.
+
+ Inventory *inv_from = mgr->getInventory(from_inv);
+ if(!inv_from)
+ return;
+
+ InventoryLocation current_player;
+ current_player.setCurrentPlayer();
+ Inventory *inv_player = mgr->getInventory(current_player);
+ if(inv_from != inv_player)
+ return;
+
+ InventoryList *list_from = inv_from->getList(from_list);
+ if(!list_from)
+ return;
+
+ if(count == 0)
+ list_from->changeItem(from_i, ItemStack());
+ else
+ list_from->takeItem(from_i, count);
+
+ mgr->setInventoryModified(from_inv);
+}
+
/*
- Craft checking system
+ ICraftAction
*/
-bool ItemSpec::checkItem(const InventoryItem *item) const
+ICraftAction::ICraftAction(std::istream &is)
{
- 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 ts;
- std::string itemname = item->getName();
+ std::getline(is, ts, ' ');
+ count = stoi(ts);
- 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;
+ std::getline(is, ts, ' ');
+ craft_inv.deSerialize(ts);
}
-bool checkItemCombination(InventoryItem const * const *items, const ItemSpec *specs)
+void ICraftAction::apply(InventoryManager *mgr, ServerActiveObject *player, IGameDef *gamedef)
{
- 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;
+ Inventory *inv_craft = mgr->getInventory(craft_inv);
- 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;
+ if(!inv_craft){
+ infostream<<"ICraftAction::apply(): FAIL: inventory not found: "
+ <<"craft_inv=\""<<craft_inv.dump()<<"\""<<std::endl;
+ return;
}
- // 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;
+ InventoryList *list_craft = inv_craft->getList("craft");
+ InventoryList *list_craftresult = inv_craft->getList("craftresult");
- // Different sizes
- if(items_w != specs_w || items_h != specs_h)
- return false;
+ /*
+ If a list doesn't exist or the source item doesn't exist
+ */
+ if(!list_craft){
+ infostream<<"ICraftAction::apply(): FAIL: craft list not found: "
+ <<"craft_inv=\""<<craft_inv.dump()<<"\""<<std::endl;
+ return;
+ }
+ if(!list_craftresult){
+ infostream<<"ICraftAction::apply(): FAIL: craftresult list not found: "
+ <<"craft_inv=\""<<craft_inv.dump()<<"\""<<std::endl;
+ return;
+ }
+ if(list_craftresult->getSize() < 1){
+ infostream<<"ICraftAction::apply(): FAIL: craftresult list too short: "
+ <<"craft_inv=\""<<craft_inv.dump()<<"\""<<std::endl;
+ return;
+ }
- for(u16 y=0; y<specs_h; y++)
- for(u16 x=0; x<specs_w; x++)
+ ItemStack crafted;
+ int count_remaining = count;
+ bool found = getCraftingResult(inv_craft, crafted, false, gamedef);
+
+ while(found && list_craftresult->itemFits(0, crafted))
{
- 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;
+ // Decrement input and add crafting output
+ getCraftingResult(inv_craft, crafted, true, gamedef);
+ list_craftresult->addItem(0, crafted);
+ mgr->setInventoryModified(craft_inv);
+
+ actionstream<<player->getDescription()
+ <<" crafts "
+ <<crafted.getItemString()
+ <<std::endl;
+
+ // Decrement counter
+ if(count_remaining == 1)
+ break;
+ else if(count_remaining > 1)
+ count_remaining--;
+
+ // Get next crafting result
+ found = getCraftingResult(inv_craft, crafted, false, gamedef);
}
- return true;
+ infostream<<"ICraftAction::apply(): crafted "
+ <<" craft_inv=\""<<craft_inv.dump()<<"\""
+ <<std::endl;
}
-bool checkItemCombination(const InventoryItem * const * items,
- const InventoryItem * const * specs)
+void ICraftAction::clientApply(InventoryManager *mgr, IGameDef *gamedef)
{
- 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;
+ // Optional InventoryAction operation that is run on the client
+ // to make lag less apparent.
+}
+
+
+// Crafting helper
+bool getCraftingResult(Inventory *inv, ItemStack& result,
+ bool decrementInput, IGameDef *gamedef)
+{
+ DSTACK(__FUNCTION_NAME);
- 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;
+ result.clear();
- u16 specs_w = specs_max_x - specs_min_x + 1;
- u16 specs_h = specs_max_y - specs_min_y + 1;
+ // TODO: Allow different sizes of crafting grids
- // Different sizes
- if(items_w != specs_w || items_h != specs_h)
+ // Get the InventoryList in which we will operate
+ InventoryList *clist = inv->getList("craft");
+ if(!clist || clist->getSize() != 9)
return false;
- for(u16 y=0; y<specs_h; y++)
- for(u16 x=0; x<specs_w; x++)
+ // Mangle crafting grid to an another format
+ CraftInput ci;
+ ci.method = CRAFT_METHOD_NORMAL;
+ ci.width = 3;
+ for(u16 i=0; i<9; i++)
+ ci.items.push_back(clist->getItem(i));
+
+ // Find out what is crafted and add it to result item slot
+ CraftOutput co;
+ bool found = gamedef->getCraftDefManager()->getCraftResult(
+ ci, co, decrementInput, gamedef);
+ if(found)
+ result.deSerialize(co.item, gamedef->getItemDefManager());
+
+ if(found && decrementInput)
{
- 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;
+ // CraftInput has been changed, apply changes in clist
+ for(u16 i=0; i<9; i++)
+ {
+ clist->changeItem(i, ci.items[i]);
+ }
}
- return true;
+ return found;
}
-
diff --git a/src/inventorymanager.h b/src/inventorymanager.h
index 4abe5e73d..52377f9a4 100644
--- a/src/inventorymanager.h
+++ b/src/inventorymanager.h
@@ -21,19 +21,34 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define INVENTORYMANAGER_HEADER
#include "inventory.h"
+#include <iostream>
+#include <string>
+class ServerActiveObject;
-// Should probably somehow replace InventoryContext over time
struct InventoryLocation
{
enum Type{
UNDEFINED,
+ CURRENT_PLAYER,
PLAYER,
- NODEMETA
+ NODEMETA,
} type;
std::string name; // PLAYER
v3s16 p; // NODEMETA
+ InventoryLocation()
+ {
+ setUndefined();
+ }
+ void setUndefined()
+ {
+ type = UNDEFINED;
+ }
+ void setCurrentPlayer()
+ {
+ type = CURRENT_PLAYER;
+ }
void setPlayer(const std::string &name_)
{
type = PLAYER;
@@ -44,17 +59,17 @@ struct InventoryLocation
type = NODEMETA;
p = p_;
}
-};
-class Player;
+ void applyCurrentPlayer(const std::string &name_)
+ {
+ if(type == CURRENT_PLAYER)
+ setPlayer(name_);
+ }
-struct InventoryContext
-{
- Player *current_player;
-
- InventoryContext():
- current_player(NULL)
- {}
+ std::string dump() const;
+ void serialize(std::ostream &os) const;
+ void deSerialize(std::istream &is);
+ void deSerialize(std::string s);
};
struct InventoryAction;
@@ -68,22 +83,16 @@ public:
// Get an inventory or set it modified (so it will be updated over
// network or so)
virtual Inventory* getInventory(const InventoryLocation &loc){return NULL;}
+ virtual std::string getInventoryOwner(const InventoryLocation &loc){return "";}
virtual void setInventoryModified(const InventoryLocation &loc){}
// Used on the client to send an action to the server
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_DROP 1
+#define IACTION_CRAFT 2
struct InventoryAction
{
@@ -91,18 +100,20 @@ struct InventoryAction
virtual u16 getType() const = 0;
virtual void serialize(std::ostream &os) const = 0;
- virtual void apply(InventoryContext *c, InventoryManager *mgr,
- ServerEnvironment *env) = 0;
+ virtual void apply(InventoryManager *mgr, ServerActiveObject *player,
+ IGameDef *gamedef) = 0;
+ virtual void clientApply(InventoryManager *mgr, IGameDef *gamedef) = 0;
+ virtual ~InventoryAction() {};
};
struct IMoveAction : public InventoryAction
{
// count=0 means "everything"
u16 count;
- std::string from_inv;
+ InventoryLocation from_inv;
std::string from_list;
s16 from_i;
- std::string to_inv;
+ InventoryLocation to_inv;
std::string to_list;
s16 to_i;
@@ -124,23 +135,24 @@ struct IMoveAction : public InventoryAction
{
os<<"Move ";
os<<count<<" ";
- os<<from_inv<<" ";
+ os<<from_inv.dump()<<" ";
os<<from_list<<" ";
os<<from_i<<" ";
- os<<to_inv<<" ";
+ os<<to_inv.dump()<<" ";
os<<to_list<<" ";
os<<to_i;
}
- void apply(InventoryContext *c, InventoryManager *mgr,
- ServerEnvironment *env);
+ void apply(InventoryManager *mgr, ServerActiveObject *player, IGameDef *gamedef);
+
+ void clientApply(InventoryManager *mgr, IGameDef *gamedef);
};
struct IDropAction : public InventoryAction
{
// count=0 means "everything"
u16 count;
- std::string from_inv;
+ InventoryLocation from_inv;
std::string from_list;
s16 from_i;
@@ -161,68 +173,49 @@ struct IDropAction : public InventoryAction
{
os<<"Drop ";
os<<count<<" ";
- os<<from_inv<<" ";
+ os<<from_inv.dump()<<" ";
os<<from_list<<" ";
os<<from_i;
}
- void apply(InventoryContext *c, InventoryManager *mgr,
- ServerEnvironment *env);
-};
+ void apply(InventoryManager *mgr, ServerActiveObject *player, IGameDef *gamedef);
-/*
- Craft checking system
-*/
-
-enum ItemSpecType
-{
- ITEM_NONE,
- ITEM_MATERIAL,
- ITEM_CRAFT,
- ITEM_TOOL,
- ITEM_MBO
+ void clientApply(InventoryManager *mgr, IGameDef *gamedef);
};
-struct ItemSpec
+struct ICraftAction : public InventoryAction
{
- enum ItemSpecType type;
- // Only other one of these is used
- std::string name;
- u16 num;
-
- ItemSpec():
- type(ITEM_NONE)
+ // count=0 means "everything"
+ u16 count;
+ InventoryLocation craft_inv;
+
+ ICraftAction()
{
+ count = 0;
}
- ItemSpec(enum ItemSpecType a_type, std::string a_name):
- type(a_type),
- name(a_name),
- num(65535)
+
+ ICraftAction(std::istream &is);
+
+ u16 getType() const
{
+ return IACTION_CRAFT;
}
- ItemSpec(enum ItemSpecType a_type, u16 a_num):
- type(a_type),
- name(""),
- num(a_num)
+
+ void serialize(std::ostream &os) const
{
+ os<<"Craft ";
+ os<<count<<" ";
+ os<<craft_inv.dump()<<" ";
}
- bool checkItem(const InventoryItem *item) const;
-};
+ void apply(InventoryManager *mgr, ServerActiveObject *player, IGameDef *gamedef);
-/*
- 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);
+ void clientApply(InventoryManager *mgr, IGameDef *gamedef);
+};
+// Crafting helper
+bool getCraftingResult(Inventory *inv, ItemStack& result,
+ bool decrementInput, IGameDef *gamedef);
#endif
diff --git a/src/irrlichttypes.h b/src/irrlichttypes.h
index bc17694fc..67c96a653 100644
--- a/src/irrlichttypes.h
+++ b/src/irrlichttypes.h
@@ -39,6 +39,8 @@ typedef core::vector2d<s32> v2s32;
typedef core::vector2d<u32> v2u32;
typedef core::vector2d<f32> v2f32;
+typedef core::aabbox3d<f32> aabb3f;
+
#ifdef _MSC_VER
// Windows
typedef unsigned long long u64;
diff --git a/src/itemdef.cpp b/src/itemdef.cpp
new file mode 100644
index 000000000..aa888bbdf
--- /dev/null
+++ b/src/itemdef.cpp
@@ -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();
+}
+
diff --git a/src/itemdef.h b/src/itemdef.h
new file mode 100644
index 000000000..5a432591d
--- /dev/null
+++ b/src/itemdef.h
@@ -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
diff --git a/src/light.cpp b/src/light.cpp
index f214d6ea0..93e498620 100644
--- a/src/light.cpp
+++ b/src/light.cpp
@@ -20,6 +20,56 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "light.h"
#if 1
+/*
+Made using this and adding 230 as the second last one:
+
+#!/usr/bin/python
+
+from math import *
+from sys import stdout
+
+# We want 0 at light=0 and 255 at light=LIGHT_MAX
+LIGHT_MAX = 14
+#FACTOR = 0.69
+#FACTOR = 0.75
+FACTOR = 0.83
+START_FROM_ZERO = False
+
+L = []
+if START_FROM_ZERO:
+ for i in range(1,LIGHT_MAX+1):
+ L.append(int(round(255.0 * FACTOR ** (i-1))))
+ L.append(0)
+else:
+ for i in range(1,LIGHT_MAX+1):
+ L.append(int(round(255.0 * FACTOR ** (i-1))))
+ L.append(255)
+
+L.reverse()
+for i in L:
+ stdout.write(str(i)+",\n")
+*/
+u8 light_decode_table[LIGHT_MAX+1] =
+{
+23,
+27,
+33,
+40,
+48,
+57,
+69,
+83,
+100,
+121,
+146,
+176,
+212,
+230,
+255,
+};
+#endif
+
+#if 0
// This is good
// a_n+1 = a_n * 0.786
// Length of LIGHT_MAX+1 means LIGHT_MAX is the last value.
@@ -42,7 +92,9 @@ u8 light_decode_table[LIGHT_MAX+1] =
200,
255,
};
-#else
+#endif
+
+#if 0
// Use for debugging in dark
u8 light_decode_table[LIGHT_MAX+1] =
{
diff --git a/src/light.h b/src/light.h
index c1af7fa62..238acce43 100644
--- a/src/light.h
+++ b/src/light.h
@@ -75,16 +75,27 @@ inline u8 undiminish_light(u8 light)
extern u8 light_decode_table[LIGHT_MAX+1];
+// 0 <= light <= LIGHT_SUN
+// 0 <= return value <= 255
inline u8 decode_light(u8 light)
{
- if(light == LIGHT_SUN)
- return light_decode_table[LIGHT_MAX];
-
if(light > LIGHT_MAX)
light = LIGHT_MAX;
return light_decode_table[light];
}
+// 0 <= daylight_factor <= 1000
+// 0 <= lightday, lightnight <= LIGHT_SUN
+// 0 <= return value <= LIGHT_SUN
+inline u8 blend_light(u32 daylight_factor, u8 lightday, u8 lightnight)
+{
+ u32 c = 1000;
+ u32 l = ((daylight_factor * lightday + (c-daylight_factor) * lightnight))/c;
+ if(l > LIGHT_SUN)
+ l = LIGHT_SUN;
+ return l;
+}
+
#endif
diff --git a/src/main.cpp b/src/main.cpp
index b7c3ceffe..6cb9cf984 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -54,24 +54,6 @@ A list of "active blocks" in which stuff happens. (+=done)
+ This was left to be done by the old system and it sends only the
nearest ones.
-Vim conversion regexpes for moving to extended content type storage:
-%s/\(\.\|->\)d \([!=]=\)/\1getContent() \2/g
-%s/content_features(\([^.]*\)\.d)/content_features(\1)/g
-%s/\(\.\|->\)d = \([^;]*\);/\1setContent(\2);/g
-%s/\(getNodeNoExNoEmerge([^)]*)\)\.d/\1.getContent()/g
-%s/\(getNodeNoExNoEmerge(.*)\)\.d/\1.getContent()/g
-%s/\.d;/.getContent();/g
-%s/\(content_liquid\|content_flowing_liquid\|make_liquid_flowing\|content_pointable\)(\([^.]*\).d)/\1(\2.getContent())/g
-Other things to note:
-- node.d = node.param0 (only in raw serialization; use getContent() otherwise)
-- node.param = node.param1
-- node.dir = node.param2
-- content_walkable(node.d) etc should be changed to
- content_features(node).walkable etc
-- Also check for lines that store the result of getContent to a 8-bit
- variable and fix them (result of getContent() must be stored in
- content_t, which is 16-bit)
-
NOTE: Seeds in 1260:6c77e7dbfd29:
5721858502589302589:
Spawns you on a small sand island with a surface dungeon
@@ -351,8 +333,6 @@ TODO: Block cube placement around player's head
TODO: Protocol version field
TODO: Think about using same bits for material for fences and doors, for
example
-TODO: Move mineral to param2, increment map serialization version, add
- conversion
SUGG: Restart irrlicht completely when coming back to main menu from game.
- This gets rid of everything that is stored in irrlicht's caches.
@@ -419,7 +399,6 @@ Doing currently:
#include "filesys.h"
#include "config.h"
#include "guiMainMenu.h"
-#include "mineral.h"
#include "materials.h"
#include "game.h"
#include "keycode.h"
@@ -1261,16 +1240,6 @@ int main(int argc, char *argv[])
mysrand(time(0));
/*
- Pre-initialize some stuff with a dummy irrlicht wrapper.
-
- These are needed for unit tests at least.
- */
-
- // Must be called before texturesource is created
- // (for texture atlas making)
- init_mineral();
-
- /*
Run unit tests
*/
diff --git a/src/map.cpp b/src/map.cpp
index 8bdc2ad4c..c245242e8 100644
--- a/src/map.cpp
+++ b/src/map.cpp
@@ -915,7 +915,7 @@ void Map::updateLighting(core::map<v3s16, MapBlock*> & a_blocks,
/*
*/
void Map::addNodeAndUpdate(v3s16 p, MapNode n,
- core::map<v3s16, MapBlock*> &modified_blocks, std::string &player_name)
+ core::map<v3s16, MapBlock*> &modified_blocks)
{
INodeDefManager *nodemgr = m_gamedef->ndef();
@@ -1011,7 +1011,6 @@ void Map::addNodeAndUpdate(v3s16 p, MapNode n,
errorstream<<"Failed to create node metadata \""
<<metadata_name<<"\""<<std::endl;
} else {
- meta->setOwner(player_name);
setNodeMetadata(p, meta);
}
}
@@ -1291,8 +1290,7 @@ bool Map::addNodeWithEvent(v3s16 p, MapNode n)
bool succeeded = true;
try{
core::map<v3s16, MapBlock*> modified_blocks;
- std::string st = std::string("");
- addNodeAndUpdate(p, n, modified_blocks, st);
+ addNodeAndUpdate(p, n, modified_blocks);
// Copy modified_blocks to event
for(core::map<v3s16, MapBlock*>::Iterator
@@ -3271,10 +3269,7 @@ void ServerMap::saveBlock(MapBlock *block)
o.write((char*)&version, 1);
// Write basic data
- block->serialize(o, version);
-
- // Write extra data stored on disk
- block->serializeDiskExtra(o, version);
+ block->serialize(o, version, true);
// Write block to database
@@ -3336,11 +3331,8 @@ void ServerMap::loadBlock(std::string sectordir, std::string blockfile, MapSecto
}
// Read basic data
- block->deSerialize(is, version);
+ block->deSerialize(is, version, true);
- // Read extra data stored on disk
- block->deSerializeDiskExtra(is, version);
-
// If it's a new block, insert it to the map
if(created_new)
sector->insertBlock(block);
@@ -3406,10 +3398,7 @@ void ServerMap::loadBlock(std::string *blob, v3s16 p3d, MapSector *sector, bool
}
// Read basic data
- block->deSerialize(is, version);
-
- // Read extra data stored on disk
- block->deSerializeDiskExtra(is, version);
+ block->deSerialize(is, version, true);
// If it's a new block, insert it to the map
if(created_new)
diff --git a/src/map.h b/src/map.h
index 2bd2c0eb8..90255c1d9 100644
--- a/src/map.h
+++ b/src/map.h
@@ -212,7 +212,7 @@ public:
These handle lighting but not faces.
*/
void addNodeAndUpdate(v3s16 p, MapNode n,
- core::map<v3s16, MapBlock*> &modified_blocks, std::string &player_name);
+ core::map<v3s16, MapBlock*> &modified_blocks);
void removeNodeAndUpdate(v3s16 p,
core::map<v3s16, MapBlock*> &modified_blocks);
diff --git a/src/mapblock.cpp b/src/mapblock.cpp
index 016cb222e..b436378da 100644
--- a/src/mapblock.cpp
+++ b/src/mapblock.cpp
@@ -30,6 +30,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "log.h"
#include "nameidmapping.h"
#include "content_mapnode.h" // For legacy name-id mapping
+#ifndef SERVER
+#include "mapblock_mesh.h"
+#endif
/*
MapBlock
@@ -504,25 +507,41 @@ s16 MapBlock::getGroundLevel(v2s16 p2d)
/*
Serialization
*/
-
// List relevant id-name pairs for ids in the block using nodedef
-static void getBlockNodeIdMapping(NameIdMapping *nimap, MapBlock *block,
+// Renumbers the content IDs (starting at 0 and incrementing
+static void getBlockNodeIdMapping(NameIdMapping *nimap, MapNode *nodes,
INodeDefManager *nodedef)
{
+ std::map<content_t, content_t> mapping;
std::set<content_t> unknown_contents;
- for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
- for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
- for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
+ content_t id_counter = 0;
+ for(u32 i=0; i<MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE; i++)
{
- v3s16 p(x0,y0,z0);
- MapNode n = block->getNode(p);
- content_t id = n.getContent();
- const ContentFeatures &f = nodedef->get(id);
- const std::string &name = f.name;
- if(name == "")
- unknown_contents.insert(id);
+ content_t global_id = nodes[i].getContent();
+ content_t id = CONTENT_IGNORE;
+
+ // Try to find an existing mapping
+ std::map<content_t, content_t>::iterator j = mapping.find(global_id);
+ if(j != mapping.end())
+ {
+ id = j->second;
+ }
else
- nimap->set(id, name);
+ {
+ // We have to assign a new mapping
+ id = id_counter++;
+ mapping.insert(std::make_pair(global_id, id));
+
+ const ContentFeatures &f = nodedef->get(global_id);
+ const std::string &name = f.name;
+ if(name == "")
+ unknown_contents.insert(global_id);
+ else
+ nimap->set(id, name);
+ }
+
+ // Update the MapNode
+ nodes[i].setContent(id);
}
for(std::set<content_t>::const_iterator
i = unknown_contents.begin();
@@ -534,7 +553,7 @@ static void getBlockNodeIdMapping(NameIdMapping *nimap, MapBlock *block,
// Correct ids in the block to match nodedef based on names.
// Unknown ones are added to nodedef.
// Will not update itself to match id-name pairs in nodedef.
-void correctBlockNodeIds(const NameIdMapping *nimap, MapBlock *block,
+static void correctBlockNodeIds(const NameIdMapping *nimap, MapNode *nodes,
IGameDef *gamedef)
{
INodeDefManager *nodedef = gamedef->ndef();
@@ -544,13 +563,9 @@ void correctBlockNodeIds(const NameIdMapping *nimap, MapBlock *block,
// correct ids.
std::set<content_t> unnamed_contents;
std::set<std::string> unallocatable_contents;
- for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
- for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
- for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
+ for(u32 i=0; i<MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE; i++)
{
- v3s16 p(x0,y0,z0);
- MapNode n = block->getNode(p);
- content_t local_id = n.getContent();
+ content_t local_id = nodes[i].getContent();
std::string name;
bool found = nimap->getName(local_id, name);
if(!found){
@@ -566,8 +581,7 @@ void correctBlockNodeIds(const NameIdMapping *nimap, MapBlock *block,
continue;
}
}
- n.setContent(global_id);
- block->setNode(p, n);
+ nodes[i].setContent(global_id);
}
for(std::set<content_t>::const_iterator
i = unnamed_contents.begin();
@@ -585,7 +599,7 @@ void correctBlockNodeIds(const NameIdMapping *nimap, MapBlock *block,
}
}
-void MapBlock::serialize(std::ostream &os, u8 version)
+void MapBlock::serialize(std::ostream &os, u8 version, bool disk)
{
if(!ser_ver_supported(version))
throw VersionMismatchException("ERROR: MapBlock format not supported");
@@ -595,22 +609,226 @@ void MapBlock::serialize(std::ostream &os, u8 version)
throw SerializationError("ERROR: Not writing dummy block.");
}
- // These have no compression
- if(version <= 3 || version == 5 || version == 6)
+ if(version <= 21)
{
- u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
-
- u32 buflen = 1 + nodecount * MapNode::serializedLength(version);
- SharedBuffer<u8> dest(buflen);
+ serialize_pre22(os, version, disk);
+ return;
+ }
- dest[0] = is_underground;
+ // First byte
+ u8 flags = 0;
+ if(is_underground)
+ flags |= 0x01;
+ if(m_day_night_differs)
+ flags |= 0x02;
+ if(m_lighting_expired)
+ flags |= 0x04;
+ if(m_generated == false)
+ flags |= 0x08;
+ writeU8(os, flags);
+
+ /*
+ Bulk node data
+ */
+ NameIdMapping nimap;
+ u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
+ if(disk)
+ {
+ MapNode *tmp_nodes = new MapNode[nodecount];
for(u32 i=0; i<nodecount; i++)
+ tmp_nodes[i] = data[i];
+ getBlockNodeIdMapping(&nimap, tmp_nodes, m_gamedef->ndef());
+
+ u8 content_width = 1;
+ /*u8 content_width = (nimap.size() <= 255) ? 1 : 2;*/
+ u8 params_width = 2;
+ writeU8(os, content_width);
+ writeU8(os, params_width);
+ MapNode::serializeBulk(os, version, tmp_nodes, nodecount,
+ content_width, params_width, true);
+ delete[] tmp_nodes;
+ }
+ else
+ {
+ u8 content_width = 1;
+ /*u8 content_width = 2;*/
+ u8 params_width = 2;
+ writeU8(os, content_width);
+ writeU8(os, params_width);
+ MapNode::serializeBulk(os, version, data, nodecount,
+ content_width, params_width, true);
+ }
+
+ /*
+ Node metadata
+ */
+ std::ostringstream oss(std::ios_base::binary);
+ m_node_metadata->serialize(oss);
+ compressZlib(oss.str(), os);
+
+ /*
+ Data that goes to disk, but not the network
+ */
+ if(disk)
+ {
+ // Static objects
+ m_static_objects.serialize(os);
+
+ // Timestamp
+ writeU32(os, getTimestamp());
+
+ // Write block-specific node definition id mapping
+ nimap.serialize(os);
+ }
+}
+
+
+void MapBlock::deSerialize(std::istream &is, u8 version, bool disk)
+{
+ if(!ser_ver_supported(version))
+ throw VersionMismatchException("ERROR: MapBlock format not supported");
+
+ if(version <= 21)
+ {
+ deSerialize_pre22(is, version, disk);
+ return;
+ }
+
+ u8 flags = readU8(is);
+ is_underground = (flags & 0x01) ? true : false;
+ m_day_night_differs = (flags & 0x02) ? true : false;
+ m_lighting_expired = (flags & 0x04) ? true : false;
+ m_generated = (flags & 0x08) ? false : true;
+
+ /*
+ Bulk node data
+ */
+ u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
+ u8 content_width = readU8(is);
+ u8 params_width = readU8(is);
+ if(content_width != 1)
+ throw SerializationError("MapBlock::deSerialize(): invalid content_width");
+ if(params_width != 2)
+ throw SerializationError("MapBlock::deSerialize(): invalid params_width");
+ MapNode::deSerializeBulk(is, version, data, nodecount,
+ content_width, params_width, true);
+
+ /*
+ NodeMetadata
+ */
+ // Ignore errors
+ try{
+ std::ostringstream oss(std::ios_base::binary);
+ decompressZlib(is, oss);
+ std::istringstream iss(oss.str(), std::ios_base::binary);
+ m_node_metadata->deSerialize(iss, m_gamedef);
+ }
+ catch(SerializationError &e)
+ {
+ errorstream<<"WARNING: MapBlock::deSerialize(): Ignoring an error"
+ <<" while deserializing node metadata"<<std::endl;
+ }
+
+ /*
+ Data that is only on disk
+ */
+ if(disk)
+ {
+ // Static objects
+ m_static_objects.deSerialize(is);
+
+ // Timestamp
+ setTimestamp(readU32(is));
+ m_disk_timestamp = m_timestamp;
+
+ // Dynamically re-set ids based on node names
+ NameIdMapping nimap;
+ nimap.deSerialize(is);
+ correctBlockNodeIds(&nimap, data, m_gamedef);
+ }
+}
+
+/*
+ Legacy serialization
+*/
+
+// List relevant id-name pairs for ids in the block using nodedef
+// Before serialization version 22
+static void getBlockNodeIdMapping_pre22(NameIdMapping *nimap, MapNode *nodes,
+ INodeDefManager *nodedef)
+{
+ std::set<content_t> unknown_contents;
+ for(u32 i=0; i<MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE; i++)
+ {
+ content_t id = nodes[i].getContent();
+ const ContentFeatures &f = nodedef->get(id);
+ const std::string &name = f.name;
+ if(name == "")
+ unknown_contents.insert(id);
+ else
+ nimap->set(id, name);
+ }
+ for(std::set<content_t>::const_iterator
+ i = unknown_contents.begin();
+ i != unknown_contents.end(); i++){
+ errorstream<<"getBlockNodeIdMapping_pre22(): IGNORING ERROR: "
+ <<"Name for node id "<<(*i)<<" not known"<<std::endl;
+ }
+}
+void MapBlock::serialize_pre22(std::ostream &os, u8 version, bool disk)
+{
+ u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
+
+ MapNode *tmp_data = new MapNode[nodecount];
+
+ // Legacy data changes
+ // This code has to change from post-22 to pre-22 format.
+ INodeDefManager *nodedef = m_gamedef->ndef();
+ for(u32 i=0; i<nodecount; i++)
+ {
+ const ContentFeatures &f = nodedef->get(tmp_data[i].getContent());
+ // Mineral
+ if(nodedef->getId("default:stone_with_coal") == tmp_data[i].getContent())
{
- u32 s = 1 + i * MapNode::serializedLength(version);
- data[i].serialize(&dest[s], version);
+ tmp_data[i].setContent(nodedef->getId("default:stone"));
+ tmp_data[i].setParam1(1); // MINERAL_COAL
}
+ else if(nodedef->getId("default:stone_with_iron") == tmp_data[i].getContent())
+ {
+ tmp_data[i].setContent(nodedef->getId("default:stone"));
+ tmp_data[i].setParam1(2); // MINERAL_IRON
+ }
+ // facedir_simple
+ if(f.legacy_facedir_simple)
+ {
+ tmp_data[i].setParam1(tmp_data[i].getParam2());
+ tmp_data[i].setParam2(0);
+ }
+ // wall_mounted
+ if(f.legacy_wallmounted)
+ {
+ u8 wallmounted_new_to_old[8] = {0x04, 0x08, 0x01, 0x02, 0x10, 0x20, 0, 0};
+ u8 dir_new_format = tmp_data[i].getParam2() & 7; // lowest 3 bits
+ u8 dir_old_format = wallmounted_new_to_old[dir_new_format];
+ tmp_data[i].setParam2(dir_old_format);
+ }
+ }
+
+ // Serialize nodes
+ u32 ser_length = MapNode::serializedLength(version);
+ SharedBuffer<u8> databuf_nodelist(nodecount * ser_length);
+ for(u32 i=0; i<nodecount; i++)
+ {
+ tmp_data[i].serialize(&databuf_nodelist[i*ser_length], version);
+ }
+
+ delete[] tmp_data;
- os.write((char*)*dest, dest.getSize());
+ // These have no compression
+ if(version <= 3 || version == 5 || version == 6)
+ {
+ writeU8(os, is_underground);
+ os.write((char*)*databuf_nodelist, databuf_nodelist.getSize());
}
else if(version <= 10)
{
@@ -620,15 +838,13 @@ void MapBlock::serialize(std::ostream &os, u8 version)
*/
// First byte
- os.write((char*)&is_underground, 1);
-
- u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
+ writeU8(os, is_underground);
// Get and compress materials
SharedBuffer<u8> materialdata(nodecount);
for(u32 i=0; i<nodecount; i++)
{
- materialdata[i] = data[i].param0;
+ materialdata[i] = databuf_nodelist[i*ser_length];
}
compress(materialdata, os, version);
@@ -636,7 +852,7 @@ void MapBlock::serialize(std::ostream &os, u8 version)
SharedBuffer<u8> lightdata(nodecount);
for(u32 i=0; i<nodecount; i++)
{
- lightdata[i] = data[i].param1;
+ lightdata[i] = databuf_nodelist[i*ser_length+1];
}
compress(lightdata, os, version);
@@ -646,7 +862,7 @@ void MapBlock::serialize(std::ostream &os, u8 version)
SharedBuffer<u8> param2data(nodecount);
for(u32 i=0; i<nodecount; i++)
{
- param2data[i] = data[i].param2;
+ param2data[i] = databuf_nodelist[i*ser_length+2];
}
compress(param2data, os, version);
}
@@ -667,28 +883,19 @@ void MapBlock::serialize(std::ostream &os, u8 version)
if(m_generated == false)
flags |= 0x08;
}
- os.write((char*)&flags, 1);
+ writeU8(os, flags);
- u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
-
/*
Get data
*/
- // Serialize nodes
- SharedBuffer<u8> databuf_nodelist(nodecount*3);
- for(u32 i=0; i<nodecount; i++)
- {
- data[i].serialize(&databuf_nodelist[i*3], version);
- }
-
// Create buffer with different parameters sorted
SharedBuffer<u8> databuf(nodecount*3);
for(u32 i=0; i<nodecount; i++)
{
- databuf[i] = databuf_nodelist[i*3];
- databuf[i+nodecount] = databuf_nodelist[i*3+1];
- databuf[i+nodecount*2] = databuf_nodelist[i*3+2];
+ databuf[i] = databuf_nodelist[i*ser_length];
+ databuf[i+nodecount] = databuf_nodelist[i*ser_length+1];
+ databuf[i+nodecount*2] = databuf_nodelist[i*ser_length+2];
}
/*
@@ -725,50 +932,69 @@ void MapBlock::serialize(std::ostream &os, u8 version)
}
}
}
-}
-void MapBlock::deSerialize(std::istream &is, u8 version)
-{
- if(!ser_ver_supported(version))
- throw VersionMismatchException("ERROR: MapBlock format not supported");
- // These have no lighting info
- if(version <= 1)
+ if(disk)
{
- setLightingExpired(true);
- }
+ // Versions up from 9 have block objects. (DEPRECATED)
+ if(version >= 9)
+ {
+ // count=0
+ writeU16(os, 0);
+ }
- // These have no "generated" field
- if(version < 18)
- {
- m_generated = true;
+ // Versions up from 15 have static objects.
+ if(version >= 15)
+ {
+ m_static_objects.serialize(os);
+ }
+
+ // Timestamp
+ if(version >= 17)
+ {
+ writeU32(os, getTimestamp());
+ }
+
+ // Scan and write node definition id mapping
+ if(version >= 21)
+ {
+ NameIdMapping nimap;
+ getBlockNodeIdMapping_pre22(&nimap, data, m_gamedef->ndef());
+ nimap.serialize(os);
+ }
}
+}
+
+void MapBlock::deSerialize_pre22(std::istream &is, u8 version, bool disk)
+{
+ u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
+
+ // Initialize default flags
+ is_underground = false;
+ m_day_night_differs = false;
+ m_lighting_expired = false;
+ m_generated = true;
+
+ // Make a temporary buffer
+ u32 ser_length = MapNode::serializedLength(version);
+ SharedBuffer<u8> databuf_nodelist(nodecount * ser_length);
// These have no compression
if(version <= 3 || version == 5 || version == 6)
{
- u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
char tmp;
is.read(&tmp, 1);
if(is.gcount() != 1)
throw SerializationError
("MapBlock::deSerialize: no enough input data");
is_underground = tmp;
- for(u32 i=0; i<nodecount; i++)
- {
- s32 len = MapNode::serializedLength(version);
- SharedBuffer<u8> d(len);
- is.read((char*)*d, len);
- if(is.gcount() != len)
- throw SerializationError
- ("MapBlock::deSerialize: no enough input data");
- data[i].deSerialize(*d, version);
- }
+ is.read((char*)*databuf_nodelist, nodecount * ser_length);
+ if(is.gcount() != nodecount * ser_length)
+ throw SerializationError
+ ("MapBlock::deSerialize: no enough input data");
}
else if(version <= 10)
{
- u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
-
u8 t8;
is.read((char*)&t8, 1);
is_underground = t8;
@@ -783,7 +1009,7 @@ void MapBlock::deSerialize(std::istream &is, u8 version)
("MapBlock::deSerialize: invalid format");
for(u32 i=0; i<s.size(); i++)
{
- data[i].param0 = s[i];
+ databuf_nodelist[i*ser_length] = s[i];
}
}
{
@@ -796,7 +1022,7 @@ void MapBlock::deSerialize(std::istream &is, u8 version)
("MapBlock::deSerialize: invalid format");
for(u32 i=0; i<s.size(); i++)
{
- data[i].param1 = s[i];
+ databuf_nodelist[i*ser_length + 1] = s[i];
}
}
@@ -811,15 +1037,13 @@ void MapBlock::deSerialize(std::istream &is, u8 version)
("MapBlock::deSerialize: invalid format");
for(u32 i=0; i<s.size(); i++)
{
- data[i].param2 = s[i];
+ databuf_nodelist[i*ser_length + 2] = s[i];
}
}
}
// All other versions (newest)
else
{
- u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
-
u8 flags;
is.read((char*)&flags, 1);
is_underground = (flags & 0x01) ? true : false;
@@ -840,11 +1064,9 @@ void MapBlock::deSerialize(std::istream &is, u8 version)
// deserialize nodes from buffer
for(u32 i=0; i<nodecount; i++)
{
- u8 buf[3];
- buf[0] = s[i];
- buf[1] = s[i+nodecount];
- buf[2] = s[i+nodecount*2];
- data[i].deSerialize(buf, version);
+ databuf_nodelist[i*ser_length] = s[i];
+ databuf_nodelist[i*ser_length + 1] = s[i+nodecount];
+ databuf_nodelist[i*ser_length + 2] = s[i+nodecount*2];
}
/*
@@ -876,76 +1098,98 @@ void MapBlock::deSerialize(std::istream &is, u8 version)
}
}
}
-}
-void MapBlock::serializeDiskExtra(std::ostream &os, u8 version)
-{
- // Versions up from 9 have block objects. (DEPRECATED)
- if(version >= 9)
+ // Deserialize node data
+ for(u32 i=0; i<nodecount; i++)
{
- // count=0
- writeU16(os, 0);
- }
-
- // Versions up from 15 have static objects.
- if(version >= 15)
- {
- m_static_objects.serialize(os);
+ data[i].deSerialize(&databuf_nodelist[i*ser_length], version);
}
- // Timestamp
- if(version >= 17)
+ if(disk)
{
- writeU32(os, getTimestamp());
- }
+ /*
+ Versions up from 9 have block objects. (DEPRECATED)
+ */
+ if(version >= 9){
+ u16 count = readU16(is);
+ // Not supported and length not known if count is not 0
+ if(count != 0){
+ errorstream<<"WARNING: MapBlock::deSerialize_pre22(): "
+ <<"Ignoring stuff coming at and after MBOs"<<std::endl;
+ return;
+ }
+ }
+
+ /*
+ Versions up from 15 have static objects.
+ */
+ if(version >= 15)
+ m_static_objects.deSerialize(is);
+
+ // Timestamp
+ if(version >= 17){
+ setTimestamp(readU32(is));
+ m_disk_timestamp = m_timestamp;
+ } else {
+ setTimestamp(BLOCK_TIMESTAMP_UNDEFINED);
+ }
- // Scan and write node definition id mapping
- if(version >= 21){
+ // Dynamically re-set ids based on node names
NameIdMapping nimap;
- getBlockNodeIdMapping(&nimap, this, m_gamedef->ndef());
- nimap.serialize(os);
+ // If supported, read node definition id mapping
+ if(version >= 21){
+ nimap.deSerialize(is);
+ // Else set the legacy mapping
+ } else {
+ content_mapnode_get_name_id_mapping(&nimap);
+ }
+ correctBlockNodeIds(&nimap, data, m_gamedef);
}
-}
-void MapBlock::deSerializeDiskExtra(std::istream &is, u8 version)
-{
- /*
- Versions up from 9 have block objects. (DEPRECATED)
- */
- if(version >= 9){
- u16 count = readU16(is);
- // Not supported and length not known if count is not 0
- if(count != 0){
- errorstream<<"WARNING: MapBlock::deSerializeDiskExtra(): "
- <<"Ignoring stuff coming at and after MBOs"<<std::endl;
- return;
+
+ // Legacy data changes
+ // This code has to convert from pre-22 to post-22 format.
+ INodeDefManager *nodedef = m_gamedef->ndef();
+ for(u32 i=0; i<nodecount; i++)
+ {
+ const ContentFeatures &f = nodedef->get(data[i].getContent());
+ // Mineral
+ if(nodedef->getId("default:stone") == data[i].getContent()
+ && data[i].getParam1() == 1)
+ {
+ data[i].setContent(nodedef->getId("default:stone_with_coal"));
+ data[i].setParam1(0);
+ }
+ else if(nodedef->getId("default:stone") == data[i].getContent()
+ && data[i].getParam1() == 2)
+ {
+ data[i].setContent(nodedef->getId("default:stone_with_iron"));
+ data[i].setParam1(0);
+ }
+ // facedir_simple
+ if(f.legacy_facedir_simple)
+ {
+ data[i].setParam2(data[i].getParam1());
+ data[i].setParam1(0);
+ }
+ // wall_mounted
+ if(f.legacy_wallmounted)
+ {
+ u8 wallmounted_new_to_old[8] = {0x04, 0x08, 0x01, 0x02, 0x10, 0x20, 0, 0};
+ u8 dir_old_format = data[i].getParam2();
+ u8 dir_new_format = 0;
+ for(u8 j=0; j<8; j++)
+ {
+ if((dir_old_format & wallmounted_new_to_old[j]) != 0)
+ {
+ dir_new_format = j;
+ break;
+ }
+ }
+ data[i].setParam2(dir_new_format);
}
}
- /*
- Versions up from 15 have static objects.
- */
- if(version >= 15)
- m_static_objects.deSerialize(is);
-
- // Timestamp
- if(version >= 17){
- setTimestamp(readU32(is));
- m_disk_timestamp = m_timestamp;
- } else {
- setTimestamp(BLOCK_TIMESTAMP_UNDEFINED);
- }
-
- // Dynamically re-set ids based on node names
- NameIdMapping nimap;
- // If supported, read node definition id mapping
- if(version >= 21){
- nimap.deSerialize(is);
- // Else set the legacy mapping
- } else {
- content_mapnode_get_name_id_mapping(&nimap);
- }
- correctBlockNodeIds(&nimap, this, m_gamedef);
}
/*
diff --git a/src/mapblock.h b/src/mapblock.h
index aa5aa43f7..c9ff36679 100644
--- a/src/mapblock.h
+++ b/src/mapblock.h
@@ -32,9 +32,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "voxel.h"
#include "staticobject.h"
#include "mapblock_nodemod.h"
-#ifndef SERVER
- #include "mapblock_mesh.h"
-#endif
#include "modifiedstate.h"
class Map;
@@ -366,17 +363,8 @@ public:
Graphics-related methods
*/
- /*// A quick version with nodes passed as parameters
- u8 getFaceLight(u32 daynight_ratio, MapNode n, MapNode n2,
- v3s16 face_dir);*/
- /*// A more convenient version
- u8 getFaceLight(u32 daynight_ratio, v3s16 p, v3s16 face_dir)
- {
- return getFaceLight(daynight_ratio,
- getNodeParentNoEx(p),
- getNodeParentNoEx(p + face_dir),
- face_dir);
- }*/
+#ifndef SERVER // Only on client
+
u8 getFaceLight2(u32 daynight_ratio, v3s16 p, v3s16 face_dir,
INodeDefManager *nodemgr)
{
@@ -386,8 +374,6 @@ public:
face_dir, nodemgr);
}
-#ifndef SERVER // Only on client
-
#if 1
/*
Thread-safely updates the whole mesh of the mapblock.
@@ -527,20 +513,20 @@ public:
*/
// These don't write or read version by itself
- void serialize(std::ostream &os, u8 version);
- void deSerialize(std::istream &is, u8 version);
-
- // Used after the basic ones when writing on disk (serverside)
- void serializeDiskExtra(std::ostream &os, u8 version);
- // In addition to doing other things, will add unknown blocks from
- // id-name mapping to wndef
- void deSerializeDiskExtra(std::istream &is, u8 version);
+ // Set disk to true for on-disk format, false for over-the-network format
+ void serialize(std::ostream &os, u8 version, bool disk);
+ // If disk == true: In addition to doing other things, will add
+ // unknown blocks from id-name mapping to wndef
+ void deSerialize(std::istream &is, u8 version, bool disk);
private:
/*
Private methods
*/
+ void serialize_pre22(std::ostream &os, u8 version, bool disk);
+ void deSerialize_pre22(std::istream &is, u8 version, bool disk);
+
/*
Used only internally, because changes can't be tracked
*/
diff --git a/src/mapblock_mesh.cpp b/src/mapblock_mesh.cpp
index c051dda50..b843448c4 100644
--- a/src/mapblock_mesh.cpp
+++ b/src/mapblock_mesh.cpp
@@ -25,10 +25,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "settings.h"
#include "profiler.h"
#include "nodedef.h"
-#include "tile.h"
#include "gamedef.h"
#include "content_mapblock.h"
-#include "mineral.h" // For mineral_block_texture
void MeshMakeData::fill(u32 daynight_ratio, MapBlock *block)
{
@@ -83,6 +81,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]
*/
@@ -207,8 +238,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.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 = 255;
if(tile.id == TILE_WATER)
@@ -230,16 +261,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,
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),
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),
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),
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),
core::vector2d<f32>(x0+w*abs_scale, y0));
@@ -250,70 +281,48 @@ static void makeFastFace(TileSpec tile, u8 li0, u8 li1, u8 li2, u8 li3, v3f p,
dest.push_back(face);
}
-static TileSpec getTile(const MapNode &node, v3s16 dir,
- ITextureSource *tsrc, INodeDefManager *nodemgr)
+static TileSpec getTile(const MapNode &node, v3s16 dir, INodeDefManager *nodemgr)
{
- const ContentFeatures &f = nodemgr->get(node);
-
- if(f.param_type == CPT_FACEDIR_SIMPLE)
- dir = facedir_rotate(node.param1, dir);
-
- TileSpec spec;
-
- s32 dir_i = -1;
+ // Direction must be (1,0,0), (-1,0,0), (0,1,0), (0,-1,0),
+ // (0,0,1), (0,0,-1) or (0,0,0)
+ assert(dir.X * dir.X + dir.Y * dir.Y + dir.Z * dir.Z <= 1);
+
+ // Convert direction to single integer for table lookup
+ // 0 = (0,0,0)
+ // 1 = (1,0,0)
+ // 2 = (0,1,0)
+ // 3 = (0,0,1)
+ // 4 = invalid, treat as (0,0,0)
+ // 5 = (0,0,-1)
+ // 6 = (0,-1,0)
+ // 7 = (-1,0,0)
+ u8 dir_i = (dir.X + 2 * dir.Y + 3 * dir.Z) & 7;
+
+ // Get rotation for things like chests
+ u8 facedir = node.getFaceDir(nodemgr);
+ assert(facedir <= 3);
- if(dir == v3s16(0,0,0))
- dir_i = -1;
- else if(dir == v3s16(0,1,0))
- dir_i = 0;
- else if(dir == v3s16(0,-1,0))
- dir_i = 1;
- else if(dir == v3s16(1,0,0))
- dir_i = 2;
- else if(dir == v3s16(-1,0,0))
- dir_i = 3;
- else if(dir == v3s16(0,0,1))
- dir_i = 4;
- else if(dir == v3s16(0,0,-1))
- dir_i = 5;
-
- if(dir_i == -1)
- // Non-directional
- spec = f.tiles[0];
- else
- spec = f.tiles[dir_i];
-
- /*
- If it contains some mineral, change texture id
- */
- if(f.param_type == CPT_MINERAL && tsrc)
+ static const u8 dir_to_tile[4 * 8] =
{
- u8 mineral = node.getMineral(nodemgr);
- std::string mineral_texture_name = mineral_block_texture(mineral);
- if(mineral_texture_name != "")
- {
- u32 orig_id = spec.texture.id;
- std::string texture_name = tsrc->getTextureName(orig_id);
- //texture_name += "^blit:";
- texture_name += "^";
- texture_name += mineral_texture_name;
- u32 new_id = tsrc->getTextureId(texture_name);
- spec.texture = tsrc->getTexture(new_id);
- }
- }
-
- return spec;
+ // 0 +X +Y +Z 0 -Z -Y -X
+ 0, 2, 0, 4, 0, 5, 1, 3, // facedir = 0
+ 0, 4, 0, 3, 0, 2, 1, 5, // facedir = 1
+ 0, 3, 0, 5, 0, 4, 1, 2, // facedir = 2
+ 0, 5, 0, 2, 0, 3, 1, 4, // facedir = 3
+ };
+
+ return nodemgr->get(node).tiles[dir_to_tile[facedir*8 + dir_i]];
}
/*
Gets node tile from any place relative to block.
Returns TILE_NODE if doesn't exist or should not be drawn.
*/
-static TileSpec getNodeTile(MapNode mn, v3s16 p, v3s16 face_dir,
- NodeModMap &temp_mods, ITextureSource *tsrc, INodeDefManager *ndef)
+TileSpec getNodeTile(MapNode mn, v3s16 p, v3s16 face_dir,
+ NodeModMap *temp_mods, ITextureSource *tsrc, INodeDefManager *ndef)
{
TileSpec spec;
- spec = getTile(mn, face_dir, tsrc, ndef);
+ spec = getTile(mn, face_dir, ndef);
/*
Check temporary modifications on this node
@@ -325,13 +334,15 @@ static TileSpec getNodeTile(MapNode mn, v3s16 p, v3s16 face_dir,
{
struct NodeMod mod = n->getValue();*/
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)
{
MapNode mn2(mod.param);
- spec = getTile(mn2, face_dir, tsrc, ndef);
+ spec = getTile(mn2, face_dir, ndef);
}
+ #endif
if(mod.type == NODEMOD_CRACK)
{
/*
@@ -361,19 +372,14 @@ static TileSpec getNodeTile(MapNode mn, v3s16 p, v3s16 face_dir,
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
*/
- /*core::map<v3s16, NodeMod>::Node *n;
- n = m_temp_mods.find(p);
- // If modified
- if(n != NULL)
- {
- struct NodeMod mod = n->getValue();*/
+ #if 0 // NODEMOD_CHANGECONTENT isn't used at the moment
NodeMod mod;
- if(temp_mods.get(p, &mod))
+ if(temp_mods && temp_mods->get(p, &mod))
{
if(mod.type == NODEMOD_CHANGECONTENT)
{
@@ -395,6 +401,7 @@ static content_t getNodeContent(v3s16 p, MapNode mn, NodeModMap &temp_mods)
*/
}
}
+ #endif
return mn.getContent();
}
@@ -469,7 +476,7 @@ static void getTileInfo(
v3s16 face_dir,
u32 daynight_ratio,
VoxelManipulator &vmanip,
- NodeModMap &temp_mods,
+ NodeModMap *temp_mods,
bool smooth_lighting,
IGameDef *gamedef,
// Output:
@@ -553,7 +560,7 @@ static void updateFastFaceRow(
v3s16 face_dir,
v3f face_dir_f,
core::array<FastFace> &dest,
- NodeModMap &temp_mods,
+ NodeModMap *temp_mods,
VoxelManipulator &vmanip,
v3s16 blockpos_nodes,
bool smooth_lighting,
@@ -749,7 +756,7 @@ scene::SMesh* makeMapBlockMesh(MeshMakeData *data, IGameDef *gamedef)
v3s16(0,1,0), //face dir
v3f (0,1,0),
fastfaces_new,
- data->m_temp_mods,
+ &data->m_temp_mods,
data->m_vmanip,
blockpos_nodes,
smooth_lighting,
@@ -768,7 +775,7 @@ scene::SMesh* makeMapBlockMesh(MeshMakeData *data, IGameDef *gamedef)
v3s16(1,0,0),
v3f (1,0,0),
fastfaces_new,
- data->m_temp_mods,
+ &data->m_temp_mods,
data->m_vmanip,
blockpos_nodes,
smooth_lighting,
@@ -787,7 +794,7 @@ scene::SMesh* makeMapBlockMesh(MeshMakeData *data, IGameDef *gamedef)
v3s16(0,0,1),
v3f (0,0,1),
fastfaces_new,
- data->m_temp_mods,
+ &data->m_temp_mods,
data->m_vmanip,
blockpos_nodes,
smooth_lighting,
diff --git a/src/mapblock_mesh.h b/src/mapblock_mesh.h
index 36cc9be24..4d3e7d29d 100644
--- a/src/mapblock_mesh.h
+++ b/src/mapblock_mesh.h
@@ -22,6 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "common_irrlicht.h"
#include "mapblock_nodemod.h"
+#include "tile.h"
#include "voxel.h"
class IGameDef;
@@ -125,6 +126,8 @@ private:
// Helper functions
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;
@@ -140,6 +143,11 @@ struct MeshMakeData
parent of 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
diff --git a/src/mapgen.cpp b/src/mapgen.cpp
index c2256cedb..fe2ce13f5 100644
--- a/src/mapgen.cpp
+++ b/src/mapgen.cpp
@@ -22,7 +22,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "noise.h"
#include "mapblock.h"
#include "map.h"
-#include "mineral.h"
//#include "serverobject.h"
#include "content_sao.h"
#include "nodedef.h"
@@ -1652,15 +1651,20 @@ void make_block(BlockMakeData *data)
MapNode n_##name(c_##name);
CONTENT_VARIABLE(ndef, stone);
- CONTENT_VARIABLE(ndef, water_source);
CONTENT_VARIABLE(ndef, air);
+ CONTENT_VARIABLE(ndef, water_source);
CONTENT_VARIABLE(ndef, dirt);
CONTENT_VARIABLE(ndef, sand);
CONTENT_VARIABLE(ndef, gravel);
+ CONTENT_VARIABLE(ndef, clay);
CONTENT_VARIABLE(ndef, lava_source);
CONTENT_VARIABLE(ndef, cobble);
CONTENT_VARIABLE(ndef, mossycobble);
CONTENT_VARIABLE(ndef, dirt_with_grass);
+ CONTENT_VARIABLE(ndef, junglegrass);
+ CONTENT_VARIABLE(ndef, stone_with_coal);
+ CONTENT_VARIABLE(ndef, stone_with_iron);
+ CONTENT_VARIABLE(ndef, mese);
/*
Make base ground level
@@ -1703,139 +1707,6 @@ void make_block(BlockMakeData *data)
}
/*
- Add minerals
- */
-
- {
- PseudoRandom mineralrandom(blockseed);
-
- /*
- Add meseblocks
- */
- for(s16 i=0; i<approx_ground_depth/4; i++)
- {
- if(mineralrandom.next()%50 == 0)
- {
- s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
- s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
- s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
- for(u16 i=0; i<27; i++)
- {
- v3s16 p = v3s16(x,y,z) + g_27dirs[i];
- u32 vi = vmanip.m_area.index(p);
- if(vmanip.m_data[vi].getContent() == c_stone)
- if(mineralrandom.next()%8 == 0)
- vmanip.m_data[vi] = MapNode(LEGN(ndef, "CONTENT_MESE"));
- }
-
- }
- }
- /*
- Add others
- */
- {
- u16 a = mineralrandom.range(0,15);
- a = a*a*a;
- u16 amount = 20 * a/1000;
- for(s16 i=0; i<amount; i++)
- {
- s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
- s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
- s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
-
- u8 base_content = LEGN(ndef, "CONTENT_STONE");
- MapNode new_content(CONTENT_IGNORE);
- u32 sparseness = 6;
-
- if(noisebuf_ground_crumbleness.get(x,y+5,z) < -0.1)
- {
- new_content = MapNode(LEGN(ndef, "CONTENT_STONE"), MINERAL_COAL);
- }
- else
- {
- if(noisebuf_ground_wetness.get(x,y+5,z) > 0.0)
- new_content = MapNode(LEGN(ndef, "CONTENT_STONE"), MINERAL_IRON);
- /*if(noisebuf_ground_wetness.get(x,y,z) > 0.0)
- vmanip.m_data[i] = MapNode(LEGN(ndef, "CONTENT_MUD"));
- else
- vmanip.m_data[i] = MapNode(LEGN(ndef, "CONTENT_SAND"));*/
- }
- /*else if(noisebuf_ground_crumbleness.get(x,y,z) > 0.1)
- {
- }*/
-
- if(new_content.getContent() != CONTENT_IGNORE)
- {
- for(u16 i=0; i<27; i++)
- {
- v3s16 p = v3s16(x,y,z) + g_27dirs[i];
- u32 vi = vmanip.m_area.index(p);
- if(vmanip.m_data[vi].getContent() == base_content)
- {
- if(mineralrandom.next()%sparseness == 0)
- vmanip.m_data[vi] = new_content;
- }
- }
- }
- }
- }
- /*
- Add coal
- */
- //for(s16 i=0; i < MYMAX(0, 50 - abs(node_min.Y+8 - (-30))); i++)
- //for(s16 i=0; i<50; i++)
- u16 coal_amount = 30;
- u16 coal_rareness = 60 / coal_amount;
- if(coal_rareness == 0)
- coal_rareness = 1;
- if(mineralrandom.next()%coal_rareness == 0)
- {
- u16 a = mineralrandom.next() % 16;
- u16 amount = coal_amount * a*a*a / 1000;
- for(s16 i=0; i<amount; i++)
- {
- s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
- s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
- s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
- for(u16 i=0; i<27; i++)
- {
- v3s16 p = v3s16(x,y,z) + g_27dirs[i];
- u32 vi = vmanip.m_area.index(p);
- if(vmanip.m_data[vi].getContent() == c_stone)
- if(mineralrandom.next()%8 == 0)
- vmanip.m_data[vi] = MapNode(LEGN(ndef, "CONTENT_STONE"), MINERAL_COAL);
- }
- }
- }
- /*
- Add iron
- */
- u16 iron_amount = 8;
- u16 iron_rareness = 60 / iron_amount;
- if(iron_rareness == 0)
- iron_rareness = 1;
- if(mineralrandom.next()%iron_rareness == 0)
- {
- u16 a = mineralrandom.next() % 16;
- u16 amount = iron_amount * a*a*a / 1000;
- for(s16 i=0; i<amount; i++)
- {
- s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
- s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
- s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
- for(u16 i=0; i<27; i++)
- {
- v3s16 p = v3s16(x,y,z) + g_27dirs[i];
- u32 vi = vmanip.m_area.index(p);
- if(vmanip.m_data[vi].getContent() == c_stone)
- if(mineralrandom.next()%8 == 0)
- vmanip.m_data[vi] = MapNode(LEGN(ndef, "CONTENT_STONE"), MINERAL_IRON);
- }
- }
- }
- }
-
- /*
Add mud and sand and others underground (in place of stone)
*/
@@ -1955,7 +1826,7 @@ void make_block(BlockMakeData *data)
/*else if(vmanip.m_flags[i] & VMANIP_FLAG_DUNGEON_INSIDE)
{
if(wetness > 1.2)
- vmanip.m_data[i].setContent(LEGN(ndef, "CONTENT_MUD"));
+ vmanip.m_data[i].setContent(c_dirt);
}*/
data->vmanip->m_area.add_y(em, i, -1);
}
@@ -2077,23 +1948,23 @@ void make_block(BlockMakeData *data)
((claynoise > 0) && (claynoise < 0.12) && (current_depth == 1))
);
if (have_clay)
- vmanip.m_data[i] = MapNode(LEGN(ndef, "CONTENT_CLAY"));
+ vmanip.m_data[i] = MapNode(c_clay);
else
- vmanip.m_data[i] = MapNode(LEGN(ndef, "CONTENT_SAND"));
+ vmanip.m_data[i] = MapNode(c_sand);
}
#if 1
else if(current_depth==0 && !water_detected
&& y >= WATER_LEVEL && air_detected)
- vmanip.m_data[i] = MapNode(LEGN(ndef, "CONTENT_GRASS"));
+ vmanip.m_data[i] = MapNode(c_dirt_with_grass);
#endif
else
- vmanip.m_data[i] = MapNode(LEGN(ndef, "CONTENT_MUD"));
+ vmanip.m_data[i] = MapNode(c_dirt);
}
else
{
- if(vmanip.m_data[i].getContent() == LEGN(ndef, "CONTENT_MUD")
- || vmanip.m_data[i].getContent() == LEGN(ndef, "CONTENT_GRASS"))
- vmanip.m_data[i] = MapNode(LEGN(ndef, "CONTENT_STONE"));
+ if(vmanip.m_data[i].getContent() == c_dirt
+ || vmanip.m_data[i].getContent() == c_dirt_with_grass)
+ vmanip.m_data[i] = MapNode(c_stone);
}
current_depth++;
@@ -2171,7 +2042,7 @@ void make_block(BlockMakeData *data)
make_papyrus(vmanip, p, ndef);
}
// Trees grow only on mud and grass, on land
- else if((n->getContent() == c_dirt || n->getContent() == LEGN(ndef, "CONTENT_GRASS")) && y > WATER_LEVEL + 2)
+ else if((n->getContent() == c_dirt || n->getContent() == c_dirt_with_grass) && y > WATER_LEVEL + 2)
{
p.Y++;
//if(surface_humidity_2d(data->seed, v2s16(x, y)) < 0.5)
@@ -2238,10 +2109,10 @@ void make_block(BlockMakeData *data)
continue;
/*p.Y--;
if(vmanip.m_area.contains(p))
- vmanip.m_data[vmanip.m_area.index(p)] = LEGN(ndef, "CONTENT_MUD");
+ vmanip.m_data[vmanip.m_area.index(p)] = c_dirt;
p.Y++;*/
if(vmanip.m_area.contains(p))
- vmanip.m_data[vmanip.m_area.index(p)] = LEGN(ndef, "CONTENT_JUNGLEGRASS");
+ vmanip.m_data[vmanip.m_area.index(p)] = c_junglegrass;
}
}
@@ -2269,7 +2140,7 @@ void make_block(BlockMakeData *data)
/*{
u32 i = data->vmanip->m_area.index(v3s16(p));
MapNode *n = &data->vmanip->m_data[i];
- if(n->getContent() != LEGN(ndef, "CONTENT_MUD") && n->getContent() != LEGN(ndef, "CONTENT_GRASS"))
+ if(n->getContent() != c_dirt && n->getContent() != c_dirt_with_grass)
continue;
}*/
// Will be placed one higher
@@ -2304,7 +2175,7 @@ void make_block(BlockMakeData *data)
/*{
u32 i = data->vmanip->m_area.index(v3s16(p));
MapNode *n = &data->vmanip->m_data[i];
- if(n->getContent() != LEGN(ndef, "CONTENT_MUD") && n->getContent() != LEGN(ndef, "CONTENT_GRASS"))
+ if(n->getContent() != c_dirt && n->getContent() != c_dirt_with_grass)
continue;
}*/
// Will be placed one lower
@@ -2315,6 +2186,139 @@ void make_block(BlockMakeData *data)
#endif
}
+ /*
+ Add minerals
+ */
+
+ {
+ PseudoRandom mineralrandom(blockseed);
+
+ /*
+ Add meseblocks
+ */
+ for(s16 i=0; i<approx_ground_depth/4; i++)
+ {
+ if(mineralrandom.next()%50 == 0)
+ {
+ s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
+ s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
+ s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
+ for(u16 i=0; i<27; i++)
+ {
+ v3s16 p = v3s16(x,y,z) + g_27dirs[i];
+ u32 vi = vmanip.m_area.index(p);
+ if(vmanip.m_data[vi].getContent() == c_stone)
+ if(mineralrandom.next()%8 == 0)
+ vmanip.m_data[vi] = MapNode(c_mese);
+ }
+
+ }
+ }
+ /*
+ Add others
+ */
+ {
+ u16 a = mineralrandom.range(0,15);
+ a = a*a*a;
+ u16 amount = 20 * a/1000;
+ for(s16 i=0; i<amount; i++)
+ {
+ s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
+ s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
+ s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
+
+ u8 base_content = c_stone;
+ MapNode new_content(CONTENT_IGNORE);
+ u32 sparseness = 6;
+
+ if(noisebuf_ground_crumbleness.get(x,y+5,z) < -0.1)
+ {
+ new_content = MapNode(c_stone_with_coal);
+ }
+ else
+ {
+ if(noisebuf_ground_wetness.get(x,y+5,z) > 0.0)
+ new_content = MapNode(c_stone_with_iron);
+ /*if(noisebuf_ground_wetness.get(x,y,z) > 0.0)
+ vmanip.m_data[i] = MapNode(c_dirt);
+ else
+ vmanip.m_data[i] = MapNode(c_sand);*/
+ }
+ /*else if(noisebuf_ground_crumbleness.get(x,y,z) > 0.1)
+ {
+ }*/
+
+ if(new_content.getContent() != CONTENT_IGNORE)
+ {
+ for(u16 i=0; i<27; i++)
+ {
+ v3s16 p = v3s16(x,y,z) + g_27dirs[i];
+ u32 vi = vmanip.m_area.index(p);
+ if(vmanip.m_data[vi].getContent() == base_content)
+ {
+ if(mineralrandom.next()%sparseness == 0)
+ vmanip.m_data[vi] = new_content;
+ }
+ }
+ }
+ }
+ }
+ /*
+ Add coal
+ */
+ //for(s16 i=0; i < MYMAX(0, 50 - abs(node_min.Y+8 - (-30))); i++)
+ //for(s16 i=0; i<50; i++)
+ u16 coal_amount = 30;
+ u16 coal_rareness = 60 / coal_amount;
+ if(coal_rareness == 0)
+ coal_rareness = 1;
+ if(mineralrandom.next()%coal_rareness == 0)
+ {
+ u16 a = mineralrandom.next() % 16;
+ u16 amount = coal_amount * a*a*a / 1000;
+ for(s16 i=0; i<amount; i++)
+ {
+ s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
+ s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
+ s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
+ for(u16 i=0; i<27; i++)
+ {
+ v3s16 p = v3s16(x,y,z) + g_27dirs[i];
+ u32 vi = vmanip.m_area.index(p);
+ if(vmanip.m_data[vi].getContent() == c_stone)
+ if(mineralrandom.next()%8 == 0)
+ vmanip.m_data[vi] = MapNode(c_stone_with_coal);
+ }
+ }
+ }
+ /*
+ Add iron
+ */
+ u16 iron_amount = 8;
+ u16 iron_rareness = 60 / iron_amount;
+ if(iron_rareness == 0)
+ iron_rareness = 1;
+ if(mineralrandom.next()%iron_rareness == 0)
+ {
+ u16 a = mineralrandom.next() % 16;
+ u16 amount = iron_amount * a*a*a / 1000;
+ for(s16 i=0; i<amount; i++)
+ {
+ s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
+ s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
+ s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
+ for(u16 i=0; i<27; i++)
+ {
+ v3s16 p = v3s16(x,y,z) + g_27dirs[i];
+ u32 vi = vmanip.m_area.index(p);
+ if(vmanip.m_data[vi].getContent() == c_stone)
+ if(mineralrandom.next()%8 == 0)
+ vmanip.m_data[vi] = MapNode(c_stone_with_iron);
+ }
+ }
+ }
+ }
+
}
BlockMakeData::BlockMakeData():
diff --git a/src/mapnode.cpp b/src/mapnode.cpp
index a757149b1..6cb9671b5 100644
--- a/src/mapnode.cpp
+++ b/src/mapnode.cpp
@@ -21,136 +21,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "mapnode.h"
#include "porting.h"
#include <string>
-#include "mineral.h"
#include "main.h" // For g_settings
#include "nodedef.h"
#include "content_mapnode.h" // For mapnode_translate_*_internal
#include "serialization.h" // For ser_ver_supported
-#ifndef SERVER
-/*
- Nodes make a face if contents differ and solidness differs.
- Return value:
- 0: No face
- 1: Face uses m1's content
- 2: Face uses m2's content
- equivalent: Whether the blocks share the same face (eg. water and glass)
-
- TODO: Add 3: Both faces drawn with backface culling, remove equivalent
-*/
-u8 face_contents(content_t m1, content_t m2, bool *equivalent,
- INodeDefManager *nodemgr)
-{
- *equivalent = false;
-
- if(m1 == CONTENT_IGNORE || m2 == CONTENT_IGNORE)
- return 0;
-
- bool contents_differ = (m1 != m2);
-
- const ContentFeatures &f1 = nodemgr->get(m1);
- const ContentFeatures &f2 = nodemgr->get(m2);
-
- // Contents don't differ for different forms of same liquid
- if(f1.sameLiquid(f2))
- contents_differ = false;
-
- u8 c1 = f1.solidness;
- u8 c2 = f2.solidness;
-
- bool solidness_differs = (c1 != c2);
- bool makes_face = contents_differ && solidness_differs;
-
- if(makes_face == false)
- return 0;
-
- if(c1 == 0)
- c1 = f1.visual_solidness;
- if(c2 == 0)
- c2 = f2.visual_solidness;
-
- if(c1 == c2){
- *equivalent = true;
- // If same solidness, liquid takes precense
- if(f1.isLiquid())
- return 1;
- if(f2.isLiquid())
- return 2;
- }
-
- if(c1 > c2)
- return 1;
- else
- return 2;
-}
-#endif
-
-v3s16 facedir_rotate(u8 facedir, v3s16 dir)
-{
- /*
- Face 2 (normally Z-) direction:
- facedir=0: Z-
- facedir=1: X-
- facedir=2: Z+
- facedir=3: X+
- */
- v3s16 newdir;
- if(facedir==0) // Same
- newdir = v3s16(dir.X, dir.Y, dir.Z);
- else if(facedir == 1) // Face is taken from rotXZccv(-90)
- newdir = v3s16(-dir.Z, dir.Y, dir.X);
- else if(facedir == 2) // Face is taken from rotXZccv(180)
- newdir = v3s16(-dir.X, dir.Y, -dir.Z);
- else if(facedir == 3) // Face is taken from rotXZccv(90)
- newdir = v3s16(dir.Z, dir.Y, -dir.X);
- else
- newdir = dir;
- return newdir;
-}
-
-u8 packDir(v3s16 dir)
-{
- u8 b = 0;
-
- if(dir.X > 0)
- b |= (1<<0);
- else if(dir.X < 0)
- b |= (1<<1);
-
- if(dir.Y > 0)
- b |= (1<<2);
- else if(dir.Y < 0)
- b |= (1<<3);
-
- if(dir.Z > 0)
- b |= (1<<4);
- else if(dir.Z < 0)
- b |= (1<<5);
-
- return b;
-}
-v3s16 unpackDir(u8 b)
-{
- v3s16 d(0,0,0);
-
- if(b & (1<<0))
- d.X = 1;
- else if(b & (1<<1))
- d.X = -1;
-
- if(b & (1<<2))
- d.Y = 1;
- else if(b & (1<<3))
- d.Y = -1;
-
- if(b & (1<<4))
- d.Z = 1;
- else if(b & (1<<5))
- d.Z = -1;
-
- return d;
-}
-
/*
MapNode
*/
@@ -191,8 +66,9 @@ void MapNode::setLight(enum LightBank bank, u8 a_light, INodeDefManager *nodemgr
u8 MapNode::getLight(enum LightBank bank, INodeDefManager *nodemgr) const
{
// Select the brightest of [light source, propagated light]
+ const ContentFeatures &f = nodemgr->get(*this);
u8 light = 0;
- if(nodemgr->get(*this).param_type == CPT_LIGHT)
+ if(f.param_type == CPT_LIGHT)
{
if(bank == LIGHTBANK_DAY)
light = param1 & 0x0f;
@@ -201,38 +77,63 @@ u8 MapNode::getLight(enum LightBank bank, INodeDefManager *nodemgr) const
else
assert(0);
}
- if(nodemgr->get(*this).light_source > light)
- light = nodemgr->get(*this).light_source;
+ if(f.light_source > light)
+ light = f.light_source;
return light;
}
-u8 MapNode::getLightBanksWithSource(INodeDefManager *nodemgr) const
+bool MapNode::getLightBanks(u8 &lightday, u8 &lightnight, INodeDefManager *nodemgr) const
{
// Select the brightest of [light source, propagated light]
- u8 lightday = 0;
- u8 lightnight = 0;
- if(nodemgr->get(*this).param_type == CPT_LIGHT)
+ const ContentFeatures &f = nodemgr->get(*this);
+ if(f.param_type == CPT_LIGHT)
{
lightday = param1 & 0x0f;
lightnight = (param1>>4)&0x0f;
}
- if(nodemgr->get(*this).light_source > lightday)
- lightday = nodemgr->get(*this).light_source;
- if(nodemgr->get(*this).light_source > lightnight)
- lightnight = nodemgr->get(*this).light_source;
- return (lightday&0x0f) | ((lightnight<<4)&0xf0);
+ else
+ {
+ lightday = 0;
+ lightnight = 0;
+ }
+ if(f.light_source > lightday)
+ lightday = f.light_source;
+ if(f.light_source > lightnight)
+ lightnight = f.light_source;
+ return f.param_type == CPT_LIGHT || f.light_source != 0;
}
-u8 MapNode::getMineral(INodeDefManager *nodemgr) const
+u8 MapNode::getFaceDir(INodeDefManager *nodemgr) const
{
- if(nodemgr->get(*this).param_type == CPT_MINERAL)
+ const ContentFeatures &f = nodemgr->get(*this);
+ if(f.param_type_2 == CPT2_FACEDIR)
+ return getParam2() & 0x03;
+ return 0;
+}
+
+u8 MapNode::getWallMounted(INodeDefManager *nodemgr) const
+{
+ const ContentFeatures &f = nodemgr->get(*this);
+ if(f.param_type_2 == CPT2_WALLMOUNTED)
+ return getParam2() & 0x07;
+ return 0;
+}
+
+v3s16 MapNode::getWallMountedDir(INodeDefManager *nodemgr) const
+{
+ switch(getWallMounted(nodemgr))
{
- return param1 & 0x0f;
+ case 0: default: return v3s16(0,1,0);
+ case 1: return v3s16(0,-1,0);
+ case 2: return v3s16(1,0,0);
+ case 3: return v3s16(-1,0,0);
+ case 4: return v3s16(0,0,1);
+ case 5: return v3s16(0,0,-1);
}
-
- return MINERAL_NONE;
}
+
+
u32 MapNode::serializedLength(u8 version)
{
if(!ser_ver_supported(version))
@@ -249,7 +150,144 @@ void MapNode::serialize(u8 *dest, u8 version)
{
if(!ser_ver_supported(version))
throw VersionMismatchException("ERROR: MapNode format not supported");
+
+ if(version <= 21)
+ {
+ serialize_pre22(dest, version);
+ return;
+ }
+
+ writeU8(dest+0, param0);
+ writeU8(dest+1, param1);
+ writeU8(dest+2, param2);
+}
+void MapNode::deSerialize(u8 *source, u8 version)
+{
+ if(!ser_ver_supported(version))
+ throw VersionMismatchException("ERROR: MapNode format not supported");
+ if(version <= 21)
+ {
+ deSerialize_pre22(source, version);
+ return;
+ }
+
+ param0 = readU8(source+0);
+ param1 = readU8(source+1);
+ param2 = readU8(source+2);
+}
+void MapNode::serializeBulk(std::ostream &os, int version,
+ const MapNode *nodes, u32 nodecount,
+ u8 content_width, u8 params_width, bool compressed)
+{
+ if(!ser_ver_supported(version))
+ throw VersionMismatchException("ERROR: MapNode format not supported");
+
+ assert(version >= 22);
+ assert(content_width == 1);
+ assert(params_width == 2);
+
+ SharedBuffer<u8> databuf(nodecount * (content_width + params_width));
+
+ // Serialize content
+ if(content_width == 1)
+ {
+ for(u32 i=0; i<nodecount; i++)
+ writeU8(&databuf[i], nodes[i].param0);
+ }
+ /* If param0 is extended to two bytes, use something like this: */
+ /*else if(content_width == 2)
+ {
+ for(u32 i=0; i<nodecount; i++)
+ writeU16(&databuf[i*2], nodes[i].param0);
+ }*/
+
+ // Serialize param1
+ u32 start1 = content_width * nodecount;
+ for(u32 i=0; i<nodecount; i++)
+ writeU8(&databuf[start1 + i], nodes[i].param1);
+
+ // Serialize param2
+ u32 start2 = (content_width + 1) * nodecount;
+ for(u32 i=0; i<nodecount; i++)
+ writeU8(&databuf[start2 + i], nodes[i].param2);
+
+ /*
+ Compress data to output stream
+ */
+
+ if(compressed)
+ {
+ compressZlib(databuf, os);
+ }
+ else
+ {
+ os.write((const char*) &databuf[0], databuf.getSize());
+ }
+}
+
+// Deserialize bulk node data
+void MapNode::deSerializeBulk(std::istream &is, int version,
+ MapNode *nodes, u32 nodecount,
+ u8 content_width, u8 params_width, bool compressed)
+{
+ if(!ser_ver_supported(version))
+ throw VersionMismatchException("ERROR: MapNode format not supported");
+
+ assert(version >= 22);
+ assert(content_width == 1);
+ assert(params_width == 2);
+
+ // Uncompress or read data
+ u32 len = nodecount * (content_width + params_width);
+ SharedBuffer<u8> databuf(len);
+ if(compressed)
+ {
+ std::ostringstream os(std::ios_base::binary);
+ decompressZlib(is, os);
+ std::string s = os.str();
+ if(s.size() != len)
+ throw SerializationError("deSerializeBulkNodes: "
+ "decompress resulted in invalid size");
+ memcpy(&databuf[0], s.c_str(), len);
+ }
+ else
+ {
+ is.read((char*) &databuf[0], len);
+ if(is.eof() || is.fail())
+ throw SerializationError("deSerializeBulkNodes: "
+ "failed to read bulk node data");
+ }
+
+ // Deserialize content
+ if(content_width == 1)
+ {
+ for(u32 i=0; i<nodecount; i++)
+ nodes[i].param0 = readU8(&databuf[i]);
+ }
+ /* If param0 is extended to two bytes, use something like this: */
+ /*else if(content_width == 2)
+ {
+ for(u32 i=0; i<nodecount; i++)
+ nodes[i].param0 = readU16(&databuf[i*2]);
+ }*/
+
+ // Deserialize param1
+ u32 start1 = content_width * nodecount;
+ for(u32 i=0; i<nodecount; i++)
+ nodes[i].param1 = readU8(&databuf[start1 + i]);
+
+ // Deserialize param2
+ u32 start2 = (content_width + 1) * nodecount;
+ for(u32 i=0; i<nodecount; i++)
+ nodes[i].param2 = readU8(&databuf[start2 + i]);
+}
+
+/*
+ Legacy serialization
+*/
+void MapNode::serialize_pre22(u8 *dest, u8 version)
+{
// Translate to wanted version
MapNode n_foreign = mapnode_translate_from_internal(*this, version);
@@ -282,16 +320,9 @@ void MapNode::serialize(u8 *dest, u8 version)
dest[2] = n_foreign.param2;
}
}
-void MapNode::deSerialize(u8 *source, u8 version)
+void MapNode::deSerialize_pre22(u8 *source, u8 version)
{
- if(!ser_ver_supported(version))
- throw VersionMismatchException("ERROR: MapNode format not supported");
-
- if(version == 0)
- {
- param0 = source[0];
- }
- else if(version == 1)
+ if(version <= 1)
{
param0 = source[0];
}
@@ -308,18 +339,11 @@ void MapNode::deSerialize(u8 *source, u8 version)
}
// Convert special values from old version to new
- if(version <= 18)
+ if(version <= 19)
{
// In these versions, CONTENT_IGNORE and CONTENT_AIR
// are 255 and 254
- if(param0 == 255)
- param0 = CONTENT_IGNORE;
- else if(param0 == 254)
- param0 = CONTENT_AIR;
- }
- // version 19 is fucked up with sometimes the old values and sometimes not
- if(version == 19)
- {
+ // Version 19 is fucked up with sometimes the old values and sometimes not
if(param0 == 255)
param0 = CONTENT_IGNORE;
else if(param0 == 254)
@@ -330,6 +354,65 @@ void MapNode::deSerialize(u8 *source, u8 version)
*this = mapnode_translate_to_internal(*this, version);
}
+
+#ifndef SERVER
+
+/*
+ Nodes make a face if contents differ and solidness differs.
+ Return value:
+ 0: No face
+ 1: Face uses m1's content
+ 2: Face uses m2's content
+ equivalent: Whether the blocks share the same face (eg. water and glass)
+
+ TODO: Add 3: Both faces drawn with backface culling, remove equivalent
+*/
+u8 face_contents(content_t m1, content_t m2, bool *equivalent,
+ INodeDefManager *nodemgr)
+{
+ *equivalent = false;
+
+ if(m1 == CONTENT_IGNORE || m2 == CONTENT_IGNORE)
+ return 0;
+
+ bool contents_differ = (m1 != m2);
+
+ const ContentFeatures &f1 = nodemgr->get(m1);
+ const ContentFeatures &f2 = nodemgr->get(m2);
+
+ // Contents don't differ for different forms of same liquid
+ if(f1.sameLiquid(f2))
+ contents_differ = false;
+
+ u8 c1 = f1.solidness;
+ u8 c2 = f2.solidness;
+
+ bool solidness_differs = (c1 != c2);
+ bool makes_face = contents_differ && solidness_differs;
+
+ if(makes_face == false)
+ return 0;
+
+ if(c1 == 0)
+ c1 = f1.visual_solidness;
+ if(c2 == 0)
+ c2 = f2.visual_solidness;
+
+ if(c1 == c2){
+ *equivalent = true;
+ // If same solidness, liquid takes precense
+ if(f1.isLiquid())
+ return 1;
+ if(f2.isLiquid())
+ return 2;
+ }
+
+ if(c1 > c2)
+ return 1;
+ else
+ return 2;
+}
+
/*
Gets lighting value at face of node
@@ -380,4 +463,5 @@ u8 getFaceLight(u32 daynight_ratio, MapNode n, MapNode n2,
}
}
+#endif
diff --git a/src/mapnode.h b/src/mapnode.h
index 65fc3b3e2..5e066604b 100644
--- a/src/mapnode.h
+++ b/src/mapnode.h
@@ -32,8 +32,8 @@ class INodeDefManager;
- Tile = TileSpec at some side of a node of some content type
Content ranges:
- 0x000...0x07f: param2 is fully usable
- 0x800...0xfff: param2 lower 4 bytes are free
+ 0x000...0x07f: param2 is fully usable
+ 0x800...0xfff: param2 lower 4 bits are free
*/
typedef u16 content_t;
#define MAX_CONTENT 0xfff
@@ -56,36 +56,6 @@ typedef u16 content_t;
*/
#define CONTENT_AIR 126
-#ifndef SERVER
-/*
- Nodes make a face if contents differ and solidness differs.
- Return value:
- 0: No face
- 1: Face uses m1's content
- 2: Face uses m2's content
- equivalent: Whether the blocks share the same face (eg. water and glass)
-*/
-u8 face_contents(content_t m1, content_t m2, bool *equivalent,
- INodeDefManager *nodemgr);
-#endif
-
-/*
- Packs directions like (1,0,0), (1,-1,0) in six bits.
- NOTE: This wastes way too much space for most purposes.
-*/
-u8 packDir(v3s16 dir);
-v3s16 unpackDir(u8 b);
-
-/*
- facedir: CPT_FACEDIR_SIMPLE param1 value
- dir: The face for which stuff is wanted
- return value: The face from which the stuff is actually found
-
- NOTE: Currently this uses 2 bits for Z-,X-,Z+,X+, should there be Y+
- and Y- too?
-*/
-v3s16 facedir_rotate(u8 facedir, v3s16 dir);
-
enum LightBank
{
LIGHTBANK_DAY,
@@ -122,7 +92,6 @@ struct MapNode
stored logarithmically from 0 to LIGHT_MAX.
Sunlight is LIGHT_SUN, which is LIGHT_MAX+1.
- Contains 2 values, day- and night lighting. Each takes 4 bits.
- - Mineral content (should be removed from here)
- Uhh... well, most blocks have light or nothing in here.
*/
u8 param1;
@@ -210,40 +179,22 @@ struct MapNode
void setLight(enum LightBank bank, u8 a_light, INodeDefManager *nodemgr);
u8 getLight(enum LightBank bank, INodeDefManager *nodemgr) const;
- u8 getLightBanksWithSource(INodeDefManager *nodemgr) const;
+ bool getLightBanks(u8 &lightday, u8 &lightnight, INodeDefManager *nodemgr) const;
// 0 <= daylight_factor <= 1000
// 0 <= return value <= LIGHT_SUN
u8 getLightBlend(u32 daylight_factor, INodeDefManager *nodemgr) const
{
- u8 l = ((daylight_factor * getLight(LIGHTBANK_DAY, nodemgr)
- + (1000-daylight_factor) * getLight(LIGHTBANK_NIGHT, nodemgr))
- )/1000;
- u8 max = LIGHT_MAX;
- if(getLight(LIGHTBANK_DAY, nodemgr) == LIGHT_SUN)
- max = LIGHT_SUN;
- if(l > max)
- l = max;
- return l;
+ u8 lightday = 0;
+ u8 lightnight = 0;
+ getLightBanks(lightday, lightnight, nodemgr);
+ return blend_light(daylight_factor, lightday, lightnight);
}
- /*// 0 <= daylight_factor <= 1000
- // 0 <= return value <= 255
- u8 getLightBlend(u32 daylight_factor, INodeDefManager *nodemgr)
- {
- u8 daylight = decode_light(getLight(LIGHTBANK_DAY, nodemgr));
- u8 nightlight = decode_light(getLight(LIGHTBANK_NIGHT, nodemgr));
- u8 mix = ((daylight_factor * daylight
- + (1000-daylight_factor) * nightlight)
- )/1000;
- return mix;
- }*/
- /*
- Gets mineral content of node, if there is any.
- MINERAL_NONE if doesn't contain or isn't able to contain mineral.
- */
- u8 getMineral(INodeDefManager *nodemgr) const;
-
+ u8 getFaceDir(INodeDefManager *nodemgr) const;
+ u8 getWallMounted(INodeDefManager *nodemgr) const;
+ v3s16 getWallMountedDir(INodeDefManager *nodemgr) const;
+
/*
Serialization functions
*/
@@ -252,8 +203,44 @@ struct MapNode
void serialize(u8 *dest, u8 version);
void deSerialize(u8 *source, u8 version);
+ // Serializes or deserializes a list of nodes in bulk format (first the
+ // content of all nodes, then the param1 of all nodes, then the param2
+ // of all nodes).
+ // version = serialization version. Must be >= 22
+ // content_width = the number of bytes of content per node
+ // params_width = the number of bytes of params per node
+ // compressed = true to zlib-compress output
+ static void serializeBulk(std::ostream &os, int version,
+ const MapNode *nodes, u32 nodecount,
+ u8 content_width, u8 params_width, bool compressed);
+ static void deSerializeBulk(std::istream &is, int version,
+ MapNode *nodes, u32 nodecount,
+ u8 content_width, u8 params_width, bool compressed);
+
+private:
+ // Deprecated serialization methods
+ void serialize_pre22(u8 *dest, u8 version);
+ void deSerialize_pre22(u8 *source, u8 version);
};
+
+/*
+ MapNode helpers for mesh making stuff
+*/
+
+#ifndef SERVER
+
+/*
+ Nodes make a face if contents differ and solidness differs.
+ Return value:
+ 0: No face
+ 1: Face uses m1's content
+ 2: Face uses m2's content
+ equivalent: Whether the blocks share the same face (eg. water and glass)
+*/
+u8 face_contents(content_t m1, content_t m2, bool *equivalent,
+ INodeDefManager *nodemgr);
+
/*
Gets lighting value at face of node
@@ -275,3 +262,6 @@ u8 getFaceLight(u32 daynight_ratio, MapNode n, MapNode n2,
#endif
+
+#endif
+
diff --git a/src/materials.cpp b/src/materials.cpp
index d2d37ebf4..c37b7c505 100644
--- a/src/materials.cpp
+++ b/src/materials.cpp
@@ -18,9 +18,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
*/
#include "materials.h"
-#include "mapnode.h"
-#include "nodedef.h"
-#include "tooldef.h"
#include "utility.h"
void MaterialProperties::serialize(std::ostream &os)
@@ -49,6 +46,56 @@ void MaterialProperties::deSerialize(std::istream &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,
const ToolDiggingProperties *tp, float time_from_last_punch)
{
@@ -90,13 +137,6 @@ DiggingProperties getDiggingProperties(const MaterialProperties *mp,
return getDiggingProperties(mp, tp, 1000000);
}
-DiggingProperties getDiggingProperties(u16 content,
- const ToolDiggingProperties *tp, INodeDefManager *nodemgr)
-{
- const MaterialProperties &mp = nodemgr->get(content).material;
- return getDiggingProperties(&mp, tp);
-}
-
HittingProperties getHittingProperties(const MaterialProperties *mp,
const ToolDiggingProperties *tp, float time_from_last_punch)
{
@@ -111,3 +151,9 @@ HittingProperties getHittingProperties(const MaterialProperties *mp,
return HittingProperties(hp, wear);
}
+HittingProperties getHittingProperties(const MaterialProperties *mp,
+ const ToolDiggingProperties *tp)
+{
+ return getHittingProperties(mp, tp, 1000000);
+}
+
diff --git a/src/materials.h b/src/materials.h
index b25d047be..058b2ab85 100644
--- a/src/materials.h
+++ b/src/materials.h
@@ -72,6 +72,29 @@ struct MaterialProperties
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
{
bool diggable;
@@ -87,18 +110,12 @@ struct DiggingProperties
{}
};
-struct ToolDiggingProperties;
-class INodeDefManager;
-
DiggingProperties getDiggingProperties(const MaterialProperties *mp,
const ToolDiggingProperties *tp, float time_from_last_punch);
DiggingProperties getDiggingProperties(const MaterialProperties *mp,
const ToolDiggingProperties *tp);
-DiggingProperties getDiggingProperties(u16 content,
- const ToolDiggingProperties *tp, INodeDefManager *nodemgr);
-
struct HittingProperties
{
s16 hp;
@@ -113,5 +130,8 @@ struct HittingProperties
HittingProperties getHittingProperties(const MaterialProperties *mp,
const ToolDiggingProperties *tp, float time_from_last_punch);
+HittingProperties getHittingProperties(const MaterialProperties *mp,
+ const ToolDiggingProperties *tp);
+
#endif
diff --git a/src/mesh.cpp b/src/mesh.cpp
index c0b1419d4..44b3b9bbb 100644
--- a/src/mesh.cpp
+++ b/src/mesh.cpp
@@ -18,8 +18,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
*/
#include "mesh.h"
+#include "log.h"
+#include <cassert>
+#include <iostream>
#include <IAnimatedMesh.h>
#include <SAnimatedMesh.h>
+#include <ICameraSceneNode.h>
// In Irrlicht 1.8 the signature of ITexture::lock was changed from
// (bool, u32) to (E_TEXTURE_LOCK_MODE, u32).
@@ -73,9 +77,15 @@ scene::IAnimatedMesh* createCubeMesh(v3f scale)
{
scene::IMeshBuffer *buf = new scene::SMeshBuffer();
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);
buf->drop();
}
+
scene::SAnimatedMesh *anim_mesh = new scene::SAnimatedMesh(mesh);
mesh->drop();
scaleMesh(anim_mesh, scale); // also recalculates bounding box
@@ -379,6 +389,13 @@ scene::IAnimatedMesh* createExtrudedMesh(video::ITexture *texture,
}
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
return mesh;
}
@@ -412,6 +429,35 @@ void scaleMesh(scene::IMesh *mesh, v3f scale)
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)
{
if(mesh == NULL)
@@ -459,3 +505,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;
+}
diff --git a/src/mesh.h b/src/mesh.h
index b22ccc318..631dc0cca 100644
--- a/src/mesh.h
+++ b/src/mesh.h
@@ -21,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define MESH_HEADER
#include "common_irrlicht.h"
+#include <string>
/*
Create a new cube mesh.
@@ -67,6 +68,11 @@ scene::IAnimatedMesh* createPlantMesh(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
*/
void setMeshColor(scene::IMesh *mesh, const video::SColor &color);
@@ -82,4 +88,20 @@ void setMeshColorByNormalXYZ(scene::IMesh *mesh,
const video::SColor &colorY,
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
diff --git a/src/mineral.cpp b/src/mineral.cpp
deleted file mode 100644
index 038251fa3..000000000
--- a/src/mineral.cpp
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
-Minetest-c55
-Copyright (C) 2010 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 "mineral.h"
-
-
-const char *mineral_filenames[MINERAL_COUNT] =
-{
- NULL,
- "mineral_coal.png",
- "mineral_iron.png"
-};
-
-std::string mineral_textures[MINERAL_COUNT];
-
-void init_mineral()
-{
- for(u32 i=0; i<MINERAL_COUNT; i++)
- {
- if(mineral_filenames[i] == NULL)
- continue;
- mineral_textures[i] = mineral_filenames[i];
- }
-}
-
-std::string mineral_block_texture(u8 mineral)
-{
- if(mineral >= MINERAL_COUNT)
- return "";
-
- return mineral_textures[mineral];
-}
-
-
-
diff --git a/src/mineral.h b/src/mineral.h
deleted file mode 100644
index 4949fe07e..000000000
--- a/src/mineral.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
-Minetest-c55
-Copyright (C) 2010 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 MINERAL_HEADER
-#define MINERAL_HEADER
-
-#include "inventory.h"
-
-/*
- Minerals
-
- Value is stored in the lowest 5 bits of a MapNode's CPT_MINERAL
- type param.
-*/
-
-// Caches textures
-void init_mineral();
-
-#define MINERAL_NONE 0
-#define MINERAL_COAL 1
-#define MINERAL_IRON 2
-
-#define MINERAL_COUNT 3
-
-std::string mineral_block_texture(u8 mineral);
-
-class IGameDef;
-
-inline CraftItem * 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
-
diff --git a/src/nameidmapping.h b/src/nameidmapping.h
index 071599e10..238deb451 100644
--- a/src/nameidmapping.h
+++ b/src/nameidmapping.h
@@ -70,6 +70,9 @@ public:
result = i->second;
return true;
}
+ u16 size() const{
+ return m_id_to_name.size();
+ }
private:
std::map<u16, std::string> m_id_to_name;
std::map<std::string, u16> m_name_to_id;
diff --git a/src/nodedef.cpp b/src/nodedef.cpp
index d7769700b..0c2793a0e 100644
--- a/src/nodedef.cpp
+++ b/src/nodedef.cpp
@@ -20,7 +20,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "nodedef.h"
#include "main.h" // For g_settings
-#include "nodemetadata.h"
+#include "itemdef.h"
#ifndef SERVER
#include "tile.h"
#endif
@@ -103,8 +103,6 @@ void ContentFeatures::reset()
Cached stuff
*/
#ifndef SERVER
- inventory_texture = NULL;
-
for(u16 j=0; j<CF_SPECIAL_COUNT; j++){
special_materials[j] = NULL;
special_aps[j] = NULL;
@@ -113,7 +111,6 @@ void ContentFeatures::reset()
visual_solidness = 0;
backface_culling = true;
#endif
- used_texturenames.clear();
/*
Actual data
@@ -127,10 +124,10 @@ void ContentFeatures::reset()
tname_tiles[i] = "";
for(u16 j=0; j<CF_SPECIAL_COUNT; j++)
mspec_special[j] = MaterialSpec();
- tname_inventory = "";
alpha = 255;
post_effect_color = video::SColor(0, 0, 0, 0);
param_type = CPT_NONE;
+ param_type_2 = CPT2_NONE;
is_ground_content = false;
light_propagates = false;
sunlight_propagates = false;
@@ -139,11 +136,6 @@ void ContentFeatures::reset()
diggable = true;
climbable = false;
buildable_to = false;
- wall_mounted = false;
- often_contains_mineral = false;
- dug_item = "";
- extra_dug_item = "";
- extra_dug_item_rarity = 2;
metadata_name = "";
liquid_type = LIQUID_NONE;
liquid_alternative_flowing = "";
@@ -153,21 +145,22 @@ void ContentFeatures::reset()
damage_per_second = 0;
selection_box = NodeBox();
material = MaterialProperties();
- cookresult_item = ""; // Cannot be cooked
- furnace_cooktime = 3.0;
- furnace_burntime = -1.0; // Cannot be burned
+ // Make unknown blocks diggable
+ material.diggability = DIGGABLE_CONSTANT;
+ material.constant_time = 0.5;
+ legacy_facedir_simple = false;
+ legacy_wallmounted = false;
}
void ContentFeatures::serialize(std::ostream &os)
{
- writeU8(os, 0); // version
+ writeU8(os, 1); // version
os<<serializeString(name);
writeU8(os, drawtype);
writeF1000(os, visual_scale);
writeU8(os, 6);
for(u32 i=0; i<6; i++)
os<<serializeString(tname_tiles[i]);
- os<<serializeString(tname_inventory);
writeU8(os, CF_SPECIAL_COUNT);
for(u32 i=0; i<CF_SPECIAL_COUNT; i++){
mspec_special[i].serialize(os);
@@ -178,6 +171,7 @@ void ContentFeatures::serialize(std::ostream &os)
writeU8(os, post_effect_color.getGreen());
writeU8(os, post_effect_color.getBlue());
writeU8(os, param_type);
+ writeU8(os, param_type_2);
writeU8(os, is_ground_content);
writeU8(os, light_propagates);
writeU8(os, sunlight_propagates);
@@ -186,11 +180,6 @@ void ContentFeatures::serialize(std::ostream &os)
writeU8(os, diggable);
writeU8(os, climbable);
writeU8(os, buildable_to);
- writeU8(os, wall_mounted);
- writeU8(os, often_contains_mineral);
- os<<serializeString(dug_item);
- os<<serializeString(extra_dug_item);
- writeS32(os, extra_dug_item_rarity);
os<<serializeString(metadata_name);
writeU8(os, liquid_type);
os<<serializeString(liquid_alternative_flowing);
@@ -200,15 +189,14 @@ void ContentFeatures::serialize(std::ostream &os)
writeU32(os, damage_per_second);
selection_box.serialize(os);
material.serialize(os);
- os<<serializeString(cookresult_item);
- writeF1000(os, furnace_cooktime);
- writeF1000(os, furnace_burntime);
+ writeU8(os, legacy_facedir_simple);
+ writeU8(os, legacy_wallmounted);
}
-void ContentFeatures::deSerialize(std::istream &is, IGameDef *gamedef)
+void ContentFeatures::deSerialize(std::istream &is)
{
int version = readU8(is);
- if(version != 0)
+ if(version != 1)
throw SerializationError("unsupported ContentFeatures version");
name = deSerializeString(is);
drawtype = (enum NodeDrawType)readU8(is);
@@ -216,9 +204,7 @@ void ContentFeatures::deSerialize(std::istream &is, IGameDef *gamedef)
if(readU8(is) != 6)
throw SerializationError("unsupported tile count");
for(u32 i=0; i<6; i++)
- setTexture(i, deSerializeString(is));
- //tname_tiles[i] = deSerializeString(is);
- tname_inventory = deSerializeString(is);
+ tname_tiles[i] = deSerializeString(is);
if(readU8(is) != CF_SPECIAL_COUNT)
throw SerializationError("unsupported CF_SPECIAL_COUNT");
for(u32 i=0; i<CF_SPECIAL_COUNT; i++){
@@ -230,6 +216,7 @@ void ContentFeatures::deSerialize(std::istream &is, IGameDef *gamedef)
post_effect_color.setGreen(readU8(is));
post_effect_color.setBlue(readU8(is));
param_type = (enum ContentParamType)readU8(is);
+ param_type_2 = (enum ContentParamType2)readU8(is);
is_ground_content = readU8(is);
light_propagates = readU8(is);
sunlight_propagates = readU8(is);
@@ -238,11 +225,6 @@ void ContentFeatures::deSerialize(std::istream &is, IGameDef *gamedef)
diggable = readU8(is);
climbable = readU8(is);
buildable_to = readU8(is);
- wall_mounted = readU8(is);
- often_contains_mineral = readU8(is);
- dug_item = deSerializeString(is);
- extra_dug_item = deSerializeString(is);
- extra_dug_item_rarity = readS32(is);
metadata_name = deSerializeString(is);
liquid_type = (enum LiquidType)readU8(is);
liquid_alternative_flowing = deSerializeString(is);
@@ -252,53 +234,8 @@ void ContentFeatures::deSerialize(std::istream &is, IGameDef *gamedef)
damage_per_second = readU32(is);
selection_box.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;
+ legacy_facedir_simple = readU8(is);
+ legacy_wallmounted = readU8(is);
}
/*
@@ -311,14 +248,12 @@ public:
void clear()
{
m_name_id_mapping.clear();
+ m_name_id_mapping_with_aliases.clear();
- m_aliases.clear();
-
for(u16 i=0; i<=MAX_CONTENT; i++)
{
ContentFeatures &f = m_content_features[i];
f.reset(); // Reset to defaults
- f.setAllTextures("unknown_block.png");
}
// Set CONTENT_AIR
@@ -336,7 +271,7 @@ public:
// Insert directly into containers
content_t c = CONTENT_AIR;
m_content_features[c] = f;
- m_name_id_mapping.set(c, f.name);
+ addNameIdMapping(c, f.name);
}
// Set CONTENT_IGNORE
{
@@ -354,13 +289,13 @@ public:
// Insert directly into containers
content_t c = CONTENT_IGNORE;
m_content_features[c] = f;
- m_name_id_mapping.set(c, f.name);
+ addNameIdMapping(c, f.name);
}
}
// CONTENT_IGNORE = not found
content_t getFreeId(bool require_full_param2)
{
- // If allowed, first search in the large 4-byte-param2 pool
+ // If allowed, first search in the large 4-bit-param2 pool
if(!require_full_param2){
for(u16 i=0x800; i<=0xfff; i++){
const ContentFeatures &f = m_content_features[i];
@@ -368,7 +303,7 @@ public:
return i;
}
}
- // Then search from the small 8-byte-param2 pool
+ // Then search from the small 8-bit-param2 pool
for(u16 i=0; i<=125; i++){
const ContentFeatures &f = m_content_features[i];
if(f.name == "")
@@ -401,12 +336,14 @@ public:
{
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::string name = getAlias(name_);
- // Get id
- return m_name_id_mapping.getId(name, result);
+ std::map<std::string, content_t>::const_iterator
+ i = m_name_id_mapping_with_aliases.find(name);
+ if(i == m_name_id_mapping_with_aliases.end())
+ return false;
+ result = i->second;
+ return true;
}
virtual content_t getId(const std::string &name) const
{
@@ -420,14 +357,6 @@ public:
getId(name, 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
virtual void set(content_t c, const ContentFeatures &def)
{
@@ -451,37 +380,29 @@ public:
}
m_content_features[c] = def;
if(def.name != "")
- m_name_id_mapping.set(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;
+ addNameIdMapping(c, def.name);
}
virtual content_t set(const std::string &name,
const ContentFeatures &def)
{
assert(name == def.name);
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){
// Determine if full param2 is required
bool require_full_param2 = (
- def.liquid_type == LIQUID_FLOWING
+ def.param_type_2 == CPT2_FULL
||
- def.drawtype == NDT_FLOWINGLIQUID
+ def.param_type_2 == CPT2_FLOWINGLIQUID
||
- def.drawtype == NDT_TORCHLIKE
- ||
- def.drawtype == NDT_SIGNLIKE
+ def.legacy_wallmounted
);
// Get some id
id = getFreeId(require_full_param2);
if(id == CONTENT_IGNORE)
return CONTENT_IGNORE;
if(name != "")
- m_name_id_mapping.set(id, name);
+ addNameIdMapping(id, name);
}
set(id, def);
return id;
@@ -491,23 +412,27 @@ public:
assert(name != "");
ContentFeatures f;
f.name = name;
- f.setAllTextures("unknown_block.png");
// Make unknown blocks diggable
- f.material.diggability = DIGGABLE_NORMAL;
+ f.material.diggability = DIGGABLE_CONSTANT;
+ f.material.constant_time = 0.5;
return set(name, f);
}
- virtual void setAlias(const std::string &name,
- const std::string &convert_to)
+ virtual void updateAliases(IItemDefManager *idef)
{
- content_t id;
- if(getId(name, id)){
- infostream<<"ndef: not setting alias "<<name<<" -> "<<convert_to
- <<": "<<name<<" is already defined"<<std::endl;
- return;
+ std::set<std::string> all = idef->getAll();
+ m_name_id_mapping_with_aliases.clear();
+ for(std::set<std::string>::iterator
+ i = all.begin(); i != all.end(); i++)
+ {
+ 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)
{
@@ -523,6 +448,14 @@ public:
{
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){
default:
case NDT_NORMAL:
@@ -567,8 +500,7 @@ public:
f->drawtype = NDT_NORMAL;
f->solidness = 2;
for(u32 i=0; i<6; i++){
- f->setTexture(i, f->tname_tiles[i]
- + std::string("^[noalpha"));
+ tname_tiles[i] += std::string("^[noalpha");
}
}
break;
@@ -581,16 +513,9 @@ public:
break;
}
- // Inventory texture
- if(f->tname_inventory != "")
- f->inventory_texture = tsrc->getTextureRaw(f->tname_inventory);
- else
- f->inventory_texture = NULL;
// Tile textures
for(u16 j=0; j<6; j++){
- if(f->tname_tiles[j] == "")
- continue;
- f->tiles[j].texture = tsrc->getTexture(f->tname_tiles[j]);
+ f->tiles[j].texture = tsrc->getTexture(tname_tiles[j]);
f->tiles[j].alpha = f->alpha;
if(f->alpha == 255)
f->tiles[j].material_type = MATERIAL_ALPHA_SIMPLE;
@@ -649,16 +574,8 @@ public:
}
writeU16(os, count);
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();
u16 count = readU16(is);
@@ -674,27 +591,26 @@ public:
if(i == CONTENT_IGNORE || i == CONTENT_AIR)
continue;*/
ContentFeatures *f = &m_content_features[i];
- f->deSerialize(tmp_is, gamedef);
+ f->deSerialize(tmp_is);
if(f->name != "")
- m_name_id_mapping.set(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;
- }
+ addNameIdMapping(i, f->name);
}
}
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:
// Features indexed by id
ContentFeatures m_content_features[MAX_CONTENT+1];
// A mapping for fast converting back and forth between names and ids
NameIdMapping m_name_id_mapping;
- // Aliases
- std::map<std::string, std::string> m_aliases;
+ // Like m_name_id_mapping, but only from names to ids, and includes
+ // item aliases too. Updated by updateAliases()
+ // Note: Not serialized.
+ std::map<std::string, content_t> m_name_id_mapping_with_aliases;
};
IWritableNodeDefManager* createNodeDefManager()
diff --git a/src/nodedef.h b/src/nodedef.h
index fdf2f8c45..9524385cf 100644
--- a/src/nodedef.h
+++ b/src/nodedef.h
@@ -29,6 +29,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "tile.h"
#endif
#include "materials.h" // MaterialProperties
+class IItemDefManager;
class ITextureSource;
class IGameDef;
@@ -36,9 +37,19 @@ enum ContentParamType
{
CPT_NONE,
CPT_LIGHT,
- CPT_MINERAL,
+};
+
+enum ContentParamType2
+{
+ CPT2_NONE,
+ // Need 8-bit param2
+ CPT2_FULL,
+ // Flowing liquid properties
+ CPT2_FLOWINGLIQUID,
// Direction for chests and furnaces and such
- CPT_FACEDIR_SIMPLE
+ CPT2_FACEDIR,
+ // Direction for signs, torches and such
+ CPT2_WALLMOUNTED,
};
enum LiquidType
@@ -52,7 +63,7 @@ enum NodeBoxType
{
NODEBOX_REGULAR, // Regular block; allows buildable_to
NODEBOX_FIXED, // Static separately defined box
- NODEBOX_WALLMOUNTED, // Box for wall_mounted nodes; (top, bottom, side)
+ NODEBOX_WALLMOUNTED, // Box for wall mounted nodes; (top, bottom, side)
};
struct NodeBox
@@ -124,7 +135,6 @@ struct ContentFeatures
// 0 1 2 3 4 5
// up down right left back front
TileSpec tiles[6];
- video::ITexture *inventory_texture;
// Special material/texture
// - Currently used for flowing liquids
video::SMaterial *special_materials[CF_SPECIAL_COUNT];
@@ -133,11 +143,7 @@ struct ContentFeatures
u8 visual_solidness; // When solidness=0, this tells how it looks like
bool backface_culling;
#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
*/
@@ -148,7 +154,6 @@ struct ContentFeatures
enum NodeDrawType drawtype;
float visual_scale; // Misc. scale parameter
std::string tname_tiles[6];
- std::string tname_inventory;
MaterialSpec mspec_special[CF_SPECIAL_COUNT]; // Use setter methods
u8 alpha;
@@ -156,6 +161,8 @@ struct ContentFeatures
video::SColor post_effect_color;
// Type of MapNode::param1
ContentParamType param_type;
+ // Type of MapNode::param2
+ ContentParamType2 param_type_2;
// True for all ground-like things like stone and mud, false for eg. trees
bool is_ground_content;
bool light_propagates;
@@ -171,20 +178,6 @@ struct ContentFeatures
bool climbable;
// Player can build on these
bool buildable_to;
- // If true, param2 is set to direction when placed. Used for torches.
- // NOTE: the direction format is quite inefficient and should be changed
- 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.
- // Mineral overrides this.
- std::string dug_item;
- // Extra dug item and its rarity
- std::string extra_dug_item;
- // Usual get interval for extra dug item
- s32 extra_dug_item_rarity;
// Metadata name of node (eg. "furnace")
std::string metadata_name;
// Whether the node is non-liquid, source liquid or flowing liquid
@@ -202,9 +195,11 @@ struct ContentFeatures
u32 damage_per_second;
NodeBox selection_box;
MaterialProperties material;
- std::string cookresult_item;
- float furnace_cooktime;
- float furnace_burntime;
+ // Compatibility with old maps
+ // Set to true if paramtype used to be 'facedir_simple'
+ bool legacy_facedir_simple;
+ // Set to true if wall_mounted used to be set to true
+ bool legacy_wallmounted;
/*
Methods
@@ -214,23 +209,9 @@ struct ContentFeatures
~ContentFeatures();
void reset();
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
*/
bool isLiquid() const{
@@ -253,7 +234,6 @@ public:
virtual bool getId(const std::string &name, content_t &result) const=0;
virtual content_t getId(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;
};
@@ -271,8 +251,7 @@ public:
virtual content_t getId(const std::string &name) const=0;
// If not found, returns the features of CONTENT_IGNORE
virtual const ContentFeatures& get(const std::string &name) const=0;
- virtual std::string getAlias(const std::string &name) const =0;
-
+
// Register node definition
virtual void set(content_t c, const ContentFeatures &def)=0;
// Register node definition by name (allocate an id)
@@ -281,11 +260,12 @@ public:
const ContentFeatures &def)=0;
// If returns CONTENT_IGNORE, could not allocate id
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.
- virtual void setAlias(const std::string &name,
- const std::string &convert_to)=0;
+
+ /*
+ Update item alias mapping.
+ Call after updating item definitions.
+ */
+ virtual void updateAliases(IItemDefManager *idef)=0;
/*
Update tile textures to latest return values of TextueSource.
@@ -294,7 +274,7 @@ public:
virtual void updateTextures(ITextureSource *tsrc)=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();
diff --git a/src/player.cpp b/src/player.cpp
index 963f67c28..6506c43c3 100644
--- a/src/player.cpp
+++ b/src/player.cpp
@@ -28,6 +28,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "main.h" // For g_settings
#include "settings.h"
#include "nodedef.h"
+#include "collision.h"
#include "environment.h"
#include "gamedef.h"
@@ -37,13 +38,12 @@ Player::Player(IGameDef *gamedef):
in_water_stable(false),
is_climbing(false),
swimming_up(false),
+ inventory(gamedef->idef()),
inventory_backup(NULL),
- craftresult_is_preview(true),
hp(20),
peer_id(PEER_ID_INEXISTENT),
// protected
m_gamedef(gamedef),
- m_selected_item(0),
m_pitch(0),
m_yaw(0),
m_speed(0,0,0),
@@ -58,16 +58,12 @@ Player::~Player()
delete inventory_backup;
}
-void Player::wieldItem(u16 item)
-{
- m_selected_item = item;
-}
-
void Player::resetInventory()
{
inventory.clear();
inventory.addList("main", PLAYER_INVENTORY_SIZE);
inventory.addList("craft", 9);
+ inventory.addList("craftpreview", 1);
inventory.addList("craftresult", 1);
}
@@ -123,7 +119,6 @@ void Player::serialize(std::ostream &os)
args.setFloat("pitch", m_pitch);
args.setFloat("yaw", m_yaw);
args.setV3F("position", m_position);
- args.setBool("craftresult_is_preview", craftresult_is_preview);
args.setS32("hp", hp);
args.writeLines(os);
@@ -162,17 +157,27 @@ void Player::deSerialize(std::istream &is)
setYaw(args.getFloat("yaw"));
setPosition(args.getV3F("position"));
try{
- craftresult_is_preview = args.getBool("craftresult_is_preview");
- }catch(SettingNotFoundException &e){
- craftresult_is_preview = true;
- }
- try{
hp = args.getS32("hp");
}catch(SettingNotFoundException &e){
hp = 20;
}
- inventory.deSerialize(is, m_gamedef);
+ inventory.deSerialize(is);
+
+ if(inventory.getList("craftpreview") == NULL)
+ {
+ // Convert players without craftpreview
+ inventory.addList("craftpreview", 1);
+
+ bool craftresult_is_preview = true;
+ if(args.exists("craftresult_is_preview"))
+ craftresult_is_preview = args.getBool("craftresult_is_preview");
+ if(craftresult_is_preview)
+ {
+ // Clear craftresult
+ inventory.getList("craftresult")->changeItem(0, ItemStack());
+ }
+ }
}
#ifndef SERVER
diff --git a/src/player.h b/src/player.h
index 1c9dde7e0..d62fb6111 100644
--- a/src/player.h
+++ b/src/player.h
@@ -22,7 +22,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "common_irrlicht.h"
#include "inventory.h"
-#include "collision.h"
#define PLAYERNAME_SIZE 20
@@ -31,6 +30,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
class Map;
class IGameDef;
+struct CollisionInfo;
class Player
{
@@ -117,16 +117,7 @@ public:
snprintf(m_name, PLAYERNAME_SIZE, "%s", name);
}
- virtual void wieldItem(u16 item);
- virtual const InventoryItem *getWieldItem() const
- {
- const InventoryList *list = inventory.getList("main");
- if (list)
- return list->getItem(m_selected_item);
- return NULL;
- }
-
- const char * getName()
+ const char * getName() const
{
return m_name;
}
@@ -164,8 +155,6 @@ public:
// Actual inventory is backed up here when creative mode is used
Inventory *inventory_backup;
- bool craftresult_is_preview;
-
u16 hp;
u16 peer_id;
@@ -174,7 +163,6 @@ protected:
IGameDef *m_gamedef;
char m_name[PLAYERNAME_SIZE];
- u16 m_selected_item;
f32 m_pitch;
f32 m_yaw;
v3f m_speed;
diff --git a/src/profiler.h b/src/profiler.h
index 129118ef6..7bb3b3750 100644
--- a/src/profiler.h
+++ b/src/profiler.h
@@ -100,11 +100,30 @@ public:
void print(std::ostream &o)
{
+ printPage(o, 1, 1);
+ }
+
+ void printPage(std::ostream &o, u32 page, u32 pagecount)
+ {
JMutexAutoLock lock(m_mutex);
+
+ u32 minindex, maxindex;
+ paging(m_data.size(), page, pagecount, minindex, maxindex);
+
for(core::map<std::string, float>::Iterator
i = m_data.getIterator();
i.atEnd() == false; i++)
{
+ if(maxindex == 0)
+ break;
+ maxindex--;
+
+ if(minindex != 0)
+ {
+ minindex--;
+ continue;
+ }
+
std::string name = i.getNode()->getKey();
int avgcount = 1;
core::map<std::string, int>::Node *n = m_avgcounts.find(name);
diff --git a/src/scriptapi.cpp b/src/scriptapi.cpp
index 39a3b06ff..23063a3c8 100644
--- a/src/scriptapi.cpp
+++ b/src/scriptapi.cpp
@@ -36,10 +36,9 @@ extern "C" {
//#include "luna.h"
#include "luaentity_common.h"
#include "content_sao.h" // For LuaEntitySAO
-#include "tooldef.h"
+#include "itemdef.h"
#include "nodedef.h"
#include "craftdef.h"
-#include "craftitemdef.h"
#include "main.h" // For g_settings
#include "settings.h" // For accessing g_settings
#include "nodemetadata.h"
@@ -128,46 +127,308 @@ public:
}
};
-std::string get_current_modname(lua_State *L)
+/*
+ Getters for stuff in main tables
+*/
+
+static Server* get_server(lua_State *L)
{
- lua_getfield(L, LUA_REGISTRYINDEX, "minetest_current_modname");
- std::string modname = "";
- if(lua_type(L, -1) == LUA_TSTRING)
- modname = lua_tostring(L, -1);
+ // Get server from registry
+ lua_getfield(L, LUA_REGISTRYINDEX, "minetest_server");
+ Server *server = (Server*)lua_touserdata(L, -1);
lua_pop(L, 1);
- return modname;
+ return server;
}
-void check_modname_prefix(lua_State *L, std::string &name)
+static ServerEnvironment* get_env(lua_State *L)
{
- if(name.size() == 0)
- throw LuaError(L, std::string("Name is empty"));
-
- if(name[0] == ':'){
- name = name.substr(1);
- return;
+ // Get environment from registry
+ lua_getfield(L, LUA_REGISTRYINDEX, "minetest_env");
+ ServerEnvironment *env = (ServerEnvironment*)lua_touserdata(L, -1);
+ lua_pop(L, 1);
+ return env;
+}
+
+static void objectref_get(lua_State *L, u16 id)
+{
+ // Get minetest.object_refs[i]
+ lua_getglobal(L, "minetest");
+ lua_getfield(L, -1, "object_refs");
+ luaL_checktype(L, -1, LUA_TTABLE);
+ lua_pushnumber(L, id);
+ lua_gettable(L, -2);
+ lua_remove(L, -2); // object_refs
+ lua_remove(L, -2); // minetest
+}
+
+static void luaentity_get(lua_State *L, u16 id)
+{
+ // Get minetest.luaentities[i]
+ lua_getglobal(L, "minetest");
+ lua_getfield(L, -1, "luaentities");
+ luaL_checktype(L, -1, LUA_TTABLE);
+ lua_pushnumber(L, id);
+ lua_gettable(L, -2);
+ lua_remove(L, -2); // luaentities
+ lua_remove(L, -2); // minetest
+}
+
+/*
+ Table field getters
+*/
+
+static bool getstringfield(lua_State *L, int table,
+ const char *fieldname, std::string &result)
+{
+ lua_getfield(L, table, fieldname);
+ bool got = false;
+ if(lua_isstring(L, -1)){
+ size_t len = 0;
+ const char *ptr = lua_tolstring(L, -1, &len);
+ result.assign(ptr, len);
+ got = true;
}
-
- std::string modname = get_current_modname(L);
- assert(modname != "");
-
- // For __builtin, anything goes
- if(modname == "__builtin")
- return;
-
- if(name.substr(0, modname.size()+1) != modname + ":")
- throw LuaError(L, std::string("Name \"")+name
- +"\" does not follow naming conventions: "
- +"\"modname:\" or \":\" prefix required)");
-
- std::string subname = name.substr(modname.size()+1);
- if(!string_allowed(subname, "abcdefghijklmnopqrstuvwxyz"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"))
- throw LuaError(L, std::string("Name \"")+name
- +"\" does not follow naming conventions: "
- +"\"contains unallowed characters");
+ lua_pop(L, 1);
+ return got;
+}
+
+static bool getintfield(lua_State *L, int table,
+ const char *fieldname, int &result)
+{
+ lua_getfield(L, table, fieldname);
+ bool got = false;
+ if(lua_isnumber(L, -1)){
+ result = lua_tonumber(L, -1);
+ got = true;
+ }
+ lua_pop(L, 1);
+ return got;
}
+static bool getfloatfield(lua_State *L, int table,
+ const char *fieldname, float &result)
+{
+ lua_getfield(L, table, fieldname);
+ bool got = false;
+ if(lua_isnumber(L, -1)){
+ result = lua_tonumber(L, -1);
+ got = true;
+ }
+ lua_pop(L, 1);
+ return got;
+}
+
+static bool getboolfield(lua_State *L, int table,
+ const char *fieldname, bool &result)
+{
+ lua_getfield(L, table, fieldname);
+ bool got = false;
+ if(lua_isboolean(L, -1)){
+ result = lua_toboolean(L, -1);
+ got = true;
+ }
+ lua_pop(L, 1);
+ return got;
+}
+
+static std::string checkstringfield(lua_State *L, int table,
+ const char *fieldname)
+{
+ lua_getfield(L, table, fieldname);
+ std::string s = luaL_checkstring(L, -1);
+ lua_pop(L, 1);
+ return s;
+}
+
+static std::string getstringfield_default(lua_State *L, int table,
+ const char *fieldname, const std::string &default_)
+{
+ std::string result = default_;
+ getstringfield(L, table, fieldname, result);
+ return result;
+}
+
+static int getintfield_default(lua_State *L, int table,
+ const char *fieldname, int default_)
+{
+ int result = default_;
+ getintfield(L, table, fieldname, result);
+ return result;
+}
+
+static float getfloatfield_default(lua_State *L, int table,
+ const char *fieldname, float default_)
+{
+ float result = default_;
+ getfloatfield(L, table, fieldname, result);
+ return result;
+}
+
+static bool getboolfield_default(lua_State *L, int table,
+ const char *fieldname, bool default_)
+{
+ bool result = default_;
+ getboolfield(L, table, fieldname, result);
+ return result;
+}
+
+struct EnumString
+{
+ int num;
+ const char *str;
+};
+
+static bool string_to_enum(const EnumString *spec, int &result,
+ const std::string &str)
+{
+ const EnumString *esp = spec;
+ while(esp->str){
+ if(str == std::string(esp->str)){
+ result = esp->num;
+ return true;
+ }
+ esp++;
+ }
+ return false;
+}
+
+/*static bool enum_to_string(const EnumString *spec, std::string &result,
+ int num)
+{
+ const EnumString *esp = spec;
+ while(esp){
+ if(num == esp->num){
+ result = esp->str;
+ return true;
+ }
+ esp++;
+ }
+ return false;
+}*/
+
+static int getenumfield(lua_State *L, int table,
+ const char *fieldname, const EnumString *spec, int default_)
+{
+ int result = default_;
+ string_to_enum(spec, result,
+ getstringfield_default(L, table, fieldname, ""));
+ return result;
+}
+
+static void setintfield(lua_State *L, int table,
+ const char *fieldname, int value)
+{
+ lua_pushinteger(L, value);
+ if(table < 0)
+ table -= 1;
+ lua_setfield(L, table, fieldname);
+}
+
+static void setfloatfield(lua_State *L, int table,
+ const char *fieldname, float value)
+{
+ lua_pushnumber(L, value);
+ if(table < 0)
+ table -= 1;
+ lua_setfield(L, table, fieldname);
+}
+
+static void setboolfield(lua_State *L, int table,
+ const char *fieldname, bool value)
+{
+ lua_pushboolean(L, value);
+ if(table < 0)
+ table -= 1;
+ lua_setfield(L, table, fieldname);
+}
+
+static void warn_if_field_exists(lua_State *L, int table,
+ const char *fieldname, const std::string &message)
+{
+ lua_getfield(L, table, fieldname);
+ if(!lua_isnil(L, -1)){
+ infostream<<script_get_backtrace(L)<<std::endl;
+ infostream<<"WARNING: field \""<<fieldname<<"\": "
+ <<message<<std::endl;
+ }
+ lua_pop(L, 1);
+}
+
+/*
+ EnumString definitions
+*/
+
+struct EnumString es_ItemType[] =
+{
+ {ITEM_NONE, "none"},
+ {ITEM_NODE, "node"},
+ {ITEM_CRAFT, "craft"},
+ {ITEM_TOOL, "tool"},
+ {0, NULL},
+};
+
+struct EnumString es_DrawType[] =
+{
+ {NDT_NORMAL, "normal"},
+ {NDT_AIRLIKE, "airlike"},
+ {NDT_LIQUID, "liquid"},
+ {NDT_FLOWINGLIQUID, "flowingliquid"},
+ {NDT_GLASSLIKE, "glasslike"},
+ {NDT_ALLFACES, "allfaces"},
+ {NDT_ALLFACES_OPTIONAL, "allfaces_optional"},
+ {NDT_TORCHLIKE, "torchlike"},
+ {NDT_SIGNLIKE, "signlike"},
+ {NDT_PLANTLIKE, "plantlike"},
+ {NDT_FENCELIKE, "fencelike"},
+ {NDT_RAILLIKE, "raillike"},
+ {0, NULL},
+};
+
+struct EnumString es_ContentParamType[] =
+{
+ {CPT_NONE, "none"},
+ {CPT_LIGHT, "light"},
+ {0, NULL},
+};
+
+struct EnumString es_ContentParamType2[] =
+{
+ {CPT2_NONE, "none"},
+ {CPT2_FULL, "full"},
+ {CPT2_FLOWINGLIQUID, "flowingliquid"},
+ {CPT2_FACEDIR, "facedir"},
+ {CPT2_WALLMOUNTED, "wallmounted"},
+ {0, NULL},
+};
+
+struct EnumString es_LiquidType[] =
+{
+ {LIQUID_NONE, "none"},
+ {LIQUID_FLOWING, "flowing"},
+ {LIQUID_SOURCE, "source"},
+ {0, NULL},
+};
+
+struct EnumString es_NodeBoxType[] =
+{
+ {NODEBOX_REGULAR, "regular"},
+ {NODEBOX_FIXED, "fixed"},
+ {NODEBOX_WALLMOUNTED, "wallmounted"},
+ {0, NULL},
+};
+
+struct EnumString es_Diggability[] =
+{
+ {DIGGABLE_NOT, "not"},
+ {DIGGABLE_NORMAL, "normal"},
+ {DIGGABLE_CONSTANT, "constant"},
+ {0, NULL},
+};
+
+/*
+ C struct <-> Lua table converter functions
+*/
+
static void push_v3f(lua_State *L, v3f p)
{
lua_newtable(L);
@@ -205,20 +466,6 @@ static v2f read_v2f(lua_State *L, int index)
return p;
}
-static Server* get_server(lua_State *L)
-{
- // Get server from registry
- lua_getfield(L, LUA_REGISTRYINDEX, "minetest_server");
- return (Server*)lua_touserdata(L, -1);
-}
-
-static ServerEnvironment* get_env(lua_State *L)
-{
- // Get environment from registry
- lua_getfield(L, LUA_REGISTRYINDEX, "minetest_env");
- return (ServerEnvironment*)lua_touserdata(L, -1);
-}
-
static v3f read_v3f(lua_State *L, int index)
{
v3f pos;
@@ -366,170 +613,376 @@ static core::aabbox3d<f32> read_aabbox3df32(lua_State *L, int index, f32 scale)
return box;
}
-static bool getstringfield(lua_State *L, int table,
- const char *fieldname, std::string &result)
+/*
+ MaterialProperties
+*/
+
+static MaterialProperties read_material_properties(
+ lua_State *L, int table)
{
- lua_getfield(L, table, fieldname);
- bool got = false;
- if(lua_isstring(L, -1)){
- result = lua_tostring(L, -1);
- got = true;
- }
- lua_pop(L, 1);
- return got;
+ MaterialProperties prop;
+ prop.diggability = (Diggability)getenumfield(L, -1, "diggability",
+ es_Diggability, DIGGABLE_NORMAL);
+ getfloatfield(L, -1, "constant_time", prop.constant_time);
+ getfloatfield(L, -1, "weight", prop.weight);
+ getfloatfield(L, -1, "crackiness", prop.crackiness);
+ getfloatfield(L, -1, "crumbliness", prop.crumbliness);
+ getfloatfield(L, -1, "cuttability", prop.cuttability);
+ getfloatfield(L, -1, "flammability", prop.flammability);
+ return prop;
}
-static bool getintfield(lua_State *L, int table,
- const char *fieldname, int &result)
+/*
+ ToolDiggingProperties
+*/
+
+static ToolDiggingProperties read_tool_digging_properties(
+ lua_State *L, int table)
{
- lua_getfield(L, table, fieldname);
- bool got = false;
- if(lua_isnumber(L, -1)){
- result = lua_tonumber(L, -1);
- got = true;
- }
- lua_pop(L, 1);
- return got;
+ ToolDiggingProperties prop;
+ getfloatfield(L, table, "full_punch_interval", prop.full_punch_interval);
+ getfloatfield(L, table, "basetime", prop.basetime);
+ getfloatfield(L, table, "dt_weight", prop.dt_weight);
+ getfloatfield(L, table, "dt_crackiness", prop.dt_crackiness);
+ getfloatfield(L, table, "dt_crumbliness", prop.dt_crumbliness);
+ getfloatfield(L, table, "dt_cuttability", prop.dt_cuttability);
+ getfloatfield(L, table, "basedurability", prop.basedurability);
+ getfloatfield(L, table, "dd_weight", prop.dd_weight);
+ getfloatfield(L, table, "dd_crackiness", prop.dd_crackiness);
+ getfloatfield(L, table, "dd_crumbliness", prop.dd_crumbliness);
+ getfloatfield(L, table, "dd_cuttability", prop.dd_cuttability);
+ return prop;
}
-static bool getfloatfield(lua_State *L, int table,
- const char *fieldname, float &result)
+static void set_tool_digging_properties(lua_State *L, int table,
+ const ToolDiggingProperties &prop)
{
- lua_getfield(L, table, fieldname);
- bool got = false;
- if(lua_isnumber(L, -1)){
- result = lua_tonumber(L, -1);
- got = true;
- }
- lua_pop(L, 1);
- return got;
+ setfloatfield(L, table, "full_punch_interval", prop.full_punch_interval);
+ setfloatfield(L, table, "basetime", prop.basetime);
+ setfloatfield(L, table, "dt_weight", prop.dt_weight);
+ setfloatfield(L, table, "dt_crackiness", prop.dt_crackiness);
+ setfloatfield(L, table, "dt_crumbliness", prop.dt_crumbliness);
+ setfloatfield(L, table, "dt_cuttability", prop.dt_cuttability);
+ setfloatfield(L, table, "basedurability", prop.basedurability);
+ setfloatfield(L, table, "dd_weight", prop.dd_weight);
+ setfloatfield(L, table, "dd_crackiness", prop.dd_crackiness);
+ setfloatfield(L, table, "dd_crumbliness", prop.dd_crumbliness);
+ setfloatfield(L, table, "dd_cuttability", prop.dd_cuttability);
}
-static bool getboolfield(lua_State *L, int table,
- const char *fieldname, bool &result)
+static void push_tool_digging_properties(lua_State *L,
+ const ToolDiggingProperties &prop)
{
- lua_getfield(L, table, fieldname);
- bool got = false;
- if(lua_isboolean(L, -1)){
- result = lua_toboolean(L, -1);
- got = true;
- }
- lua_pop(L, 1);
- return got;
+ lua_newtable(L);
+ set_tool_digging_properties(L, -1, prop);
}
-static std::string checkstringfield(lua_State *L, int table,
- const char *fieldname)
+/*
+ DiggingProperties
+*/
+
+static void set_digging_properties(lua_State *L, int table,
+ const DiggingProperties &prop)
{
- lua_getfield(L, table, fieldname);
- std::string s = luaL_checkstring(L, -1);
- lua_pop(L, 1);
- return s;
+ setboolfield(L, table, "diggable", prop.diggable);
+ setfloatfield(L, table, "time", prop.time);
+ setintfield(L, table, "wear", prop.wear);
}
-static std::string getstringfield_default(lua_State *L, int table,
- const char *fieldname, const std::string &default_)
+static void push_digging_properties(lua_State *L,
+ const DiggingProperties &prop)
{
- std::string result = default_;
- getstringfield(L, table, fieldname, result);
- return result;
+ lua_newtable(L);
+ set_digging_properties(L, -1, prop);
}
-static int getintfield_default(lua_State *L, int table,
- const char *fieldname, int default_)
+/*
+ HittingProperties
+*/
+
+static void set_hitting_properties(lua_State *L, int table,
+ const HittingProperties &prop)
{
- int result = default_;
- getintfield(L, table, fieldname, result);
- return result;
+ setintfield(L, table, "hp", prop.hp);
+ setintfield(L, table, "wear", prop.wear);
}
-/*static float getfloatfield_default(lua_State *L, int table,
- const char *fieldname, float default_)
+static void push_hitting_properties(lua_State *L,
+ const HittingProperties &prop)
{
- float result = default_;
- getfloatfield(L, table, fieldname, result);
- return result;
-}*/
+ lua_newtable(L);
+ set_hitting_properties(L, -1, prop);
+}
-static bool getboolfield_default(lua_State *L, int table,
- const char *fieldname, bool default_)
+/*
+ PointedThing
+*/
+
+static void push_pointed_thing(lua_State *L, const PointedThing& pointed)
{
- bool result = default_;
- getboolfield(L, table, fieldname, result);
- return result;
+ lua_newtable(L);
+ if(pointed.type == POINTEDTHING_NODE)
+ {
+ lua_pushstring(L, "node");
+ lua_setfield(L, -2, "type");
+ push_v3s16(L, pointed.node_undersurface);
+ lua_setfield(L, -2, "under");
+ push_v3s16(L, pointed.node_abovesurface);
+ lua_setfield(L, -2, "above");
+ }
+ else if(pointed.type == POINTEDTHING_OBJECT)
+ {
+ lua_pushstring(L, "object");
+ lua_setfield(L, -2, "type");
+ objectref_get(L, pointed.object_id);
+ lua_setfield(L, -2, "ref");
+ }
+ else
+ {
+ lua_pushstring(L, "nothing");
+ lua_setfield(L, -2, "type");
+ }
}
-struct EnumString
-{
- int num;
- const char *str;
-};
+/*
+ ItemDefinition
+*/
-static bool string_to_enum(const EnumString *spec, int &result,
- const std::string &str)
+static ItemDefinition read_item_definition(lua_State *L, int index)
{
- const EnumString *esp = spec;
- while(esp->str){
- if(str == std::string(esp->str)){
- result = esp->num;
- return true;
- }
- esp++;
+ if(index < 0)
+ index = lua_gettop(L) + 1 + index;
+
+ // Read the item definition
+ ItemDefinition def;
+
+ def.type = (ItemType)getenumfield(L, index, "type",
+ es_ItemType, ITEM_NONE);
+ getstringfield(L, index, "name", def.name);
+ getstringfield(L, index, "description", def.description);
+ getstringfield(L, index, "inventory_image", def.inventory_image);
+ getstringfield(L, index, "wield_image", def.wield_image);
+
+ lua_getfield(L, index, "wield_scale");
+ if(lua_istable(L, -1)){
+ def.wield_scale = check_v3f(L, -1);
}
- return false;
+ lua_pop(L, 1);
+
+ def.stack_max = getintfield_default(L, index, "stack_max", def.stack_max);
+ if(def.stack_max == 0)
+ def.stack_max = 1;
+
+ lua_getfield(L, index, "on_use");
+ def.usable = lua_isfunction(L, -1);
+ lua_pop(L, 1);
+
+ getboolfield(L, index, "liquids_pointable", def.liquids_pointable);
+
+ lua_getfield(L, index, "tool_digging_properties");
+ if(lua_istable(L, -1)){
+ def.tool_digging_properties = new ToolDiggingProperties(
+ read_tool_digging_properties(L, -1));
+ }
+ lua_pop(L, 1);
+
+ // If name is "" (hand), ensure there are ToolDiggingProperties
+ // because it will be looked up there whenever any other item has
+ // no ToolDiggingProperties
+ if(def.name == "" && def.tool_digging_properties == NULL){
+ def.tool_digging_properties = new ToolDiggingProperties();
+ }
+
+ return def;
}
-/*static bool enum_to_string(const EnumString *spec, std::string &result,
- int num)
+/*
+ ContentFeatures
+*/
+
+static ContentFeatures read_content_features(lua_State *L, int index)
{
- const EnumString *esp = spec;
- while(esp){
- if(num == esp->num){
- result = esp->str;
- return true;
+ if(index < 0)
+ index = lua_gettop(L) + 1 + index;
+
+ ContentFeatures f;
+ getstringfield(L, index, "name", f.name);
+
+ /* Visual definition */
+
+ f.drawtype = (NodeDrawType)getenumfield(L, index, "drawtype", es_DrawType,
+ NDT_NORMAL);
+ getfloatfield(L, index, "visual_scale", f.visual_scale);
+
+ lua_getfield(L, index, "tile_images");
+ if(lua_istable(L, -1)){
+ int table = lua_gettop(L);
+ lua_pushnil(L);
+ int i = 0;
+ while(lua_next(L, table) != 0){
+ // key at index -2 and value at index -1
+ if(lua_isstring(L, -1))
+ f.tname_tiles[i] = lua_tostring(L, -1);
+ else
+ f.tname_tiles[i] = "";
+ // removes value, keeps key for next iteration
+ lua_pop(L, 1);
+ i++;
+ if(i==6){
+ lua_pop(L, 1);
+ break;
+ }
+ }
+ // Copy last value to all remaining textures
+ if(i >= 1){
+ std::string lastname = f.tname_tiles[i-1];
+ while(i < 6){
+ f.tname_tiles[i] = lastname;
+ i++;
+ }
}
- esp++;
}
- return false;
-}*/
+ lua_pop(L, 1);
-static int getenumfield(lua_State *L, int table,
- const char *fieldname, const EnumString *spec, int default_)
-{
- int result = default_;
- string_to_enum(spec, result,
- getstringfield_default(L, table, fieldname, ""));
- return result;
-}
+ lua_getfield(L, index, "special_materials");
+ if(lua_istable(L, -1)){
+ int table = lua_gettop(L);
+ lua_pushnil(L);
+ int i = 0;
+ while(lua_next(L, table) != 0){
+ // key at index -2 and value at index -1
+ int smtable = lua_gettop(L);
+ std::string tname = getstringfield_default(
+ L, smtable, "image", "");
+ bool backface_culling = getboolfield_default(
+ L, smtable, "backface_culling", true);
+ MaterialSpec mspec(tname, backface_culling);
+ f.mspec_special[i] = mspec;
+ // removes value, keeps key for next iteration
+ lua_pop(L, 1);
+ i++;
+ if(i==6){
+ lua_pop(L, 1);
+ break;
+ }
+ }
+ }
+ lua_pop(L, 1);
-static void setfloatfield(lua_State *L, int table,
- const char *fieldname, float value)
-{
- lua_pushnumber(L, value);
- if(table < 0)
- table -= 1;
- lua_setfield(L, table, fieldname);
-}
+ f.alpha = getintfield_default(L, index, "alpha", 255);
-static void warn_if_field_exists(lua_State *L, int table,
- const char *fieldname, const std::string &message)
-{
- lua_getfield(L, table, fieldname);
- if(!lua_isnil(L, -1)){
- infostream<<script_get_backtrace(L)<<std::endl;
- infostream<<"WARNING: field \""<<fieldname<<"\": "
- <<message<<std::endl;
+ /* Other stuff */
+
+ lua_getfield(L, index, "post_effect_color");
+ if(!lua_isnil(L, -1))
+ f.post_effect_color = readARGB8(L, -1);
+ lua_pop(L, 1);
+
+ f.param_type = (ContentParamType)getenumfield(L, index, "paramtype",
+ es_ContentParamType, CPT_NONE);
+ f.param_type_2 = (ContentParamType2)getenumfield(L, index, "paramtype2",
+ es_ContentParamType2, CPT2_NONE);
+
+ // Warn about some deprecated fields
+ warn_if_field_exists(L, index, "wall_mounted",
+ "deprecated: use paramtype2 = 'wallmounted'");
+ warn_if_field_exists(L, index, "light_propagates",
+ "deprecated: determined from paramtype");
+ warn_if_field_exists(L, index, "dug_item",
+ "deprecated: use 'drop' field");
+ warn_if_field_exists(L, index, "extra_dug_item",
+ "deprecated: use 'drop' field");
+ warn_if_field_exists(L, index, "extra_dug_item_rarity",
+ "deprecated: use 'drop' field");
+
+ // True for all ground-like things like stone and mud, false for eg. trees
+ getboolfield(L, index, "is_ground_content", f.is_ground_content);
+ f.light_propagates = (f.param_type == CPT_LIGHT);
+ getboolfield(L, index, "sunlight_propagates", f.sunlight_propagates);
+ // This is used for collision detection.
+ // Also for general solidness queries.
+ getboolfield(L, index, "walkable", f.walkable);
+ // Player can point to these
+ getboolfield(L, index, "pointable", f.pointable);
+ // Player can dig these
+ getboolfield(L, index, "diggable", f.diggable);
+ // Player can climb these
+ getboolfield(L, index, "climbable", f.climbable);
+ // Player can build on these
+ getboolfield(L, index, "buildable_to", f.buildable_to);
+ // Metadata name of node (eg. "furnace")
+ getstringfield(L, index, "metadata_name", f.metadata_name);
+ // Whether the node is non-liquid, source liquid or flowing liquid
+ f.liquid_type = (LiquidType)getenumfield(L, index, "liquidtype",
+ es_LiquidType, LIQUID_NONE);
+ // If the content is liquid, this is the flowing version of the liquid.
+ getstringfield(L, index, "liquid_alternative_flowing",
+ f.liquid_alternative_flowing);
+ // If the content is liquid, this is the source version of the liquid.
+ getstringfield(L, index, "liquid_alternative_source",
+ f.liquid_alternative_source);
+ // Viscosity for fluid flow, ranging from 1 to 7, with
+ // 1 giving almost instantaneous propagation and 7 being
+ // the slowest possible
+ f.liquid_viscosity = getintfield_default(L, index,
+ "liquid_viscosity", f.liquid_viscosity);
+ // Amount of light the node emits
+ f.light_source = getintfield_default(L, index,
+ "light_source", f.light_source);
+ f.damage_per_second = getintfield_default(L, index,
+ "damage_per_second", f.damage_per_second);
+
+ lua_getfield(L, index, "selection_box");
+ if(lua_istable(L, -1)){
+ f.selection_box.type = (NodeBoxType)getenumfield(L, -1, "type",
+ es_NodeBoxType, NODEBOX_REGULAR);
+
+ lua_getfield(L, -1, "fixed");
+ if(lua_istable(L, -1))
+ f.selection_box.fixed = read_aabbox3df32(L, -1, BS);
+ lua_pop(L, 1);
+
+ lua_getfield(L, -1, "wall_top");
+ if(lua_istable(L, -1))
+ f.selection_box.wall_top = read_aabbox3df32(L, -1, BS);
+ lua_pop(L, 1);
+
+ lua_getfield(L, -1, "wall_bottom");
+ if(lua_istable(L, -1))
+ f.selection_box.wall_bottom = read_aabbox3df32(L, -1, BS);
+ lua_pop(L, 1);
+
+ lua_getfield(L, -1, "wall_side");
+ if(lua_istable(L, -1))
+ f.selection_box.wall_side = read_aabbox3df32(L, -1, BS);
+ lua_pop(L, 1);
}
lua_pop(L, 1);
+
+ lua_getfield(L, index, "material");
+ if(lua_istable(L, -1)){
+ f.material = read_material_properties(L, -1);
+ }
+ lua_pop(L, 1);
+
+ // Set to true if paramtype used to be 'facedir_simple'
+ getboolfield(L, index, "legacy_facedir_simple", f.legacy_facedir_simple);
+ // Set to true if wall_mounted used to be set to true
+ getboolfield(L, index, "legacy_wallmounted", f.legacy_wallmounted);
+
+ return f;
}
/*
Inventory stuff
*/
+static ItemStack read_item(lua_State *L, int index);
+
static void inventory_set_list_from_lua(Inventory *inv, const char *name,
- lua_State *L, int tableindex, IGameDef *gamedef, int forcesize=-1)
+ lua_State *L, int tableindex, int forcesize=-1)
{
+ dstream<<"inventory_set_list_from_lua\n";
if(tableindex < 0)
tableindex = lua_gettop(L) + 1 + tableindex;
// If nil, delete list
@@ -538,39 +991,30 @@ static void inventory_set_list_from_lua(Inventory *inv, const char *name,
return;
}
// Otherwise set list
- std::list<std::string> items;
+ std::vector<ItemStack> items;
luaL_checktype(L, tableindex, LUA_TTABLE);
- int table = tableindex;
lua_pushnil(L);
- while(lua_next(L, table) != 0){
+ while(lua_next(L, tableindex) != 0){
// key at index -2 and value at index -1
- luaL_checktype(L, -1, LUA_TSTRING);
- std::string itemstring = luaL_checkstring(L, -1);
- items.push_back(itemstring);
+ items.push_back(read_item(L, -1));
// removes value, keeps key for next iteration
lua_pop(L, 1);
}
int listsize = (forcesize != -1) ? forcesize : items.size();
InventoryList *invlist = inv->addList(name, listsize);
int index = 0;
- for(std::list<std::string>::const_iterator
+ for(std::vector<ItemStack>::const_iterator
i = items.begin(); i != items.end(); i++){
if(forcesize != -1 && index == forcesize)
break;
- const std::string &itemstring = *i;
- InventoryItem *newitem = NULL;
- if(itemstring != "")
- newitem = InventoryItem::deSerialize(itemstring,
- gamedef);
- InventoryItem *olditem = invlist->changeItem(index, newitem);
- delete olditem;
+ invlist->changeItem(index, *i);
index++;
}
while(forcesize != -1 && index < forcesize){
- InventoryItem *olditem = invlist->changeItem(index, NULL);
- delete olditem;
+ invlist->deleteItem(index);
index++;
}
+ dstream<<"inventory_set_list_from_lua done\n";
}
static void inventory_get_list_to_lua(Inventory *inv, const char *name,
@@ -589,375 +1033,317 @@ static void inventory_get_list_to_lua(Inventory *inv, const char *name,
lua_newtable(L);
int table = lua_gettop(L);
for(u32 i=0; i<invlist->getSize(); i++){
- InventoryItem *item = invlist->getItem(i);
+ ItemStack item = invlist->getItem(i);
lua_pushvalue(L, table_insert);
lua_pushvalue(L, table);
- if(item == NULL){
- lua_pushstring(L, "");
- } else {
- lua_pushstring(L, item->getItemString().c_str());
- }
+ lua_pushstring(L, item.getItemString().c_str());
if(lua_pcall(L, 2, 0, 0))
script_error(L, "error: %s", lua_tostring(L, -1));
}
}
-static void push_stack_item(lua_State *L, InventoryItem *item0)
-{
- if(item0 == NULL){
- lua_pushnil(L);
- }
- else if(std::string("MaterialItem") == item0->getName()){
- MaterialItem *item = (MaterialItem*)item0;
- lua_newtable(L);
- lua_pushstring(L, "node");
- lua_setfield(L, -2, "type");
- lua_pushstring(L, item->getNodeName().c_str());
- lua_setfield(L, -2, "name");
- }
- else if(std::string("CraftItem") == item0->getName()){
- CraftItem *item = (CraftItem*)item0;
- lua_newtable(L);
- lua_pushstring(L, "craft");
- lua_setfield(L, -2, "type");
- lua_pushstring(L, item->getSubName().c_str());
- lua_setfield(L, -2, "name");
- }
- else if(std::string("ToolItem") == item0->getName()){
- ToolItem *item = (ToolItem*)item0;
- lua_newtable(L);
- lua_pushstring(L, "tool");
- lua_setfield(L, -2, "type");
- lua_pushstring(L, item->getToolName().c_str());
- lua_setfield(L, -2, "name");
- lua_pushstring(L, itos(item->getWear()).c_str());
- lua_setfield(L, -2, "wear");
- }
- else{
- errorstream<<"push_stack_item: Unknown item name: \""
- <<item0->getName()<<"\""<<std::endl;
- lua_pushnil(L);
- }
-}
-
-static InventoryItem* check_stack_item(lua_State *L, int index)
-{
- if(index < 0)
- index = lua_gettop(L) + 1 + index;
- if(lua_isnil(L, index))
- return NULL;
- if(!lua_istable(L, index))
- throw LuaError(L, "check_stack_item: Item not nil or table");
- // A very crappy implementation for now
- // Will be replaced when unified namespace for items is made
- std::string type = getstringfield_default(L, index, "type", "");
- std::string name = getstringfield_default(L, index, "name", "");
- std::string num = getstringfield_default(L, index, "wear", "_");
- if(num == "_")
- num = 1;
- std::string itemstring = type + " \"" + name + "\" " + num;
- try{
- return InventoryItem::deSerialize(itemstring, get_server(L));
- }catch(SerializationError &e){
- throw LuaError(L, std::string("check_stack_item: "
- "internal error (itemstring=\"")+itemstring+"\")");
- }
-}
-
/*
- ToolDiggingProperties
+ Helpful macros for userdata classes
*/
-static ToolDiggingProperties read_tool_digging_properties(
- lua_State *L, int table)
-{
- ToolDiggingProperties prop;
- getfloatfield(L, table, "full_punch_interval", prop.full_punch_interval);
- getfloatfield(L, table, "basetime", prop.basetime);
- getfloatfield(L, table, "dt_weight", prop.dt_weight);
- getfloatfield(L, table, "dt_crackiness", prop.dt_crackiness);
- getfloatfield(L, table, "dt_crumbliness", prop.dt_crumbliness);
- getfloatfield(L, table, "dt_cuttability", prop.dt_cuttability);
- getfloatfield(L, table, "basedurability", prop.basedurability);
- getfloatfield(L, table, "dd_weight", prop.dd_weight);
- getfloatfield(L, table, "dd_crackiness", prop.dd_crackiness);
- getfloatfield(L, table, "dd_crumbliness", prop.dd_crumbliness);
- getfloatfield(L, table, "dd_cuttability", prop.dd_cuttability);
- return prop;
-}
-
-static void set_tool_digging_properties(lua_State *L, int table,
- const ToolDiggingProperties &prop)
-{
- setfloatfield(L, table, "full_punch_interval", prop.full_punch_interval);
- setfloatfield(L, table, "basetime", prop.basetime);
- setfloatfield(L, table, "dt_weight", prop.dt_weight);
- setfloatfield(L, table, "dt_crackiness", prop.dt_crackiness);
- setfloatfield(L, table, "dt_crumbliness", prop.dt_crumbliness);
- setfloatfield(L, table, "dt_cuttability", prop.dt_cuttability);
- setfloatfield(L, table, "basedurability", prop.basedurability);
- setfloatfield(L, table, "dd_weight", prop.dd_weight);
- setfloatfield(L, table, "dd_crackiness", prop.dd_crackiness);
- setfloatfield(L, table, "dd_crumbliness", prop.dd_crumbliness);
- setfloatfield(L, table, "dd_cuttability", prop.dd_cuttability);
-}
-
-static void push_tool_digging_properties(lua_State *L,
- const ToolDiggingProperties &prop)
-{
- lua_newtable(L);
- set_tool_digging_properties(L, -1, prop);
-}
+#define method(class, name) {#name, class::l_##name}
/*
- ToolDefinition
+ LuaItemStack
*/
-static ToolDefinition read_tool_definition(lua_State *L, int table)
+class LuaItemStack
{
- ToolDefinition def;
- getstringfield(L, table, "image", def.imagename);
- def.properties = read_tool_digging_properties(L, table);
- return def;
-}
+private:
+ ItemStack m_stack;
-static void push_tool_definition(lua_State *L, const ToolDefinition &def)
-{
- lua_newtable(L);
- lua_pushstring(L, def.imagename.c_str());
- lua_setfield(L, -2, "image");
- set_tool_digging_properties(L, -1, def.properties);
-}
+ static const char className[];
+ static const luaL_reg methods[];
-/*
- EnumString definitions
-*/
+ // Exported functions
+
+ // garbage collector
+ static int gc_object(lua_State *L)
+ {
+ LuaItemStack *o = *(LuaItemStack **)(lua_touserdata(L, 1));
+ delete o;
+ return 0;
+ }
-struct EnumString es_DrawType[] =
-{
- {NDT_NORMAL, "normal"},
- {NDT_AIRLIKE, "airlike"},
- {NDT_LIQUID, "liquid"},
- {NDT_FLOWINGLIQUID, "flowingliquid"},
- {NDT_GLASSLIKE, "glasslike"},
- {NDT_ALLFACES, "allfaces"},
- {NDT_ALLFACES_OPTIONAL, "allfaces_optional"},
- {NDT_TORCHLIKE, "torchlike"},
- {NDT_SIGNLIKE, "signlike"},
- {NDT_PLANTLIKE, "plantlike"},
- {NDT_FENCELIKE, "fencelike"},
- {NDT_RAILLIKE, "raillike"},
- {0, NULL},
-};
+ // is_empty(self) -> true/false
+ static int l_is_empty(lua_State *L)
+ {
+ LuaItemStack *o = checkobject(L, 1);
+ ItemStack &item = o->m_stack;
+ lua_pushboolean(L, item.empty());
+ return 1;
+ }
-struct EnumString es_ContentParamType[] =
-{
- {CPT_NONE, "none"},
- {CPT_LIGHT, "light"},
- {CPT_MINERAL, "mineral"},
- {CPT_FACEDIR_SIMPLE, "facedir_simple"},
- {0, NULL},
-};
+ // get_name(self) -> string
+ static int l_get_name(lua_State *L)
+ {
+ LuaItemStack *o = checkobject(L, 1);
+ ItemStack &item = o->m_stack;
+ lua_pushstring(L, item.name.c_str());
+ return 1;
+ }
-struct EnumString es_LiquidType[] =
-{
- {LIQUID_NONE, "none"},
- {LIQUID_FLOWING, "flowing"},
- {LIQUID_SOURCE, "source"},
- {0, NULL},
-};
+ // get_count(self) -> number
+ static int l_get_count(lua_State *L)
+ {
+ LuaItemStack *o = checkobject(L, 1);
+ ItemStack &item = o->m_stack;
+ lua_pushinteger(L, item.count);
+ return 1;
+ }
-struct EnumString es_NodeBoxType[] =
-{
- {NODEBOX_REGULAR, "regular"},
- {NODEBOX_FIXED, "fixed"},
- {NODEBOX_WALLMOUNTED, "wallmounted"},
- {0, NULL},
-};
+ // get_wear(self) -> number
+ static int l_get_wear(lua_State *L)
+ {
+ LuaItemStack *o = checkobject(L, 1);
+ ItemStack &item = o->m_stack;
+ lua_pushinteger(L, item.wear);
+ return 1;
+ }
-struct EnumString es_Diggability[] =
-{
- {DIGGABLE_NOT, "not"},
- {DIGGABLE_NORMAL, "normal"},
- {DIGGABLE_CONSTANT, "constant"},
- {0, NULL},
-};
+ // get_metadata(self) -> string
+ static int l_get_metadata(lua_State *L)
+ {
+ LuaItemStack *o = checkobject(L, 1);
+ ItemStack &item = o->m_stack;
+ lua_pushlstring(L, item.metadata.c_str(), item.metadata.size());
+ return 1;
+ }
-/*
- Getters for stuff in main tables
-*/
+ // clear(self) -> true
+ static int l_clear(lua_State *L)
+ {
+ LuaItemStack *o = checkobject(L, 1);
+ o->m_stack.clear();
+ lua_pushboolean(L, true);
+ return 1;
+ }
-static void objectref_get(lua_State *L, u16 id)
-{
- // Get minetest.object_refs[i]
- lua_getglobal(L, "minetest");
- lua_getfield(L, -1, "object_refs");
- luaL_checktype(L, -1, LUA_TTABLE);
- lua_pushnumber(L, id);
- lua_gettable(L, -2);
- lua_remove(L, -2); // object_refs
- lua_remove(L, -2); // minetest
-}
+ // replace(self, itemstack or itemstring or table or nil) -> true
+ static int l_replace(lua_State *L)
+ {
+ LuaItemStack *o = checkobject(L, 1);
+ o->m_stack = read_item(L, 2);
+ lua_pushboolean(L, true);
+ return 1;
+ }
-static void luaentity_get(lua_State *L, u16 id)
-{
- // Get minetest.luaentities[i]
- lua_getglobal(L, "minetest");
- lua_getfield(L, -1, "luaentities");
- luaL_checktype(L, -1, LUA_TTABLE);
- lua_pushnumber(L, id);
- lua_gettable(L, -2);
- lua_remove(L, -2); // luaentities
- lua_remove(L, -2); // minetest
-}
+ // to_string(self) -> string
+ static int l_to_string(lua_State *L)
+ {
+ LuaItemStack *o = checkobject(L, 1);
+ std::string itemstring = o->m_stack.getItemString();
+ lua_pushstring(L, itemstring.c_str());
+ return 1;
+ }
-/*
- Object wrappers
-*/
+ // to_table(self) -> table or nil
+ static int l_to_table(lua_State *L)
+ {
+ LuaItemStack *o = checkobject(L, 1);
+ const ItemStack &item = o->m_stack;
+ if(item.empty())
+ {
+ lua_pushnil(L);
+ }
+ else
+ {
+ lua_newtable(L);
+ lua_pushstring(L, item.name.c_str());
+ lua_setfield(L, -2, "name");
+ lua_pushinteger(L, item.count);
+ lua_setfield(L, -2, "count");
+ lua_pushinteger(L, item.wear);
+ lua_setfield(L, -2, "wear");
+ lua_pushlstring(L, item.metadata.c_str(), item.metadata.size());
+ lua_setfield(L, -2, "metadata");
+ }
+ return 1;
+ }
-#define method(class, name) {#name, class::l_##name}
+ // get_stack_max(self) -> number
+ static int l_get_stack_max(lua_State *L)
+ {
+ LuaItemStack *o = checkobject(L, 1);
+ ItemStack &item = o->m_stack;
+ lua_pushinteger(L, item.getStackMax(get_server(L)->idef()));
+ return 1;
+ }
-/*
- ItemStack
-*/
+ // get_free_space(self) -> number
+ static int l_get_free_space(lua_State *L)
+ {
+ LuaItemStack *o = checkobject(L, 1);
+ ItemStack &item = o->m_stack;
+ lua_pushinteger(L, item.freeSpace(get_server(L)->idef()));
+ return 1;
+ }
-class ItemStack
-{
-private:
- InventoryItem *m_stack;
+ // is_known(self) -> true/false
+ // Checks if the item is defined.
+ static int l_is_known(lua_State *L)
+ {
+ LuaItemStack *o = checkobject(L, 1);
+ ItemStack &item = o->m_stack;
+ bool is_known = item.isKnown(get_server(L)->idef());
+ lua_pushboolean(L, is_known);
+ return 1;
+ }
- static const char className[];
- static const luaL_reg methods[];
+ // get_definition(self) -> table
+ // Returns the item definition table from minetest.registered_items,
+ // or a fallback one (name="unknown")
+ static int l_get_definition(lua_State *L)
+ {
+ LuaItemStack *o = checkobject(L, 1);
+ ItemStack &item = o->m_stack;
- // Exported functions
-
- // garbage collector
- static int gc_object(lua_State *L) {
- ItemStack *o = *(ItemStack **)(lua_touserdata(L, 1));
- delete o;
- return 0;
+ // Get minetest.registered_items[name]
+ lua_getglobal(L, "minetest");
+ lua_getfield(L, -1, "registered_items");
+ luaL_checktype(L, -1, LUA_TTABLE);
+ lua_getfield(L, -1, item.name.c_str());
+ if(lua_isnil(L, -1))
+ {
+ lua_pop(L, 1);
+ lua_getfield(L, -1, "unknown");
+ }
+ return 1;
}
- // peek_item(self)
- static int l_peek_item(lua_State *L)
+ // get_tool_digging_properties(self) -> table
+ // Returns the effective tool digging properties.
+ // Returns those of the hand ("") if this item has none associated.
+ static int l_get_tool_digging_properties(lua_State *L)
{
- ItemStack *o = checkobject(L, 1);
- push_stack_item(L, o->m_stack);
+ LuaItemStack *o = checkobject(L, 1);
+ ItemStack &item = o->m_stack;
+ const ToolDiggingProperties &prop =
+ item.getToolDiggingProperties(get_server(L)->idef());
+ push_tool_digging_properties(L, prop);
return 1;
}
- // take_item(self)
- static int l_take_item(lua_State *L)
+ // add_wear(self, amount) -> true/false
+ // The range for "amount" is [0,65535]. Wear is only added if the item
+ // is a tool. Adding wear might destroy the item.
+ // Returns true if the item is (or was) a tool.
+ static int l_add_wear(lua_State *L)
{
- ItemStack *o = checkobject(L, 1);
- push_stack_item(L, o->m_stack);
- if(o->m_stack->getCount() <= 1){
- delete o->m_stack;
- o->m_stack = NULL;
- } else {
- o->m_stack->remove(1);
- }
+ LuaItemStack *o = checkobject(L, 1);
+ ItemStack &item = o->m_stack;
+ int amount = lua_tointeger(L, 2);
+ bool result = item.addWear(amount, get_server(L)->idef());
+ lua_pushboolean(L, result);
return 1;
}
- // put_item(self, item) -> true/false
- static int l_put_item(lua_State *L)
+ // add_item(self, itemstack or itemstring or table or nil) -> itemstack
+ // Returns leftover item stack
+ static int l_add_item(lua_State *L)
{
- ItemStack *o = checkobject(L, 1);
- InventoryItem *item = check_stack_item(L, 2);
- if(!item){ // nil can always be inserted
- lua_pushboolean(L, true);
- return 1;
- }
- if(!item->addableTo(o->m_stack)){
- lua_pushboolean(L, false);
- return 1;
- }
- o->m_stack->add(1);
- delete item;
- lua_pushboolean(L, true);
+ LuaItemStack *o = checkobject(L, 1);
+ ItemStack &item = o->m_stack;
+ ItemStack newitem = read_item(L, 2);
+ ItemStack leftover = item.addItem(newitem, get_server(L)->idef());
+ create(L, leftover);
return 1;
}
- // put_stackstring(self, stackstring) -> true/false
- static int l_put_stackstring(lua_State *L)
+ // item_fits(self, itemstack or itemstring or table or nil) -> true/false, itemstack
+ // First return value is true iff the new item fits fully into the stack
+ // Second return value is the would-be-left-over item stack
+ static int l_item_fits(lua_State *L)
{
- ItemStack *o = checkobject(L, 1);
- std::string stackstring = luaL_checkstring(L, 2);
- try{
- InventoryItem *item = InventoryItem::deSerialize(stackstring,
- get_server(L));
- if(!item->addableTo(o->m_stack)){
- lua_pushboolean(L, false);
- return 1;
- }
- o->m_stack->add(1);
- delete item;
- lua_pushboolean(L, true);
- return 1;
- }
- catch(SerializationError &e){
- lua_pushboolean(L, false);
- return 1;
- }
+ LuaItemStack *o = checkobject(L, 1);
+ ItemStack &item = o->m_stack;
+ ItemStack newitem = read_item(L, 2);
+ ItemStack restitem;
+ bool fits = item.itemFits(newitem, &restitem, get_server(L)->idef());
+ lua_pushboolean(L, fits); // first return value
+ create(L, restitem); // second return value
+ return 2;
+ }
+
+ // take_item(self, takecount=1) -> itemstack
+ static int l_take_item(lua_State *L)
+ {
+ LuaItemStack *o = checkobject(L, 1);
+ ItemStack &item = o->m_stack;
+ u32 takecount = 1;
+ if(!lua_isnone(L, 2))
+ takecount = lua_tointeger(L, 2);
+ ItemStack taken = item.takeItem(takecount);
+ create(L, taken);
+ return 1;
+ }
+
+ // peek_item(self, peekcount=1) -> itemstack
+ static int l_peek_item(lua_State *L)
+ {
+ LuaItemStack *o = checkobject(L, 1);
+ ItemStack &item = o->m_stack;
+ u32 peekcount = 1;
+ if(!lua_isnone(L, 2))
+ peekcount = lua_tointeger(L, 2);
+ ItemStack peekaboo = item.peekItem(peekcount);
+ create(L, peekaboo);
+ return 1;
}
public:
- ItemStack(InventoryItem *item=NULL):
+ LuaItemStack(const ItemStack &item):
m_stack(item)
{
}
- ~ItemStack()
+ ~LuaItemStack()
{
- delete m_stack;
}
- static ItemStack* checkobject(lua_State *L, int narg)
+ const ItemStack& getItem() const
{
- luaL_checktype(L, narg, LUA_TUSERDATA);
- void *ud = luaL_checkudata(L, narg, className);
- if(!ud) luaL_typerror(L, narg, className);
- return *(ItemStack**)ud; // unbox pointer
+ return m_stack;
}
-
- InventoryItem* getItemCopy()
+ ItemStack& getItem()
{
- if(!m_stack)
- return NULL;
- return m_stack->clone();
+ return m_stack;
}
- // Creates an ItemStack and leaves it on top of stack
+ // LuaItemStack(itemstack or itemstring or table or nil)
+ // Creates an LuaItemStack and leaves it on top of stack
static int create_object(lua_State *L)
{
- InventoryItem *item = NULL;
- if(lua_isstring(L, 1)){
- std::string itemstring = lua_tostring(L, 1);
- if(itemstring != ""){
- try{
- IGameDef *gdef = get_server(L);
- item = InventoryItem::deSerialize(itemstring, gdef);
- }catch(SerializationError &e){
- }
- }
- }
- ItemStack *o = new ItemStack(item);
+ ItemStack item = read_item(L, 1);
+ LuaItemStack *o = new LuaItemStack(item);
*(void **)(lua_newuserdata(L, sizeof(void *))) = o;
luaL_getmetatable(L, className);
lua_setmetatable(L, -2);
return 1;
}
// Not callable from Lua
- static int create(lua_State *L, InventoryItem *item)
+ static int create(lua_State *L, const ItemStack &item)
{
- ItemStack *o = new ItemStack(item);
+ LuaItemStack *o = new LuaItemStack(item);
*(void **)(lua_newuserdata(L, sizeof(void *))) = o;
luaL_getmetatable(L, className);
lua_setmetatable(L, -2);
return 1;
}
+ static LuaItemStack* checkobject(lua_State *L, int narg)
+ {
+ luaL_checktype(L, narg, LUA_TUSERDATA);
+ void *ud = luaL_checkudata(L, narg, className);
+ if(!ud) luaL_typerror(L, narg, className);
+ return *(LuaItemStack**)ud; // unbox pointer
+ }
+
static void Register(lua_State *L)
{
lua_newtable(L);
@@ -982,19 +1368,83 @@ public:
luaL_openlib(L, 0, methods, 0); // fill methodtable
lua_pop(L, 1); // drop methodtable
- // Can be created from Lua (ItemStack::create(itemstring))
+ // Can be created from Lua (LuaItemStack(itemstack or itemstring or table or nil))
lua_register(L, className, create_object);
}
};
-const char ItemStack::className[] = "ItemStack";
-const luaL_reg ItemStack::methods[] = {
- method(ItemStack, peek_item),
- method(ItemStack, take_item),
- method(ItemStack, put_item),
- method(ItemStack, put_stackstring),
+const char LuaItemStack::className[] = "ItemStack";
+const luaL_reg LuaItemStack::methods[] = {
+ method(LuaItemStack, is_empty),
+ method(LuaItemStack, get_name),
+ method(LuaItemStack, get_count),
+ method(LuaItemStack, get_wear),
+ method(LuaItemStack, get_metadata),
+ method(LuaItemStack, clear),
+ method(LuaItemStack, replace),
+ method(LuaItemStack, to_string),
+ method(LuaItemStack, to_table),
+ method(LuaItemStack, get_stack_max),
+ method(LuaItemStack, get_free_space),
+ method(LuaItemStack, is_known),
+ method(LuaItemStack, get_definition),
+ method(LuaItemStack, get_tool_digging_properties),
+ method(LuaItemStack, add_wear),
+ method(LuaItemStack, add_item),
+ method(LuaItemStack, item_fits),
+ method(LuaItemStack, take_item),
+ method(LuaItemStack, peek_item),
{0,0}
};
+static ItemStack read_item(lua_State *L, int index)
+{
+ if(index < 0)
+ index = lua_gettop(L) + 1 + index;
+
+ if(lua_isnil(L, index))
+ {
+ return ItemStack();
+ }
+ else if(lua_isuserdata(L, index))
+ {
+ // Convert from LuaItemStack
+ LuaItemStack *o = LuaItemStack::checkobject(L, index);
+ return o->getItem();
+ }
+ else if(lua_isstring(L, index))
+ {
+ // Convert from itemstring
+ std::string itemstring = lua_tostring(L, index);
+ IItemDefManager *idef = get_server(L)->idef();
+ try
+ {
+ ItemStack item;
+ item.deSerialize(itemstring, idef);
+ return item;
+ }
+ catch(SerializationError &e)
+ {
+ infostream<<"WARNING: unable to create item from itemstring"
+ <<": "<<itemstring<<std::endl;
+ return ItemStack();
+ }
+ }
+ else if(lua_istable(L, index))
+ {
+ // Convert from table
+ IItemDefManager *idef = get_server(L)->idef();
+ std::string name = getstringfield_default(L, index, "name", "");
+ int count = getintfield_default(L, index, "count", 1);
+ int wear = getintfield_default(L, index, "wear", 0);
+ std::string metadata = getstringfield_default(L, index, "metadata", "");
+ return ItemStack(name, count, wear, metadata, idef);
+ }
+ else
+ {
+ throw LuaError(L, "Expecting itemstack, itemstring, table or nil");
+ }
+}
+
/*
InvRef
*/
@@ -1029,15 +1479,6 @@ private:
return inv->getList(listname);
}
- static InventoryItem* getitem(lua_State *L, InvRef *ref,
- const char *listname, int i)
- {
- InventoryList *list = getlist(L, ref, listname);
- if(!list)
- return NULL;
- return list->getItem(i);
- }
-
static void reportInventoryChange(lua_State *L, InvRef *ref)
{
// Inform other things that the inventory has changed
@@ -1089,39 +1530,35 @@ private:
return 0;
}
- // get_stack(self, listname, i)
+ // get_stack(self, listname, i) -> itemstack
static int l_get_stack(lua_State *L)
{
InvRef *ref = checkobject(L, 1);
const char *listname = luaL_checkstring(L, 2);
int i = luaL_checknumber(L, 3) - 1;
- InventoryItem *item = getitem(L, ref, listname, i);
- if(!item){
- ItemStack::create(L, NULL);
- return 1;
- }
- ItemStack::create(L, item->clone());
+ InventoryList *list = getlist(L, ref, listname);
+ ItemStack item;
+ if(list != NULL && i >= 0 && i < (int) list->getSize())
+ item = list->getItem(i);
+ LuaItemStack::create(L, item);
return 1;
}
- // set_stack(self, listname, i, stack)
+ // set_stack(self, listname, i, stack) -> true/false
static int l_set_stack(lua_State *L)
{
InvRef *ref = checkobject(L, 1);
const char *listname = luaL_checkstring(L, 2);
int i = luaL_checknumber(L, 3) - 1;
- ItemStack *stack = ItemStack::checkobject(L, 4);
+ ItemStack newitem = read_item(L, 4);
InventoryList *list = getlist(L, ref, listname);
- if(!list){
+ if(list != NULL && i >= 0 && i < (int) list->getSize()){
+ list->changeItem(i, newitem);
+ reportInventoryChange(L, ref);
+ lua_pushboolean(L, true);
+ } else {
lua_pushboolean(L, false);
- return 1;
}
- InventoryItem *newitem = stack->getItemCopy();
- InventoryItem *olditem = list->changeItem(i, newitem);
- bool success = (olditem != newitem);
- delete olditem;
- lua_pushboolean(L, success);
- reportInventoryChange(L, ref);
return 1;
}
@@ -1144,57 +1581,79 @@ private:
InventoryList *list = inv->getList(listname);
if(list)
inventory_set_list_from_lua(inv, listname, L, 3,
- get_server(L), list->getSize());
+ list->getSize());
else
- inventory_set_list_from_lua(inv, listname, L, 3,
- get_server(L));
+ inventory_set_list_from_lua(inv, listname, L, 3);
reportInventoryChange(L, ref);
return 0;
}
- // autoinsert_stack(self, listname, stack)
- static int l_autoinsert_stack(lua_State *L)
+ // add_item(self, listname, itemstack or itemstring or table or nil) -> itemstack
+ // Returns the leftover stack
+ static int l_add_item(lua_State *L)
{
InvRef *ref = checkobject(L, 1);
const char *listname = luaL_checkstring(L, 2);
- ItemStack *stack = ItemStack::checkobject(L, 3);
+ ItemStack item = read_item(L, 3);
InventoryList *list = getlist(L, ref, listname);
- if(!list){
- lua_pushboolean(L, false);
- return 1;
+ if(list){
+ ItemStack leftover = list->addItem(item);
+ if(leftover.count != item.count)
+ reportInventoryChange(L, ref);
+ LuaItemStack::create(L, leftover);
+ } else {
+ LuaItemStack::create(L, item);
}
- InventoryItem *item = stack->getItemCopy();
- if(list->roomForItem(item)){
- delete list->addItem(item);
- lua_pushboolean(L, true);
- reportInventoryChange(L, ref);
+ return 1;
+ }
+
+ // room_for_item(self, listname, itemstack or itemstring or table or nil) -> true/false
+ // Returns true if the item completely fits into the list
+ static int l_room_for_item(lua_State *L)
+ {
+ InvRef *ref = checkobject(L, 1);
+ const char *listname = luaL_checkstring(L, 2);
+ ItemStack item = read_item(L, 3);
+ InventoryList *list = getlist(L, ref, listname);
+ if(list){
+ lua_pushboolean(L, list->roomForItem(item));
} else {
- delete item;
lua_pushboolean(L, false);
}
return 1;
}
- // autoinsert_stackstring(self, listname, stackstring)
- static int l_autoinsert_stackstring(lua_State *L)
+ // contains_item(self, listname, itemstack or itemstring or table or nil) -> true/false
+ // Returns true if the list contains the given count of the given item name
+ static int l_contains_item(lua_State *L)
{
InvRef *ref = checkobject(L, 1);
const char *listname = luaL_checkstring(L, 2);
- const char *stackstring = luaL_checkstring(L, 3);
+ ItemStack item = read_item(L, 3);
InventoryList *list = getlist(L, ref, listname);
- if(!list){
+ if(list){
+ lua_pushboolean(L, list->containsItem(item));
+ } else {
lua_pushboolean(L, false);
- return 1;
}
- InventoryItem *item = InventoryItem::deSerialize(stackstring,
- get_server(L));
- if(list->roomForItem(item)){
- delete list->addItem(item);
- lua_pushboolean(L, true);
- reportInventoryChange(L, ref);
+ return 1;
+ }
+
+ // remove_item(self, listname, itemstack or itemstring or table or nil) -> itemstack
+ // Returns the items that were actually removed
+ static int l_remove_item(lua_State *L)
+ {
+ InvRef *ref = checkobject(L, 1);
+ const char *listname = luaL_checkstring(L, 2);
+ ItemStack item = read_item(L, 3);
+ InventoryList *list = getlist(L, ref, listname);
+ if(list){
+ ItemStack removed = list->removeItem(item);
+ if(!removed.empty())
+ reportInventoryChange(L, ref);
+ LuaItemStack::create(L, removed);
} else {
- delete item;
- lua_pushboolean(L, false);
+ LuaItemStack::create(L, ItemStack());
}
return 1;
}
@@ -1267,8 +1726,10 @@ const luaL_reg InvRef::methods[] = {
method(InvRef, set_stack),
method(InvRef, get_list),
method(InvRef, set_list),
- method(InvRef, autoinsert_stack),
- method(InvRef, autoinsert_stackstring),
+ method(InvRef, add_item),
+ method(InvRef, room_for_item),
+ method(InvRef, contains_item),
+ method(InvRef, remove_item),
{0,0}
};
@@ -1395,59 +1856,56 @@ private:
return 1;
}
- /* IGenericNodeMetadata interface */
-
- // set_infotext(self, text)
- static int l_set_infotext(lua_State *L)
+ // set_owner(self, string)
+ static int l_set_owner(lua_State *L)
{
NodeMetaRef *ref = checkobject(L, 1);
NodeMetadata *meta = getmeta(ref);
if(meta == NULL) return 0;
// Do it
- std::string text = luaL_checkstring(L, 2);
- meta->setInfoText(text);
+ std::string owner = luaL_checkstring(L, 2);
+ meta->setOwner(owner);
reportMetadataChange(ref);
- return 0;
+ return 1;
}
- // get_inventory(self)
- static int l_get_inventory(lua_State *L)
+ // get_allow_removal(self)
+ static int l_get_allow_removal(lua_State *L)
{
NodeMetaRef *ref = checkobject(L, 1);
NodeMetadata *meta = getmeta(ref);
- if(meta == NULL) return 0;
+ if(meta == NULL){
+ lua_pushboolean(L, true);
+ return 1;
+ }
// Do it
- InvRef::createNodeMeta(L, ref->m_p);
+ lua_pushboolean(L, !meta->nodeRemovalDisabled());
return 1;
}
- // deprecated: inventory_set_list(self, name, {item1, item2, ...})
- static int l_inventory_set_list(lua_State *L)
+ /* IGenericNodeMetadata interface */
+
+ // set_infotext(self, text)
+ static int l_set_infotext(lua_State *L)
{
- infostream<<"Deprecated: inventory_set_list"<<std::endl;
NodeMetaRef *ref = checkobject(L, 1);
NodeMetadata *meta = getmeta(ref);
if(meta == NULL) return 0;
// Do it
- Inventory *inv = meta->getInventory();
- const char *name = luaL_checkstring(L, 2);
- inventory_set_list_from_lua(inv, name, L, 3,
- ref->m_env->getGameDef());
+ std::string text = luaL_checkstring(L, 2);
+ meta->setInfoText(text);
reportMetadataChange(ref);
return 0;
}
- // deprecated: inventory_get_list(self, name)
- static int l_inventory_get_list(lua_State *L)
+ // get_inventory(self)
+ static int l_get_inventory(lua_State *L)
{
- infostream<<"Deprecated: inventory_get_list"<<std::endl;
NodeMetaRef *ref = checkobject(L, 1);
NodeMetadata *meta = getmeta(ref);
if(meta == NULL) return 0;
// Do it
- Inventory *inv = meta->getInventory();
- const char *name = luaL_checkstring(L, 2);
- inventory_get_list_to_lua(inv, name, L);
+ InvRef::createNodeMeta(L, ref->m_p);
return 1;
}
@@ -1635,10 +2093,10 @@ const luaL_reg NodeMetaRef::methods[] = {
method(NodeMetaRef, set_text),
method(NodeMetaRef, get_text),
method(NodeMetaRef, get_owner),
+ method(NodeMetaRef, set_owner),
+ method(NodeMetaRef, get_allow_removal),
method(NodeMetaRef, set_infotext),
method(NodeMetaRef, get_inventory),
- method(NodeMetaRef, inventory_set_list), // deprecated
- method(NodeMetaRef, inventory_get_list), // deprecated
method(NodeMetaRef, set_inventory_draw_spec),
method(NodeMetaRef, set_allow_text_input),
method(NodeMetaRef, set_allow_removal),
@@ -1799,122 +2257,98 @@ private:
return 0;
}
- // get_wield_digging_properties(self)
- static int l_get_wield_digging_properties(lua_State *L)
+ // set_hp(self, hp)
+ // hp = number of hitpoints (2 * number of hearts)
+ // returns: nil
+ static int l_set_hp(lua_State *L)
{
ObjectRef *ref = checkobject(L, 1);
+ luaL_checknumber(L, 2);
ServerActiveObject *co = getobject(ref);
if(co == NULL) return 0;
+ int hp = lua_tonumber(L, 2);
+ infostream<<"ObjectRef::l_set_hp(): id="<<co->getId()
+ <<" hp="<<hp<<std::endl;
// Do it
- ToolDiggingProperties prop;
- co->getWieldDiggingProperties(&prop);
- push_tool_digging_properties(L, prop);
+ co->setHP(hp);
+ // Return
+ return 0;
+ }
+
+ // get_hp(self)
+ // returns: number of hitpoints (2 * number of hearts)
+ // 0 if not applicable to this type of object
+ static int l_get_hp(lua_State *L)
+ {
+ ObjectRef *ref = checkobject(L, 1);
+ ServerActiveObject *co = getobject(ref);
+ if(co == NULL) return 0;
+ int hp = co->getHP();
+ infostream<<"ObjectRef::l_get_hp(): id="<<co->getId()
+ <<" hp="<<hp<<std::endl;
+ // Return
+ lua_pushnumber(L, hp);
return 1;
}
- // damage_wielded_item(self, amount)
- static int l_damage_wielded_item(lua_State *L)
+ // get_inventory(self)
+ static int l_get_inventory(lua_State *L)
{
ObjectRef *ref = checkobject(L, 1);
ServerActiveObject *co = getobject(ref);
if(co == NULL) return 0;
// Do it
- int amount = lua_tonumber(L, 2);
- co->damageWieldedItem(amount);
- return 0;
+ InventoryLocation loc = co->getInventoryLocation();
+ if(get_server(L)->getInventory(loc) != NULL)
+ InvRef::create(L, loc);
+ else
+ lua_pushnil(L);
+ return 1;
}
- // add_to_inventory(self, itemstring)
- // returns: true if item was added, (false, "reason") otherwise
- static int l_add_to_inventory(lua_State *L)
+ // get_wield_list(self)
+ static int l_get_wield_list(lua_State *L)
{
ObjectRef *ref = checkobject(L, 1);
- luaL_checkstring(L, 2);
ServerActiveObject *co = getobject(ref);
if(co == NULL) return 0;
- // itemstring
- const char *itemstring = luaL_checkstring(L, 2);
- infostream<<"ObjectRef::l_add_to_inventory(): id="<<co->getId()
- <<" itemstring=\""<<itemstring<<"\""<<std::endl;
// Do it
- std::istringstream is(itemstring, std::ios::binary);
- ServerEnvironment *env = co->getEnv();
- assert(env);
- IGameDef *gamedef = env->getGameDef();
- try{
- InventoryItem *item = InventoryItem::deSerialize(is, gamedef);
- if(item->getCount() == 0)
- item->setCount(1);
- bool added = co->addToInventory(item);
- // Return
- lua_pushboolean(L, added);
- if(!added)
- lua_pushstring(L, "failed to add item");
- return 2;
- } catch(SerializationError &e){
- // Return
- lua_pushboolean(L, false);
- lua_pushstring(L, (std::string("Invalid item: ")
- + e.what()).c_str());
- return 2;
- }
+ lua_pushstring(L, co->getWieldList().c_str());
+ return 1;
}
- // add_to_inventory_later(self, itemstring)
- // returns: nil
- static int l_add_to_inventory_later(lua_State *L)
+ // get_wield_index(self)
+ static int l_get_wield_index(lua_State *L)
{
ObjectRef *ref = checkobject(L, 1);
- luaL_checkstring(L, 2);
ServerActiveObject *co = getobject(ref);
if(co == NULL) return 0;
- // itemstring
- const char *itemstring = luaL_checkstring(L, 2);
- infostream<<"ObjectRef::l_add_to_inventory_later(): id="<<co->getId()
- <<" itemstring=\""<<itemstring<<"\""<<std::endl;
// Do it
- std::istringstream is(itemstring, std::ios::binary);
- ServerEnvironment *env = co->getEnv();
- assert(env);
- IGameDef *gamedef = env->getGameDef();
- InventoryItem *item = InventoryItem::deSerialize(is, gamedef);
- infostream<<"item="<<env<<std::endl;
- co->addToInventoryLater(item);
- // Return
- return 0;
+ lua_pushinteger(L, co->getWieldIndex() + 1);
+ return 1;
}
- // set_hp(self, hp)
- // hp = number of hitpoints (2 * number of hearts)
- // returns: nil
- static int l_set_hp(lua_State *L)
+ // get_wielded_item(self)
+ static int l_get_wielded_item(lua_State *L)
{
ObjectRef *ref = checkobject(L, 1);
- luaL_checknumber(L, 2);
ServerActiveObject *co = getobject(ref);
if(co == NULL) return 0;
- int hp = lua_tonumber(L, 2);
- infostream<<"ObjectRef::l_set_hp(): id="<<co->getId()
- <<" hp="<<hp<<std::endl;
// Do it
- co->setHP(hp);
- // Return
- return 0;
+ LuaItemStack::create(L, co->getWieldedItem());
+ return 1;
}
- // get_hp(self)
- // returns: number of hitpoints (2 * number of hearts)
- // 0 if not applicable to this type of object
- static int l_get_hp(lua_State *L)
+ // set_wielded_item(self, itemstack or itemstring or table or nil)
+ static int l_set_wielded_item(lua_State *L)
{
ObjectRef *ref = checkobject(L, 1);
ServerActiveObject *co = getobject(ref);
if(co == NULL) return 0;
- int hp = co->getHP();
- infostream<<"ObjectRef::l_get_hp(): id="<<co->getId()
- <<" hp="<<hp<<std::endl;
- // Return
- lua_pushnumber(L, hp);
+ // Do it
+ ItemStack item = read_item(L, 2);
+ bool success = co->setWieldedItem(item);
+ lua_pushboolean(L, success);
return 1;
}
@@ -2071,73 +2505,6 @@ private:
return 1;
}
- // get_inventory(self)
- static int l_get_inventory(lua_State *L)
- {
- ObjectRef *ref = checkobject(L, 1);
- ServerRemotePlayer *player = getplayer(ref);
- if(player == NULL) return 0;
- // Do it
- InvRef::createPlayer(L, player);
- return 1;
- }
-
- // deprecated: inventory_set_list(self, name, {item1, item2, ...})
- static int l_inventory_set_list(lua_State *L)
- {
- infostream<<"Deprecated: inventory_set_list"<<std::endl;
- ObjectRef *ref = checkobject(L, 1);
- ServerRemotePlayer *player = getplayer(ref);
- if(player == NULL) return 0;
- const char *name = luaL_checkstring(L, 2);
- // Do it
- inventory_set_list_from_lua(&player->inventory, name, L, 3,
- player->getEnv()->getGameDef(), PLAYER_INVENTORY_SIZE);
- player->m_inventory_not_sent = true;
- return 0;
- }
-
- // deprecated: inventory_get_list(self, name)
- static int l_inventory_get_list(lua_State *L)
- {
- infostream<<"Deprecated: inventory_get_list"<<std::endl;
- ObjectRef *ref = checkobject(L, 1);
- ServerRemotePlayer *player = getplayer(ref);
- if(player == NULL) return 0;
- const char *name = luaL_checkstring(L, 2);
- // Do it
- inventory_get_list_to_lua(&player->inventory, name, L);
- return 1;
- }
-
- // get_wielded_itemstring(self)
- static int l_get_wielded_itemstring(lua_State *L)
- {
- ObjectRef *ref = checkobject(L, 1);
- ServerRemotePlayer *player = getplayer(ref);
- if(player == NULL) return 0;
- // Do it
- InventoryItem *item = player->getWieldedItem();
- if(item == NULL){
- lua_pushnil(L);
- return 1;
- }
- lua_pushstring(L, item->getItemString().c_str());
- return 1;
- }
-
- // get_wielded_item(self)
- static int l_get_wielded_item(lua_State *L)
- {
- ObjectRef *ref = checkobject(L, 1);
- ServerRemotePlayer *player = getplayer(ref);
- if(player == NULL) return 0;
- // Do it
- InventoryItem *item0 = player->getWieldedItem();
- push_stack_item(L, item0);
- return 1;
- }
-
// get_look_dir(self)
static int l_get_look_dir(lua_State *L)
{
@@ -2300,12 +2667,13 @@ const luaL_reg ObjectRef::methods[] = {
method(ObjectRef, moveto),
method(ObjectRef, punch),
method(ObjectRef, right_click),
- method(ObjectRef, get_wield_digging_properties),
- method(ObjectRef, damage_wielded_item),
- method(ObjectRef, add_to_inventory),
- method(ObjectRef, add_to_inventory_later),
method(ObjectRef, set_hp),
method(ObjectRef, get_hp),
+ method(ObjectRef, get_inventory),
+ method(ObjectRef, get_wield_list),
+ method(ObjectRef, get_wield_index),
+ method(ObjectRef, get_wielded_item),
+ method(ObjectRef, set_wielded_item),
// LuaEntitySAO-only
method(ObjectRef, setvelocity),
method(ObjectRef, getvelocity),
@@ -2319,11 +2687,6 @@ const luaL_reg ObjectRef::methods[] = {
method(ObjectRef, get_luaentity),
// Player-only
method(ObjectRef, get_player_name),
- method(ObjectRef, get_inventory),
- method(ObjectRef, inventory_set_list), // deprecated
- method(ObjectRef, inventory_get_list), // deprecated
- method(ObjectRef, get_wielded_itemstring),
- method(ObjectRef, get_wielded_item),
method(ObjectRef, get_look_dir),
method(ObjectRef, get_look_pitch),
method(ObjectRef, get_look_yaw),
@@ -2467,7 +2830,7 @@ private:
}
}
- // EnvRef:add_entity(pos, entityname)
+ // EnvRef:add_entity(pos, entityname) -> ObjectRef or nil
// pos = {x=num, y=num, z=num}
static int l_add_entity(lua_State *L)
{
@@ -2490,22 +2853,29 @@ private:
return 1;
}
- // EnvRef:add_item(pos, inventorystring)
+ // EnvRef:add_item(pos, itemstack or itemstring or table) -> ObjectRef or nil
// pos = {x=num, y=num, z=num}
static int l_add_item(lua_State *L)
{
- infostream<<"EnvRef::l_add_item()"<<std::endl;
+ //infostream<<"EnvRef::l_add_item()"<<std::endl;
EnvRef *o = checkobject(L, 1);
ServerEnvironment *env = o->m_env;
if(env == NULL) return 0;
// pos
v3f pos = checkFloatPos(L, 2);
- // inventorystring
- const char *inventorystring = luaL_checkstring(L, 3);
+ // item
+ ItemStack item = read_item(L, 3);
+ if(item.empty() || !item.isKnown(get_server(L)->idef()))
+ return 0;
// Do it
- ServerActiveObject *obj = new ItemSAO(env, pos, inventorystring);
- env->addActiveObject(obj);
- return 0;
+ ServerActiveObject *obj = new ItemSAO(env, pos, item.getItemString());
+ int objectid = env->addActiveObject(obj);
+ // If failed to add, return nothing (reads as nil)
+ if(objectid == 0)
+ return 0;
+ // Return ObjectRef
+ objectref_get_or_create(L, obj);
+ return 1;
}
// EnvRef:add_rat(pos)
@@ -2631,6 +3001,38 @@ private:
return 1;
}
+ // EnvRef:set_timeofday(val)
+ // val = 0...1
+ static int l_set_timeofday(lua_State *L)
+ {
+ EnvRef *o = checkobject(L, 1);
+ ServerEnvironment *env = o->m_env;
+ if(env == NULL) return 0;
+ // Do it
+ float timeofday_f = luaL_checknumber(L, 2);
+ assert(timeofday_f >= 0.0 && timeofday_f <= 1.0);
+ int timeofday_mh = (int)(timeofday_f * 24000.0);
+ // This should be set directly in the environment but currently
+ // such changes aren't immediately sent to the clients, so call
+ // the server instead.
+ //env->setTimeOfDay(timeofday_mh);
+ get_server(L)->setTimeOfDay(timeofday_mh);
+ return 0;
+ }
+
+ // EnvRef:get_timeofday() -> 0...1
+ static int l_get_timeofday(lua_State *L)
+ {
+ EnvRef *o = checkobject(L, 1);
+ ServerEnvironment *env = o->m_env;
+ if(env == NULL) return 0;
+ // Do it
+ int timeofday_mh = env->getTimeOfDay();
+ float timeofday_f = (float)timeofday_mh / 24000.0;
+ lua_pushnumber(L, timeofday_f);
+ return 1;
+ }
+
static int gc_object(lua_State *L) {
EnvRef *o = *(EnvRef **)(lua_touserdata(L, 1));
delete o;
@@ -2709,6 +3111,8 @@ const luaL_reg EnvRef::methods[] = {
method(EnvRef, get_player_by_name),
method(EnvRef, get_objects_inside_radius),
method(EnvRef, get_nodes_inside_radius),
+ method(EnvRef, set_timeofday),
+ method(EnvRef, get_timeofday),
{0,0}
};
@@ -2716,55 +3120,6 @@ const luaL_reg EnvRef::methods[] = {
Global functions
*/
-static int l_register_nodedef_defaults(lua_State *L)
-{
- luaL_checktype(L, 1, LUA_TTABLE);
-
- lua_pushvalue(L, 1); // Explicitly put parameter 1 on top of stack
- lua_setfield(L, LUA_REGISTRYINDEX, "minetest_nodedef_default");
-
- return 0;
-}
-
-// Register new object prototype
-// register_entity(name, prototype)
-static int l_register_entity(lua_State *L)
-{
- std::string name = luaL_checkstring(L, 1);
- check_modname_prefix(L, name);
- //infostream<<"register_entity: "<<name<<std::endl;
- luaL_checktype(L, 2, LUA_TTABLE);
-
- // Get minetest.registered_entities
- lua_getglobal(L, "minetest");
- lua_getfield(L, -1, "registered_entities");
- luaL_checktype(L, -1, LUA_TTABLE);
- int registered_entities = lua_gettop(L);
- lua_pushvalue(L, 2); // Object = param 2 -> stack top
- // registered_entities[name] = object
- lua_setfield(L, registered_entities, name.c_str());
-
- // Get registered object to top of stack
- lua_pushvalue(L, 2);
-
- // Set name field
- lua_pushvalue(L, 1);
- lua_setfield(L, -2, "name");
-
- // Set __index to point to itself
- lua_pushvalue(L, -1);
- lua_setfield(L, -2, "__index");
-
- // Set metatable.__index = metatable
- luaL_getmetatable(L, "minetest.entity");
- lua_pushvalue(L, -1); // duplicate metatable
- lua_setfield(L, -2, "__index");
- // Set object metatable
- lua_setmetatable(L, -2);
-
- return 0; /* number of results */
-}
-
class LuaABM : public ActiveBlockModifier
{
private:
@@ -2838,454 +3193,318 @@ public:
}
};
-// register_abm({...})
-static int l_register_abm(lua_State *L)
+// debug(text)
+// Writes a line to dstream
+static int l_debug(lua_State *L)
{
- //infostream<<"register_abm"<<std::endl;
- luaL_checktype(L, 1, LUA_TTABLE);
-
- // Get minetest.registered_abms
- lua_getglobal(L, "minetest");
- lua_getfield(L, -1, "registered_abms");
- luaL_checktype(L, -1, LUA_TTABLE);
- int registered_abms = lua_gettop(L);
+ std::string text = lua_tostring(L, 1);
+ dstream << text << std::endl;
+ return 0;
+}
- int id = 1;
- // Find free id
- for(;;){
- lua_pushnumber(L, id);
- lua_gettable(L, registered_abms);
- if(lua_isnil(L, -1))
- break;
- lua_pop(L, 1);
- id++;
+// log([level,] text)
+// Writes a line to the logger.
+// The one-argument version logs to infostream.
+// The two-argument version accept a log level: error, action, info, or verbose.
+static int l_log(lua_State *L)
+{
+ std::string text;
+ LogMessageLevel level = LMT_INFO;
+ if(lua_isnone(L, 2))
+ {
+ text = lua_tostring(L, 1);
}
- lua_pop(L, 1);
-
- infostream<<"register_abm: id="<<id<<std::endl;
-
- // registered_abms[id] = spec
- lua_pushnumber(L, id);
- lua_pushvalue(L, 1);
- lua_settable(L, registered_abms);
-
- return 0; /* number of results */
+ else
+ {
+ std::string levelname = lua_tostring(L, 1);
+ text = lua_tostring(L, 2);
+ if(levelname == "error")
+ level = LMT_ERROR;
+ else if(levelname == "action")
+ level = LMT_ACTION;
+ else if(levelname == "verbose")
+ level = LMT_VERBOSE;
+ }
+ log_printline(level, text);
+ return 0;
}
-// register_tool(name, {lots of stuff})
-static int l_register_tool(lua_State *L)
+// register_item_raw({lots of stuff})
+static int l_register_item_raw(lua_State *L)
{
- std::string name = luaL_checkstring(L, 1);
- check_modname_prefix(L, name);
- //infostream<<"register_tool: "<<name<<std::endl;
- luaL_checktype(L, 2, LUA_TTABLE);
- int table = 2;
-
- // Get the writable tool definition manager from the server
- IWritableToolDefManager *tooldef =
- get_server(L)->getWritableToolDefManager();
-
- ToolDefinition def = read_tool_definition(L, table);
+ luaL_checktype(L, 1, LUA_TTABLE);
+ int table = 1;
- tooldef->registerTool(name, def);
- return 0; /* number of results */
-}
+ // Get the writable item and node definition managers from the server
+ IWritableItemDefManager *idef =
+ get_server(L)->getWritableItemDefManager();
+ IWritableNodeDefManager *ndef =
+ get_server(L)->getWritableNodeDefManager();
-// register_craftitem(name, {lots of stuff})
-static int l_register_craftitem(lua_State *L)
-{
- std::string name = luaL_checkstring(L, 1);
- check_modname_prefix(L, name);
- //infostream<<"register_craftitem: "<<name<<std::endl;
- luaL_checktype(L, 2, LUA_TTABLE);
- int table = 2;
-
- // Get the writable CraftItem definition manager from the server
- IWritableCraftItemDefManager *craftitemdef =
- get_server(L)->getWritableCraftItemDefManager();
-
- // Check if on_drop is defined
- lua_getfield(L, table, "on_drop");
- bool got_on_drop = !lua_isnil(L, -1);
- lua_pop(L, 1);
+ // Check if name is defined
+ lua_getfield(L, table, "name");
+ if(lua_isstring(L, -1)){
+ std::string name = lua_tostring(L, -1);
+ infostream<<"register_item_raw: "<<name<<std::endl;
+ } else {
+ throw LuaError(L, "register_item_raw: name is not defined or not a string");
+ }
// Check if on_use is defined
- lua_getfield(L, table, "on_use");
- bool got_on_use = !lua_isnil(L, -1);
- lua_pop(L, 1);
- CraftItemDefinition def;
-
- getstringfield(L, table, "image", def.imagename);
- getstringfield(L, table, "cookresult_itemstring", def.cookresult_item);
- getfloatfield(L, table, "furnace_cooktime", def.furnace_cooktime);
- getfloatfield(L, table, "furnace_burntime", def.furnace_burntime);
- def.usable = getboolfield_default(L, table, "usable", got_on_use);
- getboolfield(L, table, "liquids_pointable", def.liquids_pointable);
- def.dropcount = getintfield_default(L, table, "dropcount", def.dropcount);
- def.stack_max = getintfield_default(L, table, "stack_max", def.stack_max);
-
- // If an on_drop callback is defined, force dropcount to 1
- if (got_on_drop)
- def.dropcount = 1;
-
- // Register it
- craftitemdef->registerCraftItem(name, def);
+ // Read the item definition and register it
+ ItemDefinition def = read_item_definition(L, table);
+ idef->registerItem(def);
- lua_pushvalue(L, table);
- scriptapi_add_craftitem(L, name.c_str());
+ // Read the node definition (content features) and register it
+ if(def.type == ITEM_NODE)
+ {
+ ContentFeatures f = read_content_features(L, table);
+ ndef->set(f.name, f);
+ }
return 0; /* number of results */
}
-// register_node(name, {lots of stuff})
-static int l_register_node(lua_State *L)
+// register_alias_raw(name, convert_to_name)
+static int l_register_alias_raw(lua_State *L)
{
std::string name = luaL_checkstring(L, 1);
- check_modname_prefix(L, name);
- //infostream<<"register_node: "<<name<<std::endl;
- luaL_checktype(L, 2, LUA_TTABLE);
- int nodedef_table = 2;
-
- // Get the writable node definition manager from the server
- IWritableNodeDefManager *nodedef =
- get_server(L)->getWritableNodeDefManager();
-
- // Get default node definition from registry
- lua_getfield(L, LUA_REGISTRYINDEX, "minetest_nodedef_default");
- int nodedef_default = lua_gettop(L);
-
- /*
- Add to minetest.registered_nodes with default as metatable
- */
-
- // Get the node definition table given as parameter
- lua_pushvalue(L, nodedef_table);
-
- // Set __index to point to itself
- lua_pushvalue(L, -1);
- lua_setfield(L, -2, "__index");
-
- // Set nodedef_default as metatable for the definition
- lua_pushvalue(L, nodedef_default);
- lua_setmetatable(L, nodedef_table);
-
- // minetest.registered_nodes[name] = nodedef
- lua_getglobal(L, "minetest");
- lua_getfield(L, -1, "registered_nodes");
- luaL_checktype(L, -1, LUA_TTABLE);
- lua_pushstring(L, name.c_str());
- lua_pushvalue(L, nodedef_table);
- lua_settable(L, -3);
+ std::string convert_to = luaL_checkstring(L, 2);
- /*
- Create definition
- */
+ // Get the writable item definition manager from the server
+ IWritableItemDefManager *idef =
+ get_server(L)->getWritableItemDefManager();
- ContentFeatures f;
-
- // Default to getting the corresponding NodeItem when dug
- f.dug_item = std::string("NodeItem \"")+name+"\" 1";
+ idef->registerAlias(name, convert_to);
- // Default to unknown_block.png as all textures
- f.setAllTextures("unknown_block.png");
-
- /*
- Read definiton from Lua
- */
+ return 0; /* number of results */
+}
- f.name = name;
-
- /* Visual definition */
+// helper for register_craft
+static bool read_craft_recipe_shaped(lua_State *L, int index,
+ int &width, std::vector<std::string> &recipe)
+{
+ if(index < 0)
+ index = lua_gettop(L) + 1 + index;
- f.drawtype = (NodeDrawType)getenumfield(L, nodedef_table, "drawtype", es_DrawType,
- NDT_NORMAL);
- getfloatfield(L, nodedef_table, "visual_scale", f.visual_scale);
+ if(!lua_istable(L, index))
+ return false;
- lua_getfield(L, nodedef_table, "tile_images");
- if(lua_istable(L, -1)){
- int table = lua_gettop(L);
+ lua_pushnil(L);
+ int rowcount = 0;
+ while(lua_next(L, index) != 0){
+ int colcount = 0;
+ // key at index -2 and value at index -1
+ if(!lua_istable(L, -1))
+ return false;
+ int table2 = lua_gettop(L);
lua_pushnil(L);
- int i = 0;
- while(lua_next(L, table) != 0){
+ while(lua_next(L, table2) != 0){
// key at index -2 and value at index -1
- if(lua_isstring(L, -1))
- f.tname_tiles[i] = lua_tostring(L, -1);
- else
- f.tname_tiles[i] = "";
+ if(!lua_isstring(L, -1))
+ return false;
+ recipe.push_back(lua_tostring(L, -1));
// removes value, keeps key for next iteration
lua_pop(L, 1);
- i++;
- if(i==6){
- lua_pop(L, 1);
- break;
- }
+ colcount++;
}
- // Copy last value to all remaining textures
- if(i >= 1){
- std::string lastname = f.tname_tiles[i-1];
- while(i < 6){
- f.tname_tiles[i] = lastname;
- i++;
- }
- }
- }
- lua_pop(L, 1);
-
- getstringfield(L, nodedef_table, "inventory_image", f.tname_inventory);
-
- lua_getfield(L, nodedef_table, "special_materials");
- if(lua_istable(L, -1)){
- int table = lua_gettop(L);
- lua_pushnil(L);
- int i = 0;
- while(lua_next(L, table) != 0){
- // key at index -2 and value at index -1
- int smtable = lua_gettop(L);
- std::string tname = getstringfield_default(
- L, smtable, "image", "");
- bool backface_culling = getboolfield_default(
- L, smtable, "backface_culling", true);
- MaterialSpec mspec(tname, backface_culling);
- f.setSpecialMaterial(i, mspec);
- // removes value, keeps key for next iteration
- lua_pop(L, 1);
- i++;
- if(i==6){
- lua_pop(L, 1);
- break;
- }
+ if(rowcount == 0){
+ width = colcount;
+ } else {
+ if(colcount != width)
+ return false;
}
- }
- lua_pop(L, 1);
-
- f.alpha = getintfield_default(L, nodedef_table, "alpha", 255);
-
- /* Other stuff */
-
- lua_getfield(L, nodedef_table, "post_effect_color");
- if(!lua_isnil(L, -1))
- f.post_effect_color = readARGB8(L, -1);
- lua_pop(L, 1);
-
- f.param_type = (ContentParamType)getenumfield(L, nodedef_table, "paramtype",
- es_ContentParamType, CPT_NONE);
-
- // True for all ground-like things like stone and mud, false for eg. trees
- getboolfield(L, nodedef_table, "is_ground_content", f.is_ground_content);
- f.light_propagates = (f.param_type == CPT_LIGHT);
- warn_if_field_exists(L, nodedef_table, "light_propagates",
- "deprecated: determined from paramtype");
- getboolfield(L, nodedef_table, "sunlight_propagates", f.sunlight_propagates);
- // This is used for collision detection.
- // Also for general solidness queries.
- getboolfield(L, nodedef_table, "walkable", f.walkable);
- // Player can point to these
- getboolfield(L, nodedef_table, "pointable", f.pointable);
- // Player can dig these
- getboolfield(L, nodedef_table, "diggable", f.diggable);
- // Player can climb these
- getboolfield(L, nodedef_table, "climbable", f.climbable);
- // Player can build on these
- getboolfield(L, nodedef_table, "buildable_to", f.buildable_to);
- // If true, param2 is set to direction when placed. Used for torches.
- // NOTE: the direction format is quite inefficient and should be changed
- getboolfield(L, nodedef_table, "wall_mounted", f.wall_mounted);
- // Whether this content type often contains mineral.
- // Used for texture atlas creation.
- // Currently only enabled for CONTENT_STONE.
- getboolfield(L, nodedef_table, "often_contains_mineral", f.often_contains_mineral);
- // Inventory item string as which the node appears in inventory when dug.
- // Mineral overrides this.
- getstringfield(L, nodedef_table, "dug_item", f.dug_item);
- // Extra dug item and its rarity
- getstringfield(L, nodedef_table, "extra_dug_item", f.extra_dug_item);
- // Usual get interval for extra dug item
- getintfield(L, nodedef_table, "extra_dug_item_rarity", f.extra_dug_item_rarity);
- // Metadata name of node (eg. "furnace")
- getstringfield(L, nodedef_table, "metadata_name", f.metadata_name);
- // Whether the node is non-liquid, source liquid or flowing liquid
- f.liquid_type = (LiquidType)getenumfield(L, nodedef_table, "liquidtype",
- es_LiquidType, LIQUID_NONE);
- // If the content is liquid, this is the flowing version of the liquid.
- getstringfield(L, nodedef_table, "liquid_alternative_flowing",
- f.liquid_alternative_flowing);
- // If the content is liquid, this is the source version of the liquid.
- getstringfield(L, nodedef_table, "liquid_alternative_source",
- f.liquid_alternative_source);
- // Viscosity for fluid flow, ranging from 1 to 7, with
- // 1 giving almost instantaneous propagation and 7 being
- // the slowest possible
- f.liquid_viscosity = getintfield_default(L, nodedef_table,
- "liquid_viscosity", f.liquid_viscosity);
- // Amount of light the node emits
- f.light_source = getintfield_default(L, nodedef_table,
- "light_source", f.light_source);
- f.damage_per_second = getintfield_default(L, nodedef_table,
- "damage_per_second", f.damage_per_second);
-
- lua_getfield(L, nodedef_table, "selection_box");
- if(lua_istable(L, -1)){
- f.selection_box.type = (NodeBoxType)getenumfield(L, -1, "type",
- es_NodeBoxType, NODEBOX_REGULAR);
-
- lua_getfield(L, -1, "fixed");
- if(lua_istable(L, -1))
- f.selection_box.fixed = read_aabbox3df32(L, -1, BS);
- lua_pop(L, 1);
-
- lua_getfield(L, -1, "wall_top");
- if(lua_istable(L, -1))
- f.selection_box.wall_top = read_aabbox3df32(L, -1, BS);
- lua_pop(L, 1);
-
- lua_getfield(L, -1, "wall_bottom");
- if(lua_istable(L, -1))
- f.selection_box.wall_bottom = read_aabbox3df32(L, -1, BS);
- lua_pop(L, 1);
-
- lua_getfield(L, -1, "wall_side");
- if(lua_istable(L, -1))
- f.selection_box.wall_side = read_aabbox3df32(L, -1, BS);
+ // removes value, keeps key for next iteration
lua_pop(L, 1);
+ rowcount++;
}
- lua_pop(L, 1);
-
- lua_getfield(L, nodedef_table, "material");
- if(lua_istable(L, -1)){
- f.material.diggability = (Diggability)getenumfield(L, -1, "diggability",
- es_Diggability, DIGGABLE_NORMAL);
-
- getfloatfield(L, -1, "constant_time", f.material.constant_time);
- getfloatfield(L, -1, "weight", f.material.weight);
- getfloatfield(L, -1, "crackiness", f.material.crackiness);
- getfloatfield(L, -1, "crumbliness", f.material.crumbliness);
- getfloatfield(L, -1, "cuttability", f.material.cuttability);
- getfloatfield(L, -1, "flammability", f.material.flammability);
- }
- lua_pop(L, 1);
-
- getstringfield(L, nodedef_table, "cookresult_itemstring", f.cookresult_item);
- getfloatfield(L, nodedef_table, "furnace_cooktime", f.furnace_cooktime);
- getfloatfield(L, nodedef_table, "furnace_burntime", f.furnace_burntime);
-
- /*
- Register it
- */
-
- nodedef->set(name, f);
-
- return 0; /* number of results */
+ return width != 0;
}
-// alias_node(name, convert_to_name)
-static int l_alias_node(lua_State *L)
+// helper for register_craft
+static bool read_craft_recipe_shapeless(lua_State *L, int index,
+ std::vector<std::string> &recipe)
{
- std::string name = luaL_checkstring(L, 1);
- std::string convert_to = luaL_checkstring(L, 2);
-
- // Get the writable node definition manager from the server
- IWritableNodeDefManager *nodedef =
- get_server(L)->getWritableNodeDefManager();
-
- nodedef->setAlias(name, convert_to);
-
- return 0; /* number of results */
-}
-
-// alias_tool(name, convert_to_name)
-static int l_alias_tool(lua_State *L)
-{
- std::string name = luaL_checkstring(L, 1);
- std::string convert_to = luaL_checkstring(L, 2);
+ if(index < 0)
+ index = lua_gettop(L) + 1 + index;
- // Get the writable tool definition manager from the server
- IWritableToolDefManager *tooldef =
- get_server(L)->getWritableToolDefManager();
-
- tooldef->setAlias(name, convert_to);
+ if(!lua_istable(L, index))
+ return false;
- return 0; /* number of results */
+ lua_pushnil(L);
+ while(lua_next(L, index) != 0){
+ // key at index -2 and value at index -1
+ if(!lua_isstring(L, -1))
+ return false;
+ recipe.push_back(lua_tostring(L, -1));
+ // removes value, keeps key for next iteration
+ lua_pop(L, 1);
+ }
+ return true;
}
-// alias_craftitem(name, convert_to_name)
-static int l_alias_craftitem(lua_State *L)
+// helper for register_craft
+static bool read_craft_replacements(lua_State *L, int index,
+ CraftReplacements &replacements)
{
- std::string name = luaL_checkstring(L, 1);
- std::string convert_to = luaL_checkstring(L, 2);
+ if(index < 0)
+ index = lua_gettop(L) + 1 + index;
- // Get the writable CraftItem definition manager from the server
- IWritableCraftItemDefManager *craftitemdef =
- get_server(L)->getWritableCraftItemDefManager();
-
- craftitemdef->setAlias(name, convert_to);
+ if(!lua_istable(L, index))
+ return false;
- return 0; /* number of results */
+ lua_pushnil(L);
+ while(lua_next(L, index) != 0){
+ // key at index -2 and value at index -1
+ if(!lua_istable(L, -1))
+ return false;
+ lua_rawgeti(L, -1, 1);
+ if(!lua_isstring(L, -1))
+ return false;
+ std::string replace_from = lua_tostring(L, -1);
+ lua_pop(L, 1);
+ lua_rawgeti(L, -1, 2);
+ if(!lua_isstring(L, -1))
+ return false;
+ std::string replace_to = lua_tostring(L, -1);
+ lua_pop(L, 1);
+ replacements.pairs.push_back(
+ std::make_pair(replace_from, replace_to));
+ // removes value, keeps key for next iteration
+ lua_pop(L, 1);
+ }
+ return true;
}
-
// register_craft({output=item, recipe={{item00,item10},{item01,item11}})
static int l_register_craft(lua_State *L)
{
//infostream<<"register_craft"<<std::endl;
luaL_checktype(L, 1, LUA_TTABLE);
- int table0 = 1;
+ int table = 1;
// Get the writable craft definition manager from the server
IWritableCraftDefManager *craftdef =
get_server(L)->getWritableCraftDefManager();
- std::string output;
- int width = 0;
- std::vector<std::string> input;
-
- lua_getfield(L, table0, "output");
- luaL_checktype(L, -1, LUA_TSTRING);
- if(lua_isstring(L, -1))
- output = lua_tostring(L, -1);
- lua_pop(L, 1);
+ std::string type = getstringfield_default(L, table, "type", "shaped");
- lua_getfield(L, table0, "recipe");
- luaL_checktype(L, -1, LUA_TTABLE);
- if(lua_istable(L, -1)){
- int table1 = lua_gettop(L);
- lua_pushnil(L);
- int rowcount = 0;
- while(lua_next(L, table1) != 0){
- int colcount = 0;
- // key at index -2 and value at index -1
- luaL_checktype(L, -1, LUA_TTABLE);
- if(lua_istable(L, -1)){
- int table2 = lua_gettop(L);
- lua_pushnil(L);
- while(lua_next(L, table2) != 0){
- // key at index -2 and value at index -1
- luaL_checktype(L, -1, LUA_TSTRING);
- input.push_back(lua_tostring(L, -1));
- // removes value, keeps key for next iteration
- lua_pop(L, 1);
- colcount++;
- }
- }
- if(rowcount == 0){
- width = colcount;
- } else {
- if(colcount != width){
- std::string error;
- error += "Invalid crafting recipe (output=\""
- + output + "\")";
- throw LuaError(L, error);
- }
- }
- // removes value, keeps key for next iteration
- lua_pop(L, 1);
- rowcount++;
+ /*
+ CraftDefinitionShaped
+ */
+ if(type == "shaped"){
+ std::string output = getstringfield_default(L, table, "output", "");
+ if(output == "")
+ throw LuaError(L, "Crafting definition is missing an output");
+
+ int width = 0;
+ std::vector<std::string> recipe;
+ lua_getfield(L, table, "recipe");
+ if(lua_isnil(L, -1))
+ throw LuaError(L, "Crafting definition is missing a recipe"
+ " (output=\"" + output + "\")");
+ if(!read_craft_recipe_shaped(L, -1, width, recipe))
+ throw LuaError(L, "Invalid crafting recipe"
+ " (output=\"" + output + "\")");
+
+ CraftReplacements replacements;
+ lua_getfield(L, table, "replacements");
+ if(!lua_isnil(L, -1))
+ {
+ if(!read_craft_replacements(L, -1, replacements))
+ throw LuaError(L, "Invalid replacements"
+ " (output=\"" + output + "\")");
}
+
+ CraftDefinition *def = new CraftDefinitionShaped(
+ output, width, recipe, replacements);
+ craftdef->registerCraft(def);
}
- lua_pop(L, 1);
+ /*
+ CraftDefinitionShapeless
+ */
+ else if(type == "shapeless"){
+ std::string output = getstringfield_default(L, table, "output", "");
+ if(output == "")
+ throw LuaError(L, "Crafting definition (shapeless)"
+ " is missing an output");
+
+ std::vector<std::string> recipe;
+ lua_getfield(L, table, "recipe");
+ if(lua_isnil(L, -1))
+ throw LuaError(L, "Crafting definition (shapeless)"
+ " is missing a recipe"
+ " (output=\"" + output + "\")");
+ if(!read_craft_recipe_shapeless(L, -1, recipe))
+ throw LuaError(L, "Invalid crafting recipe"
+ " (output=\"" + output + "\")");
+
+ CraftReplacements replacements;
+ lua_getfield(L, table, "replacements");
+ if(!lua_isnil(L, -1))
+ {
+ if(!read_craft_replacements(L, -1, replacements))
+ throw LuaError(L, "Invalid replacements"
+ " (output=\"" + output + "\")");
+ }
- CraftDefinition def(output, width, input);
- craftdef->registerCraft(def);
+ CraftDefinition *def = new CraftDefinitionShapeless(
+ output, recipe, replacements);
+ craftdef->registerCraft(def);
+ }
+ /*
+ CraftDefinitionToolRepair
+ */
+ else if(type == "toolrepair"){
+ float additional_wear = getfloatfield_default(L, table,
+ "additional_wear", 0.0);
+
+ CraftDefinition *def = new CraftDefinitionToolRepair(
+ additional_wear);
+ craftdef->registerCraft(def);
+ }
+ /*
+ CraftDefinitionCooking
+ */
+ else if(type == "cooking"){
+ std::string output = getstringfield_default(L, table, "output", "");
+ if(output == "")
+ throw LuaError(L, "Crafting definition (cooking)"
+ " is missing an output");
+
+ std::string recipe = getstringfield_default(L, table, "recipe", "");
+ if(recipe == "")
+ throw LuaError(L, "Crafting definition (cooking)"
+ " is missing a recipe"
+ " (output=\"" + output + "\")");
+
+ float cooktime = getfloatfield_default(L, table, "cooktime", 3.0);
+
+ CraftDefinition *def = new CraftDefinitionCooking(
+ output, recipe, cooktime);
+ craftdef->registerCraft(def);
+ }
+ /*
+ CraftDefinitionFuel
+ */
+ else if(type == "fuel"){
+ std::string recipe = getstringfield_default(L, table, "recipe", "");
+ if(recipe == "")
+ throw LuaError(L, "Crafting definition (fuel)"
+ " is missing a recipe");
+
+ float burntime = getfloatfield_default(L, table, "burntime", 1.0);
+
+ CraftDefinition *def = new CraftDefinitionFuel(
+ recipe, burntime);
+ craftdef->registerCraft(def);
+ }
+ else
+ {
+ throw LuaError(L, "Unknown crafting definition type: \"" + type + "\"");
+ }
+ lua_pop(L, 1);
return 0; /* number of results */
}
@@ -3383,15 +3602,45 @@ static int l_get_inventory(lua_State *L)
return 1;
}
+// get_digging_properties(material_properties, tool_digging_properties[, time_from_last_punch])
+static int l_get_digging_properties(lua_State *L)
+{
+ MaterialProperties mp = read_material_properties(L, 1);
+ ToolDiggingProperties tp = read_tool_digging_properties(L, 2);
+ if(lua_isnoneornil(L, 3))
+ push_digging_properties(L, getDiggingProperties(&mp, &tp));
+ else
+ push_digging_properties(L, getDiggingProperties(&mp, &tp,
+ luaL_checknumber(L, 3)));
+ return 1;
+}
+
+// get_hitting_properties(material_properties, tool_digging_properties[, time_from_last_punch])
+static int l_get_hitting_properties(lua_State *L)
+{
+ MaterialProperties mp = read_material_properties(L, 1);
+ ToolDiggingProperties tp = read_tool_digging_properties(L, 2);
+ if(lua_isnoneornil(L, 3))
+ push_hitting_properties(L, getHittingProperties(&mp, &tp));
+ else
+ push_hitting_properties(L, getHittingProperties(&mp, &tp,
+ luaL_checknumber(L, 3)));
+ return 1;
+}
+
+// get_current_modname()
+static int l_get_current_modname(lua_State *L)
+{
+ lua_getfield(L, LUA_REGISTRYINDEX, "minetest_current_modname");
+ return 1;
+}
+
// get_modpath(modname)
static int l_get_modpath(lua_State *L)
{
const char *modname = luaL_checkstring(L, 1);
- // Get server from registry
- lua_getfield(L, LUA_REGISTRYINDEX, "minetest_server");
- Server *server = (Server*)lua_touserdata(L, -1);
// Do it
- const ModSpec *mod = server->getModSpec(modname);
+ const ModSpec *mod = get_server(L)->getModSpec(modname);
if(!mod){
lua_pushnil(L);
return 1;
@@ -3401,35 +3650,25 @@ static int l_get_modpath(lua_State *L)
}
static const struct luaL_Reg minetest_f [] = {
- {"register_nodedef_defaults", l_register_nodedef_defaults},
- {"register_entity", l_register_entity},
- {"register_tool", l_register_tool},
- {"register_craftitem", l_register_craftitem},
- {"register_node", l_register_node},
+ {"debug", l_debug},
+ {"log", l_log},
+ {"register_item_raw", l_register_item_raw},
+ {"register_alias_raw", l_register_alias_raw},
{"register_craft", l_register_craft},
- {"register_abm", l_register_abm},
- {"alias_node", l_alias_node},
- {"alias_tool", l_alias_tool},
- {"alias_craftitem", l_alias_craftitem},
{"setting_get", l_setting_get},
{"setting_getbool", l_setting_getbool},
{"chat_send_all", l_chat_send_all},
{"chat_send_player", l_chat_send_player},
{"get_player_privs", l_get_player_privs},
{"get_inventory", l_get_inventory},
+ {"get_digging_properties", l_get_digging_properties},
+ {"get_hitting_properties", l_get_hitting_properties},
+ {"get_current_modname", l_get_current_modname},
{"get_modpath", l_get_modpath},
{NULL, NULL}
};
/*
- LuaEntity functions
-*/
-
-static const struct luaL_Reg minetest_entity_m [] = {
- {NULL, NULL}
-};
-
-/*
Main export function
*/
@@ -3444,10 +3683,6 @@ void scriptapi_export(lua_State *L, Server *server)
lua_pushlightuserdata(L, server);
lua_setfield(L, LUA_REGISTRYINDEX, "minetest_server");
- // Store nil as minetest_nodedef_defaults in registry
- lua_pushnil(L);
- lua_setfield(L, LUA_REGISTRYINDEX, "minetest_nodedef_default");
-
// Register global functions in table minetest
lua_newtable(L);
luaL_register(L, NULL, minetest_f);
@@ -3459,30 +3694,12 @@ void scriptapi_export(lua_State *L, Server *server)
// Add tables to minetest
lua_newtable(L);
- lua_setfield(L, -2, "registered_nodes");
- lua_newtable(L);
- lua_setfield(L, -2, "registered_entities");
- lua_newtable(L);
- lua_setfield(L, -2, "registered_craftitems");
- lua_newtable(L);
- lua_setfield(L, -2, "registered_abms");
-
- lua_newtable(L);
lua_setfield(L, -2, "object_refs");
lua_newtable(L);
lua_setfield(L, -2, "luaentities");
- // Create entity prototype
- luaL_newmetatable(L, "minetest.entity");
- // metatable.__index = metatable
- lua_pushvalue(L, -1); // Duplicate metatable
- lua_setfield(L, -2, "__index");
- // Put functions in metatable
- luaL_register(L, NULL, minetest_entity_m);
- // Put other stuff in metatable
-
// Register wrappers
- ItemStack::Register(L);
+ LuaItemStack::Register(L);
InvRef::Register(L);
NodeMetaRef::Register(L);
ObjectRef::Register(L);
@@ -3763,6 +3980,8 @@ bool scriptapi_on_respawnplayer(lua_State *L, ServerActiveObject *player)
assert(lua_checkstack(L, 20));
StackUnroller stack_unroller(L);
+ dstream<<"player: "<<player<<" id: "<<player->getId()<<std::endl;
+
bool positioning_handled_by_some = false;
// Get minetest.registered_on_respawnplayers
@@ -3794,62 +4013,22 @@ void scriptapi_get_creative_inventory(lua_State *L, ServerRemotePlayer *player)
lua_getfield(L, -1, "creative_inventory");
luaL_checktype(L, -1, LUA_TTABLE);
inventory_set_list_from_lua(&player->inventory, "main", L, -1,
- player->getEnv()->getGameDef(), PLAYER_INVENTORY_SIZE);
+ PLAYER_INVENTORY_SIZE);
}
/*
- craftitem
+ item callbacks and node callbacks
*/
-static void pushPointedThing(lua_State *L, const PointedThing& pointed)
+// Retrieves minetest.registered_items[name][callbackname]
+// If that is nil or on error, return false and stack is unchanged
+// If that is a function, returns true and pushes the
+// function onto the stack
+static bool get_item_callback(lua_State *L,
+ const char *name, const char *callbackname)
{
- lua_newtable(L);
- if(pointed.type == POINTEDTHING_NODE)
- {
- lua_pushstring(L, "node");
- lua_setfield(L, -2, "type");
- push_v3s16(L, pointed.node_undersurface);
- lua_setfield(L, -2, "under");
- push_v3s16(L, pointed.node_abovesurface);
- lua_setfield(L, -2, "above");
- }
- else if(pointed.type == POINTEDTHING_OBJECT)
- {
- lua_pushstring(L, "object");
- lua_setfield(L, -2, "type");
- objectref_get(L, pointed.object_id);
- lua_setfield(L, -2, "ref");
- }
- else
- {
- lua_pushstring(L, "nothing");
- lua_setfield(L, -2, "type");
- }
-}
-
-void scriptapi_add_craftitem(lua_State *L, const char *name)
-{
- StackUnroller stack_unroller(L);
- assert(lua_gettop(L) > 0);
-
- // Set minetest.registered_craftitems[name] = table on top of stack
lua_getglobal(L, "minetest");
- lua_getfield(L, -1, "registered_craftitems");
- luaL_checktype(L, -1, LUA_TTABLE);
- lua_pushvalue(L, -3); // push another reference to the table to be registered
- lua_setfield(L, -2, name); // set minetest.registered_craftitems[name]
-}
-
-static bool get_craftitem_callback(lua_State *L, const char *name,
- const char *callbackname)
-{
- // Get minetest.registered_craftitems[name][callbackname]
- // If that is nil or on error, return false and stack is unchanged
- // If that is a function, returns true and pushes the
- // function onto the stack
-
- lua_getglobal(L, "minetest");
- lua_getfield(L, -1, "registered_craftitems");
+ lua_getfield(L, -1, "registered_items");
lua_remove(L, -2);
luaL_checktype(L, -1, LUA_TTABLE);
lua_getfield(L, -1, name);
@@ -3857,7 +4036,7 @@ static bool get_craftitem_callback(lua_State *L, const char *name,
// Should be a table
if(lua_type(L, -1) != LUA_TTABLE)
{
- errorstream<<"CraftItem name \""<<name<<"\" not defined"<<std::endl;
+ errorstream<<"Item \""<<name<<"\" not defined"<<std::endl;
lua_pop(L, 1);
return false;
}
@@ -3875,193 +4054,137 @@ static bool get_craftitem_callback(lua_State *L, const char *name,
}
else
{
- errorstream<<"CraftItem name \""<<name<<"\" callback \""
+ errorstream<<"Item \""<<name<<"\" callback \""
<<callbackname<<" is not a function"<<std::endl;
lua_pop(L, 1);
return false;
}
}
-bool scriptapi_craftitem_on_drop(lua_State *L, const char *name,
- ServerActiveObject *dropper, v3f pos,
- bool &callback_exists)
+bool scriptapi_item_on_drop(lua_State *L, ItemStack &item,
+ ServerActiveObject *dropper, v3f pos)
{
realitycheck(L);
assert(lua_checkstack(L, 20));
- //infostream<<"scriptapi_craftitem_on_drop"<<std::endl;
StackUnroller stack_unroller(L);
- bool result = false;
- callback_exists = get_craftitem_callback(L, name, "on_drop");
- if(callback_exists)
- {
- // Call function
- lua_pushstring(L, name);
- objectref_get_or_create(L, dropper);
- pushFloatPos(L, pos);
- if(lua_pcall(L, 3, 1, 0))
- script_error(L, "error: %s", lua_tostring(L, -1));
- result = lua_toboolean(L, -1);
- }
- return result;
+ // Push callback function on stack
+ if(!get_item_callback(L, item.name.c_str(), "on_drop"))
+ return false;
+
+ // Call function
+ LuaItemStack::create(L, item);
+ objectref_get_or_create(L, dropper);
+ pushFloatPos(L, pos);
+ if(lua_pcall(L, 3, 1, 0))
+ script_error(L, "error: %s", lua_tostring(L, -1));
+ if(!lua_isnil(L, -1))
+ item = read_item(L, -1);
+ return true;
}
-bool scriptapi_craftitem_on_place_on_ground(lua_State *L, const char *name,
- ServerActiveObject *placer, v3f pos,
- bool &callback_exists)
+bool scriptapi_item_on_place(lua_State *L, ItemStack &item,
+ ServerActiveObject *placer, const PointedThing &pointed)
{
realitycheck(L);
assert(lua_checkstack(L, 20));
- //infostream<<"scriptapi_craftitem_on_place_on_ground"<<std::endl;
StackUnroller stack_unroller(L);
- bool result = false;
- callback_exists = get_craftitem_callback(L, name, "on_place_on_ground");
- if(callback_exists)
- {
- // Call function
- lua_pushstring(L, name);
- objectref_get_or_create(L, placer);
- pushFloatPos(L, pos);
- if(lua_pcall(L, 3, 1, 0))
- script_error(L, "error: %s", lua_tostring(L, -1));
- result = lua_toboolean(L, -1);
- }
- return result;
+ // Push callback function on stack
+ if(!get_item_callback(L, item.name.c_str(), "on_place"))
+ return false;
+
+ // Call function
+ LuaItemStack::create(L, item);
+ objectref_get_or_create(L, placer);
+ push_pointed_thing(L, pointed);
+ if(lua_pcall(L, 3, 1, 0))
+ script_error(L, "error: %s", lua_tostring(L, -1));
+ if(!lua_isnil(L, -1))
+ item = read_item(L, -1);
+ return true;
}
-bool scriptapi_craftitem_on_use(lua_State *L, const char *name,
- ServerActiveObject *user, const PointedThing& pointed,
- bool &callback_exists)
+bool scriptapi_item_on_use(lua_State *L, ItemStack &item,
+ ServerActiveObject *user, const PointedThing &pointed)
{
realitycheck(L);
assert(lua_checkstack(L, 20));
- //infostream<<"scriptapi_craftitem_on_use"<<std::endl;
StackUnroller stack_unroller(L);
- bool result = false;
- callback_exists = get_craftitem_callback(L, name, "on_use");
- if(callback_exists)
- {
- // Call function
- lua_pushstring(L, name);
- objectref_get_or_create(L, user);
- pushPointedThing(L, pointed);
- if(lua_pcall(L, 3, 1, 0))
- script_error(L, "error: %s", lua_tostring(L, -1));
- result = lua_toboolean(L, -1);
- }
- return result;
-}
+ // Push callback function on stack
+ if(!get_item_callback(L, item.name.c_str(), "on_use"))
+ return false;
-/*
- environment
-*/
+ // Call function
+ LuaItemStack::create(L, item);
+ objectref_get_or_create(L, user);
+ push_pointed_thing(L, pointed);
+ if(lua_pcall(L, 3, 1, 0))
+ script_error(L, "error: %s", lua_tostring(L, -1));
+ if(!lua_isnil(L, -1))
+ item = read_item(L, -1);
+ return true;
+}
-void scriptapi_environment_step(lua_State *L, float dtime)
+bool scriptapi_node_on_punch(lua_State *L, v3s16 pos, MapNode node,
+ ServerActiveObject *puncher)
{
realitycheck(L);
assert(lua_checkstack(L, 20));
- //infostream<<"scriptapi_environment_step"<<std::endl;
StackUnroller stack_unroller(L);
- // Get minetest.registered_globalsteps
- lua_getglobal(L, "minetest");
- lua_getfield(L, -1, "registered_globalsteps");
- luaL_checktype(L, -1, LUA_TTABLE);
- int table = lua_gettop(L);
- // Foreach
- lua_pushnil(L);
- while(lua_next(L, table) != 0){
- // key at index -2 and value at index -1
- luaL_checktype(L, -1, LUA_TFUNCTION);
- // Call function
- lua_pushnumber(L, dtime);
- if(lua_pcall(L, 1, 0, 0))
- script_error(L, "error: %s", lua_tostring(L, -1));
- // value removed, keep key for next iteration
- }
-}
+ INodeDefManager *ndef = get_server(L)->ndef();
-void scriptapi_environment_on_placenode(lua_State *L, v3s16 p, MapNode newnode,
- ServerActiveObject *placer)
-{
- realitycheck(L);
- assert(lua_checkstack(L, 20));
- //infostream<<"scriptapi_environment_on_placenode"<<std::endl;
- StackUnroller stack_unroller(L);
+ // Push callback function on stack
+ if(!get_item_callback(L, ndef->get(node).name.c_str(), "on_punch"))
+ return false;
- // Get the writable node definition manager from the server
- IWritableNodeDefManager *ndef =
- get_server(L)->getWritableNodeDefManager();
-
- // Get minetest.registered_on_placenodes
- lua_getglobal(L, "minetest");
- lua_getfield(L, -1, "registered_on_placenodes");
- luaL_checktype(L, -1, LUA_TTABLE);
- int table = lua_gettop(L);
- // Foreach
- lua_pushnil(L);
- while(lua_next(L, table) != 0){
- // key at index -2 and value at index -1
- luaL_checktype(L, -1, LUA_TFUNCTION);
- // Call function
- push_v3s16(L, p);
- pushnode(L, newnode, ndef);
- objectref_get_or_create(L, placer);
- if(lua_pcall(L, 3, 0, 0))
- script_error(L, "error: %s", lua_tostring(L, -1));
- // value removed, keep key for next iteration
- }
+ // Call function
+ push_v3s16(L, pos);
+ pushnode(L, node, ndef);
+ objectref_get_or_create(L, puncher);
+ if(lua_pcall(L, 3, 0, 0))
+ script_error(L, "error: %s", lua_tostring(L, -1));
+ return true;
}
-void scriptapi_environment_on_dignode(lua_State *L, v3s16 p, MapNode oldnode,
+bool scriptapi_node_on_dig(lua_State *L, v3s16 pos, MapNode node,
ServerActiveObject *digger)
{
realitycheck(L);
assert(lua_checkstack(L, 20));
- //infostream<<"scriptapi_environment_on_dignode"<<std::endl;
StackUnroller stack_unroller(L);
- // Get the writable node definition manager from the server
- IWritableNodeDefManager *ndef =
- get_server(L)->getWritableNodeDefManager();
-
- // Get minetest.registered_on_dignodes
- lua_getglobal(L, "minetest");
- lua_getfield(L, -1, "registered_on_dignodes");
- luaL_checktype(L, -1, LUA_TTABLE);
- int table = lua_gettop(L);
- // Foreach
- lua_pushnil(L);
- while(lua_next(L, table) != 0){
- // key at index -2 and value at index -1
- luaL_checktype(L, -1, LUA_TFUNCTION);
- // Call function
- push_v3s16(L, p);
- pushnode(L, oldnode, ndef);
- objectref_get_or_create(L, digger);
- if(lua_pcall(L, 3, 0, 0))
- script_error(L, "error: %s", lua_tostring(L, -1));
- // value removed, keep key for next iteration
- }
+ INodeDefManager *ndef = get_server(L)->ndef();
+
+ // Push callback function on stack
+ if(!get_item_callback(L, ndef->get(node).name.c_str(), "on_dig"))
+ return false;
+
+ // Call function
+ push_v3s16(L, pos);
+ pushnode(L, node, ndef);
+ objectref_get_or_create(L, digger);
+ if(lua_pcall(L, 3, 0, 0))
+ script_error(L, "error: %s", lua_tostring(L, -1));
+ return true;
}
-void scriptapi_environment_on_punchnode(lua_State *L, v3s16 p, MapNode node,
- ServerActiveObject *puncher)
+/*
+ environment
+*/
+
+void scriptapi_environment_step(lua_State *L, float dtime)
{
realitycheck(L);
assert(lua_checkstack(L, 20));
- //infostream<<"scriptapi_environment_on_punchnode"<<std::endl;
+ //infostream<<"scriptapi_environment_step"<<std::endl;
StackUnroller stack_unroller(L);
- // Get the writable node definition manager from the server
- IWritableNodeDefManager *ndef =
- get_server(L)->getWritableNodeDefManager();
-
- // Get minetest.registered_on_punchnodes
+ // Get minetest.registered_globalsteps
lua_getglobal(L, "minetest");
- lua_getfield(L, -1, "registered_on_punchnodes");
+ lua_getfield(L, -1, "registered_globalsteps");
luaL_checktype(L, -1, LUA_TTABLE);
int table = lua_gettop(L);
// Foreach
@@ -4070,10 +4193,8 @@ void scriptapi_environment_on_punchnode(lua_State *L, v3s16 p, MapNode node,
// key at index -2 and value at index -1
luaL_checktype(L, -1, LUA_TFUNCTION);
// Call function
- push_v3s16(L, p);
- pushnode(L, node, ndef);
- objectref_get_or_create(L, puncher);
- if(lua_pcall(L, 3, 0, 0))
+ lua_pushnumber(L, dtime);
+ if(lua_pcall(L, 1, 0, 0))
script_error(L, "error: %s", lua_tostring(L, -1));
// value removed, keep key for next iteration
}
diff --git a/src/scriptapi.h b/src/scriptapi.h
index af8afa3d9..df8ae344e 100644
--- a/src/scriptapi.h
+++ b/src/scriptapi.h
@@ -27,11 +27,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
class Server;
class ServerEnvironment;
class ServerActiveObject;
+class ServerRemotePlayer;
typedef struct lua_State lua_State;
struct LuaEntityProperties;
+struct ItemStack;
struct PointedThing;
//class IGameDef;
-class ServerRemotePlayer;
void scriptapi_export(lua_State *L, Server *server);
bool scriptapi_loadmod(lua_State *L, const std::string &scriptpath,
@@ -48,15 +49,6 @@ bool scriptapi_on_chat_message(lua_State *L, const std::string &name,
/* environment */
// On environment step
void scriptapi_environment_step(lua_State *L, float dtime);
-// After adding node
-void scriptapi_environment_on_placenode(lua_State *L, v3s16 p, MapNode newnode,
- ServerActiveObject *placer);
-// After removing node
-void scriptapi_environment_on_dignode(lua_State *L, v3s16 p, MapNode oldnode,
- ServerActiveObject *digger);
-// When punching node
-void scriptapi_environment_on_punchnode(lua_State *L, v3s16 p, MapNode node,
- ServerActiveObject *puncher);
// After generating a piece of map
void scriptapi_environment_on_generated(lua_State *L, v3s16 minp, v3s16 maxp);
@@ -66,17 +58,19 @@ void scriptapi_on_dieplayer(lua_State *L, ServerActiveObject *player);
bool scriptapi_on_respawnplayer(lua_State *L, ServerActiveObject *player);
void scriptapi_get_creative_inventory(lua_State *L, ServerRemotePlayer *player);
-/* craftitem */
-void scriptapi_add_craftitem(lua_State *L, const char *name);
-bool scriptapi_craftitem_on_drop(lua_State *L, const char *name,
- ServerActiveObject *dropper, v3f pos,
- bool &callback_exists);
-bool scriptapi_craftitem_on_place_on_ground(lua_State *L, const char *name,
- ServerActiveObject *placer, v3f pos,
- bool &callback_exists);
-bool scriptapi_craftitem_on_use(lua_State *L, const char *name,
- ServerActiveObject *user, const PointedThing& pointed,
- bool &callback_exists);
+/* item callbacks */
+bool scriptapi_item_on_drop(lua_State *L, ItemStack &item,
+ ServerActiveObject *dropper, v3f pos);
+bool scriptapi_item_on_place(lua_State *L, ItemStack &item,
+ ServerActiveObject *placer, const PointedThing &pointed);
+bool scriptapi_item_on_use(lua_State *L, ItemStack &item,
+ ServerActiveObject *user, const PointedThing &pointed);
+
+/* node callbacks */
+bool scriptapi_node_on_punch(lua_State *L, v3s16 p, MapNode node,
+ ServerActiveObject *puncher);
+bool scriptapi_node_on_dig(lua_State *L, v3s16 p, MapNode node,
+ ServerActiveObject *digger);
/* luaentity */
// Returns true if succesfully added into Lua; false otherwise.
diff --git a/src/serialization.h b/src/serialization.h
index cc4381155..bcfea451a 100644
--- a/src/serialization.h
+++ b/src/serialization.h
@@ -57,11 +57,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
19: new content type handling
20: many existing content types translated to extended ones
21: dynamic content type allocation
+ 22: full 16-bit content types, minerals removed, facedir & wallmounted changed
*/
// This represents an uninitialized or invalid format
#define SER_FMT_VER_INVALID 255
// Highest supported serialization version
-#define SER_FMT_VER_HIGHEST 21
+#define SER_FMT_VER_HIGHEST 22
// Lowest supported serialization version
#define SER_FMT_VER_LOWEST 0
diff --git a/src/server.cpp b/src/server.cpp
index d704bf861..a0c8a0092 100644
--- a/src/server.cpp
+++ b/src/server.cpp
@@ -28,7 +28,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "constants.h"
#include "voxel.h"
#include "materials.h"
-#include "mineral.h"
#include "config.h"
#include "servercommand.h"
#include "filesys.h"
@@ -42,9 +41,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "script.h"
#include "scriptapi.h"
#include "nodedef.h"
-#include "tooldef.h"
+#include "itemdef.h"
#include "craftdef.h"
-#include "craftitemdef.h"
#include "mapgen.h"
#include "content_abm.h"
#include "mods.h"
@@ -853,10 +851,9 @@ Server::Server(
m_authmanager(mapsavedir+DIR_DELIM+"auth.txt"),
m_banmanager(mapsavedir+DIR_DELIM+"ipban.txt"),
m_lua(NULL),
- m_toolmgr(createToolDefManager()),
+ m_itemdef(createItemDefManager()),
m_nodedef(createNodeDefManager()),
m_craftdef(createCraftDefManager()),
- m_craftitemdef(createCraftItemDefManager()),
m_thread(this),
m_emergethread(this),
m_time_counter(0),
@@ -934,6 +931,9 @@ Server::Server(
// Read Textures and calculate sha1 sums
PrepareTextures();
+ // Apply item aliases in the node definition manager
+ m_nodedef->updateAliases(m_itemdef);
+
// Initialize Environment
m_env = new ServerEnvironment(new ServerMap(mapsavedir, this), m_lua,
@@ -1042,10 +1042,9 @@ Server::~Server()
// Delete Environment
delete m_env;
- delete m_toolmgr;
+ delete m_itemdef;
delete m_nodedef;
delete m_craftdef;
- delete m_craftitemdef;
// Deinitialize scripting
infostream<<"Server: Deinitializing scripting"<<std::endl;
@@ -2106,15 +2105,12 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
Send some initialization data
*/
- // Send tool definitions
- SendToolDef(m_con, peer_id, m_toolmgr);
+ // Send item definitions
+ SendItemDef(m_con, peer_id, m_itemdef);
// Send node definitions
SendNodeDef(m_con, peer_id, m_nodedef);
- // Send CraftItem definitions
- SendCraftItemDef(m_con, peer_id, m_craftitemdef);
-
// Send texture announcement
SendTextureAnnouncement(peer_id);
@@ -2362,13 +2358,6 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
}
else if(command == TOSERVER_INVENTORY_ACTION)
{
- /*// Ignore inventory changes if in creative mode
- if(g_settings->getBool("creative_mode") == true)
- {
- infostream<<"TOSERVER_INVENTORY_ACTION: ignoring in creative mode"
- <<std::endl;
- return;
- }*/
// Strip command and create a stream
std::string datastring((char*)&data[2], datasize-2);
infostream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
@@ -2382,179 +2371,92 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
<<std::endl;
return;
}
- // Create context
- InventoryContext c;
- c.current_player = player;
+
+ /*
+ Note: Always set inventory not sent, to repair cases
+ where the client made a bad prediction.
+ */
/*
Handle restrictions and special cases of the move action
*/
- if(a->getType() == IACTION_MOVE
- && g_settings->getBool("creative_mode") == false)
+ if(a->getType() == IACTION_MOVE)
{
- InventoryList *rlist = player->inventory.getList("craftresult");
- assert(rlist);
- InventoryList *clist = player->inventory.getList("craft");
- assert(clist);
- InventoryList *mlist = player->inventory.getList("main");
- assert(mlist);
-
IMoveAction *ma = (IMoveAction*)a;
+ ma->from_inv.applyCurrentPlayer(player->getName());
+ ma->to_inv.applyCurrentPlayer(player->getName());
+
+ setInventoryModified(ma->from_inv);
+ setInventoryModified(ma->to_inv);
+
+ bool from_inv_is_current_player =
+ (ma->from_inv.type == InventoryLocation::PLAYER) &&
+ (ma->from_inv.name == player->getName());
+
+ bool to_inv_is_current_player =
+ (ma->to_inv.type == InventoryLocation::PLAYER) &&
+ (ma->to_inv.name == player->getName());
+
/*
- Disable moving items into craftresult from elsewhere
+ Disable moving items out of craftpreview
*/
- if(ma->to_inv == "current_player"
- && ma->to_list == "craftresult"
- && (ma->from_inv != "current_player"
- || ma->from_list != "craftresult"))
+ if(ma->from_list == "craftpreview")
{
infostream<<"Ignoring IMoveAction from "
- <<ma->from_inv<<":"<<ma->from_list
- <<" to "<<ma->to_inv<<":"<<ma->to_list
- <<" because dst is craftresult"
- <<" and src isn't craftresult"<<std::endl;
+ <<(ma->from_inv.dump())<<":"<<ma->from_list
+ <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
+ <<" because src is "<<ma->from_list<<std::endl;
delete a;
return;
}
/*
- Handle crafting (source is craftresult, which is preview)
+ Disable moving items into craftresult and craftpreview
*/
- if(ma->from_inv == "current_player"
- && ma->from_list == "craftresult"
- && player->craftresult_is_preview)
+ if(ma->to_list == "craftpreview" || ma->to_list == "craftresult")
{
- /*
- If the craftresult is placed on itself, crafting takes
- place and result is moved into main list
- */
- if(ma->to_inv == "current_player"
- && ma->to_list == "craftresult")
- {
- // Except if main list doesn't have free slots
- if(mlist->getFreeSlots() == 0){
- infostream<<"Cannot craft: Main list doesn't have"
- <<" free slots"<<std::endl;
- delete a;
- return;
- }
-
- player->craftresult_is_preview = false;
- clist->decrementMaterials(1);
-
- InventoryItem *item1 = rlist->changeItem(0, NULL);
- mlist->addItem(item1);
-
- srp->m_inventory_not_sent = true;
-
- delete a;
- return;
- }
- /*
- Disable action if there are no free slots in
- destination
-
- If the item is placed on an item that is not of the
- same kind, the existing item will be first moved to
- craftresult and immediately moved to the free slot.
- */
- do{
- Inventory *inv_to = InventoryManager::getInventory(&c, ma->to_inv);
- if(!inv_to) break;
- InventoryList *list_to = inv_to->getList(ma->to_list);
- if(!list_to) break;
- if(list_to->getFreeSlots() == 0){
- infostream<<"Cannot craft: Destination doesn't have"
- <<" free slots"<<std::endl;
- delete a;
- return;
- }
- }while(0); // Allow break
-
- /*
- Ok, craft normally.
- */
- player->craftresult_is_preview = false;
- clist->decrementMaterials(1);
-
- /* Print out action */
- InventoryItem *item = rlist->getItem(0);
- std::string itemstring = "NULL";
- if(item)
- itemstring = item->getItemString();
- actionstream<<player->getName()<<" crafts "
- <<itemstring<<std::endl;
-
- // Do the action
- a->apply(&c, this, m_env);
-
+ infostream<<"Ignoring IMoveAction from "
+ <<(ma->from_inv.dump())<<":"<<ma->from_list
+ <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
+ <<" because dst is "<<ma->to_list<<std::endl;
delete a;
return;
}
- /*
- Non-crafting move
- */
-
// Disallow moving items in elsewhere than player's inventory
- // if not allowed to build
+ // if not allowed to interact
if((getPlayerPrivs(player) & PRIV_INTERACT) == 0
- && (ma->from_inv != "current_player"
- || ma->to_inv != "current_player"))
+ && (!from_inv_is_current_player
+ || !to_inv_is_current_player))
{
infostream<<"Cannot move outside of player's inventory: "
- <<"No build privilege"<<std::endl;
+ <<"No interact privilege"<<std::endl;
delete a;
return;
}
- // If player is not an admin, check for ownership of src
- if(ma->from_inv != "current_player"
- && (getPlayerPrivs(player) & PRIV_SERVER) == 0)
+ // If player is not an admin, check for ownership of src and dst
+ if((getPlayerPrivs(player) & PRIV_SERVER) == 0)
{
- Strfnd fn(ma->from_inv);
- std::string id0 = fn.next(":");
- if(id0 == "nodemeta")
+ std::string owner_from = getInventoryOwner(ma->from_inv);
+ if(owner_from != "" && owner_from != player->getName())
{
- v3s16 p;
- p.X = stoi(fn.next(","));
- p.Y = stoi(fn.next(","));
- p.Z = stoi(fn.next(","));
- NodeMetadata *meta = m_env->getMap().getNodeMetadata(p);
- if(meta->getOwner() != "" &&
- meta->getOwner() != player->getName())
- {
- infostream<<"Cannot move item: "
- "not owner of metadata"
- <<std::endl;
- delete a;
- return;
- }
+ infostream<<"WARNING: "<<player->getName()
+ <<" tried to access an inventory that"
+ <<" belongs to "<<owner_from<<std::endl;
+ delete a;
+ return;
}
- }
- // If player is not an admin, check for ownership of dst
- if(ma->to_inv != "current_player"
- && (getPlayerPrivs(player) & PRIV_SERVER) == 0)
- {
- Strfnd fn(ma->to_inv);
- std::string id0 = fn.next(":");
- if(id0 == "nodemeta")
+
+ std::string owner_to = getInventoryOwner(ma->to_inv);
+ if(owner_to != "" && owner_to != player->getName())
{
- v3s16 p;
- p.X = stoi(fn.next(","));
- p.Y = stoi(fn.next(","));
- p.Z = stoi(fn.next(","));
- NodeMetadata *meta = m_env->getMap().getNodeMetadata(p);
- if(meta->getOwner() != "" &&
- meta->getOwner() != player->getName())
- {
- infostream<<"Cannot move item: "
- "not owner of metadata"
- <<std::endl;
- delete a;
- return;
- }
+ infostream<<"WARNING: "<<player->getName()
+ <<" tried to access an inventory that"
+ <<" belongs to "<<owner_to<<std::endl;
+ delete a;
+ return;
}
}
}
@@ -2564,40 +2466,72 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
else if(a->getType() == IACTION_DROP)
{
IDropAction *da = (IDropAction*)a;
- // Disallow dropping items if not allowed to build
+
+ da->from_inv.applyCurrentPlayer(player->getName());
+
+ setInventoryModified(da->from_inv);
+
+ // Disallow dropping items if not allowed to interact
if((getPlayerPrivs(player) & PRIV_INTERACT) == 0)
{
delete a;
return;
}
// If player is not an admin, check for ownership
- else if (da->from_inv != "current_player"
- && (getPlayerPrivs(player) & PRIV_SERVER) == 0)
+ else if((getPlayerPrivs(player) & PRIV_SERVER) == 0)
{
- Strfnd fn(da->from_inv);
- std::string id0 = fn.next(":");
- if(id0 == "nodemeta")
+ std::string owner_from = getInventoryOwner(da->from_inv);
+ if(owner_from != "" && owner_from != player->getName())
{
- v3s16 p;
- p.X = stoi(fn.next(","));
- p.Y = stoi(fn.next(","));
- p.Z = stoi(fn.next(","));
- NodeMetadata *meta = m_env->getMap().getNodeMetadata(p);
- if(meta->getOwner() != "" &&
- meta->getOwner() != player->getName())
- {
- infostream<<"Cannot move item: "
- "not owner of metadata"
- <<std::endl;
- delete a;
- return;
- }
+ infostream<<"WARNING: "<<player->getName()
+ <<" tried to access an inventory that"
+ <<" belongs to "<<owner_from<<std::endl;
+ delete a;
+ return;
+ }
+ }
+ }
+ /*
+ Handle restrictions and special cases of the craft action
+ */
+ else if(a->getType() == IACTION_CRAFT)
+ {
+ ICraftAction *ca = (ICraftAction*)a;
+
+ ca->craft_inv.applyCurrentPlayer(player->getName());
+
+ setInventoryModified(ca->craft_inv);
+
+ //bool craft_inv_is_current_player =
+ // (ca->craft_inv.type == InventoryLocation::PLAYER) &&
+ // (ca->craft_inv.name == player->getName());
+
+ // Disallow crafting if not allowed to interact
+ if((getPlayerPrivs(player) & PRIV_INTERACT) == 0)
+ {
+ infostream<<"Cannot craft: "
+ <<"No interact privilege"<<std::endl;
+ delete a;
+ return;
+ }
+
+ // If player is not an admin, check for ownership of inventory
+ if((getPlayerPrivs(player) & PRIV_SERVER) == 0)
+ {
+ std::string owner_craft = getInventoryOwner(ca->craft_inv);
+ if(owner_craft != "" && owner_craft != player->getName())
+ {
+ infostream<<"WARNING: "<<player->getName()
+ <<" tried to access an inventory that"
+ <<" belongs to "<<owner_craft<<std::endl;
+ delete a;
+ return;
}
}
}
// Do the action
- a->apply(&c, this, m_env);
+ a->apply(this, srp, this);
// Eat the action
delete a;
}
@@ -2809,8 +2743,8 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
return;
u16 item = readU16(&data[2]);
- player->wieldItem(item);
- SendWieldedItem(player);
+ srp->setWieldIndex(item);
+ SendWieldedItem(srp);
}
else if(command == TOSERVER_RESPAWN)
{
@@ -2880,7 +2814,11 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
v3f player_pos = srp->m_last_good_position;
// Update wielded item
- srp->wieldItem(item_i);
+ if(srp->getWieldIndex() != item_i)
+ {
+ srp->setWieldIndex(item_i);
+ SendWieldedItem(srp);
+ }
// Get pointed to node (undefined if not POINTEDTYPE_NODE)
v3s16 p_under = pointed.node_undersurface;
@@ -2900,23 +2838,26 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
}
+ v3f pointed_pos_under = player_pos;
+ v3f pointed_pos_above = player_pos;
+ if(pointed.type == POINTEDTHING_NODE)
+ {
+ pointed_pos_under = intToFloat(p_under, BS);
+ pointed_pos_above = intToFloat(p_above, BS);
+ }
+ else if(pointed.type == POINTEDTHING_OBJECT)
+ {
+ pointed_pos_under = pointed_object->getBasePosition();
+ pointed_pos_above = pointed_pos_under;
+ }
+
/*
Check that target is reasonably close
(only when digging or placing things)
*/
if(action == 0 || action == 2 || action == 3)
{
- v3f pointed_pos = player_pos;
- if(pointed.type == POINTEDTHING_NODE)
- {
- pointed_pos = intToFloat(p_under, BS);
- }
- else if(pointed.type == POINTEDTHING_OBJECT)
- {
- pointed_pos = pointed_object->getBasePosition();
- }
-
- float d = player_pos.getDistanceFrom(pointed_pos);
+ float d = player_pos.getDistanceFrom(pointed_pos_under);
float max_d = BS * 10; // Just some large enough value
if(d > max_d){
actionstream<<"Player "<<player->getName()
@@ -2926,7 +2867,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
<<". ignoring."<<std::endl;
// Re-send block to revert change on client-side
RemoteClient *client = getClient(peer_id);
- v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos, BS));
+ v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
client->SetBlockNotSent(blockpos);
// Do nothing else
return;
@@ -2936,13 +2877,12 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
/*
Make sure the player is allowed to do it
*/
- bool build_priv = (getPlayerPrivs(player) & PRIV_INTERACT) != 0;
- if(!build_priv)
+ if((getPlayerPrivs(player) & PRIV_INTERACT) == 0)
{
infostream<<"Ignoring interaction from player "<<player->getName()
<<" because privileges are "<<getPlayerPrivs(player)
<<std::endl;
- // NOTE: no return; here, fall through
+ return;
}
/*
@@ -2956,10 +2896,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
NOTE: This can be used in the future to check if
somebody is cheating, by checking the timing.
*/
- bool cannot_punch_node = !build_priv;
-
MapNode n(CONTENT_IGNORE);
-
try
{
n = m_env->getMap().getNode(p_under);
@@ -2971,22 +2908,12 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
<<std::endl;
m_emerge_queue.addBlock(peer_id,
getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
- cannot_punch_node = true;
}
-
- if(cannot_punch_node)
- return;
-
- /*
- Run script hook
- */
- scriptapi_environment_on_punchnode(m_lua, p_under, n, srp);
+ if(n.getContent() != CONTENT_IGNORE)
+ scriptapi_node_on_punch(m_lua, p_under, n, srp);
}
else if(pointed.type == POINTEDTHING_OBJECT)
{
- if(!build_priv)
- return;
-
// Skip if object has been removed
if(pointed_object->m_removed)
return;
@@ -3014,211 +2941,24 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
else if(action == 2)
{
// Only complete digging of nodes
- if(pointed.type != POINTEDTHING_NODE)
- return;
-
- // Mandatory parameter; actually used for nothing
- core::map<v3s16, MapBlock*> modified_blocks;
-
- content_t material = CONTENT_IGNORE;
- u8 mineral = MINERAL_NONE;
-
- bool cannot_remove_node = !build_priv;
-
- MapNode n(CONTENT_IGNORE);
- try
- {
- n = m_env->getMap().getNode(p_under);
- // Get mineral
- mineral = n.getMineral(m_nodedef);
- // Get material at position
- material = n.getContent();
- // If not yet cancelled
- if(cannot_remove_node == false)
- {
- // If it's not diggable, do nothing
- if(m_nodedef->get(material).diggable == false)
- {
- infostream<<"Server: Not finishing digging: "
- <<"Node not diggable"
- <<std::endl;
- cannot_remove_node = true;
- }
- }
- // If not yet cancelled
- if(cannot_remove_node == false)
- {
- // Get node metadata
- NodeMetadata *meta = m_env->getMap().getNodeMetadata(p_under);
- if(meta && meta->nodeRemovalDisabled() == true)
- {
- infostream<<"Server: Not finishing digging: "
- <<"Node metadata disables removal"
- <<std::endl;
- cannot_remove_node = true;
- }
- }
- }
- catch(InvalidPositionException &e)
- {
- infostream<<"Server: Not finishing digging: Node not found."
- <<" Adding block to emerge queue."
- <<std::endl;
- m_emerge_queue.addBlock(peer_id,
- getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
- cannot_remove_node = true;
- }
-
- /*
- If node can't be removed, set block to be re-sent to
- client and quit.
- */
- if(cannot_remove_node)
- {
- infostream<<"Server: Not finishing digging."<<std::endl;
-
- // Client probably has wrong data.
- // Set block not sent, so that client will get
- // a valid one.
- infostream<<"Client "<<peer_id<<" tried to dig "
- <<"node; but node cannot be removed."
- <<" setting MapBlock not sent."<<std::endl;
- RemoteClient *client = getClient(peer_id);
- v3s16 blockpos = getNodeBlockPos(p_under);
- client->SetBlockNotSent(blockpos);
-
- return;
- }
-
- actionstream<<player->getName()<<" digs "<<PP(p_under)
- <<", gets material "<<(int)material<<", mineral "
- <<(int)mineral<<std::endl;
-
- /*
- Send the removal to all close-by players.
- - If other player is close, send REMOVENODE
- - Otherwise set blocks not sent
- */
- core::list<u16> far_players;
- sendRemoveNode(p_under, peer_id, &far_players, 30);
-
- /*
- Update and send inventory
- */
-
- if(g_settings->getBool("creative_mode") == false)
+ if(pointed.type == POINTEDTHING_NODE)
{
- /*
- Wear out tool
- */
- InventoryList *mlist = player->inventory.getList("main");
- if(mlist != NULL)
- {
- InventoryItem *item = mlist->getItem(item_i);
- if(item && (std::string)item->getName() == "ToolItem")
- {
- ToolItem *titem = (ToolItem*)item;
- std::string toolname = titem->getToolName();
-
- // Get digging properties for material and tool
- ToolDiggingProperties tp =
- m_toolmgr->getDiggingProperties(toolname);
- DiggingProperties prop =
- getDiggingProperties(material, &tp, m_nodedef);
-
- if(prop.diggable == false)
- {
- infostream<<"Server: WARNING: Player digged"
- <<" with impossible material + tool"
- <<" combination"<<std::endl;
- }
-
- bool weared_out = titem->addWear(prop.wear);
-
- if(weared_out)
- {
- mlist->deleteItem(item_i);
- }
-
- srp->m_inventory_not_sent = true;
- }
- }
-
- /*
- Add dug item to inventory
- */
-
- InventoryItem *item = NULL;
-
- if(mineral != MINERAL_NONE)
- item = getDiggedMineralItem(mineral, this);
-
- // If not mineral
- if(item == NULL)
- {
- const std::string &dug_s = m_nodedef->get(material).dug_item;
- if(dug_s != "")
- {
- std::istringstream is(dug_s, std::ios::binary);
- item = InventoryItem::deSerialize(is, this);
- }
- }
-
- if(item != NULL)
- {
- // Add a item to inventory
- player->inventory.addItem("main", item);
- srp->m_inventory_not_sent = true;
- }
-
- item = NULL;
-
+ MapNode n(CONTENT_IGNORE);
+ try
{
- const std::string &extra_dug_s = m_nodedef->get(material).extra_dug_item;
- s32 extra_rarity = m_nodedef->get(material).extra_dug_item_rarity;
- if(extra_dug_s != "" && extra_rarity != 0
- && myrand() % extra_rarity == 0)
- {
- std::istringstream is(extra_dug_s, std::ios::binary);
- item = InventoryItem::deSerialize(is, this);
- }
+ n = m_env->getMap().getNode(p_under);
}
-
- if(item != NULL)
+ catch(InvalidPositionException &e)
{
- // Add a item to inventory
- player->inventory.addItem("main", item);
- srp->m_inventory_not_sent = true;
+ infostream<<"Server: Not finishing digging: Node not found."
+ <<" Adding block to emerge queue."
+ <<std::endl;
+ m_emerge_queue.addBlock(peer_id,
+ getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
}
+ if(n.getContent() != CONTENT_IGNORE)
+ scriptapi_node_on_dig(m_lua, p_under, n, srp);
}
-
- /*
- Remove the node
- (this takes some time so it is done after the quick stuff)
- */
- {
- MapEditEventIgnorer ign(&m_ignore_map_edit_events);
-
- m_env->getMap().removeNodeAndUpdate(p_under, modified_blocks);
- }
- /*
- Set blocks not sent to far players
- */
- for(core::list<u16>::Iterator
- i = far_players.begin();
- i != far_players.end(); i++)
- {
- u16 peer_id = *i;
- RemoteClient *client = getClient(peer_id);
- if(client==NULL)
- continue;
- client->SetBlocksNotSent(modified_blocks);
- }
-
- /*
- Run script hook
- */
- scriptapi_environment_on_dignode(m_lua, p_under, n, srp);
} // action == 2
/*
@@ -3226,233 +2966,17 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
*/
else if(action == 3)
{
- if(pointed.type == POINTEDTHING_NODE)
- {
- InventoryList *ilist = player->inventory.getList("main");
- if(ilist == NULL)
- return;
-
- // Get item
- InventoryItem *item = ilist->getItem(item_i);
-
- // If there is no item, it is not possible to add it anywhere
- if(item == NULL)
- return;
-
- /*
- Handle material items
- */
- if(std::string("MaterialItem") == item->getName())
- {
- bool cannot_place_node = !build_priv;
-
- try{
- // Don't add a node if this is not a free space
- MapNode n2 = m_env->getMap().getNode(p_above);
- if(m_nodedef->get(n2).buildable_to == false)
- {
- infostream<<"Client "<<peer_id<<" tried to place"
- <<" node in invalid position."<<std::endl;
- cannot_place_node = true;
- }
- }
- catch(InvalidPositionException &e)
- {
- infostream<<"Server: Ignoring ADDNODE: Node not found"
- <<" Adding block to emerge queue."
- <<std::endl;
- m_emerge_queue.addBlock(peer_id,
- getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
- cannot_place_node = true;
- }
+ ItemStack item = srp->getWieldedItem();
- if(cannot_place_node)
- {
- // Client probably has wrong data.
- // Set block not sent, so that client will get
- // a valid one.
- RemoteClient *client = getClient(peer_id);
- v3s16 blockpos = getNodeBlockPos(p_above);
- client->SetBlockNotSent(blockpos);
- return;
- }
+ // Reset build time counter
+ if(pointed.type == POINTEDTHING_NODE &&
+ item.getDefinition(m_itemdef).type == ITEM_NODE)
+ getClient(peer_id)->m_time_from_building = 0.0;
- // Reset build time counter
- getClient(peer_id)->m_time_from_building = 0.0;
-
- // Create node data
- MaterialItem *mitem = (MaterialItem*)item;
- MapNode n;
- n.setContent(mitem->getMaterial());
-
- actionstream<<player->getName()<<" places material "
- <<(int)mitem->getMaterial()
- <<" at "<<PP(p_under)<<std::endl;
-
- // Calculate direction for wall mounted stuff
- if(m_nodedef->get(n).wall_mounted)
- n.param2 = packDir(p_under - p_above);
-
- // Calculate the direction for furnaces and chests and stuff
- if(m_nodedef->get(n).param_type == CPT_FACEDIR_SIMPLE)
- {
- v3f playerpos = player->getPosition();
- v3f blockpos = intToFloat(p_above, BS) - playerpos;
- blockpos = blockpos.normalize();
- n.param1 = 0;
- if (fabs(blockpos.X) > fabs(blockpos.Z)) {
- if (blockpos.X < 0)
- n.param1 = 3;
- else
- n.param1 = 1;
- } else {
- if (blockpos.Z < 0)
- n.param1 = 2;
- else
- n.param1 = 0;
- }
- }
-
- /*
- Send to all close-by players
- */
- core::list<u16> far_players;
- sendAddNode(p_above, n, 0, &far_players, 30);
-
- /*
- Handle inventory
- */
- InventoryList *ilist = player->inventory.getList("main");
- if(g_settings->getBool("creative_mode") == false && ilist)
- {
- // Remove from inventory and send inventory
- if(mitem->getCount() <= 1)
- ilist->deleteItem(item_i);
- else
- mitem->remove(1);
- srp->m_inventory_not_sent = true;
- }
-
- /*
- Add node.
-
- This takes some time so it is done after the quick stuff
- */
- core::map<v3s16, MapBlock*> modified_blocks;
- {
- MapEditEventIgnorer ign(&m_ignore_map_edit_events);
-
- std::string p_name = std::string(player->getName());
- m_env->getMap().addNodeAndUpdate(p_above, n, modified_blocks, p_name);
- }
- /*
- Set blocks not sent to far players
- */
- for(core::list<u16>::Iterator
- i = far_players.begin();
- i != far_players.end(); i++)
- {
- u16 peer_id = *i;
- RemoteClient *client = getClient(peer_id);
- if(client==NULL)
- continue;
- client->SetBlocksNotSent(modified_blocks);
- }
-
- /*
- Run script hook
- */
- scriptapi_environment_on_placenode(m_lua, p_above, n, srp);
-
- /*
- Calculate special events
- */
-
- /*if(n.d == LEGN(m_nodedef, "CONTENT_MESE"))
- {
- u32 count = 0;
- for(s16 z=-1; z<=1; z++)
- for(s16 y=-1; y<=1; y++)
- for(s16 x=-1; x<=1; x++)
- {
-
- }
- }*/
- }
- /*
- Place other item (not a block)
- */
- else
- {
- if(!build_priv)
- {
- infostream<<"Not allowing player to place item: "
- "no build privileges"<<std::endl;
- return;
- }
-
- // Calculate a position for it
- v3f pos = player_pos;
- if(pointed.type == POINTEDTHING_NOTHING)
- {
- infostream<<"Not allowing player to place item: "
- "pointing to nothing"<<std::endl;
- return;
- }
- else if(pointed.type == POINTEDTHING_NODE)
- {
- pos = intToFloat(p_above, BS);
- }
- else if(pointed.type == POINTEDTHING_OBJECT)
- {
- pos = pointed_object->getBasePosition();
-
- // Randomize a bit
- pos.X += BS*0.2*(float)myrand_range(-1000,1000)/1000.0;
- pos.Z += BS*0.2*(float)myrand_range(-1000,1000)/1000.0;
- }
-
- //pos.Y -= BS*0.45;
- //pos.Y -= BS*0.25; // let it drop a bit
-
- /*
- Check that the block is loaded so that the item
- can properly be added to the static list too
- */
- v3s16 blockpos = getNodeBlockPos(floatToInt(pos, BS));
- MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
- if(block==NULL)
- {
- infostream<<"Error while placing item: "
- "block not found"<<std::endl;
- return;
- }
-
- actionstream<<player->getName()<<" places "<<item->getName()
- <<" at "<<PP(pos)<<std::endl;
-
- /*
- Place the item
- */
- bool remove = item->dropOrPlace(m_env, srp, pos, true, -1);
- if(remove && g_settings->getBool("creative_mode") == false)
- {
- InventoryList *ilist = player->inventory.getList("main");
- if(ilist){
- // Remove from inventory and send inventory
- ilist->deleteItem(item_i);
- srp->m_inventory_not_sent = true;
- }
- }
- }
- }
- else if(pointed.type == POINTEDTHING_OBJECT)
+ if(pointed.type == POINTEDTHING_OBJECT)
{
// Right click object
- if(!build_priv)
- return;
-
// Skip if object has been removed
if(pointed_object->m_removed)
return;
@@ -3463,6 +2987,15 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
// Do stuff
pointed_object->rightClick(srp);
}
+ else if(scriptapi_item_on_place(m_lua,
+ item, srp, pointed))
+ {
+ // Placement was handled in lua
+
+ // Apply returned ItemStack
+ if(g_settings->getBool("creative_mode") == false)
+ srp->setWieldedItem(item);
+ }
} // action == 3
@@ -3471,38 +3004,17 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
*/
else if(action == 4)
{
- InventoryList *ilist = player->inventory.getList("main");
- if(ilist == NULL)
- return;
+ ItemStack item = srp->getWieldedItem();
- // Get item
- InventoryItem *item = ilist->getItem(item_i);
-
- // If there is no item, it is not possible to add it anywhere
- if(item == NULL)
- return;
-
- // Requires build privs
- if(!build_priv)
- {
- infostream<<"Not allowing player to use item: "
- "no build privileges"<<std::endl;
- return;
- }
-
- actionstream<<player->getName()<<" uses "<<item->getName()
+ actionstream<<player->getName()<<" uses "<<item.name
<<", pointing at "<<pointed.dump()<<std::endl;
- bool remove = item->use(m_env, srp, pointed);
-
- if(remove && g_settings->getBool("creative_mode") == false)
+ if(scriptapi_item_on_use(m_lua,
+ item, srp, pointed))
{
- InventoryList *ilist = player->inventory.getList("main");
- if(ilist){
- // Remove from inventory and send inventory
- ilist->deleteItem(item_i);
- srp->m_inventory_not_sent = true;
- }
+ // Apply returned ItemStack
+ if(g_settings->getBool("creative_mode") == false)
+ srp->setWieldedItem(item);
}
} // action == 4
@@ -3515,9 +3027,6 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
infostream<<"WARNING: Server: Invalid action "
<<action<<std::endl;
}
-
- // Complete add_to_inventory_later
- srp->completeAddToInventoryLater(item_i);
}
else
{
@@ -3549,6 +3058,9 @@ Inventory* Server::getInventory(const InventoryLocation &loc)
case InventoryLocation::UNDEFINED:
{}
break;
+ case InventoryLocation::CURRENT_PLAYER:
+ {}
+ break;
case InventoryLocation::PLAYER:
{
Player *player = m_env->getPlayer(loc.name.c_str());
@@ -3570,6 +3082,33 @@ Inventory* Server::getInventory(const InventoryLocation &loc)
}
return NULL;
}
+std::string Server::getInventoryOwner(const InventoryLocation &loc)
+{
+ switch(loc.type){
+ case InventoryLocation::UNDEFINED:
+ {}
+ break;
+ case InventoryLocation::CURRENT_PLAYER:
+ {}
+ break;
+ case InventoryLocation::PLAYER:
+ {
+ return loc.name;
+ }
+ break;
+ case InventoryLocation::NODEMETA:
+ {
+ NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
+ if(!meta)
+ return "";
+ return meta->getOwner();
+ }
+ break;
+ default:
+ assert(0);
+ }
+ return "";
+}
void Server::setInventoryModified(const InventoryLocation &loc)
{
switch(loc.type){
@@ -3604,64 +3143,6 @@ void Server::setInventoryModified(const InventoryLocation &loc)
assert(0);
}
}
-#if 0
-Inventory* Server::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(","));
-
- InventoryLocation loc;
- loc.setNodeMeta(p);
- return getInventory(loc);
- }
-
- infostream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
- return NULL;
-}
-void Server::inventoryModified(InventoryContext *c, std::string id)
-{
- if(id == "current_player")
- {
- assert(c->current_player);
- ServerRemotePlayer *srp =
- static_cast<ServerRemotePlayer*>(c->current_player);
- srp->m_inventory_not_sent = true;
- return;
- }
-
- 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(","));
- v3s16 blockpos = getNodeBlockPos(p);
-
- InventoryLocation loc;
- loc.setNodeMeta(p);
- setInventoryModified(loc);
- return;
- }
-
- infostream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
-}
-#endif
core::list<PlayerInfo> Server::getPlayerInfo()
{
@@ -3783,8 +3264,8 @@ void Server::SendDeathscreen(con::Connection &con, u16 peer_id,
con.Send(peer_id, 0, data, true);
}
-void Server::SendToolDef(con::Connection &con, u16 peer_id,
- IToolDefManager *tooldef)
+void Server::SendItemDef(con::Connection &con, u16 peer_id,
+ IItemDefManager *itemdef)
{
DSTACK(__FUNCTION_NAME);
std::ostringstream os(std::ios_base::binary);
@@ -3792,16 +3273,18 @@ void Server::SendToolDef(con::Connection &con, u16 peer_id,
/*
u16 command
u32 length of the next item
- serialized ToolDefManager
+ zlib-compressed serialized ItemDefManager
*/
- writeU16(os, TOCLIENT_TOOLDEF);
+ writeU16(os, TOCLIENT_ITEMDEF);
std::ostringstream tmp_os(std::ios::binary);
- tooldef->serialize(tmp_os);
- os<<serializeLongString(tmp_os.str());
+ itemdef->serialize(tmp_os);
+ std::ostringstream tmp_os2(std::ios::binary);
+ compressZlib(tmp_os.str(), tmp_os2);
+ os<<serializeLongString(tmp_os2.str());
// Make data buffer
std::string s = os.str();
- infostream<<"Server::SendToolDef(): Sending tool definitions: size="
+ infostream<<"Server::SendItemDef(): Sending item definitions: size="
<<s.size()<<std::endl;
SharedBuffer<u8> data((u8*)s.c_str(), s.size());
// Send as reliable
@@ -3817,12 +3300,14 @@ void Server::SendNodeDef(con::Connection &con, u16 peer_id,
/*
u16 command
u32 length of the next item
- serialized NodeDefManager
+ zlib-compressed serialized NodeDefManager
*/
writeU16(os, TOCLIENT_NODEDEF);
std::ostringstream tmp_os(std::ios::binary);
nodedef->serialize(tmp_os);
- os<<serializeLongString(tmp_os.str());
+ std::ostringstream tmp_os2(std::ios::binary);
+ compressZlib(tmp_os.str(), tmp_os2);
+ os<<serializeLongString(tmp_os2.str());
// Make data buffer
std::string s = os.str();
@@ -3833,31 +3318,6 @@ void Server::SendNodeDef(con::Connection &con, u16 peer_id,
con.Send(peer_id, 0, data, true);
}
-void Server::SendCraftItemDef(con::Connection &con, u16 peer_id,
- ICraftItemDefManager *craftitemdef)
-{
- DSTACK(__FUNCTION_NAME);
- std::ostringstream os(std::ios_base::binary);
-
- /*
- u16 command
- u32 length of the next item
- serialized CraftItemDefManager
- */
- writeU16(os, TOCLIENT_CRAFTITEMDEF);
- std::ostringstream tmp_os(std::ios::binary);
- craftitemdef->serialize(tmp_os);
- os<<serializeLongString(tmp_os.str());
-
- // Make data buffer
- std::string s = os.str();
- infostream<<"Server::SendCraftItemDef(): Sending craft item definitions: size="
- <<s.size()<<std::endl;
- SharedBuffer<u8> data((u8*)s.c_str(), s.size());
- // Send as reliable
- con.Send(peer_id, 0, data, true);
-}
-
/*
Non-static send methods
*/
@@ -3891,28 +3351,18 @@ void Server::SendInventory(u16 peer_id)
m_con.Send(peer_id, 0, data, true);
}
-std::string getWieldedItemString(const Player *player)
-{
- const InventoryItem *item = player->getWieldItem();
- if (item == NULL)
- return std::string("");
- std::ostringstream os(std::ios_base::binary);
- item->serialize(os);
- return os.str();
-}
-
-void Server::SendWieldedItem(const Player* player)
+void Server::SendWieldedItem(const ServerRemotePlayer* srp)
{
DSTACK(__FUNCTION_NAME);
- assert(player);
+ assert(srp);
std::ostringstream os(std::ios_base::binary);
writeU16(os, TOCLIENT_PLAYERITEM);
writeU16(os, 1);
- writeU16(os, player->peer_id);
- os<<serializeString(getWieldedItemString(player));
+ writeU16(os, srp->peer_id);
+ os<<serializeString(srp->getWieldedItem().getItemString());
// Make data buffer
std::string s = os.str();
@@ -3934,8 +3384,10 @@ void Server::SendPlayerItems()
for(i = players.begin(); i != players.end(); ++i)
{
Player *p = *i;
+ ServerRemotePlayer *srp =
+ static_cast<ServerRemotePlayer*>(p);
writeU16(os, p->peer_id);
- os<<serializeString(getWieldedItemString(p));
+ os<<serializeString(srp->getWieldedItem().getItemString());
}
// Make data buffer
@@ -4167,7 +3619,7 @@ void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
*/
std::ostringstream os(std::ios_base::binary);
- block->serialize(os, ver);
+ block->serialize(os, ver, false);
std::string s = os.str();
SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
@@ -4582,63 +4034,18 @@ void Server::UpdateCrafting(u16 peer_id)
Player* player = m_env->getPlayer(peer_id);
assert(player);
- ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
+ // Get a preview for crafting
+ ItemStack preview;
// No crafting in creative mode
- if(g_settings->getBool("creative_mode"))
- return;
-
- // Get the InventoryLists of the player in which we will operate
- InventoryList *clist = player->inventory.getList("craft");
- assert(clist);
- InventoryList *rlist = player->inventory.getList("craftresult");
- assert(rlist);
- InventoryList *mlist = player->inventory.getList("main");
- assert(mlist);
-
- // If the result list is not a preview and is not empty, try to
- // throw the item into main list
- if(!player->craftresult_is_preview && rlist->getUsedSlots() != 0)
- {
- // Grab item out of craftresult
- InventoryItem *item = rlist->changeItem(0, NULL);
- // Try to put in main
- InventoryItem *leftover = mlist->addItem(item);
- // If there are leftovers, put them back to craftresult and
- // delete leftovers
- delete rlist->addItem(leftover);
- // Inventory was modified
- srp->m_inventory_not_sent = true;
- }
-
- // If result list is empty, we will make it preview what would be
- // crafted
- if(rlist->getUsedSlots() == 0)
- player->craftresult_is_preview = true;
-
- // If it is a preview, clear the possible old preview in it
- if(player->craftresult_is_preview)
- rlist->clearItems();
-
- // If it is a preview, find out what is the crafting result
- // and put it in
- if(player->craftresult_is_preview)
- {
- // Mangle crafting grid to an another format
- std::vector<InventoryItem*> items;
- for(u16 i=0; i<9; i++){
- if(clist->getItem(i) == NULL)
- items.push_back(NULL);
- else
- items.push_back(clist->getItem(i)->clone());
- }
- CraftPointerInput cpi(3, items);
-
- // Find out what is crafted and add it to result item slot
- InventoryItem *result = m_craftdef->getCraftResult(cpi, this);
- if(result)
- rlist->addItem(result);
- }
+ if(g_settings->getBool("creative_mode") == false)
+ getCraftingResult(&player->inventory, preview, false, this);
+
+ // Put the new preview in
+ InventoryList *plist = player->inventory.getList("craftpreview");
+ assert(plist);
+ assert(plist->getSize() >= 1);
+ plist->changeItem(0, preview);
}
RemoteClient* Server::getClient(u16 peer_id)
@@ -4734,9 +4141,9 @@ void Server::queueBlockEmerge(v3s16 blockpos, bool allow_generate)
// IGameDef interface
// Under envlock
-IToolDefManager* Server::getToolDefManager()
+IItemDefManager* Server::getItemDefManager()
{
- return m_toolmgr;
+ return m_itemdef;
}
INodeDefManager* Server::getNodeDefManager()
{
@@ -4746,10 +4153,6 @@ ICraftDefManager* Server::getCraftDefManager()
{
return m_craftdef;
}
-ICraftItemDefManager* Server::getCraftItemDefManager()
-{
- return m_craftitemdef;
-}
ITextureSource* Server::getTextureSource()
{
return NULL;
@@ -4759,9 +4162,9 @@ u16 Server::allocateUnknownNodeId(const std::string &name)
return m_nodedef->allocateDummy(name);
}
-IWritableToolDefManager* Server::getWritableToolDefManager()
+IWritableItemDefManager* Server::getWritableItemDefManager()
{
- return m_toolmgr;
+ return m_itemdef;
}
IWritableNodeDefManager* Server::getWritableNodeDefManager()
{
@@ -4771,10 +4174,6 @@ IWritableCraftDefManager* Server::getWritableCraftDefManager()
{
return m_craftdef;
}
-IWritableCraftItemDefManager* Server::getWritableCraftItemDefManager()
-{
- return m_craftitemdef;
-}
const ModSpec* Server::getModSpec(const std::string &modname)
{
@@ -4874,7 +4273,7 @@ ServerRemotePlayer *Server::emergePlayer(const char *name, u16 peer_id)
{
// Warning: double code below
// Backup actual inventory
- player->inventory_backup = new Inventory();
+ player->inventory_backup = new Inventory(m_itemdef);
*(player->inventory_backup) = player->inventory;
// Set creative inventory
player->resetInventory();
@@ -4919,7 +4318,7 @@ ServerRemotePlayer *Server::emergePlayer(const char *name, u16 peer_id)
{
// Warning: double code above
// Backup actual inventory
- player->inventory_backup = new Inventory();
+ player->inventory_backup = new Inventory(m_itemdef);
*(player->inventory_backup) = player->inventory;
// Set creative inventory
player->resetInventory();
diff --git a/src/server.h b/src/server.h
index 5938f915d..4fdb60065 100644
--- a/src/server.h
+++ b/src/server.h
@@ -36,10 +36,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "inventorymanager.h"
struct LuaState;
typedef struct lua_State lua_State;
-class IWritableToolDefManager;
+class IWritableItemDefManager;
class IWritableNodeDefManager;
class IWritableCraftDefManager;
-class IWritableCraftItemDefManager;
/*
Some random functions
@@ -437,6 +436,7 @@ public:
Shall be called with the environment and the connection locked.
*/
Inventory* getInventory(const InventoryLocation &loc);
+ std::string getInventoryOwner(const InventoryLocation &loc);
void setInventoryModified(const InventoryLocation &loc);
// Connection must be locked when called
@@ -514,17 +514,15 @@ public:
// IGameDef interface
// Under envlock
- virtual IToolDefManager* getToolDefManager();
+ virtual IItemDefManager* getItemDefManager();
virtual INodeDefManager* getNodeDefManager();
virtual ICraftDefManager* getCraftDefManager();
- virtual ICraftItemDefManager* getCraftItemDefManager();
virtual ITextureSource* getTextureSource();
virtual u16 allocateUnknownNodeId(const std::string &name);
- IWritableToolDefManager* getWritableToolDefManager();
+ IWritableItemDefManager* getWritableItemDefManager();
IWritableNodeDefManager* getWritableNodeDefManager();
IWritableCraftDefManager* getWritableCraftDefManager();
- IWritableCraftItemDefManager* getWritableCraftItemDefManager();
const ModSpec* getModSpec(const std::string &modname);
@@ -545,12 +543,10 @@ private:
const std::wstring &reason);
static void SendDeathscreen(con::Connection &con, u16 peer_id,
bool set_camera_point_target, v3f camera_point_target);
- static void SendToolDef(con::Connection &con, u16 peer_id,
- IToolDefManager *tooldef);
+ static void SendItemDef(con::Connection &con, u16 peer_id,
+ IItemDefManager *itemdef);
static void SendNodeDef(con::Connection &con, u16 peer_id,
INodeDefManager *nodedef);
- static void SendCraftItemDef(con::Connection &con, u16 peer_id,
- ICraftItemDefManager *nodedef);
/*
Non-static send methods.
@@ -562,7 +558,7 @@ private:
// Envlock and conlock should be locked when calling these
void SendInventory(u16 peer_id);
// 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
void SendPlayerItems();
void SendChatMessage(u16 peer_id, const std::wstring &message);
@@ -664,8 +660,8 @@ private:
// Envlock and conlock should be locked when using Lua
lua_State *m_lua;
- // Tool definition manager
- IWritableToolDefManager *m_toolmgr;
+ // Item definition manager
+ IWritableItemDefManager *m_itemdef;
// Node definition manager
IWritableNodeDefManager *m_nodedef;
@@ -673,9 +669,6 @@ private:
// Craft definition manager
IWritableCraftDefManager *m_craftdef;
- // CraftItem definition manager
- IWritableCraftItemDefManager *m_craftitemdef;
-
// Mods
core::list<ModSpec> m_mods;
@@ -740,7 +733,7 @@ private:
core::list<std::string> m_modspaths;
bool m_shutdown_requested;
-
+
/*
Map edit event queue. Automatically receives all map edits.
The constructor of this class registers us to receive them through
diff --git a/src/servermain.cpp b/src/servermain.cpp
index e8a54512e..3ef1d9479 100644
--- a/src/servermain.cpp
+++ b/src/servermain.cpp
@@ -68,7 +68,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "porting.h"
#include "materials.h"
#include "config.h"
-#include "mineral.h"
#include "filesys.h"
#include "defaultsettings.h"
#include "settings.h"
@@ -301,10 +300,6 @@ int main(int argc, char *argv[])
srand(time(0));
mysrand(time(0));
- // Initialize stuff
-
- init_mineral();
-
/*
Run unit tests
*/
diff --git a/src/serverobject.cpp b/src/serverobject.cpp
index b5fd6fc3a..76a70ca5b 100644
--- a/src/serverobject.cpp
+++ b/src/serverobject.cpp
@@ -20,7 +20,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "serverobject.h"
#include <fstream>
#include "inventory.h"
-#include "tooldef.h"
+#include "materials.h"
ServerActiveObject::ServerActiveObject(ServerEnvironment *env, v3f pos):
ActiveObject(0),
@@ -67,10 +67,31 @@ void ServerActiveObject::registerType(u8 type, Factory f)
ServerActiveObject::getTypes().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;
+}
diff --git a/src/serverobject.h b/src/serverobject.h
index d2627c87e..844bfd2ff 100644
--- a/src/serverobject.h
+++ b/src/serverobject.h
@@ -23,6 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "irrlichttypes.h"
#include "activeobject.h"
#include "utility.h"
+#include "inventorymanager.h"
/*
@@ -41,7 +42,7 @@ Some planning
*/
class ServerEnvironment;
-class InventoryItem;
+struct ItemStack;
class Player;
struct ToolDiggingProperties;
@@ -138,19 +139,27 @@ public:
{}
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 s16 getHP()
{ 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
deleted until this is 0 to keep the id preserved for the right
diff --git a/src/serverremoteplayer.cpp b/src/serverremoteplayer.cpp
index 1681900e0..b4dbbdb1b 100644
--- a/src/serverremoteplayer.cpp
+++ b/src/serverremoteplayer.cpp
@@ -22,7 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "settings.h"
#include "log.h"
#include "gamedef.h"
-#include "tooldef.h"
+#include "inventory.h"
#include "environment.h"
#include "materials.h"
@@ -31,6 +31,7 @@ ServerRemotePlayer::ServerRemotePlayer(ServerEnvironment *env):
ServerActiveObject(env, v3f(0,0,0)),
m_last_good_position(0,0,0),
m_last_good_position_age(0),
+ m_wield_index(0),
m_inventory_not_sent(false),
m_hp_not_sent(false),
m_respawn_active(false),
@@ -45,6 +46,7 @@ ServerRemotePlayer::ServerRemotePlayer(ServerEnvironment *env, v3f pos_, u16 pee
ServerActiveObject(env, pos_),
m_last_good_position(0,0,0),
m_last_good_position_age(0),
+ m_wield_index(0),
m_inventory_not_sent(false),
m_hp_not_sent(false),
m_is_in_environment(false),
@@ -57,7 +59,6 @@ ServerRemotePlayer::ServerRemotePlayer(ServerEnvironment *env, v3f pos_, u16 pee
}
ServerRemotePlayer::~ServerRemotePlayer()
{
- clearAddToInventoryLater();
}
void ServerRemotePlayer::setPosition(const v3f &position)
@@ -67,12 +68,41 @@ void ServerRemotePlayer::setPosition(const v3f &position)
m_position_not_sent = true;
}
-InventoryItem* ServerRemotePlayer::getWieldedItem()
+Inventory* ServerRemotePlayer::getInventory()
{
- InventoryList *list = inventory.getList("main");
- if (list)
- return list->getItem(m_selected_item);
- return NULL;
+ return &inventory;
+}
+
+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 */
@@ -156,8 +186,10 @@ void ServerRemotePlayer::punch(ServerActiveObject *puncher,
mp.crackiness = -0.5;
mp.cuttability = 0.5;
- ToolDiggingProperties tp;
- puncher->getWieldDiggingProperties(&tp);
+ IItemDefManager *idef = m_env->getGameDef()->idef();
+ ItemStack punchitem = puncher->getWieldedItem();
+ ToolDiggingProperties tp =
+ punchitem.getToolDiggingProperties(idef);
HittingProperties hitprop = getHittingProperties(&mp, &tp,
time_from_last_punch);
@@ -167,7 +199,8 @@ void ServerRemotePlayer::punch(ServerActiveObject *puncher,
<<" HP"<<std::endl;
setHP(getHP() - hitprop.hp);
- puncher->damageWieldedItem(hitprop.wear);
+ punchitem.addWear(hitprop.wear, idef);
+ puncher->setWieldedItem(punchitem);
if(hitprop.hp != 0)
{
@@ -201,109 +234,6 @@ void ServerRemotePlayer::moveTo(v3f pos, bool continuous)
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_)
{
s16 oldhp = hp;
diff --git a/src/serverremoteplayer.h b/src/serverremoteplayer.h
index bdc3bba20..9d9437646 100644
--- a/src/serverremoteplayer.h
+++ b/src/serverremoteplayer.h
@@ -46,9 +46,6 @@ public:
virtual void setPosition(const v3f &position);
- // Returns a reference
- virtual InventoryItem* getWieldedItem();
-
/* ServerActiveObject interface */
u8 getType() const
@@ -77,19 +74,20 @@ public:
virtual std::string getDescription()
{return std::string("player ")+getName();}
- 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);
- virtual void addToInventoryLater(InventoryItem *item);
- void clearAddToInventoryLater();
- void completeAddToInventoryLater(u16 preferred_index);
+ virtual Inventory* getInventory();
+ virtual const Inventory* getInventory() const;
+ virtual InventoryLocation getInventoryLocation() const;
+ virtual void setInventoryModified();
+ virtual std::string getWieldList() const;
+ virtual int getWieldIndex() const;
+ virtual void setWieldIndex(int i);
+
virtual void setHP(s16 hp_);
virtual s16 getHP();
v3f m_last_good_position;
float m_last_good_position_age;
- std::vector<InventoryItem*> m_additional_items;
+ int m_wield_index;
bool m_inventory_not_sent;
bool m_hp_not_sent;
bool m_respawn_active;
diff --git a/src/test.cpp b/src/test.cpp
index f778f2d91..4226df544 100644
--- a/src/test.cpp
+++ b/src/test.cpp
@@ -47,6 +47,72 @@ with this program; if not, write to the Free Software Foundation, Inc.,
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.is_ground_content = true;
+ 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.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
{
void Run()
@@ -96,7 +162,120 @@ struct TestSettings
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);
+ // MSVC fails when directly using "\\\\"
+ std::string backslash = "\\";
+ 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) +
+ backslash + backslash + 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
{
void Run()
@@ -283,11 +462,11 @@ struct TestVoxelManipulator
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);
- 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;
@@ -301,7 +480,7 @@ struct TestVoxelManipulator
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)));
}
};
@@ -1022,7 +1201,7 @@ struct TestConnection
server.Send(peer_id_client, 0, data1, true);
- sleep_ms(3000);
+ //sleep_ms(3000);
SharedBuffer<u8> recvdata;
infostream<<"** running client.Receive()"<<std::endl;
@@ -1031,7 +1210,7 @@ struct TestConnection
bool received = false;
u32 timems0 = porting::getTimeMs();
for(;;){
- if(porting::getTimeMs() - timems0 > 5000)
+ if(porting::getTimeMs() - timems0 > 5000 || received)
break;
try{
size = client.Receive(peer_id, recvdata);
@@ -1086,16 +1265,18 @@ void run_tests()
{
DSTACK(__FUNCTION_NAME);
- // Create node definitions
- IWritableNodeDefManager *nodedef = createNodeDefManager();
- content_mapnode_init(nodedef);
+ // Create item and node definitions
+ IWritableItemDefManager *idef = createItemDefManager();
+ IWritableNodeDefManager *ndef = createNodeDefManager();
+ define_some_nodes(idef, ndef);
infostream<<"run_tests() started"<<std::endl;
TEST(TestUtilities);
TEST(TestSettings);
TEST(TestCompress);
- TESTPARAMS(TestMapNode, nodedef);
- TESTPARAMS(TestVoxelManipulator, nodedef);
+ TEST(TestSerialization);
+ TESTPARAMS(TestMapNode, ndef);
+ TESTPARAMS(TestVoxelManipulator, ndef);
//TEST(TestMapBlock);
//TEST(TestMapSector);
if(INTERNET_SIMULATOR == false){
diff --git a/src/tile.cpp b/src/tile.cpp
index 89f345197..bc4c49cb1 100644
--- a/src/tile.cpp
+++ b/src/tile.cpp
@@ -27,7 +27,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <ICameraSceneNode.h>
#include "log.h"
#include "mapnode.h" // For texture atlas making
-#include "mineral.h" // For texture atlas making
#include "nodedef.h" // For texture atlas making
#include "gamedef.h"
@@ -299,8 +298,8 @@ public:
Example names:
"stone.png"
"stone.png^crack2"
- "stone.png^blit:mineral_coal.png"
- "stone.png^blit:mineral_coal.png^crack1"
+ "stone.png^mineral_coal.png"
+ "stone.png^mineral_coal.png^crack1"
- If texture specified by name is found from cache, return the
cached id.
@@ -337,6 +336,12 @@ public:
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
// AtlasPointer based on it's texture id
void updateAP(AtlasPointer &ap);
@@ -469,8 +474,6 @@ u32 TextureSource::getTextureId(const std::string &name)
return 0;
}
-// Draw a progress bar on the image
-void make_progressbar(float value, video::IImage *image);
// Brighten image
void brighten(video::IImage *image);
@@ -816,20 +819,10 @@ void TextureSource::buildMainAtlas(class IGameDef *gamedef)
if(j == CONTENT_IGNORE || j == CONTENT_AIR)
continue;
const ContentFeatures &f = ndef->get(j);
- for(std::set<std::string>::const_iterator
- i = f.used_texturenames.begin();
- i != f.used_texturenames.end(); i++)
+ for(u32 i=0; i<6; i++)
{
- std::string name = *i;
+ std::string name = f.tname_tiles[i];
sourcelist[name] = true;
-
- if(f.often_contains_mineral){
- for(int k=1; k<MINERAL_COUNT; k++){
- std::string mineraltexture = mineral_block_texture(k);
- std::string fulltexture = name + "^" + mineraltexture;
- sourcelist[fulltexture] = true;
- }
- }
}
}
@@ -1317,23 +1310,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"
*/
else if(part_of_name.substr(0,9) == "[brighten")
@@ -1442,23 +1418,6 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
std::string imagename_left = 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
video::IImage *img_top = generate_image_from_scratch(
imagename_top, device, sourcecache);
@@ -1482,84 +1441,65 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
img_left->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:
- - An unit cube is centered at 0,0,0
- - Camera looks at cube from Y+, Z- towards Y-, Z+
+ Draw a cube mesh into a render target texture
*/
-
scene::IMesh* cube = createCubeMesh(v3f(1, 1, 1));
setMeshColor(cube, video::SColor(255, 255, 255, 255));
-
- scene::IMeshSceneNode* cubenode = smgr->addMeshSceneNode(cube, NULL, -1, v3f(0,0,0), v3f(0,45,0), v3f(1,1,1), true);
- cube->drop();
-
- // Set texture of cube
- cubenode->getMaterial(0).setTexture(0, texture_top);
- cubenode->getMaterial(1).setTexture(0, texture_top);
- cubenode->getMaterial(2).setTexture(0, texture_right);
- 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));
+ 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);
+
+ core::dimension2d<u32> dim(64,64);
+ std::string rtt_texture_name = part_of_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
- core::CMatrix4<f32> pm;
- pm.buildProjectionMatrixOrthoLH(1.65, 1.65, 0, 100);
- camera->setProjectionMatrix(pm, true);
-
- /*scene::ILightSceneNode *light =*/ smgr->addLightSceneNode(0,
- v3f(-50, 100, -75), video::SColorf(0.5,0.5,0.5), 1000);
-
- smgr->setAmbientLight(video::SColorf(0.2,0.2,0.2));
-
- // Render scene
- driver->beginScene(true, true, video::SColor(0,0,0,0));
- smgr->drawAll();
- driver->endScene();
+ 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;
+
+ video::ITexture *rtt = generateTextureFromMesh(
+ cube, device, dim, rtt_texture_name,
+ camera_position,
+ camera_lookat,
+ camera_projection_matrix,
+ ambient_light,
+ light_position,
+ light_color,
+ light_radius);
- // 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);
+ // Drop mesh
+ cube->drop();
// Free textures of images
driver->removeTexture(texture_top);
driver->removeTexture(texture_left);
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
video::IImage *image = driver->createImage(rtt, v2s32(0,0), dim);
-
assert(image);
-
+
baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
if(image)
@@ -1567,7 +1507,6 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
image->copyTo(baseimg);
image->drop();
}
-#endif
}
else
{
@@ -1579,38 +1518,6 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
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)
{
if(image == NULL)
diff --git a/src/tile.h b/src/tile.h
index 23849ca1f..c0d8914b0 100644
--- a/src/tile.h
+++ b/src/tile.h
@@ -110,6 +110,8 @@ public:
{return AtlasPointer(0);}
virtual video::ITexture* getTextureRaw(const std::string &name)
{return NULL;}
+ virtual IrrlichtDevice* getDevice()
+ {return NULL;}
virtual void updateAP(AtlasPointer &ap){};
};
@@ -126,6 +128,8 @@ public:
{return AtlasPointer(0);}
virtual video::ITexture* getTextureRaw(const std::string &name)
{return NULL;}
+ virtual IrrlichtDevice* getDevice()
+ {return NULL;}
virtual void updateAP(AtlasPointer &ap){};
virtual void processQueue()=0;
diff --git a/src/tooldef.cpp b/src/tooldef.cpp
deleted file mode 100644
index 7d7eceab0..000000000
--- a/src/tooldef.cpp
+++ /dev/null
@@ -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();
-}
-
diff --git a/src/tooldef.h b/src/tooldef.h
deleted file mode 100644
index 68a894898..000000000
--- a/src/tooldef.h
+++ /dev/null
@@ -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
-
diff --git a/src/utility.cpp b/src/utility.cpp
index 4e9f307d8..06b60884f 100644
--- a/src/utility.cpp
+++ b/src/utility.cpp
@@ -26,6 +26,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "sha1.h"
#include "base64.h"
#include "log.h"
+#include <iomanip>
TimeTaker::TimeTaker(const char *name, u32 *result)
{
@@ -234,6 +235,100 @@ bool isBlockInSight(v3s16 blockpos_b, v3f camera_pos, v3f camera_dir,
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
// the password entered. That's what the server uses as
// their password. (Exception : if the password field is
diff --git a/src/utility.h b/src/utility.h
index 14b49772b..f4c7c3017 100644
--- a/src/utility.h
+++ b/src/utility.h
@@ -1694,6 +1694,12 @@ inline std::string deSerializeLongString(std::istream &is)
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)
@@ -1751,6 +1757,50 @@ protected:
float m_accumulator;
};
+/*
+ Splits a list into "pages". For example, the list [1,2,3,4,5] split
+ into two pages would be [1,2,3],[4,5]. This function computes the
+ minimum and maximum indices of a single page.
+
+ length: Length of the list that should be split
+ page: Page number, 1 <= page <= pagecount
+ pagecount: The number of pages, >= 1
+ minindex: Receives the minimum index (inclusive).
+ maxindex: Receives the maximum index (exclusive).
+
+ Ensures 0 <= minindex <= maxindex <= length.
+*/
+inline void paging(u32 length, u32 page, u32 pagecount, u32 &minindex, u32 &maxindex)
+{
+ if(length < 1 || pagecount < 1 || page < 1 || page > pagecount)
+ {
+ // Special cases or invalid parameters
+ minindex = maxindex = 0;
+ }
+ else if(pagecount <= length)
+ {
+ // Less pages than entries in the list:
+ // Each page contains at least one entry
+ minindex = (length * (page-1) + (pagecount-1)) / pagecount;
+ maxindex = (length * page + (pagecount-1)) / pagecount;
+ }
+ else
+ {
+ // More pages than entries in the list:
+ // Make sure the empty pages are at the end
+ if(page < length)
+ {
+ minindex = page-1;
+ maxindex = page;
+ }
+ else
+ {
+ minindex = 0;
+ maxindex = 0;
+ }
+ }
+}
+
std::string translatePassword(std::string playername, std::wstring password);
enum PointedThingType