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.aayushatharva.brotli4j.encoder.Encoder
import com.nisemoe.nise.integrations.CircleguardService import com.nisemoe.nise.integrations.CircleguardService
import org.springframework.stereotype.Service import org.springframework.stereotype.Service
import java.io.ByteArrayOutputStream
import java.nio.ByteBuffer import java.nio.ByteBuffer
import kotlin.math.round import kotlin.math.round
@Service @Service
class CompressJudgements { class CompressJudgements {
@ -19,25 +19,55 @@ class CompressJudgements {
Brotli4jLoader.ensureAvailability() 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 { fun serialize(judgements: List<CircleguardService.ScoreJudgement>): ByteArray {
val buffer = ByteBuffer.allocate(judgements.size * (2 + 4 + 4 + 1 + 2 + 2 + 2)) val byteStream = ByteArrayOutputStream()
var lastTime = 0.0 var lastTimestamp = 0.0
judgements.forEach { judgement -> judgements.forEach { judgement ->
val deltaTime = (judgement.time - lastTime).toInt() byteStream.use { stream ->
buffer.putShort(deltaTime.toShort()) /**
* 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.putVLQ((judgement.distance_center * 100).toInt())
buffer.putVLQ((judgement.distance_edge * 100).toInt())
buffer.putVLQ(judgement.error.toInt())
buffer.putInt((round(judgement.x * 1000)).toInt()) lastTimestamp = judgement.time
buffer.putInt((round(judgement.y * 1000)).toInt()) stream.write(buffer.array(), 0, buffer.position())
}
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())
lastTime = judgement.time
} }
return Encoder.compress(buffer.array(), brotliParameters)
return Encoder.compress(byteStream.toByteArray(), brotliParameters)
} }
fun deserialize(compressedData: ByteArray): List<CircleguardService.ScoreJudgement> { fun deserialize(compressedData: ByteArray): List<CircleguardService.ScoreJudgement> {
@ -47,28 +77,18 @@ class CompressJudgements {
var lastTime = 0.0 var lastTime = 0.0
while (buffer.hasRemaining()) { while (buffer.hasRemaining()) {
val deltaTime = buffer.short.toInt() val deltaTime = buffer.getVLQ()
lastTime += deltaTime 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( judgements.add(
CircleguardService.ScoreJudgement( CircleguardService.ScoreJudgement(
time = lastTime, time = lastTime,
x = deltaX / 1000.0, x = buffer.getVLQ() / 100.0,
y = deltaY / 1000.0, y = buffer.getVLQ() / 100.0,
type = type, type = CircleguardService.JudgementType.entries[buffer.get().toInt()],
distance_center = distanceCenter, distance_center = buffer.getVLQ() / 100.0,
distance_edge = distanceEdge, distance_edge = buffer.getVLQ() / 100.0,
error = error.toDouble() error = buffer.getVLQ().toDouble()
)) ))
} }