diff --git a/src/main/java/com/mitchej123/hodgepodge/config/FixesConfig.java b/src/main/java/com/mitchej123/hodgepodge/config/FixesConfig.java index 96a2e6dec..c3d5c0e7c 100644 --- a/src/main/java/com/mitchej123/hodgepodge/config/FixesConfig.java +++ b/src/main/java/com/mitchej123/hodgepodge/config/FixesConfig.java @@ -40,6 +40,10 @@ public class FixesConfig { @Config.DefaultBoolean(true) public static boolean fixBogusIntegratedServerNPEs; + @Config.Comment("Send only the written bytes of FML proxy packets. FML sends the whole backing array of a packet's buffer, so mods that pass an untrimmed buffer also send its unused capacity as zeros (up to the next power of two, at least 256 bytes per packet).") + @Config.DefaultBoolean(true) + public static boolean fixProxyPacketPadding; + @Config.Comment("Patch Forge's @Optional.Interface processor to also strip Signature attribute entries (fixes TypeNotPresentException from Class.getGenericInterfaces when an optional interface's mod is missing)") @Config.DefaultBoolean(true) public static boolean fixForgeOptionalInterfaceSignature; diff --git a/src/main/java/com/mitchej123/hodgepodge/mixins/Mixins.java b/src/main/java/com/mitchej123/hodgepodge/mixins/Mixins.java index 5d3a77ed6..141c9a4f3 100644 --- a/src/main/java/com/mitchej123/hodgepodge/mixins/Mixins.java +++ b/src/main/java/com/mitchej123/hodgepodge/mixins/Mixins.java @@ -465,6 +465,10 @@ public enum Mixins implements IMixins { "minecraft.NetworkManagerAccessor") .setApplyIf(() -> FixesConfig.fixBogusIntegratedServerNPEs) .setPhase(Phase.EARLY)), + FIX_PROXY_PACKET_PADDING(new MixinBuilder("Send only the written bytes of FML proxy packets, not their buffer's unused capacity") + .addCommonMixins("fml.MixinFMLProxyPacket_TrimPayload") + .setApplyIf(() -> FixesConfig.fixProxyPacketPadding) + .setPhase(Phase.EARLY)), FIX_LAG_ON_INVENTORY_SYNC(new MixinBuilder("Fix inventory sync lag") .addCommonMixins("minecraft.MixinInventoryCrafting") .setApplyIf(() -> FixesConfig.fixInventorySyncLag) diff --git a/src/main/java/com/mitchej123/hodgepodge/mixins/early/fml/MixinFMLProxyPacket_TrimPayload.java b/src/main/java/com/mitchej123/hodgepodge/mixins/early/fml/MixinFMLProxyPacket_TrimPayload.java new file mode 100644 index 000000000..4a8b77083 --- /dev/null +++ b/src/main/java/com/mitchej123/hodgepodge/mixins/early/fml/MixinFMLProxyPacket_TrimPayload.java @@ -0,0 +1,23 @@ +package com.mitchej123.hodgepodge.mixins.early.fml; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +import com.mitchej123.hodgepodge.mixins.hooks.ProxyPacketPayload; + +import cpw.mods.fml.common.network.internal.FMLProxyPacket; +import io.netty.buffer.ByteBuf; + +@Mixin(FMLProxyPacket.class) +public class MixinFMLProxyPacket_TrimPayload { + + @Redirect( + method = { "toC17Packet", "toS3FPacket" }, + at = @At(value = "INVOKE", target = "Lio/netty/buffer/ByteBuf;array()[B", remap = false), + remap = false, + expect = 2) + private byte[] hodgepodge$sendWrittenBytesOnly(ByteBuf payload) { + return ProxyPacketPayload.withoutUnusedCapacity(payload); + } +} diff --git a/src/main/java/com/mitchej123/hodgepodge/mixins/hooks/ProxyPacketPayload.java b/src/main/java/com/mitchej123/hodgepodge/mixins/hooks/ProxyPacketPayload.java new file mode 100644 index 000000000..3069ee558 --- /dev/null +++ b/src/main/java/com/mitchej123/hodgepodge/mixins/hooks/ProxyPacketPayload.java @@ -0,0 +1,35 @@ +package com.mitchej123.hodgepodge.mixins.hooks; + +import java.util.Arrays; + +import io.netty.buffer.ByteBuf; + +/** + * FMLProxyPacket sends the whole backing array of its payload buffer. Mods that hand it an untrimmed buffer (such as a + * plain {@code Unpooled.buffer()}) send the buffer's unused capacity as trailing zeros: up to the next power of two, at + * least 256 bytes per packet. + */ +public final class ProxyPacketPayload { + + private ProxyPacketPayload() {} + + /** + * The payload's backing array without its unused capacity, the zeros after the written bytes. Everything up to the + * writer index is kept as before, including bytes before the reader index. The array is returned unchanged if + * nothing follows the written bytes, if anything after them is not zero, or if nothing was written: a client to + * server payload of length 0 arrives as null and fails in FML, so empty payloads keep their zeros. + */ + public static byte[] withoutUnusedCapacity(ByteBuf payload) { + final byte[] array = payload.array(); + final int end = payload.arrayOffset() + payload.writerIndex(); + if (end <= 0 || end >= array.length) { + return array; + } + for (int i = end; i < array.length; i++) { + if (array[i] != 0) { + return array; + } + } + return Arrays.copyOf(array, end); + } +}