const AROUND : Array[Vector2i] = [ Vector2i(-1, 0), Vector2i(0, -1), Vector2i(1, 0), Vector2i(0, 1) ] func compute_water_from(source : Vector2i, heights : PackedFloat64Array, size : Vector2i, required_output : float = 1.) -> PackedFloat64Array: assert(source.x < size.x and source.y < size.y) var cell_count : int = size.x * size.y var water : PackedFloat64Array = PackedFloat64Array() water.resize(cell_count); water.fill(NAN) var sort_func : Callable = func (a : Vector2i, b : Vector2i) -> bool: var ai : int = a.y * size.x + a.x; var bi : int = b.y * size.x + b.x return heights[ai] < heights[bi] var compute : PackedByteArray = PackedByteArray() compute.resize(cell_count); compute.fill(0) var queue : Array[Vector2i] = [ source ] var stack : Array[int] = [ source.y * size.x + source.x ] var lowest_output : float = NAN var current_output : float = NAN while not (queue.is_empty() or (is_finite(current_output) and (current_output - lowest_output) >= required_output)): var current : Vector2i = queue.pop_front() var idx : int = current.y * size.x + current.x if compute[idx] != 0: continue compute[idx] = 1 stack.append(idx) for a : Vector2i in AROUND: var v : Vector2i = current + a if v.x < 0 or v.y < 0 or v.x == size.x or v.y == size.y: if not is_finite(lowest_output): lowest_output = heights[idx] current_output = lowest_output elif heights[idx] < lowest_output: lowest_output = heights[idx] else: current_output = heights[idx] break var vidx : int = v.y * size.x + v.x if compute[vidx] != 0: continue # Add to queue var i : int = max(0, queue.bsearch_custom(v, sort_func)) queue.insert(i, v) # Resolve water level var water_level : float = heights[stack.back()] for i : int in range(stack.size() - 1, -1, -1): var idx : int = stack[i] water_level = max(heights[idx], water_level) water[idx] = water_level return water
or share this direct link: