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
This commit is contained in:
Treer 2020-07-26 14:34:06 +10:00 committed by GitHub
parent 8769593d6f
commit 5b3b56ebec
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 140 additions and 53 deletions

View File

@ -23,6 +23,7 @@ read_globals = {
"PseudoRandom", "PseudoRandom",
"stairs", "stairs",
"stairsplus", "stairsplus",
"string.split",
table = { fields = { "copy", "getn" } }, table = { fields = { "copy", "getn" } },
"vector", "vector",
"VoxelArea", "VoxelArea",

View File

@ -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_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) 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) 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 end
nether.DEPTH = nether.DEPTH_CEILING -- Deprecated, use nether.DEPTH_CEILING instead. 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 return pos.y < nether.DEPTH_CEILING
end, 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 -- divide x and z by a factor of 8 to implement Nether fast-travel
local destination_pos = vector.divide(surface_anchorPos, nether.FASTTRAVEL_FACTOR) local destination_pos = vector.divide(surface_anchorPos, nether.FASTTRAVEL_FACTOR)
destination_pos.x = math.floor(0.5 + destination_pos.x) -- round to int 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 return existing_portal_location, existing_portal_orientation
else else
local start_y = nether.DEPTH_CEILING - math.random(500, 1500) -- Search starting altitude 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 return destination_pos
end end
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, -- 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 -- since find_surface_target_y() will be used by default, but Nether portals also scale position
-- to create fast-travel. -- 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 if existing_portal_location ~= nil then
return existing_portal_location, existing_portal_orientation return existing_portal_location, existing_portal_orientation
else 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 return destination_pos
end end
end, end,

View File

@ -465,10 +465,15 @@ end
-- use knowledge of the nether mapgen algorithm to return a suitable ground level for placing a portal. -- 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 nobj_cave_point = minetest.get_perlin(np_cave)
local air = 0 -- Consecutive air nodes found 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 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}) 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 air = air + 1
else -- Not cavern, check if 4 nodes of space above else -- Not cavern, check if 4 nodes of space above
if air >= 4 then if air >= 4 then
local portal_y = y + 1
-- Check volume for non-natural nodes -- Check volume for non-natural nodes
local minp = {x = target_x - 1, y = y , z = target_z - 2} minp.y = minp_schem.y + portal_y
local maxp = {x = target_x + 2, y = y + 4, z = target_z + 2} maxp.y = maxp_schem.y + portal_y
if nether.volume_is_natural(minp, maxp) then if nether.volume_is_natural_and_unprotected(minp, maxp, player_name) then
return y + 1 return portal_y
else -- Restart search a little lower 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 end
else -- Not enough space, reset air to zero else -- Not enough space, reset air to zero
air = 0 air = 0

View File

@ -201,24 +201,30 @@ end)
-- use knowledge of the nether mapgen algorithm to return a suitable ground level for placing a portal. -- 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 nobj_cave_point = minetest.get_perlin(np_cave)
local air = 0 -- Consecutive air nodes found 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}) local nval_cave = nobj_cave_point:get3d({x = target_x, y = y, z = target_z})
if nval_cave > TCAVE then -- Cavern if nval_cave > TCAVE then -- Cavern
air = air + 1 air = air + 1
else -- Not cavern, check if 4 nodes of space above else -- Not cavern, check if 4 nodes of space above
if air >= 4 then if air >= 4 then
local portal_y = y + 1
-- Check volume for non-natural nodes -- Check volume for non-natural nodes
local minp = {x = target_x - 1, y = y , z = target_z - 2} minp.y = minp_schem.y + portal_y
local maxp = {x = target_x + 2, y = y + 4, z = target_z + 2} maxp.y = maxp_schem.y + portal_y
if nether.volume_is_natural(minp, maxp) then if nether.volume_is_natural_and_unprotected(minp, maxp, player_name) then
return y + 1 return portal_y
else -- Restart search a little lower 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 end
else -- Not enough space, reset air to zero else -- Not enough space, reset air to zero
air = 0 air = 0
@ -226,5 +232,5 @@ function nether.find_nether_ground_y(target_x, target_z, start_y)
end end
end end
return start_y -- Fallback return math.max(start_y, NETHER_FLOOR + BLEND) -- Fallback
end end

View File

@ -1303,8 +1303,9 @@ end
-- invoked when a player attempts to turn obsidian nodes into an open portal -- 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 -- 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 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 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 local destination_anchorPos, destination_orientation
if portal_definition.is_within_realm(ignition_pos) then 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 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 end
if DEBUG and destination_orientation == nil then minetest.chat_send_all("No destination_orientation given") 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 destination_orientation = orientation end
@ -1825,7 +1826,7 @@ function register_frame_node(frame_node_name)
extended_node_def.mesecons = {effector = { extended_node_def.mesecons = {effector = {
action_on = function (pos, node) action_on = function (pos, node)
if DEBUG then minetest.chat_send_all("portal frame material: mesecons action ON") end 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, end,
action_off = function (pos, node) action_off = function (pos, node)
if DEBUG then minetest.chat_send_all("portal frame material: mesecons action OFF") end 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 end
if portaldef.find_surface_anchorPos == nil then -- default to using find_surface_target_y() 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 destination_pos = {x = pos.x, y = 0, z = pos.z}
local existing_portal_location, existing_portal_orientation = local existing_portal_location, existing_portal_orientation =
@ -2089,7 +2090,7 @@ function nether.register_portal(name, portaldef)
if existing_portal_location ~= nil then if existing_portal_location ~= nil then
return existing_portal_location, existing_portal_orientation return existing_portal_location, existing_portal_orientation
else 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 return destination_pos
end end
end end
@ -2153,10 +2154,10 @@ end
function nether.register_portal_ignition_item(item_name, ignition_failure_sound) function nether.register_portal_ignition_item(item_name, ignition_failure_sound)
minetest.override_item(item_name, { minetest.override_item(item_name, {
on_place = function(stack, _, pt) on_place = function(stack, placer, pt)
local done = false local done = false
if pt.under and nether.is_frame_node[minetest.get_node(pt.under).name] then 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 if done and not minetest.settings:get_bool("creative_mode") then
stack:take_item() stack:take_item()
end end
@ -2175,22 +2176,22 @@ end
-- use this when determining where to spawn a portal, to avoid overwriting player builds -- 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. -- 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) -- (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_air = minetest.get_content_id("air")
local c_ignore = minetest.get_content_id("ignore") local c_ignore = minetest.get_content_id("ignore")
local vm = minetest.get_voxel_manip() local vm = minetest.get_voxel_manip()
local pos1 = {x = minp.x, y = minp.y, z = minp.z} local emin, emax = vm:read_from_map(minp, maxp)
local pos2 = {x = maxp.x, y = maxp.y, z = maxp.z}
local emin, emax = vm:read_from_map(pos1, pos2)
local area = VoxelArea:new({MinEdge = emin, MaxEdge = emax}) local area = VoxelArea:new({MinEdge = emin, MaxEdge = emax})
local data = vm:get_data() local data = vm:get_data()
for z = pos1.z, pos2.z do for z = minp.z, maxp.z do
for y = pos1.y, pos2.y do for y = minp.y, maxp.y do
local vi = area:index(pos1.x, y, z) local vi = area:index(minp.x, y, z)
for x = pos1.x, pos2.x do for x = minp.x, maxp.x do
local id = data[vi] -- Existing node local id = data[vi] -- Existing node
if DEBUG and id == nil then minetest.chat_send_all("nil block at index " .. vi) end 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 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" -- trees are natural but not "ground content"
local node_groups = nodedef.groups 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 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 return false
end end
end end
@ -2210,13 +2211,73 @@ function nether.volume_is_natural(minp, maxp)
end end
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 return true
end 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 -- 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. -- portal_name is optional, providing it allows existing portals on the surface to be reused, and
function nether.find_surface_target_y(target_x, target_z, portal_name) -- 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()") 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
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 for y = start_y, start_y - 256, -16 do
-- Check volume for non-natural nodes -- Check volume for non-natural nodes
local minp = {x = target_x - 1, y = y - 1, z = target_z - 2} minp.y = minp_schem.y + y
local maxp = {x = target_x + 2, y = y + 3, z = target_z + 2} maxp.y = maxp_schem.y + y
if nether.volume_is_natural(minp, maxp) then if nether.volume_is_natural_and_unprotected(minp, maxp, player_name) then
return y return y
elseif portal_name ~= nil and nether.registered_portals[portal_name] ~= nil then elseif portal_name ~= nil and nether.registered_portals[portal_name] ~= nil then
-- players have built here - don't grief. -- players have built here - don't grief.
-- but reigniting existing portals in portal rooms is fine - desirable even. -- 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}) 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 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 return y
end end
end end

View File

@ -49,17 +49,22 @@ surface.
Helper functions 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 * 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 player builds. It checks the area for any nodes that aren't ground or
trees. trees.
Water will fail this test, unless it is unemerged. 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 * `nether.find_surface_target_y(target_x, target_z, portal_name, player_name)`:
suitable anchorPos returns a suitable anchorPos
* Can be used when implementing custom find_surface_anchorPos() functions * Can be used when implementing custom find_surface_anchorPos() functions
* portal_name is optional, providing it allows existing portals on the * portal_name is optional, providing it allows existing portals on the
surface to be reused. 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 * `nether.find_nearest_working_portal(portal_name, anchorPos, distance_limit, y_factor)`: returns
(anchorPos, orientation), or nil if no portal was found within the (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 -- Ideally implementations are fast, as this function can be used to
-- sift through a list of portals. -- 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 -- Required. Return a position in the realm that a portal created at
-- surface_anchorPos will link to. -- surface_anchorPos will link to.
-- Return an anchorPos or (anchorPos, orientation) -- Return an anchorPos or (anchorPos, orientation)
@ -218,8 +223,10 @@ Used by `nether.register_portal`.
-- orientation, otherwise the existing portal could be overwritten by -- orientation, otherwise the existing portal could be overwritten by
-- a new one with the orientation of the surface portal. -- a new one with the orientation of the surface portal.
-- Return nil to prevent the portal from igniting. -- 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 -- Optional. If you don't implement this then a position near the
-- surface will be picked. -- surface will be picked.
-- Return an anchorPos or (anchorPos, orientation) -- Return an anchorPos or (anchorPos, orientation)
@ -233,6 +240,8 @@ Used by `nether.register_portal`.
-- orientation, otherwise the existing portal could be overwritten by -- orientation, otherwise the existing portal could be overwritten by
-- a new one with the orientation of the realm portal. -- a new one with the orientation of the realm portal.
-- Return nil to prevent the portal from igniting. -- 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), on_run_wormhole = function(portalDef, anochorPos, orientation),
-- invoked once per second per portal -- invoked once per second per portal

View File

@ -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 return pos.y > FLOATLAND_LEVEL - 200
end, 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 -- 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} 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 return true
end, 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 -- 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") minetest.log("error" , "find_realm_anchorPos called for surface portal")
return {x=0, y=0, z=0} return {x=0, y=0, z=0}
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, -- 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 -- 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. -- 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 end
local destination_pos = {x = target_x + adj_x, y = 0, z = target_z + adj_z} 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 return destination_pos
end end