Make portals branch fully playable (reduce y scale to 2), fix critical bugs

This commit is contained in:
kay27 2021-03-19 12:34:07 +04:00
parent 60fc57d878
commit ef395af838
3 changed files with 63 additions and 34 deletions

View File

@ -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)

View File

@ -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

View File

@ -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 <type>”.")
errord = true