From e24677bcf1e8faac6c9b35ced93ba9e9fc871572 Mon Sep 17 00:00:00 2001 From: kno10 <erich.schubert@gmail.com> Date: Mon, 20 Jan 2025 18:36:27 +0100 Subject: [PATCH] mcl_portals cleanups (#4858) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-on: https://git.minetest.land/VoxeLibre/VoxeLibre/pulls/4858 Reviewed-by: Mikita Wiśniewski <rudzik8@protonmail.com> Co-authored-by: kno10 <erich.schubert@gmail.com> Co-committed-by: kno10 <erich.schubert@gmail.com> --- mods/ITEMS/mcl_portals/portal_nether.lua | 295 +++++++++-------------- 1 file changed, 116 insertions(+), 179 deletions(-) diff --git a/mods/ITEMS/mcl_portals/portal_nether.lua b/mods/ITEMS/mcl_portals/portal_nether.lua index d261b4bd3..f9b0e1131 100644 --- a/mods/ITEMS/mcl_portals/portal_nether.lua +++ b/mods/ITEMS/mcl_portals/portal_nether.lua @@ -9,10 +9,11 @@ local floor = math.floor local max = math.max local min = math.min local random = math.random -local dist = vector.distance -local add = vector.add -local mul = vector.multiply -local sub = vector.subtract +local vector_new = vector.new +local vector_copy = vector.copy +local vector_offset = vector.offset +local vector_subtract = vector.subtract +local vector_distance = vector.distance local log = function(level, message) minetest.log(level, string.format("[mcl_portals] %s", message)) @@ -183,19 +184,19 @@ local dimension_to_teleport = { nether = "overworld", overworld = "nether" } local limits = { nether = { - pmin = {x=LIM_MIN, y = N_Y_MIN, z = LIM_MIN}, - pmax = {x=LIM_MAX, y = N_Y_MAX, z = LIM_MAX}, + pmin = vector_new(LIM_MIN, N_Y_MIN, LIM_MIN), + pmax = vector_new(LIM_MAX, N_Y_MAX, LIM_MAX), }, overworld = { - pmin = {x=LIM_MIN, y = O_Y_MIN, z = LIM_MIN}, - pmax = {x=LIM_MAX, y = O_Y_MAX, z = LIM_MAX}, + pmin = vector_new(LIM_MIN, O_Y_MIN, LIM_MIN), + pmax = vector_new(LIM_MAX, O_Y_MAX, LIM_MAX), }, } -- Deletes exit from this portal's node storage. local function delete_portal_pos(pos) - local p1 = vector.offset(pos,-5,-1,-5) - local p2 = vector.offset(pos,5,5,5) + local p1 = vector_offset(pos,-5,-1,-5) + local p2 = vector_offset(pos,5,5,5) local nn = find_nodes_in_area(p1,p2,{"mcl_portals:portal"}) for _,p in pairs(nn) do minetest.get_meta(p):set_string("target_portal","") @@ -206,12 +207,10 @@ end -- for old portals, so that players don't get surprises. New portals, or portals that lost -- node storage due to destruction should use the lookup table. local function get_portal_pos(pos) - local p1 = vector.offset(pos,-5,-1,-5) - local p2 = vector.offset(pos,5,5,5) - local nn = find_nodes_in_area(p1,p2,{"mcl_portals:portal"}) + local nn = find_nodes_in_area(vector_offset(pos,-5,-1,-5), vector_offset(pos,5,5,5), {"mcl_portals:portal"}) for _,p in pairs(nn) do local m = minetest.get_meta(p):get_string("target_portal") - if m and m ~= "" and mcl_vars.get_node(p).name == "mcl_portals:portal" then + if m and m ~= "" and minetest.get_node(p).name == "mcl_portals:portal" then return minetest.get_position_from_hash(m) end end @@ -229,15 +228,13 @@ end local function add_exit(p) local retval = {key=false, new=false} - if not p or not p.y or not p.z or not p.x then - return retval - end + if not p or not p.y or not p.z or not p.x then return retval end local x, y, z = floor(p.x), floor(p.y), floor(p.z) - local p = {x = x, y = y, z = z} + local p = vector_new(x, y, z) - if get_node({x=x,y=y-1,z=z}).name ~= OBSIDIAN + if get_node(vector_new(x, y-1, z)).name ~= OBSIDIAN or get_node(p).name ~= PORTAL - or get_node({x=x,y=y+1,z=z}).name ~= PORTAL + or get_node(vector_new(x, y+1, z)).name ~= PORTAL then return retval end @@ -301,7 +298,7 @@ local function remove_exit(p) end local x, y, z = floor(p.x), floor(p.y), floor(p.z) - local p = {x = x, y = y, z = z} + local p = vector_new(x, y, z) local k = get_exit_key(p) if not exits[k] then @@ -375,7 +372,7 @@ local function find_exit(p, dx, dz) -- exit is in the correct dimension if abs(t0.x-p.x) <= dx and abs(t0.z-p.z) <= dz then -- exit is within the search range - local d0 = dist(p, t0) + local d0 = vector_distance(p, t0) if not nearest_distance or nearest_distance>d0 then -- it is the only exit so far, or it is the Euclidean-closest exit nearest_distance = d0 @@ -491,7 +488,7 @@ local function get_target(p) y = max(min(y, N_Y_MAX), N_Y_MIN) end - return vector.new(x,y,z) + return vector_new(x,y,z) end -- Destroy a nether portal. Connected portal nodes are searched and removed @@ -529,14 +526,14 @@ local function destroy_nether_portal(pos, node) while i <= #nodes do pos = nodes[i] if orientation == 0 then - check_remove({x = pos.x - 1, y = pos.y, z = pos.z}) - check_remove({x = pos.x + 1, y = pos.y, z = pos.z}) + check_remove(vector_offset(pos, -1, 0, 0)) + check_remove(vector_offset(pos, 1, 0, 0)) else - check_remove({x = pos.x, y = pos.y, z = pos.z - 1}) - check_remove({x = pos.x, y = pos.y, z = pos.z + 1}) + check_remove(vector_offset(pos, 0, 0, -1)) + check_remove(vector_offset(pos, 0, 0, 1)) end - check_remove({x = pos.x, y = pos.y - 1, z = pos.z}) - check_remove({x = pos.x, y = pos.y + 1, z = pos.z}) + check_remove(vector_offset(pos, 0, -1, 0)) + check_remove(vector_offset(pos, 0, 1, 0)) remove_exits({pos}) i = i + 1 end @@ -623,9 +620,7 @@ local function build_and_light_frame(x1, y1, z1, x2, y2, z2, name) set_node(pos, {name = OBSIDIAN}) else set_node(pos, {name = PORTAL, param2 = orientation}) - add_exits({ - {x=pos.x, y=pos.y-1, z=pos.z} - }) + add_exits({ vector_offset(pos, 0, -1, 0) }) end end end @@ -645,7 +640,7 @@ function build_nether_portal(cube_pos1, width, height, orientation, name, clear_ local width_inner = width-2 local height_inner = height-2 - local cube_pos2 = add(cube_pos1, vector.new(width-1, height-1, width-1)) + local cube_pos2 = vector_offset(cube_pos1, width - 1, height - 1, width - 1) if is_area_protected(cube_pos1, cube_pos2, name) then if name then minetest.chat_send_player(name, "Unable to build portal, area is protected.") @@ -656,32 +651,16 @@ function build_nether_portal(cube_pos1, width, height, orientation, name, clear_ -- Calculate "bottom-left" position of the PORTAL blocks. -- Offset Y because we don't want it in the floor. -- Offset X and Z to fit the frame and place the portal in the middle-ish. - local pos = add(cube_pos1, vector.new(1,1,1)) + local pos = vector_offset(cube_pos1, 1, 1, 1) if clear_before_build then local clear1, clear2 if orientation == 0 then - clear1 = vector.new( - cube_pos1.x, - cube_pos1.y + 1, -- do not delete floor - cube_pos1.z - ) - clear2 = vector.new( - cube_pos1.x + width - 1, - cube_pos1.y + height - 2, - cube_pos1.z + 2 -- both sides of the entrance, so player has somewhere to step. - ) + clear1 = vector_offset(cube_pos1, 0, 1, 0) -- do not delete floor + clear2 = vector_offset(cube_pos1, width - 1, height - 2, 2) -- both sides of the entrance, so player has somewhere to step. else - clear1 = vector.new( - cube_pos1.x, - cube_pos1.y + 1, -- do not delete floor - cube_pos1.z - ) - clear2 = vector.new( - cube_pos1.x + 2, -- both sides of the entrance, so player has somewhere to step. - cube_pos1.y + height - 2, - cube_pos1.z + width - 1 - ) + clear1 = vector_offset(cube_pos1, 0, 1, 0) -- do not delete floor + clear2 = vector_offset(cube_pos1, 2, height - 2, width - 1) -- both sides of the entrance, so player has somewhere to step. end log("verbose", "Clearing between "..pos_to_string(clear1).." and "..pos_to_string(clear2)) @@ -689,7 +668,7 @@ function build_nether_portal(cube_pos1, width, height, orientation, name, clear_ for x = clear1.x, clear2.x do for y = clear1.y, clear2.y do for z = clear1.z, clear2.z do - airs[#airs+1] = vector.new(x,y,z) + airs[#airs+1] = vector_new(x,y,z) end end end @@ -701,8 +680,8 @@ function build_nether_portal(cube_pos1, width, height, orientation, name, clear_ -- Build obsidian platform: for x = pos.x - orientation, pos.x + orientation + (width_inner - 1) * (1 - orientation), 1 + orientation do for z = pos.z - 1 + orientation, pos.z + 1 - orientation + (width_inner - 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 pp = vector_new(x, pos.y - 1, z) + local pp_1 = vector_new(x, pos.y - 2, z) local nn = get_node(pp).name local nn_1 = get_node(pp_1).name if ((nn=="air" and nn_1 == "air") or not registered_nodes[nn].is_ground_content) and not is_protected(pp, name) then @@ -766,13 +745,9 @@ minetest.register_chatcommand("spawnportal", { local pos = pointed_thing.under -- Portal node will appear above the pointed node. The pointed node will turn into obsidian. - exit = mcl_portals.spawn_nether_portal(add(pos, vector.new(-1,0,-1)), orientation, nil, name) + exit = mcl_portals.spawn_nether_portal(vector_offset(pos, -1, 0, -1), orientation, nil, name) elseif #params==3 or #params==4 then - pos = { - x=tonumber(params[1]), - y=tonumber(params[2]), - z=tonumber(params[3]) - } + pos = vector_new(tonumber(params[1]), tonumber(params[2]), tonumber(params[3])) local orientation = 0 if #params==4 then @@ -780,7 +755,7 @@ minetest.register_chatcommand("spawnportal", { end -- Portal will be placed so that the first registered exit is at requested location. - exit = mcl_portals.spawn_nether_portal(add(pos, vector.new(-1,-1,-1)), orientation, nil, name) + exit = mcl_portals.spawn_nether_portal(vector_offset(pos, -1, -1, -1), orientation, nil, name) else return false, "Invalid parameters. Pass either zero, three or four" end @@ -823,7 +798,7 @@ local function finalize_teleport(obj, exit) local _, dim = mcl_worlds.y_to_layer(exit.y) -- If player stands, player is at ca. something+0.5 which might cause precision problems, so we used ceil for objpos.y - objpos = {x = floor(objpos.x+0.5), y = ceil(objpos.y), z = floor(objpos.z+0.5)} + objpos = vector_new(floor(objpos.x+0.5), ceil(objpos.y), floor(objpos.z+0.5)) if get_node(objpos).name ~= PORTAL then log("action", "Entity no longer standing in portal") return @@ -857,21 +832,15 @@ local function finalize_teleport(obj, exit) end local function is_origin_queued(origin) - local key = pos_to_string(origin) - if origin_queue[key] then - return true - else - return false - end + return not not origin_queue[pos_to_string(origin)] end -local function is_entity_queued() +local function is_entity_queued(obj) for _, q in pairs(origin_queue) do if q[obj] then return true end end - return false end @@ -916,43 +885,26 @@ local function find_build_limits(pos, target_dim) -- According to what people said in minetest discord and couple of docs, mapgen -- works on entire chunks, so we need to limit the search to chunk boundary. -- The goal is to emerge at most two chunks. - local chunk_limit1 = add( - mul( - mcl_vars.pos_to_chunk(pos), - mcl_vars.chunk_size_in_nodes - ), - vector.new( - mcl_vars.central_chunk_offset_in_nodes, - mcl_vars.central_chunk_offset_in_nodes, - mcl_vars.central_chunk_offset_in_nodes - ) - ) - local chunk_limit2 = add( - chunk_limit1, - vector.new( - mcl_vars.chunk_size_in_nodes - 1, - mcl_vars.chunk_size_in_nodes - 1, - mcl_vars.chunk_size_in_nodes - 1 - ) - ) - + local chunk_pos = mcl_vars.pos_to_chunk(pos) + local chunk_limit1 = vector_new(chunk_pos.x * mcl_vars.chunk_size_in_nodes + mcl_vars.central_chunk_offset_in_nodes, + chunk_pos.y * mcl_vars.chunk_size_in_nodes + mcl_vars.central_chunk_offset_in_nodes, + chunk_pos.z * mcl_vars.chunk_size_in_nodes + mcl_vars.central_chunk_offset_in_nodes) + local chunk_limit2 = vector_offset(chunk_limit1, mcl_vars.chunk_size_in_nodes - 1, mcl_vars.chunk_size_in_nodes - 1, mcl_vars.chunk_size_in_nodes - 1) -- Limit search area by using search distances. There is no Y build limit. - local build_limit1 = add( - pos, + local build_limit1 = vector_offset(pos, -- minus 1 to account for the pos block being included. -- plus 1 to account for the portal block offset (ignore frame) - vector.new(-BUILD_DISTANCE_XZ-1+1, 0, -BUILD_DISTANCE_XZ-1+1) + -BUILD_DISTANCE_XZ-1+1, 0, -BUILD_DISTANCE_XZ-1+1 ) - local build_limit2 = add( - pos, + local build_limit2 = vector_offset(pos, -- plus 1 to account for the portal block offset (ignore frame) -- minus potential portal width, so that the generated portal doesn't "stick out" - vector.new(BUILD_DISTANCE_XZ+1-(W_MIN-1), 0, BUILD_DISTANCE_XZ+1-(W_MIN-1)) + BUILD_DISTANCE_XZ+1-(W_MIN-1), 0, BUILD_DISTANCE_XZ+1-(W_MIN-1) ) -- Start with chunk limits - pos1 = vector.new(chunk_limit1.x, chunk_limit1.y, chunk_limit1.z) - pos2 = vector.new(chunk_limit2.x, chunk_limit2.y, chunk_limit2.z) + local pos1 = vector_new(chunk_limit1.x, chunk_limit1.y, chunk_limit1.z) + local pos2 = vector_new(chunk_limit2.x, chunk_limit2.y, chunk_limit2.z) -- Make sure the portal is not built beyond chunk boundary -- (we will be searching for the node with lowest X, Y and Z) @@ -964,42 +916,26 @@ local function find_build_limits(pos, target_dim) if pos2.y < pos1.y then pos2.y = pos1.y end if pos2.z < pos1.z then pos2.z = pos1.z end - -- Apply build distances. - pos1 = { - x = max(pos1.x, build_limit1.x), - y = pos1.y, - z = max(pos1.z, build_limit1.z) - } - pos2 = { - x = min(pos2.x, build_limit2.x), - y = pos2.y, - z = min(pos2.z, build_limit2.z) - } - - -- Apply dimension-specific distances, so that player does not end up in void or in lava. + -- Apply build distances and dimension-specific distances, so that player does not end up in void or in lava. local limit1, limit2 = limits[target_dim].pmin, limits[target_dim].pmax - pos1 = { - x = max(pos1.x, limit1.x), - y = max(pos1.y, limit1.y), - z = max(pos1.z, limit1.z) - } - pos2 = { - x = min(pos2.x, limit2.x), - y = min(pos2.y, limit2.y), - z = min(pos2.z, limit2.z) - } + pos1.x = max(pos1.x, build_limit1.x, limit1.x) + pos1.y = max(pos1.y, limit1.y) + pos1.z = max(pos1.z, build_limit1.z, limit1.z) + pos2.x = min(pos2.x, build_limit2.x, limit2.x) + pos2.y = min(pos2.y, limit2.y) + pos2.z = min(pos2.z, build_limit2.z, limit2.z) - local diff = add(pos2, mul(pos1, -1)) - local area = diff.x * diff.z + local diff = vector_subtract(pos2, pos1) + local area = (diff.x + 1) * (diff.z + 1) local msg = string.format( "Portal build area between %s-%s, a %dx%dx%d cuboid with floor area of %d nodes. " .."Chunk limit was at [%s,%s]. " .."Ideal build area was at [(%d,*,%d),(%d,*,%d)].", pos_to_string(pos1), pos_to_string(pos2), - diff.x, - diff.y, - diff.z, + diff.x + 1, + diff.y + 1, + diff.z + 1, area, pos_to_string(chunk_limit1), pos_to_string(chunk_limit2), @@ -1025,9 +961,6 @@ local function search_for_build_location(blockpos, action, calls_remaining, para local target, pos1, pos2, name, obj = param.target, param.pos1, param.pos2, param.name or "", param.obj local chunk = mcl_vars.get_chunk_number(target) - local pos0, distance - local most_airy_count, most_airy_pos, most_airy_distance = param.most_airy_count, param.most_airy_pos, param.most_airy_distance - local lava = get_lava_level(target, pos1, pos2) -- Portal might still exist in the area even though nothing was found in the table. -- This could be due to bugs, or old worlds (portals added before the exits table). @@ -1060,44 +993,46 @@ local function search_for_build_location(blockpos, action, calls_remaining, para local nodes = find_nodes_in_area_under_air(pos1, pos2, {"group:building_block"}) -- Sort by distance so that we are checking the nearest nodes first. -- This can speed up the search considerably if there is space around the ideal X and Z. + local center = vector_offset(param.ideal_target, -1, -1, -1) table.sort(nodes, function(a,b) - local da = dist(param.ideal_target, add(a, vector.new(1,1,1))) - local db = dist(param.ideal_target, add(b, vector.new(1,1,1))) - return da<db + return vector_distance(center, a) < vector_distance(center, b) end) + local most_airy_count, most_airy_pos, most_airy_distance = param.most_airy_count, param.most_airy_pos, param.most_airy_distance + local lava = get_lava_level(target, pos1, pos2) + local pos0, distance if nodes then local nc = #nodes if nc > 0 then for i=1,nc do local node = nodes[i] - local portal_node = add(node, vector.new(1,1,1)) -- Skip the frame - local node1 = add(node, vector.new(0,1,0)) -- Floor can be solid - local node2 = add(node, vector.new(W_MIN-1,H_MIN-1,W_MIN-1)) + local portal_node = vector_offset(node, 1, 1, 1) -- Skip the frame + local node1 = vector_offset(node, 0, 1, 0) -- Floor can be solid + local node2 = vector_offset(node, W_MIN - 1, H_MIN - 1, W_MIN - 1) local nodes2 = find_nodes_in_area(node1, node2, {"air"}) if nodes2 then local nc2 = #nodes2 if not is_area_protected(node, node2, name) and node.y > lava then - local distance0 = dist(param.ideal_target, portal_node) + local distance0 = vector_distance(param.ideal_target, portal_node) if nc2 >= (W_MIN*(H_MIN-1)*W_MIN) - ACCEPTABLE_PORTAL_REPLACES then -- We have sorted the candidates by distance, this is the best location. distance = distance0 - pos0 = {x=node.x, y=node.y, z=node.z} + pos0 = vector_copy(node) log("verbose", "Found acceptable location at "..pos_to_string(pos0)..", distance "..distance0..", air nodes "..nc2) break elseif not most_airy_pos or nc2>most_airy_count then -- Remember the cube with the most amount of air as a fallback. most_airy_count = nc2 most_airy_distance = distance0 - most_airy_pos = {x=node.x, y=node.y, z=node.z} + most_airy_pos = vector_copy(node) log("verbose", "Found fallback location at "..pos_to_string(most_airy_pos)..", distance "..distance0..", air nodes "..nc2) elseif most_airy_pos and nc2==most_airy_count and distance0<most_airy_distance then -- Use distance as a tiebreaker. most_airy_distance = distance0 - most_airy_pos = {x=node.x, y=node.y, z=node.z} + most_airy_pos = vector_copy(node) log("verbose", "Found fallback location at "..pos_to_string(most_airy_pos)..", distance "..distance0..", air nodes "..nc2) end @@ -1118,6 +1053,7 @@ local function search_for_build_location(blockpos, action, calls_remaining, para -- space. Since our Y map distance is quite short due to the flatness of -- the non-lava nether, falling back like this should cover entire Y range. if param.chunk_counter==1 then + local direction if limits[param.target_dim].pmax.y-target.y > target.y-limits[param.target_dim].pmin.y then -- Look up direction = 1 @@ -1128,9 +1064,9 @@ local function search_for_build_location(blockpos, action, calls_remaining, para log("verbose", "No space found, emerging one chunk below") end - local new_target = {x=target.x, y=target.y + direction * mcl_vars.chunk_size_in_nodes, z=target.z} + local new_target = vector_offset(target, 0, direction * mcl_vars.chunk_size_in_nodes, 0) pos1, pos2 = find_build_limits(new_target, param.target_dim) - local diff = add(pos2, mul(pos1, -1)) + local diff = vector_subtract(pos2, pos1) -- Only emerge if there is sufficient headroom to actually fit entire portal. if diff.y+1>=H_MIN then @@ -1145,7 +1081,7 @@ local function search_for_build_location(blockpos, action, calls_remaining, para minetest.emerge_area(pos1, pos2, search_for_build_location, { origin=param.origin, target = new_target, - target_dim = target_dim, + target_dim = param.target_dim, ideal_target = param.ideal_target, pos1 = pos1, pos2 = pos2, @@ -1202,7 +1138,7 @@ local function create_portal(origin, target, target_dim, name, obj) origin = origin, target = target, target_dim = target_dim, - ideal_target = vector.new(target.x, target.y, target.z), -- copy + ideal_target = vector.copy(target), pos1 = pos1, pos2 = pos2, name=name, @@ -1223,13 +1159,12 @@ local function available_for_nether_portal(p) end local function check_and_light_shape(pos, orientation) - local stack = {{x = pos.x, y = pos.y, z = pos.z}} + local stack = {vector.copy(pos)} local node_list = {} local index_list = {} local node_counter = 0 -- Search most low node from the left (pos1) and most right node from the top (pos2) - local pos1 = {x = pos.x, y = pos.y, z = pos.z} - local pos2 = {x = pos.x, y = pos.y, z = pos.z} + local pos1, pos2 = vector.copy(pos), vector.copy(pos) local kx, ky, kz = pos.x - 1999, pos.y - 1999, pos.z - 1999 while #stack > 0 do @@ -1247,22 +1182,22 @@ local function check_and_light_shape(pos, orientation) return false end node_counter = node_counter + 1 - node_list[node_counter] = {x = x, y = y, z = z} + node_list[node_counter] = vector_new(x, y, z) index_list[k] = true stack[i].y = y - 1 - stack[i + 1] = {x = x, y = y + 1, z = z} + stack[i + 1] = vector_new(x, y + 1, z) if orientation == 0 then - stack[i + 2] = {x = x - 1, y = y, z = z} - stack[i + 3] = {x = x + 1, y = y, z = z} + stack[i + 2] = vector_new(x - 1, y, z) + stack[i + 3] = vector_new(x + 1, y, z) else - stack[i + 2] = {x = x, y = y, z = z - 1} - stack[i + 3] = {x = x, y = y, z = z + 1} + stack[i + 2] = vector_new(x, y, z - 1) + stack[i + 3] = vector_new(x, y, z + 1) end if (y < pos1.y) or (y == pos1.y and (x < pos1.x or z < pos1.z)) then - pos1 = {x = x, y = y, z = z} + pos1 = vector_new(x, y, z) end if (x > pos2.x or z > pos2.z) or (x == pos2.x and z == pos2.z and y > pos2.y) then - pos2 = {x = x, y = y, z = z} + pos2 = vector_new(x, y, z) end end end @@ -1344,7 +1279,7 @@ local function check_portal_then_teleport(obj, origin, exit) remove_exits({exit}) -- Also remove from structure storage, otherwise ABM will try the same bad exit again. local objpos = obj:get_pos() - delete_portal_pos({x = floor(objpos.x+0.5), y = ceil(objpos.y), z = floor(objpos.z+0.5)}) + delete_portal_pos(vector_new(floor(objpos.x+0.5), ceil(objpos.y), floor(objpos.z+0.5))) origin_flush(origin, nil) return @@ -1367,7 +1302,7 @@ local function teleport_no_delay(obj, portal_pos) local target_dim = dimension_to_teleport[current_dim] -- If player stands, player is at ca. something+0.5 which might cause precision problems, so we used ceil for objpos.y - origin = {x = floor(objpos.x+0.5), y = ceil(objpos.y), z = floor(objpos.z+0.5)} + local origin = vector_new(floor(objpos.x+0.5), ceil(objpos.y), floor(objpos.z+0.5)) if get_node(origin).name ~= PORTAL then return end local target = get_target(origin) @@ -1450,8 +1385,8 @@ local function animation(player, playername) end minetest.add_particlespawner({ amount = 1, - minpos = {x = pos.x - 0.1, y = pos.y + 1.4, z = pos.z - 0.1}, - maxpos = {x = pos.x + 0.1, y = pos.y + 1.6, z = pos.z + 0.1}, + minpos = vector_offset(pos, -0.1, 1.4, -0.1), + maxpos = vector_offset(pos, 0.1, 1.6, 0.1), minvel = 0, maxvel = 0, minacc = 0, @@ -1496,13 +1431,15 @@ minetest.register_abm({ local time = random() * 1.9 + 0.5 local velocity, acceleration if o == 1 then - velocity = {x = random() * 0.7 + 0.3, y = random() - 0.5, z = random() - 0.5} - acceleration = {x = random() * 1.1 + 0.3, y = random() - 0.5, z = random() - 0.5} + velocity = vector_new(random() * 0.7 + 0.3, random() - 0.5, random() - 0.5) + acceleration = vector_new(random() * 1.1 + 0.3, random() - 0.5, random() - 0.5) else - velocity = {x = random() - 0.5, y = random() - 0.5, z = random() * 0.7 + 0.3} - acceleration = {x = random() - 0.5, y = random() - 0.5, z = random() * 1.1 + 0.3} + velocity = vector_new(random() - 0.5, random() - 0.5, random() * 0.7 + 0.3) + acceleration = vector_new(random() - 0.5, random() - 0.5, random() * 1.1 + 0.3) end - local distance = add(mul(velocity, time), mul(acceleration, time * time / 2)) + local distance = vector_new(velocity.x * time + acceleration.x * time * time * 0.5, + velocity.y * time + acceleration.y * time * time * 0.5, + velocity.z * time + acceleration.z * time * time * 0.5) if d == 1 then if o == 1 then distance.x = -distance.x @@ -1514,7 +1451,7 @@ minetest.register_abm({ acceleration.z = -acceleration.z end end - distance = sub(pos, distance) + distance = vector.subtract(pos, distance) for _, obj in pairs(minetest.get_objects_inside_radius(pos, 15)) do if obj:is_player() then minetest.add_particlespawner({ @@ -1566,12 +1503,12 @@ minetest.override_item(OBSIDIAN, { end -- check each of 6 sides of it and destroy every portal - check_remove({x = pos.x - 1, y = pos.y, z = pos.z}) - check_remove({x = pos.x + 1, y = pos.y, z = pos.z}) - check_remove({x = pos.x, y = pos.y, z = pos.z - 1}) - check_remove({x = pos.x, y = pos.y, z = pos.z + 1}) - check_remove({x = pos.x, y = pos.y - 1, z = pos.z}) - check_remove({x = pos.x, y = pos.y + 1, z = pos.z}) + check_remove(vector_offset(pos, -1, 0, 0)) + check_remove(vector_offset(pos, 1, 0, 0)) + check_remove(vector_offset(pos, 0, 0, -1)) + check_remove(vector_offset(pos, 0, 0, 1)) + check_remove(vector_offset(pos, 0, -1, 0)) + check_remove(vector_offset(pos, 0, 1, 0)) end, _on_ignite = function(user, pointed_thing) @@ -1579,16 +1516,16 @@ minetest.override_item(OBSIDIAN, { -- Check empty spaces around obsidian and light all frames found. -- Permit igniting of portals that are partly protected to maintain integrity. local portals_placed = - mcl_portals.light_nether_portal({x = x - 1, y = y, z = z}) or mcl_portals.light_nether_portal({x = x + 1, y = y, 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 + 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}) + mcl_portals.light_nether_portal(vector_new(x - 1, y, z)) or mcl_portals.light_nether_portal(vector_new(x + 1, y, z)) or + mcl_portals.light_nether_portal(vector_new(x, y - 1, z)) or mcl_portals.light_nether_portal(vector_new(x, y + 1, z)) or + mcl_portals.light_nether_portal(vector_new(x, y, z - 1)) or mcl_portals.light_nether_portal(vector_new(x, y, z + 1)) if portals_placed then - log("verbose", "Nether portal activated at "..pos_to_string({x=x,y=y,z=z})..".") + log("verbose", "Nether portal activated at "..pos_to_string(vector_new(x, y, z))..".") if minetest.get_modpath("doc") then doc.mark_entry_as_revealed(user:get_player_name(), "nodes", PORTAL) -- Achievement for finishing a Nether portal TO the Nether - local dim = mcl_worlds.pos_to_dimension({x=x, y=y, z=z}) + local dim = mcl_worlds.pos_to_dimension(vector_new(x, y, z)) if minetest.get_modpath("awards") and dim ~= "nether" and user:is_player() then awards.unlock(user:get_player_name(), "mcl:buildNetherPortal") end @@ -1614,7 +1551,7 @@ mcl_structures.register_structure("nether_portal_open",{ after_place = function(pos,def,pr,blockseed) -- The mts is the smallest portal (two wide) and places the first PORTAL block -- above the location of the caller (y+1). The second one is either at x+1 or z+1. - local portals = find_nodes_in_area(add(pos, vector.new(0,1,0)), add(pos, vector.new(1,1,1)), {PORTAL}) + local portals = find_nodes_in_area(vector_offset(pos, 0, 1, 0), vector_offset(pos, 1, 1, 1), {PORTAL}) if portals and #portals>0 then for _, p in pairs(portals) do add_exits({p})