Almost completely rewrite serialization system
This commit is contained in:
parent
dda62a1a02
commit
224f85323f
@ -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" />
|
||||||
|
@ -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)
|
||||||
|
123
src/net/tofvesson/data/RBuffer.kt
Normal file
123
src/net/tofvesson/data/RBuffer.kt
Normal 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)
|
||||||
|
}
|
@ -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!")
|
|
||||||
}
|
|
||||||
}
|
|
@ -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")
|
||||||
}
|
}
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
249
src/net/tofvesson/data/WBuffer.kt
Normal file
249
src/net/tofvesson/data/WBuffer.kt
Normal 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)
|
||||||
|
}
|
@ -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!")
|
|
||||||
}
|
|
||||||
}
|
|
@ -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()
|
||||||
}
|
}
|
@ -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()
|
||||||
|
@ -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
|
@ -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(){
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
@ -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
|
||||||
}
|
}
|
@ -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")
|
||||||
|
@ -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
|
||||||
|
}
|
||||||
}
|
}
|
@ -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)
|
||||||
|
}
|
||||||
}
|
}
|
@ -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
|
||||||
}
|
}
|
@ -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
|
||||||
}
|
}
|
@ -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();
|
Loading…
x
Reference in New Issue
Block a user