62 lines
2.9 KiB
Python
62 lines
2.9 KiB
Python
#!/usr/bin/env python3
|
|
"""Deterministic floating-island columns, independent of any map or server.
|
|
|
|
Large contour harmonics shape the silhouette; correlated low-frequency fields
|
|
shape the underside. Surface grading and gameplay layout belong to the caller.
|
|
This is an offline geometry helper, not an additional MCP tool or live edit API.
|
|
"""
|
|
import math
|
|
|
|
|
|
def smooth(value):
|
|
value = max(0., min(1., value))
|
|
return value * value * (3 - 2 * value)
|
|
|
|
|
|
def hash_value(x, z, seed):
|
|
n = (x * 374761393 + z * 668265263 + seed * 1442695041) & 0xffffffff
|
|
n = ((n ^ (n >> 13)) * 1274126177) & 0xffffffff
|
|
return (n ^ (n >> 16)) / 0xffffffff
|
|
|
|
|
|
def noise(x, z, seed):
|
|
x0, z0 = math.floor(x), math.floor(z)
|
|
u, v = smooth(x - x0), smooth(z - z0)
|
|
a = hash_value(x0, z0, seed) * (1 - u) + hash_value(x0 + 1, z0, seed) * u
|
|
b = hash_value(x0, z0 + 1, seed) * (1 - u) + hash_value(x0 + 1, z0 + 1, seed) * u
|
|
return a * (1 - v) + b * v
|
|
|
|
|
|
def columns(cx, cz, radius_x, radius_z, surface_y, depth, seed, contour=.055):
|
|
"""Return {(x,z): {bottom, top, radial}} with inclusive occupied Y ranges.
|
|
|
|
``radial`` is normalized distance from the warped boundary (0 centre,1 rim).
|
|
The terrain is a connected solid below each top, with no inferred live air.
|
|
Neighbouring columns have coherent variation; random per-block noise is left
|
|
out deliberately. Integers give reproducible inclusive world coordinates.
|
|
"""
|
|
values = (radius_x, radius_z, depth, contour)
|
|
if not all(math.isfinite(v) for v in values) or min(radius_x, radius_z, depth) <= 0 or not 0 <= contour <= .2:
|
|
raise ValueError('Use positive finite radii/depth and contour in0..0.2')
|
|
if any(type(v) is not int for v in (cx, cz, surface_y, seed)):
|
|
raise ValueError('Centre, surface and seed must be integers')
|
|
result = {}
|
|
for x in range(math.floor(cx - radius_x * 1.3), math.ceil(cx + radius_x * 1.3) + 1):
|
|
for z in range(math.floor(cz - radius_z * 1.3), math.ceil(cz + radius_z * 1.3) + 1):
|
|
dx, dz = (x - cx) / radius_x, (z - cz) / radius_z
|
|
angle = math.atan2(dz, dx)
|
|
boundary = 1 + contour * (math.sin(3 * angle + seed * .07)
|
|
+ .45 * math.sin(7 * angle - seed * .11))
|
|
radial = math.hypot(dx, dz) / boundary
|
|
if radial > 1:
|
|
continue
|
|
# A broad taper and coherent hanging buttresses give a recognisable
|
|
# mass even when viewed in silhouette, before material decoration.
|
|
taper = max(0., 1 - radial ** 1.55) ** .62
|
|
buttress = .63 + .37 * noise(x / 7.5, z / 7.5, seed + 31)
|
|
ribs = 2.5 * smooth(noise(x / 3.8, z / 3.8, seed + 57))
|
|
thickness = max(3, round(3 + depth * taper * buttress + ribs))
|
|
result[x, z] = {'top': surface_y, 'bottom': surface_y - thickness + 1,
|
|
'radial': radial}
|
|
return result
|