From 68f3d6aa2987216f227e933a6eb648d975993d74 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Sat, 6 Apr 2024 03:02:32 +0700 Subject: [PATCH] =?UTF-8?q?Flatten=20perlin=20noise=20structure,=20improvi?= =?UTF-8?q?ng=20perfomance=20by=20margin=20of=204=20=D0=BD=D0=B5=20=D1=80?= =?UTF-8?q?=D1=83=D0=B7=D0=B5=D0=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gradle.properties | 2 +- .../kstarbound/server/ServerConnection.kt | 1 + .../kstarbound/server/world/ServerWorld.kt | 4 + .../util/random/AbstractPerlinNoise.kt | 175 +++++++++--------- .../kstarbound/util/random/BillowNoise.kt | 3 - .../kstarbound/util/random/PerlinNoise.kt | 3 - .../kstarbound/util/random/RidgedNoise.kt | 3 - .../ru/dbotthepony/kstarbound/world/Sky.kt | 14 +- .../terrain/DisplacementTerrainSelector.kt | 4 +- 9 files changed, 99 insertions(+), 110 deletions(-) diff --git a/gradle.properties b/gradle.properties index 38bf5df3..ddd86970 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,7 +3,7 @@ org.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=512m kotlinVersion=1.9.10 kotlinCoroutinesVersion=1.8.0 -kommonsVersion=2.12.1 +kommonsVersion=2.12.2 ffiVersion=2.2.13 lwjglVersion=3.3.0 diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/server/ServerConnection.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/server/ServerConnection.kt index 77c76549..835f13ef 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/server/ServerConnection.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/server/ServerConnection.kt @@ -207,6 +207,7 @@ class ServerConnection(val server: StarboundServer, type: ConnectionType) : Conn // coordinates ship flight private suspend fun shipFlightEventLoop() { + shipWorld.sky.skyType = SkyType.ORBITAL shipWorld.sky.startFlying(true, true) var visited = 0 diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/server/world/ServerWorld.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/server/world/ServerWorld.kt index ed1ae8a2..be8aaf55 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/server/world/ServerWorld.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/server/world/ServerWorld.kt @@ -322,6 +322,10 @@ class ServerWorld private constructor( } private suspend fun findPlayerStart(hint: Vector2d? = null): Vector2d { + //if (true) { + // return Vector2d(10.0, template.surfaceLevel().toDouble()) + //} + val tickets = ArrayList() try { diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/util/random/AbstractPerlinNoise.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/util/random/AbstractPerlinNoise.kt index 15dd2d4c..8822dce9 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/util/random/AbstractPerlinNoise.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/util/random/AbstractPerlinNoise.kt @@ -31,21 +31,21 @@ abstract class AbstractPerlinNoise(val parameters: PerlinNoiseParameters) { var hasSeedSpecified = false private set - private var initializationTask: CompletableFuture? = null - private var isInitialized = false - private val initLock = Any() - var seed: Long = 0L private set - val scaleD = parameters.scale.toDouble() - protected data class Setup(val b0: Int, val b1: Int, val r0: Double, val r1: Double) - protected val p by lazy { IntArray(parameters.scale * 2 + 2) } - protected val g1 by lazy { DoubleArray(parameters.scale * 2 + 2) } - protected val g2 by lazy { Double2DArray.allocate(parameters.scale * 2 + 2, 2) } - protected val g3 by lazy { Double2DArray.allocate(parameters.scale * 2 + 2, 3) } + @JvmField protected val p = IntArray(parameters.scale * 2 + 2) + @JvmField protected val g1 = DoubleArray(parameters.scale * 2 + 2) + + // flat arrays for performance + @JvmField protected val g2_0 = DoubleArray(parameters.scale * 2 + 2) + @JvmField protected val g2_1 = DoubleArray(parameters.scale * 2 + 2) + + @JvmField protected val g3_0 = DoubleArray(parameters.scale * 2 + 2) + @JvmField protected val g3_1 = DoubleArray(parameters.scale * 2 + 2) + @JvmField protected val g3_2 = DoubleArray(parameters.scale * 2 + 2) init { if (parameters.seed != null && parameters.type != PerlinNoiseParameters.Type.UNITIALIZED) { @@ -53,50 +53,62 @@ abstract class AbstractPerlinNoise(val parameters: PerlinNoiseParameters) { } } - private fun doInit(seed: Long) { + fun init(seed: Long, now: Boolean = false) { + if (parameters.type == PerlinNoiseParameters.Type.UNITIALIZED) + return + + this.hasSeedSpecified = true + this.seed = seed + val p = p val g1 = g1 - val g2 = g2 - val g3 = g3 + val g2_0 = g2_0 + val g2_1 = g2_1 + val g3_0 = g3_0 + val g3_1 = g3_1 + val g3_2 = g3_2 p.fill(0) g1.fill(0.0) - g2.fill(0.0) - g3.fill(0.0) + g2_0.fill(0.0) + g2_1.fill(0.0) + g3_0.fill(0.0) + g3_1.fill(0.0) + g3_2.fill(0.0) val random = random(seed) for (i in 0 until parameters.scale) { p[i] = i - g1[i] = random.nextInt(-parameters.scale, parameters.scale) / scaleD + g1[i] = random.nextInt(-parameters.scale, parameters.scale) / parameters.scale.toDouble() - g2[i, 0] = random.nextInt(-parameters.scale, parameters.scale) / scaleD - g2[i, 1] = random.nextInt(-parameters.scale, parameters.scale) / scaleD + g2_0[i] = random.nextInt(-parameters.scale, parameters.scale) / parameters.scale.toDouble() + g2_1[i] = random.nextInt(-parameters.scale, parameters.scale) / parameters.scale.toDouble() - g3[i, 0] = random.nextInt(-parameters.scale, parameters.scale) / scaleD - g3[i, 1] = random.nextInt(-parameters.scale, parameters.scale) / scaleD - g3[i, 2] = random.nextInt(-parameters.scale, parameters.scale) / scaleD + g3_0[i] = random.nextInt(-parameters.scale, parameters.scale) / parameters.scale.toDouble() + g3_1[i] = random.nextInt(-parameters.scale, parameters.scale) / parameters.scale.toDouble() + g3_2[i] = random.nextInt(-parameters.scale, parameters.scale) / parameters.scale.toDouble() - val l2 = sqrt(g2[i, 0] * g2[i, 0] + g2[i, 1] * g2[i, 1]) - val l3 = sqrt(g3[i, 0] * g3[i, 0] + g3[i, 1] * g3[i, 1] + g3[i, 2] * g3[i, 2]) + val l2 = sqrt(g2_0[i] * g2_0[i] + g2_1[i] * g2_1[i]) + val l3 = sqrt(g3_0[i] * g3_0[i] + g3_1[i] * g3_1[i] + g3_2[i] * g3_2[i]) if (l2 == 0.0) { - g2[i, 0] = 1.0 - g2[i, 1] = 0.0 + g2_0[i] = 1.0 + g2_1[i] = 0.0 } else { - g2[i, 0] = g2[i, 0] / l2 - g2[i, 1] = g2[i, 1] / l2 + g2_0[i] = g2_0[i] / l2 + g2_1[i] = g2_1[i] / l2 } if (l3 == 0.0) { - g3[i, 0] = 1.0 - g3[i, 1] = 0.0 - g3[i, 2] = 0.0 + g3_0[i] = 1.0 + g3_1[i] = 0.0 + g3_2[i] = 0.0 } else { - g3[i, 0] = g3[i, 0] / l3 - g3[i, 1] = g3[i, 1] / l3 - g3[i, 2] = g3[i, 2] / l3 + g3_0[i] = g3_0[i] / l3 + g3_1[i] = g3_1[i] / l3 + g3_2[i] = g3_2[i] / l3 } } @@ -111,44 +123,22 @@ abstract class AbstractPerlinNoise(val parameters: PerlinNoiseParameters) { p[parameters.scale + i] = p[i] g1[parameters.scale + i] = g1[i] - g2[parameters.scale + i, 0] = g2[i, 0] - g2[parameters.scale + i, 1] = g2[i, 1] + g2_0[parameters.scale + i] = g2_0[i] + g2_1[parameters.scale + i] = g2_1[i] - g3[parameters.scale + i, 0] = g3[i, 0] - g3[parameters.scale + i, 1] = g3[i, 1] - g3[parameters.scale + i, 2] = g3[i, 2] + g3_0[parameters.scale + i] = g3_0[i] + g3_1[parameters.scale + i] = g3_1[i] + g3_2[parameters.scale + i] = g3_2[i] } } - protected fun checkInit() { - synchronized(initLock) { - check(hasSeedSpecified) { "Tried to use perlin noise without seed specified" } - - if (!isInitialized) { - doInit(seed) - isInitialized = true - } - } - } - - fun init(seed: Long, now: Boolean = false) { - if (parameters.type == PerlinNoiseParameters.Type.UNITIALIZED) - return - - this.hasSeedSpecified = true - this.isInitialized = false - this.seed = seed - - if (now) { - checkInit() - } - } - - protected fun curve(value: Double): Double { + @Suppress("NOTHING_TO_INLINE") + protected inline fun curve(value: Double): Double { return value * value * (3.0 - 2.0 * value) } - protected fun setup(value: Double): Setup { + @Suppress("NOTHING_TO_INLINE") + protected inline fun setup(value: Double): Setup { val iv: Int = floor(value).toInt() val fv: Double = value - iv @@ -159,15 +149,18 @@ abstract class AbstractPerlinNoise(val parameters: PerlinNoiseParameters) { return Setup(b0, b1, fv, r1) } - protected fun at2(x: Double, y: Double, rx: Double, ry: Double): Double { + @Suppress("NOTHING_TO_INLINE") + protected inline fun at2(x: Double, y: Double, rx: Double, ry: Double): Double { return rx * x + ry * y } - protected fun at3(x: Double, y: Double, z: Double, rx: Double, ry: Double, rz: Double): Double { + @Suppress("NOTHING_TO_INLINE") + protected inline fun at3(x: Double, y: Double, z: Double, rx: Double, ry: Double, rz: Double): Double { return rx * x + ry * y + rz * z } - protected fun noise1(x: Double): Double { + @Suppress("NOTHING_TO_INLINE") + protected inline fun noise1(x: Double): Double { val (bx0, bx1, rx0, rx1) = setup(x) val sx = curve(rx0) @@ -177,7 +170,8 @@ abstract class AbstractPerlinNoise(val parameters: PerlinNoiseParameters) { return linearInterpolation(sx, u, v) } - protected fun noise2(x: Double, y: Double): Double { + @Suppress("NOTHING_TO_INLINE") + protected inline fun noise2(x: Double, y: Double): Double { val (bx0, bx1, rx0, rx1) = setup(x) val (by0, by1, ry0, ry1) = setup(y) @@ -192,50 +186,51 @@ abstract class AbstractPerlinNoise(val parameters: PerlinNoiseParameters) { val sx = curve(rx0) val sy = curve(ry0) - var u = at2(g2[b00, 0], g2[b00, 1], rx0, ry0) - var v = at2(g2[b10, 0], g2[b10, 1], rx1, ry0) + var u = at2(g2_0[b00], g2_1[b00], rx0, ry0) + var v = at2(g2_0[b10], g2_1[b10], rx1, ry0) val a = linearInterpolation(sx, u, v) - u = at2(g2[b01, 0], g2[b01, 1], rx0, ry1) - v = at2(g2[b11, 0], g2[b11, 1], rx1, ry1) + u = at2(g2_0[b01], g2_1[b01], rx0, ry1) + v = at2(g2_0[b11], g2_1[b11], rx1, ry1) val b = linearInterpolation(sx, u, v) return linearInterpolation(sy, a, b) } - protected fun noise3(x: Double, y: Double, z: Double): Double { + @Suppress("NOTHING_TO_INLINE") + protected inline fun noise3(x: Double, y: Double, z: Double): Double { val (bx0, bx1, rx0, rx1) = setup(x) val (by0, by1, ry0, ry1) = setup(y) val (bz0, bz1, rz0, rz1) = setup(z) - val i = p[bx0]; - val j = p[bx1]; + val i = p[bx0] + val j = p[bx1] - val b00 = p[i + by0]; - val b10 = p[j + by0]; - val b01 = p[i + by1]; - val b11 = p[j + by1]; + val b00 = p[i + by0] + val b10 = p[j + by0] + val b01 = p[i + by1] + val b11 = p[j + by1] - val sx = curve(rx0); - val sy = curve(ry0); - val sz = curve(rz0); + val sx = curve(rx0) + val sy = curve(ry0) + val sz = curve(rz0) - var u = at3(g3[b00 + bz0, 0], g3[b00 + bz0, 1], g3[b00 + bz0, 2], rx0, ry0, rz0) - var v = at3(g3[b10 + bz0, 0], g3[b10 + bz0, 1], g3[b10 + bz0, 2], rx1, ry0, rz0) + var u = at3(g3_0[b00 + bz0], g3_1[b00 + bz0], g3_2[b00 + bz0], rx0, ry0, rz0) + var v = at3(g3_0[b10 + bz0], g3_1[b10 + bz0], g3_2[b10 + bz0], rx1, ry0, rz0) var a = linearInterpolation(sx, u, v) - u = at3(g3[b01 + bz0, 0], g3[b01 + bz0, 1], g3[b01 + bz0, 2], rx0, ry1, rz0) - v = at3(g3[b11 + bz0, 0], g3[b11 + bz0, 1], g3[b11 + bz0, 2], rx1, ry1, rz0) + u = at3(g3_0[b01 + bz0], g3_1[b01 + bz0], g3_2[b01 + bz0], rx0, ry1, rz0) + v = at3(g3_0[b11 + bz0], g3_1[b11 + bz0], g3_2[b11 + bz0], rx1, ry1, rz0) var b = linearInterpolation(sx, u, v) val c = linearInterpolation(sy, a, b) - u = at3(g3[b00 + bz1, 0], g3[b00 + bz1, 1], g3[b00 + bz1, 2], rx0, ry0, rz1) - v = at3(g3[b10 + bz1, 0], g3[b10 + bz1, 1], g3[b10 + bz1, 2], rx1, ry0, rz1) + u = at3(g3_0[b00 + bz1], g3_1[b00 + bz1], g3_2[b00 + bz1], rx0, ry0, rz1) + v = at3(g3_0[b10 + bz1], g3_1[b10 + bz1], g3_2[b10 + bz1], rx1, ry0, rz1) a = linearInterpolation(sx, u, v) - u = at3(g3[b01 + bz1, 0], g3[b01 + bz1, 1], g3[b01 + bz1, 2], rx0, ry1, rz1) - v = at3(g3[b11 + bz1, 0], g3[b11 + bz1, 1], g3[b11 + bz1, 2], rx1, ry1, rz1) + u = at3(g3_0[b01 + bz1], g3_1[b01 + bz1], g3_2[b01 + bz1], rx0, ry1, rz1) + v = at3(g3_0[b11 + bz1], g3_1[b11 + bz1], g3_2[b11 + bz1], rx1, ry1, rz1) b = linearInterpolation(sx, u, v) val d = linearInterpolation(sy, a, b) diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/util/random/BillowNoise.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/util/random/BillowNoise.kt index a683f470..28425226 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/util/random/BillowNoise.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/util/random/BillowNoise.kt @@ -9,7 +9,6 @@ class BillowNoise(parameters: PerlinNoiseParameters) : AbstractPerlinNoise(param } override fun get(x: Double): Double { - checkInit() var sum = 0.0 var p = x * parameters.frequency var scale = 1.0 @@ -24,7 +23,6 @@ class BillowNoise(parameters: PerlinNoiseParameters) : AbstractPerlinNoise(param } override fun get(x: Double, y: Double): Double { - checkInit() var sum = 0.0 var px = x * parameters.frequency var py = y * parameters.frequency @@ -41,7 +39,6 @@ class BillowNoise(parameters: PerlinNoiseParameters) : AbstractPerlinNoise(param } override fun get(x: Double, y: Double, z: Double): Double { - checkInit() var sum = 0.0 var px = x * parameters.frequency var py = y * parameters.frequency diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/util/random/PerlinNoise.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/util/random/PerlinNoise.kt index 2129b666..7a028e7f 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/util/random/PerlinNoise.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/util/random/PerlinNoise.kt @@ -8,7 +8,6 @@ class PerlinNoise(parameters: PerlinNoiseParameters) : AbstractPerlinNoise(param } override fun get(x: Double): Double { - checkInit() var sum = 0.0 var p = x * parameters.frequency var scale = 1.0 @@ -23,7 +22,6 @@ class PerlinNoise(parameters: PerlinNoiseParameters) : AbstractPerlinNoise(param } override fun get(x: Double, y: Double): Double { - checkInit() var sum = 0.0 var px = x * parameters.frequency var py = y * parameters.frequency @@ -40,7 +38,6 @@ class PerlinNoise(parameters: PerlinNoiseParameters) : AbstractPerlinNoise(param } override fun get(x: Double, y: Double, z: Double): Double { - checkInit() var sum = 0.0 var px = x * parameters.frequency var py = y * parameters.frequency diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/util/random/RidgedNoise.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/util/random/RidgedNoise.kt index eb8c5517..5bb3d33d 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/util/random/RidgedNoise.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/util/random/RidgedNoise.kt @@ -9,7 +9,6 @@ class RidgedNoise(parameters: PerlinNoiseParameters) : AbstractPerlinNoise(param } override fun get(x: Double): Double { - checkInit() var sum = 0.0 var p = x * parameters.frequency var scale = 1.0 @@ -32,7 +31,6 @@ class RidgedNoise(parameters: PerlinNoiseParameters) : AbstractPerlinNoise(param } override fun get(x: Double, y: Double): Double { - checkInit() var sum = 0.0 var px = x * parameters.frequency var py = y * parameters.frequency @@ -57,7 +55,6 @@ class RidgedNoise(parameters: PerlinNoiseParameters) : AbstractPerlinNoise(param } override fun get(x: Double, y: Double, z: Double): Double { - checkInit() var sum = 0.0 var px = x * parameters.frequency var py = y * parameters.frequency diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/world/Sky.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/world/Sky.kt index b10cf894..ce0964cc 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/world/Sky.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/world/Sky.kt @@ -31,10 +31,8 @@ import kotlin.math.sin class Sky() { val networkedGroup = MasterElement(NetworkedGroup()) - private val skyParametersNetState = networkedGroup.upstream.add(networkedJson(SkyParameters())) - + var skyParameters by networkedGroup.upstream.add(networkedJson(SkyParameters())) var skyType by networkedGroup.upstream.add(networkedEnumStupid(SkyType.ORBITAL)) - private set var time by networkedGroup.upstream.add(networkedDouble()) private set @@ -90,7 +88,7 @@ class Sky() { } constructor(parameters: SkyParameters) : this() { - skyParametersNetState.value = parameters.copy() + skyParameters = parameters.copy() skyType = parameters.skyType } @@ -196,7 +194,7 @@ class Sky() { flyingTimer += delta if (flyingType == FlyingType.DISEMBARKING) { - val finished = if (skyParametersNetState.value.skyType == SkyType.SPACE) + val finished = if (skyParameters.skyType == SkyType.SPACE) controlledMovement(Globals.sky.spaceDisembarkPath, Globals.sky.spaceDisembarkOrigin, flyingTimer) else controlledMovement(Globals.sky.disembarkPath, Globals.sky.disembarkOrigin, flyingTimer) @@ -205,7 +203,7 @@ class Sky() { flyingType = FlyingType.WARP } } else if (flyingType == FlyingType.ARRIVING) { - val finished = if (skyParametersNetState.value.skyType == SkyType.SPACE) + val finished = if (skyParameters.skyType == SkyType.SPACE) controlledMovement(Globals.sky.spaceArrivalPath, Globals.sky.spaceArrivalOrigin, flyingTimer) else controlledMovement(Globals.sky.arrivalPath, Globals.sky.arrivalOrigin, flyingTimer) @@ -235,13 +233,13 @@ class Sky() { } if (warpPhase == WarpPhase.SPEEDING_UP && flyingTimer >= speedupTime && !enterHyperspace && destination != null) { - skyParametersNetState.value = destination!! + skyParameters = destination!! destination = null warpPhase = WarpPhase.SLOWING_DOWN } else if (warpPhase == WarpPhase.SPEEDING_UP && flyingTimer >= speedupTime && enterHyperspace) { warpPhase = WarpPhase.MAINTAIN } else if (warpPhase == WarpPhase.MAINTAIN && flyingTimer >= Globals.sky.flyingTimer && destination != null) { - skyParametersNetState.value = destination!! + skyParameters = destination!! destination = null warpPhase = WarpPhase.SLOWING_DOWN } else if (warpPhase == WarpPhase.SLOWING_DOWN && flyingTimer >= slowdownTime) { diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/world/terrain/DisplacementTerrainSelector.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/world/terrain/DisplacementTerrainSelector.kt index d56a7f90..1fc11b9b 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/world/terrain/DisplacementTerrainSelector.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/world/terrain/DisplacementTerrainSelector.kt @@ -12,7 +12,7 @@ class DisplacementTerrainSelector(data: Data, parameters: TerrainSelectorParamet @JsonFactory data class Data( val xType: PerlinNoiseParameters.Type, - val xScale: Int = 512, + val xScale: Int = PerlinNoiseParameters.DEFAULT_SCALE, val xOctaves: Int, val xFreq: Double, val xAmp: Double, @@ -21,7 +21,7 @@ class DisplacementTerrainSelector(data: Data, parameters: TerrainSelectorParamet val xBeta: Double = 2.0, val yType: PerlinNoiseParameters.Type, - val yScale: Int = 512, + val yScale: Int = PerlinNoiseParameters.DEFAULT_SCALE, val yOctaves: Int, val yFreq: Double, val yAmp: Double,