From 8769593d6f86ee9a58a574d242aca6b2eb76dc77 Mon Sep 17 00:00:00 2001 From: Treer Date: Sun, 12 Jul 2020 12:12:00 +1000 Subject: [PATCH 1/3] Reduce lava in biomes-based mapgen (#25) The biomes-based mapgen was creating the same amount of lava as the original nether mapgen, but it doesn't have the same issue of chunk emerge order sometimes causing lava in the overdraw regions to get removed. This adjustment will hopefully balance that a little. Also makes glowstone stalactite a bit rarer. Adjusting lava ore scarcity in the biomes-mapgen doesn't cause forwards or backwards compatibilty issues with existing maps, likewise with schematic rarety like glowstone stalactites, so can afford to fiddle and tune. --- mapgen.lua | 4 ++-- mapgen_decorations.lua | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/mapgen.lua b/mapgen.lua index 41b8453..982e75e 100644 --- a/mapgen.lua +++ b/mapgen.lua @@ -113,7 +113,7 @@ override_underground_biomes() -- nether:native_mapgen is used to prevent ores and decorations being generated according -- to landforms created by the native mapgen. --- Ores and decorations are registered against "nether:rack" instead, and the lua +-- Ores and decorations can be registered against "nether:rack" instead, and the lua -- on_generate() callback will carve the Nether with nether:rack before invoking -- generate_decorations and generate_ores. minetest.register_node("nether:native_mapgen", {}) @@ -160,7 +160,7 @@ minetest.register_ore({ ore_type = "scatter", ore = "default:lava_source", wherein = "nether:rack", - clust_scarcity = 32 * 32 * 32, + clust_scarcity = 36 * 36 * 36, clust_num_ores = 4, clust_size = 2, y_max = NETHER_CEILING, diff --git a/mapgen_decorations.lua b/mapgen_decorations.lua index b210db8..5b7d7e3 100644 --- a/mapgen_decorations.lua +++ b/mapgen_decorations.lua @@ -113,7 +113,7 @@ minetest.register_decoration({ deco_type = "schematic", place_on = "nether:rack", sidelen = 80, - fill_ratio = 0.0004, + fill_ratio = 0.0003, biomes = {"nether_caverns"}, y_max = nether.DEPTH_CEILING, -- keep compatibility with mapgen_nobiomes.lua y_min = nether.DEPTH_FLOOR, @@ -127,7 +127,7 @@ minetest.register_decoration({ deco_type = "schematic", place_on = "nether:rack", sidelen = 80, - fill_ratio = 0.0007, + fill_ratio = 0.0008, biomes = {"nether_caverns"}, y_max = nether.DEPTH_CEILING, -- keep compatibility with mapgen_nobiomes.lua y_min = nether.DEPTH_FLOOR, From 5b3b56ebec6fe75c37747fd039bbf162801e2f31 Mon Sep 17 00:00:00 2001 From: Treer Date: Sun, 26 Jul 2020 14:34:06 +1000 Subject: [PATCH 2/3] Respect protected areas when spawning remote portals (#27) * respect protected areas when spawning remote portals * Use portal_shape to determine area to check for natural/protected * Log warning on deprecated function call --- .luacheckrc | 1 + init.lua | 10 ++-- mapgen.lua | 18 ++++--- mapgen_nobiomes.lua | 24 ++++++---- portal_api.lua | 113 ++++++++++++++++++++++++++++++++++---------- portal_api.txt | 19 ++++++-- portal_examples.lua | 8 ++-- 7 files changed, 140 insertions(+), 53 deletions(-) diff --git a/.luacheckrc b/.luacheckrc index 5ed2386..99f4685 100644 --- a/.luacheckrc +++ b/.luacheckrc @@ -23,6 +23,7 @@ read_globals = { "PseudoRandom", "stairs", "stairsplus", + "string.split", table = { fields = { "copy", "getn" } }, "vector", "VoxelArea", diff --git a/init.lua b/init.lua index cbc684b..7497840 100644 --- a/init.lua +++ b/init.lua @@ -58,7 +58,7 @@ nether.NETHER_REALM_ENABLED = minetest.settings:get_bool("nether_realm_ena nether.DEPTH_CEILING = tonumber(minetest.settings:get("nether_depth_ymax") or nether.DEPTH_CEILING) nether.DEPTH_FLOOR = tonumber(minetest.settings:get("nether_depth_ymin") or nether.DEPTH_FLOOR) -if nether.DEPTH_FLOOR + 1000 > nether.DEPTH_CEILING then +if nether.DEPTH_FLOOR + 1000 > nether.DEPTH_CEILING then error("The lower limit of the Nether must be set at least 1000 lower than the upper limit, and more than 3000 is recommended. Set settingtypes.txt, or 'All Settings' -> 'Mods' -> 'nether' -> 'Nether depth'", 0) end nether.DEPTH = nether.DEPTH_CEILING -- Deprecated, use nether.DEPTH_CEILING instead. @@ -101,7 +101,7 @@ The expedition parties have found no diamonds or gold, and after an experienced return pos.y < nether.DEPTH_CEILING end, - find_realm_anchorPos = function(surface_anchorPos) + find_realm_anchorPos = function(surface_anchorPos, player_name) -- divide x and z by a factor of 8 to implement Nether fast-travel local destination_pos = vector.divide(surface_anchorPos, nether.FASTTRAVEL_FACTOR) destination_pos.x = math.floor(0.5 + destination_pos.x) -- round to int @@ -116,12 +116,12 @@ The expedition parties have found no diamonds or gold, and after an experienced return existing_portal_location, existing_portal_orientation else local start_y = nether.DEPTH_CEILING - math.random(500, 1500) -- Search starting altitude - destination_pos.y = nether.find_nether_ground_y(destination_pos.x, destination_pos.z, start_y) + destination_pos.y = nether.find_nether_ground_y(destination_pos.x, destination_pos.z, start_y, player_name) return destination_pos end end, - find_surface_anchorPos = function(realm_anchorPos) + find_surface_anchorPos = function(realm_anchorPos, player_name) -- A portal definition doesn't normally need to provide a find_surface_anchorPos() function, -- since find_surface_target_y() will be used by default, but Nether portals also scale position -- to create fast-travel. @@ -140,7 +140,7 @@ The expedition parties have found no diamonds or gold, and after an experienced if existing_portal_location ~= nil then return existing_portal_location, existing_portal_orientation else - destination_pos.y = nether.find_surface_target_y(destination_pos.x, destination_pos.z, "nether_portal") + destination_pos.y = nether.find_surface_target_y(destination_pos.x, destination_pos.z, "nether_portal", player_name) return destination_pos end end, diff --git a/mapgen.lua b/mapgen.lua index 982e75e..b449c5c 100644 --- a/mapgen.lua +++ b/mapgen.lua @@ -465,10 +465,15 @@ end -- use knowledge of the nether mapgen algorithm to return a suitable ground level for placing a portal. -function nether.find_nether_ground_y(target_x, target_z, start_y) +-- player_name is optional, allowing a player to spawn a remote portal in their own protected areas. +function nether.find_nether_ground_y(target_x, target_z, start_y, player_name) local nobj_cave_point = minetest.get_perlin(np_cave) local air = 0 -- Consecutive air nodes found + local minp_schem, maxp_schem = nether.get_schematic_volume({x = target_x, y = 0, z = target_z}, nil, "nether_portal") + local minp = {x = minp_schem.x, y = 0, z = minp_schem.z} + local maxp = {x = maxp_schem.x, y = 0, z = maxp_schem.z} + for y = start_y, math_max(NETHER_FLOOR + BLEND, start_y - 4096), -1 do local nval_cave = nobj_cave_point:get3d({x = target_x, y = y, z = target_z}) @@ -476,13 +481,14 @@ function nether.find_nether_ground_y(target_x, target_z, start_y) air = air + 1 else -- Not cavern, check if 4 nodes of space above if air >= 4 then + local portal_y = y + 1 -- Check volume for non-natural nodes - local minp = {x = target_x - 1, y = y , z = target_z - 2} - local maxp = {x = target_x + 2, y = y + 4, z = target_z + 2} - if nether.volume_is_natural(minp, maxp) then - return y + 1 + minp.y = minp_schem.y + portal_y + maxp.y = maxp_schem.y + portal_y + if nether.volume_is_natural_and_unprotected(minp, maxp, player_name) then + return portal_y else -- Restart search a little lower - nether.find_nether_ground_y(target_x, target_z, y - 16) + nether.find_nether_ground_y(target_x, target_z, y - 16, player_name) end else -- Not enough space, reset air to zero air = 0 diff --git a/mapgen_nobiomes.lua b/mapgen_nobiomes.lua index 2d1093c..103537d 100644 --- a/mapgen_nobiomes.lua +++ b/mapgen_nobiomes.lua @@ -201,24 +201,30 @@ end) -- use knowledge of the nether mapgen algorithm to return a suitable ground level for placing a portal. -function nether.find_nether_ground_y(target_x, target_z, start_y) +-- player_name is optional, allowing a player to spawn a remote portal in their own protected areas. +function nether.find_nether_ground_y(target_x, target_z, start_y, player_name) local nobj_cave_point = minetest.get_perlin(np_cave) local air = 0 -- Consecutive air nodes found - for y = start_y, start_y - 4096, -1 do + local minp_schem, maxp_schem = nether.get_schematic_volume({x = target_x, y = 0, z = target_z}, nil, "nether_portal") + local minp = {x = minp_schem.x, y = 0, z = minp_schem.z} + local maxp = {x = maxp_schem.x, y = 0, z = maxp_schem.z} + + for y = start_y, math.max(NETHER_FLOOR + BLEND, start_y - 4096), -1 do local nval_cave = nobj_cave_point:get3d({x = target_x, y = y, z = target_z}) if nval_cave > TCAVE then -- Cavern air = air + 1 else -- Not cavern, check if 4 nodes of space above if air >= 4 then + local portal_y = y + 1 -- Check volume for non-natural nodes - local minp = {x = target_x - 1, y = y , z = target_z - 2} - local maxp = {x = target_x + 2, y = y + 4, z = target_z + 2} - if nether.volume_is_natural(minp, maxp) then - return y + 1 + minp.y = minp_schem.y + portal_y + maxp.y = maxp_schem.y + portal_y + if nether.volume_is_natural_and_unprotected(minp, maxp, player_name) then + return portal_y else -- Restart search a little lower - nether.find_nether_ground_y(target_x, target_z, y - 16) + nether.find_nether_ground_y(target_x, target_z, y - 16, player_name) end else -- Not enough space, reset air to zero air = 0 @@ -226,5 +232,5 @@ function nether.find_nether_ground_y(target_x, target_z, start_y) end end - return start_y -- Fallback -end \ No newline at end of file + return math.max(start_y, NETHER_FLOOR + BLEND) -- Fallback +end diff --git a/portal_api.lua b/portal_api.lua index 9b5df54..c396b4f 100644 --- a/portal_api.lua +++ b/portal_api.lua @@ -1303,8 +1303,9 @@ end -- invoked when a player attempts to turn obsidian nodes into an open portal +-- player_name is optional, allowing a player to spawn a remote portal in their own protected area -- ignition_node_name is optional -local function ignite_portal(ignition_pos, ignition_node_name) +local function ignite_portal(ignition_pos, player_name, ignition_node_name) if ignition_node_name == nil then ignition_node_name = minetest.get_node(ignition_pos).name end if DEBUG then minetest.chat_send_all("IGNITE the " .. ignition_node_name .. " at " .. minetest.pos_to_string(ignition_pos)) end @@ -1354,9 +1355,9 @@ local function ignite_portal(ignition_pos, ignition_node_name) local destination_anchorPos, destination_orientation if portal_definition.is_within_realm(ignition_pos) then - destination_anchorPos, destination_orientation = portal_definition.find_surface_anchorPos(anchorPos) + destination_anchorPos, destination_orientation = portal_definition.find_surface_anchorPos(anchorPos, player_name or "") else - destination_anchorPos, destination_orientation = portal_definition.find_realm_anchorPos(anchorPos) + destination_anchorPos, destination_orientation = portal_definition.find_realm_anchorPos(anchorPos, player_name or "") end if DEBUG and destination_orientation == nil then minetest.chat_send_all("No destination_orientation given") end if destination_orientation == nil then destination_orientation = orientation end @@ -1825,7 +1826,7 @@ function register_frame_node(frame_node_name) extended_node_def.mesecons = {effector = { action_on = function (pos, node) if DEBUG then minetest.chat_send_all("portal frame material: mesecons action ON") end - ignite_portal(pos, node.name) + ignite_portal(pos, nil, node.name) end, action_off = function (pos, node) if DEBUG then minetest.chat_send_all("portal frame material: mesecons action OFF") end @@ -2081,7 +2082,7 @@ function nether.register_portal(name, portaldef) end if portaldef.find_surface_anchorPos == nil then -- default to using find_surface_target_y() - portaldef.find_surface_anchorPos = function(pos) + portaldef.find_surface_anchorPos = function(pos, player_name) local destination_pos = {x = pos.x, y = 0, z = pos.z} local existing_portal_location, existing_portal_orientation = @@ -2089,7 +2090,7 @@ function nether.register_portal(name, portaldef) if existing_portal_location ~= nil then return existing_portal_location, existing_portal_orientation else - destination_pos.y = nether.find_surface_target_y(destination_pos.x, destination_pos.z, name) + destination_pos.y = nether.find_surface_target_y(destination_pos.x, destination_pos.z, name, player_name) return destination_pos end end @@ -2153,10 +2154,10 @@ end function nether.register_portal_ignition_item(item_name, ignition_failure_sound) minetest.override_item(item_name, { - on_place = function(stack, _, pt) + on_place = function(stack, placer, pt) local done = false if pt.under and nether.is_frame_node[minetest.get_node(pt.under).name] then - done = ignite_portal(pt.under) + done = ignite_portal(pt.under, placer:get_player_name()) if done and not minetest.settings:get_bool("creative_mode") then stack:take_item() end @@ -2175,22 +2176,22 @@ end -- use this when determining where to spawn a portal, to avoid overwriting player builds -- It checks the area for any nodes that aren't ground or trees. +-- player_name is optional, allowing a player to spawn a remote portal in their own protected areas. -- (Water also fails this test, unless it is unemerged) -function nether.volume_is_natural(minp, maxp) +function nether.volume_is_natural_and_unprotected(minp, maxp, player_name) + local c_air = minetest.get_content_id("air") local c_ignore = minetest.get_content_id("ignore") local vm = minetest.get_voxel_manip() - local pos1 = {x = minp.x, y = minp.y, z = minp.z} - local pos2 = {x = maxp.x, y = maxp.y, z = maxp.z} - local emin, emax = vm:read_from_map(pos1, pos2) + local emin, emax = vm:read_from_map(minp, maxp) local area = VoxelArea:new({MinEdge = emin, MaxEdge = emax}) local data = vm:get_data() - for z = pos1.z, pos2.z do - for y = pos1.y, pos2.y do - local vi = area:index(pos1.x, y, z) - for x = pos1.x, pos2.x do + for z = minp.z, maxp.z do + for y = minp.y, maxp.y do + local vi = area:index(minp.x, y, z) + for x = minp.x, maxp.x do local id = data[vi] -- Existing node if DEBUG and id == nil then minetest.chat_send_all("nil block at index " .. vi) end if id ~= c_air and id ~= c_ignore and id ~= nil then -- checked for common natural or not emerged @@ -2200,7 +2201,7 @@ function nether.volume_is_natural(minp, maxp) -- trees are natural but not "ground content" local node_groups = nodedef.groups if node_groups == nil or (node_groups.tree == nil and node_groups.leaves == nil and node_groups.leafdecay == nil) then - if DEBUG then minetest.chat_send_all("volume_is_natural() found unnatural node " .. name) end + if DEBUG then minetest.chat_send_all("volume_is_natural_and_unprotected() found unnatural node " .. name) end return false end end @@ -2210,13 +2211,73 @@ function nether.volume_is_natural(minp, maxp) end end - if DEBUG then minetest.chat_send_all("Volume is natural") end + if minetest.is_area_protected(minp, maxp, player_name or "") then + if DEBUG then minetest.chat_send_all("Volume is protected " .. minetest.pos_to_string(minp) .. "-" .. minetest.pos_to_string(maxp)) end + return false; + end + + if DEBUG then minetest.chat_send_all("Volume is natural and unprotected for player '" .. (player_name or "") .. "', " .. minetest.pos_to_string(minp) .. "-" .. minetest.pos_to_string(maxp)) end return true end +-- Deprecated, use nether.volume_is_natural_and_unprotected() instead. +function nether.volume_is_natural(minp, maxp) + + if nether.deprecation_warning_volume_is_natural == nil then + local stack = debug.traceback("", 2); + local calling_func = (string.split(stack, "\n", false, 2, false)[2] or ""):trim() + minetest.log("warning", + "Deprecated function \"nether.volume_is_natural()\" invoked. Use \"nether.volume_is_natural_and_unprotected()\" instead. " .. + calling_func) + nether.deprecation_warning_volume_is_natural = true; + end + + return nether.volume_is_natural_and_unprotected(minp, maxp) +end + +-- Gets the volume that may be altered if a portal is placed at the anchor_pos +-- orientation is optional, but specifying it will reduce the volume returned +-- portal_name is optional, but specifying it will reduce the volume returned +-- returns minp, maxp +function nether.get_schematic_volume(anchor_pos, orientation, portal_name) + + if orientation == nil then + -- Return a volume large enough for any orientation + local minp0, maxp0 = nether.get_schematic_volume(anchor_pos, 0, portal_name) + local minp1, maxp1 = nether.get_schematic_volume(anchor_pos, 1, portal_name) + + -- ToDo: If an asymmetric portal is used with an anchor not at the center of the + -- schematic then we will also need to check orientations 3 and 4. + -- (The currently existing portal-shapes are not affected) + return + {x = math.min(minp0.x, minp1.x), y = math.min(minp0.y, minp1.y), z = math.min(minp0.z, minp1.z)}, + {x = math.max(maxp0.x, maxp1.x), y = math.max(maxp0.y, maxp1.y), z = math.max(maxp0.z, maxp1.z)} + end + + -- Assume the largest possible portal shape unless we know it's a smaller one. + local shape_defintion = nether.PortalShape_Circular + if portal_name ~= nil and nether.registered_portals[portal_name] ~= nil then + shape_defintion = nether.registered_portals[portal_name].shape + end + + local size = shape_defintion.schematic.size + local minp = shape_defintion.get_schematicPos_from_anchorPos(anchor_pos, orientation); + local maxp + + if (orientation % 2) == 0 then + maxp = {x = minp.x + size.x - 1, y = minp.y + size.y - 1, z = minp.z + size.z - 1} + else + maxp = {x = minp.x + size.z - 1, y = minp.y + size.y - 1, z = minp.z + size.x - 1} + end + return minp, maxp +end + + -- Can be used when implementing custom find_surface_anchorPos() functions --- portal_name is optional, providing it allows existing portals on the surface to be reused. -function nether.find_surface_target_y(target_x, target_z, portal_name) +-- portal_name is optional, providing it allows existing portals on the surface to be reused, and +-- a potentially smaller volume to be checked by volume_is_natural_and_unprotected(). +-- player_name is optional, allowing a player to spawn a remote portal in their own protected areas. +function nether.find_surface_target_y(target_x, target_z, portal_name, player_name) assert(target_x ~= nil and target_z ~= nil, "Arguments `target_x` and `target_z` cannot be nil when calling find_surface_target_y()") @@ -2246,18 +2307,22 @@ function nether.find_surface_target_y(target_x, target_z, portal_name) end end + local minp_schem, maxp_schem = nether.get_schematic_volume({x = target_x, y = 0, z = target_z}, nil, portal_name) + local minp = {x = minp_schem.x, y = 0, z = minp_schem.z} + local maxp = {x = maxp_schem.x, y = 0, z = maxp_schem.z} + for y = start_y, start_y - 256, -16 do -- Check volume for non-natural nodes - local minp = {x = target_x - 1, y = y - 1, z = target_z - 2} - local maxp = {x = target_x + 2, y = y + 3, z = target_z + 2} - if nether.volume_is_natural(minp, maxp) then + minp.y = minp_schem.y + y + maxp.y = maxp_schem.y + y + if nether.volume_is_natural_and_unprotected(minp, maxp, player_name) then return y elseif portal_name ~= nil and nether.registered_portals[portal_name] ~= nil then -- players have built here - don't grief. -- but reigniting existing portals in portal rooms is fine - desirable even. local anchorPos, orientation, is_ignited = is_within_portal_frame(nether.registered_portals[portal_name], {x = target_x, y = y, z = target_z}) if anchorPos ~= nil then - if DEBUG then minetest.chat_send_all("Volume_is_natural check failed, but a portal frame is here " .. minetest.pos_to_string(anchorPos) .. ", so this is still a good target y level") end + if DEBUG then minetest.chat_send_all("volume_is_natural_and_unprotected check failed, but a portal frame is here " .. minetest.pos_to_string(anchorPos) .. ", so this is still a good target y level") end return y end end diff --git a/portal_api.txt b/portal_api.txt index b07e2cb..c5118f1 100644 --- a/portal_api.txt +++ b/portal_api.txt @@ -49,17 +49,22 @@ surface. Helper functions ---------------- -* `nether.volume_is_natural(minp, maxp)`: returns a boolean +* `nether.volume_is_natural_and_unprotected(minp, maxp, player_name)`: returns + a boolean. * use this when determining where to spawn a portal, to avoid overwriting player builds. It checks the area for any nodes that aren't ground or trees. Water will fail this test, unless it is unemerged. + * player_name is optional, providing it allows the player's own protected + areas to be treated as unprotected. -* `nether.find_surface_target_y(target_x, target_z, portal_name)`: returns a - suitable anchorPos +* `nether.find_surface_target_y(target_x, target_z, portal_name, player_name)`: + returns a suitable anchorPos * Can be used when implementing custom find_surface_anchorPos() functions * portal_name is optional, providing it allows existing portals on the surface to be reused. + * player_name is optional, providing it prevents the exclusion of surface + target areas which are protected by the player. * `nether.find_nearest_working_portal(portal_name, anchorPos, distance_limit, y_factor)`: returns (anchorPos, orientation), or nil if no portal was found within the @@ -208,7 +213,7 @@ Used by `nether.register_portal`. -- Ideally implementations are fast, as this function can be used to -- sift through a list of portals. - find_realm_anchorPos = function(surface_anchorPos), + find_realm_anchorPos = function(surface_anchorPos, player_name), -- Required. Return a position in the realm that a portal created at -- surface_anchorPos will link to. -- Return an anchorPos or (anchorPos, orientation) @@ -218,8 +223,10 @@ Used by `nether.register_portal`. -- orientation, otherwise the existing portal could be overwritten by -- a new one with the orientation of the surface portal. -- Return nil to prevent the portal from igniting. + -- player_name may be "", e.g. if the portal was ignited by a mesecon, + -- and is provided for use with volume_is_natural_and_unprotected() etc. - find_surface_anchorPos = function(realm_anchorPos), + find_surface_anchorPos = function(realm_anchorPos, player_name), -- Optional. If you don't implement this then a position near the -- surface will be picked. -- Return an anchorPos or (anchorPos, orientation) @@ -233,6 +240,8 @@ Used by `nether.register_portal`. -- orientation, otherwise the existing portal could be overwritten by -- a new one with the orientation of the realm portal. -- Return nil to prevent the portal from igniting. + -- player_name may be "", e.g. if the portal was ignited by a mesecon, + -- and is provided for use with volume_is_natural_and_unprotected() etc. on_run_wormhole = function(portalDef, anochorPos, orientation), -- invoked once per second per portal diff --git a/portal_examples.lua b/portal_examples.lua index 1a33943..ac71848 100644 --- a/portal_examples.lua +++ b/portal_examples.lua @@ -85,7 +85,7 @@ This portal is different to the others, rather than acting akin to a doorway it return pos.y > FLOATLAND_LEVEL - 200 end, - find_realm_anchorPos = function(surface_anchorPos) + find_realm_anchorPos = function(surface_anchorPos, player_name) -- TODO: Once paramat finishes adjusting the floatlands, implement a surface algorithm that finds land local destination_pos = {x = surface_anchorPos.x ,y = FLOATLAND_LEVEL + 2, z = surface_anchorPos.z} @@ -131,13 +131,13 @@ Due to such difficulties, we never learned what determines the direction and dis return true end, - find_realm_anchorPos = function(surface_anchorPos) + find_realm_anchorPos = function(surface_anchorPos, player_name) -- This function isn't needed, since this type of portal always goes to the surface minetest.log("error" , "find_realm_anchorPos called for surface portal") return {x=0, y=0, z=0} end, - find_surface_anchorPos = function(realm_anchorPos) + find_surface_anchorPos = function(realm_anchorPos, player_name) -- A portal definition doesn't normally need to provide a find_surface_anchorPos() function, -- since find_surface_target_y() will be used by default, but these portals travel around the -- surface (following a Moore curve) so will be calculating a different x and z to realm_anchorPos. @@ -192,7 +192,7 @@ Due to such difficulties, we never learned what determines the direction and dis end local destination_pos = {x = target_x + adj_x, y = 0, z = target_z + adj_z} - destination_pos.y = nether.find_surface_target_y(destination_pos.x, destination_pos.z, "surface_portal") + destination_pos.y = nether.find_surface_target_y(destination_pos.x, destination_pos.z, "surface_portal", player_name) return destination_pos end From e326a942661c8c449bb942968be55ce0000d5cb1 Mon Sep 17 00:00:00 2001 From: Treer Date: Sun, 26 Jul 2020 15:07:39 +1000 Subject: [PATCH 3/3] Add nether.debug() (#28) --- init.lua | 49 ++++++++++++++++++++++ portal_api.lua | 109 ++++++++++++++++++++++++++----------------------- 2 files changed, 106 insertions(+), 52 deletions(-) diff --git a/init.lua b/init.lua index 7497840..cf0123b 100644 --- a/init.lua +++ b/init.lua @@ -19,6 +19,13 @@ ]]-- +-- Set DEBUG_FLAGS to determine the behavior of nether.debug(): +-- 0 = off +-- 1 = print(...) +-- 2 = minetest.chat_send_all(...) +-- 4 = minetest.log("info", ...) +local DEBUG_FLAGS = 0 + local S if minetest.get_translator ~= nil then S = minetest.get_translator("nether") @@ -63,6 +70,48 @@ if nether.DEPTH_FLOOR + 1000 > nether.DEPTH_CEILING then end nether.DEPTH = nether.DEPTH_CEILING -- Deprecated, use nether.DEPTH_CEILING instead. + +-- A debug-print function that understands vectors etc. and does not +-- evaluate when debugging is turned off. +-- Works like string.format(), treating the message as a format string. +-- nils, tables, and vectors passed as arguments to nether.debug() are +-- converted to strings and can be included inside the message with %s +function nether.debug(message, ...) + + local args = {...} + local argCount = select("#", ...) + + for i = 1, argCount do + local arg = args[i] + if arg == nil then + -- convert nils to strings + args[i] = '' + elseif type(arg) == "table" then + local tableCount = 0 + for _,_ in pairs(arg) do tableCount = tableCount + 1 end + if tableCount == 3 and arg.x ~= nil and arg.y ~= nil and arg.z ~= nil then + -- convert vectors to strings + args[i] = minetest.pos_to_string(arg) + else + -- convert tables to strings + -- (calling function can use dump() if a multi-line listing is desired) + args[i] = string.gsub(dump(arg, ""), "\n", " ") + end + end + end + + local composed_message = string.format(message, unpack(args)) + + if math.floor(DEBUG_FLAGS / 1) % 2 == 1 then print(composed_message) end + if math.floor(DEBUG_FLAGS / 2) % 2 == 1 then minetest.chat_send_all(composed_message) end + if math.floor(DEBUG_FLAGS / 4) % 2 == 1 then minetest.log("info", composed_message) end +end +if DEBUG_FLAGS == 0 then + -- do as little evaluation as possible + nether.debug = function() end +end + + -- Load files dofile(nether.path .. "/portal_api.lua") dofile(nether.path .. "/nodes.lua") diff --git a/portal_api.lua b/portal_api.lua index c396b4f..f2780ce 100644 --- a/portal_api.lua +++ b/portal_api.lua @@ -23,8 +23,9 @@ ]]-- -local DEBUG = false -local DEBUG_IGNORE_MODSTORAGE = false -- setting true prevents portals from knowing where other portals are, forcing find_realm_anchorpos() etc. to be executed every time +-- setting DEBUG_IGNORE_MODSTORAGE true prevents portals from knowing where other +-- portals are, forcing find_realm_anchorpos() etc. to be executed every time. +local DEBUG_IGNORE_MODSTORAGE = false nether.registered_portals = {} nether.registered_portals_count = 0 @@ -662,8 +663,9 @@ nether.PortalShape_Platform = { -- Portal implementation functions -- -- =============================== -- +local S = nether.get_translator +local debugf = nether.debug local ignition_item_name -local S = nether.get_translator local mod_storage = minetest.get_mod_storage() local meseconsAvailable = minetest.get_modpath("mesecon") ~= nil and minetest.global_exists("mesecon") local book_added_as_treasure = false @@ -821,7 +823,7 @@ end local function store_portal_location_info(portal_name, anchorPos, orientation, ignited) if not DEBUG_IGNORE_MODSTORAGE then local key = minetest.pos_to_string(anchorPos) .. " is " .. portal_name - if DEBUG then minetest.chat_send_all("Adding/updating portal in mod_storage: " .. key) end + debugf("Adding/updating portal in mod_storage: " .. key) mod_storage:set_string( key, minetest.serialize({orientation = orientation, active = ignited}) @@ -834,7 +836,7 @@ end local function remove_portal_location_info(portal_name, anchorPos) if not DEBUG_IGNORE_MODSTORAGE then local key = minetest.pos_to_string(anchorPos) .. " is " .. portal_name - if DEBUG then minetest.chat_send_all("Removing portal from mod_storage: " .. key) end + debugf("Removing portal from mod_storage: " .. key) mod_storage:set_string(key, "") end end @@ -872,7 +874,7 @@ local function list_closest_portals(portal_definition, anchorPos, distance_limit local distance = math.hypot(y * y_factor, math.hypot(x, z)) if distance <= distance_limit or distance_limit < 0 then local info = minetest.deserialize(value) or {} - if DEBUG then minetest.chat_send_all("found " .. found_name .. " listed at distance " .. distance .. " (within " .. distance_limit .. ") from dest " .. minetest.pos_to_string(anchorPos) .. ", found: " .. minetest.pos_to_string(found_anchorPos) .. " orientation " .. info.orientation) end + debugf("found %s listed at distance %.2f (within %.2f) from dest %s, found: %s orientation %s", found_name, distance, distance_limit, anchorPos, found_anchorPos, info.orientation) info.anchorPos = found_anchorPos info.distance = distance result[distance] = info @@ -924,14 +926,14 @@ end function extinguish_portal(pos, node_name, frame_was_destroyed) -- mesecons seems to invoke action_off() 6 times every time you place a block? - if DEBUG then minetest.chat_send_all("extinguish_portal" .. minetest.pos_to_string(pos) .. " " .. node_name) end + debugf("extinguish_portal %s %s", pos, node_name) local meta = minetest.get_meta(pos) local p1 = minetest.string_to_pos(meta:get_string("p1")) local p2 = minetest.string_to_pos(meta:get_string("p2")) local target = minetest.string_to_pos(meta:get_string("target")) if p1 == nil or p2 == nil then - if DEBUG then minetest.chat_send_all(" no active portal found to extinguish") end + debugf(" no active portal found to extinguish") return false end @@ -983,7 +985,7 @@ function extinguish_portal(pos, node_name, frame_was_destroyed) end if target ~= nil then - if DEBUG then minetest.chat_send_all(" attempting to also extinguish target with wormholePos " .. minetest.pos_to_string(target)) end + debugf(" attempting to also extinguish target with wormholePos %s", target) extinguish_portal(target, node_name) end @@ -1000,7 +1002,8 @@ end -- Note: will extinguish any portal using the same nodes that are being set local function set_portal_metadata(portal_definition, anchorPos, orientation, destination_wormholePos, ignite) - if DEBUG then minetest.chat_send_all("set_portal_metadata(ignite=" .. tostring(ignite) .. ") at " .. minetest.pos_to_string(anchorPos) .. " orient " .. orientation .. ", setting to target " .. minetest.pos_to_string(destination_wormholePos)) end + ignite = ignite or false; + debugf("set_portal_metadata(ignite=%s) at %s orient %s, setting to target %s", ignite, anchorPos, orientation, destination_wormholePos) -- Portal position is stored in metadata as p1 and p2 to keep maps compatible with earlier versions of this mod. -- p1 is the bottom/west/south corner of the portal, and p2 is the opposite corner, together @@ -1028,7 +1031,7 @@ local function set_portal_metadata(portal_definition, anchorPos, orientation, de if existing_p1 ~= "" then local existing_p2 = meta:get_string("p2") if existing_p1 ~= p1_string or existing_p2 ~= p2_string then - if DEBUG then minetest.chat_send_all("set_portal_metadata() found existing metadata from another portal: existing_p1 " .. existing_p1 .. ", existing_p2" .. existing_p2 .. ", p1 " .. p1_string .. ", p2 " .. p2_string .. ", will existinguish existing portal...") end + debugf("set_portal_metadata() found existing metadata from another portal: existing_p1 %s, existing_p2 %s, p1 %s, p2 %s, will extinguish existing portal...", existing_p1, existing_p2, p1_string, p2_string) -- this node is already part of another portal, so extinguish that, because nodes only -- contain a link in the metadata to one portal, and being part of two allows a slew of bugs extinguish_portal(pos, node_name, false) @@ -1092,7 +1095,7 @@ local function is_portal_at_anchorPos(portal_definition, anchorPos, orientation, -- area isn't loaded, force loading/emerge of check area minetest.get_voxel_manip():read_from_map(check_pos, check_pos) foundName = minetest.get_node(check_pos).name - if DEBUG then minetest.chat_send_all("Forced loading of 'ignore' node at " .. minetest.pos_to_string(check_pos) .. ", got " .. foundName) end + debugf("Forced loading of 'ignore' node at %s, got %s", check_pos, foundName) if foundName ~= frame_node_name then nodes_are_valid = false @@ -1202,7 +1205,7 @@ local function build_portal(portal_definition, anchorPos, orientation, destinati function(pos) minetest.swap_node(pos, wormholeNode) end ) - if DEBUG then minetest.chat_send_all("Placed " .. portal_definition.name .. " portal schematic at " .. minetest.pos_to_string(portal_definition.shape.get_schematicPos_from_anchorPos(anchorPos, orientation)) .. ", orientation " .. orientation) end + debugf("Placed %s portal schematic at %s, orientation %s", portal_definition.name, portal_definition.shape.get_schematicPos_from_anchorPos(anchorPos, orientation), orientation) set_portal_metadata(portal_definition, anchorPos, orientation, destination_wormholePos) @@ -1216,7 +1219,7 @@ end -- Make portals immortal for ~20 seconds after creation local function remote_portal_checkup(elapsed, portal_definition, anchorPos, orientation, destination_wormholePos) - if DEBUG then minetest.chat_send_all("portal checkup at " .. elapsed .. " seconds") end + debugf("portal checkup at %d seconds", elapsed) local wormholePos = portal_definition.shape.get_wormholePos_from_anchorPos(anchorPos, orientation) local wormhole_node = minetest.get_node_or_nil(wormholePos) @@ -1231,7 +1234,7 @@ local function remote_portal_checkup(elapsed, portal_definition, anchorPos, orie -- ruh roh local message = "Newly created portal at " .. minetest.pos_to_string(anchorPos) .. " was overwritten. Attempting to recreate. Issue spotted after " .. elapsed .. " seconds" minetest.log("warning", message) - if DEBUG then minetest.chat_send_all("!!! " .. message) end + debugf("!!! " .. message) -- A pre-existing portal frame wouldn't have been immediately overwritten, so no need to check for one, just place the portal. build_portal(portal_definition, anchorPos, orientation, destination_wormholePos) @@ -1259,7 +1262,7 @@ end -- specified if an existing portal was already found there. local function locate_or_build_portal(portal_definition, suggested_wormholePos, suggested_orientation, destination_wormholePos) - if DEBUG then minetest.chat_send_all("locate_or_build_portal() called at wormholePos" .. minetest.pos_to_string(suggested_wormholePos) .. " with suggested orient " .. suggested_orientation .. ", targetted to " .. minetest.pos_to_string(destination_wormholePos)) end + debugf("locate_or_build_portal() called at wormholePos%s with suggested orient %s, targeted to %s", suggested_wormholePos, suggested_orientation, destination_wormholePos) local result_anchorPos; local result_orientation; @@ -1280,13 +1283,13 @@ local function locate_or_build_portal(portal_definition, suggested_wormholePos, if result_target ~= nil and vector.equals(result_target, destination_wormholePos) then -- It already links back to the portal the player is teleporting from, so don't -- extinguish it or the player's portal will also extinguish. - if DEBUG then minetest.chat_send_all(" Build unnecessary: already a lit portal that links back here at " .. minetest.pos_to_string(found_anchorPos) .. ", orientation " .. result_orientation) end + debugf(" Build unnecessary: already a lit portal that links back here at %s, orientation %s", found_anchorPos, result_orientation) else - if DEBUG then minetest.chat_send_all(" Build unnecessary: already a lit portal at " .. minetest.pos_to_string(found_anchorPos) .. ", orientation " .. result_orientation .. ", linking to " .. result_target_str .. ". Extinguishing...") end + debugf(" Build unnecessary: already a lit portal at %s, orientation %s, linking to %s. Extinguishing...", found_anchorPos, result_orientation, result_target_str) extinguish_portal(found_anchorPos, portal_definition.frame_node_name, false) end else - if DEBUG then minetest.chat_send_all(" Build unnecessary: already an unlit portal at " .. minetest.pos_to_string(found_anchorPos) .. ", orientation " .. result_orientation) end + debugf(" Build unnecessary: already an unlit portal at %s, orientation %s", found_anchorPos, result_orientation) end -- ignite the portal set_portal_metadata_and_ignite(portal_definition, result_anchorPos, result_orientation, destination_wormholePos) @@ -1308,7 +1311,7 @@ end local function ignite_portal(ignition_pos, player_name, ignition_node_name) if ignition_node_name == nil then ignition_node_name = minetest.get_node(ignition_pos).name end - if DEBUG then minetest.chat_send_all("IGNITE the " .. ignition_node_name .. " at " .. minetest.pos_to_string(ignition_pos)) end + debugf("IGNITE the %s at %s", ignition_node_name, ignition_pos) -- find which sort of portals are made from the node that was clicked on local portal_definition_list = list_portal_definitions_for_frame_node(ignition_node_name) @@ -1319,7 +1322,7 @@ local function ignite_portal(ignition_pos, player_name, ignition_node_name) -- check it was a portal frame that the player is trying to ignite local anchorPos, orientation, is_ignited = is_within_portal_frame(portal_definition, ignition_pos) if anchorPos == nil then - if DEBUG then minetest.chat_send_all("No " .. portal_definition.name .. " portal frame found at " .. minetest.pos_to_string(ignition_pos)) end + debugf("No %s portal frame found at ", portal_definition.name, ignition_pos) continue = true -- no portal is here, but perhaps there's more than one portal type we need to search for elseif is_ignited then -- Found a portal, check its metadata and timer is healthy. @@ -1331,10 +1334,10 @@ local function ignite_portal(ignition_pos, player_name, ignition_node_name) -- metadata is missing, the portal frame node must have been removed without calling -- on_destruct - perhaps by an ABM, then replaced - presumably by a player. -- allowing reigniting will repair the portal - if DEBUG then minetest.chat_send_all("Broken portal detected, allowing reignition/repair") end + debugf("Broken portal detected, allowing reignition/repair") repair = true else - if DEBUG then minetest.chat_send_all("This portal links to " .. meta:get_string("target") .. ". p1=" .. meta:get_string("p1") .. " p2=" .. meta:get_string("p2")) end + debugf("This portal links to %s. p1=%s p2=%s", meta:get_string("target"), meta:get_string("p1"), meta:get_string("p2")) -- Check the portal's timer is running, and fix if it's not. -- A portal's timer can stop running if the game is played without that portal type being @@ -1342,7 +1345,7 @@ local function ignite_portal(ignition_pos, player_name, ignition_node_name) -- (if this is a frequent problem, then change the value of "run_at_every_load" in the lbm) local timer = minetest.get_node_timer(get_timerPos_from_p1_and_p2(minetest.string_to_pos(p1), minetest.string_to_pos(p2))) if timer ~= nil and timer:get_timeout() == 0 then - if DEBUG then minetest.chat_send_all("Portal timer was not running: restarting the timer.") end + debugf("Portal timer was not running: restarting the timer.") timer:start(1) end end @@ -1351,7 +1354,7 @@ local function ignite_portal(ignition_pos, player_name, ignition_node_name) end if continue == false then - if DEBUG then minetest.chat_send_all("Found portal frame. Looked at " .. minetest.pos_to_string(ignition_pos) .. ", found at " .. minetest.pos_to_string(anchorPos) .. " orientation " .. orientation) end + debugf("Found portal frame. Looked at %s, found at %s orientation %s", ignition_pos, anchorPos, orientation) local destination_anchorPos, destination_orientation if portal_definition.is_within_realm(ignition_pos) then @@ -1359,15 +1362,17 @@ local function ignite_portal(ignition_pos, player_name, ignition_node_name) else destination_anchorPos, destination_orientation = portal_definition.find_realm_anchorPos(anchorPos, player_name or "") end - if DEBUG and destination_orientation == nil then minetest.chat_send_all("No destination_orientation given") end - if destination_orientation == nil then destination_orientation = orientation end + if destination_orientation == nil then + debugf("No destination_orientation given") + destination_orientation = orientation + end if destination_anchorPos == nil then - if DEBUG then minetest.chat_send_all("No portal destination available here!") end + debugf("No portal destination available here!") return false else local destination_wormholePos = portal_definition.shape.get_wormholePos_from_anchorPos(destination_anchorPos, destination_orientation) - if DEBUG then minetest.chat_send_all("Destination set to " .. minetest.pos_to_string(destination_anchorPos)) end + debugf("Destination set to %s", destination_anchorPos) -- ignition/BURN_BABY_BURN set_portal_metadata_and_ignite(portal_definition, anchorPos, orientation, destination_wormholePos) @@ -1406,7 +1411,7 @@ local function ensure_remote_portal_then_teleport(playerName, portal_definition, local local_p1, local_p2 = portal_definition.shape:get_p1_and_p2_from_anchorPos(local_anchorPos, local_orientation) local p1_at_playerPos = minetest.string_to_pos(meta:get_string("p1")) if p1_at_playerPos == nil or not vector.equals(local_p1, p1_at_playerPos) then - if DEBUG then minetest.chat_send_all("the player already teleported from " .. minetest.pos_to_string(local_anchorPos) .. ", and is now standing in a different portal - " .. meta:get_string("p1")) end + debugf("the player already teleported from %s, and is now standing in a different portal - %s", local_anchorPos, meta:get_string("p1")) return -- the player already teleported, and is now standing in a different portal end @@ -1414,7 +1419,7 @@ local function ensure_remote_portal_then_teleport(playerName, portal_definition, if dest_wormhole_node == nil then -- area not emerged yet, delay and retry - if DEBUG then minetest.chat_send_all("ensure_remote_portal_then_teleport() could not find anything yet at " .. minetest.pos_to_string(destination_wormholePos)) end + debugf("ensure_remote_portal_then_teleport() could not find anything yet at %s", destination_wormholePos) minetest.after(1, ensure_remote_portal_then_teleport, playerName, portal_definition, local_anchorPos, local_orientation, destination_wormholePos) else local local_wormholePos = portal_definition.shape.get_wormholePos_from_anchorPos(local_anchorPos, local_orientation) @@ -1431,9 +1436,9 @@ local function ensure_remote_portal_then_teleport(playerName, portal_definition, local remoteMeta = minetest.get_meta(destination_wormholePos) local remoteTarget = minetest.string_to_pos(remoteMeta:get_string("target")) if remoteTarget == nil then - if DEBUG then minetest.chat_send_all("Failed to test whether target portal links back to this one") end + debugf("Failed to test whether target portal links back to this one") elseif not vector.equals(remoteTarget, local_wormholePos) then - if DEBUG then minetest.chat_send_all("Target portal is already linked, extinguishing then relighting to point back at this one") end + debugf("Target portal is already linked, extinguishing then relighting to point back at this one") extinguish_portal(remoteTarget, portal_definition.frame_node_name, false) set_portal_metadata_and_ignite( portal_definition, @@ -1443,7 +1448,7 @@ local function ensure_remote_portal_then_teleport(playerName, portal_definition, ) end - if DEBUG then minetest.chat_send_all("Teleporting player from wormholePos" .. minetest.pos_to_string(local_wormholePos) .. " to wormholePos" .. minetest.pos_to_string(destination_wormholePos)) end + debugf("Teleporting player from wormholePos%s to wormholePos%s", local_wormholePos, destination_wormholePos) -- play the teleport sound if portal_definition.sounds.teleport ~= nil then @@ -1470,7 +1475,7 @@ local function ensure_remote_portal_then_teleport(playerName, portal_definition, -- which will leave a confused player. -- I don't think this is worth preventing, but I document it incase someone describes entering a portal -- and then the portal turning off. - if DEBUG then minetest.chat_send_all("ensure_remote_portal_then_teleport() saw " .. dest_wormhole_node.name .. " at " .. minetest.pos_to_string(destination_wormholePos) .. " rather than a wormhole. Calling locate_or_build_portal()") end + debugf("ensure_remote_portal_then_teleport() saw %s at %s rather than a wormhole. Calling locate_or_build_portal()", dest_wormhole_node.name, destination_wormholePos) local new_dest_anchorPos, new_dest_orientation = locate_or_build_portal(portal_definition, destination_wormholePos, local_orientation, local_wormholePos) local new_dest_wormholePos = portal_definition.shape.get_wormholePos_from_anchorPos(new_dest_anchorPos, new_dest_orientation) @@ -1487,10 +1492,10 @@ local function ensure_remote_portal_then_teleport(playerName, portal_definition, -- local portal to also be extinguished. local message = "Local portal at " .. minetest.pos_to_string(local_anchorPos) .. " was extinguished while linking to existing portal at " .. minetest.pos_to_string(new_dest_anchorPos) minetest.log("error", message) - if DEBUG then minetest.chat_send_all("!ERROR! - " .. message) end + debugf("!ERROR! - " .. message) else destination_wormholePos = new_dest_wormholePos - if DEBUG then minetest.chat_send_all(" updating target to where remote portal was found - " .. minetest.pos_to_string(destination_wormholePos)) end + debugf(" updating target to where remote portal was found - %s", destination_wormholePos) set_portal_metadata( portal_definition, @@ -1825,22 +1830,22 @@ function register_frame_node(frame_node_name) extended_node_def.replaced_by_portalapi.mesecons = extended_node_def.mesecons extended_node_def.mesecons = {effector = { action_on = function (pos, node) - if DEBUG then minetest.chat_send_all("portal frame material: mesecons action ON") end + debugf("portal frame material: mesecons action ON") ignite_portal(pos, nil, node.name) end, action_off = function (pos, node) - if DEBUG then minetest.chat_send_all("portal frame material: mesecons action OFF") end + debugf("portal frame material: mesecons action OFF") extinguish_portal(pos, node.name, false) end }} extended_node_def.replaced_by_portalapi.on_destruct = extended_node_def.on_destruct extended_node_def.on_destruct = function(pos) - if DEBUG then minetest.chat_send_all("portal frame material: destruct") end + debugf("portal frame material: destruct") extinguish_portal(pos, frame_node_name, true) end extended_node_def.replaced_by_portalapi.on_blast = extended_node_def.on_blast extended_node_def.on_blast = function(pos, intensity) - if DEBUG then minetest.chat_send_all("portal frame material: blast") end + debugf("portal frame material: blast") extinguish_portal(pos, frame_node_name, extended_node_def.replaced_by_portalapi.on_blast == nil) if extended_node_def.replaced_by_portalapi.on_blast ~= nil then extended_node_def.replaced_by_portalapi.on_blast(pos, intensity) @@ -1936,9 +1941,9 @@ minetest.register_lbm({ local timer = minetest.get_node_timer(timerPos) if timer ~= nil then timer:start(1) - if DEBUG then minetest.chat_send_all("LBM started portal timer " .. minetest.pos_to_string(timerPos)) end - elseif DEBUG then - minetest.chat_send_all("get_node_timer" .. minetest.pos_to_string(timerPos) .. " returned null") + debugf("LBM started portal timer %s", timerPos) + else + debugf("get_node_timer%s returned null", timerPos) end end end @@ -2193,7 +2198,7 @@ function nether.volume_is_natural_and_unprotected(minp, maxp, player_name) local vi = area:index(minp.x, y, z) for x = minp.x, maxp.x do local id = data[vi] -- Existing node - if DEBUG and id == nil then minetest.chat_send_all("nil block at index " .. vi) end + if id == nil then debugf("nil block at index " .. vi) end if id ~= c_air and id ~= c_ignore and id ~= nil then -- checked for common natural or not emerged local name = minetest.get_name_from_content_id(id) local nodedef = minetest.registered_nodes[name] @@ -2201,7 +2206,7 @@ function nether.volume_is_natural_and_unprotected(minp, maxp, player_name) -- trees are natural but not "ground content" local node_groups = nodedef.groups if node_groups == nil or (node_groups.tree == nil and node_groups.leaves == nil and node_groups.leafdecay == nil) then - if DEBUG then minetest.chat_send_all("volume_is_natural_and_unprotected() found unnatural node " .. name) end + debugf("volume_is_natural_and_unprotected() found unnatural node %s", name) return false end end @@ -2212,11 +2217,11 @@ function nether.volume_is_natural_and_unprotected(minp, maxp, player_name) end if minetest.is_area_protected(minp, maxp, player_name or "") then - if DEBUG then minetest.chat_send_all("Volume is protected " .. minetest.pos_to_string(minp) .. "-" .. minetest.pos_to_string(maxp)) end + debugf("Volume is protected %s-%s", minp, maxp) return false; end - if DEBUG then minetest.chat_send_all("Volume is natural and unprotected for player '" .. (player_name or "") .. "', " .. minetest.pos_to_string(minp) .. "-" .. minetest.pos_to_string(maxp)) end + debugf("Volume is natural and unprotected for player '%s', %s-%s", player_name, minp, maxp) return true end @@ -2227,7 +2232,7 @@ function nether.volume_is_natural(minp, maxp) local stack = debug.traceback("", 2); local calling_func = (string.split(stack, "\n", false, 2, false)[2] or ""):trim() minetest.log("warning", - "Deprecated function \"nether.volume_is_natural()\" invoked. Use \"nether.volume_is_natural_and_unprotected()\" instead. " .. + "Deprecated function \"nether.volume_is_natural()\" invoked, use \"nether.volume_is_natural_and_unprotected()\" instead. " .. calling_func) nether.deprecation_warning_volume_is_natural = true; end @@ -2322,7 +2327,7 @@ function nether.find_surface_target_y(target_x, target_z, portal_name, player_na -- but reigniting existing portals in portal rooms is fine - desirable even. local anchorPos, orientation, is_ignited = is_within_portal_frame(nether.registered_portals[portal_name], {x = target_x, y = y, z = target_z}) if anchorPos ~= nil then - if DEBUG then minetest.chat_send_all("volume_is_natural_and_unprotected check failed, but a portal frame is here " .. minetest.pos_to_string(anchorPos) .. ", so this is still a good target y level") end + debugf("volume_is_natural_and_unprotected check failed, but a portal frame is here %s, so this is still a good target y level", anchorPos) return y end end @@ -2351,7 +2356,7 @@ function nether.find_nearest_working_portal(portal_name, anchorPos, distance_lim for _, dist in ipairs(dist_list) do local portal_info = contenders[dist] - if DEBUG then minetest.chat_send_all("checking portal from mod_storage at " .. minetest.pos_to_string(portal_info.anchorPos) .. " orientation " .. portal_info.orientation) end + debugf("checking portal from mod_storage at %s orientation %s", portal_info.anchorPos, portal_info.orientation) -- the mod_storage list of portals is unreliable - e.g. it won't know if inactive portals have been -- destroyed, so check the portal is still there @@ -2360,7 +2365,7 @@ function nether.find_nearest_working_portal(portal_name, anchorPos, distance_lim if portalFound then return portal_info.anchorPos, portal_info.orientation else - if DEBUG then minetest.chat_send_all("Portal wasn't found, removing portal from mod_storage at " .. minetest.pos_to_string(portal_info.anchorPos) .. " orientation " .. portal_info.orientation) end + debugf("Portal wasn't found, removing portal from mod_storage at %s orientation %s", portal_info.anchorPos, portal_info.orientation) -- The portal at that location must have been destroyed remove_portal_location_info(portal_name, portal_info.anchorPos) end