mc gen start
This commit is contained in:
@@ -0,0 +1,70 @@
|
|||||||
|
package gen
|
||||||
|
|
||||||
|
type NoiseParam int
|
||||||
|
|
||||||
|
const (
|
||||||
|
NoiseParamTemperature NoiseParam = iota
|
||||||
|
NoiseParamHumidity
|
||||||
|
NoiseParamContinentalNess
|
||||||
|
NoiseParamErosion
|
||||||
|
NoiseParamShift
|
||||||
|
NoiseParamWeirdness
|
||||||
|
)
|
||||||
|
|
||||||
|
type NoiseParamMapV struct {
|
||||||
|
A []float64
|
||||||
|
S string
|
||||||
|
O int
|
||||||
|
}
|
||||||
|
|
||||||
|
var NoiseParamMap = map[NoiseParam]NoiseParamMapV{
|
||||||
|
NoiseParamShift: {A: []float64{1, 1, 1, 0}, S: "minecraft:offset", O: -3},
|
||||||
|
NoiseParamTemperature: {A: []float64{1.5, 0, 1, 0, 0, 0}, S: "minecraft:temperature", O: -10},
|
||||||
|
NoiseParamHumidity: {A: []float64{1, 1, 0, 0, 0, 0}, S: "minecraft:vegetation", O: -8},
|
||||||
|
NoiseParamContinentalNess: {A: []float64{1, 1, 2, 2, 2, 1, 1, 1, 1}, S: "minecraft:continentalness", O: -9},
|
||||||
|
NoiseParamErosion: {A: []float64{1, 1, 0, 1, 1}, S: "minecraft:erosion", O: -9},
|
||||||
|
NoiseParamWeirdness: {A: []float64{1, 2, 1, 0, 0, 0}, S: "minecraft:ridge", O: -7},
|
||||||
|
}
|
||||||
|
|
||||||
|
func InitClimateSeed(n NoiseParam, x Xoroshiro, large bool, nmax int) DoublePerlin {
|
||||||
|
v := NoiseParamMap[n]
|
||||||
|
s := v.S
|
||||||
|
if large && n != NoiseParamShift && n != NoiseParamWeirdness {
|
||||||
|
s += "_large"
|
||||||
|
}
|
||||||
|
x.XorString(s) // SLOW potential
|
||||||
|
return DoublePerlinFromXoroshiro(x, v.A, v.O, len(v.A), nmax)
|
||||||
|
}
|
||||||
|
|
||||||
|
type BiomeNoise struct {
|
||||||
|
Temperature, Humidity, ContinentalNess, Erosion, Shift, Weirdness DoublePerlin
|
||||||
|
}
|
||||||
|
|
||||||
|
func BiomeNoiseFromXoroshiro(x Xoroshiro, large bool) (v BiomeNoise) {
|
||||||
|
x = x.Split()
|
||||||
|
|
||||||
|
v.Temperature = InitClimateSeed(NoiseParamTemperature, x, large, -1)
|
||||||
|
v.Humidity = InitClimateSeed(NoiseParamHumidity, x, large, -1)
|
||||||
|
v.ContinentalNess = InitClimateSeed(NoiseParamContinentalNess, x, large, -1)
|
||||||
|
v.Erosion = InitClimateSeed(NoiseParamErosion, x, large, -1)
|
||||||
|
v.Shift = InitClimateSeed(NoiseParamShift, x, large, -1)
|
||||||
|
v.Weirdness = InitClimateSeed(NoiseParamWeirdness, x, large, -1)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b BiomeNoise) Sample(x, y, z int) {
|
||||||
|
px := float64(x)
|
||||||
|
pz := float64(z)
|
||||||
|
px += b.Shift.Sample(px, 0, pz) * 4
|
||||||
|
pz += b.Shift.Sample(pz, float64(x), 0) * 4
|
||||||
|
|
||||||
|
c := b.ContinentalNess.Sample(px, 0, pz)
|
||||||
|
e := b.Erosion.Sample(px, 0, pz)
|
||||||
|
w := b.Weirdness.Sample(px, 0, pz)
|
||||||
|
t := b.Temperature.Sample(px, 0, pz)
|
||||||
|
h := b.Humidity.Sample(px, 0, pz)
|
||||||
|
|
||||||
|
d := float64(0) // FIXME
|
||||||
|
var combinedData = [6]int64{int64(t * 10000), int64(h * 10000), int64(c * 10000), int64(e * 10000), int64(d * 10000), int64(w * 10000)}
|
||||||
|
_ = combinedData
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
package gen
|
||||||
|
|
||||||
|
type DoublePerlin struct {
|
||||||
|
Amplitude float64
|
||||||
|
A Octave
|
||||||
|
B Octave
|
||||||
|
}
|
||||||
|
|
||||||
|
func DoublePerlinFromXoroshiro(x Xoroshiro, amplitudes []float64, omin int, lenn int, nmax int) (d DoublePerlin) {
|
||||||
|
na := -1
|
||||||
|
nb := -1
|
||||||
|
if nmax > 0 {
|
||||||
|
na = (nmax + 1) >> 1
|
||||||
|
nb = nmax - na
|
||||||
|
}
|
||||||
|
d.A = OctaveFromXoroshiro(x, amplitudes, omin, lenn, na)
|
||||||
|
d.B = OctaveFromXoroshiro(x, amplitudes, omin, lenn, nb)
|
||||||
|
|
||||||
|
for i := lenn - 1; i >= 0 && amplitudes[i] == 0.0; i-- {
|
||||||
|
lenn--
|
||||||
|
}
|
||||||
|
for i := 0; amplitudes[i] == 0.0; i++ {
|
||||||
|
lenn--
|
||||||
|
}
|
||||||
|
var ampInits = []float64{ // (5 ./ 3) * len / (len + 1), len = 2..16
|
||||||
|
0, 5 / 6, 10 / 9, 15 / 12, 20 / 15, 25 / 18, 30 / 21, 35 / 24, 40 / 27, 45 / 30,
|
||||||
|
50 / 33, 55 / 36, 60 / 39, 65 / 42, 70 / 45, 75 / 48, 80 / 51,
|
||||||
|
}
|
||||||
|
d.Amplitude = ampInits[lenn]
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const DoublePerlinNoiseFactor = 337.0 / 331.0
|
||||||
|
|
||||||
|
func (d *DoublePerlin) Sample(x, y, z float64) float64 {
|
||||||
|
return d.Amplitude * (d.A.Sample(x, y, z) + d.B.Sample(x*DoublePerlinNoiseFactor, y*DoublePerlinNoiseFactor, z*DoublePerlinNoiseFactor))
|
||||||
|
}
|
||||||
+137
@@ -0,0 +1,137 @@
|
|||||||
|
package gen
|
||||||
|
|
||||||
|
import "math"
|
||||||
|
|
||||||
|
type PerlinNoise struct {
|
||||||
|
d [257]byte
|
||||||
|
h2 byte
|
||||||
|
xoffset, yoffset, zoffset, amplitude, lacunarity, d2, t2 float64
|
||||||
|
}
|
||||||
|
|
||||||
|
func indexedLerp(idx uint8, a, b, c float64) float64 {
|
||||||
|
switch idx & 0xf {
|
||||||
|
case 0:
|
||||||
|
return a + b
|
||||||
|
case 1:
|
||||||
|
return -a + b
|
||||||
|
case 2:
|
||||||
|
return a - b
|
||||||
|
case 3:
|
||||||
|
return -a - b
|
||||||
|
case 4:
|
||||||
|
return a + c
|
||||||
|
case 5:
|
||||||
|
return -a + c
|
||||||
|
case 6:
|
||||||
|
return a - c
|
||||||
|
case 7:
|
||||||
|
return -a - c
|
||||||
|
case 8:
|
||||||
|
return b + c
|
||||||
|
case 9:
|
||||||
|
return -b + c
|
||||||
|
case 10:
|
||||||
|
return b - c
|
||||||
|
case 11:
|
||||||
|
return -b - c
|
||||||
|
case 12:
|
||||||
|
return a + b
|
||||||
|
case 13:
|
||||||
|
return -b + c
|
||||||
|
case 14:
|
||||||
|
return -a + b
|
||||||
|
case 15:
|
||||||
|
return -b - c
|
||||||
|
}
|
||||||
|
panic("unreachable")
|
||||||
|
}
|
||||||
|
|
||||||
|
func lerp(part, from, to float64) float64 {
|
||||||
|
return from + part*(to-from)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n PerlinNoise) Sample(x, y, z float64, yamp, ymin float64) (v float64) {
|
||||||
|
var h1, h2, h3 uint8
|
||||||
|
var t1, t2, t3 float64
|
||||||
|
|
||||||
|
if y == 0 {
|
||||||
|
y = n.d2
|
||||||
|
h2 = n.h2
|
||||||
|
t2 = n.t2
|
||||||
|
} else {
|
||||||
|
y += n.yoffset
|
||||||
|
yFloored := math.Floor(y)
|
||||||
|
y -= yFloored
|
||||||
|
h2 = uint8(int(yFloored))
|
||||||
|
t2 = y * y * y * (y*(y*6.0-15.0) + 10.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
x += n.xoffset
|
||||||
|
z += n.zoffset
|
||||||
|
|
||||||
|
xFloored := math.Floor(x)
|
||||||
|
zFloored := math.Floor(z)
|
||||||
|
x -= xFloored
|
||||||
|
z -= zFloored
|
||||||
|
|
||||||
|
h1 = uint8(int(xFloored))
|
||||||
|
h3 = uint8(int(zFloored))
|
||||||
|
|
||||||
|
t1 = x * x * x * (x*(x*6.0-15.0) + 10.0)
|
||||||
|
t3 = z * z * z * (z*(z*6.0-15.0) + 10.0)
|
||||||
|
|
||||||
|
if yamp != 0 {
|
||||||
|
y -= math.Floor(math.Min(y, ymin)/yamp) * yamp
|
||||||
|
}
|
||||||
|
|
||||||
|
a1 := n.d[h1] + h2
|
||||||
|
b1 := n.d[h1+1] + h2
|
||||||
|
|
||||||
|
a2 := n.d[a1] + h3
|
||||||
|
b2 := n.d[b1] + h3
|
||||||
|
a3 := n.d[a1+1] + h3
|
||||||
|
b3 := n.d[b1+1] + h3
|
||||||
|
|
||||||
|
l1 := indexedLerp(n.d[a2], x, y, z)
|
||||||
|
l2 := indexedLerp(n.d[b2], x-1, y, z)
|
||||||
|
l3 := indexedLerp(n.d[a3], x, y-1, z)
|
||||||
|
l4 := indexedLerp(n.d[b3], x-1, y-1, z)
|
||||||
|
l5 := indexedLerp(n.d[a2+1], x, y, z-1)
|
||||||
|
l6 := indexedLerp(n.d[b2+1], x-1, y, z-1)
|
||||||
|
l7 := indexedLerp(n.d[a3+1], x, y-1, z-1)
|
||||||
|
l8 := indexedLerp(n.d[b3+1], x-1, y-1, z-1)
|
||||||
|
|
||||||
|
l1 = lerp(t1, l1, l2)
|
||||||
|
l3 = lerp(t1, l3, l4)
|
||||||
|
l5 = lerp(t1, l5, l6)
|
||||||
|
l7 = lerp(t1, l7, l8)
|
||||||
|
|
||||||
|
l1 = lerp(t2, l1, l3)
|
||||||
|
l5 = lerp(t2, l5, l7)
|
||||||
|
|
||||||
|
return lerp(t3, l1, l5)
|
||||||
|
}
|
||||||
|
|
||||||
|
func PerlinNoiseFromXoroshiro(x Xoroshiro) (p PerlinNoise) {
|
||||||
|
p.xoffset = x.NextFloat64() * 256.0
|
||||||
|
p.yoffset = x.NextFloat64() * 256.0
|
||||||
|
p.zoffset = x.NextFloat64() * 256.0
|
||||||
|
p.amplitude = 1
|
||||||
|
p.lacunarity = 1
|
||||||
|
for i := range 256 {
|
||||||
|
p.d[i] = uint8(i)
|
||||||
|
}
|
||||||
|
for i := range int32(256) {
|
||||||
|
j := x.NextBound(uint32(256-i)) + i
|
||||||
|
n := p.d[i]
|
||||||
|
p.d[i] = p.d[j]
|
||||||
|
p.d[j] = n
|
||||||
|
}
|
||||||
|
p.d[256] = 0
|
||||||
|
i2 := math.Floor(p.yoffset)
|
||||||
|
d2 := p.yoffset - i2
|
||||||
|
p.h2 = uint8(int(i2))
|
||||||
|
p.d2 = d2
|
||||||
|
p.t2 = d2 * d2 * d2 * (d2*(d2*6.0-15.0) + 10.0)
|
||||||
|
return
|
||||||
|
}
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
package gen
|
||||||
|
|
||||||
|
type Octave []PerlinNoise
|
||||||
|
|
||||||
|
var octaveStrHashes = []Xoroshiro{
|
||||||
|
XoroshiroFromString("octave_-16"),
|
||||||
|
XoroshiroFromString("octave_-15"),
|
||||||
|
XoroshiroFromString("octave_-14"),
|
||||||
|
XoroshiroFromString("octave_-13"),
|
||||||
|
XoroshiroFromString("octave_-12"),
|
||||||
|
XoroshiroFromString("octave_-11"),
|
||||||
|
XoroshiroFromString("octave_-10"),
|
||||||
|
XoroshiroFromString("octave_-9"),
|
||||||
|
XoroshiroFromString("octave_-8"),
|
||||||
|
XoroshiroFromString("octave_-7"),
|
||||||
|
XoroshiroFromString("octave_-6"),
|
||||||
|
XoroshiroFromString("octave_-5"),
|
||||||
|
XoroshiroFromString("octave_-4"),
|
||||||
|
XoroshiroFromString("octave_-3"),
|
||||||
|
XoroshiroFromString("octave_-2"),
|
||||||
|
XoroshiroFromString("octave_-1"),
|
||||||
|
XoroshiroFromString("octave_0"),
|
||||||
|
}
|
||||||
|
|
||||||
|
var octaveLacunaInits = []float64{1, .5, .25, 1. / 8, 1. / 16, 1. / 32, 1. / 64, 1. / 128, 1. / 256, 1. / 512, 1. / 1024,
|
||||||
|
1. / 2048, 1. / 4096, 1. / 8192, 1. / 16384, 1. / 32768, 1. / 65536}
|
||||||
|
|
||||||
|
var octavePersistInits = []float64{0, 1, 2. / 3, 4. / 7, 8. / 15, 16. / 31, 32. / 63, 64. / 127, 128. / 255, 256. / 511, 512. / 1023,
|
||||||
|
1024. / 2047, 2048. / 4095, 4096. / 8191, 8192. / 16383, 16384. / 32767, 32768. / 65535}
|
||||||
|
|
||||||
|
func OctaveFromXoroshiro(x Xoroshiro, amplitudes []float64, omin int, lenn int, nmax int) (o Octave) {
|
||||||
|
if (-omin < 0 || -omin >= len(octaveLacunaInits)) || (lenn < 0 || lenn >= len(octavePersistInits)) {
|
||||||
|
panic("octave initialization out of range")
|
||||||
|
}
|
||||||
|
octaveX := x.Split()
|
||||||
|
i := 0
|
||||||
|
n := 0
|
||||||
|
lacuna := octaveLacunaInits[-omin]
|
||||||
|
persist := octavePersistInits[lenn]
|
||||||
|
|
||||||
|
for i < lenn && n != nmax {
|
||||||
|
if amplitudes[i] == 0 {
|
||||||
|
i++
|
||||||
|
lacuna *= 2
|
||||||
|
persist *= 0.5
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
copyX := octaveX
|
||||||
|
copyX.Xor(octaveStrHashes[16+omin+i])
|
||||||
|
p := PerlinNoiseFromXoroshiro(copyX)
|
||||||
|
p.amplitude = amplitudes[i] * persist
|
||||||
|
p.lacunarity = lacuna
|
||||||
|
o = append(o, p)
|
||||||
|
i++
|
||||||
|
n++
|
||||||
|
lacuna *= 2
|
||||||
|
persist *= 0.5
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Octave) Sample(x, y, z float64) (v float64) {
|
||||||
|
for _, n := range *o {
|
||||||
|
v += n.Sample(x*n.lacunarity, y*n.lacunarity, z*n.lacunarity, 0, 0) * n.amplitude
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
package gen
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/md5"
|
||||||
|
"encoding/binary"
|
||||||
|
)
|
||||||
|
|
||||||
|
func rotl64(x uint64, b uint8) uint64 {
|
||||||
|
return (x << b) | (x >> (64 - b))
|
||||||
|
}
|
||||||
|
|
||||||
|
type Xoroshiro struct {
|
||||||
|
L uint64
|
||||||
|
H uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Xoroshiro) Next() uint64 {
|
||||||
|
l := x.L
|
||||||
|
h := x.H
|
||||||
|
n := rotl64(l+h, 17) + l
|
||||||
|
h ^= l
|
||||||
|
x.L = rotl64(l, 49) ^ h ^ (h << 21)
|
||||||
|
x.H = rotl64(h, 28)
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Xoroshiro) NextBound(n uint32) int32 {
|
||||||
|
r := (x.Next() & 0xFFFFFFFF) * uint64(n)
|
||||||
|
if uint32(r) < n {
|
||||||
|
for uint32(r) < (^n+1)%n {
|
||||||
|
r = (x.Next() & 0xFFFFFFFF) * uint64(n)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return int32(r >> 32)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Xoroshiro) NextFloat() float32 {
|
||||||
|
return float32(x.Next()>>(64-24)) * 5.9604645e-8
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Xoroshiro) NextFloat64() float64 {
|
||||||
|
return float64(x.Next()>>(64-53)) * 1.1102230246251565e-16
|
||||||
|
}
|
||||||
|
|
||||||
|
func XoroshiroFromString(s string) (x Xoroshiro) {
|
||||||
|
sum := md5.Sum([]byte(s))
|
||||||
|
x.L = binary.BigEndian.Uint64(sum[:8])
|
||||||
|
x.H = binary.BigEndian.Uint64(sum[8:])
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func XoroshiroFromSeed(seed int64) (x Xoroshiro) {
|
||||||
|
x.L = uint64(seed) ^ 0x6a09e667f3bcc909
|
||||||
|
x.H = x.L + 0x9e3779b97f4a7c15
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func mixStafford13(s uint64) uint64 {
|
||||||
|
s = (s ^ (s >> 30)) * 0xbf58476d1ce4e5b9
|
||||||
|
s = (s ^ (s >> 27)) * 0x94d049bb133111eb
|
||||||
|
return s ^ (s >> 31)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Xoroshiro) Mix() {
|
||||||
|
x.L = mixStafford13(x.L)
|
||||||
|
x.H = mixStafford13(x.H)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Xoroshiro) Xor(x2 Xoroshiro) {
|
||||||
|
x.L ^= x2.L
|
||||||
|
x.H ^= x2.H
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Xoroshiro) XorString(s string) {
|
||||||
|
x.Xor(XoroshiroFromString(s))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Xoroshiro) Split() (x2 Xoroshiro) {
|
||||||
|
x2.L = x.Next()
|
||||||
|
x2.H = x.Next()
|
||||||
|
return
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
package gen
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestXoroshiroFromString(t *testing.T) {
|
||||||
|
x := XoroshiroFromString("minecraft:offset")
|
||||||
|
if x.L != 0x080518cf6af25384 || x.H != 0x3f3dfb40a54febd5 {
|
||||||
|
t.Errorf("bad L: %x, H: %x", x.L, x.H)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSeedChain(t *testing.T) {
|
||||||
|
var worldSeed int64 = 70388202460762
|
||||||
|
x := XoroshiroFromSeed(worldSeed)
|
||||||
|
x.XorString("minecraft:entities/wither_skeleton")
|
||||||
|
x.Mix()
|
||||||
|
i := 0
|
||||||
|
for {
|
||||||
|
_ = x.NextBound(1)
|
||||||
|
_ = x.NextBound(2)
|
||||||
|
if x.NextFloat() < 0.025 {
|
||||||
|
i++
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if i != 7 {
|
||||||
|
t.Errorf("expected 7, got %d", i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBiome(t *testing.T) {
|
||||||
|
var worldSeed int64 = 70388202460762
|
||||||
|
x := XoroshiroFromSeed(worldSeed)
|
||||||
|
x.Mix()
|
||||||
|
b := BiomeNoiseFromXoroshiro(x, false)
|
||||||
|
b.Sample(-1, -16, 0)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user