Almost completely rewrite serialization system
This commit is contained in:
parent
dda62a1a02
commit
224f85323f
@ -4,6 +4,7 @@
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/test" isTestSource="true" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<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) {
|
||||
|
||||
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{
|
||||
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.exception.UnsupportedTypeException
|
||||
import net.tofvesson.reflect.access
|
||||
import java.lang.reflect.Field
|
||||
import java.util.*
|
||||
|
||||
@ -16,7 +17,9 @@ abstract class Serializer(registeredTypes: Array<Class<*>>) {
|
||||
flags: Array<out SyncFlag>,
|
||||
owner: Any?,
|
||||
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(
|
||||
field: Field,
|
||||
@ -34,14 +37,16 @@ abstract class Serializer(registeredTypes: Array<Class<*>>) {
|
||||
field: Field,
|
||||
flags: Array<out SyncFlag>,
|
||||
owner: Any?,
|
||||
writeBuffer: WriteBuffer
|
||||
) = serializeExplicit(field, flags, owner, writeBuffer, field.type)
|
||||
writeBuffer: WBuffer
|
||||
) = if (canSerialize(field.get(owner), flags, field.type))
|
||||
serializeExplicit(field.access(), flags, owner, writeBuffer, field.type)
|
||||
else Unit
|
||||
|
||||
abstract fun serializeExplicit(
|
||||
field: Field,
|
||||
flags: Array<out SyncFlag>,
|
||||
owner: Any?,
|
||||
writeBuffer: WriteBuffer,
|
||||
writeBuffer: WBuffer,
|
||||
fieldType: Class<*>
|
||||
)
|
||||
|
||||
@ -53,20 +58,25 @@ abstract class Serializer(registeredTypes: Array<Class<*>>) {
|
||||
field: Field,
|
||||
flags: Array<out SyncFlag>,
|
||||
owner: Any?,
|
||||
readBuffer: ReadBuffer
|
||||
) = deserializeExplicit(field, flags, owner, readBuffer, field.type)
|
||||
readBuffer: RBuffer
|
||||
) = if (canDeserialize(field.get(owner), flags, field.type))
|
||||
deserializeExplicit(field.access(), flags, owner, readBuffer, field.type)
|
||||
else Unit
|
||||
|
||||
abstract fun deserializeExplicit(
|
||||
field: Field,
|
||||
flags: Array<out SyncFlag>,
|
||||
owner: Any?,
|
||||
readBuffer: ReadBuffer,
|
||||
readBuffer: RBuffer,
|
||||
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 canSerialize(field: Field): Boolean = registeredTypes.contains(field.type)
|
||||
fun canSerialize(type: Class<*>): Boolean = registeredTypes.contains(type)
|
||||
fun canSerialize(field: Field) = canSerialize(field.type)
|
||||
open fun canSerialize(type: Class<*>): Boolean = registeredTypes.contains(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 getRegisteredSerializers() = serializers.toArray()
|
||||
fun getCompatibleSerializer(type: Class<*>): Serializer {
|
||||
fun getRegisteredSerializers() = serializers.toTypedArray()
|
||||
fun getCompatibleSerializer(type: Class<*>): Serializer? {
|
||||
for(serializer in serializers)
|
||||
if(serializer.canSerialize(type))
|
||||
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)
|
||||
if(entry is Class<*>) computeClassSize(entry, writeState)
|
||||
else computeObjectSize(entry, writeState)
|
||||
val writeBuffer = WriteBuffer(writeState)
|
||||
val writeBuffer = WBuffer(null, 0, writeState)
|
||||
for(entry in toSync)
|
||||
if(entry is Class<*>) readClass(entry, writeBuffer)
|
||||
else readObject(entry, writeBuffer)
|
||||
@ -91,7 +91,7 @@ class SyncHandler(private val permissiveMismatchCheck: Boolean = false) {
|
||||
for(entry in toSync)
|
||||
if(entry is Class<*>) computeClassSize(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)
|
||||
if(entry is Class<*>) writeClass(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) {
|
||||
for(field in collectSyncable(type, value == null))
|
||||
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 readClass(value: Class<*>, writeBuffer: WriteBuffer) = readType(value, null, writeBuffer)
|
||||
private fun readType(type: Class<*>, value: Any?, writeBuffer: WriteBuffer) {
|
||||
private fun readObject(value: Any, writeBuffer: WBuffer) = readType(value.javaClass, value, writeBuffer)
|
||||
private fun readClass(value: Class<*>, writeBuffer: WBuffer) = readType(value, null, writeBuffer)
|
||||
private fun readType(type: Class<*>, value: Any?, writeBuffer: WBuffer) {
|
||||
for(field in collectSyncable(type, value == null))
|
||||
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 writeClass(value: Class<*>, readBuffer: ReadBuffer) = writeType(value, null, readBuffer)
|
||||
private fun writeType(type: Class<*>, value: Any?, readBuffer: ReadBuffer) {
|
||||
private fun writeObject(value: Any, readBuffer: RBuffer) = writeType(value.javaClass, value, readBuffer)
|
||||
private fun writeClass(value: Class<*>, readBuffer: RBuffer) = writeType(value, null, readBuffer)
|
||||
private fun writeType(type: Class<*>, value: Any?, readBuffer: RBuffer) {
|
||||
for(field in collectSyncable(type, value == null))
|
||||
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
|
||||
var bits: Int = _bits
|
||||
private set
|
||||
var header: Int = _header
|
||||
private set
|
||||
|
||||
fun registerBytes(bytes: Int): WriteState { this.bytes += bytes; 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) =
|
||||
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()
|
||||
}
|
@ -6,6 +6,7 @@ import kotlin.math.roundToInt
|
||||
|
||||
fun varIntSize(value: Long): Int =
|
||||
when {
|
||||
value < 0 -> 9
|
||||
value <= 240 -> 1
|
||||
value <= 2287 -> 2
|
||||
value <= 67823 -> 3
|
||||
@ -64,19 +65,19 @@ fun writeVarInt(buffer: ByteBuffer, offset: Int, value: Long){
|
||||
}
|
||||
buffer.put(offset, header.toByte())
|
||||
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){
|
||||
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){
|
||||
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 {
|
||||
@ -106,13 +107,13 @@ fun readVarInt(buffer: ByteBuffer, offset: Int): Long {
|
||||
}
|
||||
|
||||
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){
|
||||
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)
|
||||
|
||||
@ -140,17 +141,17 @@ fun longToDouble(value: Long): Double =
|
||||
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) =
|
||||
((value shr 24) and 0xFF) or
|
||||
((value shr 8) and 0xFF00) or
|
||||
((value ushr 24) and 0xFF) or
|
||||
((value ushr 8) and 0xFF00) or
|
||||
((value shl 24) and -16777216) or
|
||||
((value shl 8) and 0xFF0000)
|
||||
fun swapEndian(value: Long) =
|
||||
((value shr 56) and 0xFFL) or
|
||||
((value shr 40) and 0xFF00L) or
|
||||
((value shr 24) and 0xFF0000L) or
|
||||
((value shr 8) and 0xFF000000L) or
|
||||
((value ushr 40) and 0xFF00L) or
|
||||
((value ushr 24) and 0xFF0000L) or
|
||||
((value ushr 8) and 0xFF000000L) or
|
||||
((value shl 56) and -72057594037927936L) or
|
||||
((value shl 40) and 0xFF000000000000L) 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 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 {
|
||||
if(this < 0 || this > 360) throw RotationOutOfBoundsException()
|
||||
|
@ -1,7 +1,7 @@
|
||||
package net.tofvesson.math
|
||||
|
||||
fun Boolean.toNumber() = if(this) 1 else 0
|
||||
fun Number.toBoolean() = this!=0
|
||||
fun Number.toBoolean() = this != 0
|
||||
|
||||
fun Int.collapseLowerByte(): Int =
|
||||
((this ushr 7) or
|
||||
@ -10,4 +10,5 @@ fun Int.collapseLowerByte(): Int =
|
||||
(this ushr 4) or
|
||||
(this ushr 3) 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{
|
||||
val theUnsafe = Unsafe::class.java.getDeclaredField("theUnsafe")
|
||||
theUnsafe.trySetAccessible()
|
||||
theUnsafe.isAccessible = true
|
||||
return theUnsafe.get(null) as Unsafe
|
||||
}
|
@ -3,8 +3,19 @@ package net.tofvesson.reflect
|
||||
import java.lang.reflect.Field
|
||||
|
||||
fun Field.setStaticFinalValue(value: Any?){
|
||||
val factory = Class.forName("jdk.internal.reflect.UnsafeFieldAccessorFactory").getDeclaredMethod("newFieldAccessor", Field::class.java, Boolean::class.java)
|
||||
val isReadonly = Class.forName("jdk.internal.reflect.UnsafeQualifiedStaticFieldAccessorImpl").getDeclaredField("isReadOnly")
|
||||
var pkg = "jdk.internal.relfect"
|
||||
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
|
||||
factory.forceAccessible = true
|
||||
val overrideAccessor = Field::class.java.getDeclaredField("overrideFieldAccessor")
|
||||
|
@ -2,6 +2,7 @@ package net.tofvesson.serializers
|
||||
|
||||
import net.tofvesson.annotation.SyncFlag
|
||||
import net.tofvesson.data.*
|
||||
import net.tofvesson.reflect.access
|
||||
import java.lang.reflect.Field
|
||||
|
||||
class DiffTrackedSerializer private constructor(): Serializer(arrayOf(
|
||||
@ -11,23 +12,39 @@ class DiffTrackedSerializer private constructor(): Serializer(arrayOf(
|
||||
companion object {
|
||||
private val trackedField = DiffTracked::class.java.getDeclaredField("_value")
|
||||
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<*>) {
|
||||
when (fieldType) {
|
||||
DiffTracked::class.java -> {
|
||||
val tracker = field.get(owner) as DiffTracked<*>
|
||||
val serializer = SyncHandler.getCompatibleSerializer(tracker.valueType)
|
||||
state.registerHeader(1)
|
||||
val serializer = SyncHandler.getCompatibleSerializer(tracker.valueType) ?: return
|
||||
state.registerBits(1)
|
||||
if (tracker.hasChanged())
|
||||
serializer.computeSizeExplicit(trackedField, flags, tracker, state, tracker.valueType)
|
||||
}
|
||||
DiffTrackedArray::class.java -> {
|
||||
val tracker = field.get(owner) as DiffTrackedArray<*>
|
||||
val serializer = SyncHandler.getCompatibleSerializer(tracker.elementType)
|
||||
state.registerHeader(1)
|
||||
val serializer = SyncHandler.getCompatibleSerializer(tracker.elementType) ?: return
|
||||
state.registerBits(1)
|
||||
if (tracker.hasChanged()) {
|
||||
val holder = Holder(null)
|
||||
state.registerHeader(tracker.size)
|
||||
state.registerBits(tracker.size)
|
||||
for (index in tracker.changeMap.indices)
|
||||
if (tracker.changeMap[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) {
|
||||
DiffTracked::class.java -> {
|
||||
val tracker = field.get(owner) as DiffTracked<*>
|
||||
val serializer = SyncHandler.getCompatibleSerializer(tracker.valueType)
|
||||
writeBuffer.writeHeader(tracker.hasChanged())
|
||||
val serializer = SyncHandler.getCompatibleSerializer(tracker.valueType) ?: return
|
||||
writeBuffer.writeBit(tracker.hasChanged())
|
||||
if (tracker.hasChanged()) {
|
||||
serializer.serializeExplicit(trackedField, flags, tracker, writeBuffer, tracker.valueType)
|
||||
tracker.clearChangeState()
|
||||
@ -52,13 +69,13 @@ class DiffTrackedSerializer private constructor(): Serializer(arrayOf(
|
||||
}
|
||||
DiffTrackedArray::class.java -> {
|
||||
val tracker = field.get(owner) as DiffTrackedArray<*>
|
||||
val serializer = SyncHandler.getCompatibleSerializer(tracker.elementType)
|
||||
writeBuffer.writeHeader(tracker.hasChanged())
|
||||
val serializer = SyncHandler.getCompatibleSerializer(tracker.elementType) ?: return
|
||||
writeBuffer.writeBit(tracker.hasChanged())
|
||||
if (tracker.hasChanged()) {
|
||||
val holder = Holder(null)
|
||||
|
||||
for (index in tracker.changeMap.indices) {
|
||||
writeBuffer.writeHeader(tracker.changeMap[index])
|
||||
writeBuffer.writeBit(tracker.changeMap[index])
|
||||
if (tracker.changeMap[index]) {
|
||||
holder.value = tracker[index]
|
||||
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) {
|
||||
DiffTracked::class.java -> {
|
||||
val tracker = field.get(owner) as DiffTracked<*>
|
||||
val serializer = SyncHandler.getCompatibleSerializer(tracker.valueType)
|
||||
if (readBuffer.readHeader())
|
||||
val serializer = SyncHandler.getCompatibleSerializer(tracker.valueType) ?: return
|
||||
if (readBuffer.readBit())
|
||||
serializer.deserializeExplicit(trackedField, flags, tracker, readBuffer, tracker.valueType)
|
||||
tracker.clearChangeState()
|
||||
}
|
||||
DiffTrackedArray::class.java -> {
|
||||
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 array = tracker.values as Array<Any?>
|
||||
|
||||
for (index in tracker.changeMap.indices) {
|
||||
if (readBuffer.readHeader()) {
|
||||
if (readBuffer.readBit()) {
|
||||
serializer.deserializeExplicit(Holder.valueField, flags, holder, readBuffer, tracker.elementType)
|
||||
array[index] = holder.value
|
||||
}
|
||||
@ -101,4 +118,25 @@ class DiffTrackedSerializer private constructor(): Serializer(arrayOf(
|
||||
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<*>) {
|
||||
when (fieldType) {
|
||||
Vector3::class.java -> {
|
||||
val floatSerializer = SyncHandler.getCompatibleSerializer(Float::class.java) ?: return
|
||||
|
||||
val vector = field.access().get(owner) as Vector3
|
||||
val xDiff = xField.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)
|
||||
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 {
|
||||
c1 || c2 || c3 -> {
|
||||
val bytes =
|
||||
@ -56,7 +58,6 @@ class MathSerializer: Serializer(arrayOf(
|
||||
.registerBytes(if (zDiff.hasChanged()) varIntSize(zDiff.value.encodeRotation(bytes).toLong()) else 0)
|
||||
}
|
||||
else -> {
|
||||
val floatSerializer = SyncHandler.getCompatibleSerializer(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 (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) {
|
||||
Vector3::class.java -> {
|
||||
val intSerializer = SyncHandler.getCompatibleSerializer(Int::class.java) ?: return
|
||||
val floatSerializer = SyncHandler.getCompatibleSerializer(Float::class.java) ?: return
|
||||
|
||||
var flags = _flags
|
||||
val vector = field.access().get(owner) as Vector3
|
||||
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!")
|
||||
|
||||
writeBuffer.writeHeader(xDiff.hasChanged())
|
||||
writeBuffer.writeHeader(yDiff.hasChanged())
|
||||
writeBuffer.writeHeader(zDiff.hasChanged())
|
||||
writeBuffer.writeBit(xDiff.hasChanged())
|
||||
writeBuffer.writeBit(yDiff.hasChanged())
|
||||
writeBuffer.writeBit(zDiff.hasChanged())
|
||||
|
||||
when {
|
||||
c1 || c2 || c3 -> {
|
||||
val intSerializer = SyncHandler.getCompatibleSerializer(Int::class.java)
|
||||
val bytes =
|
||||
when {
|
||||
c1 -> 1
|
||||
@ -123,7 +126,6 @@ class MathSerializer: Serializer(arrayOf(
|
||||
if (zDiff.hasChanged()) intSerializer.serializeExplicit(Holder.valueField, flags, zHolder, writeBuffer, Int::class.java)
|
||||
}
|
||||
else -> {
|
||||
val floatSerializer = SyncHandler.getCompatibleSerializer(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)
|
||||
@ -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) {
|
||||
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 c1 = flags.contains(compressedRotationVector1)
|
||||
val c2 = flags.contains(compressedRotationVector2)
|
||||
@ -153,37 +158,35 @@ class MathSerializer: Serializer(arrayOf(
|
||||
|
||||
when {
|
||||
c1 || c2 || c3 -> {
|
||||
val intSerializer = SyncHandler.getCompatibleSerializer(Int::class.java)
|
||||
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)
|
||||
xDiff.value = (xHolder.value as Int).decodeRotation(bytes)
|
||||
xDiff.clearChangeState()
|
||||
}
|
||||
if (readBuffer.readHeader()) {
|
||||
if (readBuffer.readBit()) {
|
||||
intSerializer.deserializeExplicit(Holder.valueField, flags, yHolder, readBuffer, Int::class.java)
|
||||
yDiff.value = (yHolder.value as Int).decodeRotation(bytes)
|
||||
yDiff.clearChangeState()
|
||||
}
|
||||
if (readBuffer.readHeader()) {
|
||||
if (readBuffer.readBit()) {
|
||||
intSerializer.deserializeExplicit(Holder.valueField, flags, zHolder, readBuffer, Int::class.java)
|
||||
zDiff.value = (zHolder.value as Int).decodeRotation(bytes)
|
||||
zDiff.clearChangeState()
|
||||
}
|
||||
}
|
||||
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)
|
||||
xDiff.clearChangeState()
|
||||
}
|
||||
if (readBuffer.readHeader()){
|
||||
if (readBuffer.readBit()){
|
||||
floatSerializer.deserializeExplicit(diffValue, flags, yField.get(vector), readBuffer, Float::class.java)
|
||||
yDiff.clearChangeState()
|
||||
}
|
||||
if (readBuffer.readHeader()){
|
||||
if (readBuffer.readBit()){
|
||||
floatSerializer.deserializeExplicit(diffValue, flags, zField.get(vector), readBuffer, Float::class.java)
|
||||
zDiff.clearChangeState()
|
||||
}
|
||||
@ -193,4 +196,10 @@ class MathSerializer: Serializer(arrayOf(
|
||||
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.data.*
|
||||
import net.tofvesson.math.varIntSize
|
||||
import java.lang.reflect.Field
|
||||
|
||||
@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<*>) {
|
||||
val arrayLength = java.lang.reflect.Array.getLength(field.get(owner))
|
||||
val holder = Holder(null)
|
||||
|
||||
when (fieldType) {
|
||||
BooleanArray::class.java -> state.registerBits(arrayLength)
|
||||
ByteArray::class.java -> state.registerBytes(arrayLength)
|
||||
ShortArray::class.java ->
|
||||
if(flags.contains(SyncFlag.NoCompress)) state.registerBytes(arrayLength * 2)
|
||||
else {
|
||||
val shortSerializer = SyncHandler.getCompatibleSerializer(Short::class.java)
|
||||
val shortSerializer = SyncHandler.getCompatibleSerializer(Short::class.java) ?: return
|
||||
for (value in field.get(owner) as ShortArray) {
|
||||
holder.value = value
|
||||
shortSerializer.computeSizeExplicit(Holder.valueField, flags, holder, state, Short::class.java)
|
||||
@ -38,7 +40,7 @@ class PrimitiveArraySerializer private constructor(): Serializer(arrayOf(
|
||||
IntArray::class.java ->
|
||||
if(flags.contains(SyncFlag.NoCompress)) state.registerBytes(arrayLength * 4)
|
||||
else {
|
||||
val intSerializer = SyncHandler.getCompatibleSerializer(Int::class.java)
|
||||
val intSerializer = SyncHandler.getCompatibleSerializer(Int::class.java) ?: return
|
||||
for (value in field.get(owner) as IntArray) {
|
||||
holder.value = value
|
||||
intSerializer.computeSizeExplicit(Holder.valueField, flags, holder, state, Int::class.java)
|
||||
@ -47,7 +49,7 @@ class PrimitiveArraySerializer private constructor(): Serializer(arrayOf(
|
||||
LongArray::class.java ->
|
||||
if(flags.contains(SyncFlag.NoCompress)) state.registerBytes(arrayLength * 8)
|
||||
else {
|
||||
val longSerializer = SyncHandler.getCompatibleSerializer(Long::class.java)
|
||||
val longSerializer = SyncHandler.getCompatibleSerializer(Long::class.java) ?: return
|
||||
for (value in field.get(owner) as LongArray) {
|
||||
holder.value = value
|
||||
longSerializer.computeSizeExplicit(Holder.valueField, flags, holder, state, Long::class.java)
|
||||
@ -56,7 +58,7 @@ class PrimitiveArraySerializer private constructor(): Serializer(arrayOf(
|
||||
FloatArray::class.java ->
|
||||
if(flags.contains(SyncFlag.NoCompress)) state.registerBytes(arrayLength * 4)
|
||||
else {
|
||||
val floatSerializer = SyncHandler.getCompatibleSerializer(Float::class.java)
|
||||
val floatSerializer = SyncHandler.getCompatibleSerializer(Float::class.java) ?: return
|
||||
for (value in field.get(owner) as FloatArray) {
|
||||
holder.value = value
|
||||
floatSerializer.computeSizeExplicit(Holder.valueField, flags, holder, state, Float::class.java)
|
||||
@ -65,7 +67,7 @@ class PrimitiveArraySerializer private constructor(): Serializer(arrayOf(
|
||||
DoubleArray::class.java ->
|
||||
if(flags.contains(SyncFlag.NoCompress)) state.registerBytes(arrayLength * 8)
|
||||
else {
|
||||
val doubleSerializer = SyncHandler.getCompatibleSerializer(Double::class.java)
|
||||
val doubleSerializer = SyncHandler.getCompatibleSerializer(Double::class.java) ?: return
|
||||
for (value in field.get(owner) as DoubleArray) {
|
||||
holder.value = value
|
||||
doubleSerializer.computeSizeExplicit(Holder.valueField, flags, holder, state, Double::class.java)
|
||||
@ -73,12 +75,16 @@ class PrimitiveArraySerializer private constructor(): Serializer(arrayOf(
|
||||
}
|
||||
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 holder = Holder(null)
|
||||
if(!flags.contains(knownSize)) writeBuffer.writePackedInt(arrayLength, true)
|
||||
if(!flags.contains(knownSize))
|
||||
writeBuffer.writePackedInt(arrayLength, true)
|
||||
when (fieldType) {
|
||||
BooleanArray::class.java ->
|
||||
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)
|
||||
writeBuffer.writeShort(value)
|
||||
else {
|
||||
val shortSerializer = SyncHandler.getCompatibleSerializer(Short::class.java)
|
||||
val shortSerializer = SyncHandler.getCompatibleSerializer(Short::class.java) ?: return
|
||||
for (value in field.get(owner) as ShortArray) {
|
||||
holder.value = value
|
||||
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)
|
||||
writeBuffer.writeInt(value)
|
||||
else {
|
||||
val intSerializer = SyncHandler.getCompatibleSerializer(Int::class.java)
|
||||
val intSerializer = SyncHandler.getCompatibleSerializer(Int::class.java) ?: return
|
||||
for (value in field.get(owner) as IntArray) {
|
||||
holder.value = value
|
||||
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)
|
||||
writeBuffer.writeLong(value)
|
||||
else {
|
||||
val longSerializer = SyncHandler.getCompatibleSerializer(Long::class.java)
|
||||
val longSerializer = SyncHandler.getCompatibleSerializer(Long::class.java) ?: return
|
||||
for (value in field.get(owner) as LongArray) {
|
||||
holder.value = value
|
||||
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)
|
||||
writeBuffer.writeFloat(value)
|
||||
else {
|
||||
val floatSerializer = SyncHandler.getCompatibleSerializer(Float::class.java)
|
||||
val floatSerializer = SyncHandler.getCompatibleSerializer(Float::class.java) ?: return
|
||||
for (value in field.get(owner) as FloatArray) {
|
||||
holder.value = value
|
||||
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)
|
||||
writeBuffer.writeDouble(value)
|
||||
else {
|
||||
val doubleSerializer = SyncHandler.getCompatibleSerializer(Double::class.java)
|
||||
val doubleSerializer = SyncHandler.getCompatibleSerializer(Double::class.java) ?: return
|
||||
for (value in field.get(owner) as DoubleArray) {
|
||||
holder.value = value
|
||||
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 arrayLength =
|
||||
if(flags.contains(knownSize)) localLength
|
||||
@ -215,4 +221,7 @@ class PrimitiveArraySerializer private constructor(): Serializer(arrayOf(
|
||||
}
|
||||
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
|
||||
|
||||
import net.tofvesson.annotation.SyncFlag
|
||||
import net.tofvesson.data.ReadBuffer
|
||||
import net.tofvesson.data.RBuffer
|
||||
import net.tofvesson.data.Serializer
|
||||
import net.tofvesson.data.WriteBuffer
|
||||
import net.tofvesson.data.WBuffer
|
||||
import net.tofvesson.data.WriteState
|
||||
import net.tofvesson.math.*
|
||||
import net.tofvesson.reflect.*
|
||||
@ -75,7 +75,7 @@ class PrimitiveSerializer private constructor() : Serializer(arrayOf(
|
||||
field: Field,
|
||||
flags: Array<out SyncFlag>,
|
||||
owner: Any?,
|
||||
writeBuffer: WriteBuffer,
|
||||
writeBuffer: WBuffer,
|
||||
fieldType: Class<*>
|
||||
){
|
||||
when (fieldType) {
|
||||
@ -104,7 +104,7 @@ class PrimitiveSerializer private constructor() : Serializer(arrayOf(
|
||||
field: Field,
|
||||
flags: Array<out SyncFlag>,
|
||||
owner: Any?,
|
||||
readBuffer: ReadBuffer,
|
||||
readBuffer: RBuffer,
|
||||
fieldType: Class<*>
|
||||
) =
|
||||
when(fieldType){
|
||||
@ -127,4 +127,7 @@ class PrimitiveSerializer private constructor() : Serializer(arrayOf(
|
||||
else field.setDoubleAdaptive(owner, readBuffer.readPackedDouble(flags.contains(SyncFlag.FloatEndianSwap)))
|
||||
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.DiffTrackedArray;
|
||||
import net.tofvesson.data.SyncHandler;
|
||||
import net.tofvesson.math.ArithmeticKt;
|
||||
import net.tofvesson.serializers.MathSerializer;
|
||||
import net.tofvesson.math.Vector3;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
public class Main {
|
||||
@SyncedVar("NonNegative")
|
||||
public int syncTest = 5;
|
||||
@ -28,12 +31,16 @@ public class Main {
|
||||
public static DiffTracked<Integer> tracker = new DiffTracked<>(5, Integer.class);
|
||||
|
||||
@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})
|
||||
public static Vector3 lookDirection = new Vector3(60, 90, 80);
|
||||
|
||||
public static void main(String[] args){
|
||||
ByteBuffer buf = ByteBuffer.allocate(256);
|
||||
ArithmeticKt.writeVarInt(buf, 0, -260);
|
||||
|
||||
|
||||
Main testObject = new Main();
|
||||
|
||||
SyncHandler sync = new SyncHandler();
|
Loading…
x
Reference in New Issue
Block a user