Fabric API

Fabric API

106M Downloads

IOOBE with ReplayMod in Singleplayer as of FAPI 0.91+1.20.2

Johni0702 opened this issue ยท 0 comments

commented

Trying to run ReplayMod (not yet released 1.20.2 version) alongside FAPI 0.91 (or 0.91.1) results in the following IOOBE and corresponding Connection Lost/Internal Exception: ... screen when opening a Singleplayer world:

[21:39:34] [Netty Local Client IO #0/ERROR]: Encountered exception while handling in channel with name "c:version"
java.lang.IndexOutOfBoundsException: readerIndex(2) + length(1) exceeds writerIndex(2): UnpooledByteBufAllocator$InstrumentedUnpooledUnsafeHeapByteBuf(ridx: 2, widx: 2, cap: 256)
	at io.netty.buffer.AbstractByteBuf.checkReadableBytes0(AbstractByteBuf.java:1442) ~[netty-buffer-4.1.97.Final.jar:?]
	at io.netty.buffer.AbstractByteBuf.readByte(AbstractByteBuf.java:730) ~[netty-buffer-4.1.97.Final.jar:?]
	at net.minecraft.class_8703.method_53016(class_8703.java:28) ~[client-intermediary.jar:?]
	at net.minecraft.class_2540.method_10816(class_2540.java:525) ~[client-intermediary.jar:?]
	at net.minecraft.class_2540.method_10799(class_2540.java:374) ~[client-intermediary.jar:?]
	at net.minecraft.class_2540.method_10787(class_2540.java:370) ~[client-intermediary.jar:?]
	at net.fabricmc.fabric.impl.networking.CommonVersionPayload.<init>(CommonVersionPayload.java:27) ~[fabric-networking-api-v1-3.1.1+e3b69503a0-628d589b36e3c75a.jar:?]
	at net.fabricmc.fabric.impl.networking.client.ClientNetworkingImpl.lambda$clientInit$2(ClientNetworkingImpl.java:157) ~[fabric-networking-api-v1-3.1.1+e3b69503a0-628d589b36e3c75a.jar:?]
[...]
Full stacktrace
[21:39:34] [Netty Local Client IO #0/ERROR]: Encountered exception while handling in channel with name "c:version"
java.lang.IndexOutOfBoundsException: readerIndex(2) + length(1) exceeds writerIndex(2): UnpooledByteBufAllocator$InstrumentedUnpooledUnsafeHeapByteBuf(ridx: 2, widx: 2, cap: 256)
	at io.netty.buffer.AbstractByteBuf.checkReadableBytes0(AbstractByteBuf.java:1442) ~[netty-buffer-4.1.97.Final.jar:?]
	at io.netty.buffer.AbstractByteBuf.readByte(AbstractByteBuf.java:730) ~[netty-buffer-4.1.97.Final.jar:?]
	at net.minecraft.class_8703.method_53016(class_8703.java:28) ~[client-intermediary.jar:?]
	at net.minecraft.class_2540.method_10816(class_2540.java:525) ~[client-intermediary.jar:?]
	at net.minecraft.class_2540.method_10799(class_2540.java:374) ~[client-intermediary.jar:?]
	at net.minecraft.class_2540.method_10787(class_2540.java:370) ~[client-intermediary.jar:?]
	at net.fabricmc.fabric.impl.networking.CommonVersionPayload.<init>(CommonVersionPayload.java:27) ~[fabric-networking-api-v1-3.1.1+e3b69503a0-628d589b36e3c75a.jar:?]
	at net.fabricmc.fabric.impl.networking.client.ClientNetworkingImpl.lambda$clientInit$2(ClientNetworkingImpl.java:157) ~[fabric-networking-api-v1-3.1.1+e3b69503a0-628d589b36e3c75a.jar:?]
	at net.fabricmc.fabric.api.client.networking.v1.ClientConfigurationNetworking.lambda$wrapUntyped$0(ClientConfigurationNetworking.java:365) ~[fabric-networking-api-v1-3.1.1+e3b69503a0-628d589b36e3c75a.jar:?]
	at net.fabricmc.fabric.impl.networking.client.ClientConfigurationNetworkAddon.receive(ClientConfigurationNetworkAddon.java:77) ~[fabric-networking-api-v1-3.1.1+e3b69503a0-628d589b36e3c75a.jar:?]
	at net.fabricmc.fabric.impl.networking.client.ClientConfigurationNetworkAddon.receive(ClientConfigurationNetworkAddon.java:42) ~[fabric-networking-api-v1-3.1.1+e3b69503a0-628d589b36e3c75a.jar:?]
	at net.fabricmc.fabric.impl.networking.AbstractChanneledNetworkAddon.handle(AbstractChanneledNetworkAddon.java:99) ~[fabric-networking-api-v1-3.1.1+e3b69503a0-628d589b36e3c75a.jar:?]
	at net.minecraft.class_8673.handler$zgj000$fabric-networking-api-v1$onCustomPayload(class_8673.java:1043) ~[client-intermediary.jar:?]
	at net.minecraft.class_8673.method_52780(class_8673.java) ~[client-intermediary.jar:?]
	at net.minecraft.class_2658.method_53024(class_2658.java:92) ~[client-intermediary.jar:?]
	at net.minecraft.class_2658.method_11054(class_2658.java:31) ~[client-intermediary.jar:?]
	at net.minecraft.class_2535.method_10759(class_2535.java:196) ~[client-intermediary.jar:?]
	at net.minecraft.class_2535.method_10770(class_2535.java:181) ~[client-intermediary.jar:?]
	at net.minecraft.class_2535.channelRead0(class_2535.java:60) ~[client-intermediary.jar:?]
	at io.netty.channel.SimpleChannelInboundHandler.channelRead(SimpleChannelInboundHandler.java:99) ~[netty-transport-4.1.97.Final.jar:?]
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:444) ~[netty-transport-4.1.97.Final.jar:?]
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420) ~[netty-transport-4.1.97.Final.jar:?]
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412) ~[netty-transport-4.1.97.Final.jar:?]
	at io.netty.handler.flow.FlowControlHandler.dequeue(FlowControlHandler.java:202) ~[netty-handler-4.1.97.Final.jar:?]
	at io.netty.handler.flow.FlowControlHandler.channelRead(FlowControlHandler.java:164) ~[netty-handler-4.1.97.Final.jar:?]
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:442) ~[netty-transport-4.1.97.Final.jar:?]
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420) ~[netty-transport-4.1.97.Final.jar:?]
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412) ~[netty-transport-4.1.97.Final.jar:?]
	at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:103) ~[netty-codec-4.1.97.Final.jar:?]
	at io.netty.handler.codec.MessageToMessageCodec.channelRead(MessageToMessageCodec.java:111) ~[netty-codec-4.1.97.Final.jar:?]
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:442) ~[netty-transport-4.1.97.Final.jar:?]
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420) ~[netty-transport-4.1.97.Final.jar:?]
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412) ~[netty-transport-4.1.97.Final.jar:?]
	at io.netty.channel.ChannelInboundHandlerAdapter.channelRead(ChannelInboundHandlerAdapter.java:93) ~[netty-transport-4.1.97.Final.jar:?]
	at com.replaymod.recording.packet.PacketListener$DecodedPacketListener.channelRead(PacketListener.java:547) ~[replaymod-1.20.2-2.6.13-5-gb8ab7aa.jar:?]
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:444) ~[netty-transport-4.1.97.Final.jar:?]
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420) ~[netty-transport-4.1.97.Final.jar:?]
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412) ~[netty-transport-4.1.97.Final.jar:?]
	at io.netty.channel.ChannelInboundHandlerAdapter.channelRead(ChannelInboundHandlerAdapter.java:93) ~[netty-transport-4.1.97.Final.jar:?]
	at com.replaymod.recording.packet.PacketListener.channelRead(PacketListener.java:397) ~[replaymod-1.20.2-2.6.13-5-gb8ab7aa.jar:?]
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:444) ~[netty-transport-4.1.97.Final.jar:?]
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420) ~[netty-transport-4.1.97.Final.jar:?]
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412) ~[netty-transport-4.1.97.Final.jar:?]
	at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410) ~[netty-transport-4.1.97.Final.jar:?]
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:440) ~[netty-transport-4.1.97.Final.jar:?]
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420) ~[netty-transport-4.1.97.Final.jar:?]
	at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919) ~[netty-transport-4.1.97.Final.jar:?]
	at io.netty.channel.local.LocalChannel.readInbound(LocalChannel.java:299) ~[netty-transport-4.1.97.Final.jar:?]
	at io.netty.channel.local.LocalChannel.doBeginRead(LocalChannel.java:322) ~[netty-transport-4.1.97.Final.jar:?]
	at io.netty.channel.AbstractChannel$AbstractUnsafe.beginRead(AbstractChannel.java:834) ~[netty-transport-4.1.97.Final.jar:?]
	at io.netty.channel.DefaultChannelPipeline$HeadContext.read(DefaultChannelPipeline.java:1362) ~[netty-transport-4.1.97.Final.jar:?]
	at io.netty.channel.AbstractChannelHandlerContext.invokeRead(AbstractChannelHandlerContext.java:835) ~[netty-transport-4.1.97.Final.jar:?]
	at io.netty.channel.AbstractChannelHandlerContext.read(AbstractChannelHandlerContext.java:814) ~[netty-transport-4.1.97.Final.jar:?]
	at io.netty.handler.flow.FlowControlHandler.read(FlowControlHandler.java:144) ~[netty-handler-4.1.97.Final.jar:?]
	at io.netty.channel.AbstractChannelHandlerContext.invokeRead(AbstractChannelHandlerContext.java:837) ~[netty-transport-4.1.97.Final.jar:?]
	at io.netty.channel.AbstractChannelHandlerContext.read(AbstractChannelHandlerContext.java:814) ~[netty-transport-4.1.97.Final.jar:?]
	at io.netty.channel.DefaultChannelPipeline.read(DefaultChannelPipeline.java:1004) ~[netty-transport-4.1.97.Final.jar:?]
	at io.netty.channel.AbstractChannel.read(AbstractChannel.java:290) ~[netty-transport-4.1.97.Final.jar:?]
	at io.netty.channel.DefaultChannelPipeline$HeadContext.readIfIsAutoRead(DefaultChannelPipeline.java:1422) ~[netty-transport-4.1.97.Final.jar:?]
	at io.netty.channel.DefaultChannelPipeline$HeadContext.channelReadComplete(DefaultChannelPipeline.java:1417) ~[netty-transport-4.1.97.Final.jar:?]
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelReadComplete(AbstractChannelHandlerContext.java:482) ~[netty-transport-4.1.97.Final.jar:?]
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelReadComplete(AbstractChannelHandlerContext.java:463) ~[netty-transport-4.1.97.Final.jar:?]
	at io.netty.channel.DefaultChannelPipeline.fireChannelReadComplete(DefaultChannelPipeline.java:925) ~[netty-transport-4.1.97.Final.jar:?]
	at io.netty.channel.local.LocalChannel.readInbound(LocalChannel.java:302) ~[netty-transport-4.1.97.Final.jar:?]
	at io.netty.channel.local.LocalChannel.doBeginRead(LocalChannel.java:322) ~[netty-transport-4.1.97.Final.jar:?]
	at io.netty.channel.AbstractChannel$AbstractUnsafe.beginRead(AbstractChannel.java:834) ~[netty-transport-4.1.97.Final.jar:?]
	at io.netty.channel.DefaultChannelPipeline$HeadContext.read(DefaultChannelPipeline.java:1362) ~[netty-transport-4.1.97.Final.jar:?]
	at io.netty.channel.AbstractChannelHandlerContext.invokeRead(AbstractChannelHandlerContext.java:835) ~[netty-transport-4.1.97.Final.jar:?]
	at io.netty.channel.AbstractChannelHandlerContext.read(AbstractChannelHandlerContext.java:814) ~[netty-transport-4.1.97.Final.jar:?]
	at io.netty.handler.flow.FlowControlHandler.read(FlowControlHandler.java:144) ~[netty-handler-4.1.97.Final.jar:?]
	at io.netty.channel.AbstractChannelHandlerContext.invokeRead(AbstractChannelHandlerContext.java:837) ~[netty-transport-4.1.97.Final.jar:?]
	at io.netty.channel.AbstractChannelHandlerContext.read(AbstractChannelHandlerContext.java:814) ~[netty-transport-4.1.97.Final.jar:?]
	at io.netty.channel.DefaultChannelPipeline.read(DefaultChannelPipeline.java:1004) ~[netty-transport-4.1.97.Final.jar:?]
	at io.netty.channel.AbstractChannel.read(AbstractChannel.java:290) ~[netty-transport-4.1.97.Final.jar:?]
	at io.netty.channel.DefaultChannelPipeline$HeadContext.readIfIsAutoRead(DefaultChannelPipeline.java:1422) ~[netty-transport-4.1.97.Final.jar:?]
	at io.netty.channel.DefaultChannelPipeline$HeadContext.channelReadComplete(DefaultChannelPipeline.java:1417) ~[netty-transport-4.1.97.Final.jar:?]
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelReadComplete(AbstractChannelHandlerContext.java:482) ~[netty-transport-4.1.97.Final.jar:?]
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelReadComplete(AbstractChannelHandlerContext.java:463) ~[netty-transport-4.1.97.Final.jar:?]
	at io.netty.channel.DefaultChannelPipeline.fireChannelReadComplete(DefaultChannelPipeline.java:925) ~[netty-transport-4.1.97.Final.jar:?]
	at io.netty.channel.local.LocalChannel.readInbound(LocalChannel.java:302) ~[netty-transport-4.1.97.Final.jar:?]
	at io.netty.channel.local.LocalChannel.finishPeerRead0(LocalChannel.java:445) ~[netty-transport-4.1.97.Final.jar:?]
	at io.netty.channel.local.LocalChannel.access$400(LocalChannel.java:50) ~[netty-transport-4.1.97.Final.jar:?]
	at io.netty.channel.local.LocalChannel$5.run(LocalChannel.java:403) ~[netty-transport-4.1.97.Final.jar:?]
	at io.netty.util.concurrent.AbstractEventExecutor.runTask(AbstractEventExecutor.java:174) ~[netty-common-4.1.97.Final.jar:?]
	at io.netty.channel.DefaultEventLoop.run(DefaultEventLoop.java:54) ~[netty-transport-4.1.97.Final.jar:?]
	at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:997) ~[netty-common-4.1.97.Final.jar:?]
	at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) ~[netty-common-4.1.97.Final.jar:?]
	at java.lang.Thread.run(Thread.java:833) ~[?:?]

ReplayMod, when recording Singleplayer where packets are passed between server and client as Packet objects, needs to serialize Packet objects so it can write them to the recording file. The serialization works by calling Packet.write on the packet. It does so on the netty thread before MC's packet handler, you can see the PacketListener.channelRead method in the full stacktrace.
FAPI's UntypedPayload.write however seems to consume its internal buffer when it is called, and so subsequent accesses to that buffer (in above case by FAPI's regular packet handler) will see an empty buffer.

If there's no deeper reason behind this, then the issue can be easily fixed by replacing the writeBytes call with one which does not advance the readerIndex of the source ByteBuf:

diff --git a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/payload/UntypedPayload.java b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/payload/UntypedPayload.java
index 028734a4..84bf92f3 100644
--- a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/payload/UntypedPayload.java
+++ b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/payload/UntypedPayload.java
@@ -42,6 +42,6 @@ public record UntypedPayload(Identifier id, PacketByteBuf buffer) implements Res
 
        @Override
        public void write(PacketByteBuf buf) {
-               buf.writeBytes(buffer);
+               buf.writeBytes(buffer, buffer.readerIndex(), buffer.readableBytes());
        }
 }

Side note: If FAPI provides a way to broadcast custom packets (I'm not familiar with it, so idk), then that may cause similar issues because the same packet may need to be serialized multiple times, once for each receiver, in that scenario as well, and so all but the first receiver would just get an empty packet.