diff --git a/src/main/java/de/bixilon/minosoft/data/world/border/WorldBorder.kt b/src/main/java/de/bixilon/minosoft/data/world/border/WorldBorder.kt
index 3805de8c8..dc94f97b5 100644
--- a/src/main/java/de/bixilon/minosoft/data/world/border/WorldBorder.kt
+++ b/src/main/java/de/bixilon/minosoft/data/world/border/WorldBorder.kt
@@ -16,10 +16,10 @@ package de.bixilon.minosoft.data.world.border
import de.bixilon.kotlinglm.vec2.Vec2d
import de.bixilon.kotlinglm.vec3.Vec3d
import de.bixilon.kotlinglm.vec3.Vec3i
-import de.bixilon.kutil.concurrent.lock.simple.SimpleLock
-import de.bixilon.kutil.math.interpolation.DoubleInterpolation.interpolateLinear
-import de.bixilon.kutil.time.TimeUtil.millis
import de.bixilon.minosoft.data.world.World
+import de.bixilon.minosoft.data.world.border.area.BorderArea
+import de.bixilon.minosoft.data.world.border.area.DynamicBorderArea
+import de.bixilon.minosoft.data.world.border.area.StaticBorderArea
import de.bixilon.minosoft.data.world.positions.BlockPosition
import de.bixilon.minosoft.gui.rendering.util.vec.vec2.Vec2dUtil.EMPTY
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
@@ -27,24 +27,11 @@ import kotlin.math.abs
class WorldBorder {
var center = Vec2d.EMPTY
- var radius = DEFAULT_RADIUS
var warningTime = 0
var warningBlocks = 0
var portalBound = 0
- var state = WorldBorderState.STATIC
- private set
-
- var interpolationStart = -1L
- private set
- var interpolationEnd = -1L
- private set
- var oldRadius = DEFAULT_RADIUS
- private set
- var newRadius = DEFAULT_RADIUS
- private set
-
- val lock = SimpleLock()
+ var area: BorderArea = StaticBorderArea(MAX_RADIUS)
fun isOutside(blockPosition: Vec3i): Boolean {
return isOutside(blockPosition.x.toDouble(), blockPosition.z.toDouble()) && isOutside(blockPosition.x + 1.0, blockPosition.z + 1.0)
@@ -55,10 +42,9 @@ class WorldBorder {
}
fun isOutside(x: Double, z: Double): Boolean {
- lock.acquire()
- val radius = radius
+ val center = center
+ val radius = area.radius
val inside = x in maxOf(-MAX_RADIUS, center.x - radius)..minOf(MAX_RADIUS, center.x + radius) && z in maxOf(-MAX_RADIUS, center.y - radius)..minOf(MAX_RADIUS, center.y + radius)
- lock.release()
return !inside
}
@@ -72,78 +58,32 @@ class WorldBorder {
}
fun getDistanceTo(x: Double, z: Double): Double {
- lock.acquire()
- val radius = radius
+ val center = center
+ val radius = area.radius
- val closestDistance = minOf(
+ return minOf(
minOf(MAX_RADIUS, radius - abs(center.x)) - abs(x),
minOf(MAX_RADIUS, radius - abs(center.y)) - abs(z),
)
- lock.release()
- return closestDistance
- }
-
- fun stopInterpolating() {
- lock.lock()
- interpolationStart = -1L
- lock.unlock()
}
fun interpolate(oldRadius: Double, newRadius: Double, millis: Long) {
- if (millis <= 0L) {
- stopInterpolating()
- radius = newRadius
+ if (millis <= 0L || oldRadius == newRadius) {
+ area = StaticBorderArea(newRadius)
+ return
}
- lock.lock()
- val time = millis()
- interpolationStart = time
- interpolationEnd = time + millis
- this.oldRadius = oldRadius
- this.newRadius = newRadius
- lock.unlock()
+ area = DynamicBorderArea(this, oldRadius, newRadius, millis)
}
fun tick() {
- lock.lock()
- if (interpolationStart < 0L) {
- lock.unlock()
- return
- }
- val time = millis()
- if (interpolationEnd <= time) {
- this.radius = newRadius // also get the last interpolation step
- state = WorldBorderState.STATIC
- interpolationStart = -1L
- lock.unlock()
- return
- }
- val oldRadius = radius
-
- val remaining = interpolationEnd - time
- val totalTime = (interpolationEnd - interpolationStart)
- val radius = interpolateLinear(remaining.toDouble() / totalTime.toDouble(), this.oldRadius, this.newRadius)
- this.radius = radius
-
- state = if (oldRadius > newRadius) {
- WorldBorderState.SHRINKING
- } else if (oldRadius < newRadius) {
- WorldBorderState.GROWING
- } else {
- interpolationStart = -1L
- WorldBorderState.STATIC
- }
- lock.unlock()
+ area.tick()
}
fun reset() {
- lock.lock()
- radius = DEFAULT_RADIUS
- interpolationStart = -1L
- lock.unlock()
+ area = StaticBorderArea(MAX_RADIUS)
}
companion object {
const val MAX_RADIUS = (World.MAX_SIZE - ProtocolDefinition.SECTION_WIDTH_X).toDouble()
- const val DEFAULT_RADIUS = MAX_RADIUS
}
}
diff --git a/src/main/java/de/bixilon/minosoft/data/world/border/area/BorderArea.kt b/src/main/java/de/bixilon/minosoft/data/world/border/area/BorderArea.kt
new file mode 100644
index 000000000..c7e692ae4
--- /dev/null
+++ b/src/main/java/de/bixilon/minosoft/data/world/border/area/BorderArea.kt
@@ -0,0 +1,27 @@
+/*
+ * Minosoft
+ * Copyright (C) 2020-2023 Moritz Zwerger
+ *
+ * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with this program. If not, see .
+ *
+ * This software is not affiliated with Mojang AB, the original developer of Minecraft.
+ */
+
+package de.bixilon.minosoft.data.world.border.area
+
+import de.bixilon.kutil.time.TimeUtil.millis
+import de.bixilon.minosoft.data.Tickable
+import de.bixilon.minosoft.data.world.border.WorldBorderState
+
+interface BorderArea : Tickable {
+ val radius: Double
+
+ val state: WorldBorderState
+
+
+ fun radius(time: Long = millis()): Double = radius
+}
diff --git a/src/main/java/de/bixilon/minosoft/data/world/border/area/DynamicBorderArea.kt b/src/main/java/de/bixilon/minosoft/data/world/border/area/DynamicBorderArea.kt
new file mode 100644
index 000000000..c34c07000
--- /dev/null
+++ b/src/main/java/de/bixilon/minosoft/data/world/border/area/DynamicBorderArea.kt
@@ -0,0 +1,57 @@
+/*
+ * Minosoft
+ * Copyright (C) 2020-2023 Moritz Zwerger
+ *
+ * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with this program. If not, see .
+ *
+ * This software is not affiliated with Mojang AB, the original developer of Minecraft.
+ */
+
+package de.bixilon.minosoft.data.world.border.area
+
+import de.bixilon.kutil.math.interpolation.DoubleInterpolation.interpolateLinear
+import de.bixilon.kutil.time.TimeUtil.millis
+import de.bixilon.minosoft.data.world.border.WorldBorder
+import de.bixilon.minosoft.data.world.border.WorldBorderState
+
+class DynamicBorderArea(
+ val border: WorldBorder,
+ val oldRadius: Double,
+ val newRadius: Double,
+ val millis: Long,
+) : BorderArea {
+ val start: Long = millis()
+ val end = start + millis
+
+ override var state: WorldBorderState = state()
+ override var radius: Double = oldRadius
+
+ override fun radius(time: Long): Double {
+ return interpolateLinear(progress(time), oldRadius, newRadius)
+ }
+
+ private fun progress(time: Long): Double {
+ return (time - start).toDouble() / (end - start)
+ }
+
+ override fun tick() {
+ val time = millis()
+ if (end <= time) {
+ border.area = StaticBorderArea(newRadius)
+ return
+ }
+
+ this.radius = interpolateLinear(progress(time), this.oldRadius, this.newRadius)
+ this.state = state()
+ }
+
+ private fun state() = when {
+ oldRadius > newRadius -> WorldBorderState.SHRINKING
+ oldRadius < newRadius -> WorldBorderState.GROWING
+ else -> WorldBorderState.STATIC // impossible?
+ }
+}
diff --git a/src/main/java/de/bixilon/minosoft/data/world/border/area/StaticBorderArea.kt b/src/main/java/de/bixilon/minosoft/data/world/border/area/StaticBorderArea.kt
new file mode 100644
index 000000000..8f904cd90
--- /dev/null
+++ b/src/main/java/de/bixilon/minosoft/data/world/border/area/StaticBorderArea.kt
@@ -0,0 +1,24 @@
+/*
+ * Minosoft
+ * Copyright (C) 2020-2023 Moritz Zwerger
+ *
+ * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with this program. If not, see .
+ *
+ * This software is not affiliated with Mojang AB, the original developer of Minecraft.
+ */
+
+package de.bixilon.minosoft.data.world.border.area
+
+import de.bixilon.minosoft.data.world.border.WorldBorderState
+
+class StaticBorderArea(
+ override val radius: Double,
+) : BorderArea {
+ override val state: WorldBorderState get() = WorldBorderState.STATIC
+
+ override fun tick() = Unit
+}
diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/world/border/WorldBorderRenderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/world/border/WorldBorderRenderer.kt
index c6e77566d..76323bf93 100644
--- a/src/main/java/de/bixilon/minosoft/gui/rendering/world/border/WorldBorderRenderer.kt
+++ b/src/main/java/de/bixilon/minosoft/gui/rendering/world/border/WorldBorderRenderer.kt
@@ -15,7 +15,6 @@ package de.bixilon.minosoft.gui.rendering.world.border
import de.bixilon.kotlinglm.func.common.clamp
import de.bixilon.kutil.latch.CountUpAndDownLatch
-import de.bixilon.kutil.math.interpolation.DoubleInterpolation.interpolateLinear
import de.bixilon.kutil.observer.DataObserver.Companion.observe
import de.bixilon.kutil.time.TimeUtil.millis
import de.bixilon.minosoft.data.registries.identified.Namespaces.minosoft
@@ -65,7 +64,7 @@ class WorldBorderRenderer(
private fun calculateColor(): RGBColor {
val distance = border.getDistanceTo(context.connection.player.physics.position).toFloat() - 1.0f // 1 block padding
val strength = 1.0f - distance.clamp(0.0f, MAX_DISTANCE) / MAX_DISTANCE // slowly fade in
- val color = when (border.state) {
+ val color = when (border.area.state) {
WorldBorderState.GROWING -> GROWING_COLOR
WorldBorderState.SHRINKING -> SHRINKING_COLOR
WorldBorderState.STATIC -> STATIC_COLOR
@@ -86,21 +85,12 @@ class WorldBorderRenderer(
shader.tintColor = calculateColor()
}
- private fun getRadius(): Double {
- val start = border.interpolationStart
- if (start < 0L) return border.radius
-
- val progress = (millis() - start).toDouble() / (border.interpolationEnd - start)
-
- return interpolateLinear(progress, border.oldRadius, border.newRadius)
- }
-
override fun prepareDrawAsync() {
if (skipAll) return
val center = border.center
- val radius = getRadius()
+ val radius = border.area.radius()
val previous = this.borderMesh
if (previous != null && !reload && center == previous.center && radius == previous.radius) return
diff --git a/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/border/SizeWorldBorderS2CP.kt b/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/border/SizeWorldBorderS2CP.kt
index 67dd16f23..c42872c75 100644
--- a/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/border/SizeWorldBorderS2CP.kt
+++ b/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/border/SizeWorldBorderS2CP.kt
@@ -13,6 +13,7 @@
package de.bixilon.minosoft.protocol.packets.s2c.play.border
+import de.bixilon.minosoft.data.world.border.area.StaticBorderArea
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
import de.bixilon.minosoft.protocol.packets.factory.LoadPacket
import de.bixilon.minosoft.protocol.protocol.buffers.play.PlayInByteBuffer
@@ -25,11 +26,10 @@ class SizeWorldBorderS2CP(buffer: PlayInByteBuffer) : WorldBorderS2CP {
val radius = buffer.readDouble() / 2.0
override fun handle(connection: PlayConnection) {
- connection.world.border.stopInterpolating()
- connection.world.border.radius = radius
+ connection.world.border.area = StaticBorderArea(radius)
}
override fun log(reducedLog: Boolean) {
- Log.log(LogMessageType.NETWORK_PACKETS_IN, level = LogLevels.VERBOSE) { "Size set world border (diameter=$radius)" }
+ Log.log(LogMessageType.NETWORK_PACKETS_IN, level = LogLevels.VERBOSE) { "Size set world border (radius=$radius)" }
}
}