191 lines
6.9 KiB
Lua
191 lines
6.9 KiB
Lua
-- r_place/mods/rp_core/mapgen.lua
|
|
-- Handle border generation
|
|
--[[
|
|
Copyright (C) 2023 1F616EMO
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Lesser General Public
|
|
License as published by the Free Software Foundation; either
|
|
version 2.1 of the License, or (at your option) any later version.
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Lesser General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
|
License along with this library; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
|
|
USA
|
|
]]
|
|
|
|
local function v(x,z)
|
|
return vector.new(x,1,z)
|
|
end
|
|
|
|
local WP = minetest.get_worldpath()
|
|
local NEW_BORDER
|
|
-- ^%s*%(%s*([^%s,]+)%s*[,%s]%s*([^%s,]+)%s*[,%s]?%s*%)()
|
|
do
|
|
local BORDER_POS1_SETTINGS = minetest.settings:get("r_place.area_pos1") or "(30,30)"
|
|
local BORDER_POS2_SETTINGS = minetest.settings:get("r_place.area_pos2") or "(-30,-30)"
|
|
|
|
local BORDER_POS1x, BORDER_POS1z = string.match(
|
|
BORDER_POS1_SETTINGS,
|
|
"^%s*%(%s*([^%s,]+)%s*[,%s]%s*([^%s,]+)%s*[,%s]?%s*%)()"
|
|
)
|
|
local BORDER_POS2x, BORDER_POS2z = string.match(
|
|
BORDER_POS2_SETTINGS,
|
|
"^%s*%(%s*([^%s,]+)%s*[,%s]%s*([^%s,]+)%s*[,%s]?%s*%)()"
|
|
)
|
|
|
|
BORDER_POS1x, BORDER_POS1z = tonumber(BORDER_POS1x), tonumber(BORDER_POS1z)
|
|
BORDER_POS2x, BORDER_POS2z = tonumber(BORDER_POS2x), tonumber(BORDER_POS2z)
|
|
|
|
if not (BORDER_POS1x and BORDER_POS1z and BORDER_POS2x and BORDER_POS2z) then
|
|
error("[rp_core] Please pass valid coordinates into r_place.area_pos{1,2}!")
|
|
end
|
|
|
|
NEW_BORDER = {
|
|
{
|
|
BORDER_POS1x < BORDER_POS2x and BORDER_POS1x or BORDER_POS2x,
|
|
BORDER_POS1z < BORDER_POS2z and BORDER_POS1z or BORDER_POS2z
|
|
}, {
|
|
BORDER_POS1x >= BORDER_POS2x and BORDER_POS1x or BORDER_POS2x,
|
|
BORDER_POS1z >= BORDER_POS2z and BORDER_POS1z or BORDER_POS2z
|
|
}
|
|
}
|
|
end
|
|
|
|
rp_core.area = NEW_BORDER
|
|
rp_core.area_vector = {
|
|
vector.new(rp_core.area[1][1], 1, rp_core.area[1][2]),
|
|
vector.new(rp_core.area[2][1], 1, rp_core.area[2][2]),
|
|
}
|
|
rp_core.area_size = (rp_core.area[2][1] - rp_core.area[1][1] + 1) * (rp_core.area[2][2] - rp_core.area[1][2] + 1)
|
|
|
|
if vector.in_area then
|
|
function rp_core.in_area(pos)
|
|
return vector.in_area(pos, rp_core.area_vector[1], rp_core.area_vector[2])
|
|
end
|
|
else
|
|
function rp_core.in_area(pos)
|
|
local x, y, z = pos.x, pos.y, pos.z
|
|
if y ~= 1
|
|
or x < rp_core.area[1][1]
|
|
or x > rp_core.area[2][1]
|
|
or z < rp_core.area[1][2]
|
|
or z > rp_core.area[2][2] then
|
|
return false
|
|
end
|
|
return true
|
|
end
|
|
end
|
|
|
|
minetest.after(0,function()
|
|
do -- Clear old barrier and remove out-of-range nodes
|
|
local CACHE_PATH = WP .. "/" .. "rp_core_border_cache"
|
|
local CACHE_READ = io.open(CACHE_PATH, "r")
|
|
if CACHE_READ then
|
|
local OLD_BORDER = minetest.deserialize(CACHE_READ:read("*a"))
|
|
if OLD_BORDER
|
|
and (OLD_BORDER[1][1] ~= NEW_BORDER[1][1]
|
|
or OLD_BORDER[1][2] ~= NEW_BORDER[1][2]
|
|
or OLD_BORDER[2][1] ~= NEW_BORDER[2][1]
|
|
or OLD_BORDER[2][2] ~= NEW_BORDER[2][2]) then
|
|
-- Not equal
|
|
rp_core.log("action","Removing old area barriers...")
|
|
local remove_queue = {}
|
|
|
|
-- Remove building nodes
|
|
for x = OLD_BORDER[1][1], OLD_BORDER[2][1], 1 do
|
|
for z = OLD_BORDER[1][2], OLD_BORDER[2][2], 1 do
|
|
if not rp_core.in_area(vector.new(x,1,z)) then
|
|
table.insert(remove_queue,{x,z})
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Remove old border
|
|
for x = OLD_BORDER[1][1] - 1, OLD_BORDER[2][1] + 1, 1 do
|
|
table.insert(remove_queue,{x,OLD_BORDER[1][2] - 1})
|
|
table.insert(remove_queue,{x,OLD_BORDER[2][2] + 1})
|
|
end
|
|
for z = OLD_BORDER[1][2] - 1, OLD_BORDER[2][2] + 1, 1 do
|
|
table.insert(remove_queue,{OLD_BORDER[1][1] - 1,z})
|
|
table.insert(remove_queue,{OLD_BORDER[2][1] + 1,z})
|
|
end
|
|
|
|
local VM = VoxelManip()
|
|
local pmin, pmax = VM:read_from_map(
|
|
v(OLD_BORDER[1][1] - 1,OLD_BORDER[1][2] - 1),
|
|
v(OLD_BORDER[2][1] + 1,OLD_BORDER[2][2] + 1)
|
|
)
|
|
local data = VM:get_data()
|
|
local VA = VoxelArea(pmin,pmax)
|
|
|
|
for _,pos in pairs(remove_queue) do
|
|
local vm_i = VA:index(pos[1],1,pos[2])
|
|
data[vm_i] = minetest.CONTENT_AIR
|
|
end
|
|
|
|
VM:set_data(data)
|
|
VM:calc_lighting()
|
|
VM:write_to_map()
|
|
|
|
minetest.after(1,minetest.fix_light,pmin,pmax)
|
|
end
|
|
CACHE_READ:close()
|
|
end
|
|
-- Write back to cache
|
|
local CACHE_WRITE = io.open(CACHE_PATH, "w")
|
|
if CACHE_WRITE then
|
|
CACHE_WRITE:write(minetest.serialize(NEW_BORDER))
|
|
CACHE_WRITE:close()
|
|
end
|
|
end
|
|
|
|
do -- Construct area
|
|
rp_core.log("action","Constructing area")
|
|
local CONTENT_BORDER = minetest.get_content_id("rp_mapgen_nodes:border")
|
|
local CONTENT_FILL = minetest.get_content_id("rp_mapgen_nodes:default_fill")
|
|
local CONTENT_AIR = minetest.CONTENT_AIR
|
|
local CONTENT_IGNORE = minetest.CONTENT_IGNORE
|
|
|
|
local VM = VoxelManip()
|
|
local pmin, pmax = VM:read_from_map(
|
|
v(NEW_BORDER[1][1] - 1,NEW_BORDER[1][2] - 1),
|
|
v(NEW_BORDER[2][1] + 1,NEW_BORDER[2][2] + 1)
|
|
)
|
|
local data = VM:get_data()
|
|
local VA = VoxelArea(pmin,pmax)
|
|
|
|
for vm_i, d in ipairs(data) do
|
|
local pos = VA:position(vm_i)
|
|
local x,y,z = pos.x, pos.y, pos.z
|
|
if y ~= 1
|
|
or x < NEW_BORDER[1][1] - 1
|
|
or x > NEW_BORDER[2][1] + 1
|
|
or z < NEW_BORDER[1][2] - 1
|
|
or z > NEW_BORDER[2][2] + 1 then
|
|
data[vm_i] = CONTENT_IGNORE
|
|
elseif x == NEW_BORDER[1][1] - 1
|
|
or x == NEW_BORDER[2][1] + 1
|
|
or z == NEW_BORDER[1][2] - 1
|
|
or z == NEW_BORDER[2][2] + 1 then
|
|
data[vm_i] = CONTENT_BORDER
|
|
elseif d == CONTENT_AIR
|
|
or d == CONTENT_IGNORE
|
|
or d == CONTENT_BORDER then
|
|
data[vm_i] = CONTENT_FILL
|
|
else
|
|
data[vm_i] = CONTENT_IGNORE
|
|
end
|
|
end
|
|
|
|
VM:set_data(data)
|
|
VM:write_to_map()
|
|
|
|
minetest.after(1,minetest.fix_light,pmin,pmax)
|
|
end
|
|
end) |