[mcl_portals, mcl_structures] Add End gateways W-I-P by Elias Fleckenstein with minor portals improvements and fixes

This commit is contained in:
kay27 2021-04-07 03:34:15 +04:00
parent 430f958fae
commit 069e089ae4
4 changed files with 115 additions and 8 deletions

@ -24,12 +24,21 @@ local gateway_positions = {
{x = 91, y = -26925, z = -29},
}
local function spawn_gateway_portal(pos, dest_str)
local path = minetest.get_modpath("mcl_structures").."/schematics/mcl_structures_end_gateway_portal.mts"
return mcl_structures.place_schematic(vector.add(pos, vector.new(-1, -2, -1)), path, "0", nil, true, nil, dest_str and function(p1, p2, size, orientation, pr, param)
-- minetest.get_voxel_manip():read_from_map(pos, pos)
minetest.get_meta(vector.add(p1, {x=1,y=2,z=1})):set_string("mcl_portals:gateway_destination", param.dest_str)
print(param.dest_str)
end, nil, {dest_str=dest_str})
end
function mcl_portals.spawn_gateway_portal()
local id = storage:get_int("gateway_last_id") + 1
local pos = gateway_positions[id]
if not pos then return end
storage:set_int("gateway_last_id", id)
mcl_structures.call_struct(vector.add(pos, vector.new(-1, -2, -1)), "end_gateway_portal")
spawn_gateway_portal(pos)
end
local gateway_def = table.copy(minetest.registered_nodes["mcl_portals:portal_end"])
@ -43,3 +52,70 @@ gateway_def.node_box = nil
gateway_def.walkable = true
gateway_def.tiles[3] = nil
minetest.register_node("mcl_portals:portal_gateway", gateway_def)
local function find_destination_pos(minp, maxp)
for y = maxp.y, minp.y, -1 do
for x = maxp.x, minp.x, -1 do
for z = maxp.z, minp.z, -1 do
local pos = vector.new(x, y, z)
local nn = minetest.get_node(pos).name
if nn ~= "ignore" and nn ~= "mcl_portals:portal_gateway" and nn ~= "mcl_core:bedrock" then
local def = minetest.registered_nodes[nn]
if def and def.walkable then
return vector.add(pos, vector.new(0, 1.5, 0))
end
end
end
end
end
end
local preparing = {}
local function teleport(pos, obj)
local meta = minetest.get_meta(pos)
local dest_portal
local dest_str = meta:get_string("mcl_portals:gateway_destination")
local pos_str = minetest.pos_to_string(pos)
if dest_str == "" then
dest_portal = vector.multiply(vector.direction(vector.new(0, pos.y, 0), pos), math.random(768, 1024))
dest_portal.y = -26970
spawn_gateway_portal(dest_portal, pos_str)
meta:set_string("mcl_portals:gateway_destination", minetest.pos_to_string(dest_portal))
else
dest_portal = minetest.string_to_pos(dest_str)
end
local minp = vector.subtract(dest_portal, vector.new(5, 40, 5))
local maxp = vector.add(dest_portal, vector.new(5, 10, 5))
preparing[pos_str] = true
minetest.emerge_area(
minp,
maxp,
function(blockpos, action, calls_remaining, param)
if calls_remaining < 1 then
local minp, maxp, dest_portal, obj, pos_str = param.minp, param.maxp, param.dest_portal, param.obj, param.pos_str
if obj and obj:is_player() or obj:get_luaentity() then
obj:set_pos(find_destination_pos(minp, maxp) or vector.add(dest_portal, vector.new(0, 3.5, 0)))
end
preparing[pos_str] = false
end
end,
{minp=vector.new(minp), maxp=vector.new(maxp), dest_portal=vector.new(dest_portal), obj=obj, pos_str=pos_str}
)
end
minetest.register_abm({
label = "End gateway portal teleportation",
nodenames = {"mcl_portals:portal_gateway"},
interval = 0.1,
chance = 1,
action = function(pos)
if preparing[minetest.pos_to_string(pos)] then return end
for _, obj in pairs(minetest.get_objects_inside_radius(pos, 1)) do
if obj:get_hp() > 0 then
teleport(pos, obj)
return
end
end
end,
})

@ -1,5 +1,7 @@
local S = minetest.get_translator("mcl_portals")
local SCAN_2_MAP_CHUNKS = true -- slower but helps to find more suitable places
-- Localize functions for better performance
local abs = math.abs
local ceil = math.ceil
@ -26,7 +28,7 @@ local DISTANCE_MAX = 128
local PORTAL = "mcl_portals:portal"
local OBSIDIAN = "mcl_core:obsidian"
local O_Y_MIN, O_Y_MAX = max(mcl_vars.mg_overworld_min, -31), min(mcl_vars.mg_overworld_max_official, 2048)
local N_Y_MIN, N_Y_MAX = mcl_vars.mg_bedrock_nether_bottom_min, mcl_vars.mg_bedrock_nether_top_max
local N_Y_MIN, N_Y_MAX = mcl_vars.mg_bedrock_nether_bottom_min, mcl_vars.mg_bedrock_nether_top_max - H_MIN
local O_DY, N_DY = O_Y_MAX - O_Y_MIN + 1, N_Y_MAX - N_Y_MIN + 1
-- Alpha and particles
@ -486,6 +488,14 @@ local function ecb_scan_area_2(blockpos, action, calls_remaining, param)
create_portal_2(pos0, name, obj)
return
end
if param.next_chunk_1 and param.next_chunk_2 and param.next_pos then
local pos1, pos2, pos = param.next_chunk_1, param.next_chunk_2, param.next_pos
log("action", "[mcl_portals] Making additional search in chunk below, because current one doesn't contain any air space for portal, target pos "..pos_to_string(pos))
minetest.emerge_area(pos1, pos2, ecb_scan_area_2, {pos = pos, pos1 = pos1, pos2 = pos2, name=name, obj=obj})
return
end
log("action", "[mcl_portals] found no space, reverting to target pos "..pos_to_string(pos).." - creating a portal")
if pos.y < lava then
pos.y = lava + 1
@ -507,18 +517,35 @@ local function create_portal(pos, limit1, limit2, name, obj)
-- we need to emerge the area here, but currently (mt5.4/mcl20.71) map generation is slow
-- so we'll emerge single chunk only: 5x5x5 blocks, 80x80x80 nodes maximum
-- and maybe one more chunk from below if (SCAN_2_MAP_CHUNKS = true)
local pos1 = add(mul(mcl_vars.pos_to_chunk(pos), mcl_vars.chunk_size_in_nodes), mcl_vars.central_chunk_offset_in_nodes)
local pos2 = add(pos1, mcl_vars.chunk_size_in_nodes - 1)
if not SCAN_2_MAP_CHUNKS then
if limit1 and limit1.x and limit1.y and limit1.z then
pos1 = {x = max(min(limit1.x, pos.x), pos1.x), y = max(min(limit1.y, pos.y), pos1.y), z = max(min(limit1.z, pos.z), pos1.z)}
end
if limit2 and limit2.x and limit2.y and limit2.z then
pos2 = {x = min(max(limit2.x, pos.x), pos2.x), y = min(max(limit2.y, pos.y), pos2.y), z = min(max(limit2.z, pos.z), pos2.z)}
end
minetest.emerge_area(pos1, pos2, ecb_scan_area_2, {pos = vector.new(pos), pos1 = pos1, pos2 = pos2, name=name, obj=obj})
return
end
-- Basically the copy of code above, with minor additions to continue the search in single additional chunk below:
local next_chunk_1 = {x = pos1.x, y = pos1.y - mcl_vars.chunk_size_in_nodes, z = pos1.z}
local next_chunk_2 = add(next_chunk_1, mcl_vars.chunk_size_in_nodes - 1)
local next_pos = {x = pos.x, y=next_chunk_2.y, z = pos.z}
if limit1 and limit1.x and limit1.y and limit1.z then
pos1 = {x = max(min(limit1.x, pos.x), pos1.x), y = max(min(limit1.y, pos.y), pos1.y), z = max(min(limit1.z, pos.z), pos1.z)}
next_chunk_1 = {x = max(min(limit1.x, next_pos.x), next_chunk_1.x), y = max(min(limit1.y, next_pos.y), next_chunk_1.y), z = max(min(limit1.z, next_pos.z), next_chunk_1.z)}
end
if limit2 and limit2.x and limit2.y and limit2.z then
pos2 = {x = min(max(limit2.x, pos.x), pos2.x), y = min(max(limit2.y, pos.y), pos2.y), z = min(max(limit2.z, pos.z), pos2.z)}
next_chunk_2 = {x = min(max(limit2.x, next_pos.x), next_chunk_2.x), y = min(max(limit2.y, next_pos.y), next_chunk_2.y), z = min(max(limit2.z, next_pos.z), next_chunk_2.z)}
end
minetest.emerge_area(pos1, pos2, ecb_scan_area_2, {pos = vector.new(pos), pos1 = pos1, pos2 = pos2, name=name, obj=obj})
minetest.emerge_area(pos1, pos2, ecb_scan_area_2, {pos = vector.new(pos), pos1 = pos1, pos2 = pos2, name=name, obj=obj, next_chunk_1 = next_chunk_1, next_chunk_2 = next_chunk_2, next_pos = next_pos})
end
local function available_for_nether_portal(p)

@ -1484,6 +1484,7 @@ local function register_dimension_biomes()
node_stone = "mcl_nether:netherrack",
node_water = "air",
node_river_water = "air",
node_cave_liquid = "air",
y_min = mcl_vars.mg_nether_min,
-- FIXME: For some reason the Nether stops generating early if this constant is not added.
-- Figure out why.
@ -1501,6 +1502,7 @@ local function register_dimension_biomes()
node_filler = "air",
node_water = "air",
node_river_water = "air",
node_cave_liquid = "air",
-- FIXME: For some reason the End stops generating early if this constant is not added.
-- Figure out why.
y_min = mcl_vars.mg_end_min,

@ -11,10 +11,10 @@ local function ecb_place(blockpos, action, calls_remaining, param)
if calls_remaining >= 1 then return end
minetest.place_schematic(param.pos, param.schematic, param.rotation, param.replacements, param.force_placement, param.flags)
if param.after_placement_callback and param.p1 and param.p2 then
param.after_placement_callback(param.p1, param.p2, param.size, param.rotation, param.pr)
param.after_placement_callback(param.p1, param.p2, param.size, param.rotation, param.pr, param.callback_param)
end
end
mcl_structures.place_schematic = function(pos, schematic, rotation, replacements, force_placement, flags, after_placement_callback, pr)
mcl_structures.place_schematic = function(pos, schematic, rotation, replacements, force_placement, flags, after_placement_callback, pr, callback_param)
local s = loadstring(minetest.serialize_schematic(schematic, "lua", {lua_use_comments = false, lua_num_indent_spaces = 0}) .. " return(schematic)")()
if s and s.size then
local x, z = s.size.x, s.size.z
@ -32,7 +32,7 @@ mcl_structures.place_schematic = function(pos, schematic, rotation, replacements
local p1 = {x=pos.x , y=pos.y , z=pos.z }
local p2 = {x=pos.x+x-1, y=pos.y+s.size.y-1, z=pos.z+z-1}
minetest.log("verbose","[mcl_structures] size=" ..minetest.pos_to_string(s.size) .. ", rotation=" .. tostring(rotation) .. ", emerge from "..minetest.pos_to_string(p1) .. " to " .. minetest.pos_to_string(p2))
local param = {pos=vector.new(pos), schematic=s, rotation=rotation, replacements=replacements, force_placement=force_placement, flags=flags, p1=p1, p2=p2, after_placement_callback = after_placement_callback, size=vector.new(s.size), pr=pr}
local param = {pos=vector.new(pos), schematic=s, rotation=rotation, replacements=replacements, force_placement=force_placement, flags=flags, p1=p1, p2=p2, after_placement_callback = after_placement_callback, size=vector.new(s.size), pr=pr, callback_param=callback_param}
minetest.emerge_area(p1, p2, ecb_place, param)
end
end
@ -548,7 +548,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_exit_portal_opens | end_portal_shrine | nether_portal | dungeon",
params = "desert_temple | desert_well | igloo | witch_hut | boulder | ice_spike_small | ice_spike_large | fossil | end_exit_portal | end_exit_portal_opens | end_portal_shrine | nether_portal | gateway_portal | dungeon",
description = S("Generate a pre-defined structure near your position."),
privs = {debug = true},
func = function(name, param)
@ -590,6 +590,8 @@ minetest.register_chatcommand("spawnstruct", {
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 == "gateway_portal" and mcl_portals.spawn_gateway_portal then
mcl_portals.spawn_gateway_portal(pos, rot, pr, name)
elseif param == "" then
message = S("Error: No structure type given. Please use “/spawnstruct <type>”.")
errord = true