Use VLQ to store judgements

This commit is contained in:
nise.moe 2024-02-23 19:13:23 +01:00
parent fbd61e0fa1
commit f382a0ed48

View File

@ -5,10 +5,10 @@ import com.aayushatharva.brotli4j.decoder.Decoder
import com.aayushatharva.brotli4j.encoder.Encoder
import com.nisemoe.nise.integrations.CircleguardService
import org.springframework.stereotype.Service
import java.io.ByteArrayOutputStream
import java.nio.ByteBuffer
import kotlin.math.round
@Service
class CompressJudgements {
@ -19,25 +19,55 @@ class CompressJudgements {
Brotli4jLoader.ensureAvailability()
}
fun ByteBuffer.putVLQ(value: Int) {
var currentValue = value
do {
var temp = (currentValue and 0x7F)
currentValue = currentValue ushr 7
if (currentValue != 0) {
temp = temp or 0x80
}
this.put(temp.toByte())
} while (currentValue != 0)
}
fun ByteBuffer.getVLQ(): Int {
var result = 0
var shift = 0
var b: Byte
do {
b = this.get()
result = result or ((b.toInt() and 0x7F) shl shift)
shift += 7
} while (b.toInt() and 0x80 != 0)
return result
}
fun serialize(judgements: List<CircleguardService.ScoreJudgement>): ByteArray {
val buffer = ByteBuffer.allocate(judgements.size * (2 + 4 + 4 + 1 + 2 + 2 + 2))
var lastTime = 0.0
val byteStream = ByteArrayOutputStream()
var lastTimestamp = 0.0
judgements.forEach { judgement ->
val deltaTime = (judgement.time - lastTime).toInt()
buffer.putShort(deltaTime.toShort())
buffer.putInt((round(judgement.x * 1000)).toInt())
buffer.putInt((round(judgement.y * 1000)).toInt())
byteStream.use { stream ->
/**
* We allocate an arbitrary amount of buffer which *hopefully* is enough.
*/
ByteBuffer.allocate(4096).let { buffer ->
buffer.putVLQ((judgement.time - lastTimestamp).toInt())
buffer.putVLQ(round(judgement.x * 100).toInt())
buffer.putVLQ(round(judgement.y * 100).toInt())
buffer.put(judgement.type.ordinal.toByte())
buffer.putShort((judgement.distance_center * 100).toInt().toShort())
buffer.putShort((judgement.distance_edge * 100).toInt().toShort())
buffer.putShort(judgement.error.toInt().toShort())
buffer.putVLQ((judgement.distance_center * 100).toInt())
buffer.putVLQ((judgement.distance_edge * 100).toInt())
buffer.putVLQ(judgement.error.toInt())
lastTime = judgement.time
lastTimestamp = judgement.time
stream.write(buffer.array(), 0, buffer.position())
}
return Encoder.compress(buffer.array(), brotliParameters)
}
}
return Encoder.compress(byteStream.toByteArray(), brotliParameters)
}
fun deserialize(compressedData: ByteArray): List<CircleguardService.ScoreJudgement> {
@ -47,28 +77,18 @@ class CompressJudgements {
var lastTime = 0.0
while (buffer.hasRemaining()) {
val deltaTime = buffer.short.toInt()
val deltaTime = buffer.getVLQ()
lastTime += deltaTime
val deltaX = buffer.getInt()
val deltaY = buffer.getInt()
val typeOrdinal = buffer.get().toInt()
val type = CircleguardService.JudgementType.entries[typeOrdinal]
val distanceCenter = buffer.short.toInt() / 100.0
val distanceEdge = buffer.short.toInt() / 100.0
val error = buffer.short.toInt()
judgements.add(
CircleguardService.ScoreJudgement(
time = lastTime,
x = deltaX / 1000.0,
y = deltaY / 1000.0,
type = type,
distance_center = distanceCenter,
distance_edge = distanceEdge,
error = error.toDouble()
x = buffer.getVLQ() / 100.0,
y = buffer.getVLQ() / 100.0,
type = CircleguardService.JudgementType.entries[buffer.get().toInt()],
distance_center = buffer.getVLQ() / 100.0,
distance_edge = buffer.getVLQ() / 100.0,
error = buffer.getVLQ().toDouble()
))
}