mirror of
https://gitlab.bixilon.de/bixilon/minosoft.git
synced 2025-09-15 18:34:56 -04:00
network pipeline: reduce temporary allocations even more
This commit is contained in:
parent
f9617eecdf
commit
34a28bf156
@ -70,5 +70,5 @@ abstract class TemporaryAllocator<T> {
|
||||
|
||||
protected abstract fun getSize(value: T): Int
|
||||
|
||||
abstract fun create(size: Int): T
|
||||
protected abstract fun create(size: Int): T
|
||||
}
|
||||
|
@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Minosoft
|
||||
* Copyright (C) 2020-2025 Moritz Zwerger
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
||||
*/
|
||||
|
||||
package de.bixilon.minosoft.protocol.network.network.client.netty
|
||||
|
||||
import de.bixilon.minosoft.gui.rendering.util.allocator.ByteAllocator
|
||||
|
||||
val NetworkAllocator = ByteAllocator()
|
@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Minosoft
|
||||
* Copyright (C) 2020-2025 Moritz Zwerger
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
||||
*/
|
||||
|
||||
package de.bixilon.minosoft.protocol.network.network.client.netty
|
||||
|
||||
class ReadArray(
|
||||
val array: ByteArray,
|
||||
val length: Int,
|
||||
)
|
@ -13,36 +13,62 @@
|
||||
|
||||
package de.bixilon.minosoft.protocol.network.network.client.netty.pipeline.compression
|
||||
|
||||
import de.bixilon.kutil.compression.zlib.ZlibUtil.decompress
|
||||
import de.bixilon.kutil.buffer.ByteBufferUtil.createBuffer
|
||||
import de.bixilon.minosoft.protocol.network.network.client.netty.NetworkAllocator
|
||||
import de.bixilon.minosoft.protocol.network.network.client.netty.ReadArray
|
||||
import de.bixilon.minosoft.protocol.network.network.client.netty.exceptions.ciritical.PacketTooLongException
|
||||
import de.bixilon.minosoft.protocol.network.network.client.netty.pipeline.compression.exception.SizeMismatchInflaterException
|
||||
import de.bixilon.minosoft.protocol.protocol.buffers.InByteBuffer
|
||||
import de.bixilon.minosoft.util.KUtil.readByteArray
|
||||
import io.netty.channel.ChannelHandlerContext
|
||||
import io.netty.handler.codec.MessageToMessageDecoder
|
||||
import java.util.zip.Inflater
|
||||
|
||||
|
||||
class PacketInflater(
|
||||
private val maxPacketSize: Int,
|
||||
) : MessageToMessageDecoder<ByteArray>() {
|
||||
) : MessageToMessageDecoder<ReadArray>() {
|
||||
|
||||
override fun decode(context: ChannelHandlerContext?, data: ByteArray, out: MutableList<Any>) {
|
||||
val buffer = InByteBuffer(data)
|
||||
override fun decode(context: ChannelHandlerContext?, data: ReadArray, out: MutableList<Any>) {
|
||||
val buffer = InByteBuffer(data.array)
|
||||
|
||||
val uncompressedLength = buffer.readVarInt()
|
||||
val rest = buffer.readRemaining()
|
||||
val length = data.length - buffer.pointer
|
||||
val compressed = NetworkAllocator.allocate(length)
|
||||
buffer.readByteArray(compressed, 0, length)
|
||||
if (uncompressedLength == 0) {
|
||||
out += rest
|
||||
out += ReadArray(compressed, length)
|
||||
return
|
||||
}
|
||||
if (uncompressedLength > maxPacketSize) {
|
||||
throw PacketTooLongException(uncompressedLength, maxPacketSize)
|
||||
}
|
||||
|
||||
val decompressed = rest.decompress(uncompressedLength)
|
||||
if (decompressed.size != uncompressedLength) {
|
||||
val decompressed = NetworkAllocator.allocate(uncompressedLength)
|
||||
|
||||
val actualDecompressed = compressed.decompress(decompressed)
|
||||
NetworkAllocator.free(compressed)
|
||||
|
||||
if (actualDecompressed != uncompressedLength) {
|
||||
throw SizeMismatchInflaterException()
|
||||
}
|
||||
out += decompressed
|
||||
out += ReadArray(decompressed, uncompressedLength)
|
||||
}
|
||||
|
||||
|
||||
@Deprecated("kutil 1.27.1")
|
||||
private fun ByteArray.decompress(output: ByteArray): Int {
|
||||
val inflater = Inflater()
|
||||
inflater.setInput(this, 0, this.size)
|
||||
val buffer = createBuffer()
|
||||
var pointer = 0
|
||||
|
||||
while (!inflater.finished()) {
|
||||
val length = inflater.inflate(buffer)
|
||||
System.arraycopy(buffer, 0, output, pointer, length)
|
||||
pointer += length
|
||||
}
|
||||
return pointer
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
@ -14,8 +14,9 @@
|
||||
package de.bixilon.minosoft.protocol.network.network.client.netty.pipeline.encoding
|
||||
|
||||
import de.bixilon.kutil.cast.CastUtil.unsafeCast
|
||||
import de.bixilon.minosoft.gui.rendering.util.allocator.ByteAllocator
|
||||
import de.bixilon.minosoft.protocol.network.network.client.netty.NettyClient
|
||||
import de.bixilon.minosoft.protocol.network.network.client.netty.NetworkAllocator
|
||||
import de.bixilon.minosoft.protocol.network.network.client.netty.ReadArray
|
||||
import de.bixilon.minosoft.protocol.network.network.client.netty.exceptions.NetworkException
|
||||
import de.bixilon.minosoft.protocol.network.network.client.netty.exceptions.PacketReadException
|
||||
import de.bixilon.minosoft.protocol.network.network.client.netty.exceptions.ciritical.UnknownPacketIdException
|
||||
@ -35,21 +36,22 @@ import java.lang.reflect.InvocationTargetException
|
||||
|
||||
class PacketDecoder(
|
||||
private val client: NettyClient,
|
||||
) : MessageToMessageDecoder<ByteArray>() {
|
||||
) : MessageToMessageDecoder<ReadArray>() {
|
||||
private val version: Version? = client.session.version
|
||||
|
||||
override fun decode(context: ChannelHandlerContext, array: ByteArray, out: MutableList<Any>) {
|
||||
val buffer = InByteBuffer(array)
|
||||
override fun decode(context: ChannelHandlerContext, array: ReadArray, out: MutableList<Any>) {
|
||||
val buffer = InByteBuffer(array.array)
|
||||
val packetId = buffer.readVarInt()
|
||||
val length = buffer.size - buffer.pointer
|
||||
val data = ALLOCATOR.create(length)
|
||||
val length = array.length - buffer.pointer
|
||||
val data = NetworkAllocator.allocate(length)
|
||||
buffer.readByteArray(data, 0, length)
|
||||
NetworkAllocator.free(array.array)
|
||||
|
||||
try {
|
||||
val queued = decode(packetId, length, data) ?: return
|
||||
out += queued
|
||||
} finally {
|
||||
ALLOCATOR.free(data)
|
||||
NetworkAllocator.free(data)
|
||||
}
|
||||
}
|
||||
|
||||
@ -90,6 +92,5 @@ class PacketDecoder(
|
||||
|
||||
companion object {
|
||||
const val NAME = "packet_decoder"
|
||||
val ALLOCATOR = ByteAllocator()
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Minosoft
|
||||
* Copyright (C) 2020-2024 Moritz Zwerger
|
||||
* Copyright (C) 2020-2025 Moritz Zwerger
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
@ -74,8 +74,8 @@ class PacketEncoder(
|
||||
throw PacketNotAvailableException(type, state, version)
|
||||
}
|
||||
|
||||
private fun encode(packet: C2SPacket): ByteArray {
|
||||
val state = client.connection.state!!
|
||||
private fun encode(packet: C2SPacket): ByteArray? {
|
||||
val state = client.connection.state ?: return null
|
||||
|
||||
val type = DefaultPackets.C2S[state]?.get(packet::class) ?: throw UnknownPacketException(packet::class.java)
|
||||
val id = getPacketId(version, state, type)
|
||||
@ -90,7 +90,7 @@ class PacketEncoder(
|
||||
}
|
||||
|
||||
override fun encode(context: ChannelHandlerContext, packet: C2SPacket, out: MutableList<Any>) {
|
||||
out += encode(packet)
|
||||
out += encode(packet) ?: return
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Minosoft
|
||||
* Copyright (C) 2020-2022 Moritz Zwerger
|
||||
* Copyright (C) 2020-2025 Moritz Zwerger
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
@ -13,6 +13,7 @@
|
||||
|
||||
package de.bixilon.minosoft.protocol.network.network.client.netty.pipeline.encryption
|
||||
|
||||
import de.bixilon.minosoft.protocol.network.network.client.netty.NetworkAllocator
|
||||
import io.netty.buffer.ByteBuf
|
||||
import io.netty.channel.ChannelHandlerContext
|
||||
import io.netty.handler.codec.ByteToMessageDecoder
|
||||
@ -23,11 +24,15 @@ class PacketDecryptor(
|
||||
) : ByteToMessageDecoder() {
|
||||
|
||||
override fun decode(context: ChannelHandlerContext, data: ByteBuf, out: MutableList<Any>) {
|
||||
val bytes = ByteArray(data.readableBytes())
|
||||
data.readBytes(bytes)
|
||||
val length = data.readableBytes()
|
||||
val encrypted = NetworkAllocator.allocate(length)
|
||||
data.readBytes(encrypted)
|
||||
|
||||
val decrypted = cipher.update(bytes)
|
||||
val decrypted = NetworkAllocator.allocate(length)
|
||||
cipher.update(encrypted, 0, length, decrypted)
|
||||
NetworkAllocator.free(encrypted)
|
||||
out += context.alloc().buffer(decrypted.size).apply { writeBytes(decrypted) }
|
||||
NetworkAllocator.free(decrypted)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Minosoft
|
||||
* Copyright (C) 2020-2024 Moritz Zwerger
|
||||
* Copyright (C) 2020-2025 Moritz Zwerger
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
@ -14,6 +14,8 @@
|
||||
package de.bixilon.minosoft.protocol.network.network.client.netty.pipeline.length
|
||||
|
||||
import de.bixilon.kutil.exception.FastException
|
||||
import de.bixilon.minosoft.protocol.network.network.client.netty.NetworkAllocator
|
||||
import de.bixilon.minosoft.protocol.network.network.client.netty.ReadArray
|
||||
import de.bixilon.minosoft.protocol.network.network.client.netty.exceptions.ciritical.PacketTooLongException
|
||||
import io.netty.buffer.ByteBuf
|
||||
import io.netty.channel.ChannelHandlerContext
|
||||
@ -47,10 +49,10 @@ class LengthDecoder(
|
||||
return
|
||||
}
|
||||
|
||||
val array = ByteArray(length)
|
||||
buffer.readBytes(array)
|
||||
val array = NetworkAllocator.allocate(length)
|
||||
buffer.readBytes(array, 0, length)
|
||||
|
||||
out += array
|
||||
out += ReadArray(array, length)
|
||||
}
|
||||
|
||||
|
||||
|
@ -100,7 +100,7 @@ class ChunkS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket {
|
||||
this.prototype.biomeSource = SpatialBiomeArray(buffer.readBiomeArray())
|
||||
}
|
||||
val length = buffer.readVarInt()
|
||||
val data = ALLOCATOR.create(length)
|
||||
val data = ALLOCATOR.allocate(length)
|
||||
buffer.readByteArray(data, 0, length)
|
||||
readingData = ChunkReadingData(data, PlayInByteBuffer(data, buffer.session), dimension, sectionBitMask)
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user