Almost completely rewrite serialization system

This commit is contained in:
Gabriel Tofvesson 2020-03-25 21:21:43 +01:00
parent dda62a1a02
commit 224f85323f
19 changed files with 558 additions and 447 deletions

View File

@ -4,6 +4,7 @@
<exclude-output /> <exclude-output />
<content url="file://$MODULE_DIR$"> <content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" /> <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/test" isTestSource="true" />
</content> </content>
<orderEntry type="inheritedJdk" /> <orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" /> <orderEntry type="sourceFolder" forTests="false" />

View File

@ -3,7 +3,7 @@ package net.tofvesson.data
class DiffTrackedArray<T>(val elementType: Class<T>, val size: Int, gen: (Int) -> T) { class DiffTrackedArray<T>(val elementType: Class<T>, val size: Int, gen: (Int) -> T) {
val values: Array<T> = java.lang.reflect.Array.newInstance(elementType, size) as Array<T> val values: Array<T> = java.lang.reflect.Array.newInstance(elementType, size) as Array<T>
val changeMap = Array(size) {false} val changeMap = BooleanArray(size) {false}
init{ init{
for(index in 0 until size) for(index in 0 until size)

View File

@ -0,0 +1,123 @@
package net.tofvesson.data
import net.tofvesson.math.*
import java.nio.ByteBuffer
class RBuffer(val buffer: ByteBuffer, bitOffset: Long)
{
/*
* Backing fields for indices
*/
private var bits = 0L
private var bytes = 0
init {
bytes = (readPackedMisaligned((bitOffset ushr 3).toInt(), (bitOffset and 7).toInt()).toInt() + bitOffset.bitIndexToBytes()).toInt()
bits += (varIntSize(bytes.toLong()) * 8) + bitOffset
}
fun readBit() = readBitAt(bits++)
fun readByte() = buffer.get(bytes++)
fun readShort(): Short {
val result = buffer.getShort(bytes)
bytes += 2
return result
}
fun readInt(): Int {
val result = buffer.getInt(bytes)
bytes += 4
return result
}
fun readLong(): Long {
val result = buffer.getLong(bytes)
bytes += 8
return result
}
fun readFloat(): Float {
val result = buffer.getFloat(bytes)
bytes += 4
return result
}
fun readDouble(): Double {
val result = buffer.getDouble(bytes)
bytes += 8
return result
}
fun readPackedShort(noZigZag: Boolean = false) = readPackedLong(noZigZag).toShort()
fun readPackedInt(noZigZag: Boolean = false) = readPackedLong(noZigZag).toInt()
fun readPackedLong(noZigZag: Boolean = false): Long {
//doBoundaryCheck(1)
val header: Long = buffer[bytes++].toLong() and 0xFF
if (header <= 240L) return if(noZigZag) header else zigZagDecode(header)
if (header <= 248L){
//doBoundaryCheck(2)
val res = 240L + ((header - 241L).shl(8)) + (buffer[bytes++].toLong() and 0xFF)
return if(noZigZag) res else zigZagDecode(res)
}
if (header == 249L){
//doBoundaryCheck(3)
val res = 2288 + ((buffer[bytes++].toLong() and 0xFF).shl(8)) + (buffer[bytes++].toLong() and 0xFF)
return if(noZigZag) res else zigZagDecode(res)
}
val hdr = header - 247
//doBoundaryCheck(hdr.toInt())
var res = (buffer[bytes++].toLong() and 0xFF).or(((buffer[bytes++].toLong() and 0xFF).shl(8)).or((buffer[bytes++].toLong() and 0xFF).shl(16)))
var cmp = 2
while (hdr > ++cmp)
res = res.or((buffer[bytes++].toLong() and 0xFF).shl(cmp.shl(3)))
return if(noZigZag) res else zigZagDecode(res)
}
fun readPackedFloat(noSwapEndian: Boolean = false): Float {
val readVal = readPackedInt(true)
return if(noSwapEndian) intToFloat(readVal) else intToFloat(swapEndian(readVal))
}
fun readPackedDouble(noSwapEndian: Boolean = false): Double {
val readVal = readPackedLong(true)
return if(noSwapEndian) longToDouble(readVal) else longToDouble(swapEndian(readVal))
}
private fun readMisaligned(index: Int, shift: Int) =
((buffer[index].toInt() and 0xFF ushr shift) or (buffer[index + 1].toInt() and 0xFF shl (8 - shift))).toByte()
private fun readPackedMisaligned(index: Int, shift: Int): Long {
var idx = index
val header: Long = readMisaligned(idx++, shift).toLong() and 0xFF
if (header <= 240L) return header
if (header <= 248L){
return 240L + ((header - 241L).shl(8)) + (readMisaligned(idx, shift).toLong() and 0xFF)
}
if (header == 249L){
return 2288 + ((readMisaligned(idx++, shift).toLong() and 0xFF).shl(8)) + (readMisaligned(idx, shift).toLong() and 0xFF)
}
val hdr = header - 247
//doBoundaryCheck(hdr.toInt())
var res = (readMisaligned(idx++, shift).toLong() and 0xFF).or(((readMisaligned(idx++, shift).toLong() and 0xFF).shl(8)).or((readMisaligned(idx++, shift).toLong() and 0xFF).shl(16)))
var cmp = 2
while (hdr > ++cmp)
res = res.or((readMisaligned(idx++, shift).toLong() and 0xFF).shl(cmp.shl(3)))
return res
}
private fun readBitAt(bitIndex: Long) =
(buffer[(bitIndex ushr 3).toInt()].toInt() ushr (bitIndex and 7).toInt()) and 1 != 0
private fun Long.bitIndexToBytes() = (this ushr 3) + ((this or (this ushr 1) or (this ushr 2)) and 1)
}

View File

@ -1,130 +0,0 @@
package net.tofvesson.data
import net.tofvesson.exception.InsufficientCapacityException
import net.tofvesson.math.*
import java.nio.ByteBuffer
@Suppress("MemberVisibilityCanBePrivate", "unused")
class ReadBuffer(state: WriteState, private val _buffer: ByteBuffer, bufferBitOffset: Int = 0) {
/*
Buffer layout:
{BufferBitOffset}[Header][Bits]{BitOffset}[Bytes]
BufferBitOffset is optional and usually set to 0
BitOffset is between 0 and 7 bits long (to realign data to the next free byte)
*/
private var headerIndex = bufferBitOffset
private var bitOffset = bufferBitOffset + state.header
private var byteIndex = state.computeBitFieldOffset(bufferBitOffset)
// Maximum size for the above values
private val maxHeaderSize = bufferBitOffset + state.header
private val maxBitOffset: Int
private val maxByteOffset = _buffer.capacity()
val buffer: ByteBuffer
get() = this._buffer
init {
if(_buffer.capacity() - (bufferBitOffset ushr 3) - bufferBitOffset.collapseLowerByte() < state.computeBitFieldOffset())
throw InsufficientCapacityException()
byteIndex = readPackedInt(true)
maxBitOffset = bufferBitOffset + byteIndex*8
}
private fun readBit(head: Boolean): Boolean {
if(head && headerIndex >= maxHeaderSize)
throw IndexOutOfBoundsException("Attempt to read more headers than available space permits!")
val index = (if(head) headerIndex else bitOffset) ushr 3
val shift = (if(head) headerIndex else bitOffset) and 7
if(head) ++headerIndex
else ++bitOffset
return (_buffer[index].toInt() and (1 shl shift)) != 0
}
fun readHeader() = readBit(true)
fun readBit() = readBit(false)
fun readByte(): Byte {
//doBoundaryCheck(1)
return _buffer.get(byteIndex++)
}
fun readShort(): Short {
//doBoundaryCheck(2)
val res = _buffer.getShort(byteIndex)
byteIndex += 2
return res
}
fun readInt(): Int {
//doBoundaryCheck(4)
val res = _buffer.getInt(byteIndex)
byteIndex += 4
return res
}
fun readLong(): Long {
//doBoundaryCheck(8)
val res = _buffer.getLong(byteIndex)
byteIndex += 8
return res
}
fun readFloat(): Float {
//doBoundaryCheck(4)
val res = _buffer.getFloat(byteIndex)
byteIndex += 4
return res
}
fun readDouble(): Double {
//doBoundaryCheck(8)
val res = _buffer.getDouble(byteIndex)
byteIndex += 8
return res
}
fun readPackedShort(noZigZag: Boolean = false) = readPackedLong(noZigZag).toShort()
fun readPackedInt(noZigZag: Boolean = false) = readPackedLong(noZigZag).toInt()
fun readPackedLong(noZigZag: Boolean = false): Long {
//doBoundaryCheck(1)
val header: Long = buffer[byteIndex++].toLong() and 0xFF
if (header <= 240L) return if(noZigZag) header else zigZagDecode(header)
if (header <= 248L){
//doBoundaryCheck(2)
val res = 240L + ((header - 241L).shl(8)) + (buffer[byteIndex++].toLong() and 0xFF)
return if(noZigZag) res else zigZagDecode(res)
}
if (header == 249L){
//doBoundaryCheck(3)
val res = 2288 + ((buffer[byteIndex++].toLong() and 0xFF).shl(8)) + (buffer[byteIndex++].toLong() and 0xFF)
return if(noZigZag) res else zigZagDecode(res)
}
val hdr = header - 247
//doBoundaryCheck(hdr.toInt())
var res = (buffer[byteIndex++].toLong() and 0xFF).or(((buffer[byteIndex++].toLong() and 0xFF).shl(8)).or((buffer[byteIndex++].toLong() and 0xFF).shl(16)))
var cmp = 2
while (hdr > ++cmp)
res = res.or((buffer[byteIndex++].toLong() and 0xFF).shl(cmp.shl(3)))
return if(noZigZag) res else zigZagDecode(res)
}
fun readPackedFloat(noSwapEndian: Boolean = false): Float {
val readVal = readPackedInt(true)
return if(noSwapEndian) intToFloat(readVal) else intToFloat(swapEndian(readVal))
}
fun readPackedDouble(noSwapEndian: Boolean = false): Double {
val readVal = readPackedLong(true)
return if(noSwapEndian) longToDouble(readVal) else longToDouble(swapEndian(readVal))
}
private fun doBoundaryCheck(byteCount: Int) {
if(byteIndex + byteCount > maxByteOffset)
throw IndexOutOfBoundsException("Attempt to read value past maximum range!")
}
}

View File

@ -2,6 +2,7 @@ package net.tofvesson.data
import net.tofvesson.annotation.SyncFlag import net.tofvesson.annotation.SyncFlag
import net.tofvesson.exception.UnsupportedTypeException import net.tofvesson.exception.UnsupportedTypeException
import net.tofvesson.reflect.access
import java.lang.reflect.Field import java.lang.reflect.Field
import java.util.* import java.util.*
@ -16,7 +17,9 @@ abstract class Serializer(registeredTypes: Array<Class<*>>) {
flags: Array<out SyncFlag>, flags: Array<out SyncFlag>,
owner: Any?, owner: Any?,
state: WriteState state: WriteState
) = computeSizeExplicit(field, flags, owner, state, field.type) ) = if (canSerialize(field.get(owner), flags, field.type))
computeSizeExplicit(field, flags, owner, state, field.type)
else Unit
abstract fun computeSizeExplicit( abstract fun computeSizeExplicit(
field: Field, field: Field,
@ -34,14 +37,16 @@ abstract class Serializer(registeredTypes: Array<Class<*>>) {
field: Field, field: Field,
flags: Array<out SyncFlag>, flags: Array<out SyncFlag>,
owner: Any?, owner: Any?,
writeBuffer: WriteBuffer writeBuffer: WBuffer
) = serializeExplicit(field, flags, owner, writeBuffer, field.type) ) = if (canSerialize(field.get(owner), flags, field.type))
serializeExplicit(field.access(), flags, owner, writeBuffer, field.type)
else Unit
abstract fun serializeExplicit( abstract fun serializeExplicit(
field: Field, field: Field,
flags: Array<out SyncFlag>, flags: Array<out SyncFlag>,
owner: Any?, owner: Any?,
writeBuffer: WriteBuffer, writeBuffer: WBuffer,
fieldType: Class<*> fieldType: Class<*>
) )
@ -53,20 +58,25 @@ abstract class Serializer(registeredTypes: Array<Class<*>>) {
field: Field, field: Field,
flags: Array<out SyncFlag>, flags: Array<out SyncFlag>,
owner: Any?, owner: Any?,
readBuffer: ReadBuffer readBuffer: RBuffer
) = deserializeExplicit(field, flags, owner, readBuffer, field.type) ) = if (canDeserialize(field.get(owner), flags, field.type))
deserializeExplicit(field.access(), flags, owner, readBuffer, field.type)
else Unit
abstract fun deserializeExplicit( abstract fun deserializeExplicit(
field: Field, field: Field,
flags: Array<out SyncFlag>, flags: Array<out SyncFlag>,
owner: Any?, owner: Any?,
readBuffer: ReadBuffer, readBuffer: RBuffer,
fieldType: Class<*> fieldType: Class<*>
) )
abstract fun canSerialize(obj: Any?, flags: Array<out SyncFlag>, type: Class<*>): Boolean
open fun canDeserialize(obj: Any?, flags: Array<out SyncFlag>, type: Class<*>) = canSerialize(obj, flags, type)
fun getRegisteredTypes(): Array<Class<*>> = Arrays.copyOf(registeredTypes, registeredTypes.size) fun getRegisteredTypes(): Array<Class<*>> = Arrays.copyOf(registeredTypes, registeredTypes.size)
fun canSerialize(field: Field): Boolean = registeredTypes.contains(field.type) fun canSerialize(field: Field) = canSerialize(field.type)
fun canSerialize(type: Class<*>): Boolean = registeredTypes.contains(type) open fun canSerialize(type: Class<*>): Boolean = registeredTypes.contains(type)
protected fun throwInvalidType(type: Class<*>): Nothing = throw UnsupportedTypeException("Type ${this.javaClass} cannot serialize $type") protected fun throwInvalidType(type: Class<*>): Nothing = throw UnsupportedTypeException("Type ${this.javaClass} cannot serialize $type")
} }

View File

@ -41,12 +41,12 @@ class SyncHandler(private val permissiveMismatchCheck: Boolean = false) {
} }
fun clearSerializers() = serializers.clear() fun clearSerializers() = serializers.clear()
fun getRegisteredSerializers() = serializers.toArray() fun getRegisteredSerializers() = serializers.toTypedArray()
fun getCompatibleSerializer(type: Class<*>): Serializer { fun getCompatibleSerializer(type: Class<*>): Serializer? {
for(serializer in serializers) for(serializer in serializers)
if(serializer.canSerialize(type)) if(serializer.canSerialize(type))
return serializer return serializer
throw UnsupportedTypeException("Cannot find a compatible serializer for $type") return null
} }
@ -78,7 +78,7 @@ class SyncHandler(private val permissiveMismatchCheck: Boolean = false) {
for(entry in toSync) for(entry in toSync)
if(entry is Class<*>) computeClassSize(entry, writeState) if(entry is Class<*>) computeClassSize(entry, writeState)
else computeObjectSize(entry, writeState) else computeObjectSize(entry, writeState)
val writeBuffer = WriteBuffer(writeState) val writeBuffer = WBuffer(null, 0, writeState)
for(entry in toSync) for(entry in toSync)
if(entry is Class<*>) readClass(entry, writeBuffer) if(entry is Class<*>) readClass(entry, writeBuffer)
else readObject(entry, writeBuffer) else readObject(entry, writeBuffer)
@ -91,7 +91,7 @@ class SyncHandler(private val permissiveMismatchCheck: Boolean = false) {
for(entry in toSync) for(entry in toSync)
if(entry is Class<*>) computeClassSize(entry, writeState) if(entry is Class<*>) computeClassSize(entry, writeState)
else computeObjectSize(entry, writeState) else computeObjectSize(entry, writeState)
val readBuffer = ReadBuffer(writeState, ByteBuffer.wrap(syncData), bitOffset) val readBuffer = RBuffer(ByteBuffer.wrap(syncData), bitOffset.toLong())
for(entry in toSync) for(entry in toSync)
if(entry is Class<*>) writeClass(entry, readBuffer) if(entry is Class<*>) writeClass(entry, readBuffer)
else writeObject(entry, readBuffer) else writeObject(entry, readBuffer)
@ -132,22 +132,22 @@ class SyncHandler(private val permissiveMismatchCheck: Boolean = false) {
private fun computeTypeSize(type: Class<*>, value: Any?, writeState: WriteState) { private fun computeTypeSize(type: Class<*>, value: Any?, writeState: WriteState) {
for(field in collectSyncable(type, value == null)) for(field in collectSyncable(type, value == null))
getCompatibleSerializer(field.access().type) getCompatibleSerializer(field.access().type)
.computeSize(field, SyncFlag.parse(field.getAnnotation(SyncedVar::class.java).value), value, writeState) ?.computeSize(field, SyncFlag.parse(field.getAnnotation(SyncedVar::class.java).value), value, writeState)
} }
private fun readObject(value: Any, writeBuffer: WriteBuffer) = readType(value.javaClass, value, writeBuffer) private fun readObject(value: Any, writeBuffer: WBuffer) = readType(value.javaClass, value, writeBuffer)
private fun readClass(value: Class<*>, writeBuffer: WriteBuffer) = readType(value, null, writeBuffer) private fun readClass(value: Class<*>, writeBuffer: WBuffer) = readType(value, null, writeBuffer)
private fun readType(type: Class<*>, value: Any?, writeBuffer: WriteBuffer) { private fun readType(type: Class<*>, value: Any?, writeBuffer: WBuffer) {
for(field in collectSyncable(type, value == null)) for(field in collectSyncable(type, value == null))
getCompatibleSerializer(field.type) getCompatibleSerializer(field.type)
.serialize(field, SyncFlag.parse(field.getAnnotation(SyncedVar::class.java).value), value, writeBuffer) ?.serialize(field, SyncFlag.parse(field.getAnnotation(SyncedVar::class.java).value), value, writeBuffer)
} }
private fun writeObject(value: Any, readBuffer: ReadBuffer) = writeType(value.javaClass, value, readBuffer) private fun writeObject(value: Any, readBuffer: RBuffer) = writeType(value.javaClass, value, readBuffer)
private fun writeClass(value: Class<*>, readBuffer: ReadBuffer) = writeType(value, null, readBuffer) private fun writeClass(value: Class<*>, readBuffer: RBuffer) = writeType(value, null, readBuffer)
private fun writeType(type: Class<*>, value: Any?, readBuffer: ReadBuffer) { private fun writeType(type: Class<*>, value: Any?, readBuffer: RBuffer) {
for(field in collectSyncable(type, value == null)) for(field in collectSyncable(type, value == null))
getCompatibleSerializer(field.type) getCompatibleSerializer(field.type)
.deserialize(field, SyncFlag.parse(field.getAnnotation(SyncedVar::class.java).value), value, readBuffer) ?.deserialize(field, SyncFlag.parse(field.getAnnotation(SyncedVar::class.java).value), value, readBuffer)
} }
} }

View File

@ -0,0 +1,249 @@
package net.tofvesson.data
import net.tofvesson.math.*
import java.nio.ByteBuffer
import kotlin.experimental.and
import kotlin.experimental.inv
import kotlin.experimental.or
class WBuffer(_buffer: ByteBuffer?, bufferBitOffset: Long, private val maxima: WriteState)
{
/*
* Base indices
* Header base comes immediately after a special (not necessarily byte-aligned) byteBase index header
*/
/**
* Base bit index for writing metadata
*/
val metaBase = bufferBitOffset
val bitsBase = metaBase + (varIntSize((maxima.bits).toLong().bitIndexToBytes()) * 8)
val bytesBase = (bitsBase + maxima.bits).bitIndexToBytes()
/*
* Backing fields for indices
*/
private var bits = 0L
private var bytes = 0
/*
* Indices
*/
var bitIndex
get() = bitsBase + bits
set(value) {
if (value < bitsBase || value > (bitsBase + maxima.bits))
throw IndexOutOfBoundsException("Attempt to index bits beyond acceptable range")
bits = value - bitsBase
}
var byteIndex
get() = (bytesBase + bytes).toInt()
set(value) {
if (value < bytesBase || value > maxima.bytes + bytesBase + 1)
throw IndexOutOfBoundsException("Attempt to index bytes beyond acceptable range")
bytes = (value - bytesBase).toInt()
}
val buffer: ByteBuffer
init {
/*
* If given buffer is null, allocate a new buffer
* If given buffer is too small, allocate a new buffer and copy given buffer to the new buffer
* If given buffer is large enough, simply assign buffer field to said buffer
*/
when {
_buffer == null -> buffer = ByteBuffer.allocate((bytesBase + maxima.bytes).toInt())
_buffer.capacity() < bytesBase + maxima.bytes -> {
buffer = ByteBuffer.allocate((bytesBase + maxima.bytes).toInt())
buffer.put(_buffer)
}
else -> buffer = _buffer
}
writePackedMisaligned((bufferBitOffset ushr 3).toInt(), (bufferBitOffset and 7).toInt(), bytesBase)
}
fun writeBit(value: Boolean): WBuffer {
ensureBitBounds()
writeBitAt(bitIndex, value)
++bits
return this
}
fun writeByte(value: Byte): WBuffer {
ensureByteBounds(1)
buffer.put(byteIndex, value)
++bytes
return this
}
fun writeShort(value: Short): WBuffer {
ensureByteBounds(2)
buffer.putShort(byteIndex, value)
bytes += 2
return this
}
fun writeInt(value: Int): WBuffer {
ensureByteBounds(4)
buffer.putInt(byteIndex, value)
bytes += 4
return this
}
fun writeLong(value: Long): WBuffer {
ensureByteBounds(8)
buffer.putLong(byteIndex, value)
bytes += 8
return this
}
fun writeFloat(value: Float): WBuffer {
ensureByteBounds(4)
buffer.putFloat(byteIndex, value)
bytes += 4
return this
}
fun writeDouble(value: Double): WBuffer {
ensureByteBounds(8)
buffer.putDouble(byteIndex, value)
bytes += 8
return this
}
fun writePackedShort(value: Short, noZigZag: Boolean = false) = writePackedLong(value.toLong(), noZigZag)
fun writePackedInt(value: Int, noZigZag: Boolean = false) = writePackedLong(value.toLong(), noZigZag)
fun writePackedLong(value: Long, noZigZag: Boolean = false): WBuffer {
val toWrite = if(noZigZag) value else zigZagEncode(value)
val size = varIntSize(toWrite)
ensureByteBounds(size.toLong())
when(toWrite) {
in 0..240 -> buffer.put(byteIndex, toWrite.toByte())
in 241..2287 -> {
buffer.put(byteIndex, (((toWrite - 240) ushr 8) + 241).toByte())
buffer.put(byteIndex + 1, (toWrite - 240).toByte())
}
in 2288..67823 -> {
buffer.put(byteIndex, 249.toByte())
buffer.put(byteIndex + 1, ((toWrite - 2288) ushr 8).toByte())
buffer.put(byteIndex + 2, (toWrite - 2288).toByte())
}
else -> {
var header = 255
var match = 0x00FF_FFFF_FFFF_FFFFL
while (toWrite in 67824..match) {
--header
match = match ushr 8
}
buffer.put(byteIndex, header.toByte())
val max = header - 247
for (i in 0 until max)
buffer.put(byteIndex + 1 + i, (toWrite ushr (i shl 3)).toByte())
}
}
bytes += size
return this
}
fun writePackedFloat(value: Float, noSwapEndian: Boolean = false): WBuffer {
val write =
if(noSwapEndian) bitConvert(floatToInt(value))
else bitConvert(swapEndian(floatToInt(value)))
return writePackedLong(write, true)
}
fun writePackedDouble(value: Double, noSwapEndian: Boolean = false): WBuffer {
val write =
if(noSwapEndian) doubleToLong(value)
else swapEndian(doubleToLong(value))
return writePackedLong(write, true)
}
private fun writeMisaligned(index: Int, shift: Int, value: Byte) {
if(shift == 0)
{
buffer.put(index, value)
return
}
val byte = buffer[index] and (-1 shr (8 - shift)).toByte().inv()
val nextByte = buffer[index + 1] and (-1 shl shift).toByte()
buffer.put(index, byte or (value.toInt() shl (8 - shift) and 0xFF).toByte())
buffer.put(index + 1, nextByte or (value.toInt() and 0xFF ushr shift).toByte())
}
private fun writePackedMisaligned(index: Int, shift: Int, value: Long) {
when (value) {
in 0..240 -> writeMisaligned(index, shift, value.toByte())
in 241..2287 -> {
writeMisaligned(index, shift, (((value - 240) ushr 8) + 241).toByte())
writeMisaligned(index + 1, shift, (value - 240).toByte())
}
in 2288..67823 -> {
writeMisaligned(index, shift, 249.toByte())
writeMisaligned(index + 1, shift, ((value - 2288) ushr 8).toByte())
writeMisaligned(index + 2, shift, (value - 2288).toByte())
}
else -> {
var header = 255
var match = 0x00FF_FFFF_FFFF_FFFFL
while (value in 67824..match) {
--header
match = match ushr 8
}
writeMisaligned(index, shift, header.toByte())
val max = header - 247
for (i in 0 until max)
writeMisaligned(index + 1 + i, shift, (value ushr (i shl 3)).toByte())
}
}
}
private fun writeBitAt(bitIndex: Long, value: Boolean)
{
val byteIndex = (bitIndex ushr 3).toInt()
val byteShift = (bitIndex and 7).toInt()
val byte = buffer[byteIndex]
if (value)
buffer.put(byteIndex, byte or (1 shl byteShift).toByte())
else
buffer.put(byteIndex, byte and (1 shl byteShift).toByte().inv())
}
private fun ensureBitBounds() = ensureBounds(bits, 1, maxima.bits.toLong())
private fun ensureByteBounds(count: Long) = ensureBounds(bytes.toLong(), count, maxima.bytes.toLong())
private fun ensureBounds(index: Long, increment: Long, maximum: Long)
{
if (index + increment > maximum)
throw IndexOutOfBoundsException("Attempt to write past boundary!")
}
private fun Long.bitIndexToBytes() = (this ushr 3) + ((this or (this ushr 1) or (this ushr 2)) and 1)
}

View File

@ -1,154 +0,0 @@
package net.tofvesson.data
import net.tofvesson.exception.InsufficientCapacityException
import net.tofvesson.math.*
import java.nio.ByteBuffer
import kotlin.experimental.and
import kotlin.experimental.or
@Suppress("MemberVisibilityCanBePrivate", "unused")
class WriteBuffer(state: WriteState, _buffer: ByteBuffer? = null, bufferBitOffset: Int = 0) {
/*
Buffer layout:
{BufferBitOffset}[Header][Bits]{BitOffset}[Bytes]
BufferBitOffset is optional and usually set to 0
BitOffset is between 0 and 7 bits long (to realign data to the next free byte)
*/
private var headerIndex = bufferBitOffset
private var bitOffset = bufferBitOffset + state.header
private var byteIndex = state.computeBitFieldOffset(bufferBitOffset)
// Maximum size for the above values
private val maxHeaderSize = bufferBitOffset + state.header
private val maxBitOffset = bufferBitOffset + state.header + state.bits
private val maxByteOffset = state.computeRequiredBytes(0, bufferBitOffset)
val buffer: ByteBuffer
init{
buffer = _buffer ?: ByteBuffer.allocate(state.computeRequiredBytes() + varIntSize(byteIndex.toLong()))
if(buffer.capacity() + (bufferBitOffset ushr 3) + bufferBitOffset.collapseLowerByte() + varIntSize(byteIndex.toLong()) < state.computeRequiredBytes())
throw InsufficientCapacityException()
writePackedInt(byteIndex + varIntSize(byteIndex.toLong()), true)
}
private fun writeBit(bit: Boolean, head: Boolean){
if((head && headerIndex >= maxHeaderSize) || (!head && bitOffset >= maxBitOffset))
throw IndexOutOfBoundsException("Attempt to write more ${if(head)"headers" else "bits"} than available space permits!")
val index = (if(head) headerIndex else bitOffset) ushr 3
val shift = (if(head) headerIndex else bitOffset) and 7
buffer.put(index, (buffer[index] and (1 shl shift).inv().toByte()) or (bit.toNumber() shl shift).toByte())
if(head) ++headerIndex
else ++bitOffset
}
fun writeHeader(bit: Boolean): WriteBuffer {
writeBit(bit, true)
return this
}
fun writeBit(bit: Boolean): WriteBuffer {
writeBit(bit, false)
return this
}
fun writeByte(value: Byte): WriteBuffer {
doBoundaryCheck(1)
buffer.put(byteIndex, value)
++byteIndex
return this
}
fun writeShort(value: Short): WriteBuffer {
doBoundaryCheck(2)
buffer.putShort(byteIndex, value)
byteIndex += 2
return this
}
fun writeInt(value: Int): WriteBuffer {
doBoundaryCheck(4)
buffer.putInt(byteIndex, value)
byteIndex += 4
return this
}
fun writeLong(value: Long): WriteBuffer {
doBoundaryCheck(8)
buffer.putLong(byteIndex, value)
byteIndex += 8
return this
}
fun writeFloat(value: Float): WriteBuffer {
doBoundaryCheck(4)
buffer.putFloat(byteIndex, value)
byteIndex += 4
return this
}
fun writeDouble(value: Double): WriteBuffer {
doBoundaryCheck(8)
buffer.putDouble(byteIndex, value)
byteIndex += 8
return this
}
fun writePackedShort(value: Short, noZigZag: Boolean = false) = writePackedLong(value.toLong(), noZigZag)
fun writePackedInt(value: Int, noZigZag: Boolean = false) = writePackedLong(value.toLong(), noZigZag)
fun writePackedLong(value: Long, noZigZag: Boolean = false): WriteBuffer {
val toWrite = if(noZigZag) value else zigZagEncode(value)
val size = varIntSize(toWrite)
doBoundaryCheck(size)
when(toWrite) {
in 0..240 -> buffer.put(byteIndex, toWrite.toByte())
in 241..2287 -> {
buffer.put(byteIndex, (((toWrite - 240) shr 8) + 241).toByte())
buffer.put(byteIndex + 1, (toWrite - 240).toByte())
}
in 2288..67823 -> {
buffer.put(byteIndex, 249.toByte())
buffer.put(byteIndex + 1, ((toWrite - 2288) shr 8).toByte())
buffer.put(byteIndex + 2, (toWrite - 2288).toByte())
}
else -> {
var header = 255
var match = 0x00FF_FFFF_FFFF_FFFFL
while (toWrite in 67824..match) {
--header
match = match shr 8
}
buffer.put(byteIndex, header.toByte())
val max = header - 247
for (i in 0 until max)
buffer.put(byteIndex + 1 + i, (toWrite shr (i shl 3)).toByte())
}
}
byteIndex += size
return this
}
fun writePackedFloat(value: Float, noSwapEndian: Boolean = false): WriteBuffer {
val write =
if(noSwapEndian) bitConvert(floatToInt(value))
else bitConvert(swapEndian(floatToInt(value)))
return writePackedLong(write, true)
}
fun writePackedDouble(value: Double, noSwapEndian: Boolean = false): WriteBuffer {
val write =
if(noSwapEndian) doubleToLong(value)
else swapEndian(doubleToLong(value))
return writePackedLong(write, true)
}
private fun doBoundaryCheck(byteCount: Int) {
if(byteIndex + byteCount > maxByteOffset)
throw IndexOutOfBoundsException("Attempt to write value past maximum range!")
}
}

View File

@ -7,16 +7,13 @@ data class WriteState(private var _bytes: Int, private var _bits: Int, private v
private set private set
var bits: Int = _bits var bits: Int = _bits
private set private set
var header: Int = _header
private set
fun registerBytes(bytes: Int): WriteState { this.bytes += bytes; return this } fun registerBytes(bytes: Int): WriteState { this.bytes += bytes; return this }
fun registerBits(bits: Int) : WriteState { this.bits += bits; return this } fun registerBits(bits: Int) : WriteState { this.bits += bits; return this }
fun registerHeader(header: Int): WriteState { this.header += header; return this }
fun computeRequiredBytes(additionalBytes: Int = 0, additionalBits: Int = 0) = fun computeRequiredBytes(additionalBytes: Int = 0, additionalBits: Int = 0) =
bytes + additionalBytes + computeBitFieldOffset(additionalBits) bytes + additionalBytes + computeBitFieldOffset(additionalBits)
fun computeBitFieldOffset(additionalBits: Int = 0) = roundUpBitsToBytes(bits + header + additionalBits) fun computeBitFieldOffset(additionalBits: Int = 0) = roundUpBitsToBytes(bits + additionalBits)
private fun roundUpBitsToBytes(bits: Int) = (bits ushr 3) + bits.collapseLowerByte() private fun roundUpBitsToBytes(bits: Int) = (bits ushr 3) + bits.collapseLowerByte()
} }

View File

@ -6,6 +6,7 @@ import kotlin.math.roundToInt
fun varIntSize(value: Long): Int = fun varIntSize(value: Long): Int =
when { when {
value < 0 -> 9
value <= 240 -> 1 value <= 240 -> 1
value <= 2287 -> 2 value <= 2287 -> 2
value <= 67823 -> 3 value <= 67823 -> 3
@ -64,19 +65,19 @@ fun writeVarInt(buffer: ByteBuffer, offset: Int, value: Long){
} }
buffer.put(offset, header.toByte()) buffer.put(offset, header.toByte())
val max = header - 247 val max = header - 247
for (i in 0..(max-1)) buffer.put(offset+i+1, (value shr (i shl 3)).toByte()) for (i in 0..(max-1)) buffer.put(offset+i+1, (value ushr (i shl 3)).toByte())
} }
} }
} }
fun writeInt(buffer: ByteArray, offset: Int, value: Long, bytes: Int){ fun writeInt(buffer: ByteArray, offset: Int, value: Long, bytes: Int){
for(i in 0..(bytes-1)) for(i in 0..(bytes-1))
buffer[offset+i] = (value shr (8*i)).toByte() buffer[offset+i] = (value ushr (8*i)).toByte()
} }
fun writeInt(buffer: ByteBuffer, offset: Int, value: Long, bytes: Int){ fun writeInt(buffer: ByteBuffer, offset: Int, value: Long, bytes: Int){
for(i in 0..(bytes-1)) for(i in 0..(bytes-1))
buffer.put(offset+i, (value shr (8*i)).toByte()) buffer.put(offset+i, (value ushr (8*i)).toByte())
} }
fun readVarInt(buffer: ByteArray, offset: Int): Long { fun readVarInt(buffer: ByteArray, offset: Int): Long {
@ -106,13 +107,13 @@ fun readVarInt(buffer: ByteBuffer, offset: Int): Long {
} }
fun writeBit(bit: Boolean, buffer: ByteArray, index: Int){ fun writeBit(bit: Boolean, buffer: ByteArray, index: Int){
buffer[index shr 3] = buffer[index shr 3].or(((if(bit) 1 else 0) shl (index and 7)).toByte()) buffer[index ushr 3] = buffer[index ushr 3].or(((if(bit) 1 else 0) shl (index and 7)).toByte())
} }
fun readBit(buffer: ByteArray, index: Int): Boolean = buffer[index shr 3].toInt() and (1 shl (index and 7)) != 0 fun readBit(buffer: ByteArray, index: Int): Boolean = buffer[index ushr 3].toInt() and (1 shl (index and 7)) != 0
fun writeBit(bit: Boolean, buffer: ByteBuffer, index: Int){ fun writeBit(bit: Boolean, buffer: ByteBuffer, index: Int){
buffer.put(index shr 3, buffer[index shr 3] or (((if(bit) 1 else 0) shl (index and 7)).toByte())) buffer.put(index ushr 3, buffer[index ushr 3] or (((if(bit) 1 else 0) shl (index and 7)).toByte()))
} }
fun readBit(buffer: ByteBuffer, index: Int): Boolean = buffer[index shr 3].toInt() and (1 shl (index and 7)) != 0 fun readBit(buffer: ByteBuffer, index: Int): Boolean = buffer[index ushr 3].toInt() and (1 shl (index and 7)) != 0
private val converter = ByteBuffer.allocateDirect(8) private val converter = ByteBuffer.allocateDirect(8)
@ -140,17 +141,17 @@ fun longToDouble(value: Long): Double =
return@synchronized converter.getDouble(0) return@synchronized converter.getDouble(0)
} }
fun swapEndian(value: Short) = ((value.toInt() shl 8) or ((value.toInt() shr 8) and 255)).toShort() fun swapEndian(value: Short) = ((value.toInt() shl 8) or ((value.toInt() ushr 8) and 255)).toShort()
fun swapEndian(value: Int) = fun swapEndian(value: Int) =
((value shr 24) and 0xFF) or ((value ushr 24) and 0xFF) or
((value shr 8) and 0xFF00) or ((value ushr 8) and 0xFF00) or
((value shl 24) and -16777216) or ((value shl 24) and -16777216) or
((value shl 8) and 0xFF0000) ((value shl 8) and 0xFF0000)
fun swapEndian(value: Long) = fun swapEndian(value: Long) =
((value shr 56) and 0xFFL) or ((value shr 56) and 0xFFL) or
((value shr 40) and 0xFF00L) or ((value ushr 40) and 0xFF00L) or
((value shr 24) and 0xFF0000L) or ((value ushr 24) and 0xFF0000L) or
((value shr 8) and 0xFF000000L) or ((value ushr 8) and 0xFF000000L) or
((value shl 56) and -72057594037927936L) or ((value shl 56) and -72057594037927936L) or
((value shl 40) and 0xFF000000000000L) or ((value shl 40) and 0xFF000000000000L) or
((value shl 24) and 0xFF0000000000L) or ((value shl 24) and 0xFF0000000000L) or
@ -159,7 +160,7 @@ fun swapEndian(value: Long) =
fun bitConvert(value: Int): Long = value.toLong() and 0xFFFFFFFFL fun bitConvert(value: Int): Long = value.toLong() and 0xFFFFFFFFL
fun zigZagEncode(value: Long): Long = (value shl 1) xor (value shr 63) fun zigZagEncode(value: Long): Long = (value shl 1) xor (value shr 63)
fun zigZagDecode(value: Long): Long = (value shr 1) xor ((value shl 63) shr 63) fun zigZagDecode(value: Long): Long = (value ushr 1) xor ((value shl 63) shr 63)
fun Float.encodeRotation(byteCount: Int): Int { fun Float.encodeRotation(byteCount: Int): Int {
if(this < 0 || this > 360) throw RotationOutOfBoundsException() if(this < 0 || this > 360) throw RotationOutOfBoundsException()

View File

@ -1,7 +1,7 @@
package net.tofvesson.math package net.tofvesson.math
fun Boolean.toNumber() = if(this) 1 else 0 fun Boolean.toNumber() = if(this) 1 else 0
fun Number.toBoolean() = this!=0 fun Number.toBoolean() = this != 0
fun Int.collapseLowerByte(): Int = fun Int.collapseLowerByte(): Int =
((this ushr 7) or ((this ushr 7) or
@ -10,4 +10,5 @@ fun Int.collapseLowerByte(): Int =
(this ushr 4) or (this ushr 4) or
(this ushr 3) or (this ushr 3) or
(this ushr 2) or (this ushr 2) or
(this ushr 1)) and 1 (this ushr 1) or
this) and 1

View File

@ -1,64 +0,0 @@
package net.tofvesson.networking
import net.tofvesson.reflect.access
import java.net.DatagramPacket
import java.net.DatagramSocket
import java.net.InetAddress
import java.util.concurrent.atomic.AtomicBoolean
class ReliableUDP(address: InetAddress, port: Short, private val onAccept: (ByteArray, Int, Int) -> Unit, private val automaticAccept: Boolean, acceptTimeout: Long = 10L) {
private enum class PacketType(val bits: Int = (javaClass.getDeclaredField("\$VALUES").access().get(null) as Array<*>).indexOf(this)) {
DATA, ACK, FIN;
companion object {
val fieldSize = (Math.log((javaClass.getDeclaredField("\$VALUES").access().get(null) as Array<*>).size.toDouble()) / Math.log(2.0)).toInt() + 1
}
}
private var socket = DatagramSocket()
private val sync: Thread? = if(automaticAccept) Thread { acceptLoop() } else null
private val stop = AtomicBoolean(false)
private var finInitiated = false
private val packet = DatagramPacket(ByteArray(socket.receiveBufferSize), socket.receiveBufferSize)
init {
socket.connect(address, port.toInt())
socket.soTimeout = 0
sync?.start()
}
private fun acceptLoop(){
while(synchronized(stop){!stop.get()}){
accept()
if(packet.length==0) continue // Drop empty packets
val packetType = PacketType.values()[packet.data[0].toInt()]
when(packetType){
PacketType.DATA -> {
}
PacketType.ACK -> {
}
PacketType.FIN -> {
}
}
}
}
fun accept(){
if(automaticAccept && Thread.currentThread() != sync)
throw IllegalThreadStateException("Current thread isn't setup to accept datagram packets")
socket.receive(packet)
}
fun send(){
if(finInitiated) throw IllegalStateException("Cannot send message after connection is closed!")
}
fun _send(){
}
}

View File

@ -19,6 +19,6 @@ fun <T> T.access(): T where T: AccessibleObject {
fun getUnsafe(): Unsafe{ fun getUnsafe(): Unsafe{
val theUnsafe = Unsafe::class.java.getDeclaredField("theUnsafe") val theUnsafe = Unsafe::class.java.getDeclaredField("theUnsafe")
theUnsafe.trySetAccessible() theUnsafe.isAccessible = true
return theUnsafe.get(null) as Unsafe return theUnsafe.get(null) as Unsafe
} }

View File

@ -3,8 +3,19 @@ package net.tofvesson.reflect
import java.lang.reflect.Field import java.lang.reflect.Field
fun Field.setStaticFinalValue(value: Any?){ fun Field.setStaticFinalValue(value: Any?){
val factory = Class.forName("jdk.internal.reflect.UnsafeFieldAccessorFactory").getDeclaredMethod("newFieldAccessor", Field::class.java, Boolean::class.java) var pkg = "jdk.internal.relfect"
val isReadonly = Class.forName("jdk.internal.reflect.UnsafeQualifiedStaticFieldAccessorImpl").getDeclaredField("isReadOnly") try
{
Class.forName("$pkg.UnsafeFieldAccessorFactory")
}
catch(e: ClassNotFoundException)
{
pkg = "sun.reflect"
}
val factory = Class.forName("$pkg.UnsafeFieldAccessorFactory").getDeclaredMethod("newFieldAccessor", Field::class.java, Boolean::class.java)
val isReadonly = Class.forName("$pkg.UnsafeQualifiedStaticFieldAccessorImpl").getDeclaredField("isReadOnly")
isReadonly.forceAccessible = true isReadonly.forceAccessible = true
factory.forceAccessible = true factory.forceAccessible = true
val overrideAccessor = Field::class.java.getDeclaredField("overrideFieldAccessor") val overrideAccessor = Field::class.java.getDeclaredField("overrideFieldAccessor")

View File

@ -2,6 +2,7 @@ package net.tofvesson.serializers
import net.tofvesson.annotation.SyncFlag import net.tofvesson.annotation.SyncFlag
import net.tofvesson.data.* import net.tofvesson.data.*
import net.tofvesson.reflect.access
import java.lang.reflect.Field import java.lang.reflect.Field
class DiffTrackedSerializer private constructor(): Serializer(arrayOf( class DiffTrackedSerializer private constructor(): Serializer(arrayOf(
@ -11,23 +12,39 @@ class DiffTrackedSerializer private constructor(): Serializer(arrayOf(
companion object { companion object {
private val trackedField = DiffTracked::class.java.getDeclaredField("_value") private val trackedField = DiffTracked::class.java.getDeclaredField("_value")
val singleton = DiffTrackedSerializer() val singleton = DiffTrackedSerializer()
/**
* Checks if a given object/class needs to ve serialized by checking if any DiffTracked/DiffTrackedArray
* instances in the given object/class are dirty
*/
fun objectNeedsSerialization(obj: Any?) =
obj == null ||
((obj as? Class<*> ?: obj.javaClass).fields.firstOrNull {
if (it.type is DiffTracked<*> || it.type is DiffTrackedArray<*>){
it.access()
val diff = it.get(if(obj is Class<*>) null else obj)
return@firstOrNull diff.javaClass.getDeclaredMethod("hasChanged").invoke(diff) as Boolean
}
return@firstOrNull false
} != null)
} }
override fun computeSizeExplicit(field: Field, flags: Array<out SyncFlag>, owner: Any?, state: WriteState, fieldType: Class<*>) { override fun computeSizeExplicit(field: Field, flags: Array<out SyncFlag>, owner: Any?, state: WriteState, fieldType: Class<*>) {
when (fieldType) { when (fieldType) {
DiffTracked::class.java -> { DiffTracked::class.java -> {
val tracker = field.get(owner) as DiffTracked<*> val tracker = field.get(owner) as DiffTracked<*>
val serializer = SyncHandler.getCompatibleSerializer(tracker.valueType) val serializer = SyncHandler.getCompatibleSerializer(tracker.valueType) ?: return
state.registerHeader(1) state.registerBits(1)
if (tracker.hasChanged()) if (tracker.hasChanged())
serializer.computeSizeExplicit(trackedField, flags, tracker, state, tracker.valueType) serializer.computeSizeExplicit(trackedField, flags, tracker, state, tracker.valueType)
} }
DiffTrackedArray::class.java -> { DiffTrackedArray::class.java -> {
val tracker = field.get(owner) as DiffTrackedArray<*> val tracker = field.get(owner) as DiffTrackedArray<*>
val serializer = SyncHandler.getCompatibleSerializer(tracker.elementType) val serializer = SyncHandler.getCompatibleSerializer(tracker.elementType) ?: return
state.registerHeader(1) state.registerBits(1)
if (tracker.hasChanged()) { if (tracker.hasChanged()) {
val holder = Holder(null) val holder = Holder(null)
state.registerHeader(tracker.size) state.registerBits(tracker.size)
for (index in tracker.changeMap.indices) for (index in tracker.changeMap.indices)
if (tracker.changeMap[index]) { if (tracker.changeMap[index]) {
holder.value = tracker[index] holder.value = tracker[index]
@ -39,12 +56,12 @@ class DiffTrackedSerializer private constructor(): Serializer(arrayOf(
} }
} }
override fun serializeExplicit(field: Field, flags: Array<out SyncFlag>, owner: Any?, writeBuffer: WriteBuffer, fieldType: Class<*>) { override fun serializeExplicit(field: Field, flags: Array<out SyncFlag>, owner: Any?, writeBuffer: WBuffer, fieldType: Class<*>) {
when (fieldType) { when (fieldType) {
DiffTracked::class.java -> { DiffTracked::class.java -> {
val tracker = field.get(owner) as DiffTracked<*> val tracker = field.get(owner) as DiffTracked<*>
val serializer = SyncHandler.getCompatibleSerializer(tracker.valueType) val serializer = SyncHandler.getCompatibleSerializer(tracker.valueType) ?: return
writeBuffer.writeHeader(tracker.hasChanged()) writeBuffer.writeBit(tracker.hasChanged())
if (tracker.hasChanged()) { if (tracker.hasChanged()) {
serializer.serializeExplicit(trackedField, flags, tracker, writeBuffer, tracker.valueType) serializer.serializeExplicit(trackedField, flags, tracker, writeBuffer, tracker.valueType)
tracker.clearChangeState() tracker.clearChangeState()
@ -52,13 +69,13 @@ class DiffTrackedSerializer private constructor(): Serializer(arrayOf(
} }
DiffTrackedArray::class.java -> { DiffTrackedArray::class.java -> {
val tracker = field.get(owner) as DiffTrackedArray<*> val tracker = field.get(owner) as DiffTrackedArray<*>
val serializer = SyncHandler.getCompatibleSerializer(tracker.elementType) val serializer = SyncHandler.getCompatibleSerializer(tracker.elementType) ?: return
writeBuffer.writeHeader(tracker.hasChanged()) writeBuffer.writeBit(tracker.hasChanged())
if (tracker.hasChanged()) { if (tracker.hasChanged()) {
val holder = Holder(null) val holder = Holder(null)
for (index in tracker.changeMap.indices) { for (index in tracker.changeMap.indices) {
writeBuffer.writeHeader(tracker.changeMap[index]) writeBuffer.writeBit(tracker.changeMap[index])
if (tracker.changeMap[index]) { if (tracker.changeMap[index]) {
holder.value = tracker[index] holder.value = tracker[index]
serializer.serializeExplicit(Holder.valueField, flags, holder, writeBuffer, tracker.elementType) serializer.serializeExplicit(Holder.valueField, flags, holder, writeBuffer, tracker.elementType)
@ -71,26 +88,26 @@ class DiffTrackedSerializer private constructor(): Serializer(arrayOf(
} }
} }
override fun deserializeExplicit(field: Field, flags: Array<out SyncFlag>, owner: Any?, readBuffer: ReadBuffer, fieldType: Class<*>) { override fun deserializeExplicit(field: Field, flags: Array<out SyncFlag>, owner: Any?, readBuffer: RBuffer, fieldType: Class<*>) {
when (fieldType) { when (fieldType) {
DiffTracked::class.java -> { DiffTracked::class.java -> {
val tracker = field.get(owner) as DiffTracked<*> val tracker = field.get(owner) as DiffTracked<*>
val serializer = SyncHandler.getCompatibleSerializer(tracker.valueType) val serializer = SyncHandler.getCompatibleSerializer(tracker.valueType) ?: return
if (readBuffer.readHeader()) if (readBuffer.readBit())
serializer.deserializeExplicit(trackedField, flags, tracker, readBuffer, tracker.valueType) serializer.deserializeExplicit(trackedField, flags, tracker, readBuffer, tracker.valueType)
tracker.clearChangeState() tracker.clearChangeState()
} }
DiffTrackedArray::class.java -> { DiffTrackedArray::class.java -> {
val tracker = field.get(owner) as DiffTrackedArray<*> val tracker = field.get(owner) as DiffTrackedArray<*>
val serializer = SyncHandler.getCompatibleSerializer(tracker.elementType) val serializer = SyncHandler.getCompatibleSerializer(tracker.elementType) ?: return
if(readBuffer.readHeader()) { if(readBuffer.readBit()) {
val holder = Holder(null) val holder = Holder(null)
val array = tracker.values as Array<Any?> val array = tracker.values as Array<Any?>
for (index in tracker.changeMap.indices) { for (index in tracker.changeMap.indices) {
if (readBuffer.readHeader()) { if (readBuffer.readBit()) {
serializer.deserializeExplicit(Holder.valueField, flags, holder, readBuffer, tracker.elementType) serializer.deserializeExplicit(Holder.valueField, flags, holder, readBuffer, tracker.elementType)
array[index] = holder.value array[index] = holder.value
} }
@ -101,4 +118,25 @@ class DiffTrackedSerializer private constructor(): Serializer(arrayOf(
else -> throwInvalidType(fieldType) else -> throwInvalidType(fieldType)
} }
} }
override fun canSerialize(obj: Any?, flags: Array<out SyncFlag>, type: Class<*>): Boolean {
if (obj == null)
return false
if (DiffTracked::class.java.isAssignableFrom(type)){
obj as DiffTracked<*>
val handler = SyncHandler.getCompatibleSerializer(obj.valueType) ?: return false
return handler.canSerialize(obj.value, flags, obj.valueType)
}else if (DiffTrackedArray::class.java.isAssignableFrom(type)){
obj as DiffTrackedArray<*>
val handler = SyncHandler.getCompatibleSerializer(obj.elementType) ?: return false
return handler.canSerialize(obj.values, flags, obj.elementType)
}
return false
}
} }

View File

@ -32,6 +32,8 @@ class MathSerializer: Serializer(arrayOf(
override fun computeSizeExplicit(field: Field, flags: Array<out SyncFlag>, owner: Any?, state: WriteState, fieldType: Class<*>) { override fun computeSizeExplicit(field: Field, flags: Array<out SyncFlag>, owner: Any?, state: WriteState, fieldType: Class<*>) {
when (fieldType) { when (fieldType) {
Vector3::class.java -> { Vector3::class.java -> {
val floatSerializer = SyncHandler.getCompatibleSerializer(Float::class.java) ?: return
val vector = field.access().get(owner) as Vector3 val vector = field.access().get(owner) as Vector3
val xDiff = xField.get(vector) as DiffTracked<Float> val xDiff = xField.get(vector) as DiffTracked<Float>
val yDiff = yField.get(vector) as DiffTracked<Float> val yDiff = yField.get(vector) as DiffTracked<Float>
@ -41,7 +43,7 @@ class MathSerializer: Serializer(arrayOf(
val c3 = flags.contains(compressedRotationVector3) val c3 = flags.contains(compressedRotationVector3)
if ((c1 and c2) or (c2 and c3) or (c1 and c3)) throw MismatchedFlagException("Cannot have more than one rotation compression flag!") if ((c1 and c2) or (c2 and c3) or (c1 and c3)) throw MismatchedFlagException("Cannot have more than one rotation compression flag!")
state.registerHeader(3) state.registerBits(3)
when { when {
c1 || c2 || c3 -> { c1 || c2 || c3 -> {
val bytes = val bytes =
@ -56,7 +58,6 @@ class MathSerializer: Serializer(arrayOf(
.registerBytes(if (zDiff.hasChanged()) varIntSize(zDiff.value.encodeRotation(bytes).toLong()) else 0) .registerBytes(if (zDiff.hasChanged()) varIntSize(zDiff.value.encodeRotation(bytes).toLong()) else 0)
} }
else -> { else -> {
val floatSerializer = SyncHandler.getCompatibleSerializer(Float::class.java)
if (xDiff.hasChanged()) floatSerializer.computeSizeExplicit(diffValue, flags, xDiff, state, Float::class.java) if (xDiff.hasChanged()) floatSerializer.computeSizeExplicit(diffValue, flags, xDiff, state, Float::class.java)
if (yDiff.hasChanged()) floatSerializer.computeSizeExplicit(diffValue, flags, yDiff, state, Float::class.java) if (yDiff.hasChanged()) floatSerializer.computeSizeExplicit(diffValue, flags, yDiff, state, Float::class.java)
if (zDiff.hasChanged()) floatSerializer.computeSizeExplicit(diffValue, flags, zDiff, state, Float::class.java) if (zDiff.hasChanged()) floatSerializer.computeSizeExplicit(diffValue, flags, zDiff, state, Float::class.java)
@ -67,9 +68,12 @@ class MathSerializer: Serializer(arrayOf(
} }
} }
override fun serializeExplicit(field: Field, _flags: Array<out SyncFlag>, owner: Any?, writeBuffer: WriteBuffer, fieldType: Class<*>) { override fun serializeExplicit(field: Field, _flags: Array<out SyncFlag>, owner: Any?, writeBuffer: WBuffer, fieldType: Class<*>) {
when (fieldType) { when (fieldType) {
Vector3::class.java -> { Vector3::class.java -> {
val intSerializer = SyncHandler.getCompatibleSerializer(Int::class.java) ?: return
val floatSerializer = SyncHandler.getCompatibleSerializer(Float::class.java) ?: return
var flags = _flags var flags = _flags
val vector = field.access().get(owner) as Vector3 val vector = field.access().get(owner) as Vector3
val c1 = flags.contains(compressedRotationVector1) val c1 = flags.contains(compressedRotationVector1)
@ -81,13 +85,12 @@ class MathSerializer: Serializer(arrayOf(
if ((c1 and c2) or (c2 and c3) or (c1 and c3)) throw MismatchedFlagException("Cannot have more than one rotation compression flag!") if ((c1 and c2) or (c2 and c3) or (c1 and c3)) throw MismatchedFlagException("Cannot have more than one rotation compression flag!")
writeBuffer.writeHeader(xDiff.hasChanged()) writeBuffer.writeBit(xDiff.hasChanged())
writeBuffer.writeHeader(yDiff.hasChanged()) writeBuffer.writeBit(yDiff.hasChanged())
writeBuffer.writeHeader(zDiff.hasChanged()) writeBuffer.writeBit(zDiff.hasChanged())
when { when {
c1 || c2 || c3 -> { c1 || c2 || c3 -> {
val intSerializer = SyncHandler.getCompatibleSerializer(Int::class.java)
val bytes = val bytes =
when { when {
c1 -> 1 c1 -> 1
@ -123,7 +126,6 @@ class MathSerializer: Serializer(arrayOf(
if (zDiff.hasChanged()) intSerializer.serializeExplicit(Holder.valueField, flags, zHolder, writeBuffer, Int::class.java) if (zDiff.hasChanged()) intSerializer.serializeExplicit(Holder.valueField, flags, zHolder, writeBuffer, Int::class.java)
} }
else -> { else -> {
val floatSerializer = SyncHandler.getCompatibleSerializer(Float::class.java)
if (xDiff.hasChanged()) floatSerializer.serializeExplicit(diffValue, _flags, xDiff, writeBuffer, Float::class.java) if (xDiff.hasChanged()) floatSerializer.serializeExplicit(diffValue, _flags, xDiff, writeBuffer, Float::class.java)
if (yDiff.hasChanged()) floatSerializer.serializeExplicit(diffValue, _flags, yDiff, writeBuffer, Float::class.java) if (yDiff.hasChanged()) floatSerializer.serializeExplicit(diffValue, _flags, yDiff, writeBuffer, Float::class.java)
@ -135,9 +137,12 @@ class MathSerializer: Serializer(arrayOf(
} }
} }
override fun deserializeExplicit(field: Field, flags: Array<out SyncFlag>, owner: Any?, readBuffer: ReadBuffer, fieldType: Class<*>) { override fun deserializeExplicit(field: Field, flags: Array<out SyncFlag>, owner: Any?, readBuffer: RBuffer, fieldType: Class<*>) {
when (fieldType) { when (fieldType) {
Vector3::class.java -> { Vector3::class.java -> {
val floatSerializer = SyncHandler.getCompatibleSerializer(Float::class.java) ?: return
val intSerializer = SyncHandler.getCompatibleSerializer(Int::class.java) ?: return
val vector = field.access().get(owner) as Vector3 val vector = field.access().get(owner) as Vector3
val c1 = flags.contains(compressedRotationVector1) val c1 = flags.contains(compressedRotationVector1)
val c2 = flags.contains(compressedRotationVector2) val c2 = flags.contains(compressedRotationVector2)
@ -153,37 +158,35 @@ class MathSerializer: Serializer(arrayOf(
when { when {
c1 || c2 || c3 -> { c1 || c2 || c3 -> {
val intSerializer = SyncHandler.getCompatibleSerializer(Int::class.java)
val bytes = if (c1) 1 else if (c2) 2 else 3 val bytes = if (c1) 1 else if (c2) 2 else 3
if (readBuffer.readHeader()) { if (readBuffer.readBit()) {
intSerializer.deserializeExplicit(Holder.valueField, flags, xHolder, readBuffer, Int::class.java) intSerializer.deserializeExplicit(Holder.valueField, flags, xHolder, readBuffer, Int::class.java)
xDiff.value = (xHolder.value as Int).decodeRotation(bytes) xDiff.value = (xHolder.value as Int).decodeRotation(bytes)
xDiff.clearChangeState() xDiff.clearChangeState()
} }
if (readBuffer.readHeader()) { if (readBuffer.readBit()) {
intSerializer.deserializeExplicit(Holder.valueField, flags, yHolder, readBuffer, Int::class.java) intSerializer.deserializeExplicit(Holder.valueField, flags, yHolder, readBuffer, Int::class.java)
yDiff.value = (yHolder.value as Int).decodeRotation(bytes) yDiff.value = (yHolder.value as Int).decodeRotation(bytes)
yDiff.clearChangeState() yDiff.clearChangeState()
} }
if (readBuffer.readHeader()) { if (readBuffer.readBit()) {
intSerializer.deserializeExplicit(Holder.valueField, flags, zHolder, readBuffer, Int::class.java) intSerializer.deserializeExplicit(Holder.valueField, flags, zHolder, readBuffer, Int::class.java)
zDiff.value = (zHolder.value as Int).decodeRotation(bytes) zDiff.value = (zHolder.value as Int).decodeRotation(bytes)
zDiff.clearChangeState() zDiff.clearChangeState()
} }
} }
else -> { else -> {
val floatSerializer = SyncHandler.getCompatibleSerializer(Float::class.java)
if (readBuffer.readHeader()){ if (readBuffer.readBit()){
floatSerializer.deserializeExplicit(diffValue, flags, xField.get(vector), readBuffer, Float::class.java) floatSerializer.deserializeExplicit(diffValue, flags, xField.get(vector), readBuffer, Float::class.java)
xDiff.clearChangeState() xDiff.clearChangeState()
} }
if (readBuffer.readHeader()){ if (readBuffer.readBit()){
floatSerializer.deserializeExplicit(diffValue, flags, yField.get(vector), readBuffer, Float::class.java) floatSerializer.deserializeExplicit(diffValue, flags, yField.get(vector), readBuffer, Float::class.java)
yDiff.clearChangeState() yDiff.clearChangeState()
} }
if (readBuffer.readHeader()){ if (readBuffer.readBit()){
floatSerializer.deserializeExplicit(diffValue, flags, zField.get(vector), readBuffer, Float::class.java) floatSerializer.deserializeExplicit(diffValue, flags, zField.get(vector), readBuffer, Float::class.java)
zDiff.clearChangeState() zDiff.clearChangeState()
} }
@ -193,4 +196,10 @@ class MathSerializer: Serializer(arrayOf(
else -> throwInvalidType(fieldType) else -> throwInvalidType(fieldType)
} }
} }
override fun canSerialize(obj: Any?, flags: Array<out SyncFlag>, type: Class<*>): Boolean {
SyncHandler.getCompatibleSerializer(Float::class.java) ?: return false
SyncHandler.getCompatibleSerializer(Int::class.java) ?: return false
return Vector3::class.java.isAssignableFrom(type)
}
} }

View File

@ -2,6 +2,7 @@ package net.tofvesson.serializers
import net.tofvesson.annotation.SyncFlag import net.tofvesson.annotation.SyncFlag
import net.tofvesson.data.* import net.tofvesson.data.*
import net.tofvesson.math.varIntSize
import java.lang.reflect.Field import java.lang.reflect.Field
@Suppress("MemberVisibilityCanBePrivate") @Suppress("MemberVisibilityCanBePrivate")
@ -23,13 +24,14 @@ class PrimitiveArraySerializer private constructor(): Serializer(arrayOf(
override fun computeSizeExplicit(field: Field, flags: Array<out SyncFlag>, owner: Any?, state: WriteState, fieldType: Class<*>) { override fun computeSizeExplicit(field: Field, flags: Array<out SyncFlag>, owner: Any?, state: WriteState, fieldType: Class<*>) {
val arrayLength = java.lang.reflect.Array.getLength(field.get(owner)) val arrayLength = java.lang.reflect.Array.getLength(field.get(owner))
val holder = Holder(null) val holder = Holder(null)
when (fieldType) { when (fieldType) {
BooleanArray::class.java -> state.registerBits(arrayLength) BooleanArray::class.java -> state.registerBits(arrayLength)
ByteArray::class.java -> state.registerBytes(arrayLength) ByteArray::class.java -> state.registerBytes(arrayLength)
ShortArray::class.java -> ShortArray::class.java ->
if(flags.contains(SyncFlag.NoCompress)) state.registerBytes(arrayLength * 2) if(flags.contains(SyncFlag.NoCompress)) state.registerBytes(arrayLength * 2)
else { else {
val shortSerializer = SyncHandler.getCompatibleSerializer(Short::class.java) val shortSerializer = SyncHandler.getCompatibleSerializer(Short::class.java) ?: return
for (value in field.get(owner) as ShortArray) { for (value in field.get(owner) as ShortArray) {
holder.value = value holder.value = value
shortSerializer.computeSizeExplicit(Holder.valueField, flags, holder, state, Short::class.java) shortSerializer.computeSizeExplicit(Holder.valueField, flags, holder, state, Short::class.java)
@ -38,7 +40,7 @@ class PrimitiveArraySerializer private constructor(): Serializer(arrayOf(
IntArray::class.java -> IntArray::class.java ->
if(flags.contains(SyncFlag.NoCompress)) state.registerBytes(arrayLength * 4) if(flags.contains(SyncFlag.NoCompress)) state.registerBytes(arrayLength * 4)
else { else {
val intSerializer = SyncHandler.getCompatibleSerializer(Int::class.java) val intSerializer = SyncHandler.getCompatibleSerializer(Int::class.java) ?: return
for (value in field.get(owner) as IntArray) { for (value in field.get(owner) as IntArray) {
holder.value = value holder.value = value
intSerializer.computeSizeExplicit(Holder.valueField, flags, holder, state, Int::class.java) intSerializer.computeSizeExplicit(Holder.valueField, flags, holder, state, Int::class.java)
@ -47,7 +49,7 @@ class PrimitiveArraySerializer private constructor(): Serializer(arrayOf(
LongArray::class.java -> LongArray::class.java ->
if(flags.contains(SyncFlag.NoCompress)) state.registerBytes(arrayLength * 8) if(flags.contains(SyncFlag.NoCompress)) state.registerBytes(arrayLength * 8)
else { else {
val longSerializer = SyncHandler.getCompatibleSerializer(Long::class.java) val longSerializer = SyncHandler.getCompatibleSerializer(Long::class.java) ?: return
for (value in field.get(owner) as LongArray) { for (value in field.get(owner) as LongArray) {
holder.value = value holder.value = value
longSerializer.computeSizeExplicit(Holder.valueField, flags, holder, state, Long::class.java) longSerializer.computeSizeExplicit(Holder.valueField, flags, holder, state, Long::class.java)
@ -56,7 +58,7 @@ class PrimitiveArraySerializer private constructor(): Serializer(arrayOf(
FloatArray::class.java -> FloatArray::class.java ->
if(flags.contains(SyncFlag.NoCompress)) state.registerBytes(arrayLength * 4) if(flags.contains(SyncFlag.NoCompress)) state.registerBytes(arrayLength * 4)
else { else {
val floatSerializer = SyncHandler.getCompatibleSerializer(Float::class.java) val floatSerializer = SyncHandler.getCompatibleSerializer(Float::class.java) ?: return
for (value in field.get(owner) as FloatArray) { for (value in field.get(owner) as FloatArray) {
holder.value = value holder.value = value
floatSerializer.computeSizeExplicit(Holder.valueField, flags, holder, state, Float::class.java) floatSerializer.computeSizeExplicit(Holder.valueField, flags, holder, state, Float::class.java)
@ -65,7 +67,7 @@ class PrimitiveArraySerializer private constructor(): Serializer(arrayOf(
DoubleArray::class.java -> DoubleArray::class.java ->
if(flags.contains(SyncFlag.NoCompress)) state.registerBytes(arrayLength * 8) if(flags.contains(SyncFlag.NoCompress)) state.registerBytes(arrayLength * 8)
else { else {
val doubleSerializer = SyncHandler.getCompatibleSerializer(Double::class.java) val doubleSerializer = SyncHandler.getCompatibleSerializer(Double::class.java) ?: return
for (value in field.get(owner) as DoubleArray) { for (value in field.get(owner) as DoubleArray) {
holder.value = value holder.value = value
doubleSerializer.computeSizeExplicit(Holder.valueField, flags, holder, state, Double::class.java) doubleSerializer.computeSizeExplicit(Holder.valueField, flags, holder, state, Double::class.java)
@ -73,12 +75,16 @@ class PrimitiveArraySerializer private constructor(): Serializer(arrayOf(
} }
else -> throwInvalidType(fieldType) else -> throwInvalidType(fieldType)
} }
if(!flags.contains(knownSize))
state.registerBytes(varIntSize(arrayLength.toLong()))
} }
override fun serializeExplicit(field: Field, flags: Array<out SyncFlag>, owner: Any?, writeBuffer: WriteBuffer, fieldType: Class<*>) { override fun serializeExplicit(field: Field, flags: Array<out SyncFlag>, owner: Any?, writeBuffer: WBuffer, fieldType: Class<*>) {
val arrayLength = java.lang.reflect.Array.getLength(field.get(owner)) val arrayLength = java.lang.reflect.Array.getLength(field.get(owner))
val holder = Holder(null) val holder = Holder(null)
if(!flags.contains(knownSize)) writeBuffer.writePackedInt(arrayLength, true) if(!flags.contains(knownSize))
writeBuffer.writePackedInt(arrayLength, true)
when (fieldType) { when (fieldType) {
BooleanArray::class.java -> BooleanArray::class.java ->
for(value in field.get(owner) as BooleanArray) for(value in field.get(owner) as BooleanArray)
@ -91,7 +97,7 @@ class PrimitiveArraySerializer private constructor(): Serializer(arrayOf(
for(value in field.get(owner) as ShortArray) for(value in field.get(owner) as ShortArray)
writeBuffer.writeShort(value) writeBuffer.writeShort(value)
else { else {
val shortSerializer = SyncHandler.getCompatibleSerializer(Short::class.java) val shortSerializer = SyncHandler.getCompatibleSerializer(Short::class.java) ?: return
for (value in field.get(owner) as ShortArray) { for (value in field.get(owner) as ShortArray) {
holder.value = value holder.value = value
shortSerializer.serializeExplicit(Holder.valueField, flags, holder, writeBuffer, fieldType) shortSerializer.serializeExplicit(Holder.valueField, flags, holder, writeBuffer, fieldType)
@ -102,7 +108,7 @@ class PrimitiveArraySerializer private constructor(): Serializer(arrayOf(
for(value in field.get(owner) as IntArray) for(value in field.get(owner) as IntArray)
writeBuffer.writeInt(value) writeBuffer.writeInt(value)
else { else {
val intSerializer = SyncHandler.getCompatibleSerializer(Int::class.java) val intSerializer = SyncHandler.getCompatibleSerializer(Int::class.java) ?: return
for (value in field.get(owner) as IntArray) { for (value in field.get(owner) as IntArray) {
holder.value = value holder.value = value
intSerializer.serializeExplicit(Holder.valueField, flags, holder, writeBuffer, fieldType) intSerializer.serializeExplicit(Holder.valueField, flags, holder, writeBuffer, fieldType)
@ -113,7 +119,7 @@ class PrimitiveArraySerializer private constructor(): Serializer(arrayOf(
for(value in field.get(owner) as LongArray) for(value in field.get(owner) as LongArray)
writeBuffer.writeLong(value) writeBuffer.writeLong(value)
else { else {
val longSerializer = SyncHandler.getCompatibleSerializer(Long::class.java) val longSerializer = SyncHandler.getCompatibleSerializer(Long::class.java) ?: return
for (value in field.get(owner) as LongArray) { for (value in field.get(owner) as LongArray) {
holder.value = value holder.value = value
longSerializer.serializeExplicit(Holder.valueField, flags, holder, writeBuffer, fieldType) longSerializer.serializeExplicit(Holder.valueField, flags, holder, writeBuffer, fieldType)
@ -124,7 +130,7 @@ class PrimitiveArraySerializer private constructor(): Serializer(arrayOf(
for(value in field.get(owner) as FloatArray) for(value in field.get(owner) as FloatArray)
writeBuffer.writeFloat(value) writeBuffer.writeFloat(value)
else { else {
val floatSerializer = SyncHandler.getCompatibleSerializer(Float::class.java) val floatSerializer = SyncHandler.getCompatibleSerializer(Float::class.java) ?: return
for (value in field.get(owner) as FloatArray) { for (value in field.get(owner) as FloatArray) {
holder.value = value holder.value = value
floatSerializer.serializeExplicit(Holder.valueField, flags, holder, writeBuffer, fieldType) floatSerializer.serializeExplicit(Holder.valueField, flags, holder, writeBuffer, fieldType)
@ -135,7 +141,7 @@ class PrimitiveArraySerializer private constructor(): Serializer(arrayOf(
for(value in field.get(owner) as DoubleArray) for(value in field.get(owner) as DoubleArray)
writeBuffer.writeDouble(value) writeBuffer.writeDouble(value)
else { else {
val doubleSerializer = SyncHandler.getCompatibleSerializer(Double::class.java) val doubleSerializer = SyncHandler.getCompatibleSerializer(Double::class.java) ?: return
for (value in field.get(owner) as DoubleArray) { for (value in field.get(owner) as DoubleArray) {
holder.value = value holder.value = value
doubleSerializer.serializeExplicit(Holder.valueField, flags, holder, writeBuffer, fieldType) doubleSerializer.serializeExplicit(Holder.valueField, flags, holder, writeBuffer, fieldType)
@ -145,7 +151,7 @@ class PrimitiveArraySerializer private constructor(): Serializer(arrayOf(
} }
} }
override fun deserializeExplicit(field: Field, flags: Array<out SyncFlag>, owner: Any?, readBuffer: ReadBuffer, fieldType: Class<*>) { override fun deserializeExplicit(field: Field, flags: Array<out SyncFlag>, owner: Any?, readBuffer: RBuffer, fieldType: Class<*>) {
val localLength = java.lang.reflect.Array.getLength(field.get(owner)) val localLength = java.lang.reflect.Array.getLength(field.get(owner))
val arrayLength = val arrayLength =
if(flags.contains(knownSize)) localLength if(flags.contains(knownSize)) localLength
@ -215,4 +221,7 @@ class PrimitiveArraySerializer private constructor(): Serializer(arrayOf(
} }
if(arrayLength!=localLength) field.set(owner, target) if(arrayLength!=localLength) field.set(owner, target)
} }
override fun canSerialize(obj: Any?, flags: Array<out SyncFlag>, type: Class<*>) =
getRegisteredTypes().firstOrNull { it == type } != null
} }

View File

@ -1,9 +1,9 @@
package net.tofvesson.serializers package net.tofvesson.serializers
import net.tofvesson.annotation.SyncFlag import net.tofvesson.annotation.SyncFlag
import net.tofvesson.data.ReadBuffer import net.tofvesson.data.RBuffer
import net.tofvesson.data.Serializer import net.tofvesson.data.Serializer
import net.tofvesson.data.WriteBuffer import net.tofvesson.data.WBuffer
import net.tofvesson.data.WriteState import net.tofvesson.data.WriteState
import net.tofvesson.math.* import net.tofvesson.math.*
import net.tofvesson.reflect.* import net.tofvesson.reflect.*
@ -75,7 +75,7 @@ class PrimitiveSerializer private constructor() : Serializer(arrayOf(
field: Field, field: Field,
flags: Array<out SyncFlag>, flags: Array<out SyncFlag>,
owner: Any?, owner: Any?,
writeBuffer: WriteBuffer, writeBuffer: WBuffer,
fieldType: Class<*> fieldType: Class<*>
){ ){
when (fieldType) { when (fieldType) {
@ -104,7 +104,7 @@ class PrimitiveSerializer private constructor() : Serializer(arrayOf(
field: Field, field: Field,
flags: Array<out SyncFlag>, flags: Array<out SyncFlag>,
owner: Any?, owner: Any?,
readBuffer: ReadBuffer, readBuffer: RBuffer,
fieldType: Class<*> fieldType: Class<*>
) = ) =
when(fieldType){ when(fieldType){
@ -127,4 +127,7 @@ class PrimitiveSerializer private constructor() : Serializer(arrayOf(
else field.setDoubleAdaptive(owner, readBuffer.readPackedDouble(flags.contains(SyncFlag.FloatEndianSwap))) else field.setDoubleAdaptive(owner, readBuffer.readPackedDouble(flags.contains(SyncFlag.FloatEndianSwap)))
else -> throwInvalidType(fieldType) else -> throwInvalidType(fieldType)
} }
override fun canSerialize(obj: Any?, flags: Array<out SyncFlag>, type: Class<*>) =
getRegisteredTypes().firstOrNull { it == type } != null
} }

View File

@ -2,9 +2,12 @@ import net.tofvesson.annotation.SyncedVar;
import net.tofvesson.data.DiffTracked; import net.tofvesson.data.DiffTracked;
import net.tofvesson.data.DiffTrackedArray; import net.tofvesson.data.DiffTrackedArray;
import net.tofvesson.data.SyncHandler; import net.tofvesson.data.SyncHandler;
import net.tofvesson.math.ArithmeticKt;
import net.tofvesson.serializers.MathSerializer; import net.tofvesson.serializers.MathSerializer;
import net.tofvesson.math.Vector3; import net.tofvesson.math.Vector3;
import java.nio.ByteBuffer;
public class Main { public class Main {
@SyncedVar("NonNegative") @SyncedVar("NonNegative")
public int syncTest = 5; public int syncTest = 5;
@ -28,12 +31,16 @@ public class Main {
public static DiffTracked<Integer> tracker = new DiffTracked<>(5, Integer.class); public static DiffTracked<Integer> tracker = new DiffTracked<>(5, Integer.class);
@SyncedVar @SyncedVar
public static DiffTrackedArray<Long> tracker2 = new DiffTrackedArray<>(Long.class, 8, i -> (long)i); public static DiffTrackedArray<Long> tracker2 = new DiffTrackedArray<>(Long.class, 8, i -> (long)i); //14,11
@SyncedVar({MathSerializer.flagLowCompressionRotation, MathSerializer.flagPassiveCompress}) @SyncedVar({MathSerializer.flagLowCompressionRotation, MathSerializer.flagPassiveCompress})
public static Vector3 lookDirection = new Vector3(60, 90, 80); public static Vector3 lookDirection = new Vector3(60, 90, 80);
public static void main(String[] args){ public static void main(String[] args){
ByteBuffer buf = ByteBuffer.allocate(256);
ArithmeticKt.writeVarInt(buf, 0, -260);
Main testObject = new Main(); Main testObject = new Main();
SyncHandler sync = new SyncHandler(); SyncHandler sync = new SyncHandler();