Archived
1
0
Fork 0

Update player entity positions server-side

This commit is contained in:
Moritz Ruth 2021-01-06 23:30:58 +01:00
parent 818939267a
commit fb047b22a3
No known key found for this signature in database
GPG key ID: AFD57E23E753841B
19 changed files with 115 additions and 17 deletions

View file

@ -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"))

View file

@ -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

View file

@ -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>
} }

View file

@ -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

View file

@ -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()
} }

View file

@ -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
}
}
} }

View file

@ -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()
} }

View file

@ -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!!`.
*/ */

View file

@ -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()
) )

View file

@ -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

View file

@ -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.*

View file

@ -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() }
} }
} }

View file

@ -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
}
}

View file

@ -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
) )
) )

View file

@ -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
)
}
}

View file

@ -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)
}
}

View file

@ -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>()