mirror of
https://github.com/sbrl/Minetest-WorldEditAdditions.git
synced 2024-11-26 09:03:01 +00:00
//erode: initial river algorithm implementation
This commit is contained in:
parent
17b8f8a555
commit
9ecdd01914
2 changed files with 115 additions and 2 deletions
|
@ -24,14 +24,27 @@ function worldeditadditions.erode.run(pos1, pos2, algorithm, params)
|
||||||
-- worldeditadditions.format.array_2d(heightmap, heightmap_size.x)
|
-- worldeditadditions.format.array_2d(heightmap, heightmap_size.x)
|
||||||
local success, msg, stats
|
local success, msg, stats
|
||||||
if algorithm == "snowballs" then
|
if algorithm == "snowballs" then
|
||||||
success, msg = worldeditadditions.erode.snowballs(heightmap, heightmap_eroded, heightmap_size, region_height, params)
|
success, msg = worldeditadditions.erode.snowballs(
|
||||||
|
heightmap, heightmap_eroded,
|
||||||
|
heightmap_size,
|
||||||
|
region_height,
|
||||||
|
params
|
||||||
|
)
|
||||||
|
if not success then return success, msg end
|
||||||
|
elseif algorithm == "river" then
|
||||||
|
success, msg = worldeditadditions.erode.river(
|
||||||
|
heightmap, heightmap_eroded,
|
||||||
|
heightmap_size,
|
||||||
|
region_height,
|
||||||
|
params
|
||||||
|
)
|
||||||
if not success then return success, msg end
|
if not success then return success, msg end
|
||||||
else
|
else
|
||||||
-- FUTURE: Add a new "river" algorithm here that:
|
-- FUTURE: Add a new "river" algorithm here that:
|
||||||
-- * Fills in blocks that are surrounded on more than 3 horizontal sides
|
-- * Fills in blocks that are surrounded on more than 3 horizontal sides
|
||||||
-- * Destroys blocks that have no horizontal neighbours
|
-- * Destroys blocks that have no horizontal neighbours
|
||||||
-- A bit like cellular automata actually.
|
-- A bit like cellular automata actually.
|
||||||
return false, "Error: Unknown algorithm '"..algorithm.."'. Currently implemented algorithms: snowballs (2d; hydraulic-like). Ideas for algorithms to implement are welcome!"
|
return false, "Error: Unknown algorithm '"..algorithm.."'. Currently implemented algorithms: snowballs (2d; hydraulic-like), river (2d; cellular automata-like; fills potholes and lowers towers). Ideas for algorithms to implement are welcome!"
|
||||||
end
|
end
|
||||||
|
|
||||||
success, stats = worldeditadditions.apply_heightmap_changes(
|
success, stats = worldeditadditions.apply_heightmap_changes(
|
||||||
|
|
100
worldeditadditions/lib/erode/river.lua
Normal file
100
worldeditadditions/lib/erode/river.lua
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
local wea = worldeditadditions
|
||||||
|
|
||||||
|
--- Parses a comma-separated side numbers list out into a list of numbers.
|
||||||
|
-- @param list string The command separated list to parse.
|
||||||
|
-- @returns number[] A list of side numbers.
|
||||||
|
local function parse_sides_list(list)
|
||||||
|
list = list:gsub("%s", "") -- Spaces are not permitted
|
||||||
|
return wea.table_unique(wea.table_map(
|
||||||
|
wea.split(list, ","),
|
||||||
|
function(value) return tonumber(value) end
|
||||||
|
))
|
||||||
|
end
|
||||||
|
|
||||||
|
function worldeditadditions.erode.river(heightmap_initial, heightmap, heightmap_size, region_height, params_custom)
|
||||||
|
local params = {
|
||||||
|
steps = 1, -- Number of rounds/passes of the algorithm to run
|
||||||
|
remove_sides = "0,1", -- Cells with this many adjacent horizontal neighbours will be removed
|
||||||
|
fill_sides = "4,3" -- Cells with this many adjaect horizontal neighbours will be filled in
|
||||||
|
}
|
||||||
|
-- Apply the custom settings
|
||||||
|
wea.table_apply(params_custom, params)
|
||||||
|
|
||||||
|
params.remove_sides = parse_sides_list(params.remove_sides)
|
||||||
|
params.fill_sides = parse_sides_list(params.fill_sides)
|
||||||
|
|
||||||
|
local timings = {}
|
||||||
|
local filled = 0
|
||||||
|
local removed = 0
|
||||||
|
for i=1,params.steps do
|
||||||
|
local time_start = wea.get_ms_time()
|
||||||
|
|
||||||
|
for z = heightmap_size.z - 1, 0, -1 do
|
||||||
|
for x = heightmap_size.x - 1, 0, -1 do
|
||||||
|
local hi = z*heightmap_size.x + x
|
||||||
|
local thisheight = heightmap[hi]
|
||||||
|
|
||||||
|
local sides = 0
|
||||||
|
local adjacent_heights = { }
|
||||||
|
if x > 0 then
|
||||||
|
table.insert(adjacent_heights, heightmap[z*heightmap_size.x + x-1])
|
||||||
|
if heightmap[z*heightmap_size.x + x-1] >= thisheight then
|
||||||
|
sides = sides + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if x < heightmap_size.x - 1 then
|
||||||
|
table.insert(adjacent_heights, heightmap[z*heightmap_size.x + x+1])
|
||||||
|
if heightmap[z*heightmap_size.x + x+1] >= thisheight then
|
||||||
|
sides = sides + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if z > 0 then
|
||||||
|
table.insert(adjacent_heights, heightmap[(z-1)*heightmap_size.x + x])
|
||||||
|
if heightmap[(z-1)*heightmap_size.x + x] >= thisheight then
|
||||||
|
sides = sides + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if z < heightmap_size.z - 1 then
|
||||||
|
table.insert(adjacent_heights, heightmap[(z+1)*heightmap_size.x + x])
|
||||||
|
if heightmap[(z+1)*heightmap_size.x + x] >= thisheight then
|
||||||
|
sides = sides + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local action = "none"
|
||||||
|
for i,sidecount in ipairs(params.fill_sides) do
|
||||||
|
if sidecount == sides then
|
||||||
|
action = "fill"
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
for i,sidecount in ipairs(params.remove_sides) do
|
||||||
|
if sidecount == sides then
|
||||||
|
action = "remove"
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if action == "fill" then
|
||||||
|
local above_us = wea.table_filter(adjacent_heights,
|
||||||
|
function(height) return height > thisheight end
|
||||||
|
)
|
||||||
|
local above_us_next = wea.min(above_us)
|
||||||
|
heightmap[hi] = above_us_next
|
||||||
|
filled = filled + 1
|
||||||
|
elseif action == "remove" then
|
||||||
|
local below_us = wea.table_filter(adjacent_heights,
|
||||||
|
function(height) return height < thisheight end
|
||||||
|
)
|
||||||
|
local below_us_next = wea.max(below_us)
|
||||||
|
heightmap[hi] = below_us_next
|
||||||
|
removed = removed + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
table.insert(timings, wea.get_ms_time() - time_start)
|
||||||
|
end
|
||||||
|
|
||||||
|
return true, params.steps.." steps made, raising "..filled.." and lowering "..removed.." columns in "..wea.format.human_time(wea.sum(timings)).." (~"..wea.format.human_time(wea.average(timings)).." per step)"
|
||||||
|
end
|
Loading…
Reference in a new issue