Fix mod packets being processed after vanilla packets when received in the same tick.
Some checks failed
Publish / build (push) Has been cancelled
Push actions / labels (push) Has been cancelled

This commit is contained in:
LexManos 2026-08-10 21:56:47 -07:00
parent 3b981f4725
commit 1dab50ca00
No known key found for this signature in database
GPG key ID: 6E90061A7AE1F652
3 changed files with 34 additions and 1 deletions

View file

@ -15,6 +15,7 @@ import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.regex.Matcher;
@ -54,6 +55,7 @@ import net.minecraft.core.particles.ParticleTypes;
import net.minecraft.core.registries.Registries;
import net.minecraft.network.Connection;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.PacketListener;
import net.minecraft.network.RegistryFriendlyByteBuf;
import net.minecraft.network.VarInt;
import net.minecraft.network.chat.ClickEvent;
@ -107,6 +109,7 @@ import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.ListTag;
import net.minecraft.network.protocol.Packet;
import net.minecraft.network.protocol.PacketFlow;
import net.minecraft.network.protocol.PacketType;
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
import net.minecraft.network.protocol.common.custom.DiscardedPayload;
import net.minecraft.network.syncher.EntityDataSerializer;
@ -1305,4 +1308,32 @@ public final class ForgeHooks {
return Optional.of(ret);
}
// This is similar to PacketUtils.ensureRunningOnSameThread, we can't use the normal LogicalSidedProvider.WORKQUEUE because it is processed after packets.
// So any vanilla packets that are received after this packet, will be processed before our enqueued packet.
public static <MSG> void enqueuePacket(BiConsumer<MSG, CustomPayloadEvent.Context> handler, MSG packet, CustomPayloadEvent.Context context) {
var processor = LogicalSidedProvider.PACKETS.get(context.isClientSide());
if (!processor.isSameThread())
processor.scheduleIfPossible(context.getConnection().getPacketListener(), new DummyPacket<>(handler, packet, context));
else
handler.accept(packet, context);
}
private static final record DummyPacket<MSG>(
BiConsumer<MSG, CustomPayloadEvent.Context> handler,
MSG packet,
CustomPayloadEvent.Context context
) implements Packet<PacketListener> {
private static final PacketType<DummyPacket<?>> TYPE = new PacketType<>(PacketFlow.CLIENTBOUND, Identifier.fromNamespaceAndPath("forge", "dummy_for_schedualing"));
@Override
public PacketType<DummyPacket<?>> type() {
return TYPE;
}
@Override
public void handle(PacketListener listener) {
handler.accept(packet, context);
}
}
}

View file

@ -6,6 +6,7 @@
package net.minecraftforge.common.util;
import net.minecraft.client.Minecraft;
import net.minecraft.network.PacketProcessor;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.TickTask;
import net.minecraft.util.thread.BlockableEventLoop;
@ -21,6 +22,7 @@ import org.jetbrains.annotations.ApiStatus;
public class LogicalSidedProvider<T> {
public static final LogicalSidedProvider<BlockableEventLoop<? super TickTask>> WORKQUEUE = new LogicalSidedProvider<>(Supplier::get, Supplier::get);
public static final LogicalSidedProvider<Optional<Level>> CLIENTWORLD = new LogicalSidedProvider<>((c)-> Optional.of(c.get().level), (s)->Optional.empty());
public static final LogicalSidedProvider<PacketProcessor> PACKETS = new LogicalSidedProvider<>(client -> client.get().packetProcessor(), server -> server.get().packetProcessor());
public T get(LogicalSide side) {
return side == LogicalSide.CLIENT ? clientSide.apply(client) : serverSide.apply(server);

View file

@ -28,7 +28,7 @@ public interface SimpleFlow<BUF extends FriendlyByteBuf, BASE> extends SimplePro
*/
default <MSG extends BASE> SimpleFlow<BUF, BASE> addMain(Class<MSG> type, StreamCodec<BUF, MSG> codec, BiConsumer<MSG, CustomPayloadEvent.Context> handler) {
return add(type, codec, (msg, ctx) -> {
ctx.enqueueWork(() -> handler.accept(msg, ctx));
net.minecraftforge.common.ForgeHooks.enqueuePacket(handler, msg, ctx);
ctx.setPacketHandled(true);
});
}