From ef395af8381d05e59f3ea41814379aaa36099835 Mon Sep 17 00:00:00 2001 From: kay27 Date: Fri, 19 Mar 2021 12:34:07 +0400 Subject: [PATCH] Make portals branch fully playable (reduce y scale to 2), fix critical bugs --- mods/ITEMS/mcl_portals/portal_nether.lua | 91 +++++++++++++++--------- mods/MAPGEN/mcl_mapgen_core/init.lua | 2 +- mods/MAPGEN/mcl_structures/init.lua | 4 +- 3 files changed, 63 insertions(+), 34 deletions(-) diff --git a/mods/ITEMS/mcl_portals/portal_nether.lua b/mods/ITEMS/mcl_portals/portal_nether.lua index 40e63fdfd..524b06ab3 100644 --- a/mods/ITEMS/mcl_portals/portal_nether.lua +++ b/mods/ITEMS/mcl_portals/portal_nether.lua @@ -16,7 +16,7 @@ local sub = vector.subtract local W_MIN, W_MAX = 4, 23 local H_MIN, H_MAX = 5, 23 local N_MIN, N_MAX = 6, (W_MAX-2) * (H_MAX-2) -local TRAVEL_X, TRAVEL_Y, TRAVEL_Z = 8, 10, 8 +local TRAVEL_X, TRAVEL_Y, TRAVEL_Z = 8, 2, 8 local LIM_MIN, LIM_MAX = mcl_vars.mapgen_edge_min, mcl_vars.mapgen_edge_max local PLAYER_COOLOFF, MOB_COOLOFF = 3, 14 -- for this many seconds they won't teleported again local TOUCH_CHATTER_TIME = 1 -- prevent multiple teleportation attempts caused by multiple portal touches, for this number of seconds @@ -49,9 +49,21 @@ local queue = {} local chunks = {} local storage = minetest.get_mod_storage() -local exits = minetest.deserialize(storage:get_string("nether_exits") or "return {}") or {} +local exits = {} +local keys = minetest.deserialize(storage:get_string("nether_exits_keys") or "return {}") or {} +for _, key in pairs(keys) do + local n = tonumber(key) + if n then + exits[key] = minetest.deserialize(storage:get_string("nether_exits_"..key) or "return {}") or {} + end +end minetest.register_on_shutdown(function() - storage:set_string("nether_exits", minetest.serialize(exits)) + local keys={} + for key, data in pairs(exits) do + storage:set_string("nether_exits_"..tostring(key), minetest.serialize(data)) + keys[#keys+1] = key + end + storage:set_string("nether_exits_keys", minetest.serialize(keys)) end) mcl_portals.get_node = function(pos) @@ -101,7 +113,7 @@ local function add_exit(p) return end end - e[#e] = p + e[#e+1] = p log("action", "[mcl_portals] Exit added at " .. pos_to_string(p)) end @@ -114,9 +126,8 @@ local function remove_exit(p) local p = {x = x, y = y, z = z} local e = exits[k] if e then - for i = 1, #e do - local t = e[i] - if t.x == p.x and t.y == p.y and t.z == p.z then + for i, t in pairs(e) do + if t and t.x == x and t.y == y and t.z == z then e[i] = nil log("action", "[mcl_portals] Nether portal removed from " .. pos_to_string(p)) return @@ -142,7 +153,7 @@ local function find_exit(p, dx, dy, dz) if e then for i = 1, #e do local t0 = e[i] - local d0 = dist(p, t) + local d0 = dist(p, t0) if not d or d>d0 then d = d0 t = t0 @@ -289,7 +300,7 @@ local function light_frame(x1, y1, z1, x2, y2, z2, name) set_node(pos, {name = OBSIDIAN}) else set_node(pos, {name = PORTAL, param2 = orientation}) - add_exit(pos) + add_exit({x=pos.x, y=pos.y-1, z=pos.z}) end end end @@ -308,20 +319,35 @@ function build_nether_portal(pos, width, height, orientation, name) for x = pos.x - orientation, pos.x + orientation + (width - 1) * (1 - orientation), 1 + orientation do for z = pos.z - 1 + orientation, pos.z + 1 - orientation + (width - 1) * orientation, 2 - orientation do local pp = {x = x, y = pos.y - 1, z = z} + local pp_1 = {x = x, y = pos.y - 2, z = z} local nn = get_node(pp).name - log("warning", "[mcl_portals] pos=" .. pos_to_string(pp) .. " nn=" .. nn .. " name=" .. name .. " width=" .. tostring(width) .. " height=" .. tostring(height).." orientation=" ..tostring(orientation).." for obsidian platform:") - if not registered_nodes[nn].is_ground_content and not is_protected(pp, name) then + local nn_1 = get_node(pp_1).name + log("warning", "[mcl_portals] pos=" .. pos_to_string(pp) .. " nn=" .. nn .. " name=" .. name .. " width=" .. tostring(width) .. " height=" .. tostring(height).." orientation=" ..tostring(orientation).." gc="..tostring(registered_nodes[nn].is_ground_content) .." for obsidian platform:") + if ((nn=="air" and nn_1 == "air") or not registered_nodes[nn].is_ground_content) and not is_protected(pp, name) then set_node(pp, {name = OBSIDIAN}) minetest.log("warning", "set!") end end end - log("action", "[mcl_portal] Destination Nether portal generated at "..pos_to_string(pos).."!") + log("action", "[mcl_portals] Destination Nether portal generated at "..pos_to_string(pos).."!") return pos end +function mcl_portals.spawn_nether_portal(pos, rot, pr, name) + if not pos then return end + local o = 0 + if rot then + if rot == "270" or rot=="90" then + o = 1 + elseif rot == "random" then + o = random(0,1) + end + end + build_nether_portal(pos, nil, nil, o, name) +end + -- Teleportation cooloff for some seconds, to prevent back-and-forth teleportation local function stop_teleport_cooloff(o) cooloff[o] = nil @@ -342,7 +368,6 @@ local function finalize_teleport(obj, exit) local objpos = obj:get_pos() if not objpos then return end - log("warning", "[mcl_portal] 3") local is_player = obj:is_player() local name @@ -365,9 +390,9 @@ local function finalize_teleport(obj, exit) if is_player then mcl_worlds.dimension_change(obj, dim) minetest.sound_play("mcl_portals_teleport", {pos=exit, gain=0.5, max_hear_distance = 16}, true) - log("action", "[mcl_portal] player "..name.." teleported to Nether portal at "..pos_to_string(exit)..".") + log("action", "[mcl_portals] player "..name.." teleported to Nether portal at "..pos_to_string(exit)..".") else - log("action", "[mcl_portal] entity teleported to Nether portal at "..pos_to_string(exit)..".") + log("action", "[mcl_portals] entity teleported to Nether portal at "..pos_to_string(exit)..".") end end @@ -390,7 +415,9 @@ local function create_portal_2(pos1, name, obj) chunks[cn] = nil if queue[cn] then for next_obj, _ in pairs(queue[cn]) do - finalize_teleport(next_obj, exit) + if next_obj ~= obj then + finalize_teleport(next_obj, exit) + end end queue[cn] = nil end @@ -403,7 +430,7 @@ local function ecb_scan_area(blockpos, action, calls_remaining, param) -- loop in a spiral around pos local cs, x, z, dx, dz, p0x, p0z, p1x, p1y, p1z, p2x, p2y, p2z = mcl_vars.chunk_size_in_nodes, 0, 0, 0, -1, pos.x, pos.z, pos1.x, pos1.y, pos1.z, pos2.x, pos2.y, pos2.z local i_max = (cs*2-1) * (cs*2-1) - log("action", "[mcl_portal] Area for destination Nether portal emerged! We about to iterate " .. tostring(i_max) .. " positions of spiral around "..pos_to_string(pos)) + log("action", "[mcl_portals] Area for destination Nether portal emerged! We about to iterate " .. tostring(i_max) .. " positions of spiral around "..pos_to_string(pos)) local backup_pos, bnc = nil, 0 -- 'better than nothing' @@ -412,12 +439,12 @@ local function ecb_scan_area(blockpos, action, calls_remaining, param) for i = 1, i_max do local px, pz = p0x + x, p0z + z if ((i%100) == 1) then - log("action", "[mcl_portal] i=" ..tostring(i) .." px=" .. tostring(px) .." pz=" .. tostring(pz) .. " x:"..tostring(p1x) .."-"..tostring(p2x) .. " z:"..tostring(p1z) .."-"..tostring(p2z)) + log("action", "[mcl_portals] i=" ..tostring(i) .." px=" .. tostring(px) .." pz=" .. tostring(pz) .. " x:"..tostring(p1x) .."-"..tostring(p2x) .. " z:"..tostring(p1z) .."-"..tostring(p2z)) end if px >= p1x and pz >= p1z and px <= p2x and pz <= p2z then p1.x, p2.x, p1.z, p2.z = px, px, pz, pz local nodes = find_nodes_in_area_under_air(p1, p2, {"group:building_block"}) - log("action", "[mcl_portal] check " .. pos_to_string(p1) .. "-" .. pos_to_string(p2) .. ": " .. tostring(nodes and #nodes)) + log("action", "[mcl_portals] check " .. pos_to_string(p1) .. "-" .. pos_to_string(p2) .. ": " .. tostring(nodes and #nodes)) if nodes and #nodes > 0 then for j = 1, #nodes do local node = nodes[j] @@ -432,14 +459,14 @@ local function ecb_scan_area(blockpos, action, calls_remaining, param) node2.z = node2.z + 2 nodes_j = find_nodes_in_area(node, node2, {"air"}) if #nodes_j == 36 then - log("action", "[mcl_portal] found space at pos "..pos_to_string(node).." - creating a portal") + log("action", "[mcl_portals] found space at pos "..pos_to_string(node).." - creating a portal") create_portal_2(node, name, obj) return end elseif nc > bnc then bnc = nc backup_pos = {x = node.x, y = node.y-2, z = node.z} - log("action", "[mcl_portal] set backup pos "..pos_to_string(backup_pos).." with "..tostring(nc).." air node(s)") + log("action", "[mcl_portals] set backup pos "..pos_to_string(backup_pos).." with "..tostring(nc).." air node(s)") end end end @@ -453,11 +480,11 @@ local function ecb_scan_area(blockpos, action, calls_remaining, param) px, pz = p0x + x, p0z + z end if backup_pos then -- several nodes of air might be better than lava lake, right? - log("action", "[mcl_portal] using backup pos "..pos_to_string(backup_pos).." to create a portal") + log("action", "[mcl_portals] using backup pos "..pos_to_string(backup_pos).." to create a portal") create_portal_2(backup_pos, name, obj) return end - log("action", "[mcl_portal] found no space, reverting to target pos "..pos_to_string(pos).." - creating a portal") + log("action", "[mcl_portals] found no space, reverting to target pos "..pos_to_string(pos).." - creating a portal") create_portal_2(pos, name, obj) end @@ -469,24 +496,24 @@ local function ecb_scan_area_2(blockpos, action, calls_remaining, param) if nodes then local nc = #nodes if nc > 0 then - log("action", "[mcl_portal] Area for destination Nether portal emerged! Found " .. tostring(nc) .. " nodes under the air around "..pos_to_string(pos)) + log("action", "[mcl_portals] Area for destination Nether portal emerged! Found " .. tostring(nc) .. " nodes under the air around "..pos_to_string(pos)) for i=1,nc do local node = nodes[i] - local node1 = {x=node.x, y=node.y+2, z=node.z } + local node1 = {x=node.x, y=node.y+1, z=node.z } local node2 = {x=node.x+2, y=node.y+3, z=node.z+2} local nodes2 = find_nodes_in_area(node1, node2, {"air"}) if nodes2 then local nc2 = #nodes2 - log("action", "[mcl_portal] nc2=" .. tostring(nc2)) - if nc2 == 18 and not is_area_protected(node, node2, name) then + log("action", "[mcl_portals] nc2=" .. tostring(nc2)) + if nc2 == 27 and not is_area_protected(node, node2, name) then local distance0 = dist(pos, node) if distance0 < 2 then - log("action", "[mcl_portal] found space at pos "..pos_to_string(node).." - creating a portal") + log("action", "[mcl_portals] found space at pos "..pos_to_string(node).." - creating a portal") create_portal_2(node, name, obj) return end if not distance or distance0 < distance then - log("action", "[mcl_portal] found distance "..tostring(distance0).." at pos "..pos_to_string(node)) + log("action", "[mcl_portals] found distance "..tostring(distance0).." at pos "..pos_to_string(node)) distance = distance0 pos0 = {x=node.x, y=node.y, z=node.z} end @@ -496,11 +523,11 @@ local function ecb_scan_area_2(blockpos, action, calls_remaining, param) end end if distance then -- several nodes of air might be better than lava lake, right? - log("action", "[mcl_portal] using backup pos "..pos_to_string(pos0).." to create a portal") + log("action", "[mcl_portals] using backup pos "..pos_to_string(pos0).." to create a portal") create_portal_2(pos0, name, obj) return end - log("action", "[mcl_portal] found no space, reverting to target pos "..pos_to_string(pos).." - creating a portal") + log("action", "[mcl_portals] found no space, reverting to target pos "..pos_to_string(pos).." - creating a portal") create_portal_2(pos, name, obj) end @@ -786,7 +813,7 @@ minetest.override_item(OBSIDIAN, { mcl_portals.light_nether_portal({x = x, y = y - 1, z = z}) or mcl_portals.light_nether_portal({x = x, y = y + 1, z = z}) or mcl_portals.light_nether_portal({x = x, y = y, z = z - 1}) or mcl_portals.light_nether_portal({x = x, y = y, z = z + 1}) if portals_placed then - log("action", "[mcl_portal] Nether portal activated at "..pos_to_string({x=x,y=y,z=z})..".") + log("action", "[mcl_portals] Nether portal activated at "..pos_to_string({x=x,y=y,z=z})..".") if minetest.get_modpath("doc") then doc.mark_entry_as_revealed(user:get_player_name(), "nodes", PORTAL) diff --git a/mods/MAPGEN/mcl_mapgen_core/init.lua b/mods/MAPGEN/mcl_mapgen_core/init.lua index 995601841..a0459d090 100644 --- a/mods/MAPGEN/mcl_mapgen_core/init.lua +++ b/mods/MAPGEN/mcl_mapgen_core/init.lua @@ -29,7 +29,7 @@ local function add_chunk(pos) end prev = d end - chunks[#chunks] = {n, n} + chunks[#chunks+1] = {n, n} end function mcl_mapgen_core.is_generated(pos) local n = mcl_vars.get_chunk_number(pos) -- unsigned int diff --git a/mods/MAPGEN/mcl_structures/init.lua b/mods/MAPGEN/mcl_structures/init.lua index 96c620c99..0d6bc62ab 100644 --- a/mods/MAPGEN/mcl_structures/init.lua +++ b/mods/MAPGEN/mcl_structures/init.lua @@ -534,7 +534,7 @@ end -- Debug command minetest.register_chatcommand("spawnstruct", { - params = "desert_temple | desert_well | igloo | witch_hut | boulder | ice_spike_small | ice_spike_large | fossil | end_exit_portal | end_portal_shrine | dungeon", + params = "desert_temple | desert_well | igloo | witch_hut | boulder | ice_spike_small | ice_spike_large | fossil | end_exit_portal | end_portal_shrine | nether_portal | dungeon", description = S("Generate a pre-defined structure near your position."), privs = {debug = true}, func = function(name, param) @@ -570,6 +570,8 @@ minetest.register_chatcommand("spawnstruct", { mcl_structures.generate_end_portal_shrine(pos, rot, pr) elseif param == "dungeon" and mcl_dungeons and mcl_dungeons.spawn_dungeon then mcl_dungeons.spawn_dungeon(pos, rot, pr) + elseif param == "nether_portal" and mcl_portals and mcl_portals.spawn_nether_portal then + mcl_portals.spawn_nether_portal(pos, rot, pr, name) elseif param == "" then message = S("Error: No structure type given. Please use “/spawnstruct ”.") errord = true