Add entity metadata packet and object entity spawning
This commit is contained in:
parent
c959478978
commit
0b1ba947a1
26 changed files with 288 additions and 93 deletions
5
.idea/misc.xml
generated
5
.idea/misc.xml
generated
|
@ -1,5 +1,10 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="EntryPointsManager">
|
||||
<list size="1">
|
||||
<item index="0" class="java.lang.String" itemvalue="com.squareup.moshi.FromJson" />
|
||||
</list>
|
||||
</component>
|
||||
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_14" default="true" project-jdk-name="14" project-jdk-type="JavaSDK" />
|
||||
<component name="SuppressKotlinCodeStyleNotification">
|
||||
|
|
|
@ -3,12 +3,14 @@ package space.uranos.testplugin
|
|||
import space.uranos.Uranos
|
||||
import space.uranos.chat.ChatColor
|
||||
import space.uranos.chat.TextComponent
|
||||
import space.uranos.entity.MinecartEntity
|
||||
import space.uranos.entity.Position
|
||||
import space.uranos.entity.RideableMinecartEntity
|
||||
import space.uranos.net.ServerListInfo
|
||||
import space.uranos.net.event.ServerListInfoRequestEvent
|
||||
import space.uranos.net.event.SessionAfterLoginEvent
|
||||
import space.uranos.net.packet.play.EntityMetadataPacket
|
||||
import space.uranos.player.GameMode
|
||||
import space.uranos.player.event.PlayerReadyEvent
|
||||
import space.uranos.plugin.Plugin
|
||||
import space.uranos.testplugin.anvil.AnvilWorld
|
||||
import space.uranos.util.RGBColor
|
||||
|
@ -104,10 +106,22 @@ class TestPlugin : Plugin("Test", "1.0.0") {
|
|||
}
|
||||
}
|
||||
|
||||
// Not showing up yet because no metadata is sent
|
||||
val entity = Uranos.create<MinecartEntity>()
|
||||
val entity = Uranos.create<RideableMinecartEntity>()
|
||||
entity.position = Position(0.0, 4.0, 0.0)
|
||||
// entity.setWorld(world)
|
||||
entity.setWorld(world)
|
||||
|
||||
Uranos.eventBus.on<PlayerReadyEvent> {
|
||||
it.player.session.send(EntityMetadataPacket(entity.numericID, listOf(
|
||||
EntityMetadataPacket.MetadataEntry.Byte(0u, 0x00),
|
||||
EntityMetadataPacket.MetadataEntry.Int(1u, 0x00),
|
||||
EntityMetadataPacket.MetadataEntry.OptChat(2u, null),
|
||||
EntityMetadataPacket.MetadataEntry.Boolean(3u, false),
|
||||
EntityMetadataPacket.MetadataEntry.Boolean(4u, false),
|
||||
EntityMetadataPacket.MetadataEntry.Boolean(5u, false),
|
||||
EntityMetadataPacket.MetadataEntry.Int(6u, 0),
|
||||
EntityMetadataPacket.MetadataEntry.Boolean(12u, true)
|
||||
)))
|
||||
}
|
||||
|
||||
var x = 0f
|
||||
var y = -90f
|
||||
|
|
|
@ -25,7 +25,7 @@ interface Entity {
|
|||
val numericID: Int
|
||||
|
||||
/**
|
||||
* Players that can see this entity.
|
||||
* Players that can see this entity if it is in their view distance.
|
||||
*/
|
||||
val viewers: MutableSet<Player>
|
||||
|
||||
|
@ -38,6 +38,17 @@ interface Entity {
|
|||
* If players should be added to [viewers] when they enter [world].
|
||||
*/
|
||||
var visibleToNewPlayers: Boolean
|
||||
|
||||
var glowing: Boolean // even experience orbs can glow
|
||||
|
||||
var invisible: Boolean
|
||||
|
||||
/**
|
||||
* Whether this entity does not produce any sounds.
|
||||
*/
|
||||
var silent: Boolean
|
||||
|
||||
var ignoreGravity: Boolean
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
package space.uranos.entity
|
||||
|
||||
import space.uranos.world.block.Block
|
||||
|
||||
interface MinecartEntity: ObjectEntity, YawRotatable, PitchRotatable {
|
||||
/**
|
||||
* Default is `0`.
|
||||
*/
|
||||
val shakingPower: Int
|
||||
|
||||
/**
|
||||
* Default is `1`.
|
||||
*/
|
||||
val shakingDirection: Int
|
||||
|
||||
/**
|
||||
* Default is `0.0`.
|
||||
*/
|
||||
val shakingMultiplier: Float
|
||||
|
||||
val customBlock: Block?
|
||||
|
||||
/**
|
||||
* The Y offset of the block inside the minecart, measured in 16ths of a block.
|
||||
*/
|
||||
val blockOffset: Int
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
package space.uranos.entity
|
||||
|
||||
interface RideableMinecartEntity : MinecartEntity {
|
||||
companion object Type : MinecartEntityType()
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
package space.uranos.net.packet.play
|
||||
|
||||
import io.netty.buffer.ByteBuf
|
||||
import space.uranos.net.MinecraftProtocolDataTypes.writeString
|
||||
import space.uranos.net.MinecraftProtocolDataTypes.writeVarInt
|
||||
import space.uranos.net.packet.OutgoingPacketCodec
|
||||
|
||||
object EntityMetadataPacketCodec : OutgoingPacketCodec<EntityMetadataPacket>(0x44, EntityMetadataPacket::class) {
|
||||
override fun EntityMetadataPacket.encode(dst: ByteBuf) {
|
||||
dst.writeVarInt(entityID)
|
||||
|
||||
for (entry in metadata) {
|
||||
dst.writeByte(entry.index.toInt())
|
||||
dst.writeVarInt(entry.typeID)
|
||||
|
||||
when(entry) {
|
||||
is EntityMetadataPacket.MetadataEntry.Byte -> dst.writeByte(entry.value.toInt())
|
||||
is EntityMetadataPacket.MetadataEntry.Int -> dst.writeVarInt(entry.value)
|
||||
is EntityMetadataPacket.MetadataEntry.Float -> dst.writeFloat(entry.value)
|
||||
is EntityMetadataPacket.MetadataEntry.String -> dst.writeString(entry.value)
|
||||
is EntityMetadataPacket.MetadataEntry.OptChat -> {
|
||||
if (entry.value == null) dst.writeBoolean(false)
|
||||
else {
|
||||
dst.writeBoolean(true)
|
||||
dst.writeString(entry.value!!.toJson())
|
||||
}
|
||||
}
|
||||
is EntityMetadataPacket.MetadataEntry.Boolean -> dst.writeBoolean(entry.value)
|
||||
}
|
||||
}
|
||||
|
||||
dst.writeByte(0xff)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package space.uranos.net.packet.play
|
||||
|
||||
import io.netty.buffer.ByteBuf
|
||||
import space.uranos.net.MinecraftProtocolDataTypes.writeVarInt
|
||||
import space.uranos.net.packet.OutgoingPacketCodec
|
||||
|
||||
object EntityVelocityPacketCodec : OutgoingPacketCodec<EntityVelocityPacket>(0x46, EntityVelocityPacket::class) {
|
||||
override fun EntityVelocityPacket.encode(dst: ByteBuf) {
|
||||
dst.writeVarInt(entityID)
|
||||
dst.writeShort(x.toInt())
|
||||
dst.writeShort(y.toInt())
|
||||
dst.writeShort(z.toInt())
|
||||
}
|
||||
}
|
|
@ -14,10 +14,12 @@ object PlayProtocol : Protocol(
|
|||
DestroyEntitiesPacketCodec,
|
||||
DisconnectPacketCodec,
|
||||
EntityHeadYawPacketCodec,
|
||||
EntityMetadataPacketCodec,
|
||||
EntityOrientationPacketCodec,
|
||||
EntityRelativeMovePacketCodec,
|
||||
EntityRelativeMoveWithOrientationPacketCodec,
|
||||
EntityTeleportPacketCodec,
|
||||
EntityVelocityPacketCodec,
|
||||
IncomingKeepAlivePacketCodec,
|
||||
IncomingPlayerPositionPacketCodec,
|
||||
IncomingPluginMessagePacketCodec,
|
||||
|
|
|
@ -7,7 +7,7 @@ import space.uranos.util.numbers.floorMod
|
|||
object PlayerOrientationPacketCodec :
|
||||
IncomingPacketCodec<PlayerOrientationPacket>(0x14, PlayerOrientationPacket::class) {
|
||||
override fun decode(msg: ByteBuf): PlayerOrientationPacket = PlayerOrientationPacket(
|
||||
floorMod(msg.readFloat(), 360f),
|
||||
floorMod(msg.readFloat(), 360f), // TODO: Ensure it is never 360 (should be 0 then)
|
||||
msg.readFloat(),
|
||||
msg.readBoolean()
|
||||
)
|
||||
|
|
|
@ -20,8 +20,8 @@ object SpawnLivingEntityPacketCodec : OutgoingPacketCodec<SpawnLivingEntityPacke
|
|||
// This is named "head pitch" on wiki.vg, but it is actually head yaw.
|
||||
dst.writeByte(headYaw.mapToUByte(360f).toInt())
|
||||
|
||||
dst.writeShort((velocity.x * 8000).toInt().toShort().toInt())
|
||||
dst.writeShort((velocity.y * 8000).toInt().toShort().toInt())
|
||||
dst.writeShort((velocity.z * 8000).toInt().toShort().toInt())
|
||||
dst.writeShort(velocityX.toInt())
|
||||
dst.writeShort(velocityY.toInt())
|
||||
dst.writeShort(velocityZ.toInt())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,8 +16,8 @@ object SpawnObjectEntityPacketCodec : OutgoingPacketCodec<SpawnObjectEntityPacke
|
|||
dst.writeByte(pitch.toInt())
|
||||
dst.writeByte(yaw.toInt())
|
||||
dst.writeInt(data)
|
||||
dst.writeShort((velocity.x * 8000).toInt().toShort().toInt())
|
||||
dst.writeShort((velocity.y * 8000).toInt().toShort().toInt())
|
||||
dst.writeShort((velocity.z * 8000).toInt().toShort().toInt())
|
||||
dst.writeShort(velocityX.toInt())
|
||||
dst.writeShort(velocityY.toInt())
|
||||
dst.writeShort(velocityZ.toInt())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
package space.uranos.net.packet.play
|
||||
|
||||
import space.uranos.chat.ChatComponent
|
||||
import space.uranos.net.packet.OutgoingPacket
|
||||
|
||||
data class EntityMetadataPacket(
|
||||
val entityID: Int,
|
||||
val metadata: Iterable<MetadataEntry<*>>
|
||||
) : OutgoingPacket() {
|
||||
sealed class MetadataEntry<T>(val typeID: kotlin.Int) {
|
||||
abstract val index: UByte
|
||||
abstract val value: T
|
||||
|
||||
data class Byte(override val index: UByte, override val value: kotlin.Byte) : MetadataEntry<kotlin.Byte>(0)
|
||||
data class Int(override val index: UByte, override val value: kotlin.Int) : MetadataEntry<kotlin.Int>(1)
|
||||
data class Float(override val index: UByte, override val value: kotlin.Float) : MetadataEntry<kotlin.Float>(2)
|
||||
data class String(override val index: UByte, override val value: kotlin.String) : MetadataEntry<kotlin.String>(3)
|
||||
data class OptChat(override val index: UByte, override val value: ChatComponent?) : MetadataEntry<ChatComponent?>(5)
|
||||
data class Boolean(override val index: UByte, override val value: kotlin.Boolean) : MetadataEntry<kotlin.Boolean>(7)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
package space.uranos.net.packet.play
|
||||
|
||||
import space.uranos.net.packet.OutgoingPacket
|
||||
|
||||
data class EntityVelocityPacket(
|
||||
val entityID: Int,
|
||||
val x: Short,
|
||||
val y: Short,
|
||||
val z: Short
|
||||
) : OutgoingPacket()
|
|
@ -1,6 +1,5 @@
|
|||
package space.uranos.net.packet.play
|
||||
|
||||
import space.uranos.Vector
|
||||
import space.uranos.entity.EntityType
|
||||
import space.uranos.entity.Position
|
||||
import space.uranos.net.packet.OutgoingPacket
|
||||
|
@ -8,6 +7,8 @@ import java.util.UUID
|
|||
|
||||
/**
|
||||
* Sent to spawn **living** entities.
|
||||
*
|
||||
* Velocity is measured in 1/8000 blocks per tick.
|
||||
*/
|
||||
data class SpawnLivingEntityPacket(
|
||||
val entityID: Int,
|
||||
|
@ -17,8 +18,7 @@ data class SpawnLivingEntityPacket(
|
|||
val yaw: Float,
|
||||
val pitch: Float,
|
||||
val headYaw: Float,
|
||||
/**
|
||||
* Velocity in blocks per tick
|
||||
*/
|
||||
val velocity: Vector
|
||||
val velocityX: Short,
|
||||
val velocityY: Short,
|
||||
val velocityZ: Short
|
||||
) : OutgoingPacket()
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
package space.uranos.net.packet.play
|
||||
|
||||
import space.uranos.Vector
|
||||
import space.uranos.net.packet.OutgoingPacket
|
||||
import java.util.UUID
|
||||
|
||||
/**
|
||||
* Sent to spawn object entities.
|
||||
*
|
||||
* Velocity is measured in 1/8000 blocks per tick.
|
||||
*/
|
||||
data class SpawnObjectEntityPacket(
|
||||
val entityID: Int,
|
||||
|
@ -17,5 +18,7 @@ data class SpawnObjectEntityPacket(
|
|||
val yaw: UByte,
|
||||
val pitch: UByte,
|
||||
val data: Int,
|
||||
val velocity: Vector
|
||||
val velocityX: Short,
|
||||
val velocityY: Short,
|
||||
val velocityZ: Short
|
||||
) : OutgoingPacket()
|
||||
|
|
|
@ -8,37 +8,45 @@ import space.uranos.net.packet.play.SpawnPaintingPacket
|
|||
import space.uranos.util.numbers.mapToUByte
|
||||
|
||||
fun Entity.createSpawnPacket(): OutgoingPacket = when (this) {
|
||||
is LivingEntity -> if (this is HasMovableHead) SpawnLivingEntityPacket(
|
||||
numericID,
|
||||
uuid,
|
||||
type,
|
||||
position,
|
||||
headYaw,
|
||||
headPitch,
|
||||
headYaw,
|
||||
velocity
|
||||
) else SpawnLivingEntityPacket(
|
||||
numericID,
|
||||
uuid,
|
||||
type,
|
||||
position,
|
||||
if (this is YawRotatable) yaw else 0f,
|
||||
if (this is PitchRotatable) pitch else 0f,
|
||||
0f,
|
||||
velocity
|
||||
)
|
||||
is ObjectEntity -> SpawnObjectEntityPacket(
|
||||
numericID,
|
||||
uuid,
|
||||
type.numericID,
|
||||
position.x,
|
||||
position.y,
|
||||
position.z,
|
||||
if (this is YawRotatable) yaw.mapToUByte(360f) else 0u,
|
||||
if (this is PitchRotatable) pitch.mapToUByte(360f) else 0u,
|
||||
getDataValue(),
|
||||
velocity
|
||||
)
|
||||
is LivingEntity -> {
|
||||
val (velX, velY, velZ) = velocity.getAsVelocityPacketValues()
|
||||
|
||||
if (this is HasMovableHead) SpawnLivingEntityPacket(
|
||||
numericID,
|
||||
uuid,
|
||||
type,
|
||||
position,
|
||||
headYaw,
|
||||
headPitch,
|
||||
headYaw,
|
||||
velX, velY, velZ
|
||||
) else SpawnLivingEntityPacket(
|
||||
numericID,
|
||||
uuid,
|
||||
type,
|
||||
position,
|
||||
if (this is YawRotatable) yaw else 0f,
|
||||
if (this is PitchRotatable) pitch else 0f,
|
||||
0f,
|
||||
velX, velY, velZ
|
||||
)
|
||||
}
|
||||
is ObjectEntity -> {
|
||||
val (velX, velY, velZ) = velocity.getAsVelocityPacketValues()
|
||||
|
||||
SpawnObjectEntityPacket(
|
||||
numericID,
|
||||
uuid,
|
||||
type.numericID,
|
||||
position.x,
|
||||
position.y,
|
||||
position.z,
|
||||
if (this is YawRotatable) yaw.mapToUByte(360f) else 0u,
|
||||
if (this is PitchRotatable) pitch.mapToUByte(360f) else 0u,
|
||||
getDataValue(),
|
||||
velX, velY, velZ
|
||||
)
|
||||
}
|
||||
is PaintingEntity -> SpawnPaintingPacket(
|
||||
numericID,
|
||||
uuid,
|
||||
|
@ -51,7 +59,7 @@ fun Entity.createSpawnPacket(): OutgoingPacket = when (this) {
|
|||
|
||||
fun ObjectEntity.getDataValue(): Int = when (this) {
|
||||
is ItemEntity -> 1
|
||||
is MinecartEntity -> 2
|
||||
is RideableMinecartEntity -> 0
|
||||
// TODO: Add remaining
|
||||
else -> throw IllegalArgumentException("Unknown entity type")
|
||||
}
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
package space.uranos.util
|
||||
|
||||
import space.uranos.Vector
|
||||
|
||||
fun Vector.getAsVelocityPacketValues() = Triple(
|
||||
(x * 8000).toInt().toShort(),
|
||||
(y * 8000).toInt().toShort(),
|
||||
(z * 8000).toInt().toShort()
|
||||
)
|
|
@ -0,0 +1,16 @@
|
|||
package space.uranos
|
||||
|
||||
import space.uranos.entity.*
|
||||
import space.uranos.entity.impl.UranosBatEntity
|
||||
import space.uranos.entity.impl.UranosCowEntity
|
||||
import space.uranos.entity.impl.UranosCreeperEntity
|
||||
import space.uranos.entity.impl.UranosRideableMinecartEntity
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun <T : Entity> createEntityInstance(server: UranosServer, type: EntityType<T>): T = when (type) {
|
||||
CowEntity -> UranosCowEntity(server)
|
||||
BatEntity -> UranosBatEntity(server)
|
||||
CreeperEntity -> UranosCreeperEntity(server)
|
||||
RideableMinecartEntity -> UranosRideableMinecartEntity(server)
|
||||
else -> throw IllegalArgumentException("Entities of this type cannot be created with this function")
|
||||
} as T
|
|
@ -5,8 +5,10 @@ import com.sksamuel.hoplite.ConfigLoader
|
|||
import com.sksamuel.hoplite.ConfigSource
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import space.uranos.config.UranosConfig
|
||||
import space.uranos.entity.*
|
||||
import space.uranos.entity.impl.*
|
||||
import space.uranos.entity.Entity
|
||||
import space.uranos.entity.EntityType
|
||||
import space.uranos.entity.UranosEntity
|
||||
import space.uranos.entity.impl.UranosPlayerEntity
|
||||
import space.uranos.event.UranosEventBus
|
||||
import space.uranos.event.UranosEventHandlerPositionManager
|
||||
import space.uranos.logging.Logger
|
||||
|
@ -79,20 +81,8 @@ class UranosServer internal constructor() : Server() {
|
|||
private val internalEntities = HashSet<UranosEntity>()
|
||||
override val entities: Set<Entity> = internalEntities
|
||||
|
||||
override fun <T : Entity> create(type: EntityType<T>): T {
|
||||
val entity: UranosEntity = when (type) {
|
||||
CowEntity -> UranosCowEntity(this)
|
||||
BatEntity -> UranosBatEntity(this)
|
||||
CreeperEntity -> UranosCreeperEntity(this)
|
||||
MinecartEntity -> UranosMinecartEntity(this)
|
||||
else -> throw IllegalArgumentException("Entities of this type cannot be created with this function")
|
||||
}
|
||||
|
||||
internalEntities.add(entity)
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return entity as T
|
||||
}
|
||||
override fun <T : Entity> create(type: EntityType<T>): T =
|
||||
createEntityInstance(this, type).also { internalEntities.add(it as UranosEntity) }
|
||||
|
||||
fun createPlayerEntity(player: UranosPlayer) =
|
||||
UranosPlayerEntity(this, player).also { internalEntities.add(it) }
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
package space.uranos.entity
|
||||
|
||||
class EntityMetadataSynchronizer(val entity: UranosEntity) {
|
||||
init {
|
||||
// println(entity::class.allSuperclasses)
|
||||
}
|
||||
|
||||
fun tick() {
|
||||
|
||||
}
|
||||
}
|
|
@ -23,8 +23,6 @@ import java.util.UUID
|
|||
import java.util.WeakHashMap
|
||||
|
||||
sealed class UranosEntity(server: UranosServer) : Entity {
|
||||
override fun belongsToChunk(key: Chunk.Key): Boolean = key == chunkKey
|
||||
|
||||
override val numericID: Int = server.claimEntityID()
|
||||
override val uuid: UUID = UUID.randomUUID()
|
||||
|
||||
|
@ -65,19 +63,31 @@ sealed class UranosEntity(server: UranosServer) : Entity {
|
|||
}
|
||||
}
|
||||
|
||||
override fun toString(): String = "Entity($uuid)"
|
||||
override var glowing: Boolean = false
|
||||
override var ignoreGravity: Boolean = false
|
||||
override var invisible: Boolean = false
|
||||
override var silent: Boolean = false
|
||||
|
||||
override fun toString(): String = "Entity($uuid)"
|
||||
override fun belongsToChunk(key: Chunk.Key): Boolean = key == chunkKey
|
||||
|
||||
abstract suspend fun tick()
|
||||
abstract val chunkKey: Chunk.Key
|
||||
|
||||
protected val container = TickSynchronizationContainer()
|
||||
|
||||
protected fun sendSpawnAndDestroyPackets() {
|
||||
private fun sendSpawnAndDestroyPackets() {
|
||||
if (addedViewers.isNotEmpty()) createSpawnPacket().let { packet -> addedViewers.forEach { it.session.send(packet) } }
|
||||
if (removedViewers.isNotEmpty()) DestroyEntitiesPacket(arrayOf(numericID)).let { packet -> removedViewers.forEach { it.session.send(packet) } }
|
||||
}
|
||||
|
||||
protected fun finishTick() {
|
||||
@Suppress("LeakingThis")
|
||||
private val metadataSynchronizer = EntityMetadataSynchronizer(this)
|
||||
|
||||
open suspend fun tick() {
|
||||
container.tick()
|
||||
metadataSynchronizer.tick()
|
||||
|
||||
sendSpawnAndDestroyPackets()
|
||||
addedViewers.clear()
|
||||
removedViewers.clear()
|
||||
}
|
||||
|
@ -106,8 +116,6 @@ abstract class UranosNotHasMovableHeadLivingEntity(server: UranosServer) : Urano
|
|||
private var lastSentPitch: Float = 0f
|
||||
|
||||
final override suspend fun tick() {
|
||||
container.tick()
|
||||
|
||||
val viewersWithoutAdded = viewers.subtract(addedViewers)
|
||||
if (viewersWithoutAdded.isNotEmpty()) {
|
||||
val packet = createMovementPacket()
|
||||
|
@ -119,8 +127,7 @@ abstract class UranosNotHasMovableHeadLivingEntity(server: UranosServer) : Urano
|
|||
if (this is PitchRotatable) lastSentPitch = pitch
|
||||
if (this is YawRotatable) lastSentYaw = yaw
|
||||
|
||||
sendSpawnAndDestroyPackets()
|
||||
finishTick()
|
||||
super.tick()
|
||||
}
|
||||
|
||||
private fun createMovementPacket(): OutgoingPacket? = createNotHasMovableHeadMovementPacket(position, lastSentPosition, lastSentYaw, lastSentPitch)
|
||||
|
@ -138,8 +145,6 @@ abstract class UranosHasMovableHeadLivingEntity(server: UranosServer) : UranosLi
|
|||
}
|
||||
|
||||
final override suspend fun tick() {
|
||||
container.tick()
|
||||
|
||||
val viewersWithoutAdded = viewers.subtract(addedViewers)
|
||||
if (viewersWithoutAdded.isNotEmpty()) {
|
||||
val packets = createMovementPackets()
|
||||
|
@ -152,8 +157,7 @@ abstract class UranosHasMovableHeadLivingEntity(server: UranosServer) : UranosLi
|
|||
oldHeadPitch = headPitch
|
||||
oldHeadYaw = headYaw
|
||||
|
||||
sendSpawnAndDestroyPackets()
|
||||
finishTick()
|
||||
super.tick()
|
||||
}
|
||||
|
||||
private var oldPosition: Position = Position.ZERO
|
||||
|
@ -216,8 +220,6 @@ abstract class UranosObjectEntity(server: UranosServer) : UranosEntity(server),
|
|||
private var lastSentPitch: Float = 0f
|
||||
|
||||
final override suspend fun tick() {
|
||||
container.tick()
|
||||
|
||||
val viewersWithoutAdded = viewers.subtract(addedViewers)
|
||||
if (viewersWithoutAdded.isNotEmpty()) {
|
||||
val packet = createMovementPacket()
|
||||
|
@ -228,9 +230,9 @@ abstract class UranosObjectEntity(server: UranosServer) : UranosEntity(server),
|
|||
|
||||
if (this is PitchRotatable) lastSentPitch = pitch
|
||||
if (this is YawRotatable) lastSentYaw = yaw
|
||||
lastSentPosition = position
|
||||
|
||||
sendSpawnAndDestroyPackets()
|
||||
finishTick()
|
||||
super.tick()
|
||||
}
|
||||
|
||||
private fun createMovementPacket(): OutgoingPacket? = createNotHasMovableHeadMovementPacket(position, lastSentPosition, lastSentYaw, lastSentPitch)
|
||||
|
@ -247,8 +249,6 @@ class UranosPaintingEntity(
|
|||
private var lastSentTopLeftLocation: VoxelLocation = topLeftLocation
|
||||
|
||||
override suspend fun tick() {
|
||||
container.tick()
|
||||
|
||||
if (lastSentTopLeftLocation != topLeftLocation) {
|
||||
val viewersWithoutAdded = viewers.subtract(addedViewers)
|
||||
if (viewersWithoutAdded.isNotEmpty()) {
|
||||
|
@ -269,8 +269,7 @@ class UranosPaintingEntity(
|
|||
|
||||
lastSentTopLeftLocation = topLeftLocation
|
||||
|
||||
sendSpawnAndDestroyPackets()
|
||||
finishTick()
|
||||
super.tick()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,12 +1,10 @@
|
|||
package space.uranos.entity.impl
|
||||
package space.uranos.entity
|
||||
|
||||
import space.uranos.UranosServer
|
||||
import space.uranos.entity.MinecartEntity
|
||||
import space.uranos.entity.UranosObjectEntity
|
||||
import space.uranos.util.numbers.validatePitch
|
||||
import space.uranos.util.numbers.validateYaw
|
||||
|
||||
class UranosMinecartEntity(server: UranosServer) : UranosObjectEntity(server), MinecartEntity {
|
||||
abstract class UranosMinecartEntity(server: UranosServer) : UranosObjectEntity(server), MinecartEntity {
|
||||
override var yaw: Float = 0f
|
||||
set(value) {
|
||||
validateYaw(value); field = value
|
||||
|
@ -16,4 +14,8 @@ class UranosMinecartEntity(server: UranosServer) : UranosObjectEntity(server), M
|
|||
set(value) {
|
||||
validatePitch(value); field = value
|
||||
}
|
||||
|
||||
override val shakingPower: Int = 0
|
||||
override val shakingDirection: Int = 1
|
||||
override val shakingMultiplier: Float = 0f
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
package space.uranos.entity.impl
|
||||
|
||||
import space.uranos.UranosServer
|
||||
import space.uranos.entity.RideableMinecartEntity
|
||||
import space.uranos.entity.UranosMinecartEntity
|
||||
import space.uranos.world.block.Block
|
||||
|
||||
class UranosRideableMinecartEntity(server: UranosServer) : UranosMinecartEntity(server), RideableMinecartEntity {
|
||||
override val customBlock: Block? = null
|
||||
override val blockOffset: Int = 6
|
||||
}
|
|
@ -68,6 +68,7 @@ class LoginAndJoinProcedure(val session: UranosSession) {
|
|||
val result = AuthenticationHelper.authenticate(hashString, state.username)
|
||||
|
||||
session.sendNow(SetCompressionPacket(session.server.config.packetCompressionThreshold))
|
||||
// TODO: Handle disconnect errors
|
||||
session.enableCompressionCodec()
|
||||
|
||||
session.sendNow(LoginSuccessPacket(result.uuid, result.username))
|
||||
|
|
|
@ -18,6 +18,7 @@ class PacketsAdapter(val session: UranosSession) {
|
|||
private val packetsForNextTick = ArrayList<OutgoingPacket>()
|
||||
|
||||
suspend fun tick() {
|
||||
// TODO: Fix ConcurrentModificationException
|
||||
packetsForNextTick.forEach { send(it) }
|
||||
packetsForNextTick.clear()
|
||||
}
|
||||
|
|
|
@ -125,6 +125,7 @@ class UranosSession(val channel: io.netty.channel.Channel, val server: UranosSer
|
|||
if (!expected && currentProtocol != HandshakingProtocol && currentProtocol != StatusProtocol)
|
||||
logger trace "The client disconnected unexpectedly"
|
||||
|
||||
// TODO: Remove the player entity and send PlayerInfo packet
|
||||
packetsAdapter.stopProcessingIncomingPackets()
|
||||
coroutineContext.cancel(DisconnectedCancellationException())
|
||||
state = State.Disconnected
|
||||
|
|
Reference in a new issue