Update player entity positions server-side
This commit is contained in:
parent
818939267a
commit
fb047b22a3
19 changed files with 115 additions and 17 deletions
|
@ -84,6 +84,16 @@ class EntitiesGenerator(
|
||||||
.initializer("Type")
|
.initializer("Type")
|
||||||
.build()
|
.build()
|
||||||
)
|
)
|
||||||
|
.addProperty(
|
||||||
|
PropertySpec.builder(
|
||||||
|
"dataStorage",
|
||||||
|
ClassName("$BASE_PACKAGE.data", "DataStorage").parameterizedBy(ClassName(ENTITY_PACKAGE, name)),
|
||||||
|
KModifier.OVERRIDE
|
||||||
|
)
|
||||||
|
.addAnnotation(AnnotationSpec.builder(Suppress::class).addMember("\"LeakingThis\"").build())
|
||||||
|
.initializer("%T(this)", ClassName("$BASE_PACKAGE.data", "DataStorage"))
|
||||||
|
.build()
|
||||||
|
)
|
||||||
.addType(
|
.addType(
|
||||||
TypeSpec.companionObjectBuilder("Type")
|
TypeSpec.companionObjectBuilder("Type")
|
||||||
.superclass(ClassName(ENTITY_PACKAGE, name + "Type"))
|
.superclass(ClassName(ENTITY_PACKAGE, name + "Type"))
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package space.uranos.entity
|
package space.uranos
|
||||||
|
|
||||||
enum class PaintingMotive(val width: Int, val height: Int) {
|
enum class PaintingMotive(val width: Int, val height: Int) {
|
||||||
// Order is important
|
// Order is important
|
|
@ -38,15 +38,12 @@ class DataStorage<ContextT : Any>(val context: ContextT) {
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
val entry = map[key] as Entry<V>?
|
val entry = map[key] as Entry<V>?
|
||||||
|
|
||||||
println(key)
|
|
||||||
println(value)
|
|
||||||
|
|
||||||
if (entry == null) map[key] = Entry(key, value)
|
if (entry == null) map[key] = Entry(key, value)
|
||||||
else entry.value = value
|
else entry.value = value
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
fun <V> get(key: DataStorageKey<ContextT, V>) = map[key] as V
|
fun <V> get(key: DataStorageKey<ContextT, V>) = (map[key] as Entry<V>?)!!.value
|
||||||
|
|
||||||
suspend fun tick() {
|
suspend fun tick() {
|
||||||
val actions = map.values.mapNotNull { it.tick() }
|
val actions = map.values.mapNotNull { it.tick() }
|
||||||
|
@ -58,4 +55,7 @@ class DataStorage<ContextT : Any>(val context: ContextT) {
|
||||||
key.tick(context, values)
|
key.tick(context, values)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST", "NOTHING_TO_INLINE")
|
||||||
|
inline fun <T : Any> cast() = this as DataStorage<T>
|
||||||
}
|
}
|
|
@ -8,6 +8,7 @@ package space.uranos.entity
|
||||||
import kotlinx.coroutines.sync.Mutex
|
import kotlinx.coroutines.sync.Mutex
|
||||||
import kotlinx.coroutines.sync.withLock
|
import kotlinx.coroutines.sync.withLock
|
||||||
import space.uranos.Uranos
|
import space.uranos.Uranos
|
||||||
|
import space.uranos.data.DataStorage
|
||||||
import space.uranos.world.World
|
import space.uranos.world.World
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
|
@ -23,6 +24,7 @@ abstract class Entity internal constructor() {
|
||||||
open val uuid: UUID = UUID.randomUUID()
|
open val uuid: UUID = UUID.randomUUID()
|
||||||
|
|
||||||
abstract val type: EntityType
|
abstract val type: EntityType
|
||||||
|
abstract val dataStorage: DataStorage<out Entity>
|
||||||
|
|
||||||
private val worldMutex = Mutex()
|
private val worldMutex = Mutex()
|
||||||
var world: World? = null; protected set
|
var world: World? = null; protected set
|
||||||
|
|
|
@ -6,9 +6,13 @@
|
||||||
package space.uranos.entity
|
package space.uranos.entity
|
||||||
|
|
||||||
import space.uranos.Position
|
import space.uranos.Position
|
||||||
|
import space.uranos.data.DataStorage
|
||||||
|
|
||||||
open class ItemEntity(override var position: Position) : ObjectEntity() {
|
open class ItemEntity(override var position: Position) : ObjectEntity() {
|
||||||
final override val type: EntityType = Type
|
final override val type: EntityType = Type
|
||||||
|
|
||||||
companion object Type : ItemEntityType()
|
@Suppress("LeakingThis")
|
||||||
|
public override val dataStorage: DataStorage<ItemEntity> = DataStorage(this)
|
||||||
|
|
||||||
|
companion object Type : ItemEntityType()
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,13 +3,29 @@
|
||||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@file:Suppress("LeakingThis")
|
||||||
|
|
||||||
package space.uranos.entity
|
package space.uranos.entity
|
||||||
|
|
||||||
import space.uranos.Position
|
import space.uranos.Position
|
||||||
import space.uranos.Vector
|
import space.uranos.Vector
|
||||||
|
import space.uranos.data.DataStorage
|
||||||
|
import space.uranos.data.createDataStorageKey
|
||||||
|
|
||||||
abstract class LivingEntity : Entity(), Mobile {
|
abstract class LivingEntity : Entity(), Mobile {
|
||||||
abstract var headPitch: Float
|
abstract var headPitch: Float
|
||||||
abstract override var position: Position
|
|
||||||
abstract override var velocity: Vector
|
abstract override var velocity: Vector
|
||||||
|
abstract override val dataStorage: DataStorage<out LivingEntity>
|
||||||
|
|
||||||
|
override var position: Position
|
||||||
|
get() = dataStorage.cast<LivingEntity>().get(DataStorageKeys.position)
|
||||||
|
set(value) = dataStorage.cast<LivingEntity>().set(DataStorageKeys.position, value)
|
||||||
|
|
||||||
|
object DataStorageKeys {
|
||||||
|
val position = createDataStorageKey("position") { entity: LivingEntity, value: Position ->
|
||||||
|
// TODO: Send the position to players
|
||||||
|
println(value)
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
package space.uranos.entity
|
package space.uranos.entity
|
||||||
|
|
||||||
import space.uranos.CardinalDirection
|
import space.uranos.CardinalDirection
|
||||||
|
import space.uranos.PaintingMotive
|
||||||
|
import space.uranos.data.DataStorage
|
||||||
import space.uranos.world.VoxelLocation
|
import space.uranos.world.VoxelLocation
|
||||||
|
|
||||||
class PaintingEntity(
|
class PaintingEntity(
|
||||||
|
@ -13,9 +15,10 @@ class PaintingEntity(
|
||||||
val direction: CardinalDirection,
|
val direction: CardinalDirection,
|
||||||
val motive: PaintingMotive
|
val motive: PaintingMotive
|
||||||
) : Entity() {
|
) : Entity() {
|
||||||
override val type: EntityType = Type
|
override val type: EntityType = Type
|
||||||
|
|
||||||
|
@Suppress("LeakingThis")
|
||||||
|
override val dataStorage: DataStorage<PaintingEntity> = DataStorage(this)
|
||||||
|
|
||||||
|
companion object Type : PaintingEntityType()
|
||||||
companion object Type : PaintingEntityType()
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,11 +7,12 @@ package space.uranos.entity
|
||||||
|
|
||||||
import space.uranos.Position
|
import space.uranos.Position
|
||||||
import space.uranos.Vector
|
import space.uranos.Vector
|
||||||
|
import space.uranos.data.DataStorage
|
||||||
import space.uranos.player.Player
|
import space.uranos.player.Player
|
||||||
import space.uranos.world.World
|
import space.uranos.world.World
|
||||||
|
|
||||||
open class PlayerEntity(
|
open class PlayerEntity(
|
||||||
override var position: Position,
|
position: Position,
|
||||||
/**
|
/**
|
||||||
* The player to which this entity belongs.
|
* The player to which this entity belongs.
|
||||||
*
|
*
|
||||||
|
@ -23,6 +24,13 @@ open class PlayerEntity(
|
||||||
final override val type: EntityType = Type
|
final override val type: EntityType = Type
|
||||||
override var velocity: Vector = Vector.ZERO
|
override var velocity: Vector = Vector.ZERO
|
||||||
|
|
||||||
|
@Suppress("LeakingThis")
|
||||||
|
override val dataStorage: DataStorage<PlayerEntity> = DataStorage(this)
|
||||||
|
|
||||||
|
init {
|
||||||
|
this.position = position
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Because [world] is never `null` for player entities, you can use this property instead of writing `world!!`.
|
* Because [world] is never `null` for player entities, you can use this property instead of writing `world!!`.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -11,7 +11,7 @@ import space.uranos.net.packet.IncomingPacketCodec
|
||||||
object PlayerOrientationPacketCodec :
|
object PlayerOrientationPacketCodec :
|
||||||
IncomingPacketCodec<PlayerOrientationPacket>(0x14, PlayerOrientationPacket::class) {
|
IncomingPacketCodec<PlayerOrientationPacket>(0x14, PlayerOrientationPacket::class) {
|
||||||
override fun decode(msg: ByteBuf): PlayerOrientationPacket = PlayerOrientationPacket(
|
override fun decode(msg: ByteBuf): PlayerOrientationPacket = PlayerOrientationPacket(
|
||||||
360 - msg.readFloat() % 360,
|
(360 - msg.readFloat()) % 360,
|
||||||
msg.readFloat(),
|
msg.readFloat(),
|
||||||
msg.readBoolean()
|
msg.readBoolean()
|
||||||
)
|
)
|
||||||
|
|
|
@ -7,8 +7,8 @@ package space.uranos.net.packet.play
|
||||||
|
|
||||||
import io.netty.buffer.ByteBuf
|
import io.netty.buffer.ByteBuf
|
||||||
import space.uranos.CardinalDirection
|
import space.uranos.CardinalDirection
|
||||||
|
import space.uranos.PaintingMotive
|
||||||
import space.uranos.entity.PaintingEntity
|
import space.uranos.entity.PaintingEntity
|
||||||
import space.uranos.entity.PaintingMotive
|
|
||||||
import space.uranos.net.MinecraftProtocolDataTypes.writeUUID
|
import space.uranos.net.MinecraftProtocolDataTypes.writeUUID
|
||||||
import space.uranos.net.MinecraftProtocolDataTypes.writeVarInt
|
import space.uranos.net.MinecraftProtocolDataTypes.writeVarInt
|
||||||
import space.uranos.net.MinecraftProtocolDataTypes.writeVoxelLocation
|
import space.uranos.net.MinecraftProtocolDataTypes.writeVoxelLocation
|
||||||
|
|
|
@ -6,8 +6,7 @@
|
||||||
package space.uranos.net.packet.play
|
package space.uranos.net.packet.play
|
||||||
|
|
||||||
import space.uranos.CardinalDirection
|
import space.uranos.CardinalDirection
|
||||||
import space.uranos.Location
|
import space.uranos.PaintingMotive
|
||||||
import space.uranos.entity.PaintingMotive
|
|
||||||
import space.uranos.net.packet.OutgoingPacket
|
import space.uranos.net.packet.OutgoingPacket
|
||||||
import space.uranos.world.VoxelLocation
|
import space.uranos.world.VoxelLocation
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
|
@ -125,6 +125,7 @@ class UranosServer internal constructor() : Server() {
|
||||||
private fun startDataStorageTicking() {
|
private fun startDataStorageTicking() {
|
||||||
scheduler.executeRepeating(1, 0) {
|
scheduler.executeRepeating(1, 0) {
|
||||||
players.forEach { it.dataStorage.tick() }
|
players.forEach { it.dataStorage.tick() }
|
||||||
|
entities.forEach { it.dataStorage.tick() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2020-2021 Moritz Ruth and Uranos contributors
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file
|
||||||
|
*/
|
||||||
|
|
||||||
|
package space.uranos.net.packet.play
|
||||||
|
|
||||||
|
import space.uranos.net.PacketReceivedEventHandler
|
||||||
|
import space.uranos.net.UranosSession
|
||||||
|
|
||||||
|
object IncomingPlayerPositionPacketHandler : PacketReceivedEventHandler<IncomingPlayerPositionPacket>() {
|
||||||
|
override suspend fun handle(session: UranosSession, packet: IncomingPlayerPositionPacket) {
|
||||||
|
session.player!!.entity.position = packet.position
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,7 +11,10 @@ import space.uranos.net.ProtocolPacketReceivedEventHandler
|
||||||
object PlayProtocolHandler : ProtocolPacketReceivedEventHandler(
|
object PlayProtocolHandler : ProtocolPacketReceivedEventHandler(
|
||||||
mapOf(
|
mapOf(
|
||||||
ClientSettingsPacket::class to ClientSettingsPacketHandler,
|
ClientSettingsPacket::class to ClientSettingsPacketHandler,
|
||||||
|
IncomingKeepAlivePacket::class to IncomingKeepAlivePacketHandler,
|
||||||
|
IncomingPlayerPositionPacket::class to IncomingPlayerPositionPacketHandler,
|
||||||
IncomingPluginMessagePacket::class to IncomingPluginMessagePacketHandler,
|
IncomingPluginMessagePacket::class to IncomingPluginMessagePacketHandler,
|
||||||
IncomingKeepAlivePacket::class to IncomingKeepAlivePacketHandler
|
PlayerOrientationPacket::class to PlayerOrientationPacketHandler,
|
||||||
|
PlayerLocationPacket::class to PlayerLocationPacketHandler
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2020-2021 Moritz Ruth and Uranos contributors
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file
|
||||||
|
*/
|
||||||
|
|
||||||
|
package space.uranos.net.packet.play
|
||||||
|
|
||||||
|
import space.uranos.net.PacketReceivedEventHandler
|
||||||
|
import space.uranos.net.UranosSession
|
||||||
|
|
||||||
|
object PlayerLocationPacketHandler : PacketReceivedEventHandler<PlayerLocationPacket>() {
|
||||||
|
override suspend fun handle(session: UranosSession, packet: PlayerLocationPacket) {
|
||||||
|
val player = session.player!!
|
||||||
|
player.entity.position = player.entity.position.copy(
|
||||||
|
x = packet.location.x,
|
||||||
|
y = packet.location.y,
|
||||||
|
z = packet.location.z
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2020-2021 Moritz Ruth and Uranos contributors
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file
|
||||||
|
*/
|
||||||
|
|
||||||
|
package space.uranos.net.packet.play
|
||||||
|
|
||||||
|
import space.uranos.net.PacketReceivedEventHandler
|
||||||
|
import space.uranos.net.UranosSession
|
||||||
|
|
||||||
|
object PlayerOrientationPacketHandler : PacketReceivedEventHandler<PlayerOrientationPacket>() {
|
||||||
|
override suspend fun handle(session: UranosSession, packet: PlayerOrientationPacket) {
|
||||||
|
val player = session.player!!
|
||||||
|
player.entity.position = player.entity.position.copy(yaw = packet.yaw, pitch = packet.pitch)
|
||||||
|
}
|
||||||
|
}
|
|
@ -70,6 +70,7 @@ class UranosPlayer(
|
||||||
|
|
||||||
init {
|
init {
|
||||||
this.selectedHotbarSlot = selectedHotbarSlot
|
this.selectedHotbarSlot = selectedHotbarSlot
|
||||||
|
this.playerListName = null
|
||||||
}
|
}
|
||||||
|
|
||||||
override var currentlyViewedChunks = emptyList<Chunk>()
|
override var currentlyViewedChunks = emptyList<Chunk>()
|
||||||
|
|
Reference in a new issue