From 069e089ae4c6446a0de3d9740664221a6a7ebb9d Mon Sep 17 00:00:00 2001 From: kay27 Date: Wed, 7 Apr 2021 03:34:15 +0400 Subject: [PATCH] [mcl_portals, mcl_structures] Add End gateways W-I-P by Elias Fleckenstein with minor portals improvements and fixes --- mods/ITEMS/mcl_portals/portal_gateway.lua | 78 ++++++++++++++++++++++- mods/ITEMS/mcl_portals/portal_nether.lua | 33 +++++++++- mods/MAPGEN/mcl_biomes/init.lua | 2 + mods/MAPGEN/mcl_structures/init.lua | 10 +-- 4 files changed, 115 insertions(+), 8 deletions(-) diff --git a/mods/ITEMS/mcl_portals/portal_gateway.lua b/mods/ITEMS/mcl_portals/portal_gateway.lua index cae6fce4..9fa35a36 100644 --- a/mods/ITEMS/mcl_portals/portal_gateway.lua +++ b/mods/ITEMS/mcl_portals/portal_gateway.lua @@ -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, +}) diff --git a/mods/ITEMS/mcl_portals/portal_nether.lua b/mods/ITEMS/mcl_portals/portal_nether.lua index 9ac569dd..825c95e0 100644 --- a/mods/ITEMS/mcl_portals/portal_nether.lua +++ b/mods/ITEMS/mcl_portals/portal_nether.lua @@ -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) diff --git a/mods/MAPGEN/mcl_biomes/init.lua b/mods/MAPGEN/mcl_biomes/init.lua index 66de6c13..5f051034 100644 --- a/mods/MAPGEN/mcl_biomes/init.lua +++ b/mods/MAPGEN/mcl_biomes/init.lua @@ -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, diff --git a/mods/MAPGEN/mcl_structures/init.lua b/mods/MAPGEN/mcl_structures/init.lua index 00efeca1..2ce5d94b 100644 --- a/mods/MAPGEN/mcl_structures/init.lua +++ b/mods/MAPGEN/mcl_structures/init.lua @@ -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 ”.") errord = true