mirror of
https://gitlab.bixilon.de/bixilon/minosoft.git
synced 2025-09-16 10:55:01 -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
|
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
|
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.exceptions.ciritical.PacketTooLongException
|
||||||
import de.bixilon.minosoft.protocol.network.network.client.netty.pipeline.compression.exception.SizeMismatchInflaterException
|
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.protocol.protocol.buffers.InByteBuffer
|
||||||
|
import de.bixilon.minosoft.util.KUtil.readByteArray
|
||||||
import io.netty.channel.ChannelHandlerContext
|
import io.netty.channel.ChannelHandlerContext
|
||||||
import io.netty.handler.codec.MessageToMessageDecoder
|
import io.netty.handler.codec.MessageToMessageDecoder
|
||||||
|
import java.util.zip.Inflater
|
||||||
|
|
||||||
|
|
||||||
class PacketInflater(
|
class PacketInflater(
|
||||||
private val maxPacketSize: Int,
|
private val maxPacketSize: Int,
|
||||||
) : MessageToMessageDecoder<ByteArray>() {
|
) : MessageToMessageDecoder<ReadArray>() {
|
||||||
|
|
||||||
override fun decode(context: ChannelHandlerContext?, data: ByteArray, out: MutableList<Any>) {
|
override fun decode(context: ChannelHandlerContext?, data: ReadArray, out: MutableList<Any>) {
|
||||||
val buffer = InByteBuffer(data)
|
val buffer = InByteBuffer(data.array)
|
||||||
|
|
||||||
val uncompressedLength = buffer.readVarInt()
|
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) {
|
if (uncompressedLength == 0) {
|
||||||
out += rest
|
out += ReadArray(compressed, length)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (uncompressedLength > maxPacketSize) {
|
if (uncompressedLength > maxPacketSize) {
|
||||||
throw PacketTooLongException(uncompressedLength, maxPacketSize)
|
throw PacketTooLongException(uncompressedLength, maxPacketSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
val decompressed = rest.decompress(uncompressedLength)
|
val decompressed = NetworkAllocator.allocate(uncompressedLength)
|
||||||
if (decompressed.size != uncompressedLength) {
|
|
||||||
|
val actualDecompressed = compressed.decompress(decompressed)
|
||||||
|
NetworkAllocator.free(compressed)
|
||||||
|
|
||||||
|
if (actualDecompressed != uncompressedLength) {
|
||||||
throw SizeMismatchInflaterException()
|
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 {
|
companion object {
|
||||||
|
@ -14,8 +14,9 @@
|
|||||||
package de.bixilon.minosoft.protocol.network.network.client.netty.pipeline.encoding
|
package de.bixilon.minosoft.protocol.network.network.client.netty.pipeline.encoding
|
||||||
|
|
||||||
import de.bixilon.kutil.cast.CastUtil.unsafeCast
|
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.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.NetworkException
|
||||||
import de.bixilon.minosoft.protocol.network.network.client.netty.exceptions.PacketReadException
|
import de.bixilon.minosoft.protocol.network.network.client.netty.exceptions.PacketReadException
|
||||||
import de.bixilon.minosoft.protocol.network.network.client.netty.exceptions.ciritical.UnknownPacketIdException
|
import de.bixilon.minosoft.protocol.network.network.client.netty.exceptions.ciritical.UnknownPacketIdException
|
||||||
@ -35,21 +36,22 @@ import java.lang.reflect.InvocationTargetException
|
|||||||
|
|
||||||
class PacketDecoder(
|
class PacketDecoder(
|
||||||
private val client: NettyClient,
|
private val client: NettyClient,
|
||||||
) : MessageToMessageDecoder<ByteArray>() {
|
) : MessageToMessageDecoder<ReadArray>() {
|
||||||
private val version: Version? = client.session.version
|
private val version: Version? = client.session.version
|
||||||
|
|
||||||
override fun decode(context: ChannelHandlerContext, array: ByteArray, out: MutableList<Any>) {
|
override fun decode(context: ChannelHandlerContext, array: ReadArray, out: MutableList<Any>) {
|
||||||
val buffer = InByteBuffer(array)
|
val buffer = InByteBuffer(array.array)
|
||||||
val packetId = buffer.readVarInt()
|
val packetId = buffer.readVarInt()
|
||||||
val length = buffer.size - buffer.pointer
|
val length = array.length - buffer.pointer
|
||||||
val data = ALLOCATOR.create(length)
|
val data = NetworkAllocator.allocate(length)
|
||||||
buffer.readByteArray(data, 0, length)
|
buffer.readByteArray(data, 0, length)
|
||||||
|
NetworkAllocator.free(array.array)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
val queued = decode(packetId, length, data) ?: return
|
val queued = decode(packetId, length, data) ?: return
|
||||||
out += queued
|
out += queued
|
||||||
} finally {
|
} finally {
|
||||||
ALLOCATOR.free(data)
|
NetworkAllocator.free(data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,6 +92,5 @@ class PacketDecoder(
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val NAME = "packet_decoder"
|
const val NAME = "packet_decoder"
|
||||||
val ALLOCATOR = ByteAllocator()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Minosoft
|
* 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.
|
* 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)
|
throw PacketNotAvailableException(type, state, version)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun encode(packet: C2SPacket): ByteArray {
|
private fun encode(packet: C2SPacket): ByteArray? {
|
||||||
val state = client.connection.state!!
|
val state = client.connection.state ?: return null
|
||||||
|
|
||||||
val type = DefaultPackets.C2S[state]?.get(packet::class) ?: throw UnknownPacketException(packet::class.java)
|
val type = DefaultPackets.C2S[state]?.get(packet::class) ?: throw UnknownPacketException(packet::class.java)
|
||||||
val id = getPacketId(version, state, type)
|
val id = getPacketId(version, state, type)
|
||||||
@ -90,7 +90,7 @@ class PacketEncoder(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun encode(context: ChannelHandlerContext, packet: C2SPacket, out: MutableList<Any>) {
|
override fun encode(context: ChannelHandlerContext, packet: C2SPacket, out: MutableList<Any>) {
|
||||||
out += encode(packet)
|
out += encode(packet) ?: return
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Minosoft
|
* 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.
|
* 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
|
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.buffer.ByteBuf
|
||||||
import io.netty.channel.ChannelHandlerContext
|
import io.netty.channel.ChannelHandlerContext
|
||||||
import io.netty.handler.codec.ByteToMessageDecoder
|
import io.netty.handler.codec.ByteToMessageDecoder
|
||||||
@ -23,11 +24,15 @@ class PacketDecryptor(
|
|||||||
) : ByteToMessageDecoder() {
|
) : ByteToMessageDecoder() {
|
||||||
|
|
||||||
override fun decode(context: ChannelHandlerContext, data: ByteBuf, out: MutableList<Any>) {
|
override fun decode(context: ChannelHandlerContext, data: ByteBuf, out: MutableList<Any>) {
|
||||||
val bytes = ByteArray(data.readableBytes())
|
val length = data.readableBytes()
|
||||||
data.readBytes(bytes)
|
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) }
|
out += context.alloc().buffer(decrypted.size).apply { writeBytes(decrypted) }
|
||||||
|
NetworkAllocator.free(decrypted)
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Minosoft
|
* 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.
|
* 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
|
package de.bixilon.minosoft.protocol.network.network.client.netty.pipeline.length
|
||||||
|
|
||||||
import de.bixilon.kutil.exception.FastException
|
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 de.bixilon.minosoft.protocol.network.network.client.netty.exceptions.ciritical.PacketTooLongException
|
||||||
import io.netty.buffer.ByteBuf
|
import io.netty.buffer.ByteBuf
|
||||||
import io.netty.channel.ChannelHandlerContext
|
import io.netty.channel.ChannelHandlerContext
|
||||||
@ -47,10 +49,10 @@ class LengthDecoder(
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
val array = ByteArray(length)
|
val array = NetworkAllocator.allocate(length)
|
||||||
buffer.readBytes(array)
|
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())
|
this.prototype.biomeSource = SpatialBiomeArray(buffer.readBiomeArray())
|
||||||
}
|
}
|
||||||
val length = buffer.readVarInt()
|
val length = buffer.readVarInt()
|
||||||
val data = ALLOCATOR.create(length)
|
val data = ALLOCATOR.allocate(length)
|
||||||
buffer.readByteArray(data, 0, length)
|
buffer.readByteArray(data, 0, length)
|
||||||
readingData = ChunkReadingData(data, PlayInByteBuffer(data, buffer.session), dimension, sectionBitMask)
|
readingData = ChunkReadingData(data, PlayInByteBuffer(data, buffer.session), dimension, sectionBitMask)
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user