From 1c033a048f169d46291ba32b16d3bbd722043663 Mon Sep 17 00:00:00 2001 From: Deathwing777 <160651137+Deathwing777@users.noreply.github.com> Date: Thu, 29 Feb 2024 12:05:03 -0800 Subject: [PATCH] Helper functions for other mods and an obsidian portal bugfix (#15) * The obsidian portal is the first way for a player to reach the nether, so if damage is enabled and `nether.trap_players` is disabled, the obsidian portal should teleport the player instead of killing him/her since after death he/she respawns in the overworld and not in the nether. A small change in `obsi_teleport_player` fixes this problem. Fixes #16. * There exist other mods which need to check if players are in the nether and teleport them to/from the nether, so we add four helper functions: `nether.is_player_in_nether`, `nether.is_player_trapped_in_nether`. `nether.external_nether_teleport` and `nether.registry_update`. Fixes #14. * Add the `in_hell`, `trapped_in_hell` and `update_hells_registry` chat commands, which can be used for debugging * `players_in_nether` has no meaningful effect if `nether.trap_players` is disabled, so we rename it to `players_trapped_in_nether`. * Add `nether.bottom`, which approximately corresponds to the lower end of the nether --- nether/init.lua | 3 + nether/portal.lua | 155 +++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 144 insertions(+), 14 deletions(-) diff --git a/nether/init.lua b/nether/init.lua index 57e7acb..0e78bb1 100644 --- a/nether/init.lua +++ b/nether/init.lua @@ -52,6 +52,9 @@ nether.start = f_h_max+100 -- Height of the nether (bottom of the nether is nether_middle - NETHER_HEIGHT) local NETHER_HEIGHT = 30 +-- bottom height of the nether. +nether.bottom = nether_middle - NETHER_HEIGHT - 100 + -- Maximum amount of randomness in the map generation local NETHER_RANDOM = 2 diff --git a/nether/portal.lua b/nether/portal.lua index 7f08a85..d8b325b 100644 --- a/nether/portal.lua +++ b/nether/portal.lua @@ -11,7 +11,7 @@ minetest.after(5, function() end) local save_path = minetest.get_worldpath() .. "/nether_players" -local players_in_nether = {} +local players_trapped_in_nether = {} -- Load the list of players which are trapped in the nether -- (or would be trapped if nether.trap_players was true) @@ -23,7 +23,7 @@ do if contents then local playernames = string.split(contents, " ") for i = 1,#playernames do - players_in_nether[playernames[i]] = true + players_trapped_in_nether[playernames[i]] = true end end end @@ -31,7 +31,7 @@ end local function save_nether_players() local playernames,n = {},1 - for name in pairs(players_in_nether) do + for name in pairs(players_trapped_in_nether) do playernames[n] = name n = n+1 end @@ -41,6 +41,17 @@ local function save_nether_players() io.close(f) end +-- Nether aware mods will need to know if a player is in the nether. +function nether.is_player_in_nether(player) + local pos = player:get_pos() + return (pos.y < nether.start) and (pos.y >= nether.bottom) +end + +-- For testing nether trap state tracking. +function nether.is_player_trapped_in_nether(player) + return players_trapped_in_nether[player:get_player_name()] +end + local update_background if nether.trap_players then function update_background(player, down) @@ -54,6 +65,36 @@ else function update_background()end end +-- Nether aware mods may have other means of moving players between the Nether +-- and Overworld, and if so, they should tell us about it so we can keep track +-- of the player state. +function nether.external_nether_teleport(player, pos) + if not nether.trap_players then + player:set_pos(pos) + return + end + local destination_in_nether = (pos.y < nether.start) and (pos.y >= nether.bottom) + update_background(player, destination_in_nether) + local pname = player:get_player_name() + players_trapped_in_nether[pname] = destination_in_nether or nil + player:set_pos(pos) +end + +-- Has the player dug their way out of the nether? +-- Has nether.trap_players been disabled? +function nether.registry_update(player) + local pos = player:get_pos() + local in_nether = (pos.y < nether.start) and (pos.y >= nether.bottom) + local pname = player:get_player_name() + if nether.trap_players then + players_trapped_in_nether[pname] = in_nether or nil + update_background(player, in_nether) + elseif players_trapped_in_nether[pname] then + players_trapped_in_nether[pname] = nil + update_background(player, false) + end +end + -- returns nodename if area is generated, else calls generation function local function generated_or_generate(pos) local node = minetest.get_node_or_nil(pos) @@ -79,11 +120,12 @@ end -- used for obsidian portal local function obsidian_teleport(player, pname, target) - minetest.chat_send_player(pname, "For any reason you arrived here. Type " .. + minetest.chat_send_player(pname, "For some reason you arrived here. Type " .. "/nether_help to find out things like craft recipes.") - players_in_nether[pname] = true + players_trapped_in_nether[pname] = true save_nether_players() update_background(player, true) + if target then player:set_pos(target) else @@ -94,14 +136,14 @@ end -- teleports players to nether or helps it local function player_to_nether(player, pos) local pname = player:get_player_name() - players_in_nether[pname] = true + players_trapped_in_nether[pname] = true save_nether_players() update_background(player, true) if pos then player:set_pos(pos) return end - minetest.chat_send_player(pname, "For any reason you arrived here. " .. + minetest.chat_send_player(pname, "For some reason you arrived here. " .. "Type /nether_help to find out things like craft recipes.") if nether.trap_players then player:set_hp(0) @@ -113,8 +155,8 @@ end local function player_from_nether(player, pos) local pname = player:get_player_name() - if players_in_nether[pname] then - players_in_nether[pname] = nil + if players_trapped_in_nether[pname] then + players_trapped_in_nether[pname] = nil save_nether_players() end update_background(player, false) @@ -176,13 +218,98 @@ minetest.register_chatcommand("from_hell", { end }) +-- Useful for debugging Nether player state tracking. Written by Deathwing777 +minetest.register_chatcommand("in_hell", { + params = "[]", + description = "Is the player in hell?", + func = function(name, pname) + if not minetest.check_player_privs(name, {nether=true}) then + return false, + "You need the nether priv to execute this chatcommand." + end + if not player_exists(pname) then + pname = name + end + local player = minetest.get_player_by_name(pname) + if not player then + return false, "Something went wrong." + end + + local status = pname.." is in the " + if nether.is_player_in_nether(player) then + status = status.."NETHER!" + else + status = status.."OVERWORLD!" + end + + return true, status + end +}) + +-- Useful for debugging Nether player state tracking. Written by Deathwing777 +minetest.register_chatcommand("trapped_in_hell", { + params = "[]", + description = "Is the player trapped in hell?", + func = function(name, pname) + if not minetest.check_player_privs(name, {nether=true}) then + return false, + "You need the nether priv to execute this chatcommand." + end + if not player_exists(pname) then + pname = name + end + local player = minetest.get_player_by_name(pname) + if not player then + return false, "Something went wrong." + end + + local status = pname + if nether.is_player_trapped_in_nether(player) then + status = status.." is TRAPPED in nether!" + else + status = status.." is NOT trapped in nether!" + end + + return true, status + end +}) + +-- Useful for debugging Nether player state tracking. Written by Deathwing777 +minetest.register_chatcommand("update_hells_registry", { + params = "[]", + description = "Update player state if they got to or from the nether in another way.", + func = function(name, pname) + if not minetest.check_player_privs(name, {nether=true}) then + return false, + "You need the nether priv to execute this chatcommand." + end + if not player_exists(pname) then + pname = name + end + local player = minetest.get_player_by_name(pname) + if not player then + return false, "Something went wrong." + end + + nether.registry_update(player) + local status = pname + if nether.is_player_trapped_in_nether(player) then + status = status.." is TRAPPED in nether!" + else + status = status.." is NOT trapped in nether!" + end + + return true, status + end +}) + -- Disallow teleportation and change spawn positions if the nether traps players if nether.trap_players then -- randomly set player position when he/she dies in nether minetest.register_on_respawnplayer(function(player) local pname = player:get_player_name() - if not players_in_nether[pname] then + if not players_trapped_in_nether[pname] then return end local target = get_player_died_target(player) @@ -197,14 +324,14 @@ if nether.trap_players then return true end) - -- override set_pos etc. to disallow player teleportion by e.g. travelnet + -- override set_pos etc, to disallow player teleportion by e.g. travelnet local function can_teleport(player, pos) if not player:is_player() then -- the same metatable is used for entities return true end local pname = player:get_player_name() - local in_nether = players_in_nether[pname] == true + local in_nether = players_trapped_in_nether[pname] == true -- test if the target is valid if pos.y < nether.start then @@ -299,7 +426,7 @@ local particledef = { -- teleports player to neter (obsidian portal) local function obsi_teleport_player(player, pos, target) local pname = player:get_player_name() - if players_in_nether[pname] then + if players_trapped_in_nether[pname] then return end @@ -310,7 +437,7 @@ local function obsi_teleport_player(player, pos, target) end local has_teleported - if damage_enabled then + if (damage_enabled and nether.trap_players) then obsidian_teleport(player, pname) has_teleported = true elseif not mclike_portal then