Node placement / mineral / serialization / iron freq / node_dig callback

- Node placement code moved to Lua
- Mineral system removed (added default:stone_with_coal and default:stone_with_iron).
- MapBlock and MapNode serialization updated.
- Mapgen: Frequency of iron increased.
- node_dig callback and related changes.
This commit is contained in:
Kahrl 2012-01-21 00:11:44 +01:00 committed by Perttu Ahola
parent f22c73f501
commit 157a4cf18c
36 changed files with 1610 additions and 1454 deletions

@ -83,7 +83,7 @@ end
-- Item definition helpers -- Item definition helpers
-- --
minetest.inventorycube = function(img1, img2, img3) function minetest.inventorycube(img1, img2, img3)
img2 = img2 or img1 img2 = img2 or img1
img3 = img3 or img1 img3 = img3 or img1
return "[inventorycube" return "[inventorycube"
@ -92,7 +92,11 @@ minetest.inventorycube = function(img1, img2, img3)
.. "{" .. img3:gsub("%^", "&") .. "{" .. img3:gsub("%^", "&")
end end
minetest.get_pointed_thing_position = function(pointed_thing, above) 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 pointed_thing.type == "node" then
if above then if above then
-- The position where a node would be placed -- The position where a node would be placed
@ -113,31 +117,240 @@ minetest.get_pointed_thing_position = function(pointed_thing, above)
end end
end end
function minetest.item_place(itemstack, placer, pointed_thing) function minetest.dir_to_facedir(dir)
pos = minetest.get_pointed_thing_position(pointed_thing, true) if math.abs(dir.x) > math.abs(dir.z) then
if pos ~= nil then if dir.x < 0 then
item = itemstack:take_item() return 3
if item ~= nil then else
minetest.env:add_item(pos, item) return 1
end 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
print("default drop: " .. nodename)
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 end
return itemstack return itemstack
end 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) function minetest.item_drop(itemstack, dropper, pos)
minetest.env:add_item(pos, itemstack) minetest.env:add_item(pos, itemstack)
return "" return ""
end end
function minetest.item_eat(hp_change) function minetest.item_eat(hp_change, replace_with_item)
return function(itemstack, user, pointed_thing) -- closure return function(itemstack, user, pointed_thing) -- closure
if itemstack:take_item() ~= nil then if itemstack:take_item() ~= nil then
user:set_hp(user:get_hp() + hp_change) user:set_hp(user:get_hp() + hp_change)
itemstack:add_item(replace_with_item) -- note: replace_with_item is optional
end end
return itemstack return itemstack
end end
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 -- Item definition defaults
-- --
@ -151,16 +364,18 @@ minetest.nodedef_default = {
wield_image = "", wield_image = "",
wield_scale = {x=1,y=1,z=1}, wield_scale = {x=1,y=1,z=1},
stack_max = 99, stack_max = 99,
dropcount = -1,
usable = false, usable = false,
liquids_pointable = false, liquids_pointable = false,
tool_digging_properties = nil, tool_digging_properties = nil,
-- Interaction callbacks -- Interaction callbacks
on_place = nil, -- let C handle node placement for now on_place = minetest.item_place,
on_drop = minetest.item_drop, on_drop = minetest.item_drop,
on_use = nil, on_use = nil,
on_punch = minetest.node_punch,
on_dig = minetest.node_dig,
-- Node properties -- Node properties
drawtype = "normal", drawtype = "normal",
visual_scale = 1.0, visual_scale = 1.0,
@ -172,6 +387,7 @@ minetest.nodedef_default = {
alpha = 255, alpha = 255,
post_effect_color = {a=0, r=0, g=0, b=0}, post_effect_color = {a=0, r=0, g=0, b=0},
paramtype = "none", paramtype = "none",
paramtype2 = "none",
is_ground_content = false, is_ground_content = false,
sunlight_propagates = false, sunlight_propagates = false,
walkable = true, walkable = true,
@ -179,10 +395,6 @@ minetest.nodedef_default = {
diggable = true, diggable = true,
climbable = false, climbable = false,
buildable_to = false, buildable_to = false,
wall_mounted = false,
--dug_item intentionally not defined here
extra_dug_item = "",
extra_dug_item_rarity = 2,
metadata_name = "", metadata_name = "",
liquidtype = "none", liquidtype = "none",
liquid_alternative_flowing = "", liquid_alternative_flowing = "",
@ -199,6 +411,8 @@ minetest.nodedef_default = {
cuttability = 0, cuttability = 0,
flammability = 0, flammability = 0,
}, },
legacy_facedir_simple = false,
legacy_wallmounted = false,
} }
minetest.craftitemdef_default = { minetest.craftitemdef_default = {
@ -369,12 +583,12 @@ function minetest.register_item(name, itemdef)
error("Unable to register item: Type is invalid: " .. dump(itemdef)) error("Unable to register item: Type is invalid: " .. dump(itemdef))
end end
-- Default dug item -- Flowing liquid uses param2
if itemdef.type == "node" and itemdef.dug_item == nil then if itemdef.type == "node" and itemdef.liquidtype == "flowing" then
itemdef.dug_item = ItemStack({name=itemdef.name}):to_string() itemdef.paramtype2 = "flowingliquid"
end end
-- Legacy stuff -- BEGIN Legacy stuff
if itemdef.cookresult_itemstring ~= nil and itemdef.cookresult_itemstring ~= "" then if itemdef.cookresult_itemstring ~= nil and itemdef.cookresult_itemstring ~= "" then
minetest.register_craft({ minetest.register_craft({
type="cooking", type="cooking",
@ -390,6 +604,7 @@ function minetest.register_item(name, itemdef)
burntime=itemdef.furnace_burntime burntime=itemdef.furnace_burntime
}) })
end end
-- END Legacy stuff
-- Disable all further modifications -- Disable all further modifications
getmetatable(itemdef).__newindex = {} getmetatable(itemdef).__newindex = {}
@ -408,10 +623,11 @@ end
function minetest.register_craftitem(name, craftitemdef) function minetest.register_craftitem(name, craftitemdef)
craftitemdef.type = "craft" craftitemdef.type = "craft"
-- Legacy stuff -- BEGIN Legacy stuff
if craftitemdef.inventory_image == nil and craftitemdef.image ~= nil then if craftitemdef.inventory_image == nil and craftitemdef.image ~= nil then
craftitemdef.inventory_image = craftitemdef.image craftitemdef.inventory_image = craftitemdef.image
end end
-- END Legacy stuff
minetest.register_item(name, craftitemdef) minetest.register_item(name, craftitemdef)
end end
@ -420,7 +636,7 @@ function minetest.register_tool(name, tooldef)
tooldef.type = "tool" tooldef.type = "tool"
tooldef.stack_max = 1 tooldef.stack_max = 1
-- Legacy stuff -- BEGIN Legacy stuff
if tooldef.inventory_image == nil and tooldef.image ~= nil then if tooldef.inventory_image == nil and tooldef.image ~= nil then
tooldef.inventory_image = tooldef.image tooldef.inventory_image = tooldef.image
end end
@ -450,6 +666,7 @@ function minetest.register_tool(name, tooldef)
dd_cuttability = tooldef.dd_cuttability, dd_cuttability = tooldef.dd_cuttability,
} }
end end
-- END Legacy stuff
minetest.register_item(name, tooldef) minetest.register_item(name, tooldef)
end end
@ -643,4 +860,10 @@ minetest.registered_on_newplayers, minetest.register_on_newplayer = make_registr
minetest.registered_on_dieplayers, minetest.register_on_dieplayer = make_registration() minetest.registered_on_dieplayers, minetest.register_on_dieplayer = make_registration()
minetest.registered_on_respawnplayers, minetest.register_on_respawnplayer = make_registration() minetest.registered_on_respawnplayers, minetest.register_on_respawnplayer = make_registration()
--
-- Set random seed
--
math.randomseed(os.time())
-- END -- END

@ -176,6 +176,7 @@
-- - set_text(text) -- eg. set the text of a sign -- - set_text(text) -- eg. set the text of a sign
-- - get_text() -- - get_text()
-- - get_owner() -- - get_owner()
-- - set_owner(string)
-- Generic node metadata specific: -- Generic node metadata specific:
-- - set_infotext(infotext) -- - set_infotext(infotext)
-- - get_inventory() -> InvRef -- - get_inventory() -> InvRef
@ -302,7 +303,7 @@
-- myvariable = whatever, -- myvariable = whatever,
-- } -- }
-- --
-- Item definition: -- Item definition options (register_node, register_craftitem, register_tool)
-- { -- {
-- description = "Steel Axe", -- description = "Steel Axe",
-- inventory_image = "default_tool_steelaxe.png", -- inventory_image = "default_tool_steelaxe.png",
@ -328,9 +329,9 @@
-- on_use = func(item, user, pointed_thing), -- on_use = func(item, user, pointed_thing),
-- } -- }
-- --
-- Node definition options: -- Node definition options (register_node):
-- { -- {
-- <all fields from item definitions>, -- <all fields allowed in item definitions>,
-- drawtype = "normal", -- drawtype = "normal",
-- visual_scale = 1.0, -- visual_scale = 1.0,
-- tile_images = {"default_unknown_block.png"}, -- tile_images = {"default_unknown_block.png"},
@ -341,6 +342,7 @@
-- alpha = 255, -- alpha = 255,
-- post_effect_color = {a=0, r=0, g=0, b=0}, -- post_effect_color = {a=0, r=0, g=0, b=0},
-- paramtype = "none", -- paramtype = "none",
-- paramtype2 = "none",
-- is_ground_content = false, -- is_ground_content = false,
-- sunlight_propagates = false, -- sunlight_propagates = false,
-- walkable = true, -- walkable = true,
@ -348,10 +350,8 @@
-- diggable = true, -- diggable = true,
-- climbable = false, -- climbable = false,
-- buildable_to = false, -- buildable_to = false,
-- wall_mounted = false, -- drop = "",
-- dug_item = "", -- -- alternatively drop = { max_items = ..., items = { ... } }
-- extra_dug_item = "",
-- extra_dug_item_rarity = 2,
-- metadata_name = "", -- metadata_name = "",
-- liquidtype = "none", -- liquidtype = "none",
-- liquid_alternative_flowing = "", -- liquid_alternative_flowing = "",
@ -368,21 +368,8 @@
-- cuttability = 0, -- cuttability = 0,
-- flammability = 0, -- flammability = 0,
-- }, -- },
-- on_drop = func(item, dropper), -- legacy_facedir_simple = false, -- Support maps made in and before January 2012
-- on_place = func(item, placer, pointed_thing), -- legacy_wallmounted = false, -- Support maps made in and before January 2012
-- on_use = func(item, user, pointed_thing),
-- }
--
-- Craftitem definition options:
-- {
-- description = <tooltip text>,
-- inventory_image = "default_unknown_block.png",
-- wield_image = "",
-- stack_max = <maximum number of items in stack>,
-- liquids_pointable = <whether can point liquids>,
-- on_drop = func(item, dropper),
-- on_place = func(item, placer, pointed_thing),
-- on_use = func(item, user, pointed_thing),
-- } -- }
-- --
-- Recipe: -- Recipe:
@ -1111,10 +1098,26 @@ minetest.register_craft({
minetest.register_node("default:stone", { minetest.register_node("default:stone", {
description = "Stone", description = "Stone",
tile_images = {"default_stone.png"}, tile_images = {"default_stone.png"},
paramtype = "mineral",
is_ground_content = true, is_ground_content = true,
material = minetest.digprop_stonelike(1.0), 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", { minetest.register_node("default:dirt_with_grass", {
@ -1122,7 +1125,7 @@ minetest.register_node("default:dirt_with_grass", {
tile_images = {"default_grass.png", "default_dirt.png", "default_dirt.png^default_grass_side.png"}, tile_images = {"default_grass.png", "default_dirt.png", "default_dirt.png^default_grass_side.png"},
is_ground_content = true, is_ground_content = true,
material = minetest.digprop_dirtlike(1.0), material = minetest.digprop_dirtlike(1.0),
dug_item = 'node "default:dirt" 1', drop = 'default:dirt',
}) })
minetest.register_node("default:dirt_with_grass_footsteps", { minetest.register_node("default:dirt_with_grass_footsteps", {
@ -1130,7 +1133,7 @@ minetest.register_node("default:dirt_with_grass_footsteps", {
tile_images = {"default_grass_footsteps.png", "default_dirt.png", "default_dirt.png^default_grass_side.png"}, tile_images = {"default_grass_footsteps.png", "default_dirt.png", "default_dirt.png^default_grass_side.png"},
is_ground_content = true, is_ground_content = true,
material = minetest.digprop_dirtlike(1.0), material = minetest.digprop_dirtlike(1.0),
dug_item = 'node "default:dirt" 1', drop = 'default:dirt',
}) })
minetest.register_node("default:dirt", { minetest.register_node("default:dirt", {
@ -1159,7 +1162,7 @@ minetest.register_node("default:sandstone", {
tile_images = {"default_sandstone.png"}, tile_images = {"default_sandstone.png"},
is_ground_content = true, is_ground_content = true,
material = minetest.digprop_dirtlike(1.0), -- FIXME should this be stonelike? 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", { minetest.register_node("default:clay", {
@ -1167,7 +1170,7 @@ minetest.register_node("default:clay", {
tile_images = {"default_clay.png"}, tile_images = {"default_clay.png"},
is_ground_content = true, is_ground_content = true,
material = minetest.digprop_dirtlike(1.0), material = minetest.digprop_dirtlike(1.0),
dug_item = 'craft "default:clay_lump" 4', drop = 'default:clay_lump 4',
}) })
minetest.register_node("default:brick", { minetest.register_node("default:brick", {
@ -1175,7 +1178,7 @@ minetest.register_node("default:brick", {
tile_images = {"default_brick.png"}, tile_images = {"default_brick.png"},
is_ground_content = true, is_ground_content = true,
material = minetest.digprop_stonelike(1.0), material = minetest.digprop_stonelike(1.0),
dug_item = 'craft "default:clay_brick" 4', drop = 'default:clay_brick 4',
}) })
minetest.register_node("default:tree", { minetest.register_node("default:tree", {
@ -1211,8 +1214,21 @@ minetest.register_node("default:leaves", {
tile_images = {"default_leaves.png"}, tile_images = {"default_leaves.png"},
paramtype = "light", paramtype = "light",
material = minetest.digprop_leaveslike(1.0), material = minetest.digprop_leaveslike(1.0),
extra_dug_item = 'node "default:sapling" 1', drop = {
extra_dug_item_rarity = 20, 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", { minetest.register_node("default:cactus", {
@ -1290,8 +1306,8 @@ minetest.register_node("default:ladder", {
inventory_image = "default_ladder.png", inventory_image = "default_ladder.png",
wield_image = "default_ladder.png", wield_image = "default_ladder.png",
paramtype = "light", paramtype = "light",
paramtype2 = "wallmounted",
is_ground_content = true, is_ground_content = true,
wall_mounted = true,
walkable = false, walkable = false,
climbable = true, climbable = true,
selection_box = { selection_box = {
@ -1301,6 +1317,7 @@ minetest.register_node("default:ladder", {
--wall_side = = <default> --wall_side = = <default>
}, },
material = minetest.digprop_woodlike(0.5), material = minetest.digprop_woodlike(0.5),
legacy_wallmounted = true,
}) })
minetest.register_node("default:wood", { minetest.register_node("default:wood", {
@ -1420,9 +1437,9 @@ minetest.register_node("default:torch", {
inventory_image = "default_torch_on_floor.png", inventory_image = "default_torch_on_floor.png",
wield_image = "default_torch_on_floor.png", wield_image = "default_torch_on_floor.png",
paramtype = "light", paramtype = "light",
paramtype2 = "wallmounted",
sunlight_propagates = true, sunlight_propagates = true,
walkable = false, walkable = false,
wall_mounted = true,
light_source = LIGHT_MAX-1, light_source = LIGHT_MAX-1,
selection_box = { selection_box = {
type = "wallmounted", type = "wallmounted",
@ -1431,6 +1448,7 @@ minetest.register_node("default:torch", {
wall_side = {-0.5, -0.3, -0.1, -0.5+0.3, 0.3, 0.1}, wall_side = {-0.5, -0.3, -0.1, -0.5+0.3, 0.3, 0.1},
}, },
material = minetest.digprop_constanttime(0.0), material = minetest.digprop_constanttime(0.0),
legacy_wallmounted = true,
}) })
minetest.register_node("default:sign_wall", { minetest.register_node("default:sign_wall", {
@ -1440,9 +1458,9 @@ minetest.register_node("default:sign_wall", {
inventory_image = "default_sign_wall.png", inventory_image = "default_sign_wall.png",
wield_image = "default_sign_wall.png", wield_image = "default_sign_wall.png",
paramtype = "light", paramtype = "light",
paramtype2 = "wallmounted",
sunlight_propagates = true, sunlight_propagates = true,
walkable = false, walkable = false,
wall_mounted = true,
metadata_name = "sign", metadata_name = "sign",
selection_box = { selection_box = {
type = "wallmounted", type = "wallmounted",
@ -1451,33 +1469,37 @@ minetest.register_node("default:sign_wall", {
--wall_side = <default> --wall_side = <default>
}, },
material = minetest.digprop_constanttime(0.5), material = minetest.digprop_constanttime(0.5),
legacy_wallmounted = true,
}) })
minetest.register_node("default:chest", { minetest.register_node("default:chest", {
description = "Chest", description = "Chest",
tile_images = {"default_chest_top.png", "default_chest_top.png", "default_chest_side.png", 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"}, "default_chest_side.png", "default_chest_side.png", "default_chest_front.png"},
paramtype = "facedir_simple", paramtype2 = "facedir",
metadata_name = "chest", metadata_name = "chest",
material = minetest.digprop_woodlike(1.0), material = minetest.digprop_woodlike(1.0),
legacy_facedir_simple = true,
}) })
minetest.register_node("default:chest_locked", { minetest.register_node("default:chest_locked", {
description = "Locked Chest", description = "Locked Chest",
tile_images = {"default_chest_top.png", "default_chest_top.png", "default_chest_side.png", 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"}, "default_chest_side.png", "default_chest_side.png", "default_chest_lock.png"},
paramtype = "facedir_simple", paramtype2 = "facedir",
metadata_name = "locked_chest", metadata_name = "locked_chest",
material = minetest.digprop_woodlike(1.0), material = minetest.digprop_woodlike(1.0),
legacy_facedir_simple = true,
}) })
minetest.register_node("default:furnace", { minetest.register_node("default:furnace", {
description = "Furnace", description = "Furnace",
tile_images = {"default_furnace_side.png", "default_furnace_side.png", "default_furnace_side.png", 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"}, "default_furnace_side.png", "default_furnace_side.png", "default_furnace_front.png"},
paramtype = "facedir_simple", paramtype2 = "facedir",
metadata_name = "furnace", metadata_name = "furnace",
material = minetest.digprop_stonelike(3.0), material = minetest.digprop_stonelike(3.0),
legacy_facedir_simple = true,
}) })
minetest.register_node("default:cobble", { minetest.register_node("default:cobble", {
@ -1506,8 +1528,9 @@ minetest.register_node("default:nyancat", {
tile_images = {"default_nc_side.png", "default_nc_side.png", "default_nc_side.png", 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"}, "default_nc_side.png", "default_nc_back.png", "default_nc_front.png"},
inventory_image = "default_nc_front.png", inventory_image = "default_nc_front.png",
paramtype = "facedir_simple", paramtype2 = "facedir",
material = minetest.digprop_stonelike(3.0), material = minetest.digprop_stonelike(3.0),
legacy_facedir_simple = true,
}) })
minetest.register_node("default:nyancat_rainbow", { minetest.register_node("default:nyancat_rainbow", {

Before

Width:  |  Height:  |  Size: 952 B

After

Width:  |  Height:  |  Size: 952 B

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

@ -6,6 +6,8 @@
-- --
minetest.register_alias("stone", "default:stone") 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", "default:dirt_with_grass")
minetest.register_alias("dirt_with_grass_footsteps", "default:dirt_with_grass_footsteps") minetest.register_alias("dirt_with_grass_footsteps", "default:dirt_with_grass_footsteps")
minetest.register_alias("dirt", "default:dirt") minetest.register_alias("dirt", "default:dirt")

@ -115,7 +115,6 @@ set(common_SRCS
nodemetadata.cpp nodemetadata.cpp
serverobject.cpp serverobject.cpp
noise.cpp noise.cpp
mineral.cpp
porting.cpp porting.cpp
materials.cpp materials.cpp
defaultsettings.cpp defaultsettings.cpp

@ -899,7 +899,7 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
Update an existing block Update an existing block
*/ */
//infostream<<"Updating"<<std::endl; //infostream<<"Updating"<<std::endl;
block->deSerialize(istr, ser_version); block->deSerialize(istr, ser_version, false);
} }
else else
{ {
@ -908,7 +908,7 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
*/ */
//infostream<<"Creating new"<<std::endl; //infostream<<"Creating new"<<std::endl;
block = new MapBlock(&m_env.getMap(), p, this); block = new MapBlock(&m_env.getMap(), p, this);
block->deSerialize(istr, ser_version); block->deSerialize(istr, ser_version, false);
sector->insertBlock(block); sector->insertBlock(block);
} }
@ -1816,8 +1816,7 @@ void Client::addNode(v3s16 p, MapNode n)
try try
{ {
//TimeTaker timer3("Client::addNode(): addNodeAndUpdate"); //TimeTaker timer3("Client::addNode(): addNodeAndUpdate");
std::string st = std::string(""); m_env.getMap().addNodeAndUpdate(p, n, modified_blocks);
m_env.getMap().addNodeAndUpdate(p, n, modified_blocks, st);
} }
catch(InvalidPositionException &e) catch(InvalidPositionException &e)
{} {}

@ -85,15 +85,15 @@ void makeCuboid(MeshCollector *collector, const aabb3f &box,
video::S3DVertex(min.X,min.Y,min.Z, -1,0,0, c, txc[14],txc[15]), 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]), video::S3DVertex(min.X,min.Y,max.Z, -1,0,0, c, txc[12],txc[15]),
// back // back
video::S3DVertex(min.X,max.Y,min.Z, 0,0,-1, c, txc[16],txc[17]), video::S3DVertex(max.X,max.Y,max.Z, 0,0,1, c, txc[16],txc[17]),
video::S3DVertex(max.X,max.Y,min.Z, 0,0,-1, c, txc[18],txc[17]), video::S3DVertex(min.X,max.Y,max.Z, 0,0,1, c, txc[18],txc[17]),
video::S3DVertex(max.X,min.Y,min.Z, 0,0,-1, c, txc[18],txc[19]), video::S3DVertex(min.X,min.Y,max.Z, 0,0,1, c, txc[18],txc[19]),
video::S3DVertex(min.X,min.Y,min.Z, 0,0,-1, c, txc[16],txc[19]), video::S3DVertex(max.X,min.Y,max.Z, 0,0,1, c, txc[16],txc[19]),
// front // front
video::S3DVertex(max.X,max.Y,max.Z, 0,0,1, c, txc[20],txc[21]), video::S3DVertex(min.X,max.Y,min.Z, 0,0,-1, c, txc[20],txc[21]),
video::S3DVertex(min.X,max.Y,max.Z, 0,0,1, c, txc[22],txc[21]), video::S3DVertex(max.X,max.Y,min.Z, 0,0,-1, c, txc[22],txc[21]),
video::S3DVertex(min.X,min.Y,max.Z, 0,0,1, c, txc[22],txc[23]), video::S3DVertex(max.X,min.Y,min.Z, 0,0,-1, c, txc[22],txc[23]),
video::S3DVertex(max.X,min.Y,max.Z, 0,0,1, c, txc[20],txc[23]), video::S3DVertex(min.X,min.Y,min.Z, 0,0,-1, c, txc[20],txc[23]),
}; };
for(s32 j=0; j<24; j++) for(s32 j=0; j<24; j++)
@ -602,7 +602,7 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
break; break;
case NDT_TORCHLIKE: case NDT_TORCHLIKE:
{ {
v3s16 dir = unpackDir(n.param2); v3s16 dir = n.getWallMountedDir(nodedef);
AtlasPointer ap(0); AtlasPointer ap(0);
if(dir == v3s16(0,-1,0)){ if(dir == v3s16(0,-1,0)){
@ -694,7 +694,7 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
ap.x0(), ap.y1()), ap.x0(), ap.y1()),
}; };
v3s16 dir = unpackDir(n.param2); v3s16 dir = n.getWallMountedDir(nodedef);
for(s32 i=0; i<4; i++) for(s32 i=0; i<4; i++)
{ {

@ -31,7 +31,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
Ranges: Ranges:
0x000...0x07f (0...127): param2 is fully usable 0x000...0x07f (0...127): param2 is fully usable
126 and 127 are reserved (CONTENT_AIR and CONTENT_IGNORE). 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_STONE 0
#define CONTENT_WATER 2 #define CONTENT_WATER 2

@ -2057,7 +2057,9 @@ void ClientEnvironment::step(float dtime)
MapNode n = m_map->getNode(p); MapNode n = m_map->getNode(p);
light = n.getLightBlend(getDayNightRatio(), m_gamedef->ndef()); light = n.getLightBlend(getDayNightRatio(), m_gamedef->ndef());
} }
catch(InvalidPositionException &e) {} catch(InvalidPositionException &e){
light = blend_light(getDayNightRatio(), LIGHT_SUN, 0);
}
player->updateLight(light); player->updateLight(light);
/* /*
@ -2104,7 +2106,6 @@ void ClientEnvironment::step(float dtime)
if(m_active_object_light_update_interval.step(dtime, 0.21)) if(m_active_object_light_update_interval.step(dtime, 0.21))
{ {
// Update lighting // Update lighting
//u8 light = LIGHT_MAX;
u8 light = 0; u8 light = 0;
try{ try{
// Get node at head // Get node at head
@ -2112,7 +2113,9 @@ void ClientEnvironment::step(float dtime)
MapNode n = m_map->getNode(p); MapNode n = m_map->getNode(p);
light = n.getLightBlend(getDayNightRatio(), m_gamedef->ndef()); light = n.getLightBlend(getDayNightRatio(), m_gamedef->ndef());
} }
catch(InvalidPositionException &e) {} catch(InvalidPositionException &e){
light = blend_light(getDayNightRatio(), LIGHT_SUN, 0);
}
obj->updateLight(light); obj->updateLight(light);
} }
} }
@ -2203,7 +2206,9 @@ u16 ClientEnvironment::addActiveObject(ClientActiveObject *object)
MapNode n = m_map->getNode(p); MapNode n = m_map->getNode(p);
light = n.getLightBlend(getDayNightRatio(), m_gamedef->ndef()); light = n.getLightBlend(getDayNightRatio(), m_gamedef->ndef());
} }
catch(InvalidPositionException &e) {} catch(InvalidPositionException &e){
light = blend_light(getDayNightRatio(), LIGHT_SUN, 0);
}
object->updateLight(light); object->updateLight(light);
} }
return object->getId(); return object->getId();

@ -303,6 +303,8 @@ PointedThing getPointedThing(Client *client, v3f player_position,
should_show_hilightbox = false; should_show_hilightbox = false;
selected_object = NULL; selected_object = NULL;
INodeDefManager *nodedef = client->getNodeDefManager();
// First try to find a pointed at active object // First try to find a pointed at active object
if(look_for_object) if(look_for_object)
{ {
@ -378,7 +380,7 @@ PointedThing getPointedThing(Client *client, v3f player_position,
v3s16(-1,0,0), // left 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) if(f.selection_box.type == NODEBOX_FIXED)
{ {
@ -447,7 +449,7 @@ PointedThing getPointedThing(Client *client, v3f player_position,
} }
else if(f.selection_box.type == NODEBOX_WALLMOUNTED) 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); v3f dir_f = v3f(dir.X, dir.Y, dir.Z);
dir_f *= BS/2 - BS/6 - BS/20; dir_f *= BS/2 - BS/6 - BS/20;
v3f cpf = npf + dir_f; v3f cpf = npf + dir_f;
@ -1827,11 +1829,10 @@ void the_game(
MapNode n = client.getNode(nodepos); MapNode n = client.getNode(nodepos);
// Get digging properties for material and tool // Get digging properties for material and tool
content_t material = n.getContent(); MaterialProperties mp = nodedef->get(n.getContent()).material;
ToolDiggingProperties tp = ToolDiggingProperties tp =
playeritem.getToolDiggingProperties(itemdef); playeritem.getToolDiggingProperties(itemdef);
DiggingProperties prop = DiggingProperties prop = getDiggingProperties(&mp, &tp);
getDiggingProperties(material, &tp, nodedef);
float dig_time_complete = 0.0; float dig_time_complete = 0.0;

@ -26,7 +26,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
class IItemDefManager; class IItemDefManager;
class INodeDefManager; class INodeDefManager;
class ICraftDefManager; class ICraftDefManager;
// Mineral too?
class ITextureSource; class ITextureSource;
/* /*

@ -75,16 +75,27 @@ inline u8 undiminish_light(u8 light)
extern u8 light_decode_table[LIGHT_MAX+1]; extern u8 light_decode_table[LIGHT_MAX+1];
// 0 <= light <= LIGHT_SUN
// 0 <= return value <= 255
inline u8 decode_light(u8 light) inline u8 decode_light(u8 light)
{ {
if(light == LIGHT_SUN)
return light_decode_table[LIGHT_MAX];
if(light > LIGHT_MAX) if(light > LIGHT_MAX)
light = LIGHT_MAX; light = LIGHT_MAX;
return light_decode_table[light]; 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 #endif

@ -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 + This was left to be done by the old system and it sends only the
nearest ones. 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: NOTE: Seeds in 1260:6c77e7dbfd29:
5721858502589302589: 5721858502589302589:
Spawns you on a small sand island with a surface dungeon 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: Protocol version field
TODO: Think about using same bits for material for fences and doors, for TODO: Think about using same bits for material for fences and doors, for
example example
TODO: Move mineral to param2, increment map serialization version, add
conversion
SUGG: Restart irrlicht completely when coming back to main menu from game. SUGG: Restart irrlicht completely when coming back to main menu from game.
- This gets rid of everything that is stored in irrlicht's caches. - This gets rid of everything that is stored in irrlicht's caches.
@ -419,7 +399,6 @@ Doing currently:
#include "filesys.h" #include "filesys.h"
#include "config.h" #include "config.h"
#include "guiMainMenu.h" #include "guiMainMenu.h"
#include "mineral.h"
#include "materials.h" #include "materials.h"
#include "game.h" #include "game.h"
#include "keycode.h" #include "keycode.h"
@ -1260,16 +1239,6 @@ int main(int argc, char *argv[])
srand(time(0)); srand(time(0));
mysrand(time(0)); 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 Run unit tests
*/ */

@ -915,7 +915,7 @@ void Map::updateLighting(core::map<v3s16, MapBlock*> & a_blocks,
/* /*
*/ */
void Map::addNodeAndUpdate(v3s16 p, MapNode n, 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(); INodeDefManager *nodemgr = m_gamedef->ndef();
@ -1010,9 +1010,6 @@ void Map::addNodeAndUpdate(v3s16 p, MapNode n,
if(!meta){ if(!meta){
errorstream<<"Failed to create node metadata \"" errorstream<<"Failed to create node metadata \""
<<metadata_name<<"\""<<std::endl; <<metadata_name<<"\""<<std::endl;
} else {
meta->setOwner(player_name);
setNodeMetadata(p, meta);
} }
} }
@ -1291,8 +1288,7 @@ bool Map::addNodeWithEvent(v3s16 p, MapNode n)
bool succeeded = true; bool succeeded = true;
try{ try{
core::map<v3s16, MapBlock*> modified_blocks; core::map<v3s16, MapBlock*> modified_blocks;
std::string st = std::string(""); addNodeAndUpdate(p, n, modified_blocks);
addNodeAndUpdate(p, n, modified_blocks, st);
// Copy modified_blocks to event // Copy modified_blocks to event
for(core::map<v3s16, MapBlock*>::Iterator for(core::map<v3s16, MapBlock*>::Iterator
@ -3271,10 +3267,7 @@ void ServerMap::saveBlock(MapBlock *block)
o.write((char*)&version, 1); o.write((char*)&version, 1);
// Write basic data // Write basic data
block->serialize(o, version); block->serialize(o, version, true);
// Write extra data stored on disk
block->serializeDiskExtra(o, version);
// Write block to database // Write block to database
@ -3336,10 +3329,7 @@ void ServerMap::loadBlock(std::string sectordir, std::string blockfile, MapSecto
} }
// Read basic data // 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 it's a new block, insert it to the map
if(created_new) if(created_new)
@ -3406,10 +3396,7 @@ void ServerMap::loadBlock(std::string *blob, v3s16 p3d, MapSector *sector, bool
} }
// Read basic data // 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 it's a new block, insert it to the map
if(created_new) if(created_new)

@ -212,7 +212,7 @@ public:
These handle lighting but not faces. These handle lighting but not faces.
*/ */
void addNodeAndUpdate(v3s16 p, MapNode n, 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, void removeNodeAndUpdate(v3s16 p,
core::map<v3s16, MapBlock*> &modified_blocks); core::map<v3s16, MapBlock*> &modified_blocks);

@ -507,26 +507,42 @@ s16 MapBlock::getGroundLevel(v2s16 p2d)
/* /*
Serialization Serialization
*/ */
// List relevant id-name pairs for ids in the block using nodedef // 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) INodeDefManager *nodedef)
{ {
std::map<content_t, content_t> mapping;
std::set<content_t> unknown_contents; std::set<content_t> unknown_contents;
for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++) content_t id_counter = 0;
for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++) for(u32 i=0; i<MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE; i++)
for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
{ {
v3s16 p(x0,y0,z0); content_t global_id = nodes[i].getContent();
MapNode n = block->getNode(p); content_t id = CONTENT_IGNORE;
content_t id = n.getContent();
const ContentFeatures &f = nodedef->get(id); // 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
{
// 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; const std::string &name = f.name;
if(name == "") if(name == "")
unknown_contents.insert(id); unknown_contents.insert(global_id);
else else
nimap->set(id, name); nimap->set(id, name);
} }
// Update the MapNode
nodes[i].setContent(id);
}
for(std::set<content_t>::const_iterator for(std::set<content_t>::const_iterator
i = unknown_contents.begin(); i = unknown_contents.begin();
i != unknown_contents.end(); i++){ i != unknown_contents.end(); i++){
@ -537,7 +553,7 @@ static void getBlockNodeIdMapping(NameIdMapping *nimap, MapBlock *block,
// Correct ids in the block to match nodedef based on names. // Correct ids in the block to match nodedef based on names.
// Unknown ones are added to nodedef. // Unknown ones are added to nodedef.
// Will not update itself to match id-name pairs in 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) IGameDef *gamedef)
{ {
INodeDefManager *nodedef = gamedef->ndef(); INodeDefManager *nodedef = gamedef->ndef();
@ -547,13 +563,9 @@ void correctBlockNodeIds(const NameIdMapping *nimap, MapBlock *block,
// correct ids. // correct ids.
std::set<content_t> unnamed_contents; std::set<content_t> unnamed_contents;
std::set<std::string> unallocatable_contents; std::set<std::string> unallocatable_contents;
for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++) for(u32 i=0; i<MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE; i++)
for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
{ {
v3s16 p(x0,y0,z0); content_t local_id = nodes[i].getContent();
MapNode n = block->getNode(p);
content_t local_id = n.getContent();
std::string name; std::string name;
bool found = nimap->getName(local_id, name); bool found = nimap->getName(local_id, name);
if(!found){ if(!found){
@ -569,8 +581,7 @@ void correctBlockNodeIds(const NameIdMapping *nimap, MapBlock *block,
continue; continue;
} }
} }
n.setContent(global_id); nodes[i].setContent(global_id);
block->setNode(p, n);
} }
for(std::set<content_t>::const_iterator for(std::set<content_t>::const_iterator
i = unnamed_contents.begin(); i = unnamed_contents.begin();
@ -588,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)) if(!ser_ver_supported(version))
throw VersionMismatchException("ERROR: MapBlock format not supported"); throw VersionMismatchException("ERROR: MapBlock format not supported");
@ -598,22 +609,226 @@ void MapBlock::serialize(std::ostream &os, u8 version)
throw SerializationError("ERROR: Not writing dummy block."); throw SerializationError("ERROR: Not writing dummy block.");
} }
// These have no compression if(version <= 21)
if(version <= 3 || version == 5 || version == 6) {
serialize_pre22(os, version, disk);
return;
}
// 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; u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
u32 buflen = 1 + nodecount * MapNode::serializedLength(version); MapNode *tmp_data = new MapNode[nodecount];
SharedBuffer<u8> dest(buflen);
dest[0] = is_underground; // 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++) for(u32 i=0; i<nodecount; i++)
{ {
u32 s = 1 + i * MapNode::serializedLength(version); const ContentFeatures &f = nodedef->get(tmp_data[i].getContent());
data[i].serialize(&dest[s], version); // Mineral
if(nodedef->getId("default:stone_with_coal") == tmp_data[i].getContent())
{
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);
}
} }
os.write((char*)*dest, dest.getSize()); // 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;
// 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) else if(version <= 10)
{ {
@ -623,15 +838,13 @@ void MapBlock::serialize(std::ostream &os, u8 version)
*/ */
// First byte // First byte
os.write((char*)&is_underground, 1); writeU8(os, is_underground);
u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
// Get and compress materials // Get and compress materials
SharedBuffer<u8> materialdata(nodecount); SharedBuffer<u8> materialdata(nodecount);
for(u32 i=0; i<nodecount; i++) for(u32 i=0; i<nodecount; i++)
{ {
materialdata[i] = data[i].param0; materialdata[i] = databuf_nodelist[i*ser_length];
} }
compress(materialdata, os, version); compress(materialdata, os, version);
@ -639,7 +852,7 @@ void MapBlock::serialize(std::ostream &os, u8 version)
SharedBuffer<u8> lightdata(nodecount); SharedBuffer<u8> lightdata(nodecount);
for(u32 i=0; i<nodecount; i++) for(u32 i=0; i<nodecount; i++)
{ {
lightdata[i] = data[i].param1; lightdata[i] = databuf_nodelist[i*ser_length+1];
} }
compress(lightdata, os, version); compress(lightdata, os, version);
@ -649,7 +862,7 @@ void MapBlock::serialize(std::ostream &os, u8 version)
SharedBuffer<u8> param2data(nodecount); SharedBuffer<u8> param2data(nodecount);
for(u32 i=0; i<nodecount; i++) for(u32 i=0; i<nodecount; i++)
{ {
param2data[i] = data[i].param2; param2data[i] = databuf_nodelist[i*ser_length+2];
} }
compress(param2data, os, version); compress(param2data, os, version);
} }
@ -670,28 +883,19 @@ void MapBlock::serialize(std::ostream &os, u8 version)
if(m_generated == false) if(m_generated == false)
flags |= 0x08; flags |= 0x08;
} }
os.write((char*)&flags, 1); writeU8(os, flags);
u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
/* /*
Get data 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 // Create buffer with different parameters sorted
SharedBuffer<u8> databuf(nodecount*3); SharedBuffer<u8> databuf(nodecount*3);
for(u32 i=0; i<nodecount; i++) for(u32 i=0; i<nodecount; i++)
{ {
databuf[i] = databuf_nodelist[i*3]; databuf[i] = databuf_nodelist[i*ser_length];
databuf[i+nodecount] = databuf_nodelist[i*3+1]; databuf[i+nodecount] = databuf_nodelist[i*ser_length+1];
databuf[i+nodecount*2] = databuf_nodelist[i*3+2]; databuf[i+nodecount*2] = databuf_nodelist[i*ser_length+2];
} }
/* /*
@ -728,50 +932,69 @@ void MapBlock::serialize(std::ostream &os, u8 version)
} }
} }
} }
if(disk)
{
// Versions up from 9 have block objects. (DEPRECATED)
if(version >= 9)
{
// count=0
writeU16(os, 0);
} }
void MapBlock::deSerialize(std::istream &is, u8 version) // Versions up from 15 have static objects.
if(version >= 15)
{ {
if(!ser_ver_supported(version)) m_static_objects.serialize(os);
throw VersionMismatchException("ERROR: MapBlock format not supported");
// These have no lighting info
if(version <= 1)
{
setLightingExpired(true);
} }
// These have no "generated" field // Timestamp
if(version < 18) 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; m_generated = true;
}
// Make a temporary buffer
u32 ser_length = MapNode::serializedLength(version);
SharedBuffer<u8> databuf_nodelist(nodecount * ser_length);
// These have no compression // These have no compression
if(version <= 3 || version == 5 || version == 6) if(version <= 3 || version == 5 || version == 6)
{ {
u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
char tmp; char tmp;
is.read(&tmp, 1); is.read(&tmp, 1);
if(is.gcount() != 1) if(is.gcount() != 1)
throw SerializationError throw SerializationError
("MapBlock::deSerialize: no enough input data"); ("MapBlock::deSerialize: no enough input data");
is_underground = tmp; is_underground = tmp;
for(u32 i=0; i<nodecount; i++) is.read((char*)*databuf_nodelist, nodecount * ser_length);
{ if(is.gcount() != nodecount * ser_length)
s32 len = MapNode::serializedLength(version);
SharedBuffer<u8> d(len);
is.read((char*)*d, len);
if(is.gcount() != len)
throw SerializationError throw SerializationError
("MapBlock::deSerialize: no enough input data"); ("MapBlock::deSerialize: no enough input data");
data[i].deSerialize(*d, version);
}
} }
else if(version <= 10) else if(version <= 10)
{ {
u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
u8 t8; u8 t8;
is.read((char*)&t8, 1); is.read((char*)&t8, 1);
is_underground = t8; is_underground = t8;
@ -786,7 +1009,7 @@ void MapBlock::deSerialize(std::istream &is, u8 version)
("MapBlock::deSerialize: invalid format"); ("MapBlock::deSerialize: invalid format");
for(u32 i=0; i<s.size(); i++) for(u32 i=0; i<s.size(); i++)
{ {
data[i].param0 = s[i]; databuf_nodelist[i*ser_length] = s[i];
} }
} }
{ {
@ -799,7 +1022,7 @@ void MapBlock::deSerialize(std::istream &is, u8 version)
("MapBlock::deSerialize: invalid format"); ("MapBlock::deSerialize: invalid format");
for(u32 i=0; i<s.size(); i++) for(u32 i=0; i<s.size(); i++)
{ {
data[i].param1 = s[i]; databuf_nodelist[i*ser_length + 1] = s[i];
} }
} }
@ -814,15 +1037,13 @@ void MapBlock::deSerialize(std::istream &is, u8 version)
("MapBlock::deSerialize: invalid format"); ("MapBlock::deSerialize: invalid format");
for(u32 i=0; i<s.size(); i++) 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) // All other versions (newest)
else else
{ {
u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
u8 flags; u8 flags;
is.read((char*)&flags, 1); is.read((char*)&flags, 1);
is_underground = (flags & 0x01) ? true : false; is_underground = (flags & 0x01) ? true : false;
@ -843,11 +1064,9 @@ void MapBlock::deSerialize(std::istream &is, u8 version)
// deserialize nodes from buffer // deserialize nodes from buffer
for(u32 i=0; i<nodecount; i++) for(u32 i=0; i<nodecount; i++)
{ {
u8 buf[3]; databuf_nodelist[i*ser_length] = s[i];
buf[0] = s[i]; databuf_nodelist[i*ser_length + 1] = s[i+nodecount];
buf[1] = s[i+nodecount]; databuf_nodelist[i*ser_length + 2] = s[i+nodecount*2];
buf[2] = s[i+nodecount*2];
data[i].deSerialize(buf, version);
} }
/* /*
@ -879,38 +1098,14 @@ void MapBlock::deSerialize(std::istream &is, u8 version)
} }
} }
} }
}
void MapBlock::serializeDiskExtra(std::ostream &os, u8 version) // Deserialize node data
for(u32 i=0; i<nodecount; i++)
{ {
// Versions up from 9 have block objects. (DEPRECATED) data[i].deSerialize(&databuf_nodelist[i*ser_length], version);
if(version >= 9)
{
// count=0
writeU16(os, 0);
} }
// Versions up from 15 have static objects. if(disk)
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(&nimap, this, m_gamedef->ndef());
nimap.serialize(os);
}
}
void MapBlock::deSerializeDiskExtra(std::istream &is, u8 version)
{ {
/* /*
Versions up from 9 have block objects. (DEPRECATED) Versions up from 9 have block objects. (DEPRECATED)
@ -919,7 +1114,7 @@ void MapBlock::deSerializeDiskExtra(std::istream &is, u8 version)
u16 count = readU16(is); u16 count = readU16(is);
// Not supported and length not known if count is not 0 // Not supported and length not known if count is not 0
if(count != 0){ if(count != 0){
errorstream<<"WARNING: MapBlock::deSerializeDiskExtra(): " errorstream<<"WARNING: MapBlock::deSerialize_pre22(): "
<<"Ignoring stuff coming at and after MBOs"<<std::endl; <<"Ignoring stuff coming at and after MBOs"<<std::endl;
return; return;
} }
@ -948,7 +1143,57 @@ void MapBlock::deSerializeDiskExtra(std::istream &is, u8 version)
} else { } else {
content_mapnode_get_name_id_mapping(&nimap); content_mapnode_get_name_id_mapping(&nimap);
} }
correctBlockNodeIds(&nimap, this, m_gamedef); correctBlockNodeIds(&nimap, data, m_gamedef);
}
// 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)
{
//dstream << "legacy coal\n";
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)
{
//dstream << "legacy iron\n";
data[i].setContent(nodedef->getId("default:stone_with_iron"));
data[i].setParam1(0);
}
// facedir_simple
if(f.legacy_facedir_simple)
{
dstream << "legacy_facedir_simple\n";
data[i].setParam2(data[i].getParam1());
data[i].setParam1(0);
}
// wall_mounted
if(f.legacy_wallmounted)
{
dstream << "legacy_wallmounted\n";
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);
}
}
} }
/* /*

@ -363,17 +363,8 @@ public:
Graphics-related methods Graphics-related methods
*/ */
/*// A quick version with nodes passed as parameters #ifndef SERVER // Only on client
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);
}*/
u8 getFaceLight2(u32 daynight_ratio, v3s16 p, v3s16 face_dir, u8 getFaceLight2(u32 daynight_ratio, v3s16 p, v3s16 face_dir,
INodeDefManager *nodemgr) INodeDefManager *nodemgr)
{ {
@ -383,8 +374,6 @@ public:
face_dir, nodemgr); face_dir, nodemgr);
} }
#ifndef SERVER // Only on client
#if 1 #if 1
/* /*
Thread-safely updates the whole mesh of the mapblock. Thread-safely updates the whole mesh of the mapblock.
@ -524,20 +513,20 @@ public:
*/ */
// These don't write or read version by itself // These don't write or read version by itself
void serialize(std::ostream &os, u8 version); // Set disk to true for on-disk format, false for over-the-network format
void deSerialize(std::istream &is, u8 version); void serialize(std::ostream &os, u8 version, bool disk);
// If disk == true: In addition to doing other things, will add
// Used after the basic ones when writing on disk (serverside) // unknown blocks from id-name mapping to wndef
void serializeDiskExtra(std::ostream &os, u8 version); void deSerialize(std::istream &is, u8 version, bool disk);
// In addition to doing other things, will add unknown blocks from
// id-name mapping to wndef
void deSerializeDiskExtra(std::istream &is, u8 version);
private: private:
/* /*
Private methods 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 Used only internally, because changes can't be tracked
*/ */

@ -27,7 +27,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "nodedef.h" #include "nodedef.h"
#include "gamedef.h" #include "gamedef.h"
#include "content_mapblock.h" #include "content_mapblock.h"
#include "mineral.h" // For mineral_block_texture
void MeshMakeData::fill(u32 daynight_ratio, MapBlock *block) void MeshMakeData::fill(u32 daynight_ratio, MapBlock *block)
{ {
@ -282,59 +281,37 @@ static void makeFastFace(TileSpec tile, u8 li0, u8 li1, u8 li2, u8 li3, v3f p,
dest.push_back(face); dest.push_back(face);
} }
static TileSpec getTile(const MapNode &node, v3s16 dir, static TileSpec getTile(const MapNode &node, v3s16 dir, INodeDefManager *nodemgr)
ITextureSource *tsrc, INodeDefManager *nodemgr)
{ {
const ContentFeatures &f = nodemgr->get(node); // 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);
if(f.param_type == CPT_FACEDIR_SIMPLE) // Convert direction to single integer for table lookup
dir = facedir_rotate(node.param1, dir); // 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;
TileSpec spec; // Get rotation for things like chests
u8 facedir = node.getFaceDir(nodemgr);
assert(facedir <= 3);
s32 dir_i = -1; static const u8 dir_to_tile[4 * 8] =
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)
{ {
u8 mineral = node.getMineral(nodemgr); // 0 +X +Y +Z 0 -Z -Y -X
std::string mineral_texture_name = mineral_block_texture(mineral); 0, 2, 0, 4, 0, 5, 1, 3, // facedir = 0
if(mineral_texture_name != "") 0, 4, 0, 3, 0, 2, 1, 5, // facedir = 1
{ 0, 3, 0, 5, 0, 4, 1, 2, // facedir = 2
u32 orig_id = spec.texture.id; 0, 5, 0, 2, 0, 3, 1, 4, // facedir = 3
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; return nodemgr->get(node).tiles[dir_to_tile[facedir*8 + dir_i]];
} }
/* /*
@ -345,7 +322,7 @@ TileSpec getNodeTile(MapNode mn, v3s16 p, v3s16 face_dir,
NodeModMap *temp_mods, ITextureSource *tsrc, INodeDefManager *ndef) NodeModMap *temp_mods, ITextureSource *tsrc, INodeDefManager *ndef)
{ {
TileSpec spec; TileSpec spec;
spec = getTile(mn, face_dir, tsrc, ndef); spec = getTile(mn, face_dir, ndef);
/* /*
Check temporary modifications on this node Check temporary modifications on this node
@ -363,7 +340,7 @@ TileSpec getNodeTile(MapNode mn, v3s16 p, v3s16 face_dir,
if(mod.type == NODEMOD_CHANGECONTENT) if(mod.type == NODEMOD_CHANGECONTENT)
{ {
MapNode mn2(mod.param); MapNode mn2(mod.param);
spec = getTile(mn2, face_dir, tsrc, ndef); spec = getTile(mn2, face_dir, ndef);
} }
#endif #endif
if(mod.type == NODEMOD_CRACK) if(mod.type == NODEMOD_CRACK)

@ -22,7 +22,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "noise.h" #include "noise.h"
#include "mapblock.h" #include "mapblock.h"
#include "map.h" #include "map.h"
#include "mineral.h"
//#include "serverobject.h" //#include "serverobject.h"
#include "content_sao.h" #include "content_sao.h"
#include "nodedef.h" #include "nodedef.h"
@ -1652,15 +1651,20 @@ void make_block(BlockMakeData *data)
MapNode n_##name(c_##name); MapNode n_##name(c_##name);
CONTENT_VARIABLE(ndef, stone); CONTENT_VARIABLE(ndef, stone);
CONTENT_VARIABLE(ndef, water_source);
CONTENT_VARIABLE(ndef, air); CONTENT_VARIABLE(ndef, air);
CONTENT_VARIABLE(ndef, water_source);
CONTENT_VARIABLE(ndef, dirt); CONTENT_VARIABLE(ndef, dirt);
CONTENT_VARIABLE(ndef, sand); CONTENT_VARIABLE(ndef, sand);
CONTENT_VARIABLE(ndef, gravel); CONTENT_VARIABLE(ndef, gravel);
CONTENT_VARIABLE(ndef, clay);
CONTENT_VARIABLE(ndef, lava_source); CONTENT_VARIABLE(ndef, lava_source);
CONTENT_VARIABLE(ndef, cobble); CONTENT_VARIABLE(ndef, cobble);
CONTENT_VARIABLE(ndef, mossycobble); CONTENT_VARIABLE(ndef, mossycobble);
CONTENT_VARIABLE(ndef, dirt_with_grass); 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 Make base ground level
@ -1702,139 +1706,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) 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) /*else if(vmanip.m_flags[i] & VMANIP_FLAG_DUNGEON_INSIDE)
{ {
if(wetness > 1.2) 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); 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)) ((claynoise > 0) && (claynoise < 0.12) && (current_depth == 1))
); );
if (have_clay) if (have_clay)
vmanip.m_data[i] = MapNode(LEGN(ndef, "CONTENT_CLAY")); vmanip.m_data[i] = MapNode(c_clay);
else else
vmanip.m_data[i] = MapNode(LEGN(ndef, "CONTENT_SAND")); vmanip.m_data[i] = MapNode(c_sand);
} }
#if 1 #if 1
else if(current_depth==0 && !water_detected else if(current_depth==0 && !water_detected
&& y >= WATER_LEVEL && air_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 #endif
else else
vmanip.m_data[i] = MapNode(LEGN(ndef, "CONTENT_MUD")); vmanip.m_data[i] = MapNode(c_dirt);
} }
else else
{ {
if(vmanip.m_data[i].getContent() == LEGN(ndef, "CONTENT_MUD") if(vmanip.m_data[i].getContent() == c_dirt
|| vmanip.m_data[i].getContent() == LEGN(ndef, "CONTENT_GRASS")) || vmanip.m_data[i].getContent() == c_dirt_with_grass)
vmanip.m_data[i] = MapNode(LEGN(ndef, "CONTENT_STONE")); vmanip.m_data[i] = MapNode(c_stone);
} }
current_depth++; current_depth++;
@ -2171,7 +2042,7 @@ void make_block(BlockMakeData *data)
make_papyrus(vmanip, p, ndef); make_papyrus(vmanip, p, ndef);
} }
// Trees grow only on mud and grass, on land // 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++; p.Y++;
//if(surface_humidity_2d(data->seed, v2s16(x, y)) < 0.5) //if(surface_humidity_2d(data->seed, v2s16(x, y)) < 0.5)
@ -2238,10 +2109,10 @@ void make_block(BlockMakeData *data)
continue; continue;
/*p.Y--; /*p.Y--;
if(vmanip.m_area.contains(p)) 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++;*/ p.Y++;*/
if(vmanip.m_area.contains(p)) 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)); u32 i = data->vmanip->m_area.index(v3s16(p));
MapNode *n = &data->vmanip->m_data[i]; 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; continue;
}*/ }*/
// Will be placed one higher // Will be placed one higher
@ -2304,7 +2175,7 @@ void make_block(BlockMakeData *data)
/*{ /*{
u32 i = data->vmanip->m_area.index(v3s16(p)); u32 i = data->vmanip->m_area.index(v3s16(p));
MapNode *n = &data->vmanip->m_data[i]; 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; continue;
}*/ }*/
// Will be placed one lower // Will be placed one lower
@ -2315,6 +2186,139 @@ void make_block(BlockMakeData *data)
#endif #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(): BlockMakeData::BlockMakeData():

@ -21,13 +21,342 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "mapnode.h" #include "mapnode.h"
#include "porting.h" #include "porting.h"
#include <string> #include <string>
#include "mineral.h"
#include "main.h" // For g_settings #include "main.h" // For g_settings
#include "nodedef.h" #include "nodedef.h"
#include "content_mapnode.h" // For mapnode_translate_*_internal #include "content_mapnode.h" // For mapnode_translate_*_internal
#include "serialization.h" // For ser_ver_supported #include "serialization.h" // For ser_ver_supported
/*
MapNode
*/
// Create directly from a nodename
// If name is unknown, sets CONTENT_IGNORE
MapNode::MapNode(INodeDefManager *ndef, const std::string &name,
u8 a_param1, u8 a_param2)
{
content_t id = CONTENT_IGNORE;
ndef->getId(name, id);
param1 = a_param1;
param2 = a_param2;
// Set content (param0 and (param2&0xf0)) after other params
// because this needs to override part of param2
setContent(id);
}
void MapNode::setLight(enum LightBank bank, u8 a_light, INodeDefManager *nodemgr)
{
// If node doesn't contain light data, ignore this
if(nodemgr->get(*this).param_type != CPT_LIGHT)
return;
if(bank == LIGHTBANK_DAY)
{
param1 &= 0xf0;
param1 |= a_light & 0x0f;
}
else if(bank == LIGHTBANK_NIGHT)
{
param1 &= 0x0f;
param1 |= (a_light & 0x0f)<<4;
}
else
assert(0);
}
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(f.param_type == CPT_LIGHT)
{
if(bank == LIGHTBANK_DAY)
light = param1 & 0x0f;
else if(bank == LIGHTBANK_NIGHT)
light = (param1>>4)&0x0f;
else
assert(0);
}
if(f.light_source > light)
light = f.light_source;
return light;
}
bool MapNode::getLightBanks(u8 &lightday, u8 &lightnight, INodeDefManager *nodemgr) const
{
// Select the brightest of [light source, propagated light]
const ContentFeatures &f = nodemgr->get(*this);
if(f.param_type == CPT_LIGHT)
{
lightday = param1 & 0x0f;
lightnight = (param1>>4)&0x0f;
}
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::getFaceDir(INodeDefManager *nodemgr) const
{
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))
{
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);
}
}
u32 MapNode::serializedLength(u8 version)
{
if(!ser_ver_supported(version))
throw VersionMismatchException("ERROR: MapNode format not supported");
if(version == 0)
return 1;
else if(version <= 9)
return 2;
else
return 3;
}
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);
u16 actual_content = n_foreign.param0;
// Convert special values from new version to old
if(version <= 18)
{
// In these versions, CONTENT_IGNORE and CONTENT_AIR
// are 255 and 254
if(actual_content == CONTENT_IGNORE)
actual_content = 255;
else if(actual_content == CONTENT_AIR)
actual_content = 254;
}
if(version == 0)
{
dest[0] = actual_content;
}
else if(version <= 9)
{
dest[0] = actual_content;
dest[1] = n_foreign.param1;
}
else
{
dest[0] = actual_content;
dest[1] = n_foreign.param1;
dest[2] = n_foreign.param2;
}
}
void MapNode::deSerialize_pre22(u8 *source, u8 version)
{
if(version <= 1)
{
param0 = source[0];
}
else if(version <= 9)
{
param0 = source[0];
param1 = source[1];
}
else
{
param0 = source[0];
param1 = source[1];
param2 = source[2];
}
// Convert special values from old version to new
if(version <= 19)
{
// In these versions, CONTENT_IGNORE and CONTENT_AIR
// are 255 and 254
// Version 19 is fucked up with sometimes the old values and sometimes not
if(param0 == 255)
param0 = CONTENT_IGNORE;
else if(param0 == 254)
param0 = CONTENT_AIR;
}
// Translate to our known version
*this = mapnode_translate_to_internal(*this, version);
}
#ifndef SERVER #ifndef SERVER
/* /*
Nodes make a face if contents differ and solidness differs. Nodes make a face if contents differ and solidness differs.
Return value: Return value:
@ -83,252 +412,6 @@ u8 face_contents(content_t m1, content_t m2, bool *equivalent,
else else
return 2; 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
*/
// Create directly from a nodename
// If name is unknown, sets CONTENT_IGNORE
MapNode::MapNode(INodeDefManager *ndef, const std::string &name,
u8 a_param1, u8 a_param2)
{
content_t id = CONTENT_IGNORE;
ndef->getId(name, id);
param1 = a_param1;
param2 = a_param2;
// Set content (param0 and (param2&0xf0)) after other params
// because this needs to override part of param2
setContent(id);
}
void MapNode::setLight(enum LightBank bank, u8 a_light, INodeDefManager *nodemgr)
{
// If node doesn't contain light data, ignore this
if(nodemgr->get(*this).param_type != CPT_LIGHT)
return;
if(bank == LIGHTBANK_DAY)
{
param1 &= 0xf0;
param1 |= a_light & 0x0f;
}
else if(bank == LIGHTBANK_NIGHT)
{
param1 &= 0x0f;
param1 |= (a_light & 0x0f)<<4;
}
else
assert(0);
}
u8 MapNode::getLight(enum LightBank bank, INodeDefManager *nodemgr) const
{
// Select the brightest of [light source, propagated light]
u8 light = 0;
if(nodemgr->get(*this).param_type == CPT_LIGHT)
{
if(bank == LIGHTBANK_DAY)
light = param1 & 0x0f;
else if(bank == LIGHTBANK_NIGHT)
light = (param1>>4)&0x0f;
else
assert(0);
}
if(nodemgr->get(*this).light_source > light)
light = nodemgr->get(*this).light_source;
return light;
}
u8 MapNode::getLightBanksWithSource(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)
{
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);
}
u8 MapNode::getMineral(INodeDefManager *nodemgr) const
{
if(nodemgr->get(*this).param_type == CPT_MINERAL)
{
return param1 & 0x0f;
}
return MINERAL_NONE;
}
u32 MapNode::serializedLength(u8 version)
{
if(!ser_ver_supported(version))
throw VersionMismatchException("ERROR: MapNode format not supported");
if(version == 0)
return 1;
else if(version <= 9)
return 2;
else
return 3;
}
void MapNode::serialize(u8 *dest, u8 version)
{
if(!ser_ver_supported(version))
throw VersionMismatchException("ERROR: MapNode format not supported");
// Translate to wanted version
MapNode n_foreign = mapnode_translate_from_internal(*this, version);
u8 actual_param0 = n_foreign.param0;
// Convert special values from new version to old
if(version <= 18)
{
// In these versions, CONTENT_IGNORE and CONTENT_AIR
// are 255 and 254
if(actual_param0 == CONTENT_IGNORE)
actual_param0 = 255;
else if(actual_param0 == CONTENT_AIR)
actual_param0 = 254;
}
if(version == 0)
{
dest[0] = actual_param0;
}
else if(version <= 9)
{
dest[0] = actual_param0;
dest[1] = n_foreign.param1;
}
else
{
dest[0] = actual_param0;
dest[1] = n_foreign.param1;
dest[2] = n_foreign.param2;
}
}
void MapNode::deSerialize(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)
{
param0 = source[0];
}
else if(version <= 9)
{
param0 = source[0];
param1 = source[1];
}
else
{
param0 = source[0];
param1 = source[1];
param2 = source[2];
}
// Convert special values from old version to new
if(version <= 18)
{
// 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)
{
if(param0 == 255)
param0 = CONTENT_IGNORE;
else if(param0 == 254)
param0 = CONTENT_AIR;
}
// Translate to our known version
*this = mapnode_translate_to_internal(*this, version);
}
/* /*
Gets lighting value at face of node Gets lighting value at face of node
@ -380,4 +463,5 @@ u8 getFaceLight(u32 daynight_ratio, MapNode n, MapNode n2,
} }
} }
#endif

@ -33,7 +33,7 @@ class INodeDefManager;
Content ranges: Content ranges:
0x000...0x07f: param2 is fully usable 0x000...0x07f: param2 is fully usable
0x800...0xfff: param2 lower 4 bytes are free 0x800...0xfff: param2 lower 4 bits are free
*/ */
typedef u16 content_t; typedef u16 content_t;
#define MAX_CONTENT 0xfff #define MAX_CONTENT 0xfff
@ -56,36 +56,6 @@ typedef u16 content_t;
*/ */
#define CONTENT_AIR 126 #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 enum LightBank
{ {
LIGHTBANK_DAY, LIGHTBANK_DAY,
@ -122,7 +92,6 @@ struct MapNode
stored logarithmically from 0 to LIGHT_MAX. stored logarithmically from 0 to LIGHT_MAX.
Sunlight is LIGHT_SUN, which is LIGHT_MAX+1. Sunlight is LIGHT_SUN, which is LIGHT_MAX+1.
- Contains 2 values, day- and night lighting. Each takes 4 bits. - 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. - Uhh... well, most blocks have light or nothing in here.
*/ */
u8 param1; u8 param1;
@ -143,7 +112,7 @@ struct MapNode
{ {
param1 = a_param1; param1 = a_param1;
param2 = a_param2; param2 = a_param2;
// Set content (param0 and (param2&0xf0)) after other params // Set content (param0 and param2&0xf0)) after other params
// because this needs to override part of param2 // because this needs to override part of param2
setContent(content); setContent(content);
} }
@ -210,39 +179,21 @@ struct MapNode
void setLight(enum LightBank bank, u8 a_light, INodeDefManager *nodemgr); void setLight(enum LightBank bank, u8 a_light, INodeDefManager *nodemgr);
u8 getLight(enum LightBank bank, INodeDefManager *nodemgr) const; 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 <= daylight_factor <= 1000
// 0 <= return value <= LIGHT_SUN // 0 <= return value <= LIGHT_SUN
u8 getLightBlend(u32 daylight_factor, INodeDefManager *nodemgr) const u8 getLightBlend(u32 daylight_factor, INodeDefManager *nodemgr) const
{ {
u8 l = ((daylight_factor * getLight(LIGHTBANK_DAY, nodemgr) u8 lightday = 0;
+ (1000-daylight_factor) * getLight(LIGHTBANK_NIGHT, nodemgr)) u8 lightnight = 0;
)/1000; getLightBanks(lightday, lightnight, nodemgr);
u8 max = LIGHT_MAX; return blend_light(daylight_factor, lightday, lightnight);
if(getLight(LIGHTBANK_DAY, nodemgr) == LIGHT_SUN)
max = LIGHT_SUN;
if(l > max)
l = max;
return l;
} }
/*// 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;
}*/
/* u8 getFaceDir(INodeDefManager *nodemgr) const;
Gets mineral content of node, if there is any. u8 getWallMounted(INodeDefManager *nodemgr) const;
MINERAL_NONE if doesn't contain or isn't able to contain mineral. v3s16 getWallMountedDir(INodeDefManager *nodemgr) const;
*/
u8 getMineral(INodeDefManager *nodemgr) const;
/* /*
Serialization functions Serialization functions
@ -252,8 +203,44 @@ struct MapNode
void serialize(u8 *dest, u8 version); void serialize(u8 *dest, u8 version);
void deSerialize(u8 *source, 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 Gets lighting value at face of node
@ -275,3 +262,6 @@ u8 getFaceLight(u32 daynight_ratio, MapNode n, MapNode n2,
#endif #endif
#endif

@ -18,8 +18,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
*/ */
#include "materials.h" #include "materials.h"
#include "mapnode.h"
#include "nodedef.h"
#include "utility.h" #include "utility.h"
void MaterialProperties::serialize(std::ostream &os) void MaterialProperties::serialize(std::ostream &os)
@ -139,13 +137,6 @@ DiggingProperties getDiggingProperties(const MaterialProperties *mp,
return getDiggingProperties(mp, tp, 1000000); 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, HittingProperties getHittingProperties(const MaterialProperties *mp,
const ToolDiggingProperties *tp, float time_from_last_punch) const ToolDiggingProperties *tp, float time_from_last_punch)
{ {
@ -160,3 +151,9 @@ HittingProperties getHittingProperties(const MaterialProperties *mp,
return HittingProperties(hp, wear); return HittingProperties(hp, wear);
} }
HittingProperties getHittingProperties(const MaterialProperties *mp,
const ToolDiggingProperties *tp)
{
return getHittingProperties(mp, tp, 1000000);
}

@ -110,17 +110,12 @@ struct DiggingProperties
{} {}
}; };
class INodeDefManager;
DiggingProperties getDiggingProperties(const MaterialProperties *mp, DiggingProperties getDiggingProperties(const MaterialProperties *mp,
const ToolDiggingProperties *tp, float time_from_last_punch); const ToolDiggingProperties *tp, float time_from_last_punch);
DiggingProperties getDiggingProperties(const MaterialProperties *mp, DiggingProperties getDiggingProperties(const MaterialProperties *mp,
const ToolDiggingProperties *tp); const ToolDiggingProperties *tp);
DiggingProperties getDiggingProperties(u16 content,
const ToolDiggingProperties *tp, INodeDefManager *nodemgr);
struct HittingProperties struct HittingProperties
{ {
s16 hp; s16 hp;
@ -135,5 +130,8 @@ struct HittingProperties
HittingProperties getHittingProperties(const MaterialProperties *mp, HittingProperties getHittingProperties(const MaterialProperties *mp,
const ToolDiggingProperties *tp, float time_from_last_punch); const ToolDiggingProperties *tp, float time_from_last_punch);
HittingProperties getHittingProperties(const MaterialProperties *mp,
const ToolDiggingProperties *tp);
#endif #endif

@ -1,62 +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"
#include "gamedef.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];
}
ItemStack getDiggedMineralItem(u8 mineral, IGameDef *gamedef)
{
if(mineral == MINERAL_COAL)
return ItemStack("default:coal_lump", 1, 0, "", gamedef->idef());
else if(mineral == MINERAL_IRON)
return ItemStack("default:iron_lump", 1, 0, "", gamedef->idef());
else
return ItemStack();
}

@ -1,47 +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
class IGameDef;
std::string mineral_block_texture(u8 mineral);
ItemStack getDiggedMineralItem(u8 mineral, IGameDef *gamedef);
#endif

@ -70,6 +70,9 @@ public:
result = i->second; result = i->second;
return true; return true;
} }
u16 size() const{
return m_id_to_name.size();
}
private: private:
std::map<u16, std::string> m_id_to_name; std::map<u16, std::string> m_id_to_name;
std::map<std::string, u16> m_name_to_id; std::map<std::string, u16> m_name_to_id;

@ -127,6 +127,7 @@ void ContentFeatures::reset()
alpha = 255; alpha = 255;
post_effect_color = video::SColor(0, 0, 0, 0); post_effect_color = video::SColor(0, 0, 0, 0);
param_type = CPT_NONE; param_type = CPT_NONE;
param_type_2 = CPT2_NONE;
is_ground_content = false; is_ground_content = false;
light_propagates = false; light_propagates = false;
sunlight_propagates = false; sunlight_propagates = false;
@ -135,10 +136,6 @@ void ContentFeatures::reset()
diggable = true; diggable = true;
climbable = false; climbable = false;
buildable_to = false; buildable_to = false;
wall_mounted = false;
dug_item = "";
extra_dug_item = "";
extra_dug_item_rarity = 2;
metadata_name = ""; metadata_name = "";
liquid_type = LIQUID_NONE; liquid_type = LIQUID_NONE;
liquid_alternative_flowing = ""; liquid_alternative_flowing = "";
@ -151,6 +148,8 @@ void ContentFeatures::reset()
// Make unknown blocks diggable // Make unknown blocks diggable
material.diggability = DIGGABLE_CONSTANT; material.diggability = DIGGABLE_CONSTANT;
material.constant_time = 0.5; material.constant_time = 0.5;
legacy_facedir_simple = false;
legacy_wallmounted = false;
} }
void ContentFeatures::serialize(std::ostream &os) void ContentFeatures::serialize(std::ostream &os)
@ -172,6 +171,7 @@ void ContentFeatures::serialize(std::ostream &os)
writeU8(os, post_effect_color.getGreen()); writeU8(os, post_effect_color.getGreen());
writeU8(os, post_effect_color.getBlue()); writeU8(os, post_effect_color.getBlue());
writeU8(os, param_type); writeU8(os, param_type);
writeU8(os, param_type_2);
writeU8(os, is_ground_content); writeU8(os, is_ground_content);
writeU8(os, light_propagates); writeU8(os, light_propagates);
writeU8(os, sunlight_propagates); writeU8(os, sunlight_propagates);
@ -180,10 +180,6 @@ void ContentFeatures::serialize(std::ostream &os)
writeU8(os, diggable); writeU8(os, diggable);
writeU8(os, climbable); writeU8(os, climbable);
writeU8(os, buildable_to); writeU8(os, buildable_to);
writeU8(os, wall_mounted);
os<<serializeString(dug_item);
os<<serializeString(extra_dug_item);
writeS32(os, extra_dug_item_rarity);
os<<serializeString(metadata_name); os<<serializeString(metadata_name);
writeU8(os, liquid_type); writeU8(os, liquid_type);
os<<serializeString(liquid_alternative_flowing); os<<serializeString(liquid_alternative_flowing);
@ -193,6 +189,8 @@ void ContentFeatures::serialize(std::ostream &os)
writeU32(os, damage_per_second); writeU32(os, damage_per_second);
selection_box.serialize(os); selection_box.serialize(os);
material.serialize(os); material.serialize(os);
writeU8(os, legacy_facedir_simple);
writeU8(os, legacy_wallmounted);
} }
void ContentFeatures::deSerialize(std::istream &is) void ContentFeatures::deSerialize(std::istream &is)
@ -218,6 +216,7 @@ void ContentFeatures::deSerialize(std::istream &is)
post_effect_color.setGreen(readU8(is)); post_effect_color.setGreen(readU8(is));
post_effect_color.setBlue(readU8(is)); post_effect_color.setBlue(readU8(is));
param_type = (enum ContentParamType)readU8(is); param_type = (enum ContentParamType)readU8(is);
param_type_2 = (enum ContentParamType2)readU8(is);
is_ground_content = readU8(is); is_ground_content = readU8(is);
light_propagates = readU8(is); light_propagates = readU8(is);
sunlight_propagates = readU8(is); sunlight_propagates = readU8(is);
@ -226,10 +225,6 @@ void ContentFeatures::deSerialize(std::istream &is)
diggable = readU8(is); diggable = readU8(is);
climbable = readU8(is); climbable = readU8(is);
buildable_to = readU8(is); buildable_to = readU8(is);
wall_mounted = readU8(is);
dug_item = deSerializeString(is);
extra_dug_item = deSerializeString(is);
extra_dug_item_rarity = readS32(is);
metadata_name = deSerializeString(is); metadata_name = deSerializeString(is);
liquid_type = (enum LiquidType)readU8(is); liquid_type = (enum LiquidType)readU8(is);
liquid_alternative_flowing = deSerializeString(is); liquid_alternative_flowing = deSerializeString(is);
@ -239,6 +234,8 @@ void ContentFeatures::deSerialize(std::istream &is)
damage_per_second = readU32(is); damage_per_second = readU32(is);
selection_box.deSerialize(is); selection_box.deSerialize(is);
material.deSerialize(is); material.deSerialize(is);
legacy_facedir_simple = readU8(is);
legacy_wallmounted = readU8(is);
} }
/* /*
@ -298,7 +295,7 @@ public:
// CONTENT_IGNORE = not found // CONTENT_IGNORE = not found
content_t getFreeId(bool require_full_param2) 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){ if(!require_full_param2){
for(u16 i=0x800; i<=0xfff; i++){ for(u16 i=0x800; i<=0xfff; i++){
const ContentFeatures &f = m_content_features[i]; const ContentFeatures &f = m_content_features[i];
@ -306,7 +303,7 @@ public:
return i; 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++){ for(u16 i=0; i<=125; i++){
const ContentFeatures &f = m_content_features[i]; const ContentFeatures &f = m_content_features[i];
if(f.name == "") if(f.name == "")
@ -394,13 +391,9 @@ public:
if(!found){ if(!found){
// Determine if full param2 is required // Determine if full param2 is required
bool require_full_param2 = ( 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
); );
// Get some id // Get some id
id = getFreeId(require_full_param2); id = getFreeId(require_full_param2);

@ -37,9 +37,19 @@ enum ContentParamType
{ {
CPT_NONE, CPT_NONE,
CPT_LIGHT, 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 // Direction for chests and furnaces and such
CPT_FACEDIR_SIMPLE CPT2_FACEDIR,
// Direction for signs, torches and such
CPT2_WALLMOUNTED,
}; };
enum LiquidType enum LiquidType
@ -53,7 +63,7 @@ enum NodeBoxType
{ {
NODEBOX_REGULAR, // Regular block; allows buildable_to NODEBOX_REGULAR, // Regular block; allows buildable_to
NODEBOX_FIXED, // Static separately defined box 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 struct NodeBox
@ -151,6 +161,8 @@ struct ContentFeatures
video::SColor post_effect_color; video::SColor post_effect_color;
// Type of MapNode::param1 // Type of MapNode::param1
ContentParamType param_type; 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 // True for all ground-like things like stone and mud, false for eg. trees
bool is_ground_content; bool is_ground_content;
bool light_propagates; bool light_propagates;
@ -166,16 +178,6 @@ struct ContentFeatures
bool climbable; bool climbable;
// Player can build on these // Player can build on these
bool buildable_to; 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;
// 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") // Metadata name of node (eg. "furnace")
std::string metadata_name; std::string metadata_name;
// Whether the node is non-liquid, source liquid or flowing liquid // Whether the node is non-liquid, source liquid or flowing liquid
@ -193,6 +195,11 @@ struct ContentFeatures
u32 damage_per_second; u32 damage_per_second;
NodeBox selection_box; NodeBox selection_box;
MaterialProperties material; MaterialProperties material;
// 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 Methods

@ -314,6 +314,15 @@ static int getenumfield(lua_State *L, int table,
return result; 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, static void setfloatfield(lua_State *L, int table,
const char *fieldname, float value) const char *fieldname, float value)
{ {
@ -323,6 +332,15 @@ static void setfloatfield(lua_State *L, int table,
lua_setfield(L, table, fieldname); 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, static void warn_if_field_exists(lua_State *L, int table,
const char *fieldname, const std::string &message) const char *fieldname, const std::string &message)
{ {
@ -369,8 +387,16 @@ struct EnumString es_ContentParamType[] =
{ {
{CPT_NONE, "none"}, {CPT_NONE, "none"},
{CPT_LIGHT, "light"}, {CPT_LIGHT, "light"},
{CPT_MINERAL, "mineral"}, {0, NULL},
{CPT_FACEDIR_SIMPLE, "facedir_simple"}, };
struct EnumString es_ContentParamType2[] =
{
{CPT2_NONE, "none"},
{CPT2_FULL, "full"},
{CPT2_FLOWINGLIQUID, "flowingliquid"},
{CPT2_FACEDIR, "facedir"},
{CPT2_WALLMOUNTED, "wallmounted"},
{0, NULL}, {0, NULL},
}; };
@ -586,6 +612,25 @@ static core::aabbox3d<f32> read_aabbox3df32(lua_State *L, int index, f32 scale)
return box; return box;
} }
/*
MaterialProperties
*/
static MaterialProperties read_material_properties(
lua_State *L, int table)
{
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;
}
/* /*
ToolDiggingProperties ToolDiggingProperties
*/ */
@ -631,6 +676,43 @@ static void push_tool_digging_properties(lua_State *L,
set_tool_digging_properties(L, -1, prop); set_tool_digging_properties(L, -1, prop);
} }
/*
DiggingProperties
*/
static void set_digging_properties(lua_State *L, int table,
const DiggingProperties &prop)
{
setboolfield(L, table, "diggable", prop.diggable);
setfloatfield(L, table, "time", prop.time);
setintfield(L, table, "wear", prop.wear);
}
static void push_digging_properties(lua_State *L,
const DiggingProperties &prop)
{
lua_newtable(L);
set_digging_properties(L, -1, prop);
}
/*
HittingProperties
*/
static void set_hitting_properties(lua_State *L, int table,
const HittingProperties &prop)
{
setintfield(L, table, "hp", prop.hp);
setintfield(L, table, "wear", prop.wear);
}
static void push_hitting_properties(lua_State *L,
const HittingProperties &prop)
{
lua_newtable(L);
set_hitting_properties(L, -1, prop);
}
/* /*
PointedThing PointedThing
*/ */
@ -797,12 +879,24 @@ static ContentFeatures read_content_features(lua_State *L, int index)
f.param_type = (ContentParamType)getenumfield(L, index, "paramtype", f.param_type = (ContentParamType)getenumfield(L, index, "paramtype",
es_ContentParamType, CPT_NONE); 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 'drops' field");
warn_if_field_exists(L, index, "extra_dug_item",
"deprecated: use 'drops' field");
warn_if_field_exists(L, index, "extra_dug_item_rarity",
"deprecated: use 'drops' field");
// True for all ground-like things like stone and mud, false for eg. trees // True for all ground-like things like stone and mud, false for eg. trees
getboolfield(L, index, "is_ground_content", f.is_ground_content); getboolfield(L, index, "is_ground_content", f.is_ground_content);
f.light_propagates = (f.param_type == CPT_LIGHT); f.light_propagates = (f.param_type == CPT_LIGHT);
warn_if_field_exists(L, index, "light_propagates",
"deprecated: determined from paramtype");
getboolfield(L, index, "sunlight_propagates", f.sunlight_propagates); getboolfield(L, index, "sunlight_propagates", f.sunlight_propagates);
// This is used for collision detection. // This is used for collision detection.
// Also for general solidness queries. // Also for general solidness queries.
@ -815,16 +909,6 @@ static ContentFeatures read_content_features(lua_State *L, int index)
getboolfield(L, index, "climbable", f.climbable); getboolfield(L, index, "climbable", f.climbable);
// Player can build on these // Player can build on these
getboolfield(L, index, "buildable_to", f.buildable_to); getboolfield(L, index, "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, index, "wall_mounted", f.wall_mounted);
// Inventory item string as which the node appears in inventory when dug.
// Mineral overrides this.
getstringfield(L, index, "dug_item", f.dug_item);
// Extra dug item and its rarity
getstringfield(L, index, "extra_dug_item", f.extra_dug_item);
// Usual get interval for extra dug item
getintfield(L, index, "extra_dug_item_rarity", f.extra_dug_item_rarity);
// Metadata name of node (eg. "furnace") // Metadata name of node (eg. "furnace")
getstringfield(L, index, "metadata_name", f.metadata_name); getstringfield(L, index, "metadata_name", f.metadata_name);
// Whether the node is non-liquid, source liquid or flowing liquid // Whether the node is non-liquid, source liquid or flowing liquid
@ -876,18 +960,15 @@ static ContentFeatures read_content_features(lua_State *L, int index)
lua_getfield(L, index, "material"); lua_getfield(L, index, "material");
if(lua_istable(L, -1)){ if(lua_istable(L, -1)){
f.material.diggability = (Diggability)getenumfield(L, -1, "diggability", f.material = read_material_properties(L, -1);
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); 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; return f;
} }
@ -1774,6 +1855,33 @@ private:
return 1; return 1;
} }
// 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 owner = luaL_checkstring(L, 2);
meta->setOwner(owner);
reportMetadataChange(ref);
return 1;
}
// 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){
lua_pushboolean(L, true);
return 1;
}
// Do it
lua_pushboolean(L, !meta->nodeRemovalDisabled());
return 1;
}
/* IGenericNodeMetadata interface */ /* IGenericNodeMetadata interface */
// set_infotext(self, text) // set_infotext(self, text)
@ -1984,6 +2092,8 @@ const luaL_reg NodeMetaRef::methods[] = {
method(NodeMetaRef, set_text), method(NodeMetaRef, set_text),
method(NodeMetaRef, get_text), method(NodeMetaRef, get_text),
method(NodeMetaRef, get_owner), method(NodeMetaRef, get_owner),
method(NodeMetaRef, set_owner),
method(NodeMetaRef, get_allow_removal),
method(NodeMetaRef, set_infotext), method(NodeMetaRef, set_infotext),
method(NodeMetaRef, get_inventory), method(NodeMetaRef, get_inventory),
method(NodeMetaRef, set_inventory_draw_spec), method(NodeMetaRef, set_inventory_draw_spec),
@ -3369,6 +3479,32 @@ static int l_get_inventory(lua_State *L)
return 1; 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() // get_current_modname()
static int l_get_current_modname(lua_State *L) static int l_get_current_modname(lua_State *L)
{ {
@ -3402,6 +3538,8 @@ static const struct luaL_Reg minetest_f [] = {
{"chat_send_player", l_chat_send_player}, {"chat_send_player", l_chat_send_player},
{"get_player_privs", l_get_player_privs}, {"get_player_privs", l_get_player_privs},
{"get_inventory", l_get_inventory}, {"get_inventory", l_get_inventory},
{"get_digging_properties", l_get_digging_properties},
{"get_hitting_properties", l_get_hitting_properties},
{"get_current_modname", l_get_current_modname}, {"get_current_modname", l_get_current_modname},
{"get_modpath", l_get_modpath}, {"get_modpath", l_get_modpath},
{NULL, NULL} {NULL, NULL}
@ -3719,6 +3857,8 @@ bool scriptapi_on_respawnplayer(lua_State *L, ServerActiveObject *player)
assert(lua_checkstack(L, 20)); assert(lua_checkstack(L, 20));
StackUnroller stack_unroller(L); StackUnroller stack_unroller(L);
dstream<<"player: "<<player<<" id: "<<player->getId()<<std::endl;
bool positioning_handled_by_some = false; bool positioning_handled_by_some = false;
// Get minetest.registered_on_respawnplayers // Get minetest.registered_on_respawnplayers
@ -3754,7 +3894,7 @@ void scriptapi_get_creative_inventory(lua_State *L, ServerRemotePlayer *player)
} }
/* /*
item callbacks item callbacks and node callbacks
*/ */
// Retrieves minetest.registered_items[name][callbackname] // Retrieves minetest.registered_items[name][callbackname]
@ -3864,6 +4004,50 @@ bool scriptapi_item_on_use(lua_State *L, ItemStack &item,
return true; return true;
} }
bool scriptapi_node_on_punch(lua_State *L, v3s16 pos, MapNode node,
ServerActiveObject *puncher)
{
realitycheck(L);
assert(lua_checkstack(L, 20));
StackUnroller stack_unroller(L);
INodeDefManager *ndef = get_server(L)->ndef();
// Push callback function on stack
if(!get_item_callback(L, ndef->get(node).name.c_str(), "on_punch"))
return false;
// 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;
}
bool scriptapi_node_on_dig(lua_State *L, v3s16 pos, MapNode node,
ServerActiveObject *digger)
{
realitycheck(L);
assert(lua_checkstack(L, 20));
StackUnroller stack_unroller(L);
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;
}
/* /*
environment environment
*/ */
@ -3893,102 +4077,6 @@ void scriptapi_environment_step(lua_State *L, float dtime)
} }
} }
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);
// 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
}
}
void scriptapi_environment_on_dignode(lua_State *L, v3s16 p, MapNode oldnode,
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
}
}
void scriptapi_environment_on_punchnode(lua_State *L, v3s16 p, MapNode node,
ServerActiveObject *puncher)
{
realitycheck(L);
assert(lua_checkstack(L, 20));
//infostream<<"scriptapi_environment_on_punchnode"<<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
lua_getglobal(L, "minetest");
lua_getfield(L, -1, "registered_on_punchnodes");
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, node, ndef);
objectref_get_or_create(L, puncher);
if(lua_pcall(L, 3, 0, 0))
script_error(L, "error: %s", lua_tostring(L, -1));
// value removed, keep key for next iteration
}
}
void scriptapi_environment_on_generated(lua_State *L, v3s16 minp, v3s16 maxp) void scriptapi_environment_on_generated(lua_State *L, v3s16 minp, v3s16 maxp)
{ {
realitycheck(L); realitycheck(L);

@ -49,15 +49,6 @@ bool scriptapi_on_chat_message(lua_State *L, const std::string &name,
/* environment */ /* environment */
// On environment step // On environment step
void scriptapi_environment_step(lua_State *L, float dtime); 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 // After generating a piece of map
void scriptapi_environment_on_generated(lua_State *L, v3s16 minp, v3s16 maxp); void scriptapi_environment_on_generated(lua_State *L, v3s16 minp, v3s16 maxp);
@ -75,6 +66,12 @@ bool scriptapi_item_on_place(lua_State *L, ItemStack &item,
bool scriptapi_item_on_use(lua_State *L, ItemStack &item, bool scriptapi_item_on_use(lua_State *L, ItemStack &item,
ServerActiveObject *user, const PointedThing &pointed); 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 */ /* luaentity */
// Returns true if succesfully added into Lua; false otherwise. // Returns true if succesfully added into Lua; false otherwise.
bool scriptapi_luaentity_add(lua_State *L, u16 id, const char *name, bool scriptapi_luaentity_add(lua_State *L, u16 id, const char *name,

@ -57,11 +57,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
19: new content type handling 19: new content type handling
20: many existing content types translated to extended ones 20: many existing content types translated to extended ones
21: dynamic content type allocation 21: dynamic content type allocation
22: full 16-bit content types, minerals removed, facedir & wallmounted changed
*/ */
// This represents an uninitialized or invalid format // This represents an uninitialized or invalid format
#define SER_FMT_VER_INVALID 255 #define SER_FMT_VER_INVALID 255
// Highest supported serialization version // Highest supported serialization version
#define SER_FMT_VER_HIGHEST 21 #define SER_FMT_VER_HIGHEST 22
// Lowest supported serialization version // Lowest supported serialization version
#define SER_FMT_VER_LOWEST 0 #define SER_FMT_VER_LOWEST 0

@ -28,7 +28,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "constants.h" #include "constants.h"
#include "voxel.h" #include "voxel.h"
#include "materials.h" #include "materials.h"
#include "mineral.h"
#include "config.h" #include "config.h"
#include "servercommand.h" #include "servercommand.h"
#include "filesys.h" #include "filesys.h"
@ -2899,13 +2898,12 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
/* /*
Make sure the player is allowed to do it Make sure the player is allowed to do it
*/ */
bool interact_priv = (getPlayerPrivs(player) & PRIV_INTERACT) != 0; if((getPlayerPrivs(player) & PRIV_INTERACT) == 0)
if(!interact_priv)
{ {
infostream<<"Ignoring interaction from player "<<player->getName() infostream<<"Ignoring interaction from player "<<player->getName()
<<" because privileges are "<<getPlayerPrivs(player) <<" because privileges are "<<getPlayerPrivs(player)
<<std::endl; <<std::endl;
// NOTE: no return; here, fall through return;
} }
/* /*
@ -2919,10 +2917,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
NOTE: This can be used in the future to check if NOTE: This can be used in the future to check if
somebody is cheating, by checking the timing. somebody is cheating, by checking the timing.
*/ */
bool cannot_punch_node = !interact_priv;
MapNode n(CONTENT_IGNORE); MapNode n(CONTENT_IGNORE);
try try
{ {
n = m_env->getMap().getNode(p_under); n = m_env->getMap().getNode(p_under);
@ -2934,22 +2929,12 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
<<std::endl; <<std::endl;
m_emerge_queue.addBlock(peer_id, m_emerge_queue.addBlock(peer_id,
getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK); getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
cannot_punch_node = true;
} }
if(n.getContent() != CONTENT_IGNORE)
if(cannot_punch_node) scriptapi_node_on_punch(m_lua, p_under, n, srp);
return;
/*
Run script hook
*/
scriptapi_environment_on_punchnode(m_lua, p_under, n, srp);
} }
else if(pointed.type == POINTEDTHING_OBJECT) else if(pointed.type == POINTEDTHING_OBJECT)
{ {
if(!interact_priv)
return;
// Skip if object has been removed // Skip if object has been removed
if(pointed_object->m_removed) if(pointed_object->m_removed)
return; return;
@ -2977,50 +2962,12 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
else if(action == 2) else if(action == 2)
{ {
// Only complete digging of nodes // Only complete digging of nodes
if(pointed.type != POINTEDTHING_NODE) 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 = !interact_priv;
MapNode n(CONTENT_IGNORE); MapNode n(CONTENT_IGNORE);
try try
{ {
n = m_env->getMap().getNode(p_under); 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) catch(InvalidPositionException &e)
{ {
@ -3029,138 +2976,10 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
<<std::endl; <<std::endl;
m_emerge_queue.addBlock(peer_id, m_emerge_queue.addBlock(peer_id,
getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK); getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
cannot_remove_node = true;
} }
if(n.getContent() != CONTENT_IGNORE)
/* scriptapi_node_on_dig(m_lua, p_under, n, srp);
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)
{
/*
Wear out tool
*/
InventoryList *mlist = player->inventory.getList("main");
if(mlist != NULL)
{
ItemStack &item = mlist->getItem(item_i);
// Get digging properties for material and tool
ToolDiggingProperties tp =
item.getToolDiggingProperties(m_itemdef);
DiggingProperties prop =
getDiggingProperties(material, &tp, m_nodedef);
item.addWear(prop.wear, m_itemdef);
srp->m_inventory_not_sent = true;
}
/*
Add dug item to inventory
*/
ItemStack item;
if(mineral != MINERAL_NONE)
item = getDiggedMineralItem(mineral, this);
// If not mineral
if(item.empty())
{
const std::string &dug_s = m_nodedef->get(material).dug_item;
if(dug_s != "")
{
item.deSerialize(dug_s, m_itemdef);
}
}
if(!item.empty())
{
// Add a item to inventory
player->inventory.addItem("main", item);
srp->m_inventory_not_sent = true;
}
item.clear();
{
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)
{
item.deSerialize(extra_dug_s, m_itemdef);
}
}
if(!item.empty())
{
// Add a item to inventory
player->inventory.addItem("main", item);
srp->m_inventory_not_sent = true;
}
}
/*
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 } // action == 2
/* /*
@ -3168,16 +2987,13 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
*/ */
else if(action == 3) else if(action == 3)
{ {
if(!interact_priv)
{
infostream<<"Not allowing player "
<<player->getName()<<" to place item: "
<<"no interact privileges"<<std::endl;
return;
}
ItemStack item = srp->getWieldedItem(); ItemStack item = srp->getWieldedItem();
// 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;
if(pointed.type == POINTEDTHING_OBJECT) if(pointed.type == POINTEDTHING_OBJECT)
{ {
// Right click object // Right click object
@ -3201,123 +3017,6 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
if(g_settings->getBool("creative_mode") == false) if(g_settings->getBool("creative_mode") == false)
srp->setWieldedItem(item); srp->setWieldedItem(item);
} }
else if(pointed.type == POINTEDTHING_NODE &&
item.getDefinition(m_itemdef).type == ITEM_NODE)
{
bool cannot_place_node = !interact_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;
}
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
getClient(peer_id)->m_time_from_building = 0.0;
// Create node data
MapNode n(m_nodedef, item.name, 0, 0);
actionstream<<player->getName()<<" places material "
<<item.name
<<" 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
*/
if(g_settings->getBool("creative_mode") == false)
{
// Remove from inventory and send inventory
item.remove(1);
srp->setWieldedItem(item);
}
/*
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);
}
} // action == 3 } // action == 3
@ -3326,14 +3025,6 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
*/ */
else if(action == 4) else if(action == 4)
{ {
// Requires interact privs
if(!interact_priv)
{
infostream<<"Not allowing player to use item: "
"no interact privileges"<<std::endl;
return;
}
ItemStack item = srp->getWieldedItem(); ItemStack item = srp->getWieldedItem();
actionstream<<player->getName()<<" uses "<<item.name actionstream<<player->getName()<<" uses "<<item.name
@ -3949,7 +3640,7 @@ void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
*/ */
std::ostringstream os(std::ios_base::binary); std::ostringstream os(std::ios_base::binary);
block->serialize(os, ver); block->serialize(os, ver, false);
std::string s = os.str(); std::string s = os.str();
SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size()); SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());

@ -68,7 +68,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "porting.h" #include "porting.h"
#include "materials.h" #include "materials.h"
#include "config.h" #include "config.h"
#include "mineral.h"
#include "filesys.h" #include "filesys.h"
#include "defaultsettings.h" #include "defaultsettings.h"
#include "settings.h" #include "settings.h"
@ -301,10 +300,6 @@ int main(int argc, char *argv[])
srand(time(0)); srand(time(0));
mysrand(time(0)); mysrand(time(0));
// Initialize stuff
init_mineral();
/* /*
Run unit tests Run unit tests
*/ */

@ -76,9 +76,7 @@ void define_some_nodes(IWritableItemDefManager *idef, IWritableNodeDefManager *n
f.name = itemdef.name; f.name = itemdef.name;
for(int i = 0; i < 6; i++) for(int i = 0; i < 6; i++)
f.tname_tiles[i] = "default_stone.png"; f.tname_tiles[i] = "default_stone.png";
f.param_type = CPT_MINERAL;
f.is_ground_content = true; f.is_ground_content = true;
f.dug_item = itemdef.name;
f.material.diggability = DIGGABLE_NORMAL; f.material.diggability = DIGGABLE_NORMAL;
f.material.weight = 5.0; f.material.weight = 5.0;
f.material.crackiness = 1.0; f.material.crackiness = 1.0;
@ -106,7 +104,6 @@ void define_some_nodes(IWritableItemDefManager *idef, IWritableNodeDefManager *n
for(int i = 2; i < 6; i++) for(int i = 2; i < 6; i++)
f.tname_tiles[i] = "default_dirt.png^default_grass_side.png"; f.tname_tiles[i] = "default_dirt.png^default_grass_side.png";
f.is_ground_content = true; f.is_ground_content = true;
f.dug_item = itemdef.name;
f.material.diggability = DIGGABLE_NORMAL; f.material.diggability = DIGGABLE_NORMAL;
f.material.weight = 1.2; f.material.weight = 1.2;
f.material.crackiness = 0.0; f.material.crackiness = 0.0;

@ -27,7 +27,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <ICameraSceneNode.h> #include <ICameraSceneNode.h>
#include "log.h" #include "log.h"
#include "mapnode.h" // For texture atlas making #include "mapnode.h" // For texture atlas making
#include "mineral.h" // For texture atlas making
#include "nodedef.h" // For texture atlas making #include "nodedef.h" // For texture atlas making
#include "gamedef.h" #include "gamedef.h"
@ -299,8 +298,8 @@ public:
Example names: Example names:
"stone.png" "stone.png"
"stone.png^crack2" "stone.png^crack2"
"stone.png^blit:mineral_coal.png" "stone.png^mineral_coal.png"
"stone.png^blit:mineral_coal.png^crack1" "stone.png^mineral_coal.png^crack1"
- If texture specified by name is found from cache, return the - If texture specified by name is found from cache, return the
cached id. cached id.
@ -824,14 +823,6 @@ void TextureSource::buildMainAtlas(class IGameDef *gamedef)
{ {
std::string name = f.tname_tiles[i]; std::string name = f.tname_tiles[i];
sourcelist[name] = true; sourcelist[name] = true;
if(f.param_type == CPT_MINERAL){
for(int k=1; k<MINERAL_COUNT; k++){
std::string mineraltexture = mineral_block_texture(k);
std::string fulltexture = name + "^" + mineraltexture;
sourcelist[fulltexture] = true;
}
}
} }
} }