diff options
36 files changed, 1520 insertions, 1364 deletions
diff --git a/data/builtin.lua b/data/builtin.lua index 1926d88b4..2e31c43b8 100644 --- a/data/builtin.lua +++ b/data/builtin.lua @@ -83,7 +83,7 @@ end -- 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" @@ -92,7 +92,11 @@ minetest.inventorycube = function(img1, img2, img3) .. "{" .. 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 @@ -113,31 +117,240 @@ minetest.get_pointed_thing_position = function(pointed_thing, above) 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 -- @@ -151,16 +364,18 @@ minetest.nodedef_default = { 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, @@ -172,6 +387,7 @@ minetest.nodedef_default = { 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, @@ -179,10 +395,6 @@ minetest.nodedef_default = { 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 = "", @@ -199,6 +411,8 @@ minetest.nodedef_default = { cuttability = 0, flammability = 0, }, + legacy_facedir_simple = false, + legacy_wallmounted = false, } minetest.craftitemdef_default = { @@ -369,12 +583,12 @@ function minetest.register_item(name, itemdef) 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", @@ -390,6 +604,7 @@ function minetest.register_item(name, itemdef) burntime=itemdef.furnace_burntime }) end + -- END Legacy stuff -- Disable all further modifications getmetatable(itemdef).__newindex = {} @@ -408,10 +623,11 @@ end 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 @@ -420,7 +636,7 @@ function minetest.register_tool(name, tooldef) 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 @@ -450,6 +666,7 @@ function minetest.register_tool(name, tooldef) dd_cuttability = tooldef.dd_cuttability, } end + -- END Legacy stuff minetest.register_item(name, tooldef) end @@ -643,4 +860,10 @@ minetest.registered_on_newplayers, minetest.register_on_newplayer = make_registr minetest.registered_on_dieplayers, minetest.register_on_dieplayer = make_registration() minetest.registered_on_respawnplayers, minetest.register_on_respawnplayer = make_registration() +-- +-- Set random seed +-- + +math.randomseed(os.time()) + -- END diff --git a/data/mods/default/init.lua b/data/mods/default/init.lua index 8093e99d5..7c6cccd44 100644 --- a/data/mods/default/init.lua +++ b/data/mods/default/init.lua @@ -176,6 +176,7 @@ -- - 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 @@ -302,7 +303,7 @@ -- myvariable = whatever, -- } -- --- Item definition: +-- Item definition options (register_node, register_craftitem, register_tool) -- { -- description = "Steel Axe", -- inventory_image = "default_tool_steelaxe.png", @@ -328,9 +329,9 @@ -- 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"}, @@ -341,6 +342,7 @@ -- alpha = 255, -- post_effect_color = {a=0, r=0, g=0, b=0}, -- paramtype = "none", +-- paramtype2 = "none", -- is_ground_content = false, -- sunlight_propagates = false, -- walkable = true, @@ -348,10 +350,8 @@ -- 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 = "", @@ -368,23 +368,10 @@ -- 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', @@ -1111,10 +1098,26 @@ minetest.register_craft({ 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", { @@ -1122,7 +1125,7 @@ minetest.register_node("default:dirt_with_grass", { tile_images = {"default_grass.png", "default_dirt.png", "default_dirt.png^default_grass_side.png"}, 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", { @@ -1130,7 +1133,7 @@ minetest.register_node("default:dirt_with_grass_footsteps", { tile_images = {"default_grass_footsteps.png", "default_dirt.png", "default_dirt.png^default_grass_side.png"}, is_ground_content = true, material = minetest.digprop_dirtlike(1.0), - dug_item = 'node "default:dirt" 1', + drop = 'default:dirt', }) minetest.register_node("default:dirt", { @@ -1159,7 +1162,7 @@ minetest.register_node("default:sandstone", { 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", { @@ -1167,7 +1170,7 @@ 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", { @@ -1175,7 +1178,7 @@ 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", { @@ -1211,8 +1214,21 @@ minetest.register_node("default:leaves", { 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", { @@ -1290,8 +1306,8 @@ minetest.register_node("default:ladder", { 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 = { @@ -1301,6 +1317,7 @@ minetest.register_node("default:ladder", { --wall_side = = <default> }, material = minetest.digprop_woodlike(0.5), + legacy_wallmounted = true, }) minetest.register_node("default:wood", { @@ -1420,9 +1437,9 @@ minetest.register_node("default:torch", { 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", @@ -1431,6 +1448,7 @@ minetest.register_node("default:torch", { wall_side = {-0.5, -0.3, -0.1, -0.5+0.3, 0.3, 0.1}, }, material = minetest.digprop_constanttime(0.0), + legacy_wallmounted = true, }) minetest.register_node("default:sign_wall", { @@ -1440,9 +1458,9 @@ 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", @@ -1451,33 +1469,37 @@ minetest.register_node("default:sign_wall", { --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", { @@ -1506,8 +1528,9 @@ minetest.register_node("default:nyancat", { tile_images = {"default_nc_side.png", "default_nc_side.png", "default_nc_side.png", "default_nc_side.png", "default_nc_back.png", "default_nc_front.png"}, inventory_image = "default_nc_front.png", - paramtype = "facedir_simple", + paramtype2 = "facedir", material = minetest.digprop_stonelike(3.0), + legacy_facedir_simple = true, }) minetest.register_node("default:nyancat_rainbow", { diff --git a/data/mods/legacy/textures/mineral_coal.png b/data/mods/default/textures/default_mineral_coal.png Binary files differindex 3ff9692fb..3ff9692fb 100644 --- a/data/mods/legacy/textures/mineral_coal.png +++ b/data/mods/default/textures/default_mineral_coal.png diff --git a/data/mods/legacy/textures/mineral_iron.png b/data/mods/default/textures/default_mineral_iron.png Binary files differindex 51b15d95d..51b15d95d 100644 --- a/data/mods/legacy/textures/mineral_iron.png +++ b/data/mods/default/textures/default_mineral_iron.png diff --git a/data/mods/legacy/init.lua b/data/mods/legacy/init.lua index 127b0e17f..7f9088ce0 100644 --- a/data/mods/legacy/init.lua +++ b/data/mods/legacy/init.lua @@ -6,6 +6,8 @@ -- 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") diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e82e26dc7..ee02d66f0 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -115,7 +115,6 @@ set(common_SRCS nodemetadata.cpp serverobject.cpp noise.cpp - mineral.cpp porting.cpp materials.cpp defaultsettings.cpp diff --git a/src/client.cpp b/src/client.cpp index feb8a3a1e..602f0cf84 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -899,7 +899,7 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id) Update an existing block */ //infostream<<"Updating"<<std::endl; - block->deSerialize(istr, ser_version); + block->deSerialize(istr, ser_version, false); } else { @@ -908,7 +908,7 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id) */ //infostream<<"Creating new"<<std::endl; block = new MapBlock(&m_env.getMap(), p, this); - block->deSerialize(istr, ser_version); + block->deSerialize(istr, ser_version, false); sector->insertBlock(block); } @@ -1816,8 +1816,7 @@ void Client::addNode(v3s16 p, MapNode n) try { //TimeTaker timer3("Client::addNode(): addNodeAndUpdate"); - std::string st = std::string(""); - m_env.getMap().addNodeAndUpdate(p, n, modified_blocks, st); + m_env.getMap().addNodeAndUpdate(p, n, modified_blocks); } catch(InvalidPositionException &e) {} diff --git a/src/content_mapblock.cpp b/src/content_mapblock.cpp index 79f49cbf8..dc1e1daed 100644 --- a/src/content_mapblock.cpp +++ b/src/content_mapblock.cpp @@ -85,15 +85,15 @@ void makeCuboid(MeshCollector *collector, const aabb3f &box, video::S3DVertex(min.X,min.Y,min.Z, -1,0,0, c, txc[14],txc[15]), video::S3DVertex(min.X,min.Y,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++) @@ -602,7 +602,7 @@ void mapblock_mesh_generate_special(MeshMakeData *data, break; case NDT_TORCHLIKE: { - v3s16 dir = unpackDir(n.param2); + v3s16 dir = n.getWallMountedDir(nodedef); AtlasPointer ap(0); if(dir == v3s16(0,-1,0)){ @@ -694,7 +694,7 @@ void mapblock_mesh_generate_special(MeshMakeData *data, ap.x0(), ap.y1()), }; - v3s16 dir = unpackDir(n.param2); + v3s16 dir = n.getWallMountedDir(nodedef); for(s32 i=0; i<4; i++) { diff --git a/src/content_mapnode.cpp b/src/content_mapnode.cpp index 4701736cf..ce7ee593f 100644 --- a/src/content_mapnode.cpp +++ b/src/content_mapnode.cpp @@ -31,7 +31,7 @@ with this program; if not, write to the Free Software Foundation, Inc., 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 diff --git a/src/environment.cpp b/src/environment.cpp index 3a294086c..7c2aef272 100644 --- a/src/environment.cpp +++ b/src/environment.cpp @@ -2057,7 +2057,9 @@ void ClientEnvironment::step(float dtime) MapNode n = m_map->getNode(p); light = n.getLightBlend(getDayNightRatio(), m_gamedef->ndef()); } - catch(InvalidPositionException &e) {} + catch(InvalidPositionException &e){ + light = blend_light(getDayNightRatio(), LIGHT_SUN, 0); + } player->updateLight(light); /* @@ -2104,7 +2106,6 @@ void ClientEnvironment::step(float dtime) if(m_active_object_light_update_interval.step(dtime, 0.21)) { // Update lighting - //u8 light = LIGHT_MAX; u8 light = 0; try{ // Get node at head @@ -2112,7 +2113,9 @@ void ClientEnvironment::step(float dtime) MapNode n = m_map->getNode(p); light = n.getLightBlend(getDayNightRatio(), m_gamedef->ndef()); } - catch(InvalidPositionException &e) {} + catch(InvalidPositionException &e){ + light = blend_light(getDayNightRatio(), LIGHT_SUN, 0); + } obj->updateLight(light); } } @@ -2203,7 +2206,9 @@ u16 ClientEnvironment::addActiveObject(ClientActiveObject *object) MapNode n = m_map->getNode(p); light = n.getLightBlend(getDayNightRatio(), m_gamedef->ndef()); } - catch(InvalidPositionException &e) {} + catch(InvalidPositionException &e){ + light = blend_light(getDayNightRatio(), LIGHT_SUN, 0); + } object->updateLight(light); } return object->getId(); diff --git a/src/game.cpp b/src/game.cpp index 7bd5d9587..055320a8e 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -303,6 +303,8 @@ PointedThing getPointedThing(Client *client, v3f player_position, should_show_hilightbox = false; selected_object = NULL; + INodeDefManager *nodedef = client->getNodeDefManager(); + // First try to find a pointed at active object if(look_for_object) { @@ -378,7 +380,7 @@ PointedThing getPointedThing(Client *client, v3f player_position, v3s16(-1,0,0), // left }; - const ContentFeatures &f = client->getNodeDefManager()->get(n); + const ContentFeatures &f = nodedef->get(n); if(f.selection_box.type == NODEBOX_FIXED) { @@ -447,7 +449,7 @@ PointedThing getPointedThing(Client *client, v3f player_position, } else if(f.selection_box.type == NODEBOX_WALLMOUNTED) { - v3s16 dir = unpackDir(n.param2); + v3s16 dir = n.getWallMountedDir(nodedef); v3f dir_f = v3f(dir.X, dir.Y, dir.Z); dir_f *= BS/2 - BS/6 - BS/20; v3f cpf = npf + dir_f; @@ -1827,11 +1829,10 @@ void the_game( MapNode n = client.getNode(nodepos); // Get digging properties for material and tool - content_t material = n.getContent(); + MaterialProperties mp = nodedef->get(n.getContent()).material; ToolDiggingProperties tp = playeritem.getToolDiggingProperties(itemdef); - DiggingProperties prop = - getDiggingProperties(material, &tp, nodedef); + DiggingProperties prop = getDiggingProperties(&mp, &tp); float dig_time_complete = 0.0; diff --git a/src/gamedef.h b/src/gamedef.h index 8df6988ad..10ab0b0bc 100644 --- a/src/gamedef.h +++ b/src/gamedef.h @@ -26,7 +26,6 @@ with this program; if not, write to the Free Software Foundation, Inc., class IItemDefManager; class INodeDefManager; class ICraftDefManager; -// Mineral too? class ITextureSource; /* diff --git a/src/light.h b/src/light.h index c1af7fa62..238acce43 100644 --- a/src/light.h +++ b/src/light.h @@ -75,16 +75,27 @@ inline u8 undiminish_light(u8 light) extern u8 light_decode_table[LIGHT_MAX+1]; +// 0 <= light <= LIGHT_SUN +// 0 <= return value <= 255 inline u8 decode_light(u8 light) { - if(light == LIGHT_SUN) - return light_decode_table[LIGHT_MAX]; - if(light > LIGHT_MAX) light = LIGHT_MAX; return light_decode_table[light]; } +// 0 <= daylight_factor <= 1000 +// 0 <= lightday, lightnight <= LIGHT_SUN +// 0 <= return value <= LIGHT_SUN +inline u8 blend_light(u32 daylight_factor, u8 lightday, u8 lightnight) +{ + u32 c = 1000; + u32 l = ((daylight_factor * lightday + (c-daylight_factor) * lightnight))/c; + if(l > LIGHT_SUN) + l = LIGHT_SUN; + return l; +} + #endif diff --git a/src/main.cpp b/src/main.cpp index b7c3ceffe..6cb9cf984 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -54,24 +54,6 @@ A list of "active blocks" in which stuff happens. (+=done) + This was left to be done by the old system and it sends only the nearest ones. -Vim conversion regexpes for moving to extended content type storage: -%s/\(\.\|->\)d \([!=]=\)/\1getContent() \2/g -%s/content_features(\([^.]*\)\.d)/content_features(\1)/g -%s/\(\.\|->\)d = \([^;]*\);/\1setContent(\2);/g -%s/\(getNodeNoExNoEmerge([^)]*)\)\.d/\1.getContent()/g -%s/\(getNodeNoExNoEmerge(.*)\)\.d/\1.getContent()/g -%s/\.d;/.getContent();/g -%s/\(content_liquid\|content_flowing_liquid\|make_liquid_flowing\|content_pointable\)(\([^.]*\).d)/\1(\2.getContent())/g -Other things to note: -- node.d = node.param0 (only in raw serialization; use getContent() otherwise) -- node.param = node.param1 -- node.dir = node.param2 -- content_walkable(node.d) etc should be changed to - content_features(node).walkable etc -- Also check for lines that store the result of getContent to a 8-bit - variable and fix them (result of getContent() must be stored in - content_t, which is 16-bit) - NOTE: Seeds in 1260:6c77e7dbfd29: 5721858502589302589: Spawns you on a small sand island with a surface dungeon @@ -351,8 +333,6 @@ TODO: Block cube placement around player's head TODO: Protocol version field TODO: Think about using same bits for material for fences and doors, for example -TODO: Move mineral to param2, increment map serialization version, add - conversion SUGG: Restart irrlicht completely when coming back to main menu from game. - This gets rid of everything that is stored in irrlicht's caches. @@ -419,7 +399,6 @@ Doing currently: #include "filesys.h" #include "config.h" #include "guiMainMenu.h" -#include "mineral.h" #include "materials.h" #include "game.h" #include "keycode.h" @@ -1261,16 +1240,6 @@ int main(int argc, char *argv[]) mysrand(time(0)); /* - Pre-initialize some stuff with a dummy irrlicht wrapper. - - These are needed for unit tests at least. - */ - - // Must be called before texturesource is created - // (for texture atlas making) - init_mineral(); - - /* Run unit tests */ diff --git a/src/map.cpp b/src/map.cpp index 8bdc2ad4c..31c0c958b 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -915,7 +915,7 @@ void Map::updateLighting(core::map<v3s16, MapBlock*> & a_blocks, /* */ void Map::addNodeAndUpdate(v3s16 p, MapNode n, - core::map<v3s16, MapBlock*> &modified_blocks, std::string &player_name) + core::map<v3s16, MapBlock*> &modified_blocks) { INodeDefManager *nodemgr = m_gamedef->ndef(); @@ -1010,9 +1010,6 @@ void Map::addNodeAndUpdate(v3s16 p, MapNode n, if(!meta){ errorstream<<"Failed to create node metadata \"" <<metadata_name<<"\""<<std::endl; - } else { - meta->setOwner(player_name); - setNodeMetadata(p, meta); } } @@ -1291,8 +1288,7 @@ bool Map::addNodeWithEvent(v3s16 p, MapNode n) bool succeeded = true; try{ core::map<v3s16, MapBlock*> modified_blocks; - std::string st = std::string(""); - addNodeAndUpdate(p, n, modified_blocks, st); + addNodeAndUpdate(p, n, modified_blocks); // Copy modified_blocks to event for(core::map<v3s16, MapBlock*>::Iterator @@ -3271,10 +3267,7 @@ void ServerMap::saveBlock(MapBlock *block) o.write((char*)&version, 1); // Write basic data - block->serialize(o, version); - - // Write extra data stored on disk - block->serializeDiskExtra(o, version); + block->serialize(o, version, true); // Write block to database @@ -3336,11 +3329,8 @@ void ServerMap::loadBlock(std::string sectordir, std::string blockfile, MapSecto } // Read basic data - block->deSerialize(is, version); + block->deSerialize(is, version, true); - // Read extra data stored on disk - block->deSerializeDiskExtra(is, version); - // If it's a new block, insert it to the map if(created_new) sector->insertBlock(block); @@ -3406,10 +3396,7 @@ void ServerMap::loadBlock(std::string *blob, v3s16 p3d, MapSector *sector, bool } // Read basic data - block->deSerialize(is, version); - - // Read extra data stored on disk - block->deSerializeDiskExtra(is, version); + block->deSerialize(is, version, true); // If it's a new block, insert it to the map if(created_new) @@ -212,7 +212,7 @@ public: These handle lighting but not faces. */ void addNodeAndUpdate(v3s16 p, MapNode n, - core::map<v3s16, MapBlock*> &modified_blocks, std::string &player_name); + core::map<v3s16, MapBlock*> &modified_blocks); void removeNodeAndUpdate(v3s16 p, core::map<v3s16, MapBlock*> &modified_blocks); diff --git a/src/mapblock.cpp b/src/mapblock.cpp index 73c13caca..fb3bbf7a7 100644 --- a/src/mapblock.cpp +++ b/src/mapblock.cpp @@ -507,25 +507,41 @@ s16 MapBlock::getGroundLevel(v2s16 p2d) /* Serialization */ - // List relevant id-name pairs for ids in the block using nodedef -static void getBlockNodeIdMapping(NameIdMapping *nimap, MapBlock *block, +// Renumbers the content IDs (starting at 0 and incrementing +static void getBlockNodeIdMapping(NameIdMapping *nimap, MapNode *nodes, INodeDefManager *nodedef) { + std::map<content_t, content_t> mapping; std::set<content_t> unknown_contents; - for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++) - for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++) - for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++) + content_t id_counter = 0; + for(u32 i=0; i<MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE; i++) { - v3s16 p(x0,y0,z0); - MapNode n = block->getNode(p); - content_t id = n.getContent(); - const ContentFeatures &f = nodedef->get(id); - const std::string &name = f.name; - if(name == "") - unknown_contents.insert(id); + content_t global_id = nodes[i].getContent(); + content_t id = CONTENT_IGNORE; + + // Try to find an existing mapping + std::map<content_t, content_t>::iterator j = mapping.find(global_id); + if(j != mapping.end()) + { + id = j->second; + } else - nimap->set(id, name); + { + // We have to assign a new mapping + id = id_counter++; + mapping.insert(std::make_pair(global_id, id)); + + const ContentFeatures &f = nodedef->get(global_id); + const std::string &name = f.name; + if(name == "") + unknown_contents.insert(global_id); + else + nimap->set(id, name); + } + + // Update the MapNode + nodes[i].setContent(id); } for(std::set<content_t>::const_iterator i = unknown_contents.begin(); @@ -537,7 +553,7 @@ static void getBlockNodeIdMapping(NameIdMapping *nimap, MapBlock *block, // Correct ids in the block to match nodedef based on names. // Unknown ones are added to nodedef. // Will not update itself to match id-name pairs in nodedef. -void correctBlockNodeIds(const NameIdMapping *nimap, MapBlock *block, +static void correctBlockNodeIds(const NameIdMapping *nimap, MapNode *nodes, IGameDef *gamedef) { INodeDefManager *nodedef = gamedef->ndef(); @@ -547,13 +563,9 @@ void correctBlockNodeIds(const NameIdMapping *nimap, MapBlock *block, // correct ids. std::set<content_t> unnamed_contents; std::set<std::string> unallocatable_contents; - for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++) - for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++) - for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++) + for(u32 i=0; i<MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE; i++) { - v3s16 p(x0,y0,z0); - MapNode n = block->getNode(p); - content_t local_id = n.getContent(); + content_t local_id = nodes[i].getContent(); std::string name; bool found = nimap->getName(local_id, name); if(!found){ @@ -569,8 +581,7 @@ void correctBlockNodeIds(const NameIdMapping *nimap, MapBlock *block, continue; } } - n.setContent(global_id); - block->setNode(p, n); + nodes[i].setContent(global_id); } for(std::set<content_t>::const_iterator i = unnamed_contents.begin(); @@ -588,7 +599,7 @@ void correctBlockNodeIds(const NameIdMapping *nimap, MapBlock *block, } } -void MapBlock::serialize(std::ostream &os, u8 version) +void MapBlock::serialize(std::ostream &os, u8 version, bool disk) { if(!ser_ver_supported(version)) throw VersionMismatchException("ERROR: MapBlock format not supported"); @@ -598,22 +609,226 @@ void MapBlock::serialize(std::ostream &os, u8 version) throw SerializationError("ERROR: Not writing dummy block."); } - // 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) { @@ -623,15 +838,13 @@ void MapBlock::serialize(std::ostream &os, u8 version) */ // First byte - os.write((char*)&is_underground, 1); - - u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE; + writeU8(os, is_underground); // Get and compress materials SharedBuffer<u8> materialdata(nodecount); for(u32 i=0; i<nodecount; i++) { - materialdata[i] = data[i].param0; + materialdata[i] = databuf_nodelist[i*ser_length]; } compress(materialdata, os, version); @@ -639,7 +852,7 @@ void MapBlock::serialize(std::ostream &os, u8 version) SharedBuffer<u8> lightdata(nodecount); for(u32 i=0; i<nodecount; i++) { - lightdata[i] = data[i].param1; + lightdata[i] = databuf_nodelist[i*ser_length+1]; } compress(lightdata, os, version); @@ -649,7 +862,7 @@ void MapBlock::serialize(std::ostream &os, u8 version) SharedBuffer<u8> param2data(nodecount); for(u32 i=0; i<nodecount; i++) { - param2data[i] = data[i].param2; + param2data[i] = databuf_nodelist[i*ser_length+2]; } compress(param2data, os, version); } @@ -670,28 +883,19 @@ void MapBlock::serialize(std::ostream &os, u8 version) if(m_generated == false) flags |= 0x08; } - os.write((char*)&flags, 1); + writeU8(os, flags); - u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE; - /* Get data */ - // Serialize nodes - SharedBuffer<u8> databuf_nodelist(nodecount*3); - for(u32 i=0; i<nodecount; i++) - { - data[i].serialize(&databuf_nodelist[i*3], version); - } - // Create buffer with different parameters sorted SharedBuffer<u8> databuf(nodecount*3); for(u32 i=0; i<nodecount; i++) { - databuf[i] = databuf_nodelist[i*3]; - databuf[i+nodecount] = databuf_nodelist[i*3+1]; - databuf[i+nodecount*2] = databuf_nodelist[i*3+2]; + databuf[i] = databuf_nodelist[i*ser_length]; + databuf[i+nodecount] = databuf_nodelist[i*ser_length+1]; + databuf[i+nodecount*2] = databuf_nodelist[i*ser_length+2]; } /* @@ -728,50 +932,69 @@ void MapBlock::serialize(std::ostream &os, u8 version) } } } -} -void MapBlock::deSerialize(std::istream &is, u8 version) -{ - if(!ser_ver_supported(version)) - throw VersionMismatchException("ERROR: MapBlock format not supported"); - // These have no lighting info - if(version <= 1) + if(disk) { - setLightingExpired(true); - } + // Versions up from 9 have block objects. (DEPRECATED) + if(version >= 9) + { + // count=0 + writeU16(os, 0); + } - // These have no "generated" field - if(version < 18) - { - m_generated = true; + // Versions up from 15 have static objects. + if(version >= 15) + { + m_static_objects.serialize(os); + } + + // Timestamp + if(version >= 17) + { + writeU32(os, getTimestamp()); + } + + // Scan and write node definition id mapping + if(version >= 21) + { + NameIdMapping nimap; + getBlockNodeIdMapping_pre22(&nimap, data, m_gamedef->ndef()); + nimap.serialize(os); + } } +} + +void MapBlock::deSerialize_pre22(std::istream &is, u8 version, bool disk) +{ + u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE; + + // Initialize default flags + is_underground = false; + m_day_night_differs = false; + m_lighting_expired = false; + m_generated = true; + + // Make a temporary buffer + u32 ser_length = MapNode::serializedLength(version); + SharedBuffer<u8> databuf_nodelist(nodecount * ser_length); // These have no compression if(version <= 3 || version == 5 || version == 6) { - u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE; char tmp; is.read(&tmp, 1); if(is.gcount() != 1) throw SerializationError ("MapBlock::deSerialize: no enough input data"); is_underground = tmp; - for(u32 i=0; i<nodecount; i++) - { - s32 len = MapNode::serializedLength(version); - SharedBuffer<u8> d(len); - is.read((char*)*d, len); - if(is.gcount() != len) - throw SerializationError - ("MapBlock::deSerialize: no enough input data"); - data[i].deSerialize(*d, version); - } + is.read((char*)*databuf_nodelist, nodecount * ser_length); + if(is.gcount() != nodecount * ser_length) + throw SerializationError + ("MapBlock::deSerialize: no enough input data"); } else if(version <= 10) { - u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE; - u8 t8; is.read((char*)&t8, 1); is_underground = t8; @@ -786,7 +1009,7 @@ void MapBlock::deSerialize(std::istream &is, u8 version) ("MapBlock::deSerialize: invalid format"); for(u32 i=0; i<s.size(); i++) { - data[i].param0 = s[i]; + databuf_nodelist[i*ser_length] = s[i]; } } { @@ -799,7 +1022,7 @@ void MapBlock::deSerialize(std::istream &is, u8 version) ("MapBlock::deSerialize: invalid format"); for(u32 i=0; i<s.size(); i++) { - data[i].param1 = s[i]; + databuf_nodelist[i*ser_length + 1] = s[i]; } } @@ -814,15 +1037,13 @@ void MapBlock::deSerialize(std::istream &is, u8 version) ("MapBlock::deSerialize: invalid format"); for(u32 i=0; i<s.size(); i++) { - data[i].param2 = s[i]; + databuf_nodelist[i*ser_length + 2] = s[i]; } } } // All other versions (newest) else { - u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE; - u8 flags; is.read((char*)&flags, 1); is_underground = (flags & 0x01) ? true : false; @@ -843,11 +1064,9 @@ void MapBlock::deSerialize(std::istream &is, u8 version) // deserialize nodes from buffer for(u32 i=0; i<nodecount; i++) { - u8 buf[3]; - buf[0] = s[i]; - buf[1] = s[i+nodecount]; - buf[2] = s[i+nodecount*2]; - data[i].deSerialize(buf, version); + databuf_nodelist[i*ser_length] = s[i]; + databuf_nodelist[i*ser_length + 1] = s[i+nodecount]; + databuf_nodelist[i*ser_length + 2] = s[i+nodecount*2]; } /* @@ -879,76 +1098,102 @@ void MapBlock::deSerialize(std::istream &is, u8 version) } } } -} -void MapBlock::serializeDiskExtra(std::ostream &os, u8 version) -{ - // Versions up from 9 have block objects. (DEPRECATED) - if(version >= 9) + // Deserialize node data + for(u32 i=0; i<nodecount; i++) { - // count=0 - writeU16(os, 0); - } - - // Versions up from 15 have static objects. - if(version >= 15) - { - m_static_objects.serialize(os); + data[i].deSerialize(&databuf_nodelist[i*ser_length], version); } - // Timestamp - if(version >= 17) + if(disk) { - writeU32(os, getTimestamp()); - } + /* + Versions up from 9 have block objects. (DEPRECATED) + */ + if(version >= 9){ + u16 count = readU16(is); + // Not supported and length not known if count is not 0 + if(count != 0){ + errorstream<<"WARNING: MapBlock::deSerialize_pre22(): " + <<"Ignoring stuff coming at and after MBOs"<<std::endl; + return; + } + } + + /* + Versions up from 15 have static objects. + */ + if(version >= 15) + m_static_objects.deSerialize(is); + + // Timestamp + if(version >= 17){ + setTimestamp(readU32(is)); + m_disk_timestamp = m_timestamp; + } else { + setTimestamp(BLOCK_TIMESTAMP_UNDEFINED); + } - // Scan and write node definition id mapping - if(version >= 21){ + // Dynamically re-set ids based on node names NameIdMapping nimap; - getBlockNodeIdMapping(&nimap, this, m_gamedef->ndef()); - nimap.serialize(os); + // If supported, read node definition id mapping + if(version >= 21){ + nimap.deSerialize(is); + // Else set the legacy mapping + } else { + content_mapnode_get_name_id_mapping(&nimap); + } + correctBlockNodeIds(&nimap, data, m_gamedef); } -} -void MapBlock::deSerializeDiskExtra(std::istream &is, u8 version) -{ - /* - Versions up from 9 have block objects. (DEPRECATED) - */ - if(version >= 9){ - u16 count = readU16(is); - // Not supported and length not known if count is not 0 - if(count != 0){ - errorstream<<"WARNING: MapBlock::deSerializeDiskExtra(): " - <<"Ignoring stuff coming at and after MBOs"<<std::endl; - return; + + // Legacy data changes + // This code has to convert from pre-22 to post-22 format. + INodeDefManager *nodedef = m_gamedef->ndef(); + for(u32 i=0; i<nodecount; i++) + { + const ContentFeatures &f = nodedef->get(data[i].getContent()); + // Mineral + if(nodedef->getId("default:stone") == data[i].getContent() + && data[i].getParam1() == 1) + { + //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); } /* diff --git a/src/mapblock.h b/src/mapblock.h index f2d94753c..c9ff36679 100644 --- a/src/mapblock.h +++ b/src/mapblock.h @@ -363,17 +363,8 @@ public: Graphics-related methods */ - /*// A quick version with nodes passed as parameters - u8 getFaceLight(u32 daynight_ratio, MapNode n, MapNode n2, - v3s16 face_dir);*/ - /*// A more convenient version - u8 getFaceLight(u32 daynight_ratio, v3s16 p, v3s16 face_dir) - { - return getFaceLight(daynight_ratio, - getNodeParentNoEx(p), - getNodeParentNoEx(p + face_dir), - face_dir); - }*/ +#ifndef SERVER // Only on client + u8 getFaceLight2(u32 daynight_ratio, v3s16 p, v3s16 face_dir, INodeDefManager *nodemgr) { @@ -383,8 +374,6 @@ public: face_dir, nodemgr); } -#ifndef SERVER // Only on client - #if 1 /* Thread-safely updates the whole mesh of the mapblock. @@ -524,20 +513,20 @@ public: */ // These don't write or read version by itself - void serialize(std::ostream &os, u8 version); - void deSerialize(std::istream &is, u8 version); - - // Used after the basic ones when writing on disk (serverside) - void serializeDiskExtra(std::ostream &os, u8 version); - // In addition to doing other things, will add unknown blocks from - // id-name mapping to wndef - void deSerializeDiskExtra(std::istream &is, u8 version); + // Set disk to true for on-disk format, false for over-the-network format + void serialize(std::ostream &os, u8 version, bool disk); + // If disk == true: In addition to doing other things, will add + // unknown blocks from id-name mapping to wndef + void deSerialize(std::istream &is, u8 version, bool disk); private: /* Private methods */ + void serialize_pre22(std::ostream &os, u8 version, bool disk); + void deSerialize_pre22(std::istream &is, u8 version, bool disk); + /* Used only internally, because changes can't be tracked */ diff --git a/src/mapblock_mesh.cpp b/src/mapblock_mesh.cpp index db9057e19..b843448c4 100644 --- a/src/mapblock_mesh.cpp +++ b/src/mapblock_mesh.cpp @@ -27,7 +27,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #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) { @@ -282,59 +281,37 @@ static void makeFastFace(TileSpec tile, u8 li0, u8 li1, u8 li2, u8 li3, v3f p, dest.push_back(face); } -static TileSpec getTile(const MapNode &node, v3s16 dir, - ITextureSource *tsrc, INodeDefManager *nodemgr) +static TileSpec getTile(const MapNode &node, v3s16 dir, INodeDefManager *nodemgr) { - const ContentFeatures &f = nodemgr->get(node); + // 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]]; } /* @@ -345,7 +322,7 @@ TileSpec getNodeTile(MapNode mn, v3s16 p, v3s16 face_dir, NodeModMap *temp_mods, ITextureSource *tsrc, INodeDefManager *ndef) { TileSpec spec; - spec = getTile(mn, face_dir, tsrc, ndef); + spec = getTile(mn, face_dir, ndef); /* Check temporary modifications on this node @@ -363,7 +340,7 @@ TileSpec getNodeTile(MapNode mn, v3s16 p, v3s16 face_dir, 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) diff --git a/src/mapgen.cpp b/src/mapgen.cpp index c2256cedb..fe2ce13f5 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -22,7 +22,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "noise.h" #include "mapblock.h" #include "map.h" -#include "mineral.h" //#include "serverobject.h" #include "content_sao.h" #include "nodedef.h" @@ -1652,15 +1651,20 @@ void make_block(BlockMakeData *data) MapNode n_##name(c_##name); CONTENT_VARIABLE(ndef, stone); - CONTENT_VARIABLE(ndef, water_source); CONTENT_VARIABLE(ndef, air); + CONTENT_VARIABLE(ndef, water_source); CONTENT_VARIABLE(ndef, dirt); CONTENT_VARIABLE(ndef, sand); CONTENT_VARIABLE(ndef, gravel); + CONTENT_VARIABLE(ndef, clay); CONTENT_VARIABLE(ndef, lava_source); CONTENT_VARIABLE(ndef, cobble); CONTENT_VARIABLE(ndef, mossycobble); CONTENT_VARIABLE(ndef, dirt_with_grass); + CONTENT_VARIABLE(ndef, junglegrass); + CONTENT_VARIABLE(ndef, stone_with_coal); + CONTENT_VARIABLE(ndef, stone_with_iron); + CONTENT_VARIABLE(ndef, mese); /* Make base ground level @@ -1703,139 +1707,6 @@ void make_block(BlockMakeData *data) } /* - Add minerals - */ - - { - PseudoRandom mineralrandom(blockseed); - - /* - Add meseblocks - */ - for(s16 i=0; i<approx_ground_depth/4; i++) - { - if(mineralrandom.next()%50 == 0) - { - s16 x = mineralrandom.range(node_min.X+1, node_max.X-1); - s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1); - s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1); - for(u16 i=0; i<27; i++) - { - v3s16 p = v3s16(x,y,z) + g_27dirs[i]; - u32 vi = vmanip.m_area.index(p); - if(vmanip.m_data[vi].getContent() == c_stone) - if(mineralrandom.next()%8 == 0) - vmanip.m_data[vi] = MapNode(LEGN(ndef, "CONTENT_MESE")); - } - - } - } - /* - Add others - */ - { - u16 a = mineralrandom.range(0,15); - a = a*a*a; - u16 amount = 20 * a/1000; - for(s16 i=0; i<amount; i++) - { - s16 x = mineralrandom.range(node_min.X+1, node_max.X-1); - s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1); - s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1); - - u8 base_content = LEGN(ndef, "CONTENT_STONE"); - MapNode new_content(CONTENT_IGNORE); - u32 sparseness = 6; - - if(noisebuf_ground_crumbleness.get(x,y+5,z) < -0.1) - { - new_content = MapNode(LEGN(ndef, "CONTENT_STONE"), MINERAL_COAL); - } - else - { - if(noisebuf_ground_wetness.get(x,y+5,z) > 0.0) - new_content = MapNode(LEGN(ndef, "CONTENT_STONE"), MINERAL_IRON); - /*if(noisebuf_ground_wetness.get(x,y,z) > 0.0) - vmanip.m_data[i] = MapNode(LEGN(ndef, "CONTENT_MUD")); - else - vmanip.m_data[i] = MapNode(LEGN(ndef, "CONTENT_SAND"));*/ - } - /*else if(noisebuf_ground_crumbleness.get(x,y,z) > 0.1) - { - }*/ - - if(new_content.getContent() != CONTENT_IGNORE) - { - for(u16 i=0; i<27; i++) - { - v3s16 p = v3s16(x,y,z) + g_27dirs[i]; - u32 vi = vmanip.m_area.index(p); - if(vmanip.m_data[vi].getContent() == base_content) - { - if(mineralrandom.next()%sparseness == 0) - vmanip.m_data[vi] = new_content; - } - } - } - } - } - /* - Add coal - */ - //for(s16 i=0; i < MYMAX(0, 50 - abs(node_min.Y+8 - (-30))); i++) - //for(s16 i=0; i<50; i++) - u16 coal_amount = 30; - u16 coal_rareness = 60 / coal_amount; - if(coal_rareness == 0) - coal_rareness = 1; - if(mineralrandom.next()%coal_rareness == 0) - { - u16 a = mineralrandom.next() % 16; - u16 amount = coal_amount * a*a*a / 1000; - for(s16 i=0; i<amount; i++) - { - s16 x = mineralrandom.range(node_min.X+1, node_max.X-1); - s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1); - s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1); - for(u16 i=0; i<27; i++) - { - v3s16 p = v3s16(x,y,z) + g_27dirs[i]; - u32 vi = vmanip.m_area.index(p); - if(vmanip.m_data[vi].getContent() == c_stone) - if(mineralrandom.next()%8 == 0) - vmanip.m_data[vi] = MapNode(LEGN(ndef, "CONTENT_STONE"), MINERAL_COAL); - } - } - } - /* - Add iron - */ - u16 iron_amount = 8; - u16 iron_rareness = 60 / iron_amount; - if(iron_rareness == 0) - iron_rareness = 1; - if(mineralrandom.next()%iron_rareness == 0) - { - u16 a = mineralrandom.next() % 16; - u16 amount = iron_amount * a*a*a / 1000; - for(s16 i=0; i<amount; i++) - { - s16 x = mineralrandom.range(node_min.X+1, node_max.X-1); - s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1); - s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1); - for(u16 i=0; i<27; i++) - { - v3s16 p = v3s16(x,y,z) + g_27dirs[i]; - u32 vi = vmanip.m_area.index(p); - if(vmanip.m_data[vi].getContent() == c_stone) - if(mineralrandom.next()%8 == 0) - vmanip.m_data[vi] = MapNode(LEGN(ndef, "CONTENT_STONE"), MINERAL_IRON); - } - } - } - } - - /* Add mud and sand and others underground (in place of stone) */ @@ -1955,7 +1826,7 @@ void make_block(BlockMakeData *data) /*else if(vmanip.m_flags[i] & VMANIP_FLAG_DUNGEON_INSIDE) { if(wetness > 1.2) - vmanip.m_data[i].setContent(LEGN(ndef, "CONTENT_MUD")); + vmanip.m_data[i].setContent(c_dirt); }*/ data->vmanip->m_area.add_y(em, i, -1); } @@ -2077,23 +1948,23 @@ void make_block(BlockMakeData *data) ((claynoise > 0) && (claynoise < 0.12) && (current_depth == 1)) ); if (have_clay) - vmanip.m_data[i] = MapNode(LEGN(ndef, "CONTENT_CLAY")); + vmanip.m_data[i] = MapNode(c_clay); else - vmanip.m_data[i] = MapNode(LEGN(ndef, "CONTENT_SAND")); + vmanip.m_data[i] = MapNode(c_sand); } #if 1 else if(current_depth==0 && !water_detected && y >= WATER_LEVEL && air_detected) - vmanip.m_data[i] = MapNode(LEGN(ndef, "CONTENT_GRASS")); + vmanip.m_data[i] = MapNode(c_dirt_with_grass); #endif else - vmanip.m_data[i] = MapNode(LEGN(ndef, "CONTENT_MUD")); + vmanip.m_data[i] = MapNode(c_dirt); } else { - if(vmanip.m_data[i].getContent() == LEGN(ndef, "CONTENT_MUD") - || vmanip.m_data[i].getContent() == LEGN(ndef, "CONTENT_GRASS")) - vmanip.m_data[i] = MapNode(LEGN(ndef, "CONTENT_STONE")); + if(vmanip.m_data[i].getContent() == c_dirt + || vmanip.m_data[i].getContent() == c_dirt_with_grass) + vmanip.m_data[i] = MapNode(c_stone); } current_depth++; @@ -2171,7 +2042,7 @@ void make_block(BlockMakeData *data) make_papyrus(vmanip, p, ndef); } // Trees grow only on mud and grass, on land - else if((n->getContent() == c_dirt || n->getContent() == LEGN(ndef, "CONTENT_GRASS")) && y > WATER_LEVEL + 2) + else if((n->getContent() == c_dirt || n->getContent() == c_dirt_with_grass) && y > WATER_LEVEL + 2) { p.Y++; //if(surface_humidity_2d(data->seed, v2s16(x, y)) < 0.5) @@ -2238,10 +2109,10 @@ void make_block(BlockMakeData *data) continue; /*p.Y--; if(vmanip.m_area.contains(p)) - vmanip.m_data[vmanip.m_area.index(p)] = LEGN(ndef, "CONTENT_MUD"); + vmanip.m_data[vmanip.m_area.index(p)] = c_dirt; p.Y++;*/ if(vmanip.m_area.contains(p)) - vmanip.m_data[vmanip.m_area.index(p)] = LEGN(ndef, "CONTENT_JUNGLEGRASS"); + vmanip.m_data[vmanip.m_area.index(p)] = c_junglegrass; } } @@ -2269,7 +2140,7 @@ void make_block(BlockMakeData *data) /*{ u32 i = data->vmanip->m_area.index(v3s16(p)); MapNode *n = &data->vmanip->m_data[i]; - if(n->getContent() != LEGN(ndef, "CONTENT_MUD") && n->getContent() != LEGN(ndef, "CONTENT_GRASS")) + if(n->getContent() != c_dirt && n->getContent() != c_dirt_with_grass) continue; }*/ // Will be placed one higher @@ -2304,7 +2175,7 @@ void make_block(BlockMakeData *data) /*{ u32 i = data->vmanip->m_area.index(v3s16(p)); MapNode *n = &data->vmanip->m_data[i]; - if(n->getContent() != LEGN(ndef, "CONTENT_MUD") && n->getContent() != LEGN(ndef, "CONTENT_GRASS")) + if(n->getContent() != c_dirt && n->getContent() != c_dirt_with_grass) continue; }*/ // Will be placed one lower @@ -2315,6 +2186,139 @@ void make_block(BlockMakeData *data) #endif } + /* + Add minerals + */ + + { + PseudoRandom mineralrandom(blockseed); + + /* + Add meseblocks + */ + for(s16 i=0; i<approx_ground_depth/4; i++) + { + if(mineralrandom.next()%50 == 0) + { + s16 x = mineralrandom.range(node_min.X+1, node_max.X-1); + s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1); + s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1); + for(u16 i=0; i<27; i++) + { + v3s16 p = v3s16(x,y,z) + g_27dirs[i]; + u32 vi = vmanip.m_area.index(p); + if(vmanip.m_data[vi].getContent() == c_stone) + if(mineralrandom.next()%8 == 0) + vmanip.m_data[vi] = MapNode(c_mese); + } + + } + } + /* + Add others + */ + { + u16 a = mineralrandom.range(0,15); + a = a*a*a; + u16 amount = 20 * a/1000; + for(s16 i=0; i<amount; i++) + { + s16 x = mineralrandom.range(node_min.X+1, node_max.X-1); + s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1); + s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1); + + u8 base_content = c_stone; + MapNode new_content(CONTENT_IGNORE); + u32 sparseness = 6; + + if(noisebuf_ground_crumbleness.get(x,y+5,z) < -0.1) + { + new_content = MapNode(c_stone_with_coal); + } + else + { + if(noisebuf_ground_wetness.get(x,y+5,z) > 0.0) + new_content = MapNode(c_stone_with_iron); + /*if(noisebuf_ground_wetness.get(x,y,z) > 0.0) + vmanip.m_data[i] = MapNode(c_dirt); + else + vmanip.m_data[i] = MapNode(c_sand);*/ + } + /*else if(noisebuf_ground_crumbleness.get(x,y,z) > 0.1) + { + }*/ + + if(new_content.getContent() != CONTENT_IGNORE) + { + for(u16 i=0; i<27; i++) + { + v3s16 p = v3s16(x,y,z) + g_27dirs[i]; + u32 vi = vmanip.m_area.index(p); + if(vmanip.m_data[vi].getContent() == base_content) + { + if(mineralrandom.next()%sparseness == 0) + vmanip.m_data[vi] = new_content; + } + } + } + } + } + /* + Add coal + */ + //for(s16 i=0; i < MYMAX(0, 50 - abs(node_min.Y+8 - (-30))); i++) + //for(s16 i=0; i<50; i++) + u16 coal_amount = 30; + u16 coal_rareness = 60 / coal_amount; + if(coal_rareness == 0) + coal_rareness = 1; + if(mineralrandom.next()%coal_rareness == 0) + { + u16 a = mineralrandom.next() % 16; + u16 amount = coal_amount * a*a*a / 1000; + for(s16 i=0; i<amount; i++) + { + s16 x = mineralrandom.range(node_min.X+1, node_max.X-1); + s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1); + s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1); + for(u16 i=0; i<27; i++) + { + v3s16 p = v3s16(x,y,z) + g_27dirs[i]; + u32 vi = vmanip.m_area.index(p); + if(vmanip.m_data[vi].getContent() == c_stone) + if(mineralrandom.next()%8 == 0) + vmanip.m_data[vi] = MapNode(c_stone_with_coal); + } + } + } + /* + Add iron + */ + u16 iron_amount = 8; + u16 iron_rareness = 60 / iron_amount; + if(iron_rareness == 0) + iron_rareness = 1; + if(mineralrandom.next()%iron_rareness == 0) + { + u16 a = mineralrandom.next() % 16; + u16 amount = iron_amount * a*a*a / 1000; + for(s16 i=0; i<amount; i++) + { + s16 x = mineralrandom.range(node_min.X+1, node_max.X-1); + s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1); + s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1); + for(u16 i=0; i<27; i++) + { + v3s16 p = v3s16(x,y,z) + g_27dirs[i]; + u32 vi = vmanip.m_area.index(p); + if(vmanip.m_data[vi].getContent() == c_stone) + if(mineralrandom.next()%8 == 0) + vmanip.m_data[vi] = MapNode(c_stone_with_iron); + } + } + } + } + } BlockMakeData::BlockMakeData(): diff --git a/src/mapnode.cpp b/src/mapnode.cpp index a757149b1..bfadbeac5 100644 --- a/src/mapnode.cpp +++ b/src/mapnode.cpp @@ -21,136 +21,11 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "mapnode.h" #include "porting.h" #include <string> -#include "mineral.h" #include "main.h" // For g_settings #include "nodedef.h" #include "content_mapnode.h" // For mapnode_translate_*_internal #include "serialization.h" // For ser_ver_supported -#ifndef SERVER -/* - Nodes make a face if contents differ and solidness differs. - Return value: - 0: No face - 1: Face uses m1's content - 2: Face uses m2's content - equivalent: Whether the blocks share the same face (eg. water and glass) - - TODO: Add 3: Both faces drawn with backface culling, remove equivalent -*/ -u8 face_contents(content_t m1, content_t m2, bool *equivalent, - INodeDefManager *nodemgr) -{ - *equivalent = false; - - if(m1 == CONTENT_IGNORE || m2 == CONTENT_IGNORE) - return 0; - - bool contents_differ = (m1 != m2); - - const ContentFeatures &f1 = nodemgr->get(m1); - const ContentFeatures &f2 = nodemgr->get(m2); - - // Contents don't differ for different forms of same liquid - if(f1.sameLiquid(f2)) - contents_differ = false; - - u8 c1 = f1.solidness; - u8 c2 = f2.solidness; - - bool solidness_differs = (c1 != c2); - bool makes_face = contents_differ && solidness_differs; - - if(makes_face == false) - return 0; - - if(c1 == 0) - c1 = f1.visual_solidness; - if(c2 == 0) - c2 = f2.visual_solidness; - - if(c1 == c2){ - *equivalent = true; - // If same solidness, liquid takes precense - if(f1.isLiquid()) - return 1; - if(f2.isLiquid()) - return 2; - } - - if(c1 > c2) - return 1; - else - return 2; -} -#endif - -v3s16 facedir_rotate(u8 facedir, v3s16 dir) -{ - /* - Face 2 (normally Z-) direction: - facedir=0: Z- - facedir=1: X- - facedir=2: Z+ - facedir=3: X+ - */ - v3s16 newdir; - if(facedir==0) // Same - newdir = v3s16(dir.X, dir.Y, dir.Z); - else if(facedir == 1) // Face is taken from rotXZccv(-90) - newdir = v3s16(-dir.Z, dir.Y, dir.X); - else if(facedir == 2) // Face is taken from rotXZccv(180) - newdir = v3s16(-dir.X, dir.Y, -dir.Z); - else if(facedir == 3) // Face is taken from rotXZccv(90) - newdir = v3s16(dir.Z, dir.Y, -dir.X); - else - newdir = dir; - return newdir; -} - -u8 packDir(v3s16 dir) -{ - u8 b = 0; - - if(dir.X > 0) - b |= (1<<0); - else if(dir.X < 0) - b |= (1<<1); - - if(dir.Y > 0) - b |= (1<<2); - else if(dir.Y < 0) - b |= (1<<3); - - if(dir.Z > 0) - b |= (1<<4); - else if(dir.Z < 0) - b |= (1<<5); - - return b; -} -v3s16 unpackDir(u8 b) -{ - v3s16 d(0,0,0); - - if(b & (1<<0)) - d.X = 1; - else if(b & (1<<1)) - d.X = -1; - - if(b & (1<<2)) - d.Y = 1; - else if(b & (1<<3)) - d.Y = -1; - - if(b & (1<<4)) - d.Z = 1; - else if(b & (1<<5)) - d.Z = -1; - - return d; -} - /* MapNode */ @@ -191,8 +66,9 @@ void MapNode::setLight(enum LightBank bank, u8 a_light, INodeDefManager *nodemgr u8 MapNode::getLight(enum LightBank bank, INodeDefManager *nodemgr) const { // Select the brightest of [light source, propagated light] + const ContentFeatures &f = nodemgr->get(*this); u8 light = 0; - if(nodemgr->get(*this).param_type == CPT_LIGHT) + if(f.param_type == CPT_LIGHT) { if(bank == LIGHTBANK_DAY) light = param1 & 0x0f; @@ -201,38 +77,63 @@ u8 MapNode::getLight(enum LightBank bank, INodeDefManager *nodemgr) const else assert(0); } - if(nodemgr->get(*this).light_source > light) - light = nodemgr->get(*this).light_source; + if(f.light_source > light) + light = f.light_source; return light; } -u8 MapNode::getLightBanksWithSource(INodeDefManager *nodemgr) const +bool MapNode::getLightBanks(u8 &lightday, u8 &lightnight, INodeDefManager *nodemgr) const { // Select the brightest of [light source, propagated light] - u8 lightday = 0; - u8 lightnight = 0; - if(nodemgr->get(*this).param_type == CPT_LIGHT) + const ContentFeatures &f = nodemgr->get(*this); + if(f.param_type == CPT_LIGHT) { lightday = param1 & 0x0f; lightnight = (param1>>4)&0x0f; } - if(nodemgr->get(*this).light_source > lightday) - lightday = nodemgr->get(*this).light_source; - if(nodemgr->get(*this).light_source > lightnight) - lightnight = nodemgr->get(*this).light_source; - return (lightday&0x0f) | ((lightnight<<4)&0xf0); + else + { + lightday = 0; + lightnight = 0; + } + if(f.light_source > lightday) + lightday = f.light_source; + if(f.light_source > lightnight) + lightnight = f.light_source; + return f.param_type == CPT_LIGHT || f.light_source != 0; } -u8 MapNode::getMineral(INodeDefManager *nodemgr) const +u8 MapNode::getFaceDir(INodeDefManager *nodemgr) const { - if(nodemgr->get(*this).param_type == CPT_MINERAL) + const ContentFeatures &f = nodemgr->get(*this); + if(f.param_type_2 == CPT2_FACEDIR) + return getParam2() & 0x03; + return 0; +} + +u8 MapNode::getWallMounted(INodeDefManager *nodemgr) const +{ + const ContentFeatures &f = nodemgr->get(*this); + if(f.param_type_2 == CPT2_WALLMOUNTED) + return getParam2() & 0x07; + return 0; +} + +v3s16 MapNode::getWallMountedDir(INodeDefManager *nodemgr) const +{ + switch(getWallMounted(nodemgr)) { - return param1 & 0x0f; + case 0: default: return v3s16(0,1,0); + case 1: return v3s16(0,-1,0); + case 2: return v3s16(1,0,0); + case 3: return v3s16(-1,0,0); + case 4: return v3s16(0,0,1); + case 5: return v3s16(0,0,-1); } - - return MINERAL_NONE; } + + u32 MapNode::serializedLength(u8 version) { if(!ser_ver_supported(version)) @@ -249,49 +150,179 @@ 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]; } @@ -308,18 +339,11 @@ void MapNode::deSerialize(u8 *source, u8 version) } // Convert special values from old version to new - if(version <= 18) + if(version <= 19) { // In these versions, CONTENT_IGNORE and CONTENT_AIR // are 255 and 254 - if(param0 == 255) - param0 = CONTENT_IGNORE; - else if(param0 == 254) - param0 = CONTENT_AIR; - } - // version 19 is fucked up with sometimes the old values and sometimes not - if(version == 19) - { + // Version 19 is fucked up with sometimes the old values and sometimes not if(param0 == 255) param0 = CONTENT_IGNORE; else if(param0 == 254) @@ -330,6 +354,65 @@ void MapNode::deSerialize(u8 *source, u8 version) *this = mapnode_translate_to_internal(*this, version); } + +#ifndef SERVER + +/* + Nodes make a face if contents differ and solidness differs. + Return value: + 0: No face + 1: Face uses m1's content + 2: Face uses m2's content + equivalent: Whether the blocks share the same face (eg. water and glass) + + TODO: Add 3: Both faces drawn with backface culling, remove equivalent +*/ +u8 face_contents(content_t m1, content_t m2, bool *equivalent, + INodeDefManager *nodemgr) +{ + *equivalent = false; + + if(m1 == CONTENT_IGNORE || m2 == CONTENT_IGNORE) + return 0; + + bool contents_differ = (m1 != m2); + + const ContentFeatures &f1 = nodemgr->get(m1); + const ContentFeatures &f2 = nodemgr->get(m2); + + // Contents don't differ for different forms of same liquid + if(f1.sameLiquid(f2)) + contents_differ = false; + + u8 c1 = f1.solidness; + u8 c2 = f2.solidness; + + bool solidness_differs = (c1 != c2); + bool makes_face = contents_differ && solidness_differs; + + if(makes_face == false) + return 0; + + if(c1 == 0) + c1 = f1.visual_solidness; + if(c2 == 0) + c2 = f2.visual_solidness; + + if(c1 == c2){ + *equivalent = true; + // If same solidness, liquid takes precense + if(f1.isLiquid()) + return 1; + if(f2.isLiquid()) + return 2; + } + + if(c1 > c2) + return 1; + else + return 2; +} + /* Gets lighting value at face of node @@ -380,4 +463,5 @@ u8 getFaceLight(u32 daynight_ratio, MapNode n, MapNode n2, } } +#endif diff --git a/src/mapnode.h b/src/mapnode.h index 65fc3b3e2..1c75f39c5 100644 --- a/src/mapnode.h +++ b/src/mapnode.h @@ -32,8 +32,8 @@ class INodeDefManager; - Tile = TileSpec at some side of a node of some content type Content ranges: - 0x000...0x07f: param2 is fully usable - 0x800...0xfff: param2 lower 4 bytes are free + 0x000...0x07f: param2 is fully usable + 0x800...0xfff: param2 lower 4 bits are free */ typedef u16 content_t; #define MAX_CONTENT 0xfff @@ -56,36 +56,6 @@ typedef u16 content_t; */ #define CONTENT_AIR 126 -#ifndef SERVER -/* - Nodes make a face if contents differ and solidness differs. - Return value: - 0: No face - 1: Face uses m1's content - 2: Face uses m2's content - equivalent: Whether the blocks share the same face (eg. water and glass) -*/ -u8 face_contents(content_t m1, content_t m2, bool *equivalent, - INodeDefManager *nodemgr); -#endif - -/* - Packs directions like (1,0,0), (1,-1,0) in six bits. - NOTE: This wastes way too much space for most purposes. -*/ -u8 packDir(v3s16 dir); -v3s16 unpackDir(u8 b); - -/* - facedir: CPT_FACEDIR_SIMPLE param1 value - dir: The face for which stuff is wanted - return value: The face from which the stuff is actually found - - NOTE: Currently this uses 2 bits for Z-,X-,Z+,X+, should there be Y+ - and Y- too? -*/ -v3s16 facedir_rotate(u8 facedir, v3s16 dir); - enum LightBank { LIGHTBANK_DAY, @@ -122,7 +92,6 @@ struct MapNode stored logarithmically from 0 to LIGHT_MAX. Sunlight is LIGHT_SUN, which is LIGHT_MAX+1. - Contains 2 values, day- and night lighting. Each takes 4 bits. - - Mineral content (should be removed from here) - Uhh... well, most blocks have light or nothing in here. */ u8 param1; @@ -143,7 +112,7 @@ struct MapNode { 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); } @@ -210,40 +179,22 @@ struct MapNode void setLight(enum LightBank bank, u8 a_light, INodeDefManager *nodemgr); u8 getLight(enum LightBank bank, INodeDefManager *nodemgr) const; - u8 getLightBanksWithSource(INodeDefManager *nodemgr) const; + bool getLightBanks(u8 &lightday, u8 &lightnight, INodeDefManager *nodemgr) const; // 0 <= daylight_factor <= 1000 // 0 <= return value <= LIGHT_SUN u8 getLightBlend(u32 daylight_factor, INodeDefManager *nodemgr) const { - u8 l = ((daylight_factor * getLight(LIGHTBANK_DAY, nodemgr) - + (1000-daylight_factor) * getLight(LIGHTBANK_NIGHT, nodemgr)) - )/1000; - u8 max = LIGHT_MAX; - if(getLight(LIGHTBANK_DAY, nodemgr) == LIGHT_SUN) - max = LIGHT_SUN; - if(l > max) - l = max; - return l; + u8 lightday = 0; + u8 lightnight = 0; + getLightBanks(lightday, lightnight, nodemgr); + return blend_light(daylight_factor, lightday, lightnight); } - /*// 0 <= daylight_factor <= 1000 - // 0 <= return value <= 255 - u8 getLightBlend(u32 daylight_factor, INodeDefManager *nodemgr) - { - u8 daylight = decode_light(getLight(LIGHTBANK_DAY, nodemgr)); - u8 nightlight = decode_light(getLight(LIGHTBANK_NIGHT, nodemgr)); - u8 mix = ((daylight_factor * daylight - + (1000-daylight_factor) * nightlight) - )/1000; - return mix; - }*/ - /* - Gets mineral content of node, if there is any. - MINERAL_NONE if doesn't contain or isn't able to contain mineral. - */ - u8 getMineral(INodeDefManager *nodemgr) const; - + u8 getFaceDir(INodeDefManager *nodemgr) const; + u8 getWallMounted(INodeDefManager *nodemgr) const; + v3s16 getWallMountedDir(INodeDefManager *nodemgr) const; + /* Serialization functions */ @@ -252,8 +203,44 @@ struct MapNode void serialize(u8 *dest, u8 version); void deSerialize(u8 *source, u8 version); + // Serializes or deserializes a list of nodes in bulk format (first the + // content of all nodes, then the param1 of all nodes, then the param2 + // of all nodes). + // version = serialization version. Must be >= 22 + // content_width = the number of bytes of content per node + // params_width = the number of bytes of params per node + // compressed = true to zlib-compress output + static void serializeBulk(std::ostream &os, int version, + const MapNode *nodes, u32 nodecount, + u8 content_width, u8 params_width, bool compressed); + static void deSerializeBulk(std::istream &is, int version, + MapNode *nodes, u32 nodecount, + u8 content_width, u8 params_width, bool compressed); + +private: + // Deprecated serialization methods + void serialize_pre22(u8 *dest, u8 version); + void deSerialize_pre22(u8 *source, u8 version); }; + +/* + MapNode helpers for mesh making stuff +*/ + +#ifndef SERVER + +/* + Nodes make a face if contents differ and solidness differs. + Return value: + 0: No face + 1: Face uses m1's content + 2: Face uses m2's content + equivalent: Whether the blocks share the same face (eg. water and glass) +*/ +u8 face_contents(content_t m1, content_t m2, bool *equivalent, + INodeDefManager *nodemgr); + /* Gets lighting value at face of node @@ -275,3 +262,6 @@ u8 getFaceLight(u32 daynight_ratio, MapNode n, MapNode n2, #endif + +#endif + diff --git a/src/materials.cpp b/src/materials.cpp index 146209d58..c37b7c505 100644 --- a/src/materials.cpp +++ b/src/materials.cpp @@ -18,8 +18,6 @@ with this program; if not, write to the Free Software Foundation, Inc., */ #include "materials.h" -#include "mapnode.h" -#include "nodedef.h" #include "utility.h" void MaterialProperties::serialize(std::ostream &os) @@ -139,13 +137,6 @@ DiggingProperties getDiggingProperties(const MaterialProperties *mp, return getDiggingProperties(mp, tp, 1000000); } -DiggingProperties getDiggingProperties(u16 content, - const ToolDiggingProperties *tp, INodeDefManager *nodemgr) -{ - const MaterialProperties &mp = nodemgr->get(content).material; - return getDiggingProperties(&mp, tp); -} - HittingProperties getHittingProperties(const MaterialProperties *mp, const ToolDiggingProperties *tp, float time_from_last_punch) { @@ -160,3 +151,9 @@ HittingProperties getHittingProperties(const MaterialProperties *mp, return HittingProperties(hp, wear); } +HittingProperties getHittingProperties(const MaterialProperties *mp, + const ToolDiggingProperties *tp) +{ + return getHittingProperties(mp, tp, 1000000); +} + diff --git a/src/materials.h b/src/materials.h index face7d5df..058b2ab85 100644 --- a/src/materials.h +++ b/src/materials.h @@ -110,17 +110,12 @@ struct DiggingProperties {} }; -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; @@ -135,5 +130,8 @@ struct HittingProperties HittingProperties getHittingProperties(const MaterialProperties *mp, const ToolDiggingProperties *tp, float time_from_last_punch); +HittingProperties getHittingProperties(const MaterialProperties *mp, + const ToolDiggingProperties *tp); + #endif diff --git a/src/mineral.cpp b/src/mineral.cpp deleted file mode 100644 index 4e495fce6..000000000 --- a/src/mineral.cpp +++ /dev/null @@ -1,62 +0,0 @@ -/* -Minetest-c55 -Copyright (C) 2010 celeron55, Perttu Ahola <celeron55@gmail.com> - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along -with this program; if not, write to the Free Software Foundation, Inc., -51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -*/ - -#include "mineral.h" -#include "gamedef.h" - - -const char *mineral_filenames[MINERAL_COUNT] = -{ - NULL, - "mineral_coal.png", - "mineral_iron.png" -}; - -std::string mineral_textures[MINERAL_COUNT]; - -void init_mineral() -{ - for(u32 i=0; i<MINERAL_COUNT; i++) - { - if(mineral_filenames[i] == NULL) - continue; - mineral_textures[i] = mineral_filenames[i]; - } -} - -std::string mineral_block_texture(u8 mineral) -{ - if(mineral >= MINERAL_COUNT) - return ""; - - return mineral_textures[mineral]; -} - -ItemStack getDiggedMineralItem(u8 mineral, IGameDef *gamedef) -{ - if(mineral == MINERAL_COAL) - return ItemStack("default:coal_lump", 1, 0, "", gamedef->idef()); - else if(mineral == MINERAL_IRON) - return ItemStack("default:iron_lump", 1, 0, "", gamedef->idef()); - else - return ItemStack(); -} - - - diff --git a/src/mineral.h b/src/mineral.h deleted file mode 100644 index a945d0e02..000000000 --- a/src/mineral.h +++ /dev/null @@ -1,47 +0,0 @@ -/* -Minetest-c55 -Copyright (C) 2010 celeron55, Perttu Ahola <celeron55@gmail.com> - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along -with this program; if not, write to the Free Software Foundation, Inc., -51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -*/ - -#ifndef MINERAL_HEADER -#define MINERAL_HEADER - -#include "inventory.h" - -/* - Minerals - - Value is stored in the lowest 5 bits of a MapNode's CPT_MINERAL - type param. -*/ - -// Caches textures -void init_mineral(); - -#define MINERAL_NONE 0 -#define MINERAL_COAL 1 -#define MINERAL_IRON 2 - -#define MINERAL_COUNT 3 - -class IGameDef; - -std::string mineral_block_texture(u8 mineral); -ItemStack getDiggedMineralItem(u8 mineral, IGameDef *gamedef); - -#endif - diff --git a/src/nameidmapping.h b/src/nameidmapping.h index 071599e10..238deb451 100644 --- a/src/nameidmapping.h +++ b/src/nameidmapping.h @@ -70,6 +70,9 @@ public: result = i->second; return true; } + u16 size() const{ + return m_id_to_name.size(); + } private: std::map<u16, std::string> m_id_to_name; std::map<std::string, u16> m_name_to_id; diff --git a/src/nodedef.cpp b/src/nodedef.cpp index 87469bfb5..3d85bdbd9 100644 --- a/src/nodedef.cpp +++ b/src/nodedef.cpp @@ -127,6 +127,7 @@ void ContentFeatures::reset() 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; @@ -135,10 +136,6 @@ void ContentFeatures::reset() 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 = ""; @@ -151,6 +148,8 @@ void ContentFeatures::reset() // 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) @@ -172,6 +171,7 @@ void ContentFeatures::serialize(std::ostream &os) writeU8(os, post_effect_color.getGreen()); writeU8(os, post_effect_color.getBlue()); writeU8(os, param_type); + writeU8(os, param_type_2); writeU8(os, is_ground_content); writeU8(os, light_propagates); writeU8(os, sunlight_propagates); @@ -180,10 +180,6 @@ void ContentFeatures::serialize(std::ostream &os) 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); @@ -193,6 +189,8 @@ void ContentFeatures::serialize(std::ostream &os) 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) @@ -218,6 +216,7 @@ 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); @@ -226,10 +225,6 @@ void ContentFeatures::deSerialize(std::istream &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); @@ -239,6 +234,8 @@ void ContentFeatures::deSerialize(std::istream &is) damage_per_second = readU32(is); selection_box.deSerialize(is); material.deSerialize(is); + legacy_facedir_simple = readU8(is); + legacy_wallmounted = readU8(is); } /* @@ -298,7 +295,7 @@ public: // 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]; @@ -306,7 +303,7 @@ public: return i; } } - // Then search from the small 8-byte-param2 pool + // Then search from the small 8-bit-param2 pool for(u16 i=0; i<=125; i++){ const ContentFeatures &f = m_content_features[i]; if(f.name == "") @@ -394,13 +391,9 @@ public: 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); diff --git a/src/nodedef.h b/src/nodedef.h index 598ad7fb3..9524385cf 100644 --- a/src/nodedef.h +++ b/src/nodedef.h @@ -37,9 +37,19 @@ enum ContentParamType { CPT_NONE, CPT_LIGHT, - CPT_MINERAL, +}; + +enum ContentParamType2 +{ + CPT2_NONE, + // Need 8-bit param2 + CPT2_FULL, + // Flowing liquid properties + CPT2_FLOWINGLIQUID, // Direction for chests and furnaces and such - CPT_FACEDIR_SIMPLE + CPT2_FACEDIR, + // Direction for signs, torches and such + CPT2_WALLMOUNTED, }; enum LiquidType @@ -53,7 +63,7 @@ enum NodeBoxType { NODEBOX_REGULAR, // Regular block; allows buildable_to NODEBOX_FIXED, // Static separately defined box - NODEBOX_WALLMOUNTED, // Box for wall_mounted nodes; (top, bottom, side) + NODEBOX_WALLMOUNTED, // Box for wall mounted nodes; (top, bottom, side) }; struct NodeBox @@ -151,6 +161,8 @@ struct ContentFeatures video::SColor post_effect_color; // Type of MapNode::param1 ContentParamType param_type; + // Type of MapNode::param2 + ContentParamType2 param_type_2; // True for all ground-like things like stone and mud, false for eg. trees bool is_ground_content; bool light_propagates; @@ -166,16 +178,6 @@ struct ContentFeatures bool climbable; // Player can build on these bool buildable_to; - // If true, param2 is set to direction when placed. Used for torches. - // NOTE: the direction format is quite inefficient and should be changed - bool wall_mounted; - // 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 @@ -193,6 +195,11 @@ struct ContentFeatures 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 diff --git a/src/scriptapi.cpp b/src/scriptapi.cpp index 187d1a894..173e5a827 100644 --- a/src/scriptapi.cpp +++ b/src/scriptapi.cpp @@ -314,6 +314,15 @@ static int getenumfield(lua_State *L, int table, 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) { @@ -323,6 +332,15 @@ static void setfloatfield(lua_State *L, int table, 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) { @@ -369,8 +387,16 @@ struct EnumString es_ContentParamType[] = { {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}, }; @@ -587,6 +613,25 @@ static core::aabbox3d<f32> read_aabbox3df32(lua_State *L, int index, f32 scale) } /* + 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 */ @@ -632,6 +677,43 @@ static void push_tool_digging_properties(lua_State *L, } /* + 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 */ @@ -797,12 +879,24 @@ static ContentFeatures read_content_features(lua_State *L, int index) 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. @@ -815,16 +909,6 @@ static ContentFeatures read_content_features(lua_State *L, int index) 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 @@ -876,18 +960,15 @@ static ContentFeatures read_content_features(lua_State *L, int index) 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; } @@ -1774,6 +1855,33 @@ private: 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) @@ -1984,6 +2092,8 @@ const luaL_reg NodeMetaRef::methods[] = { method(NodeMetaRef, set_text), method(NodeMetaRef, get_text), method(NodeMetaRef, get_owner), + method(NodeMetaRef, set_owner), + method(NodeMetaRef, get_allow_removal), method(NodeMetaRef, set_infotext), method(NodeMetaRef, get_inventory), method(NodeMetaRef, set_inventory_draw_spec), @@ -3369,6 +3479,32 @@ static int l_get_inventory(lua_State *L) return 1; } +// get_digging_properties(material_properties, tool_digging_properties[, time_from_last_punch]) +static int l_get_digging_properties(lua_State *L) +{ + MaterialProperties mp = read_material_properties(L, 1); + ToolDiggingProperties tp = read_tool_digging_properties(L, 2); + if(lua_isnoneornil(L, 3)) + push_digging_properties(L, getDiggingProperties(&mp, &tp)); + else + push_digging_properties(L, getDiggingProperties(&mp, &tp, + luaL_checknumber(L, 3))); + return 1; +} + +// get_hitting_properties(material_properties, tool_digging_properties[, time_from_last_punch]) +static int l_get_hitting_properties(lua_State *L) +{ + MaterialProperties mp = read_material_properties(L, 1); + ToolDiggingProperties tp = read_tool_digging_properties(L, 2); + if(lua_isnoneornil(L, 3)) + push_hitting_properties(L, getHittingProperties(&mp, &tp)); + else + push_hitting_properties(L, getHittingProperties(&mp, &tp, + luaL_checknumber(L, 3))); + return 1; +} + // get_current_modname() static int l_get_current_modname(lua_State *L) { @@ -3402,6 +3538,8 @@ static const struct luaL_Reg minetest_f [] = { {"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} @@ -3719,6 +3857,8 @@ bool scriptapi_on_respawnplayer(lua_State *L, ServerActiveObject *player) assert(lua_checkstack(L, 20)); StackUnroller stack_unroller(L); + dstream<<"player: "<<player<<" id: "<<player->getId()<<std::endl; + bool positioning_handled_by_some = false; // Get minetest.registered_on_respawnplayers @@ -3754,7 +3894,7 @@ void scriptapi_get_creative_inventory(lua_State *L, ServerRemotePlayer *player) } /* - item callbacks + item callbacks and node callbacks */ // Retrieves minetest.registered_items[name][callbackname] @@ -3864,114 +4004,64 @@ bool scriptapi_item_on_use(lua_State *L, ItemStack &item, 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 @@ -3980,10 +4070,8 @@ void scriptapi_environment_on_punchnode(lua_State *L, v3s16 p, MapNode node, // key at index -2 and value at index -1 luaL_checktype(L, -1, LUA_TFUNCTION); // Call function - push_v3s16(L, p); - pushnode(L, node, ndef); - objectref_get_or_create(L, puncher); - if(lua_pcall(L, 3, 0, 0)) + lua_pushnumber(L, dtime); + if(lua_pcall(L, 1, 0, 0)) script_error(L, "error: %s", lua_tostring(L, -1)); // value removed, keep key for next iteration } diff --git a/src/scriptapi.h b/src/scriptapi.h index 198f60525..500a9ab99 100644 --- a/src/scriptapi.h +++ b/src/scriptapi.h @@ -49,15 +49,6 @@ bool scriptapi_on_chat_message(lua_State *L, const std::string &name, /* environment */ // On environment step void scriptapi_environment_step(lua_State *L, float dtime); -// After adding node -void scriptapi_environment_on_placenode(lua_State *L, v3s16 p, MapNode newnode, - ServerActiveObject *placer); -// After removing node -void scriptapi_environment_on_dignode(lua_State *L, v3s16 p, MapNode oldnode, - ServerActiveObject *digger); -// When punching node -void scriptapi_environment_on_punchnode(lua_State *L, v3s16 p, MapNode node, - ServerActiveObject *puncher); // After generating a piece of map void scriptapi_environment_on_generated(lua_State *L, v3s16 minp, v3s16 maxp); @@ -75,6 +66,12 @@ bool scriptapi_item_on_place(lua_State *L, ItemStack &item, 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, diff --git a/src/serialization.h b/src/serialization.h index cc4381155..bcfea451a 100644 --- a/src/serialization.h +++ b/src/serialization.h @@ -57,11 +57,12 @@ with this program; if not, write to the Free Software Foundation, Inc., 19: new content type handling 20: many existing content types translated to extended ones 21: dynamic content type allocation + 22: full 16-bit content types, minerals removed, facedir & wallmounted changed */ // This represents an uninitialized or invalid format #define SER_FMT_VER_INVALID 255 // Highest supported serialization version -#define SER_FMT_VER_HIGHEST 21 +#define SER_FMT_VER_HIGHEST 22 // Lowest supported serialization version #define SER_FMT_VER_LOWEST 0 diff --git a/src/server.cpp b/src/server.cpp index 3c0cab2a9..9f3db34d9 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -28,7 +28,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "constants.h" #include "voxel.h" #include "materials.h" -#include "mineral.h" #include "config.h" #include "servercommand.h" #include "filesys.h" @@ -2899,13 +2898,12 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) /* 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; } /* @@ -2919,10 +2917,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) NOTE: This can be used in the future to check if 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); @@ -2934,22 +2929,12 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) <<std::endl; m_emerge_queue.addBlock(peer_id, getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK); - cannot_punch_node = true; } - - if(cannot_punch_node) - return; - - /* - Run script hook - */ - scriptapi_environment_on_punchnode(m_lua, p_under, n, srp); + if(n.getContent() != CONTENT_IGNORE) + scriptapi_node_on_punch(m_lua, p_under, n, srp); } else if(pointed.type == POINTEDTHING_OBJECT) { - if(!interact_priv) - return; - // Skip if object has been removed if(pointed_object->m_removed) return; @@ -2977,190 +2962,24 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) else if(action == 2) { // Only complete digging of nodes - if(pointed.type != POINTEDTHING_NODE) - return; - - // Mandatory parameter; actually used for nothing - core::map<v3s16, MapBlock*> modified_blocks; - - content_t material = CONTENT_IGNORE; - u8 mineral = MINERAL_NONE; - - bool cannot_remove_node = !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 /* @@ -3168,16 +2987,13 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) */ 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 @@ -3201,123 +3017,6 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) 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 @@ -3326,14 +3025,6 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) */ 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 @@ -3949,7 +3640,7 @@ void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver) */ std::ostringstream os(std::ios_base::binary); - block->serialize(os, ver); + block->serialize(os, ver, false); std::string s = os.str(); SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size()); diff --git a/src/servermain.cpp b/src/servermain.cpp index e8a54512e..3ef1d9479 100644 --- a/src/servermain.cpp +++ b/src/servermain.cpp @@ -68,7 +68,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "porting.h" #include "materials.h" #include "config.h" -#include "mineral.h" #include "filesys.h" #include "defaultsettings.h" #include "settings.h" @@ -301,10 +300,6 @@ int main(int argc, char *argv[]) srand(time(0)); mysrand(time(0)); - // Initialize stuff - - init_mineral(); - /* Run unit tests */ diff --git a/src/test.cpp b/src/test.cpp index caf31d1af..2d5c86e64 100644 --- a/src/test.cpp +++ b/src/test.cpp @@ -76,9 +76,7 @@ void define_some_nodes(IWritableItemDefManager *idef, IWritableNodeDefManager *n 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; @@ -106,7 +104,6 @@ void define_some_nodes(IWritableItemDefManager *idef, IWritableNodeDefManager *n 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; diff --git a/src/tile.cpp b/src/tile.cpp index 1d5f4d833..bc4c49cb1 100644 --- a/src/tile.cpp +++ b/src/tile.cpp @@ -27,7 +27,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #include <ICameraSceneNode.h> #include "log.h" #include "mapnode.h" // For texture atlas making -#include "mineral.h" // For texture atlas making #include "nodedef.h" // For texture atlas making #include "gamedef.h" @@ -299,8 +298,8 @@ public: Example names: "stone.png" "stone.png^crack2" - "stone.png^blit:mineral_coal.png" - "stone.png^blit:mineral_coal.png^crack1" + "stone.png^mineral_coal.png" + "stone.png^mineral_coal.png^crack1" - If texture specified by name is found from cache, return the cached id. @@ -824,14 +823,6 @@ void TextureSource::buildMainAtlas(class IGameDef *gamedef) { 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; - } - } } } |