-- Item definition helpers
--
-minetest.inventorycube = function(img1, img2, img3)
+function minetest.inventorycube(img1, img2, img3)
img2 = img2 or img1
img3 = img3 or img1
return "[inventorycube"
.. "{" .. img3:gsub("%^", "&")
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 above then
-- The position where a node would be placed
end
end
-function minetest.item_place(itemstack, placer, pointed_thing)
- pos = minetest.get_pointed_thing_position(pointed_thing, true)
- if pos ~= nil then
- item = itemstack:take_item()
- if item ~= nil then
- minetest.env:add_item(pos, item)
+function minetest.dir_to_facedir(dir)
+ if math.abs(dir.x) > math.abs(dir.z) then
+ if dir.x < 0 then
+ return 3
+ else
+ return 1
+ end
+ else
+ if dir.z < 0 then
+ return 2
+ else
+ return 0
+ end
+ end
+end
+
+function minetest.dir_to_wallmounted(dir)
+ if math.abs(dir.y) > math.max(math.abs(dir.x), math.abs(dir.z)) then
+ if dir.y < 0 then
+ return 1
+ else
+ return 0
+ end
+ elseif math.abs(dir.x) > math.abs(dir.z) then
+ if dir.x < 0 then
+ return 3
+ else
+ return 2
+ end
+ else
+ if dir.z < 0 then
+ return 5
+ else
+ return 4
+ end
+ end
+end
+
+function minetest.get_node_drops(nodename, toolname)
+ local drop = ItemStack({name=nodename}):get_definition().drop
+ if drop == nil then
+ -- default drop
+ 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
+ return itemstack
+end
+
+function minetest.item_place_object(itemstack, placer, pointed_thing)
+ local pos = minetest.get_pointed_thing_position(pointed_thing, true)
+ if pos ~= nil then
+ local item = itemstack:take_item()
+ minetest.env:add_item(pos, item)
+ end
return itemstack
end
+function minetest.item_place(itemstack, placer, pointed_thing)
+ if itemstack:get_definition().type == "node" then
+ return minetest.item_place_node(itemstack, placer, pointed_thing)
+ else
+ return minetest.item_place_object(itemstack, placer, pointed_thing)
+ end
+end
+
function minetest.item_drop(itemstack, dropper, pos)
minetest.env:add_item(pos, itemstack)
return ""
end
-function minetest.item_eat(hp_change)
+function minetest.item_eat(hp_change, replace_with_item)
return function(itemstack, user, pointed_thing) -- closure
if itemstack:take_item() ~= nil then
user:set_hp(user:get_hp() + hp_change)
+ itemstack:add_item(replace_with_item) -- note: replace_with_item is optional
end
return itemstack
end
end
+function minetest.node_punch(pos, node, puncher)
+ -- Run script hook
+ local _, callback
+ for _, callback in ipairs(minetest.registered_on_punchnodes) do
+ callback(pos, node, puncher)
+ end
+
+end
+
+function minetest.node_dig(pos, node, digger)
+ minetest.debug("node_dig")
+
+ local def = ItemStack({name=node.name}):get_definition()
+ if not def.diggable then
+ minetest.debug("not diggable")
+ minetest.log("info", digger:get_player_name() .. " tried to dig "
+ .. node.name .. " which is not diggable "
+ .. minetest.pos_to_string(pos))
+ return
+ end
+
+ local meta = minetest.env:get_meta(pos)
+ if meta ~= nil and not meta:get_allow_removal() then
+ minetest.debug("dig prevented by metadata")
+ minetest.log("info", digger:get_player_name() .. " tried to dig "
+ .. node.name .. ", but removal is disabled by metadata "
+ .. minetest.pos_to_string(pos))
+ return
+ end
+
+ minetest.log('action', digger:get_player_name() .. " digs "
+ .. node.name .. " at " .. minetest.pos_to_string(pos))
+
+ if not minetest.setting_getbool("creative_mode") then
+ local wielded = digger:get_wielded_item()
+ local drops = minetest.get_node_drops(node.name, wielded:get_name())
+
+ -- Wear out tool
+ mp = def.material
+ tp = wielded:get_tool_digging_properties()
+ dp = minetest.get_digging_properties(mp, tp)
+ wielded:add_wear(dp.wear)
+ digger:set_wielded_item(wielded)
+
+ -- Add dropped items
+ local _, dropped_item
+ for _, dropped_item in ipairs(drops) do
+ digger:get_inventory():add_item("main", dropped_item)
+ end
+ end
+
+ -- Remove node and update
+ minetest.env:remove_node(pos)
+
+ -- Run script hook
+ local _, callback
+ for _, callback in ipairs(minetest.registered_on_dignodes) do
+ callback(pos, node, digger)
+ end
+end
+
--
-- Item definition defaults
--
wield_image = "",
wield_scale = {x=1,y=1,z=1},
stack_max = 99,
- dropcount = -1,
usable = false,
liquids_pointable = false,
tool_digging_properties = nil,
-- Interaction callbacks
- on_place = nil, -- let C handle node placement for now
+ on_place = minetest.item_place,
on_drop = minetest.item_drop,
on_use = nil,
+ on_punch = minetest.node_punch,
+ on_dig = minetest.node_dig,
+
-- Node properties
drawtype = "normal",
visual_scale = 1.0,
alpha = 255,
post_effect_color = {a=0, r=0, g=0, b=0},
paramtype = "none",
+ paramtype2 = "none",
is_ground_content = false,
sunlight_propagates = false,
walkable = true,
diggable = true,
climbable = false,
buildable_to = false,
- wall_mounted = false,
- --dug_item intentionally not defined here
- extra_dug_item = "",
- extra_dug_item_rarity = 2,
metadata_name = "",
liquidtype = "none",
liquid_alternative_flowing = "",
cuttability = 0,
flammability = 0,
},
+ legacy_facedir_simple = false,
+ legacy_wallmounted = false,
}
minetest.craftitemdef_default = {
error("Unable to register item: Type is invalid: " .. dump(itemdef))
end
- -- Default dug item
- if itemdef.type == "node" and itemdef.dug_item == nil then
- itemdef.dug_item = ItemStack({name=itemdef.name}):to_string()
+ -- Flowing liquid uses param2
+ if itemdef.type == "node" and itemdef.liquidtype == "flowing" then
+ itemdef.paramtype2 = "flowingliquid"
end
- -- Legacy stuff
+ -- BEGIN Legacy stuff
if itemdef.cookresult_itemstring ~= nil and itemdef.cookresult_itemstring ~= "" then
minetest.register_craft({
type="cooking",
burntime=itemdef.furnace_burntime
})
end
+ -- END Legacy stuff
-- Disable all further modifications
getmetatable(itemdef).__newindex = {}
function minetest.register_craftitem(name, craftitemdef)
craftitemdef.type = "craft"
- -- Legacy stuff
+ -- BEGIN Legacy stuff
if craftitemdef.inventory_image == nil and craftitemdef.image ~= nil then
craftitemdef.inventory_image = craftitemdef.image
end
+ -- END Legacy stuff
minetest.register_item(name, craftitemdef)
end
tooldef.type = "tool"
tooldef.stack_max = 1
- -- Legacy stuff
+ -- BEGIN Legacy stuff
if tooldef.inventory_image == nil and tooldef.image ~= nil then
tooldef.inventory_image = tooldef.image
end
dd_cuttability = tooldef.dd_cuttability,
}
end
+ -- END Legacy stuff
minetest.register_item(name, tooldef)
end
minetest.registered_on_dieplayers, minetest.register_on_dieplayer = make_registration()
minetest.registered_on_respawnplayers, minetest.register_on_respawnplayer = make_registration()
+--
+-- Set random seed
+--
+
+math.randomseed(os.time())
+
-- END
-- - set_text(text) -- eg. set the text of a sign
-- - get_text()
-- - get_owner()
+-- - set_owner(string)
-- Generic node metadata specific:
-- - set_infotext(infotext)
-- - get_inventory() -> InvRef
-- myvariable = whatever,
-- }
--
--- Item definition:
+-- Item definition options (register_node, register_craftitem, register_tool)
-- {
-- description = "Steel Axe",
-- inventory_image = "default_tool_steelaxe.png",
-- 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",
-- visual_scale = 1.0,
-- tile_images = {"default_unknown_block.png"},
-- alpha = 255,
-- post_effect_color = {a=0, r=0, g=0, b=0},
-- paramtype = "none",
+-- paramtype2 = "none",
-- is_ground_content = false,
-- sunlight_propagates = false,
-- walkable = true,
-- diggable = true,
-- climbable = false,
-- buildable_to = false,
--- wall_mounted = false,
--- dug_item = "",
--- extra_dug_item = "",
--- extra_dug_item_rarity = 2,
+-- drop = "",
+-- -- alternatively drop = { max_items = ..., items = { ... } }
-- metadata_name = "",
-- liquidtype = "none",
-- liquid_alternative_flowing = "",
-- cuttability = 0,
-- flammability = 0,
-- },
--- on_drop = func(item, dropper),
--- on_place = func(item, placer, pointed_thing),
--- on_use = func(item, user, pointed_thing),
+-- legacy_facedir_simple = false, -- Support maps made in and before January 2012
+-- legacy_wallmounted = false, -- Support maps made in and before January 2012
-- }
--
--- Craftitem definition options:
--- {
--- 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:
-- {
-- output = 'default:pick_stone',
minetest.register_node("default:stone", {
description = "Stone",
tile_images = {"default_stone.png"},
- paramtype = "mineral",
is_ground_content = true,
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", {
tile_images = {"default_grass.png", "default_dirt.png", "default_dirt.png^default_grass_side.png"},
is_ground_content = true,
material = minetest.digprop_dirtlike(1.0),
- dug_item = 'node "default:dirt" 1',
+ drop = 'default:dirt',
})
minetest.register_node("default:dirt_with_grass_footsteps", {
tile_images = {"default_grass_footsteps.png", "default_dirt.png", "default_dirt.png^default_grass_side.png"},
is_ground_content = true,
material = minetest.digprop_dirtlike(1.0),
- dug_item = 'node "default:dirt" 1',
+ drop = 'default:dirt',
})
minetest.register_node("default:dirt", {
tile_images = {"default_sandstone.png"},
is_ground_content = true,
material = minetest.digprop_dirtlike(1.0), -- FIXME should this be stonelike?
- dug_item = 'node "default:sand" 1', -- FIXME is this intentional?
+ drop = 'default:sand',
})
minetest.register_node("default:clay", {
tile_images = {"default_clay.png"},
is_ground_content = true,
material = minetest.digprop_dirtlike(1.0),
- dug_item = 'craft "default:clay_lump" 4',
+ drop = 'default:clay_lump 4',
})
minetest.register_node("default:brick", {
tile_images = {"default_brick.png"},
is_ground_content = true,
material = minetest.digprop_stonelike(1.0),
- dug_item = 'craft "default:clay_brick" 4',
+ drop = 'default:clay_brick 4',
})
minetest.register_node("default:tree", {
tile_images = {"default_leaves.png"},
paramtype = "light",
material = minetest.digprop_leaveslike(1.0),
- extra_dug_item = 'node "default:sapling" 1',
- extra_dug_item_rarity = 20,
+ drop = {
+ max_items = 1,
+ items = {
+ {
+ -- player will get sapling with 1/20 chance
+ items = {'default:sapling'},
+ rarity = 20,
+ },
+ {
+ -- player will get leaves only if he get no saplings,
+ -- this is because max_items is 1
+ items = {'default:leaves'},
+ }
+ }
+ },
})
minetest.register_node("default:cactus", {
inventory_image = "default_ladder.png",
wield_image = "default_ladder.png",
paramtype = "light",
+ paramtype2 = "wallmounted",
is_ground_content = true,
- wall_mounted = true,
walkable = false,
climbable = true,
selection_box = {
--wall_side = = <default>
},
material = minetest.digprop_woodlike(0.5),
+ legacy_wallmounted = true,
})
minetest.register_node("default:wood", {
inventory_image = "default_torch_on_floor.png",
wield_image = "default_torch_on_floor.png",
paramtype = "light",
+ paramtype2 = "wallmounted",
sunlight_propagates = true,
walkable = false,
- wall_mounted = true,
light_source = LIGHT_MAX-1,
selection_box = {
type = "wallmounted",
wall_side = {-0.5, -0.3, -0.1, -0.5+0.3, 0.3, 0.1},
},
material = minetest.digprop_constanttime(0.0),
+ legacy_wallmounted = true,
})
minetest.register_node("default:sign_wall", {
inventory_image = "default_sign_wall.png",
wield_image = "default_sign_wall.png",
paramtype = "light",
+ paramtype2 = "wallmounted",
sunlight_propagates = true,
walkable = false,
- wall_mounted = true,
metadata_name = "sign",
selection_box = {
type = "wallmounted",
--wall_side = <default>
},
material = minetest.digprop_constanttime(0.5),
+ legacy_wallmounted = true,
})
minetest.register_node("default:chest", {
description = "Chest",
tile_images = {"default_chest_top.png", "default_chest_top.png", "default_chest_side.png",
"default_chest_side.png", "default_chest_side.png", "default_chest_front.png"},
- paramtype = "facedir_simple",
+ paramtype2 = "facedir",
metadata_name = "chest",
material = minetest.digprop_woodlike(1.0),
+ legacy_facedir_simple = true,
})
minetest.register_node("default:chest_locked", {
description = "Locked Chest",
tile_images = {"default_chest_top.png", "default_chest_top.png", "default_chest_side.png",
"default_chest_side.png", "default_chest_side.png", "default_chest_lock.png"},
- paramtype = "facedir_simple",
+ paramtype2 = "facedir",
metadata_name = "locked_chest",
material = minetest.digprop_woodlike(1.0),
+ legacy_facedir_simple = true,
})
minetest.register_node("default:furnace", {
description = "Furnace",
tile_images = {"default_furnace_side.png", "default_furnace_side.png", "default_furnace_side.png",
"default_furnace_side.png", "default_furnace_side.png", "default_furnace_front.png"},
- paramtype = "facedir_simple",
+ paramtype2 = "facedir",
metadata_name = "furnace",
material = minetest.digprop_stonelike(3.0),
+ legacy_facedir_simple = true,
})
minetest.register_node("default:cobble", {
tile_images = {"default_nc_side.png", "default_nc_side.png", "default_nc_side.png",
"default_nc_side.png", "default_nc_back.png", "default_nc_front.png"},
inventory_image = "default_nc_front.png",
- paramtype = "facedir_simple",
+ paramtype2 = "facedir",
material = minetest.digprop_stonelike(3.0),
+ legacy_facedir_simple = true,
})
minetest.register_node("default:nyancat_rainbow", {
--
minetest.register_alias("stone", "default:stone")
+minetest.register_alias("stone_with_coal", "default:stone_with_coal")
+minetest.register_alias("stone_with_iron", "default:stone_with_iron")
minetest.register_alias("dirt_with_grass", "default:dirt_with_grass")
minetest.register_alias("dirt_with_grass_footsteps", "default:dirt_with_grass_footsteps")
minetest.register_alias("dirt", "default:dirt")
nodemetadata.cpp
serverobject.cpp
noise.cpp
- mineral.cpp
porting.cpp
materials.cpp
defaultsettings.cpp
Update an existing block
*/
//infostream<<"Updating"<<std::endl;
- block->deSerialize(istr, ser_version);
+ block->deSerialize(istr, ser_version, false);
}
else
{
*/
//infostream<<"Creating new"<<std::endl;
block = new MapBlock(&m_env.getMap(), p, this);
- block->deSerialize(istr, ser_version);
+ block->deSerialize(istr, ser_version, false);
sector->insertBlock(block);
}
try
{
//TimeTaker timer3("Client::addNode(): addNodeAndUpdate");
- std::string st = std::string("");
- m_env.getMap().addNodeAndUpdate(p, n, modified_blocks, st);
+ m_env.getMap().addNodeAndUpdate(p, n, modified_blocks);
}
catch(InvalidPositionException &e)
{}
video::S3DVertex(min.X,min.Y,min.Z, -1,0,0, c, txc[14],txc[15]),
video::S3DVertex(min.X,min.Y,max.Z, -1,0,0, c, txc[12],txc[15]),
// back
- video::S3DVertex(min.X,max.Y,min.Z, 0,0,-1, c, txc[16],txc[17]),
- video::S3DVertex(max.X,max.Y,min.Z, 0,0,-1, c, txc[18],txc[17]),
- video::S3DVertex(max.X,min.Y,min.Z, 0,0,-1, c, txc[18],txc[19]),
- video::S3DVertex(min.X,min.Y,min.Z, 0,0,-1, c, txc[16],txc[19]),
+ video::S3DVertex(max.X,max.Y,max.Z, 0,0,1, c, txc[16],txc[17]),
+ video::S3DVertex(min.X,max.Y,max.Z, 0,0,1, c, txc[18],txc[17]),
+ video::S3DVertex(min.X,min.Y,max.Z, 0,0,1, c, txc[18],txc[19]),
+ video::S3DVertex(max.X,min.Y,max.Z, 0,0,1, c, txc[16],txc[19]),
// front
- video::S3DVertex(max.X,max.Y,max.Z, 0,0,1, c, txc[20],txc[21]),
- video::S3DVertex(min.X,max.Y,max.Z, 0,0,1, c, txc[22],txc[21]),
- video::S3DVertex(min.X,min.Y,max.Z, 0,0,1, c, txc[22],txc[23]),
- video::S3DVertex(max.X,min.Y,max.Z, 0,0,1, c, txc[20],txc[23]),
+ video::S3DVertex(min.X,max.Y,min.Z, 0,0,-1, c, txc[20],txc[21]),
+ video::S3DVertex(max.X,max.Y,min.Z, 0,0,-1, c, txc[22],txc[21]),
+ video::S3DVertex(max.X,min.Y,min.Z, 0,0,-1, c, txc[22],txc[23]),
+ video::S3DVertex(min.X,min.Y,min.Z, 0,0,-1, c, txc[20],txc[23]),
};
for(s32 j=0; j<24; j++)
break;
case NDT_TORCHLIKE:
{
- v3s16 dir = unpackDir(n.param2);
+ v3s16 dir = n.getWallMountedDir(nodedef);
AtlasPointer ap(0);
if(dir == v3s16(0,-1,0)){
ap.x0(), ap.y1()),
};
- v3s16 dir = unpackDir(n.param2);
+ v3s16 dir = n.getWallMountedDir(nodedef);
for(s32 i=0; i<4; i++)
{
Ranges:
0x000...0x07f (0...127): param2 is fully usable
126 and 127 are reserved (CONTENT_AIR and CONTENT_IGNORE).
- 0x800...0xfff (2048...4095): higher 4 bytes of param2 are not usable
+ 0x800...0xfff (2048...4095): higher 4 bits of param2 are not usable
*/
#define CONTENT_STONE 0
#define CONTENT_WATER 2
MapNode n = m_map->getNode(p);
light = n.getLightBlend(getDayNightRatio(), m_gamedef->ndef());
}
- catch(InvalidPositionException &e) {}
+ catch(InvalidPositionException &e){
+ light = blend_light(getDayNightRatio(), LIGHT_SUN, 0);
+ }
player->updateLight(light);
/*
if(m_active_object_light_update_interval.step(dtime, 0.21))
{
// Update lighting
- //u8 light = LIGHT_MAX;
u8 light = 0;
try{
// Get node at head
MapNode n = m_map->getNode(p);
light = n.getLightBlend(getDayNightRatio(), m_gamedef->ndef());
}
- catch(InvalidPositionException &e) {}
+ catch(InvalidPositionException &e){
+ light = blend_light(getDayNightRatio(), LIGHT_SUN, 0);
+ }
obj->updateLight(light);
}
}
MapNode n = m_map->getNode(p);
light = n.getLightBlend(getDayNightRatio(), m_gamedef->ndef());
}
- catch(InvalidPositionException &e) {}
+ catch(InvalidPositionException &e){
+ light = blend_light(getDayNightRatio(), LIGHT_SUN, 0);
+ }
object->updateLight(light);
}
return object->getId();
should_show_hilightbox = false;
selected_object = NULL;
+ INodeDefManager *nodedef = client->getNodeDefManager();
+
// First try to find a pointed at active object
if(look_for_object)
{
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)
{
}
else if(f.selection_box.type == NODEBOX_WALLMOUNTED)
{
- v3s16 dir = unpackDir(n.param2);
+ v3s16 dir = n.getWallMountedDir(nodedef);
v3f dir_f = v3f(dir.X, dir.Y, dir.Z);
dir_f *= BS/2 - BS/6 - BS/20;
v3f cpf = npf + dir_f;
MapNode n = client.getNode(nodepos);
// Get digging properties for material and tool
- content_t material = n.getContent();
+ MaterialProperties mp = nodedef->get(n.getContent()).material;
ToolDiggingProperties tp =
playeritem.getToolDiggingProperties(itemdef);
- DiggingProperties prop =
- getDiggingProperties(material, &tp, nodedef);
+ DiggingProperties prop = getDiggingProperties(&mp, &tp);
float dig_time_complete = 0.0;
class IItemDefManager;
class INodeDefManager;
class ICraftDefManager;
-// Mineral too?
class ITextureSource;
/*
extern u8 light_decode_table[LIGHT_MAX+1];
+// 0 <= light <= LIGHT_SUN
+// 0 <= return value <= 255
inline u8 decode_light(u8 light)
{
- if(light == LIGHT_SUN)
- return light_decode_table[LIGHT_MAX];
-
if(light > LIGHT_MAX)
light = LIGHT_MAX;
return light_decode_table[light];
}
+// 0 <= daylight_factor <= 1000
+// 0 <= lightday, lightnight <= LIGHT_SUN
+// 0 <= return value <= LIGHT_SUN
+inline u8 blend_light(u32 daylight_factor, u8 lightday, u8 lightnight)
+{
+ u32 c = 1000;
+ u32 l = ((daylight_factor * lightday + (c-daylight_factor) * lightnight))/c;
+ if(l > LIGHT_SUN)
+ l = LIGHT_SUN;
+ return l;
+}
+
#endif
+ This was left to be done by the old system and it sends only the
nearest ones.
-Vim conversion regexpes for moving to extended content type storage:
-%s/\(\.\|->\)d \([!=]=\)/\1getContent() \2/g
-%s/content_features(\([^.]*\)\.d)/content_features(\1)/g
-%s/\(\.\|->\)d = \([^;]*\);/\1setContent(\2);/g
-%s/\(getNodeNoExNoEmerge([^)]*)\)\.d/\1.getContent()/g
-%s/\(getNodeNoExNoEmerge(.*)\)\.d/\1.getContent()/g
-%s/\.d;/.getContent();/g
-%s/\(content_liquid\|content_flowing_liquid\|make_liquid_flowing\|content_pointable\)(\([^.]*\).d)/\1(\2.getContent())/g
-Other things to note:
-- node.d = node.param0 (only in raw serialization; use getContent() otherwise)
-- node.param = node.param1
-- node.dir = node.param2
-- content_walkable(node.d) etc should be changed to
- content_features(node).walkable etc
-- Also check for lines that store the result of getContent to a 8-bit
- variable and fix them (result of getContent() must be stored in
- content_t, which is 16-bit)
-
NOTE: Seeds in 1260:6c77e7dbfd29:
5721858502589302589:
Spawns you on a small sand island with a surface dungeon
TODO: Protocol version field
TODO: Think about using same bits for material for fences and doors, for
example
-TODO: Move mineral to param2, increment map serialization version, add
- conversion
SUGG: Restart irrlicht completely when coming back to main menu from game.
- This gets rid of everything that is stored in irrlicht's caches.
#include "filesys.h"
#include "config.h"
#include "guiMainMenu.h"
-#include "mineral.h"
#include "materials.h"
#include "game.h"
#include "keycode.h"
srand(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
*/
/*
*/
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();
if(!meta){
errorstream<<"Failed to create node metadata \""
<<metadata_name<<"\""<<std::endl;
- } else {
- meta->setOwner(player_name);
- setNodeMetadata(p, meta);
}
}
bool succeeded = true;
try{
core::map<v3s16, MapBlock*> modified_blocks;
- std::string st = std::string("");
- addNodeAndUpdate(p, n, modified_blocks, st);
+ addNodeAndUpdate(p, n, modified_blocks);
// Copy modified_blocks to event
for(core::map<v3s16, MapBlock*>::Iterator
o.write((char*)&version, 1);
// Write basic data
- block->serialize(o, version);
-
- // Write extra data stored on disk
- block->serializeDiskExtra(o, version);
+ block->serialize(o, version, true);
// Write block to database
}
// Read basic data
- block->deSerialize(is, version);
+ block->deSerialize(is, version, true);
- // Read extra data stored on disk
- block->deSerializeDiskExtra(is, version);
-
// If it's a new block, insert it to the map
if(created_new)
sector->insertBlock(block);
}
// Read basic data
- block->deSerialize(is, version);
-
- // Read extra data stored on disk
- block->deSerializeDiskExtra(is, version);
+ block->deSerialize(is, version, true);
// If it's a new block, insert it to the map
if(created_new)
These handle lighting but not faces.
*/
void addNodeAndUpdate(v3s16 p, MapNode n,
- core::map<v3s16, MapBlock*> &modified_blocks, std::string &player_name);
+ core::map<v3s16, MapBlock*> &modified_blocks);
void removeNodeAndUpdate(v3s16 p,
core::map<v3s16, MapBlock*> &modified_blocks);
/*
Serialization
*/
-
// List relevant id-name pairs for ids in the block using nodedef
-static void getBlockNodeIdMapping(NameIdMapping *nimap, MapBlock *block,
+// Renumbers the content IDs (starting at 0 and incrementing
+static void getBlockNodeIdMapping(NameIdMapping *nimap, MapNode *nodes,
INodeDefManager *nodedef)
{
+ std::map<content_t, content_t> mapping;
std::set<content_t> unknown_contents;
- for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
- for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
- for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
+ content_t id_counter = 0;
+ for(u32 i=0; i<MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE; i++)
{
- v3s16 p(x0,y0,z0);
- MapNode n = block->getNode(p);
- content_t id = n.getContent();
- const ContentFeatures &f = nodedef->get(id);
- const std::string &name = f.name;
- if(name == "")
- unknown_contents.insert(id);
+ content_t global_id = nodes[i].getContent();
+ content_t id = CONTENT_IGNORE;
+
+ // Try to find an existing mapping
+ std::map<content_t, content_t>::iterator j = mapping.find(global_id);
+ if(j != mapping.end())
+ {
+ id = j->second;
+ }
else
- nimap->set(id, name);
+ {
+ // We have to assign a new mapping
+ id = id_counter++;
+ mapping.insert(std::make_pair(global_id, id));
+
+ const ContentFeatures &f = nodedef->get(global_id);
+ const std::string &name = f.name;
+ if(name == "")
+ unknown_contents.insert(global_id);
+ else
+ nimap->set(id, name);
+ }
+
+ // Update the MapNode
+ nodes[i].setContent(id);
}
for(std::set<content_t>::const_iterator
i = unknown_contents.begin();
// Correct ids in the block to match nodedef based on names.
// Unknown ones are added to nodedef.
// Will not update itself to match id-name pairs in nodedef.
-void correctBlockNodeIds(const NameIdMapping *nimap, MapBlock *block,
+static void correctBlockNodeIds(const NameIdMapping *nimap, MapNode *nodes,
IGameDef *gamedef)
{
INodeDefManager *nodedef = gamedef->ndef();
// correct ids.
std::set<content_t> unnamed_contents;
std::set<std::string> unallocatable_contents;
- for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
- for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
- for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
+ for(u32 i=0; i<MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE; i++)
{
- v3s16 p(x0,y0,z0);
- MapNode n = block->getNode(p);
- content_t local_id = n.getContent();
+ content_t local_id = nodes[i].getContent();
std::string name;
bool found = nimap->getName(local_id, name);
if(!found){
continue;
}
}
- n.setContent(global_id);
- block->setNode(p, n);
+ nodes[i].setContent(global_id);
}
for(std::set<content_t>::const_iterator
i = unnamed_contents.begin();
}
}
-void MapBlock::serialize(std::ostream &os, u8 version)
+void MapBlock::serialize(std::ostream &os, u8 version, bool disk)
{
if(!ser_ver_supported(version))
throw VersionMismatchException("ERROR: MapBlock format not supported");
throw SerializationError("ERROR: Not writing dummy block.");
}
- // These have no compression
- if(version <= 3 || version == 5 || version == 6)
+ if(version <= 21)
{
- u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
-
- u32 buflen = 1 + nodecount * MapNode::serializedLength(version);
- SharedBuffer<u8> dest(buflen);
+ serialize_pre22(os, version, disk);
+ return;
+ }
- dest[0] = is_underground;
+ // First byte
+ u8 flags = 0;
+ if(is_underground)
+ flags |= 0x01;
+ if(m_day_night_differs)
+ flags |= 0x02;
+ if(m_lighting_expired)
+ flags |= 0x04;
+ if(m_generated == false)
+ flags |= 0x08;
+ writeU8(os, flags);
+
+ /*
+ Bulk node data
+ */
+ NameIdMapping nimap;
+ u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
+ if(disk)
+ {
+ MapNode *tmp_nodes = new MapNode[nodecount];
for(u32 i=0; i<nodecount; i++)
+ tmp_nodes[i] = data[i];
+ getBlockNodeIdMapping(&nimap, tmp_nodes, m_gamedef->ndef());
+
+ u8 content_width = 1;
+ /*u8 content_width = (nimap.size() <= 255) ? 1 : 2;*/
+ u8 params_width = 2;
+ writeU8(os, content_width);
+ writeU8(os, params_width);
+ MapNode::serializeBulk(os, version, tmp_nodes, nodecount,
+ content_width, params_width, true);
+ delete[] tmp_nodes;
+ }
+ else
+ {
+ u8 content_width = 1;
+ /*u8 content_width = 2;*/
+ u8 params_width = 2;
+ writeU8(os, content_width);
+ writeU8(os, params_width);
+ MapNode::serializeBulk(os, version, data, nodecount,
+ content_width, params_width, true);
+ }
+
+ /*
+ Node metadata
+ */
+ std::ostringstream oss(std::ios_base::binary);
+ m_node_metadata->serialize(oss);
+ compressZlib(oss.str(), os);
+
+ /*
+ Data that goes to disk, but not the network
+ */
+ if(disk)
+ {
+ // Static objects
+ m_static_objects.serialize(os);
+
+ // Timestamp
+ writeU32(os, getTimestamp());
+
+ // Write block-specific node definition id mapping
+ nimap.serialize(os);
+ }
+}
+
+
+void MapBlock::deSerialize(std::istream &is, u8 version, bool disk)
+{
+ if(!ser_ver_supported(version))
+ throw VersionMismatchException("ERROR: MapBlock format not supported");
+
+ if(version <= 21)
+ {
+ deSerialize_pre22(is, version, disk);
+ return;
+ }
+
+ u8 flags = readU8(is);
+ is_underground = (flags & 0x01) ? true : false;
+ m_day_night_differs = (flags & 0x02) ? true : false;
+ m_lighting_expired = (flags & 0x04) ? true : false;
+ m_generated = (flags & 0x08) ? false : true;
+
+ /*
+ Bulk node data
+ */
+ u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
+ u8 content_width = readU8(is);
+ u8 params_width = readU8(is);
+ if(content_width != 1)
+ throw SerializationError("MapBlock::deSerialize(): invalid content_width");
+ if(params_width != 2)
+ throw SerializationError("MapBlock::deSerialize(): invalid params_width");
+ MapNode::deSerializeBulk(is, version, data, nodecount,
+ content_width, params_width, true);
+
+ /*
+ NodeMetadata
+ */
+ // Ignore errors
+ try{
+ std::ostringstream oss(std::ios_base::binary);
+ decompressZlib(is, oss);
+ std::istringstream iss(oss.str(), std::ios_base::binary);
+ m_node_metadata->deSerialize(iss, m_gamedef);
+ }
+ catch(SerializationError &e)
+ {
+ errorstream<<"WARNING: MapBlock::deSerialize(): Ignoring an error"
+ <<" while deserializing node metadata"<<std::endl;
+ }
+
+ /*
+ Data that is only on disk
+ */
+ if(disk)
+ {
+ // Static objects
+ m_static_objects.deSerialize(is);
+
+ // Timestamp
+ setTimestamp(readU32(is));
+ m_disk_timestamp = m_timestamp;
+
+ // Dynamically re-set ids based on node names
+ NameIdMapping nimap;
+ nimap.deSerialize(is);
+ correctBlockNodeIds(&nimap, data, m_gamedef);
+ }
+}
+
+/*
+ Legacy serialization
+*/
+
+// List relevant id-name pairs for ids in the block using nodedef
+// Before serialization version 22
+static void getBlockNodeIdMapping_pre22(NameIdMapping *nimap, MapNode *nodes,
+ INodeDefManager *nodedef)
+{
+ std::set<content_t> unknown_contents;
+ for(u32 i=0; i<MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE; i++)
+ {
+ content_t id = nodes[i].getContent();
+ const ContentFeatures &f = nodedef->get(id);
+ const std::string &name = f.name;
+ if(name == "")
+ unknown_contents.insert(id);
+ else
+ nimap->set(id, name);
+ }
+ for(std::set<content_t>::const_iterator
+ i = unknown_contents.begin();
+ i != unknown_contents.end(); i++){
+ errorstream<<"getBlockNodeIdMapping_pre22(): IGNORING ERROR: "
+ <<"Name for node id "<<(*i)<<" not known"<<std::endl;
+ }
+}
+void MapBlock::serialize_pre22(std::ostream &os, u8 version, bool disk)
+{
+ u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
+
+ MapNode *tmp_data = new MapNode[nodecount];
+
+ // Legacy data changes
+ // This code has to change from post-22 to pre-22 format.
+ INodeDefManager *nodedef = m_gamedef->ndef();
+ for(u32 i=0; i<nodecount; i++)
+ {
+ const ContentFeatures &f = nodedef->get(tmp_data[i].getContent());
+ // Mineral
+ if(nodedef->getId("default:stone_with_coal") == tmp_data[i].getContent())
+ {
+ 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)
{
- u32 s = 1 + i * MapNode::serializedLength(version);
- data[i].serialize(&dest[s], version);
+ tmp_data[i].setParam1(tmp_data[i].getParam2());
+ tmp_data[i].setParam2(0);
}
+ // wall_mounted
+ if(f.legacy_wallmounted)
+ {
+ u8 wallmounted_new_to_old[8] = {0x04, 0x08, 0x01, 0x02, 0x10, 0x20, 0, 0};
+ u8 dir_new_format = tmp_data[i].getParam2() & 7; // lowest 3 bits
+ u8 dir_old_format = wallmounted_new_to_old[dir_new_format];
+ tmp_data[i].setParam2(dir_old_format);
+ }
+ }
+
+ // Serialize nodes
+ u32 ser_length = MapNode::serializedLength(version);
+ SharedBuffer<u8> databuf_nodelist(nodecount * ser_length);
+ for(u32 i=0; i<nodecount; i++)
+ {
+ tmp_data[i].serialize(&databuf_nodelist[i*ser_length], version);
+ }
+
+ delete[] tmp_data;
- os.write((char*)*dest, dest.getSize());
+ // These have no compression
+ if(version <= 3 || version == 5 || version == 6)
+ {
+ writeU8(os, is_underground);
+ os.write((char*)*databuf_nodelist, databuf_nodelist.getSize());
}
else if(version <= 10)
{
*/
// First byte
- os.write((char*)&is_underground, 1);
-
- u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
+ writeU8(os, is_underground);
// Get and compress materials
SharedBuffer<u8> materialdata(nodecount);
for(u32 i=0; i<nodecount; i++)
{
- materialdata[i] = data[i].param0;
+ materialdata[i] = databuf_nodelist[i*ser_length];
}
compress(materialdata, os, version);
SharedBuffer<u8> lightdata(nodecount);
for(u32 i=0; i<nodecount; i++)
{
- lightdata[i] = data[i].param1;
+ lightdata[i] = databuf_nodelist[i*ser_length+1];
}
compress(lightdata, os, version);
SharedBuffer<u8> param2data(nodecount);
for(u32 i=0; i<nodecount; i++)
{
- param2data[i] = data[i].param2;
+ param2data[i] = databuf_nodelist[i*ser_length+2];
}
compress(param2data, os, version);
}
if(m_generated == false)
flags |= 0x08;
}
- os.write((char*)&flags, 1);
+ writeU8(os, flags);
- u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
-
/*
Get data
*/
- // Serialize nodes
- SharedBuffer<u8> databuf_nodelist(nodecount*3);
- for(u32 i=0; i<nodecount; i++)
- {
- data[i].serialize(&databuf_nodelist[i*3], version);
- }
-
// Create buffer with different parameters sorted
SharedBuffer<u8> databuf(nodecount*3);
for(u32 i=0; i<nodecount; i++)
{
- databuf[i] = databuf_nodelist[i*3];
- databuf[i+nodecount] = databuf_nodelist[i*3+1];
- databuf[i+nodecount*2] = databuf_nodelist[i*3+2];
+ databuf[i] = databuf_nodelist[i*ser_length];
+ databuf[i+nodecount] = databuf_nodelist[i*ser_length+1];
+ databuf[i+nodecount*2] = databuf_nodelist[i*ser_length+2];
}
/*
}
}
}
-}
-void MapBlock::deSerialize(std::istream &is, u8 version)
-{
- if(!ser_ver_supported(version))
- throw VersionMismatchException("ERROR: MapBlock format not supported");
- // These have no lighting info
- if(version <= 1)
+ if(disk)
{
- setLightingExpired(true);
- }
+ // Versions up from 9 have block objects. (DEPRECATED)
+ if(version >= 9)
+ {
+ // count=0
+ writeU16(os, 0);
+ }
- // These have no "generated" field
- if(version < 18)
- {
- m_generated = true;
+ // Versions up from 15 have static objects.
+ if(version >= 15)
+ {
+ m_static_objects.serialize(os);
+ }
+
+ // Timestamp
+ if(version >= 17)
+ {
+ writeU32(os, getTimestamp());
+ }
+
+ // Scan and write node definition id mapping
+ if(version >= 21)
+ {
+ NameIdMapping nimap;
+ getBlockNodeIdMapping_pre22(&nimap, data, m_gamedef->ndef());
+ nimap.serialize(os);
+ }
}
+}
+
+void MapBlock::deSerialize_pre22(std::istream &is, u8 version, bool disk)
+{
+ u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
+
+ // Initialize default flags
+ is_underground = false;
+ m_day_night_differs = false;
+ m_lighting_expired = false;
+ m_generated = true;
+
+ // Make a temporary buffer
+ u32 ser_length = MapNode::serializedLength(version);
+ SharedBuffer<u8> databuf_nodelist(nodecount * ser_length);
// These have no compression
if(version <= 3 || version == 5 || version == 6)
{
- u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
char tmp;
is.read(&tmp, 1);
if(is.gcount() != 1)
throw SerializationError
("MapBlock::deSerialize: no enough input data");
is_underground = tmp;
- for(u32 i=0; i<nodecount; i++)
- {
- s32 len = MapNode::serializedLength(version);
- SharedBuffer<u8> d(len);
- is.read((char*)*d, len);
- if(is.gcount() != len)
- throw SerializationError
- ("MapBlock::deSerialize: no enough input data");
- data[i].deSerialize(*d, version);
- }
+ is.read((char*)*databuf_nodelist, nodecount * ser_length);
+ if(is.gcount() != nodecount * ser_length)
+ throw SerializationError
+ ("MapBlock::deSerialize: no enough input data");
}
else if(version <= 10)
{
- u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
-
u8 t8;
is.read((char*)&t8, 1);
is_underground = t8;
("MapBlock::deSerialize: invalid format");
for(u32 i=0; i<s.size(); i++)
{
- data[i].param0 = s[i];
+ databuf_nodelist[i*ser_length] = s[i];
}
}
{
("MapBlock::deSerialize: invalid format");
for(u32 i=0; i<s.size(); i++)
{
- data[i].param1 = s[i];
+ databuf_nodelist[i*ser_length + 1] = s[i];
}
}
("MapBlock::deSerialize: invalid format");
for(u32 i=0; i<s.size(); i++)
{
- data[i].param2 = s[i];
+ databuf_nodelist[i*ser_length + 2] = s[i];
}
}
}
// All other versions (newest)
else
{
- u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
-
u8 flags;
is.read((char*)&flags, 1);
is_underground = (flags & 0x01) ? true : false;
// deserialize nodes from buffer
for(u32 i=0; i<nodecount; i++)
{
- u8 buf[3];
- buf[0] = s[i];
- buf[1] = s[i+nodecount];
- buf[2] = s[i+nodecount*2];
- data[i].deSerialize(buf, version);
+ databuf_nodelist[i*ser_length] = s[i];
+ databuf_nodelist[i*ser_length + 1] = s[i+nodecount];
+ databuf_nodelist[i*ser_length + 2] = s[i+nodecount*2];
}
/*
}
}
}
-}
-void MapBlock::serializeDiskExtra(std::ostream &os, u8 version)
-{
- // Versions up from 9 have block objects. (DEPRECATED)
- if(version >= 9)
+ // Deserialize node data
+ for(u32 i=0; i<nodecount; i++)
{
- // count=0
- writeU16(os, 0);
- }
-
- // Versions up from 15 have static objects.
- if(version >= 15)
- {
- m_static_objects.serialize(os);
+ data[i].deSerialize(&databuf_nodelist[i*ser_length], version);
}
- // Timestamp
- if(version >= 17)
+ if(disk)
{
- writeU32(os, getTimestamp());
- }
+ /*
+ Versions up from 9 have block objects. (DEPRECATED)
+ */
+ if(version >= 9){
+ u16 count = readU16(is);
+ // Not supported and length not known if count is not 0
+ if(count != 0){
+ errorstream<<"WARNING: MapBlock::deSerialize_pre22(): "
+ <<"Ignoring stuff coming at and after MBOs"<<std::endl;
+ return;
+ }
+ }
+
+ /*
+ Versions up from 15 have static objects.
+ */
+ if(version >= 15)
+ m_static_objects.deSerialize(is);
+
+ // Timestamp
+ if(version >= 17){
+ setTimestamp(readU32(is));
+ m_disk_timestamp = m_timestamp;
+ } else {
+ setTimestamp(BLOCK_TIMESTAMP_UNDEFINED);
+ }
- // Scan and write node definition id mapping
- if(version >= 21){
+ // Dynamically re-set ids based on node names
NameIdMapping nimap;
- getBlockNodeIdMapping(&nimap, this, m_gamedef->ndef());
- nimap.serialize(os);
+ // If supported, read node definition id mapping
+ if(version >= 21){
+ nimap.deSerialize(is);
+ // Else set the legacy mapping
+ } else {
+ content_mapnode_get_name_id_mapping(&nimap);
+ }
+ correctBlockNodeIds(&nimap, data, m_gamedef);
}
-}
-void MapBlock::deSerializeDiskExtra(std::istream &is, u8 version)
-{
- /*
- Versions up from 9 have block objects. (DEPRECATED)
- */
- if(version >= 9){
- u16 count = readU16(is);
- // Not supported and length not known if count is not 0
- if(count != 0){
- errorstream<<"WARNING: MapBlock::deSerializeDiskExtra(): "
- <<"Ignoring stuff coming at and after MBOs"<<std::endl;
- return;
+
+ // Legacy data changes
+ // This code has to convert from pre-22 to post-22 format.
+ INodeDefManager *nodedef = m_gamedef->ndef();
+ for(u32 i=0; i<nodecount; i++)
+ {
+ const ContentFeatures &f = nodedef->get(data[i].getContent());
+ // Mineral
+ if(nodedef->getId("default:stone") == data[i].getContent()
+ && data[i].getParam1() == 1)
+ {
+ //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);
}
}
- /*
- Versions up from 15 have static objects.
- */
- if(version >= 15)
- m_static_objects.deSerialize(is);
-
- // Timestamp
- if(version >= 17){
- setTimestamp(readU32(is));
- m_disk_timestamp = m_timestamp;
- } else {
- setTimestamp(BLOCK_TIMESTAMP_UNDEFINED);
- }
-
- // Dynamically re-set ids based on node names
- NameIdMapping nimap;
- // If supported, read node definition id mapping
- if(version >= 21){
- nimap.deSerialize(is);
- // Else set the legacy mapping
- } else {
- content_mapnode_get_name_id_mapping(&nimap);
- }
- correctBlockNodeIds(&nimap, this, m_gamedef);
}
/*
Graphics-related methods
*/
- /*// A quick version with nodes passed as parameters
- u8 getFaceLight(u32 daynight_ratio, MapNode n, MapNode n2,
- v3s16 face_dir);*/
- /*// A more convenient version
- u8 getFaceLight(u32 daynight_ratio, v3s16 p, v3s16 face_dir)
- {
- return getFaceLight(daynight_ratio,
- getNodeParentNoEx(p),
- getNodeParentNoEx(p + face_dir),
- face_dir);
- }*/
+#ifndef SERVER // Only on client
+
u8 getFaceLight2(u32 daynight_ratio, v3s16 p, v3s16 face_dir,
INodeDefManager *nodemgr)
{
face_dir, nodemgr);
}
-#ifndef SERVER // Only on client
-
#if 1
/*
Thread-safely updates the whole mesh of the mapblock.
*/
// These don't write or read version by itself
- void serialize(std::ostream &os, u8 version);
- void deSerialize(std::istream &is, u8 version);
-
- // Used after the basic ones when writing on disk (serverside)
- void serializeDiskExtra(std::ostream &os, u8 version);
- // In addition to doing other things, will add unknown blocks from
- // id-name mapping to wndef
- void deSerializeDiskExtra(std::istream &is, u8 version);
+ // Set disk to true for on-disk format, false for over-the-network format
+ void serialize(std::ostream &os, u8 version, bool disk);
+ // If disk == true: In addition to doing other things, will add
+ // unknown blocks from id-name mapping to wndef
+ void deSerialize(std::istream &is, u8 version, bool disk);
private:
/*
Private methods
*/
+ void serialize_pre22(std::ostream &os, u8 version, bool disk);
+ void deSerialize_pre22(std::istream &is, u8 version, bool disk);
+
/*
Used only internally, because changes can't be tracked
*/
#include "nodedef.h"
#include "gamedef.h"
#include "content_mapblock.h"
-#include "mineral.h" // For mineral_block_texture
void MeshMakeData::fill(u32 daynight_ratio, MapBlock *block)
{
dest.push_back(face);
}
-static TileSpec getTile(const MapNode &node, v3s16 dir,
- ITextureSource *tsrc, INodeDefManager *nodemgr)
+static TileSpec getTile(const MapNode &node, v3s16 dir, INodeDefManager *nodemgr)
{
- const ContentFeatures &f = nodemgr->get(node);
+ // Direction must be (1,0,0), (-1,0,0), (0,1,0), (0,-1,0),
+ // (0,0,1), (0,0,-1) or (0,0,0)
+ assert(dir.X * dir.X + dir.Y * dir.Y + dir.Z * dir.Z <= 1);
+
+ // Convert direction to single integer for table lookup
+ // 0 = (0,0,0)
+ // 1 = (1,0,0)
+ // 2 = (0,1,0)
+ // 3 = (0,0,1)
+ // 4 = invalid, treat as (0,0,0)
+ // 5 = (0,0,-1)
+ // 6 = (0,-1,0)
+ // 7 = (-1,0,0)
+ u8 dir_i = (dir.X + 2 * dir.Y + 3 * dir.Z) & 7;
+
+ // Get rotation for things like chests
+ u8 facedir = node.getFaceDir(nodemgr);
+ assert(facedir <= 3);
- if(f.param_type == CPT_FACEDIR_SIMPLE)
- dir = facedir_rotate(node.param1, dir);
-
- TileSpec spec;
-
- s32 dir_i = -1;
-
- if(dir == v3s16(0,0,0))
- dir_i = -1;
- else if(dir == v3s16(0,1,0))
- dir_i = 0;
- else if(dir == v3s16(0,-1,0))
- dir_i = 1;
- else if(dir == v3s16(1,0,0))
- dir_i = 2;
- else if(dir == v3s16(-1,0,0))
- dir_i = 3;
- else if(dir == v3s16(0,0,1))
- dir_i = 4;
- else if(dir == v3s16(0,0,-1))
- dir_i = 5;
-
- if(dir_i == -1)
- // Non-directional
- spec = f.tiles[0];
- else
- spec = f.tiles[dir_i];
-
- /*
- If it contains some mineral, change texture id
- */
- if(f.param_type == CPT_MINERAL && tsrc)
+ static const u8 dir_to_tile[4 * 8] =
{
- u8 mineral = node.getMineral(nodemgr);
- std::string mineral_texture_name = mineral_block_texture(mineral);
- if(mineral_texture_name != "")
- {
- u32 orig_id = spec.texture.id;
- std::string texture_name = tsrc->getTextureName(orig_id);
- //texture_name += "^blit:";
- texture_name += "^";
- texture_name += mineral_texture_name;
- u32 new_id = tsrc->getTextureId(texture_name);
- spec.texture = tsrc->getTexture(new_id);
- }
- }
-
- return spec;
+ // 0 +X +Y +Z 0 -Z -Y -X
+ 0, 2, 0, 4, 0, 5, 1, 3, // facedir = 0
+ 0, 4, 0, 3, 0, 2, 1, 5, // facedir = 1
+ 0, 3, 0, 5, 0, 4, 1, 2, // facedir = 2
+ 0, 5, 0, 2, 0, 3, 1, 4, // facedir = 3
+ };
+
+ return nodemgr->get(node).tiles[dir_to_tile[facedir*8 + dir_i]];
}
/*
NodeModMap *temp_mods, ITextureSource *tsrc, INodeDefManager *ndef)
{
TileSpec spec;
- spec = getTile(mn, face_dir, tsrc, ndef);
+ spec = getTile(mn, face_dir, ndef);
/*
Check temporary modifications on this node
if(mod.type == NODEMOD_CHANGECONTENT)
{
MapNode mn2(mod.param);
- spec = getTile(mn2, face_dir, tsrc, ndef);
+ spec = getTile(mn2, face_dir, ndef);
}
#endif
if(mod.type == NODEMOD_CRACK)
#include "noise.h"
#include "mapblock.h"
#include "map.h"
-#include "mineral.h"
//#include "serverobject.h"
#include "content_sao.h"
#include "nodedef.h"
MapNode n_##name(c_##name);
CONTENT_VARIABLE(ndef, stone);
- CONTENT_VARIABLE(ndef, water_source);
CONTENT_VARIABLE(ndef, air);
+ CONTENT_VARIABLE(ndef, water_source);
CONTENT_VARIABLE(ndef, dirt);
CONTENT_VARIABLE(ndef, sand);
CONTENT_VARIABLE(ndef, gravel);
+ CONTENT_VARIABLE(ndef, clay);
CONTENT_VARIABLE(ndef, lava_source);
CONTENT_VARIABLE(ndef, cobble);
CONTENT_VARIABLE(ndef, mossycobble);
CONTENT_VARIABLE(ndef, dirt_with_grass);
+ CONTENT_VARIABLE(ndef, junglegrass);
+ CONTENT_VARIABLE(ndef, stone_with_coal);
+ CONTENT_VARIABLE(ndef, stone_with_iron);
+ CONTENT_VARIABLE(ndef, mese);
/*
Make base ground level
}
}
- /*
- 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)
*/
/*else if(vmanip.m_flags[i] & VMANIP_FLAG_DUNGEON_INSIDE)
{
if(wetness > 1.2)
- vmanip.m_data[i].setContent(LEGN(ndef, "CONTENT_MUD"));
+ vmanip.m_data[i].setContent(c_dirt);
}*/
data->vmanip->m_area.add_y(em, i, -1);
}
((claynoise > 0) && (claynoise < 0.12) && (current_depth == 1))
);
if (have_clay)
- vmanip.m_data[i] = MapNode(LEGN(ndef, "CONTENT_CLAY"));
+ vmanip.m_data[i] = MapNode(c_clay);
else
- vmanip.m_data[i] = MapNode(LEGN(ndef, "CONTENT_SAND"));
+ vmanip.m_data[i] = MapNode(c_sand);
}
#if 1
else if(current_depth==0 && !water_detected
&& y >= WATER_LEVEL && air_detected)
- vmanip.m_data[i] = MapNode(LEGN(ndef, "CONTENT_GRASS"));
+ vmanip.m_data[i] = MapNode(c_dirt_with_grass);
#endif
else
- vmanip.m_data[i] = MapNode(LEGN(ndef, "CONTENT_MUD"));
+ vmanip.m_data[i] = MapNode(c_dirt);
}
else
{
- if(vmanip.m_data[i].getContent() == LEGN(ndef, "CONTENT_MUD")
- || vmanip.m_data[i].getContent() == LEGN(ndef, "CONTENT_GRASS"))
- vmanip.m_data[i] = MapNode(LEGN(ndef, "CONTENT_STONE"));
+ if(vmanip.m_data[i].getContent() == c_dirt
+ || vmanip.m_data[i].getContent() == c_dirt_with_grass)
+ vmanip.m_data[i] = MapNode(c_stone);
}
current_depth++;
make_papyrus(vmanip, p, ndef);
}
// Trees grow only on mud and grass, on land
- else if((n->getContent() == c_dirt || n->getContent() == LEGN(ndef, "CONTENT_GRASS")) && y > WATER_LEVEL + 2)
+ else if((n->getContent() == c_dirt || n->getContent() == c_dirt_with_grass) && y > WATER_LEVEL + 2)
{
p.Y++;
//if(surface_humidity_2d(data->seed, v2s16(x, y)) < 0.5)
continue;
/*p.Y--;
if(vmanip.m_area.contains(p))
- vmanip.m_data[vmanip.m_area.index(p)] = LEGN(ndef, "CONTENT_MUD");
+ vmanip.m_data[vmanip.m_area.index(p)] = c_dirt;
p.Y++;*/
if(vmanip.m_area.contains(p))
- vmanip.m_data[vmanip.m_area.index(p)] = LEGN(ndef, "CONTENT_JUNGLEGRASS");
+ vmanip.m_data[vmanip.m_area.index(p)] = c_junglegrass;
}
}
/*{
u32 i = data->vmanip->m_area.index(v3s16(p));
MapNode *n = &data->vmanip->m_data[i];
- if(n->getContent() != LEGN(ndef, "CONTENT_MUD") && n->getContent() != LEGN(ndef, "CONTENT_GRASS"))
+ if(n->getContent() != c_dirt && n->getContent() != c_dirt_with_grass)
continue;
}*/
// Will be placed one higher
/*{
u32 i = data->vmanip->m_area.index(v3s16(p));
MapNode *n = &data->vmanip->m_data[i];
- if(n->getContent() != LEGN(ndef, "CONTENT_MUD") && n->getContent() != LEGN(ndef, "CONTENT_GRASS"))
+ if(n->getContent() != c_dirt && n->getContent() != c_dirt_with_grass)
continue;
}*/
// Will be placed one lower
#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():
#include "mapnode.h"
#include "porting.h"
#include <string>
-#include "mineral.h"
#include "main.h" // For g_settings
#include "nodedef.h"
#include "content_mapnode.h" // For mapnode_translate_*_internal
#include "serialization.h" // For ser_ver_supported
-#ifndef SERVER
-/*
- Nodes make a face if contents differ and solidness differs.
- Return value:
- 0: No face
- 1: Face uses m1's content
- 2: Face uses m2's content
- equivalent: Whether the blocks share the same face (eg. water and glass)
-
- TODO: Add 3: Both faces drawn with backface culling, remove equivalent
-*/
-u8 face_contents(content_t m1, content_t m2, bool *equivalent,
- INodeDefManager *nodemgr)
-{
- *equivalent = false;
-
- if(m1 == CONTENT_IGNORE || m2 == CONTENT_IGNORE)
- return 0;
-
- bool contents_differ = (m1 != m2);
-
- const ContentFeatures &f1 = nodemgr->get(m1);
- const ContentFeatures &f2 = nodemgr->get(m2);
-
- // Contents don't differ for different forms of same liquid
- if(f1.sameLiquid(f2))
- contents_differ = false;
-
- u8 c1 = f1.solidness;
- u8 c2 = f2.solidness;
-
- bool solidness_differs = (c1 != c2);
- bool makes_face = contents_differ && solidness_differs;
-
- if(makes_face == false)
- return 0;
-
- if(c1 == 0)
- c1 = f1.visual_solidness;
- if(c2 == 0)
- c2 = f2.visual_solidness;
-
- if(c1 == c2){
- *equivalent = true;
- // If same solidness, liquid takes precense
- if(f1.isLiquid())
- return 1;
- if(f2.isLiquid())
- return 2;
- }
-
- if(c1 > c2)
- return 1;
- else
- return 2;
-}
-#endif
-
-v3s16 facedir_rotate(u8 facedir, v3s16 dir)
-{
- /*
- Face 2 (normally Z-) direction:
- facedir=0: Z-
- facedir=1: X-
- facedir=2: Z+
- facedir=3: X+
- */
- v3s16 newdir;
- if(facedir==0) // Same
- newdir = v3s16(dir.X, dir.Y, dir.Z);
- else if(facedir == 1) // Face is taken from rotXZccv(-90)
- newdir = v3s16(-dir.Z, dir.Y, dir.X);
- else if(facedir == 2) // Face is taken from rotXZccv(180)
- newdir = v3s16(-dir.X, dir.Y, -dir.Z);
- else if(facedir == 3) // Face is taken from rotXZccv(90)
- newdir = v3s16(dir.Z, dir.Y, -dir.X);
- else
- newdir = dir;
- return newdir;
-}
-
-u8 packDir(v3s16 dir)
-{
- u8 b = 0;
-
- if(dir.X > 0)
- b |= (1<<0);
- else if(dir.X < 0)
- b |= (1<<1);
-
- if(dir.Y > 0)
- b |= (1<<2);
- else if(dir.Y < 0)
- b |= (1<<3);
-
- if(dir.Z > 0)
- b |= (1<<4);
- else if(dir.Z < 0)
- b |= (1<<5);
-
- return b;
-}
-v3s16 unpackDir(u8 b)
-{
- v3s16 d(0,0,0);
-
- if(b & (1<<0))
- d.X = 1;
- else if(b & (1<<1))
- d.X = -1;
-
- if(b & (1<<2))
- d.Y = 1;
- else if(b & (1<<3))
- d.Y = -1;
-
- if(b & (1<<4))
- d.Z = 1;
- else if(b & (1<<5))
- d.Z = -1;
-
- return d;
-}
-
/*
MapNode
*/
u8 MapNode::getLight(enum LightBank bank, INodeDefManager *nodemgr) const
{
// Select the brightest of [light source, propagated light]
+ const ContentFeatures &f = nodemgr->get(*this);
u8 light = 0;
- if(nodemgr->get(*this).param_type == CPT_LIGHT)
+ if(f.param_type == CPT_LIGHT)
{
if(bank == LIGHTBANK_DAY)
light = param1 & 0x0f;
else
assert(0);
}
- if(nodemgr->get(*this).light_source > light)
- light = nodemgr->get(*this).light_source;
+ if(f.light_source > light)
+ light = f.light_source;
return light;
}
-u8 MapNode::getLightBanksWithSource(INodeDefManager *nodemgr) const
+bool MapNode::getLightBanks(u8 &lightday, u8 &lightnight, INodeDefManager *nodemgr) const
{
// Select the brightest of [light source, propagated light]
- u8 lightday = 0;
- u8 lightnight = 0;
- if(nodemgr->get(*this).param_type == CPT_LIGHT)
+ const ContentFeatures &f = nodemgr->get(*this);
+ if(f.param_type == CPT_LIGHT)
{
lightday = param1 & 0x0f;
lightnight = (param1>>4)&0x0f;
}
- if(nodemgr->get(*this).light_source > lightday)
- lightday = nodemgr->get(*this).light_source;
- if(nodemgr->get(*this).light_source > lightnight)
- lightnight = nodemgr->get(*this).light_source;
- return (lightday&0x0f) | ((lightnight<<4)&0xf0);
+ else
+ {
+ lightday = 0;
+ lightnight = 0;
+ }
+ if(f.light_source > lightday)
+ lightday = f.light_source;
+ if(f.light_source > lightnight)
+ lightnight = f.light_source;
+ return f.param_type == CPT_LIGHT || f.light_source != 0;
}
-u8 MapNode::getMineral(INodeDefManager *nodemgr) const
+u8 MapNode::getFaceDir(INodeDefManager *nodemgr) const
{
- if(nodemgr->get(*this).param_type == CPT_MINERAL)
+ const ContentFeatures &f = nodemgr->get(*this);
+ if(f.param_type_2 == CPT2_FACEDIR)
+ return getParam2() & 0x03;
+ return 0;
+}
+
+u8 MapNode::getWallMounted(INodeDefManager *nodemgr) const
+{
+ const ContentFeatures &f = nodemgr->get(*this);
+ if(f.param_type_2 == CPT2_WALLMOUNTED)
+ return getParam2() & 0x07;
+ return 0;
+}
+
+v3s16 MapNode::getWallMountedDir(INodeDefManager *nodemgr) const
+{
+ switch(getWallMounted(nodemgr))
{
- return param1 & 0x0f;
+ case 0: default: return v3s16(0,1,0);
+ case 1: return v3s16(0,-1,0);
+ case 2: return v3s16(1,0,0);
+ case 3: return v3s16(-1,0,0);
+ case 4: return v3s16(0,0,1);
+ case 5: return v3s16(0,0,-1);
}
-
- return MINERAL_NONE;
}
+
+
u32 MapNode::serializedLength(u8 version)
{
if(!ser_ver_supported(version))
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);
- u8 actual_param0 = n_foreign.param0;
+ 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_param0 == CONTENT_IGNORE)
- actual_param0 = 255;
- else if(actual_param0 == CONTENT_AIR)
- actual_param0 = 254;
+ if(actual_content == CONTENT_IGNORE)
+ actual_content = 255;
+ else if(actual_content == CONTENT_AIR)
+ actual_content = 254;
}
if(version == 0)
{
- dest[0] = actual_param0;
+ dest[0] = actual_content;
}
else if(version <= 9)
{
- dest[0] = actual_param0;
+ dest[0] = actual_content;
dest[1] = n_foreign.param1;
}
else
{
- dest[0] = actual_param0;
+ dest[0] = actual_content;
dest[1] = n_foreign.param1;
dest[2] = n_foreign.param2;
}
}
-void MapNode::deSerialize(u8 *source, u8 version)
+void MapNode::deSerialize_pre22(u8 *source, u8 version)
{
- if(!ser_ver_supported(version))
- throw VersionMismatchException("ERROR: MapNode format not supported");
-
- if(version == 0)
- {
- param0 = source[0];
- }
- else if(version == 1)
+ if(version <= 1)
{
param0 = source[0];
}
}
// Convert special values from old version to new
- if(version <= 18)
+ if(version <= 19)
{
// In these versions, CONTENT_IGNORE and CONTENT_AIR
// are 255 and 254
- if(param0 == 255)
- param0 = CONTENT_IGNORE;
- else if(param0 == 254)
- param0 = CONTENT_AIR;
- }
- // version 19 is fucked up with sometimes the old values and sometimes not
- if(version == 19)
- {
+ // Version 19 is fucked up with sometimes the old values and sometimes not
if(param0 == 255)
param0 = CONTENT_IGNORE;
else if(param0 == 254)
*this = mapnode_translate_to_internal(*this, version);
}
+
+#ifndef SERVER
+
+/*
+ Nodes make a face if contents differ and solidness differs.
+ Return value:
+ 0: No face
+ 1: Face uses m1's content
+ 2: Face uses m2's content
+ equivalent: Whether the blocks share the same face (eg. water and glass)
+
+ TODO: Add 3: Both faces drawn with backface culling, remove equivalent
+*/
+u8 face_contents(content_t m1, content_t m2, bool *equivalent,
+ INodeDefManager *nodemgr)
+{
+ *equivalent = false;
+
+ if(m1 == CONTENT_IGNORE || m2 == CONTENT_IGNORE)
+ return 0;
+
+ bool contents_differ = (m1 != m2);
+
+ const ContentFeatures &f1 = nodemgr->get(m1);
+ const ContentFeatures &f2 = nodemgr->get(m2);
+
+ // Contents don't differ for different forms of same liquid
+ if(f1.sameLiquid(f2))
+ contents_differ = false;
+
+ u8 c1 = f1.solidness;
+ u8 c2 = f2.solidness;
+
+ bool solidness_differs = (c1 != c2);
+ bool makes_face = contents_differ && solidness_differs;
+
+ if(makes_face == false)
+ return 0;
+
+ if(c1 == 0)
+ c1 = f1.visual_solidness;
+ if(c2 == 0)
+ c2 = f2.visual_solidness;
+
+ if(c1 == c2){
+ *equivalent = true;
+ // If same solidness, liquid takes precense
+ if(f1.isLiquid())
+ return 1;
+ if(f2.isLiquid())
+ return 2;
+ }
+
+ if(c1 > c2)
+ return 1;
+ else
+ return 2;
+}
+
/*
Gets lighting value at face of node
}
}
+#endif
- Tile = TileSpec at some side of a node of some content type
Content ranges:
- 0x000...0x07f: param2 is fully usable
- 0x800...0xfff: param2 lower 4 bytes are free
+ 0x000...0x07f: param2 is fully usable
+ 0x800...0xfff: param2 lower 4 bits are free
*/
typedef u16 content_t;
#define MAX_CONTENT 0xfff
*/
#define CONTENT_AIR 126
-#ifndef SERVER
-/*
- Nodes make a face if contents differ and solidness differs.
- Return value:
- 0: No face
- 1: Face uses m1's content
- 2: Face uses m2's content
- equivalent: Whether the blocks share the same face (eg. water and glass)
-*/
-u8 face_contents(content_t m1, content_t m2, bool *equivalent,
- INodeDefManager *nodemgr);
-#endif
-
-/*
- Packs directions like (1,0,0), (1,-1,0) in six bits.
- NOTE: This wastes way too much space for most purposes.
-*/
-u8 packDir(v3s16 dir);
-v3s16 unpackDir(u8 b);
-
-/*
- facedir: CPT_FACEDIR_SIMPLE param1 value
- dir: The face for which stuff is wanted
- return value: The face from which the stuff is actually found
-
- NOTE: Currently this uses 2 bits for Z-,X-,Z+,X+, should there be Y+
- and Y- too?
-*/
-v3s16 facedir_rotate(u8 facedir, v3s16 dir);
-
enum LightBank
{
LIGHTBANK_DAY,
stored logarithmically from 0 to LIGHT_MAX.
Sunlight is LIGHT_SUN, which is LIGHT_MAX+1.
- Contains 2 values, day- and night lighting. Each takes 4 bits.
- - Mineral content (should be removed from here)
- Uhh... well, most blocks have light or nothing in here.
*/
u8 param1;
{
param1 = a_param1;
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
setContent(content);
}
void setLight(enum LightBank bank, u8 a_light, INodeDefManager *nodemgr);
u8 getLight(enum LightBank bank, INodeDefManager *nodemgr) const;
- u8 getLightBanksWithSource(INodeDefManager *nodemgr) const;
+ bool getLightBanks(u8 &lightday, u8 &lightnight, INodeDefManager *nodemgr) const;
// 0 <= daylight_factor <= 1000
// 0 <= return value <= LIGHT_SUN
u8 getLightBlend(u32 daylight_factor, INodeDefManager *nodemgr) const
{
- u8 l = ((daylight_factor * getLight(LIGHTBANK_DAY, nodemgr)
- + (1000-daylight_factor) * getLight(LIGHTBANK_NIGHT, nodemgr))
- )/1000;
- u8 max = LIGHT_MAX;
- if(getLight(LIGHTBANK_DAY, nodemgr) == LIGHT_SUN)
- max = LIGHT_SUN;
- if(l > max)
- l = max;
- return l;
+ u8 lightday = 0;
+ u8 lightnight = 0;
+ getLightBanks(lightday, lightnight, nodemgr);
+ return blend_light(daylight_factor, lightday, lightnight);
}
- /*// 0 <= daylight_factor <= 1000
- // 0 <= return value <= 255
- u8 getLightBlend(u32 daylight_factor, INodeDefManager *nodemgr)
- {
- u8 daylight = decode_light(getLight(LIGHTBANK_DAY, nodemgr));
- u8 nightlight = decode_light(getLight(LIGHTBANK_NIGHT, nodemgr));
- u8 mix = ((daylight_factor * daylight
- + (1000-daylight_factor) * nightlight)
- )/1000;
- return mix;
- }*/
- /*
- Gets mineral content of node, if there is any.
- MINERAL_NONE if doesn't contain or isn't able to contain mineral.
- */
- u8 getMineral(INodeDefManager *nodemgr) const;
-
+ u8 getFaceDir(INodeDefManager *nodemgr) const;
+ u8 getWallMounted(INodeDefManager *nodemgr) const;
+ v3s16 getWallMountedDir(INodeDefManager *nodemgr) const;
+
/*
Serialization functions
*/
void serialize(u8 *dest, u8 version);
void deSerialize(u8 *source, u8 version);
+ // Serializes or deserializes a list of nodes in bulk format (first the
+ // content of all nodes, then the param1 of all nodes, then the param2
+ // of all nodes).
+ // version = serialization version. Must be >= 22
+ // content_width = the number of bytes of content per node
+ // params_width = the number of bytes of params per node
+ // compressed = true to zlib-compress output
+ static void serializeBulk(std::ostream &os, int version,
+ const MapNode *nodes, u32 nodecount,
+ u8 content_width, u8 params_width, bool compressed);
+ static void deSerializeBulk(std::istream &is, int version,
+ MapNode *nodes, u32 nodecount,
+ u8 content_width, u8 params_width, bool compressed);
+
+private:
+ // Deprecated serialization methods
+ void serialize_pre22(u8 *dest, u8 version);
+ void deSerialize_pre22(u8 *source, u8 version);
};
+
+/*
+ MapNode helpers for mesh making stuff
+*/
+
+#ifndef SERVER
+
+/*
+ Nodes make a face if contents differ and solidness differs.
+ Return value:
+ 0: No face
+ 1: Face uses m1's content
+ 2: Face uses m2's content
+ equivalent: Whether the blocks share the same face (eg. water and glass)
+*/
+u8 face_contents(content_t m1, content_t m2, bool *equivalent,
+ INodeDefManager *nodemgr);
+
/*
Gets lighting value at face of node
#endif
+
+#endif
+
*/
#include "materials.h"
-#include "mapnode.h"
-#include "nodedef.h"
#include "utility.h"
void MaterialProperties::serialize(std::ostream &os)
return getDiggingProperties(mp, tp, 1000000);
}
-DiggingProperties getDiggingProperties(u16 content,
- const ToolDiggingProperties *tp, INodeDefManager *nodemgr)
-{
- const MaterialProperties &mp = nodemgr->get(content).material;
- return getDiggingProperties(&mp, tp);
-}
-
HittingProperties getHittingProperties(const MaterialProperties *mp,
const ToolDiggingProperties *tp, float time_from_last_punch)
{
return HittingProperties(hp, wear);
}
+HittingProperties getHittingProperties(const MaterialProperties *mp,
+ const ToolDiggingProperties *tp)
+{
+ return getHittingProperties(mp, tp, 1000000);
+}
+
{}
};
-class INodeDefManager;
-
DiggingProperties getDiggingProperties(const MaterialProperties *mp,
const ToolDiggingProperties *tp, float time_from_last_punch);
DiggingProperties getDiggingProperties(const MaterialProperties *mp,
const ToolDiggingProperties *tp);
-DiggingProperties getDiggingProperties(u16 content,
- const ToolDiggingProperties *tp, INodeDefManager *nodemgr);
-
struct HittingProperties
{
s16 hp;
HittingProperties getHittingProperties(const MaterialProperties *mp,
const ToolDiggingProperties *tp, float time_from_last_punch);
+HittingProperties getHittingProperties(const MaterialProperties *mp,
+ const ToolDiggingProperties *tp);
+
#endif
+++ /dev/null
-/*
-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();
-}
-
-
-
+++ /dev/null
-/*
-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
-
result = i->second;
return true;
}
+ u16 size() const{
+ return m_id_to_name.size();
+ }
private:
std::map<u16, std::string> m_id_to_name;
std::map<std::string, u16> m_name_to_id;
alpha = 255;
post_effect_color = video::SColor(0, 0, 0, 0);
param_type = CPT_NONE;
+ param_type_2 = CPT2_NONE;
is_ground_content = false;
light_propagates = false;
sunlight_propagates = false;
diggable = true;
climbable = false;
buildable_to = false;
- wall_mounted = false;
- dug_item = "";
- extra_dug_item = "";
- extra_dug_item_rarity = 2;
metadata_name = "";
liquid_type = LIQUID_NONE;
liquid_alternative_flowing = "";
// Make unknown blocks diggable
material.diggability = DIGGABLE_CONSTANT;
material.constant_time = 0.5;
+ legacy_facedir_simple = false;
+ legacy_wallmounted = false;
}
void ContentFeatures::serialize(std::ostream &os)
writeU8(os, post_effect_color.getGreen());
writeU8(os, post_effect_color.getBlue());
writeU8(os, param_type);
+ writeU8(os, param_type_2);
writeU8(os, is_ground_content);
writeU8(os, light_propagates);
writeU8(os, sunlight_propagates);
writeU8(os, diggable);
writeU8(os, climbable);
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);
writeU8(os, liquid_type);
os<<serializeString(liquid_alternative_flowing);
writeU32(os, damage_per_second);
selection_box.serialize(os);
material.serialize(os);
+ writeU8(os, legacy_facedir_simple);
+ writeU8(os, legacy_wallmounted);
}
void ContentFeatures::deSerialize(std::istream &is)
post_effect_color.setGreen(readU8(is));
post_effect_color.setBlue(readU8(is));
param_type = (enum ContentParamType)readU8(is);
+ param_type_2 = (enum ContentParamType2)readU8(is);
is_ground_content = readU8(is);
light_propagates = readU8(is);
sunlight_propagates = readU8(is);
diggable = readU8(is);
climbable = 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);
liquid_type = (enum LiquidType)readU8(is);
liquid_alternative_flowing = deSerializeString(is);
damage_per_second = readU32(is);
selection_box.deSerialize(is);
material.deSerialize(is);
+ legacy_facedir_simple = readU8(is);
+ legacy_wallmounted = readU8(is);
}
/*
// CONTENT_IGNORE = not found
content_t getFreeId(bool require_full_param2)
{
- // If allowed, first search in the large 4-byte-param2 pool
+ // If allowed, first search in the large 4-bit-param2 pool
if(!require_full_param2){
for(u16 i=0x800; i<=0xfff; i++){
const ContentFeatures &f = m_content_features[i];
return i;
}
}
- // Then search from the small 8-byte-param2 pool
+ // Then search from the small 8-bit-param2 pool
for(u16 i=0; i<=125; i++){
const ContentFeatures &f = m_content_features[i];
if(f.name == "")
if(!found){
// Determine if full param2 is required
bool require_full_param2 = (
- def.liquid_type == LIQUID_FLOWING
+ def.param_type_2 == CPT2_FULL
||
- def.drawtype == NDT_FLOWINGLIQUID
- ||
- def.drawtype == NDT_TORCHLIKE
- ||
- def.drawtype == NDT_SIGNLIKE
+ def.param_type_2 == CPT2_FLOWINGLIQUID
);
// Get some id
id = getFreeId(require_full_param2);
{
CPT_NONE,
CPT_LIGHT,
- CPT_MINERAL,
+};
+
+enum ContentParamType2
+{
+ CPT2_NONE,
+ // Need 8-bit param2
+ CPT2_FULL,
+ // Flowing liquid properties
+ CPT2_FLOWINGLIQUID,
// Direction for chests and furnaces and such
- CPT_FACEDIR_SIMPLE
+ CPT2_FACEDIR,
+ // Direction for signs, torches and such
+ CPT2_WALLMOUNTED,
};
enum LiquidType
{
NODEBOX_REGULAR, // Regular block; allows buildable_to
NODEBOX_FIXED, // Static separately defined box
- NODEBOX_WALLMOUNTED, // Box for wall_mounted nodes; (top, bottom, side)
+ NODEBOX_WALLMOUNTED, // Box for wall mounted nodes; (top, bottom, side)
};
struct NodeBox
video::SColor post_effect_color;
// Type of MapNode::param1
ContentParamType param_type;
+ // Type of MapNode::param2
+ ContentParamType2 param_type_2;
// True for all ground-like things like stone and mud, false for eg. trees
bool is_ground_content;
bool light_propagates;
bool climbable;
// Player can build on these
bool buildable_to;
- // If true, param2 is set to direction when placed. Used for torches.
- // NOTE: the direction format is quite inefficient and should be changed
- bool wall_mounted;
- // Inventory item string as which the node appears in inventory when dug.
- // Mineral overrides this.
- std::string dug_item;
- // Extra dug item and its rarity
- std::string extra_dug_item;
- // Usual get interval for extra dug item
- s32 extra_dug_item_rarity;
// Metadata name of node (eg. "furnace")
std::string metadata_name;
// Whether the node is non-liquid, source liquid or flowing liquid
u32 damage_per_second;
NodeBox selection_box;
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
return result;
}
+static void setintfield(lua_State *L, int table,
+ const char *fieldname, int value)
+{
+ lua_pushinteger(L, value);
+ if(table < 0)
+ table -= 1;
+ lua_setfield(L, table, fieldname);
+}
+
static void setfloatfield(lua_State *L, int table,
const char *fieldname, float value)
{
lua_setfield(L, table, fieldname);
}
+static void setboolfield(lua_State *L, int table,
+ const char *fieldname, bool value)
+{
+ lua_pushboolean(L, value);
+ if(table < 0)
+ table -= 1;
+ lua_setfield(L, table, fieldname);
+}
+
static void warn_if_field_exists(lua_State *L, int table,
const char *fieldname, const std::string &message)
{
{
{CPT_NONE, "none"},
{CPT_LIGHT, "light"},
- {CPT_MINERAL, "mineral"},
- {CPT_FACEDIR_SIMPLE, "facedir_simple"},
+ {0, NULL},
+};
+
+struct EnumString es_ContentParamType2[] =
+{
+ {CPT2_NONE, "none"},
+ {CPT2_FULL, "full"},
+ {CPT2_FLOWINGLIQUID, "flowingliquid"},
+ {CPT2_FACEDIR, "facedir"},
+ {CPT2_WALLMOUNTED, "wallmounted"},
{0, NULL},
};
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
*/
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
*/
f.param_type = (ContentParamType)getenumfield(L, index, "paramtype",
es_ContentParamType, CPT_NONE);
+ f.param_type_2 = (ContentParamType2)getenumfield(L, index, "paramtype2",
+ es_ContentParamType2, CPT2_NONE);
+
+ // Warn about some deprecated fields
+ warn_if_field_exists(L, index, "wall_mounted",
+ "deprecated: use paramtype2 = 'wallmounted'");
+ warn_if_field_exists(L, index, "light_propagates",
+ "deprecated: determined from paramtype");
+ warn_if_field_exists(L, index, "dug_item",
+ "deprecated: use '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
getboolfield(L, index, "is_ground_content", f.is_ground_content);
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);
// This is used for collision detection.
// Also for general solidness queries.
getboolfield(L, index, "climbable", f.climbable);
// Player can build on these
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")
getstringfield(L, index, "metadata_name", f.metadata_name);
// Whether the node is non-liquid, source liquid or flowing liquid
lua_getfield(L, index, "material");
if(lua_istable(L, -1)){
- f.material.diggability = (Diggability)getenumfield(L, -1, "diggability",
- es_Diggability, DIGGABLE_NORMAL);
-
- getfloatfield(L, -1, "constant_time", f.material.constant_time);
- getfloatfield(L, -1, "weight", f.material.weight);
- getfloatfield(L, -1, "crackiness", f.material.crackiness);
- getfloatfield(L, -1, "crumbliness", f.material.crumbliness);
- getfloatfield(L, -1, "cuttability", f.material.cuttability);
- getfloatfield(L, -1, "flammability", f.material.flammability);
+ f.material = read_material_properties(L, -1);
}
lua_pop(L, 1);
+ // Set to true if paramtype used to be 'facedir_simple'
+ getboolfield(L, index, "legacy_facedir_simple", f.legacy_facedir_simple);
+ // Set to true if wall_mounted used to be set to true
+ getboolfield(L, index, "legacy_wallmounted", f.legacy_wallmounted);
+
return f;
}
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 */
// set_infotext(self, text)
method(NodeMetaRef, set_text),
method(NodeMetaRef, get_text),
method(NodeMetaRef, get_owner),
+ method(NodeMetaRef, set_owner),
+ method(NodeMetaRef, get_allow_removal),
method(NodeMetaRef, set_infotext),
method(NodeMetaRef, get_inventory),
method(NodeMetaRef, set_inventory_draw_spec),
return 1;
}
+// get_digging_properties(material_properties, tool_digging_properties[, time_from_last_punch])
+static int l_get_digging_properties(lua_State *L)
+{
+ MaterialProperties mp = read_material_properties(L, 1);
+ ToolDiggingProperties tp = read_tool_digging_properties(L, 2);
+ if(lua_isnoneornil(L, 3))
+ push_digging_properties(L, getDiggingProperties(&mp, &tp));
+ else
+ push_digging_properties(L, getDiggingProperties(&mp, &tp,
+ luaL_checknumber(L, 3)));
+ return 1;
+}
+
+// get_hitting_properties(material_properties, tool_digging_properties[, time_from_last_punch])
+static int l_get_hitting_properties(lua_State *L)
+{
+ MaterialProperties mp = read_material_properties(L, 1);
+ ToolDiggingProperties tp = read_tool_digging_properties(L, 2);
+ if(lua_isnoneornil(L, 3))
+ push_hitting_properties(L, getHittingProperties(&mp, &tp));
+ else
+ push_hitting_properties(L, getHittingProperties(&mp, &tp,
+ luaL_checknumber(L, 3)));
+ return 1;
+}
+
// get_current_modname()
static int l_get_current_modname(lua_State *L)
{
{"chat_send_player", l_chat_send_player},
{"get_player_privs", l_get_player_privs},
{"get_inventory", l_get_inventory},
+ {"get_digging_properties", l_get_digging_properties},
+ {"get_hitting_properties", l_get_hitting_properties},
{"get_current_modname", l_get_current_modname},
{"get_modpath", l_get_modpath},
{NULL, NULL}
assert(lua_checkstack(L, 20));
StackUnroller stack_unroller(L);
+ dstream<<"player: "<<player<<" id: "<<player->getId()<<std::endl;
+
bool positioning_handled_by_some = false;
// Get minetest.registered_on_respawnplayers
}
/*
- item callbacks
+ item callbacks and node callbacks
*/
// Retrieves minetest.registered_items[name][callbackname]
return true;
}
-/*
- environment
-*/
-
-void scriptapi_environment_step(lua_State *L, float dtime)
+bool scriptapi_node_on_punch(lua_State *L, v3s16 pos, MapNode node,
+ ServerActiveObject *puncher)
{
realitycheck(L);
assert(lua_checkstack(L, 20));
- //infostream<<"scriptapi_environment_step"<<std::endl;
StackUnroller stack_unroller(L);
- // Get minetest.registered_globalsteps
- lua_getglobal(L, "minetest");
- lua_getfield(L, -1, "registered_globalsteps");
- luaL_checktype(L, -1, LUA_TTABLE);
- int table = lua_gettop(L);
- // Foreach
- lua_pushnil(L);
- while(lua_next(L, table) != 0){
- // key at index -2 and value at index -1
- luaL_checktype(L, -1, LUA_TFUNCTION);
- // Call function
- lua_pushnumber(L, dtime);
- if(lua_pcall(L, 1, 0, 0))
- script_error(L, "error: %s", lua_tostring(L, -1));
- // value removed, keep key for next iteration
- }
-}
+ INodeDefManager *ndef = get_server(L)->ndef();
-void scriptapi_environment_on_placenode(lua_State *L, v3s16 p, MapNode newnode,
- ServerActiveObject *placer)
-{
- realitycheck(L);
- assert(lua_checkstack(L, 20));
- //infostream<<"scriptapi_environment_on_placenode"<<std::endl;
- StackUnroller stack_unroller(L);
+ // Push callback function on stack
+ if(!get_item_callback(L, ndef->get(node).name.c_str(), "on_punch"))
+ return false;
- // Get the writable node definition manager from the server
- IWritableNodeDefManager *ndef =
- get_server(L)->getWritableNodeDefManager();
-
- // Get minetest.registered_on_placenodes
- lua_getglobal(L, "minetest");
- lua_getfield(L, -1, "registered_on_placenodes");
- luaL_checktype(L, -1, LUA_TTABLE);
- int table = lua_gettop(L);
- // Foreach
- lua_pushnil(L);
- while(lua_next(L, table) != 0){
- // key at index -2 and value at index -1
- luaL_checktype(L, -1, LUA_TFUNCTION);
- // Call function
- push_v3s16(L, p);
- pushnode(L, newnode, ndef);
- objectref_get_or_create(L, placer);
- if(lua_pcall(L, 3, 0, 0))
- script_error(L, "error: %s", lua_tostring(L, -1));
- // value removed, keep key for next iteration
- }
+ // Call function
+ push_v3s16(L, pos);
+ pushnode(L, node, ndef);
+ objectref_get_or_create(L, puncher);
+ if(lua_pcall(L, 3, 0, 0))
+ script_error(L, "error: %s", lua_tostring(L, -1));
+ return true;
}
-void scriptapi_environment_on_dignode(lua_State *L, v3s16 p, MapNode oldnode,
+bool scriptapi_node_on_dig(lua_State *L, v3s16 pos, MapNode node,
ServerActiveObject *digger)
{
realitycheck(L);
assert(lua_checkstack(L, 20));
- //infostream<<"scriptapi_environment_on_dignode"<<std::endl;
StackUnroller stack_unroller(L);
- // Get the writable node definition manager from the server
- IWritableNodeDefManager *ndef =
- get_server(L)->getWritableNodeDefManager();
-
- // Get minetest.registered_on_dignodes
- lua_getglobal(L, "minetest");
- lua_getfield(L, -1, "registered_on_dignodes");
- luaL_checktype(L, -1, LUA_TTABLE);
- int table = lua_gettop(L);
- // Foreach
- lua_pushnil(L);
- while(lua_next(L, table) != 0){
- // key at index -2 and value at index -1
- luaL_checktype(L, -1, LUA_TFUNCTION);
- // Call function
- push_v3s16(L, p);
- pushnode(L, oldnode, ndef);
- objectref_get_or_create(L, digger);
- if(lua_pcall(L, 3, 0, 0))
- script_error(L, "error: %s", lua_tostring(L, -1));
- // value removed, keep key for next iteration
- }
+ INodeDefManager *ndef = get_server(L)->ndef();
+
+ // Push callback function on stack
+ if(!get_item_callback(L, ndef->get(node).name.c_str(), "on_dig"))
+ return false;
+
+ // Call function
+ push_v3s16(L, pos);
+ pushnode(L, node, ndef);
+ objectref_get_or_create(L, digger);
+ if(lua_pcall(L, 3, 0, 0))
+ script_error(L, "error: %s", lua_tostring(L, -1));
+ return true;
}
-void scriptapi_environment_on_punchnode(lua_State *L, v3s16 p, MapNode node,
- ServerActiveObject *puncher)
+/*
+ environment
+*/
+
+void scriptapi_environment_step(lua_State *L, float dtime)
{
realitycheck(L);
assert(lua_checkstack(L, 20));
- //infostream<<"scriptapi_environment_on_punchnode"<<std::endl;
+ //infostream<<"scriptapi_environment_step"<<std::endl;
StackUnroller stack_unroller(L);
- // Get the writable node definition manager from the server
- IWritableNodeDefManager *ndef =
- get_server(L)->getWritableNodeDefManager();
-
- // Get minetest.registered_on_punchnodes
+ // Get minetest.registered_globalsteps
lua_getglobal(L, "minetest");
- lua_getfield(L, -1, "registered_on_punchnodes");
+ lua_getfield(L, -1, "registered_globalsteps");
luaL_checktype(L, -1, LUA_TTABLE);
int table = lua_gettop(L);
// Foreach
// key at index -2 and value at index -1
luaL_checktype(L, -1, LUA_TFUNCTION);
// Call function
- push_v3s16(L, p);
- pushnode(L, node, ndef);
- objectref_get_or_create(L, puncher);
- if(lua_pcall(L, 3, 0, 0))
+ lua_pushnumber(L, dtime);
+ if(lua_pcall(L, 1, 0, 0))
script_error(L, "error: %s", lua_tostring(L, -1));
// value removed, keep key for next iteration
}
/* environment */
// On environment step
void scriptapi_environment_step(lua_State *L, float dtime);
-// After adding node
-void scriptapi_environment_on_placenode(lua_State *L, v3s16 p, MapNode newnode,
- ServerActiveObject *placer);
-// After removing node
-void scriptapi_environment_on_dignode(lua_State *L, v3s16 p, MapNode oldnode,
- ServerActiveObject *digger);
-// When punching node
-void scriptapi_environment_on_punchnode(lua_State *L, v3s16 p, MapNode node,
- ServerActiveObject *puncher);
// After generating a piece of map
void scriptapi_environment_on_generated(lua_State *L, v3s16 minp, v3s16 maxp);
bool scriptapi_item_on_use(lua_State *L, ItemStack &item,
ServerActiveObject *user, const PointedThing &pointed);
+/* node callbacks */
+bool scriptapi_node_on_punch(lua_State *L, v3s16 p, MapNode node,
+ ServerActiveObject *puncher);
+bool scriptapi_node_on_dig(lua_State *L, v3s16 p, MapNode node,
+ ServerActiveObject *digger);
+
/* luaentity */
// Returns true if succesfully added into Lua; false otherwise.
bool scriptapi_luaentity_add(lua_State *L, u16 id, const char *name,
19: new content type handling
20: many existing content types translated to extended ones
21: dynamic content type allocation
+ 22: full 16-bit content types, minerals removed, facedir & wallmounted changed
*/
// This represents an uninitialized or invalid format
#define SER_FMT_VER_INVALID 255
// Highest supported serialization version
-#define SER_FMT_VER_HIGHEST 21
+#define SER_FMT_VER_HIGHEST 22
// Lowest supported serialization version
#define SER_FMT_VER_LOWEST 0
#include "constants.h"
#include "voxel.h"
#include "materials.h"
-#include "mineral.h"
#include "config.h"
#include "servercommand.h"
#include "filesys.h"
/*
Make sure the player is allowed to do it
*/
- bool interact_priv = (getPlayerPrivs(player) & PRIV_INTERACT) != 0;
- if(!interact_priv)
+ if((getPlayerPrivs(player) & PRIV_INTERACT) == 0)
{
infostream<<"Ignoring interaction from player "<<player->getName()
<<" because privileges are "<<getPlayerPrivs(player)
<<std::endl;
- // NOTE: no return; here, fall through
+ return;
}
/*
NOTE: This can be used in the future to check if
somebody is cheating, by checking the timing.
*/
- bool cannot_punch_node = !interact_priv;
-
MapNode n(CONTENT_IGNORE);
-
try
{
n = m_env->getMap().getNode(p_under);
<<std::endl;
m_emerge_queue.addBlock(peer_id,
getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
- cannot_punch_node = true;
}
-
- if(cannot_punch_node)
- return;
-
- /*
- Run script hook
- */
- scriptapi_environment_on_punchnode(m_lua, p_under, n, srp);
+ if(n.getContent() != CONTENT_IGNORE)
+ scriptapi_node_on_punch(m_lua, p_under, n, srp);
}
else if(pointed.type == POINTEDTHING_OBJECT)
{
- if(!interact_priv)
- return;
-
// Skip if object has been removed
if(pointed_object->m_removed)
return;
else if(action == 2)
{
// Only complete digging of nodes
- if(pointed.type != POINTEDTHING_NODE)
- return;
-
- // Mandatory parameter; actually used for nothing
- core::map<v3s16, MapBlock*> modified_blocks;
-
- content_t material = CONTENT_IGNORE;
- u8 mineral = MINERAL_NONE;
-
- bool cannot_remove_node = !interact_priv;
-
- MapNode n(CONTENT_IGNORE);
- try
- {
- n = m_env->getMap().getNode(p_under);
- // Get mineral
- mineral = n.getMineral(m_nodedef);
- // Get material at position
- material = n.getContent();
- // If not yet cancelled
- if(cannot_remove_node == false)
- {
- // If it's not diggable, do nothing
- if(m_nodedef->get(material).diggable == false)
- {
- infostream<<"Server: Not finishing digging: "
- <<"Node not diggable"
- <<std::endl;
- cannot_remove_node = true;
- }
- }
- // If not yet cancelled
- if(cannot_remove_node == false)
- {
- // Get node metadata
- NodeMetadata *meta = m_env->getMap().getNodeMetadata(p_under);
- if(meta && meta->nodeRemovalDisabled() == true)
- {
- infostream<<"Server: Not finishing digging: "
- <<"Node metadata disables removal"
- <<std::endl;
- cannot_remove_node = true;
- }
- }
- }
- catch(InvalidPositionException &e)
- {
- infostream<<"Server: Not finishing digging: Node not found."
- <<" Adding block to emerge queue."
- <<std::endl;
- m_emerge_queue.addBlock(peer_id,
- getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
- cannot_remove_node = true;
- }
-
- /*
- If node can't be removed, set block to be re-sent to
- client and quit.
- */
- if(cannot_remove_node)
- {
- infostream<<"Server: Not finishing digging."<<std::endl;
-
- // Client probably has wrong data.
- // Set block not sent, so that client will get
- // a valid one.
- infostream<<"Client "<<peer_id<<" tried to dig "
- <<"node; but node cannot be removed."
- <<" setting MapBlock not sent."<<std::endl;
- RemoteClient *client = getClient(peer_id);
- v3s16 blockpos = getNodeBlockPos(p_under);
- client->SetBlockNotSent(blockpos);
-
- return;
- }
-
- actionstream<<player->getName()<<" digs "<<PP(p_under)
- <<", gets material "<<(int)material<<", mineral "
- <<(int)mineral<<std::endl;
-
- /*
- Send the removal to all close-by players.
- - If other player is close, send REMOVENODE
- - Otherwise set blocks not sent
- */
- core::list<u16> far_players;
- sendRemoveNode(p_under, peer_id, &far_players, 30);
-
- /*
- Update and send inventory
- */
-
- if(g_settings->getBool("creative_mode") == false)
+ if(pointed.type == POINTEDTHING_NODE)
{
- /*
- Wear out tool
- */
- InventoryList *mlist = player->inventory.getList("main");
- if(mlist != NULL)
- {
- 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();
-
+ MapNode n(CONTENT_IGNORE);
+ try
{
- const std::string &extra_dug_s = m_nodedef->get(material).extra_dug_item;
- s32 extra_rarity = m_nodedef->get(material).extra_dug_item_rarity;
- if(extra_dug_s != "" && extra_rarity != 0
- && myrand() % extra_rarity == 0)
- {
- item.deSerialize(extra_dug_s, m_itemdef);
- }
+ n = m_env->getMap().getNode(p_under);
}
-
- if(!item.empty())
+ catch(InvalidPositionException &e)
{
- // Add a item to inventory
- player->inventory.addItem("main", item);
- srp->m_inventory_not_sent = true;
+ infostream<<"Server: Not finishing digging: Node not found."
+ <<" Adding block to emerge queue."
+ <<std::endl;
+ m_emerge_queue.addBlock(peer_id,
+ getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
}
+ if(n.getContent() != CONTENT_IGNORE)
+ scriptapi_node_on_dig(m_lua, p_under, n, srp);
}
-
- /*
- Remove the node
- (this takes some time so it is done after the quick stuff)
- */
- {
- MapEditEventIgnorer ign(&m_ignore_map_edit_events);
-
- m_env->getMap().removeNodeAndUpdate(p_under, modified_blocks);
- }
- /*
- Set blocks not sent to far players
- */
- for(core::list<u16>::Iterator
- i = far_players.begin();
- i != far_players.end(); i++)
- {
- u16 peer_id = *i;
- RemoteClient *client = getClient(peer_id);
- if(client==NULL)
- continue;
- client->SetBlocksNotSent(modified_blocks);
- }
-
- /*
- Run script hook
- */
- scriptapi_environment_on_dignode(m_lua, p_under, n, srp);
} // action == 2
/*
*/
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();
+ // 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)
{
// Right click object
if(g_settings->getBool("creative_mode") == false)
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
*/
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();
actionstream<<player->getName()<<" uses "<<item.name
*/
std::ostringstream os(std::ios_base::binary);
- block->serialize(os, ver);
+ block->serialize(os, ver, false);
std::string s = os.str();
SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
#include "porting.h"
#include "materials.h"
#include "config.h"
-#include "mineral.h"
#include "filesys.h"
#include "defaultsettings.h"
#include "settings.h"
srand(time(0));
mysrand(time(0));
- // Initialize stuff
-
- init_mineral();
-
/*
Run unit tests
*/
f.name = itemdef.name;
for(int i = 0; i < 6; i++)
f.tname_tiles[i] = "default_stone.png";
- f.param_type = CPT_MINERAL;
f.is_ground_content = true;
- f.dug_item = itemdef.name;
f.material.diggability = DIGGABLE_NORMAL;
f.material.weight = 5.0;
f.material.crackiness = 1.0;
for(int i = 2; i < 6; i++)
f.tname_tiles[i] = "default_dirt.png^default_grass_side.png";
f.is_ground_content = true;
- f.dug_item = itemdef.name;
f.material.diggability = DIGGABLE_NORMAL;
f.material.weight = 1.2;
f.material.crackiness = 0.0;
#include <ICameraSceneNode.h>
#include "log.h"
#include "mapnode.h" // For texture atlas making
-#include "mineral.h" // For texture atlas making
#include "nodedef.h" // For texture atlas making
#include "gamedef.h"
Example names:
"stone.png"
"stone.png^crack2"
- "stone.png^blit:mineral_coal.png"
- "stone.png^blit:mineral_coal.png^crack1"
+ "stone.png^mineral_coal.png"
+ "stone.png^mineral_coal.png^crack1"
- If texture specified by name is found from cache, return the
cached id.
{
std::string name = f.tname_tiles[i];
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;
- }
- }
}
}