mirror of
				https://github.com/sbrl/Minetest-WorldEditAdditions
				synced 2025-11-04 05:53:07 +01:00 
			
		
		
		
	fix all the crashes with the new erosion algorithm
......but it doesn't look like it's functioning as intended just yet
This commit is contained in:
		
							parent
							
								
									acb288b984
								
							
						
					
					
						commit
						997eb4d101
					
				@ -27,13 +27,14 @@ function worldeditadditions.erode.run(pos1, pos2, algorithm, params)
 | 
			
		||||
		return false, "Error: Unknown algorithm '"..algorithm.."'. Currently implemented algorithms: snowballs (2d; hydraulic-like). Ideas for algorithms to implement are welcome!"
 | 
			
		||||
	end
 | 
			
		||||
	
 | 
			
		||||
	local success, msg = worldeditadditions.apply_heightmap_changes(
 | 
			
		||||
	local success, stats = worldeditadditions.apply_heightmap_changes(
 | 
			
		||||
		pos1, pos2, area, data,
 | 
			
		||||
		heightmap, heightmap_eroded, heightmap_size
 | 
			
		||||
	)
 | 
			
		||||
	if not success then return success, msg end
 | 
			
		||||
	
 | 
			
		||||
	if not success then return success, stats end
 | 
			
		||||
	worldedit.manip_helpers.finish(manip, data)
 | 
			
		||||
	
 | 
			
		||||
	print("[erode] stats")
 | 
			
		||||
	print(worldeditadditions.map_stringify(stats))
 | 
			
		||||
	return true, stats
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
@ -1,46 +1,48 @@
 | 
			
		||||
 | 
			
		||||
-- Test command: //multi //fp set1 1312 5 5543 //fp set2 1336 18 5521 //erode//multi //fp set1 1312 5 5543 //fp set2 1336 18 5521 //erode
 | 
			
		||||
 | 
			
		||||
local function snowball(heightmap, normalmap, heightmap_size, startpos, params)
 | 
			
		||||
	local offset = { -- Random jitter - apparently helps to avoid snowballs from entrenching too much
 | 
			
		||||
		x = (math.random() * 2 - 1) * params.radius,
 | 
			
		||||
		z = (math.random() * 2 - 1) * params.radius
 | 
			
		||||
	}
 | 
			
		||||
	local sediment = 0
 | 
			
		||||
	local pos = { x = startpos.x, z = startpos.z }
 | 
			
		||||
	local pos_prev = { x = pos.x, z = pos.z }
 | 
			
		||||
	local velocity = { x = 0, z = 0 }
 | 
			
		||||
	local heightmap_length = #heightmap
 | 
			
		||||
	
 | 
			
		||||
	-- print("[snowball] startpos ("..pos.x..", "..pos.z..")")
 | 
			
		||||
	
 | 
			
		||||
	for i = 1, params.snowball_max_steps do
 | 
			
		||||
		local hi = math.floor(pos.z+offset.z+0.5)*heightmap_size[1] + math.floor(pos.x+offset.x+0.5)
 | 
			
		||||
		if hi > heightmap_length then break end
 | 
			
		||||
		
 | 
			
		||||
		local x = pos.x
 | 
			
		||||
		local z = pos.z
 | 
			
		||||
		local hi = math.floor(z+0.5)*heightmap_size[1] + math.floor(x+0.5)
 | 
			
		||||
		-- Stop if we go out of bounds
 | 
			
		||||
		if offset.x < 0 or offset.z < 0
 | 
			
		||||
			or offset.x >= heightmap[1] or offset.z >= heightmap[0] then
 | 
			
		||||
			break
 | 
			
		||||
		if x < 0 or z < 0
 | 
			
		||||
			or x >= heightmap[1]-1 or z >= heightmap[0]-1 then
 | 
			
		||||
			-- print("[snowball] hit edge; stopping at ("..x..", "..z.."), (bounds @ "..heightmap_size[1]..", "..heightmap_size[0]..")")
 | 
			
		||||
			return
 | 
			
		||||
		end
 | 
			
		||||
		-- print("[snowball] now at ("..x..", "..z..") (bounds @ "..heightmap_size[1]..", "..heightmap_size[0]..")")
 | 
			
		||||
		
 | 
			
		||||
		if hi > heightmap_length then print("[snowball] out-of-bounds on the array, hi: "..hi..", heightmap_length: "..heightmap_length) return end
 | 
			
		||||
		
 | 
			
		||||
		-- print("[snowball] sediment", sediment, "rate_deposit", params.rate_deposit, "normalmap[hi].z", normalmap[hi].z)
 | 
			
		||||
		local step_deposit = sediment * params.rate_deposit * normalmap[hi].z
 | 
			
		||||
		local step_erode = params.rate_erosion * (1 - normalmap[hi].z) * math.min(1, i*params.scale_iterations)
 | 
			
		||||
		
 | 
			
		||||
		local step_diff = step_deposit - step_erode
 | 
			
		||||
		
 | 
			
		||||
		-- Erode / Deposit, but only if we are on a different node than we were in the last step
 | 
			
		||||
		if math.floor(pos_prev.x) ~= math.floor(pos.x)
 | 
			
		||||
			and math.floor(pos_prev.z) ~= math.floor(pos.z) then
 | 
			
		||||
			heightmap[hi] = heightmap[hi] + (deposit - erosion)
 | 
			
		||||
		if math.floor(pos_prev.x) ~= math.floor(x)
 | 
			
		||||
			and math.floor(pos_prev.z) ~= math.floor(z) then
 | 
			
		||||
			heightmap[hi] = heightmap[hi] + step_diff
 | 
			
		||||
		end
 | 
			
		||||
		
 | 
			
		||||
		velocity.x = params.friction * velocity.x + normalmap[hi].x * params.speed
 | 
			
		||||
		velocity.z = params.friction * velocity.z + normalmap[hi].y * params.speed
 | 
			
		||||
		pos_prev.x = pos.x
 | 
			
		||||
		pos_prev.z = pos.z
 | 
			
		||||
		pos_prev.x = x
 | 
			
		||||
		pos_prev.z = z
 | 
			
		||||
		pos.x = pos.x + velocity.x
 | 
			
		||||
		pos.z = pos.z + velocity.z
 | 
			
		||||
	end
 | 
			
		||||
	
 | 
			
		||||
	-- Round everything to the nearest int, since you can't really have
 | 
			
		||||
	-- something like .141592671 of a node
 | 
			
		||||
	for i,v in ipairs(heightmap) do
 | 
			
		||||
		heightmap[i] = math.floor(heightmap[i] + 0.5)
 | 
			
		||||
		sediment = sediment + step_diff
 | 
			
		||||
	end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
@ -64,12 +66,27 @@ function worldeditadditions.erode.snowballs(heightmap, heightmap_size, params)
 | 
			
		||||
		snowball_count = 50000
 | 
			
		||||
	}, params)
 | 
			
		||||
	
 | 
			
		||||
	print("[erode/snowballs] params: "..worldeditadditions.map_stringify(params))
 | 
			
		||||
	
 | 
			
		||||
	local normals = worldeditadditions.calculate_normals(heightmap, heightmap_size)
 | 
			
		||||
	
 | 
			
		||||
	for i = 1, params.snowball_count do
 | 
			
		||||
		snowball(
 | 
			
		||||
			heightmap, normals, heightmap_size,
 | 
			
		||||
			{ x = math.random() }
 | 
			
		||||
			{
 | 
			
		||||
				x = math.random() * (heightmap_size[1] - 1),
 | 
			
		||||
				z = math.random() * (heightmap_size[0] - 1)
 | 
			
		||||
			},
 | 
			
		||||
			params
 | 
			
		||||
		)
 | 
			
		||||
	end
 | 
			
		||||
	
 | 
			
		||||
	-- Round everything to the nearest int, since you can't really have
 | 
			
		||||
	-- something like .141592671 of a node
 | 
			
		||||
	-- Note that we do this after *all* the erosion is complete
 | 
			
		||||
	for i,v in ipairs(heightmap) do
 | 
			
		||||
		heightmap[i] = math.floor(heightmap[i] + 0.5)
 | 
			
		||||
	end
 | 
			
		||||
	
 | 
			
		||||
	return true, params.snowball_count.." snowballs simulated"
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
@ -231,7 +231,7 @@ end
 | 
			
		||||
function worldeditadditions.map_stringify(map)
 | 
			
		||||
	local result = {}
 | 
			
		||||
	for key, value in pairs(map) do
 | 
			
		||||
		table.insert(key.."\t"..value)
 | 
			
		||||
		table.insert(result, key.."\t"..value)
 | 
			
		||||
	end
 | 
			
		||||
	return table.concat(result, "\n")
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
@ -62,16 +62,18 @@ function worldeditadditions.calculate_normals(heightmap, heightmap_size)
 | 
			
		||||
			if x - 1 > 0 then left = heightmap[z*heightmap_size[1] + (x-1)] end
 | 
			
		||||
			if x + 1 < heightmap_size[1]-1 then right = heightmap[z*heightmap_size[1] + (x+1)] end
 | 
			
		||||
			
 | 
			
		||||
			print("[normals] UP	| index", (z-1)*heightmap_size[1] + x, "z", z, "z-1", z - 1, "up", up, "limit", 0)
 | 
			
		||||
			print("[normals] DOWN	| index", (z+1)*heightmap_size[1] + x, "z", z, "z+1", z + 1, "down", down, "limit", heightmap_size[1]-1)
 | 
			
		||||
			print("[normals] LEFT	| index", z*heightmap_size[1] + (x-1), "x", x, "x-1", x - 1, "left", left, "limit", 0)
 | 
			
		||||
			print("[normals] RIGHT	| index", z*heightmap_size[1] + (x+1), "x", x, "x+1", x + 1, "right", right, "limit", heightmap_size[1]-1)
 | 
			
		||||
			-- print("[normals] UP	| index", (z-1)*heightmap_size[1] + x, "z", z, "z-1", z - 1, "up", up, "limit", 0)
 | 
			
		||||
			-- print("[normals] DOWN	| index", (z+1)*heightmap_size[1] + x, "z", z, "z+1", z + 1, "down", down, "limit", heightmap_size[1]-1)
 | 
			
		||||
			-- print("[normals] LEFT	| index", z*heightmap_size[1] + (x-1), "x", x, "x-1", x - 1, "left", left, "limit", 0)
 | 
			
		||||
			-- print("[normals] RIGHT	| index", z*heightmap_size[1] + (x+1), "x", x, "x+1", x + 1, "right", right, "limit", heightmap_size[1]-1)
 | 
			
		||||
			
 | 
			
		||||
			result[hi] = worldeditadditions.vector.normalize({
 | 
			
		||||
				x = left - right,
 | 
			
		||||
				y = 2, -- Z & Y are flipped
 | 
			
		||||
				z = down - up
 | 
			
		||||
			})
 | 
			
		||||
			
 | 
			
		||||
			-- print("[normals] at "..hi.." ("..x..", "..z..") normal "..worldeditadditions.vector.tostring(result[hi]))
 | 
			
		||||
		end
 | 
			
		||||
	end
 | 
			
		||||
	return result
 | 
			
		||||
@ -85,9 +87,9 @@ function worldeditadditions.apply_heightmap_changes(pos1, pos2, area, data, heig
 | 
			
		||||
		for x = heightmap_size[1], 0, -1 do
 | 
			
		||||
			local hi = z*heightmap_size[1] + x
 | 
			
		||||
			
 | 
			
		||||
			local height_old = heightmap[hi]
 | 
			
		||||
			local height_old = heightmap_old[hi]
 | 
			
		||||
			local height_new = heightmap_new[hi]
 | 
			
		||||
			-- print("[conv/save] hi", hi, "height_old", heightmap[hi], "height_new", heightmap_new[hi], "z", z, "x", x, "pos1.y", pos1.y)
 | 
			
		||||
			-- print("[conv/save] hi", hi, "height_old", heightmap_old[hi], "height_new", heightmap_new[hi], "z", z, "x", x, "pos1.y", pos1.y)
 | 
			
		||||
			
 | 
			
		||||
			-- Lua doesn't have a continue statement :-/
 | 
			
		||||
			if height_old == height_new then
 | 
			
		||||
 | 
			
		||||
@ -37,7 +37,7 @@ worldedit.register_command("erode", {
 | 
			
		||||
		)
 | 
			
		||||
		local time_taken = worldeditadditions.get_ms_time() - start_time
 | 
			
		||||
		
 | 
			
		||||
		minetest.log("action", name .. " used //erode "..algorithm.." at " .. worldeditadditions.vector.tostring(worldedit.pos1[name]) .. ", replacing " .. changes.replaced .. " nodes and skipping " .. changes.skipped_columns .. " columns in " .. time_taken .. "s")
 | 
			
		||||
		return true, changes.replaced .. " nodes replaced and " .. changes.skipped_columns .. " columns skipped in " .. worldeditadditions.human_time(time_taken)
 | 
			
		||||
		minetest.log("action", name .. " used //erode "..algorithm.." at " .. worldeditadditions.vector.tostring(worldedit.pos1[name]) .. ", adding " .. stats.added .. " nodes and removing " .. stats.removed .. " nodes in " .. time_taken .. "s")
 | 
			
		||||
		return true, stats.added .. " nodes added and " .. stats.removed .. " nodes removed in " .. worldeditadditions.human_time(time_taken)
 | 
			
		||||
	end
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user