Unlinks target portal if it's linked to a different portal

This is effectively a missing part to the change that made locate_or_build_portal() enforce that portals only link together in mutual pairs. As target portals that didn't need to be located or built we not being updated to link back to where the player travelled from.

Also
* implements events: on_run_wormhole, on_extinguish
* adds a lot of debug info
This commit is contained in:
Treer 2019-07-17 23:07:05 +10:00 committed by SmallJoker
parent 6401052f92
commit 52b20925d5
2 changed files with 49 additions and 9 deletions

View File

@ -361,8 +361,11 @@ local function list_closest_portals(portal_definition, anchorPos, distance_limit
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
-- 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
-- they define the bounding volume for the portal.
@ -385,11 +388,11 @@ local function set_portal_metadata(portal_definition, anchorPos, orientation, de
local existing_p1 = meta:get_string("p1")
if existing_p1 ~= "" then
local existing_p2 = meta:get_string("p2")
if DEBUG then minetest.chat_send_all("existing_p1 " .. existing_p1 .. ", existing_p2" .. existing_p2 .. ", p1 " .. p1_string .. ", p2 " .. p2_string) end
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
-- 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)
extinguish_portal(pos, node_name, false)
-- clear the metadata to avoid causing a loop if extinguish_portal() fails on this node (e.g. it only works on frame nodes)
meta:set_string("p1", nil)
@ -727,6 +730,7 @@ end
local function ignite_portal(ignition_pos, 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
-- 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)
@ -760,7 +764,7 @@ local function ignite_portal(ignition_pos, ignition_node_name)
if destination_orientation == nil then destination_orientation = orientation end
local destination_wormholePos = portal_definition.shape.get_wormholePos_from_anchorPos(destination_anchorPos, destination_orientation)
if DEBUG then minetest.chat_send_all("Destinaton set to " .. minetest.pos_to_string(destination_anchorPos)) end
if DEBUG then minetest.chat_send_all("Destination set to " .. minetest.pos_to_string(destination_anchorPos)) end
-- ignition/BURN_BABY_BURN
set_portal_metadata_and_ignite(portal_definition, anchorPos, orientation, destination_wormholePos)
@ -782,6 +786,7 @@ extinguish_portal = function(pos, node_name, frame_was_destroyed) -- assigned ra
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
return
end
@ -822,7 +827,14 @@ extinguish_portal = function(pos, node_name, frame_was_destroyed) -- assigned ra
end
end
if target ~= nil then extinguish_portal(target, node_name) 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
extinguish_portal(target, node_name)
end
if portal_definition.on_extinguish ~= nil then
portal_definition.on_extinguish(portal_definition, anchorPos, orientation)
end
end
@ -859,6 +871,23 @@ local function ensure_remote_portal_then_teleport(player, portal_definition, loc
local destination_orientation = get_orientation_from_param2(dest_wormhole_node.param2)
portal_definition.shape.disable_portal_trap(destination_anchorPos, destination_orientation)
-- if the portal is already linked to a different portal then extinguish the other portal and
-- update the target portal to point back at this one
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
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
extinguish_portal(remoteTarget, portal_definition.frame_node_name, false)
set_portal_metadata_and_ignite(
portal_definition,
destination_anchorPos,
destination_orientation,
local_wormholePos
)
end
-- rotate the player if the destination portal is a different orientation
local rotation_angle = math.rad(destination_orientation - local_orientation)
local offset = vector.subtract(playerPos, local_wormholePos) -- preserve player's position in the portal
@ -965,6 +994,10 @@ function run_wormhole(pos, time_elapsed)
else
local anchorPos, orientation = portal_definition.shape.get_anchorPos_and_orientation_from_p1_and_p2(p1, p2)
portal_definition.shape.apply_func_to_wormhole_nodes(anchorPos, orientation, run_wormhole_node_func)
if portal_definition.on_run_wormhole ~= nil then
portal_definition.on_run_wormhole(portal_definition, anchorPos, orientation)
end
end
end
end
@ -1068,14 +1101,17 @@ 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
ignite_portal(pos, node.name)
end,
action_off = function (pos, node)
if DEBUG then minetest.chat_send_all("portal frame material: mesecons action OFF") end
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
extinguish_portal(pos, frame_node_name, true)
end
extended_node_def.replaced_by_portalapi.on_timer = extended_node_def.on_timer

View File

@ -96,9 +96,13 @@ Used by `nether.register_portal`.
-- If orientation is not specified then the orientation of the realm
-- portal will be used.
on_run_wormhole,
on_ignite,
on_extinguish,
on_player_teleported,
on_created
on_run_wormhole = function(portalDef, anochorPos, orientation)
-- invoked once per second per portal
on_extinguish = function(portalDef, anochorPos, orientation)
-- invoked when a portal is extinguished, including when the portal
-- it connected to was extinguished.
todo: on_ignite = function(portalDef, anochorPos, orientation)
todo: on_player_teleported = function(portalDef, oldPos, newPos)
todo: on_created = function(portalDef, anochorPos, orientation)
}