2 Players in same place test

This commit is contained in:
DBotThePony 2024-03-27 17:11:38 +07:00
parent 9bbef92ea9
commit 3579f46209
Signed by: DBot
GPG Key ID: DCC23B5715498507
22 changed files with 161 additions and 60 deletions

View File

@ -90,7 +90,7 @@ object Starbound : ISBFileLocator {
const val NATIVE_PROTOCOL_VERSION = 748
const val LEGACY_PROTOCOL_VERSION = 747
const val TIMESTEP = 1.0 / 60.0
const val TICK_TIME_ADVANCE_NANOS = (TIMESTEP * 1_000_000_000L).toLong()
const val TIMESTEP_NANOS = (TIMESTEP * 1_000_000_000L).toLong()
// compile flags. uuuugh
const val DEDUP_CELL_STATES = true

View File

@ -681,7 +681,7 @@ class StarboundClient private constructor(val clientID: Int) : Closeable {
blendFunc = BlendFunc.MULTIPLY_WITH_ALPHA
}
val spinner = ExecutionSpinner(::executeQueuedTasks, ::renderFrame, Starbound.TICK_TIME_ADVANCE_NANOS)
val spinner = ExecutionSpinner(::executeQueuedTasks, ::renderFrame, Starbound.TIMESTEP_NANOS)
val settings = ClientSettings()
val viewportCells: ICellAccess = object : ICellAccess {

View File

@ -70,9 +70,19 @@ data class HumanoidData(
stream.writeBinaryString(facialMaskDirectives)
stream.writeBinaryString(personalityIdle)
stream.writeBinaryString(personalityArmIdle)
if (isLegacy) stream.writeStruct2f(personalityHeadOffset.toFloatVector()) else stream.writeStruct2d(personalityHeadOffset)
if (isLegacy) stream.writeStruct2f(personalityArmOffset.toFloatVector()) else stream.writeStruct2d(personalityArmOffset)
stream.writeColor(color)
if (isLegacy) {
stream.writeStruct2f(personalityHeadOffset.toFloatVector())
stream.writeStruct2f(personalityArmOffset.toFloatVector())
stream.writeByte(color.redInt)
stream.writeByte(color.greenInt)
stream.writeByte(color.blueInt)
stream.writeByte(color.alphaInt)
} else {
stream.writeStruct2d(personalityHeadOffset)
stream.writeStruct2d(personalityArmOffset)
stream.writeColor(color)
}
stream.writeBoolean(imagePath != null)
@ -101,13 +111,12 @@ data class HumanoidData(
val facialMaskType = stream.readInternedString()
val facialMaskDirectives = stream.readInternedString()
val color: RGBAColor = stream.readColor()
val personalityIdle: String = stream.readInternedString()
val personalityArmIdle: String = stream.readInternedString()
val personalityHeadOffset: Vector2d = if (isLegacy) stream.readVector2f().toDoubleVector() else stream.readVector2d()
val personalityArmOffset: Vector2d = if (isLegacy) stream.readVector2f().toDoubleVector() else stream.readVector2d()
val color: RGBAColor = if (isLegacy) RGBAColor(stream.readUnsignedByte(), stream.readUnsignedByte(), stream.readUnsignedByte(), stream.readUnsignedByte()) else stream.readColor()
val imagePath: String? = if (stream.readBoolean()) stream.readInternedString() else null
return HumanoidData(

View File

@ -103,7 +103,7 @@ data class ItemDescriptor(
constructor(ref: Registry.Ref<IItemDefinition>, count: Long, parameters: JsonObject) : this(ref.key.left(), count, parameters)
val isEmpty get() = count <= 0L || name == "" || ref.isEmpty
val ref by lazy { Registries.items.ref(name) }
val ref by lazy { if (name == "") Registries.items.emptyRef else Registries.items.ref(name) }
override fun toString(): String {
return "ItemDescriptor[$name, $count, $parameters]"

View File

@ -102,8 +102,8 @@ fun OutputStream.writeAABBLegacyOptional(value: KOptional<AABB>) {
}.ifNotPresent {
writeFloat(Float.MAX_VALUE)
writeFloat(Float.MAX_VALUE)
writeFloat(Float.MIN_VALUE)
writeFloat(Float.MIN_VALUE)
writeFloat(-Float.MAX_VALUE)
writeFloat(-Float.MAX_VALUE)
}
}

View File

@ -32,7 +32,7 @@ open class ItemStack {
}
constructor(descriptor: ItemDescriptor) {
this.config = Registries.items.ref(descriptor.name)
this.config = descriptor.ref
this.count = descriptor.count
this.parameters = descriptor.parameters.deepCopy()
}
@ -211,7 +211,7 @@ open class ItemStack {
val EMPTY = ItemStack()
fun create(descriptor: ItemDescriptor): ItemStack {
return EMPTY
return ItemStack(descriptor)
}
}
}

View File

@ -236,6 +236,7 @@ class PacketRegistry(val isLegacy: Boolean) {
networkReadBuffer.removeElements(0, reader.position().toInt())
} catch (err: EOFException) {
// Ignore EOF, since it is caused by segmented nature of TCP
break
}
}
}

View File

@ -1,5 +1,6 @@
package ru.dbotthepony.kstarbound.network.packets
import it.unimi.dsi.fastutil.bytes.ByteArrayList
import it.unimi.dsi.fastutil.io.FastByteArrayInputStream
import org.apache.logging.log4j.LogManager
import ru.dbotthepony.kommons.io.readByteArray
@ -16,18 +17,18 @@ import java.io.DataInputStream
import java.io.DataOutputStream
import java.io.File
class EntityCreatePacket(val entityType: EntityType, val storeData: ByteArray, val firstNetState: ByteArray, val entityID: Int) : IServerPacket, IClientPacket {
class EntityCreatePacket(val entityType: EntityType, val storeData: ByteArrayList, val firstNetState: ByteArrayList, val entityID: Int) : IServerPacket, IClientPacket {
constructor(stream: DataInputStream, isLegacy: Boolean) : this(
EntityType.entries[stream.readUnsignedByte()],
stream.readByteArray(),
stream.readByteArray(),
ByteArrayList.wrap(stream.readByteArray()),
ByteArrayList.wrap(stream.readByteArray()),
stream.readSignedVarInt()
)
override fun write(stream: DataOutputStream, isLegacy: Boolean) {
stream.writeByte(entityType.ordinal)
stream.writeByteArray(storeData)
stream.writeByteArray(firstNetState)
stream.writeByteArray(storeData.elements(), 0, storeData.size)
stream.writeByteArray(firstNetState.elements(), 0, firstNetState.size)
stream.writeSignedVarInt(entityID)
}
@ -37,15 +38,25 @@ class EntityCreatePacket(val entityType: EntityType, val storeData: ByteArray, v
} else {
val entity = when (entityType) {
EntityType.PLAYER -> {
val player = PlayerEntity(DataInputStream(FastByteArrayInputStream(storeData)), connection.isLegacy)
player.networkGroup.read(firstNetState, isLegacy = connection.isLegacy)
player
try {
val player = PlayerEntity(DataInputStream(FastByteArrayInputStream(storeData.elements(), 0, storeData.size)), connection.isLegacy)
player.networkGroup.read(firstNetState, isLegacy = connection.isLegacy)
val (data) = player.networkGroup.write(isLegacy = true)
player.networkGroup.read(data, isLegacy = true)
player
} catch (err: Throwable) {
LOGGER.error("", err)
null
}
}
else -> null
}
entity?.entityID = entityID
entity?.isRemote = true
entity?.networkGroup?.upstream?.enableInterpolation(0.0)
connection.enqueue {
entity?.joinWorld(this)

View File

@ -10,6 +10,7 @@ import ru.dbotthepony.kommons.io.readVarInt
import ru.dbotthepony.kommons.io.writeByteArray
import ru.dbotthepony.kommons.io.writeSignedVarInt
import ru.dbotthepony.kommons.io.writeVarInt
import ru.dbotthepony.kstarbound.Starbound
import ru.dbotthepony.kstarbound.client.ClientConnection
import ru.dbotthepony.kstarbound.network.IClientPacket
import ru.dbotthepony.kstarbound.network.IServerPacket
@ -17,14 +18,14 @@ import ru.dbotthepony.kstarbound.server.ServerConnection
import java.io.DataInputStream
import java.io.DataOutputStream
class EntityUpdateSetPacket(val forConnection: Int, val deltas: Int2ObjectMap<ByteArray>) : IServerPacket, IClientPacket {
class EntityUpdateSetPacket(val forConnection: Int, val deltas: Int2ObjectMap<ByteArrayList>) : IServerPacket, IClientPacket {
override fun write(stream: DataOutputStream, isLegacy: Boolean) {
stream.writeVarInt(forConnection)
stream.writeVarInt(deltas.size)
for ((k, v) in deltas.entries) {
stream.writeSignedVarInt(k)
stream.writeByteArray(v)
stream.writeByteArray(v.elements(), 0, v.size)
}
}
@ -34,7 +35,7 @@ class EntityUpdateSetPacket(val forConnection: Int, val deltas: Int2ObjectMap<By
if (id !in connection.entityIDRange) {
LOGGER.error("Player $connection tried to update entity with ID $id, but that's outside of allowed range ${connection.entityIDRange}!")
} else {
entities[id]?.readDelta(ByteArrayList.wrap(delta), 0.0, connection.isLegacy)
entities[id]?.networkGroup?.read(delta, Starbound.TIMESTEP, connection.isLegacy)
}
}
}
@ -49,12 +50,12 @@ class EntityUpdateSetPacket(val forConnection: Int, val deltas: Int2ObjectMap<By
val forConnection = stream.readVarInt()
val size = stream.readVarInt()
val deltas = Int2ObjectAVLTreeMap<ByteArray>()
val deltas = Int2ObjectAVLTreeMap<ByteArrayList>()
for (i in 0 until size) {
val k = stream.readSignedVarInt()
val v = stream.readByteArray()
deltas[k] = v
deltas[k] = ByteArrayList.wrap(v)
}
return EntityUpdateSetPacket(forConnection, deltas)

View File

@ -145,6 +145,8 @@ class FloatingNetworkedElement(private var value: Double = 0.0, val ops: Ops, va
value = read
valueListeners.accept(read)
}
bumpVersion()
}
override fun writeDelta(data: DataOutputStream, remoteVersion: Long, isLegacy: Boolean) {
@ -193,9 +195,10 @@ class FloatingNetworkedElement(private var value: Double = 0.0, val ops: Ops, va
}
override fun tickInterpolation(delta: Double) {
require(delta >= 0.0) { "Negative interpolation delta: $delta" }
currentTime += delta
if (isInterpolating) {
if (isInterpolating && queue.size >= 2) {
while (queue.size > 2 && queue[1].first <= currentTime) {
queue.removeFirst()
}
@ -220,13 +223,23 @@ class FloatingNetworkedElement(private var value: Double = 0.0, val ops: Ops, va
val (time0, value0) = queue[0]
val (time1, value1) = queue[1]
return interpolator.interpolate(((actualTime - time0) / (time1 - time0)).coerceAtLeast(-extrapolation), value0, value1)
var diff = ((actualTime - time0) / (time1 - time0)).coerceAtLeast(-extrapolation)
if (diff.isNaN() || !diff.isFinite())
diff = 0.0
return interpolator.interpolate(diff, value0, value1)
} else if (actualTime > queue.last().first) {
// extrapolate into future
val (time0, value0) = queue[queue.size - 2]
val (time1, value1) = queue[queue.size - 1]
return interpolator.interpolate(((actualTime - time1) / (time1 - time0)).coerceAtMost(extrapolation + 1.0), value0, value1)
var diff = ((actualTime - time1) / (time1 - time0)).coerceAtMost(extrapolation + 1.0)
if (diff.isNaN() || !diff.isFinite())
diff = 0.0
return interpolator.interpolate(diff, value0, value1)
} else {
// normal interpolation
for (i in 0 until queue.size - 1) {
@ -234,7 +247,12 @@ class FloatingNetworkedElement(private var value: Double = 0.0, val ops: Ops, va
val (time1, value1) = queue[i + 1]
if (actualTime in time0 .. time1) {
return interpolator.interpolate((actualTime - time0) / (time1 - time0), value0, value1)
var diff = (actualTime - time0) / (time1 - time0)
if (diff.isNaN() || !diff.isFinite())
diff = 0.0
return interpolator.interpolate(diff, value0, value1)
}
}

View File

@ -93,6 +93,8 @@ class NetworkedMap<K, V>(
}
fun write(data: DataOutputStream, isLegacy: Boolean, self: NetworkedMap<K, V>) {
data.writeByte(action.ordinal)
if (isLegacy) {
when (action) {
Action.ADD -> {

View File

@ -3,6 +3,10 @@ package ru.dbotthepony.kstarbound.server
import com.google.gson.JsonObject
import io.netty.channel.ChannelHandlerContext
import it.unimi.dsi.fastutil.bytes.ByteArrayList
import it.unimi.dsi.fastutil.ints.Int2LongOpenHashMap
import it.unimi.dsi.fastutil.ints.Int2ObjectMap
import it.unimi.dsi.fastutil.ints.Int2ObjectMaps
import it.unimi.dsi.fastutil.io.FastByteArrayOutputStream
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap
import it.unimi.dsi.fastutil.objects.ObjectLinkedOpenHashSet
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet
@ -21,6 +25,8 @@ import ru.dbotthepony.kstarbound.network.ConnectionSide
import ru.dbotthepony.kstarbound.network.ConnectionType
import ru.dbotthepony.kstarbound.network.IServerPacket
import ru.dbotthepony.kstarbound.network.packets.ClientContextUpdatePacket
import ru.dbotthepony.kstarbound.network.packets.EntityCreatePacket
import ru.dbotthepony.kstarbound.network.packets.EntityUpdateSetPacket
import ru.dbotthepony.kstarbound.network.packets.clientbound.LegacyTileArrayUpdatePacket
import ru.dbotthepony.kstarbound.network.packets.clientbound.PlayerWarpResultPacket
import ru.dbotthepony.kstarbound.network.packets.clientbound.ServerDisconnectPacket
@ -32,6 +38,8 @@ import ru.dbotthepony.kstarbound.world.IChunkListener
import ru.dbotthepony.kstarbound.world.api.ImmutableCell
import ru.dbotthepony.kstarbound.world.entities.AbstractEntity
import ru.dbotthepony.kstarbound.world.entities.WorldObject
import ru.dbotthepony.kstarbound.world.entities.player.PlayerEntity
import java.io.DataOutputStream
import java.util.HashMap
import java.util.concurrent.ConcurrentLinkedQueue
import kotlin.properties.Delegates
@ -250,6 +258,12 @@ class ServerConnection(val server: StarboundServer, type: ConnectionType) : Conn
}
}
private val entityVersions = Int2LongOpenHashMap()
init {
entityVersions.defaultReturnValue(-1L)
}
fun tickWorld() {
val world = world
@ -284,6 +298,33 @@ class ServerConnection(val server: StarboundServer, type: ConnectionType) : Conn
itr.remove()
}
for ((id, entity) in world.entities) {
if (entity.connectionID != connectionID && entity is PlayerEntity) {
if (entityVersions.get(id) == -1L) {
// never networked
val initial = FastByteArrayOutputStream()
entity.writeNetwork(DataOutputStream(initial), isLegacy)
val (data, version) = entity.networkGroup.write(isLegacy = isLegacy)
entityVersions.put(id, version)
send(EntityCreatePacket(
entity.type,
ByteArrayList.wrap(initial.array, initial.length),
data,
entity.entityID
))
} else {
val (data, version) = entity.networkGroup.write(remoteVersion = entityVersions.get(id), isLegacy = isLegacy)
entityVersions.put(id, version)
if (data.isNotEmpty()) {
send(EntityUpdateSetPacket(entity.connectionID, Int2ObjectMaps.singleton(entity.entityID, data)))
}
}
}
}
}
override fun channelRead(ctx: ChannelHandlerContext, msg: Any) {
@ -316,9 +357,17 @@ class ServerConnection(val server: StarboundServer, type: ConnectionType) : Conn
shipWorld = it
shipWorld.thread.start()
send(PlayerWarpResultPacket(true, WarpAlias.OwnShip, false))
shipWorld.acceptPlayer(this).exceptionally {
shipWorld.acceptPlayer(this).thenAccept {
for (conn in server.channels.connections) {
if (conn.isLegacy && conn !== this) {
conn.shipWorld.acceptPlayer(this)
break
}
}
}.exceptionally {
LOGGER.error("Shipworld of $this rejected to accept its owner", it)
disconnect("Shipworld rejected player warp request: $it")
null
}
}.exceptionally {
LOGGER.error("Error while initializing shipworld for $this", it)

View File

@ -31,7 +31,7 @@ sealed class StarboundServer(val root: File) : Closeable {
val serverID = threadCounter.getAndIncrement()
val mailbox = MailboxExecutorService()
val spinner = ExecutionSpinner(mailbox::executeQueuedTasks, ::spin, Starbound.TICK_TIME_ADVANCE_NANOS)
val spinner = ExecutionSpinner(mailbox::executeQueuedTasks, ::spin, Starbound.TIMESTEP_NANOS)
val thread = Thread(spinner, "Starbound Server $serverID")
val universe = ServerUniverse()
val chat = ChatHandler(this)

View File

@ -113,7 +113,7 @@ class ServerWorld private constructor(
}
}
val spinner = ExecutionSpinner(mailbox::executeQueuedTasks, ::spin, Starbound.TICK_TIME_ADVANCE_NANOS)
val spinner = ExecutionSpinner(mailbox::executeQueuedTasks, ::spin, Starbound.TIMESTEP_NANOS)
val thread = Thread(spinner, "Starbound Server World Thread")
val ticketListLock = ReentrantLock()

View File

@ -2,7 +2,6 @@ package ru.dbotthepony.kstarbound.util
import org.apache.logging.log4j.LogManager
import org.lwjgl.system.MemoryStack
import ru.dbotthepony.kommons.util.MailboxExecutorService
import ru.dbotthepony.kstarbound.Starbound
import ru.dbotthepony.kstarbound.WindowsBindings
import java.util.concurrent.locks.LockSupport
@ -47,7 +46,7 @@ class ExecutionSpinner(private val waiter: Runnable, private val spinner: Boolea
}
private fun timeUntilNextFrame(): Long {
return Starbound.TICK_TIME_ADVANCE_NANOS - (System.nanoTime() - lastRender) - frameRenderTime
return Starbound.TIMESTEP_NANOS - (System.nanoTime() - lastRender) - frameRenderTime
}
private var carrier: Thread? = null

View File

@ -269,7 +269,7 @@ abstract class World<This : World<This, ChunkType>, ChunkType : Chunk<This, Chun
ticks++
mailbox.executeQueuedTasks()
ForkJoinPool.commonPool().submit(ParallelPerform(dynamicEntities.spliterator(), { it.movement.move() })).join()
ForkJoinPool.commonPool().submit(ParallelPerform(dynamicEntities.spliterator(), { if (!it.isRemote) it.movement.move() })).join()
mailbox.executeQueuedTasks()
entities.values.forEach { it.think() }

View File

@ -3,16 +3,19 @@ package ru.dbotthepony.kstarbound.world.entities
import it.unimi.dsi.fastutil.bytes.ByteArrayList
import ru.dbotthepony.kommons.util.MailboxExecutorService
import ru.dbotthepony.kommons.vector.Vector2d
import ru.dbotthepony.kstarbound.Starbound
import ru.dbotthepony.kstarbound.client.StarboundClient
import ru.dbotthepony.kstarbound.client.render.LayeredRenderer
import ru.dbotthepony.kstarbound.defs.EntityType
import ru.dbotthepony.kstarbound.defs.JsonDriven
import ru.dbotthepony.kstarbound.network.syncher.MasterElement
import ru.dbotthepony.kstarbound.network.syncher.NetworkedGroup
import ru.dbotthepony.kstarbound.world.Chunk
import ru.dbotthepony.kstarbound.world.ChunkPos
import ru.dbotthepony.kstarbound.world.LightCalculator
import ru.dbotthepony.kstarbound.world.World
import java.io.DataInputStream
import ru.dbotthepony.kstarbound.world.entities.player.PlayerEntity
import java.io.DataOutputStream
import java.util.UUID
import kotlin.concurrent.withLock
abstract class AbstractEntity(path: String) : JsonDriven(path) {
@ -54,8 +57,15 @@ abstract class AbstractEntity(path: String) : JsonDriven(path) {
throw IllegalStateException("Already has Entity ID set (to $field)")
field = value
if (value < 0) {
connectionID = (-value - 1) / 65536 + 1
}
}
var connectionID: Int = 0
private set
var mailbox = MailboxExecutorService()
private set
@ -67,6 +77,7 @@ abstract class AbstractEntity(path: String) : JsonDriven(path) {
val isSpawned: Boolean
get() = innerWorld != null
abstract val type: EntityType
/**
* If set, then the entity will be discoverable by its unique id and will be
@ -88,9 +99,8 @@ abstract class AbstractEntity(path: String) : JsonDriven(path) {
protected open fun onJoinWorld(world: World<*, *>) { }
protected open fun onRemove(world: World<*, *>) { }
abstract fun writeToNetwork(stream: DataOutputStream, isLegacy: Boolean)
abstract fun readDelta(stream: ByteArrayList, interpolationTime: Double = 0.0, isLegacy: Boolean)
val networkGroup = MasterElement(NetworkedGroup())
abstract fun writeNetwork(stream: DataOutputStream, isLegacy: Boolean)
fun joinWorld(world: World<*, *>) {
if (innerWorld != null)
@ -124,8 +134,7 @@ abstract class AbstractEntity(path: String) : JsonDriven(path) {
innerWorld = null
}
open val isRemote: Boolean
get() = innerWorld?.isRemote ?: false
var isRemote: Boolean = false
fun think() {
thinkShared()
@ -142,7 +151,7 @@ abstract class AbstractEntity(path: String) : JsonDriven(path) {
}
protected open fun thinkRemote() {
networkGroup.upstream.tickInterpolation(Starbound.TIMESTEP)
}
protected open fun thinkLocal() {

View File

@ -133,8 +133,8 @@ class StatusController(val entity: ActorEntity, val config: StatusControllerConf
val networkGroup = NetworkedGroup()
var duration by networkedFixedPoint(0.01).also { networkGroup.add(it); it.interpolator = Interpolator.Linear }
var maxDuration by networkedFixedPoint(0.01).also { networkGroup.add(it) }
var sourceEntity by networkedData(KOptional(), KOptionalIntValueCodec)
var maxDuration by networkedFloat().also { networkGroup.add(it) }
var sourceEntity by networkedData(KOptional(), KOptionalIntValueCodec).also { networkGroup.add(it) }
}
// stats

View File

@ -21,6 +21,7 @@ import ru.dbotthepony.kstarbound.defs.`object`.ObjectOrientation
import ru.dbotthepony.kstarbound.server.world.ServerWorld
import ru.dbotthepony.kommons.gson.get
import ru.dbotthepony.kommons.gson.set
import ru.dbotthepony.kstarbound.defs.EntityType
import ru.dbotthepony.kstarbound.world.Side
import ru.dbotthepony.kstarbound.world.LightCalculator
import ru.dbotthepony.kstarbound.world.PIXELS_IN_STARBOUND_UNITf
@ -46,11 +47,10 @@ open class WorldObject(
}
}
override fun readDelta(stream: ByteArrayList, interpolationTime: Double, isLegacy: Boolean) {
TODO("Not yet implemented")
}
override val type: EntityType
get() = EntityType.OBJECT
override fun writeToNetwork(stream: DataOutputStream, isLegacy: Boolean) {
override fun writeNetwork(stream: DataOutputStream, isLegacy: Boolean) {
TODO("Not yet implemented")
}

View File

@ -2,11 +2,13 @@ package ru.dbotthepony.kstarbound.world.entities.player
import com.google.gson.JsonObject
import it.unimi.dsi.fastutil.bytes.ByteArrayList
import ru.dbotthepony.kommons.io.writeBinaryString
import ru.dbotthepony.kommons.util.getValue
import ru.dbotthepony.kommons.util.setValue
import ru.dbotthepony.kommons.vector.Vector2d
import ru.dbotthepony.kstarbound.GlobalDefaults
import ru.dbotthepony.kstarbound.defs.EntityDamageTeam
import ru.dbotthepony.kstarbound.defs.EntityType
import ru.dbotthepony.kstarbound.defs.actor.HumanoidData
import ru.dbotthepony.kstarbound.defs.actor.HumanoidEmote
import ru.dbotthepony.kstarbound.defs.actor.player.PlayerGamemode
@ -53,10 +55,16 @@ class PlayerEntity() : HumanoidActorEntity("/") {
println(humanoidData)
}
override val type: EntityType
get() = EntityType.PLAYER
var gamemode = PlayerGamemode.CASUAL
override fun writeToNetwork(stream: DataOutputStream, isLegacy: Boolean) {
TODO("Not yet implemented")
override fun writeNetwork(stream: DataOutputStream, isLegacy: Boolean) {
stream.writeBinaryString(uniqueID!!)
stream.writeBinaryString("")
if (isLegacy) stream.writeInt(gamemode.ordinal) else stream.writeByte(gamemode.ordinal)
humanoidData.write(stream, isLegacy)
}
val inventory = PlayerInventory()
@ -65,12 +73,6 @@ class PlayerEntity() : HumanoidActorEntity("/") {
override val statusController = StatusController(this, GlobalDefaults.player.statusControllerSettings)
val techController = TechController(this)
val networkGroup = MasterElement(NetworkedGroup())
override fun readDelta(stream: ByteArrayList, interpolationTime: Double, isLegacy: Boolean) {
networkGroup.read(stream, interpolationTime, isLegacy)
}
var state by networkGroup.upstream.add(networkedEnum(State.IDLE))
var shifting by networkGroup.upstream.add(networkedBoolean())
private var xAimPosition by networkGroup.upstream.add(networkedFixedPoint(0.003125))

View File

@ -58,6 +58,8 @@ class PlayerInventory {
}
}
val networkGroup = NetworkedGroup()
// here it gets interesting, original code is using List#sorted, which itself uses Star::sort,
// which is just an alias for std::sort, and std::sort is ***not*** stable sort, meaning
// if bags have same priority, PlayerInventory behavior becomes undefined
@ -69,8 +71,6 @@ class PlayerInventory {
.map { it.key to Bag(it.value.size) }
.collect(ImmutableMap.toImmutableMap({ it.first }, { it.second }))
val networkGroup = NetworkedGroup()
val equipment: ImmutableMap<EquipmentSlot, NetworkedItemStack> = EquipmentSlot.entries
.stream()
.map { it to networkedItem() }

View File

@ -108,7 +108,7 @@ object NetworkedElementTests {
val result = master.write().first
slave.read(FastByteArrayInputStream(result.array, 0, result.length))
slave.read(result)
assertEquals(567, slaveField1.get())
assertEquals(17000, slaveField2.get())