Update matter registry networking

This commit is contained in:
DBotThePony 2024-08-13 00:38:12 +07:00
parent 5b403d3d47
commit 0db98ef8f8
Signed by: DBot
GPG Key ID: DCC23B5715498507
2 changed files with 100 additions and 116 deletions

View File

@ -53,14 +53,6 @@ fun InputStream.readBigDecimal(): BigDecimal {
return BigDecimal(BigInteger(bytes), scale) return BigDecimal(BigInteger(bytes), scale)
} }
fun InputStream.readBinaryComponent(): Component? {
return Component.Serializer.fromJson(readBinaryJson())
}
fun OutputStream.writeBinaryComponent(component: Component) {
writeBinaryJson(Component.Serializer.toJsonTree(component))
}
fun <S : OutputStream, V> S.writeCollection(collection: Collection<V>, writer: S.(V) -> Unit) { fun <S : OutputStream, V> S.writeCollection(collection: Collection<V>, writer: S.(V) -> Unit) {
writeVarIntLE(collection.size) writeVarIntLE(collection.size)
@ -246,12 +238,3 @@ fun OutputStream.writeBinaryString(input: String) {
writeVarIntLE(bytes.size) writeVarIntLE(bytes.size)
write(bytes) write(bytes)
} }
fun InputStream.readResourceLocation(): ResourceLocation {
return ResourceLocation(readBinaryString(), readBinaryString())
}
fun OutputStream.writeResourceLocation(value: ResourceLocation) {
writeBinaryString(value.namespace)
writeBinaryString(value.path)
}

View File

@ -11,6 +11,7 @@ import com.google.gson.JsonSyntaxException
import com.mojang.brigadier.arguments.StringArgumentType import com.mojang.brigadier.arguments.StringArgumentType
import com.mojang.brigadier.context.CommandContext import com.mojang.brigadier.context.CommandContext
import com.mojang.serialization.JsonOps import com.mojang.serialization.JsonOps
import io.netty.buffer.ByteBufAllocator
import it.unimi.dsi.fastutil.io.FastByteArrayInputStream import it.unimi.dsi.fastutil.io.FastByteArrayInputStream
import it.unimi.dsi.fastutil.io.FastByteArrayOutputStream import it.unimi.dsi.fastutil.io.FastByteArrayOutputStream
import it.unimi.dsi.fastutil.objects.Object2BooleanFunction import it.unimi.dsi.fastutil.objects.Object2BooleanFunction
@ -26,8 +27,10 @@ import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet
import net.minecraft.ChatFormatting import net.minecraft.ChatFormatting
import net.minecraft.commands.CommandSourceStack import net.minecraft.commands.CommandSourceStack
import net.minecraft.commands.Commands import net.minecraft.commands.Commands
import net.minecraft.core.RegistryAccess
import net.minecraft.core.registries.BuiltInRegistries import net.minecraft.core.registries.BuiltInRegistries
import net.minecraft.network.FriendlyByteBuf import net.minecraft.network.FriendlyByteBuf
import net.minecraft.network.RegistryFriendlyByteBuf
import net.minecraft.network.chat.Component import net.minecraft.network.chat.Component
import net.minecraft.network.chat.MutableComponent import net.minecraft.network.chat.MutableComponent
import net.minecraft.network.codec.StreamCodec import net.minecraft.network.codec.StreamCodec
@ -53,13 +56,13 @@ import net.minecraft.world.level.ItemLike
import net.neoforged.bus.api.IEventBus import net.neoforged.bus.api.IEventBus
import net.neoforged.fml.ModList import net.neoforged.fml.ModList
import net.neoforged.neoforge.capabilities.Capabilities import net.neoforged.neoforge.capabilities.Capabilities
import net.neoforged.neoforge.common.crafting.IShapedRecipe
import net.neoforged.neoforge.event.AddReloadListenerEvent import net.neoforged.neoforge.event.AddReloadListenerEvent
import net.neoforged.neoforge.event.OnDatapackSyncEvent import net.neoforged.neoforge.event.OnDatapackSyncEvent
import net.neoforged.neoforge.event.RegisterCommandsEvent import net.neoforged.neoforge.event.RegisterCommandsEvent
import net.neoforged.neoforge.event.entity.player.ItemTooltipEvent import net.neoforged.neoforge.event.entity.player.ItemTooltipEvent
import net.neoforged.neoforge.event.server.ServerStartedEvent import net.neoforged.neoforge.event.server.ServerStartedEvent
import net.neoforged.neoforge.network.PacketDistributor import net.neoforged.neoforge.network.PacketDistributor
import net.neoforged.neoforge.network.connection.ConnectionType
import net.neoforged.neoforge.network.handling.IPayloadContext import net.neoforged.neoforge.network.handling.IPayloadContext
import net.neoforged.neoforge.registries.DeferredRegister import net.neoforged.neoforge.registries.DeferredRegister
import net.neoforged.neoforge.server.command.EnumArgument import net.neoforged.neoforge.server.command.EnumArgument
@ -86,6 +89,7 @@ import ru.dbotthepony.mc.otm.core.getReverseTag
import ru.dbotthepony.mc.otm.core.isNotEmpty import ru.dbotthepony.mc.otm.core.isNotEmpty
import ru.dbotthepony.mc.otm.core.math.Decimal import ru.dbotthepony.mc.otm.core.math.Decimal
import ru.dbotthepony.mc.otm.core.math.isZero import ru.dbotthepony.mc.otm.core.math.isZero
import ru.dbotthepony.mc.otm.core.readComponent
import ru.dbotthepony.mc.otm.core.readItemType import ru.dbotthepony.mc.otm.core.readItemType
import ru.dbotthepony.mc.otm.core.registryName import ru.dbotthepony.mc.otm.core.registryName
import ru.dbotthepony.mc.otm.core.stream import ru.dbotthepony.mc.otm.core.stream
@ -97,6 +101,7 @@ import ru.dbotthepony.mc.otm.core.util.readBinaryComponent
import ru.dbotthepony.mc.otm.core.util.readCollection import ru.dbotthepony.mc.otm.core.util.readCollection
import ru.dbotthepony.mc.otm.core.util.writeBinaryComponent import ru.dbotthepony.mc.otm.core.util.writeBinaryComponent
import ru.dbotthepony.mc.otm.core.util.writeCollection import ru.dbotthepony.mc.otm.core.util.writeCollection
import ru.dbotthepony.mc.otm.core.writeComponent
import ru.dbotthepony.mc.otm.core.writeItemType import ru.dbotthepony.mc.otm.core.writeItemType
import ru.dbotthepony.mc.otm.matter.MatterManager.Finder import ru.dbotthepony.mc.otm.matter.MatterManager.Finder
import ru.dbotthepony.mc.otm.milliTime import ru.dbotthepony.mc.otm.milliTime
@ -1706,7 +1711,7 @@ object MatterManager {
matterValues[item] = value matterValues[item] = value
} }
syncRegistry(PacketDistributor::sendToAllPlayers) syncRegistry(server.registryAccess(), PacketDistributor::sendToAllPlayers)
} }
fun onDataPackSync(event: OnDatapackSyncEvent) { fun onDataPackSync(event: OnDatapackSyncEvent) {
@ -1714,9 +1719,9 @@ object MatterManager {
return return
if (event.player == null) { if (event.player == null) {
syncRegistry(PacketDistributor::sendToAllPlayers) syncRegistry(event.playerList.server.registryAccess(), PacketDistributor::sendToAllPlayers)
} else { } else {
syncRegistry { PacketDistributor.sendToPlayer(event.player as ServerPlayer, it) } syncRegistry(event.playerList.server.registryAccess()) { PacketDistributor.sendToPlayer(event.player as ServerPlayer, it) }
} }
} }
@ -1732,10 +1737,16 @@ object MatterManager {
private val receivedPackets = ArrayList<SyncPacket>() private val receivedPackets = ArrayList<SyncPacket>()
private fun syncRegistry(distributor: (CustomPacketPayload) -> Unit) { private fun syncRegistry(registry: RegistryAccess, distributor: (CustomPacketPayload) -> Unit) {
val time = SystemTime() val time = SystemTime()
val stream = FastByteArrayOutputStream() val writable = ByteBufAllocator.DEFAULT.heapBuffer()
val data = DataOutputStream(stream)
val chunks = ArrayList<SyncPacket>()
val totalSize: Int
var compressedSize: Int = 0
try {
val data = RegistryFriendlyByteBuf(writable, registry, ConnectionType.NEOFORGE)
var commentsSize = commentary.size var commentsSize = commentary.size
data.writeInt(matterValues.size) data.writeInt(matterValues.size)
@ -1748,10 +1759,10 @@ object MatterManager {
if (comment != null) { if (comment != null) {
commentsSize-- commentsSize--
data.write(1) data.writeBoolean(true)
data.writeCollection(comment, OutputStream::writeBinaryComponent) data.writeCollection(comment) { _, it -> data.writeComponent(it) }
} else { } else {
data.write(0) data.writeBoolean(false)
} }
} }
@ -1760,29 +1771,32 @@ object MatterManager {
for ((k, v) in commentary) { for ((k, v) in commentary) {
if (!matterValues.containsKey(k)) { if (!matterValues.containsKey(k)) {
data.writeItemType(k) data.writeItemType(k)
data.writeCollection(v, OutputStream::writeBinaryComponent) data.writeCollection(v) { _, it -> data.writeComponent(it) }
} }
} }
val deflater = Deflater(5) val deflater = Deflater(5)
deflater.setInput(stream.array, 0, stream.length) deflater.setInput(data.array(), data.arrayOffset(), data.readableBytes())
deflater.finish() deflater.finish()
val chunks = ArrayList<SyncPacket>() totalSize = data.readableBytes()
var totalSize = 0
var first = true var first = true
while (true) { while (true) {
val bytes = ByteArray(2 shl 20 - 1024) val bytes = ByteArray(2 shl 20 - 1024 /* 1 MiB - 1 KiB */)
val written = deflater.deflate(bytes) val written = deflater.deflate(bytes)
if (written == 0) { if (written == 0) {
break break
} else { } else {
totalSize += written compressedSize += written
chunks.add(SyncPacket(bytes, written, if (first) { first = false; FIRST } else NORMAL)) chunks.add(SyncPacket(bytes, written, if (first) { first = false; FIRST } else NORMAL))
} }
} }
} finally {
writable.release()
}
if (chunks.size == 1) { if (chunks.size == 1) {
chunks[0].mode = FIRST_AND_LAST chunks[0].mode = FIRST_AND_LAST
@ -1790,14 +1804,14 @@ object MatterManager {
chunks.last().mode = LAST chunks.last().mode = LAST
} }
LOGGER.debug("Encoding matter registry packet took ${time.millis}ms, (${stream.length} bytes total, $totalSize bytes compressed)") LOGGER.debug("Encoding matter registry packets took ${time.millis}ms, (${totalSize} bytes total, $compressedSize bytes compressed)")
for (chunk in chunks) { for (chunk in chunks) {
distributor.invoke(chunk) distributor.invoke(chunk)
} }
} }
private fun playRegistryPackets() { private fun playRegistryPackets(registry: RegistryAccess) {
val time = SystemTime() val time = SystemTime()
var totalCompressedSize = 0 var totalCompressedSize = 0
@ -1820,44 +1834,28 @@ object MatterManager {
receivedPackets.clear() receivedPackets.clear()
val chunks = ArrayList<ByteArray>() val spliced = ByteBufAllocator.DEFAULT.buffer(receivedPackets.sumOf { it.length })
var size = 0
try {
val buffer = ByteArray(2 shl 16)
val inflater = Inflater() val inflater = Inflater()
inflater.setInput(compressed) inflater.setInput(compressed)
while (!inflater.finished()) { while (!inflater.finished()) {
val chunk = ByteArray(2 shl 16) val inflated = inflater.inflate(buffer)
val inflated = inflater.inflate(chunk)
if (inflated == 0) { if (inflated == 0) {
break break
} else { } else {
size += inflated spliced.writeBytes(buffer, 0, inflated)
if (size >= 1 shl 24 /* 16 MiB */) { if (spliced.writerIndex() >= 1 shl 24 /* 16 MiB */) {
throw IndexOutOfBoundsException("Pipe Bomb") throw IndexOutOfBoundsException("Pipe Bomb")
} }
if (inflated == 2 shl 16) {
chunks.add(chunk)
} else {
chunks.add(chunk.copyOfRange(0, inflated))
}
}
}
val spliced = ByteArray(size)
var pointer2 = 0
for (chunk in chunks) {
for (i in chunk.indices) {
spliced[pointer2++] = chunk[i]
} }
} }
val stream = FastByteArrayInputStream(spliced) val data = RegistryFriendlyByteBuf(spliced, registry, ConnectionType.NEOFORGE)
val data = DataInputStream(stream)
val valuesSize = data.readInt() val valuesSize = data.readInt()
matterValues.clear() matterValues.clear()
@ -1867,8 +1865,8 @@ object MatterManager {
val type = data.readItemType() val type = data.readItemType()
check(matterValues.put(type, data.readMatterValue()) == null) { "Duplicate item type $type" } check(matterValues.put(type, data.readMatterValue()) == null) { "Duplicate item type $type" }
if (data.read() > 0) { if (data.readBoolean()) {
commentary[type] = data.readCollection { readBinaryComponent()!! } commentary[type] = data.readCollection(::ArrayList) { data.readComponent() }
} }
} }
@ -1876,10 +1874,13 @@ object MatterManager {
for (i in 0 until commentsSize) { for (i in 0 until commentsSize) {
val type = data.readItemType() val type = data.readItemType()
check(commentary.put(type, data.readCollection { readBinaryComponent()!! }) == null) { "Duplicate commentary item type $type" } check(commentary.put(type, data.readCollection(::ArrayList) { data.readComponent() }) == null) { "Duplicate commentary item type $type" }
} }
LOGGER.debug("Decoding matter registry packets took ${time.millis}ms ($totalCompressedSize bytes compressed, $size bytes total)") LOGGER.debug("Decoding matter registry packets took ${time.millis}ms ($totalCompressedSize bytes compressed, ${spliced.writerIndex()} bytes total)")
} finally {
spliced.release()
}
} }
fun readSyncPacket(buff: FriendlyByteBuf): SyncPacket { fun readSyncPacket(buff: FriendlyByteBuf): SyncPacket {
@ -1918,11 +1919,11 @@ object MatterManager {
receivedPackets.add(this) receivedPackets.add(this)
} else if (mode == LAST) { } else if (mode == LAST) {
receivedPackets.add(this) receivedPackets.add(this)
playRegistryPackets() playRegistryPackets(context.player().registryAccess())
} else if (mode == FIRST_AND_LAST) { } else if (mode == FIRST_AND_LAST) {
receivedPackets.clear() receivedPackets.clear()
receivedPackets.add(this) receivedPackets.add(this)
playRegistryPackets() playRegistryPackets(context.player().registryAccess())
} else { } else {
receivedPackets.add(this) receivedPackets.add(this)
} }