2 Players in same place test
This commit is contained in:
parent
9bbef92ea9
commit
3579f46209
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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(
|
||||
|
@ -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]"
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 -> {
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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()
|
||||
|
||||
|
@ -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
|
||||
|
@ -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() }
|
||||
|
@ -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() {
|
||||
|
@ -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
|
||||
|
@ -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")
|
||||
}
|
||||
|
||||
|
@ -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))
|
||||
|
@ -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() }
|
||||
|
@ -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())
|
||||
|
Loading…
Reference in New Issue
Block a user