mirror of
https://gitlab.bixilon.de/bixilon/minosoft.git
synced 2025-09-15 18:34:56 -04:00
abstract world border area
Sooooo much cleaner now
This commit is contained in:
parent
802dc48a07
commit
47f6dd7e05
@ -16,10 +16,10 @@ package de.bixilon.minosoft.data.world.border
|
|||||||
import de.bixilon.kotlinglm.vec2.Vec2d
|
import de.bixilon.kotlinglm.vec2.Vec2d
|
||||||
import de.bixilon.kotlinglm.vec3.Vec3d
|
import de.bixilon.kotlinglm.vec3.Vec3d
|
||||||
import de.bixilon.kotlinglm.vec3.Vec3i
|
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.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.data.world.positions.BlockPosition
|
||||||
import de.bixilon.minosoft.gui.rendering.util.vec.vec2.Vec2dUtil.EMPTY
|
import de.bixilon.minosoft.gui.rendering.util.vec.vec2.Vec2dUtil.EMPTY
|
||||||
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
|
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
|
||||||
@ -27,24 +27,11 @@ import kotlin.math.abs
|
|||||||
|
|
||||||
class WorldBorder {
|
class WorldBorder {
|
||||||
var center = Vec2d.EMPTY
|
var center = Vec2d.EMPTY
|
||||||
var radius = DEFAULT_RADIUS
|
|
||||||
var warningTime = 0
|
var warningTime = 0
|
||||||
var warningBlocks = 0
|
var warningBlocks = 0
|
||||||
var portalBound = 0
|
var portalBound = 0
|
||||||
|
|
||||||
var state = WorldBorderState.STATIC
|
var area: BorderArea = StaticBorderArea(MAX_RADIUS)
|
||||||
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()
|
|
||||||
|
|
||||||
fun isOutside(blockPosition: Vec3i): Boolean {
|
fun isOutside(blockPosition: Vec3i): Boolean {
|
||||||
return isOutside(blockPosition.x.toDouble(), blockPosition.z.toDouble()) && isOutside(blockPosition.x + 1.0, blockPosition.z + 1.0)
|
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 {
|
fun isOutside(x: Double, z: Double): Boolean {
|
||||||
lock.acquire()
|
val center = center
|
||||||
val radius = radius
|
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)
|
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
|
return !inside
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,78 +58,32 @@ class WorldBorder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun getDistanceTo(x: Double, z: Double): Double {
|
fun getDistanceTo(x: Double, z: Double): Double {
|
||||||
lock.acquire()
|
val center = center
|
||||||
val radius = radius
|
val radius = area.radius
|
||||||
|
|
||||||
val closestDistance = minOf(
|
return minOf(
|
||||||
minOf(MAX_RADIUS, radius - abs(center.x)) - abs(x),
|
minOf(MAX_RADIUS, radius - abs(center.x)) - abs(x),
|
||||||
minOf(MAX_RADIUS, radius - abs(center.y)) - abs(z),
|
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) {
|
fun interpolate(oldRadius: Double, newRadius: Double, millis: Long) {
|
||||||
if (millis <= 0L) {
|
if (millis <= 0L || oldRadius == newRadius) {
|
||||||
stopInterpolating()
|
area = StaticBorderArea(newRadius)
|
||||||
radius = newRadius
|
return
|
||||||
}
|
}
|
||||||
lock.lock()
|
area = DynamicBorderArea(this, oldRadius, newRadius, millis)
|
||||||
val time = millis()
|
|
||||||
interpolationStart = time
|
|
||||||
interpolationEnd = time + millis
|
|
||||||
this.oldRadius = oldRadius
|
|
||||||
this.newRadius = newRadius
|
|
||||||
lock.unlock()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun tick() {
|
fun tick() {
|
||||||
lock.lock()
|
area.tick()
|
||||||
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()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun reset() {
|
fun reset() {
|
||||||
lock.lock()
|
area = StaticBorderArea(MAX_RADIUS)
|
||||||
radius = DEFAULT_RADIUS
|
|
||||||
interpolationStart = -1L
|
|
||||||
lock.unlock()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val MAX_RADIUS = (World.MAX_SIZE - ProtocolDefinition.SECTION_WIDTH_X).toDouble()
|
const val MAX_RADIUS = (World.MAX_SIZE - ProtocolDefinition.SECTION_WIDTH_X).toDouble()
|
||||||
const val DEFAULT_RADIUS = MAX_RADIUS
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
}
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* 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?
|
||||||
|
}
|
||||||
|
}
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
}
|
@ -15,7 +15,6 @@ package de.bixilon.minosoft.gui.rendering.world.border
|
|||||||
|
|
||||||
import de.bixilon.kotlinglm.func.common.clamp
|
import de.bixilon.kotlinglm.func.common.clamp
|
||||||
import de.bixilon.kutil.latch.CountUpAndDownLatch
|
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.observer.DataObserver.Companion.observe
|
||||||
import de.bixilon.kutil.time.TimeUtil.millis
|
import de.bixilon.kutil.time.TimeUtil.millis
|
||||||
import de.bixilon.minosoft.data.registries.identified.Namespaces.minosoft
|
import de.bixilon.minosoft.data.registries.identified.Namespaces.minosoft
|
||||||
@ -65,7 +64,7 @@ class WorldBorderRenderer(
|
|||||||
private fun calculateColor(): RGBColor {
|
private fun calculateColor(): RGBColor {
|
||||||
val distance = border.getDistanceTo(context.connection.player.physics.position).toFloat() - 1.0f // 1 block padding
|
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 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.GROWING -> GROWING_COLOR
|
||||||
WorldBorderState.SHRINKING -> SHRINKING_COLOR
|
WorldBorderState.SHRINKING -> SHRINKING_COLOR
|
||||||
WorldBorderState.STATIC -> STATIC_COLOR
|
WorldBorderState.STATIC -> STATIC_COLOR
|
||||||
@ -86,21 +85,12 @@ class WorldBorderRenderer(
|
|||||||
shader.tintColor = calculateColor()
|
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() {
|
override fun prepareDrawAsync() {
|
||||||
if (skipAll) return
|
if (skipAll) return
|
||||||
|
|
||||||
val center = border.center
|
val center = border.center
|
||||||
val radius = getRadius()
|
val radius = border.area.radius()
|
||||||
|
|
||||||
val previous = this.borderMesh
|
val previous = this.borderMesh
|
||||||
if (previous != null && !reload && center == previous.center && radius == previous.radius) return
|
if (previous != null && !reload && center == previous.center && radius == previous.radius) return
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
|
|
||||||
package de.bixilon.minosoft.protocol.packets.s2c.play.border
|
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.network.connection.play.PlayConnection
|
||||||
import de.bixilon.minosoft.protocol.packets.factory.LoadPacket
|
import de.bixilon.minosoft.protocol.packets.factory.LoadPacket
|
||||||
import de.bixilon.minosoft.protocol.protocol.buffers.play.PlayInByteBuffer
|
import de.bixilon.minosoft.protocol.protocol.buffers.play.PlayInByteBuffer
|
||||||
@ -25,11 +26,10 @@ class SizeWorldBorderS2CP(buffer: PlayInByteBuffer) : WorldBorderS2CP {
|
|||||||
val radius = buffer.readDouble() / 2.0
|
val radius = buffer.readDouble() / 2.0
|
||||||
|
|
||||||
override fun handle(connection: PlayConnection) {
|
override fun handle(connection: PlayConnection) {
|
||||||
connection.world.border.stopInterpolating()
|
connection.world.border.area = StaticBorderArea(radius)
|
||||||
connection.world.border.radius = radius
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun log(reducedLog: Boolean) {
|
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)" }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user