mirror of
https://github.com/neoforged/NeoForge.git
synced 2025-12-10 12:08:25 -06:00
Add separate client-side payload handler registration (#2272)
This commit is contained in:
parent
f4117d2bdb
commit
fee486f017
@ -47,7 +47,7 @@
|
||||
+
|
||||
+ // Neo: Handle modded payloads. Vanilla payloads do not get sent to the modded handling pass. Additional payloads cannot be registered in the minecraft domain.
|
||||
+ if (net.neoforged.neoforge.network.registration.NetworkRegistry.isModdedPayload(p_295727_.payload())) {
|
||||
+ net.neoforged.neoforge.network.registration.NetworkRegistry.handleModdedPayload(this, p_295727_);
|
||||
+ net.neoforged.neoforge.client.network.registration.ClientNetworkRegistry.handleModdedPayload(this, p_295727_);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
|
||||
@ -17,7 +17,7 @@
|
||||
+ // Neo: Fallback detection layer for vanilla servers
|
||||
+ if (this.connectionType.isOther()) {
|
||||
+ this.initializedConnection = true;
|
||||
+ net.neoforged.neoforge.network.registration.NetworkRegistry.initializeOtherConnection(this);
|
||||
+ net.neoforged.neoforge.client.network.registration.ClientNetworkRegistry.initializeOtherConnection(this);
|
||||
+ }
|
||||
}
|
||||
|
||||
@ -45,7 +45,7 @@
|
||||
+ // Packets can only be sent after the outbound protocol is set up again
|
||||
+ if (!this.initializedConnection && this.connectionType.isOther()) {
|
||||
+ // Neo: Fallback detection for servers with a delayed brand payload (BungeeCord)
|
||||
+ net.neoforged.neoforge.network.registration.NetworkRegistry.initializeOtherConnection(this);
|
||||
+ net.neoforged.neoforge.client.network.registration.ClientNetworkRegistry.initializeOtherConnection(this);
|
||||
+ }
|
||||
+ net.neoforged.neoforge.network.registration.NetworkRegistry.onConfigurationFinished(this);
|
||||
this.connection.send(ServerboundFinishConfigurationPacket.INSTANCE);
|
||||
@ -67,14 +67,14 @@
|
||||
+ // Handle the query payload by responding with the client's network channels. Update the connection type accordingly.
|
||||
+ if (packet.payload() instanceof net.neoforged.neoforge.network.payload.ModdedNetworkQueryPayload) {
|
||||
+ this.connectionType = net.neoforged.neoforge.network.connection.ConnectionType.NEOFORGE;
|
||||
+ net.neoforged.neoforge.network.registration.NetworkRegistry.onNetworkQuery(this);
|
||||
+ net.neoforged.neoforge.client.network.registration.ClientNetworkRegistry.onNetworkQuery(this);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ // Receiving a modded network payload implies a successful negotiation by the server.
|
||||
+ if (packet.payload() instanceof net.neoforged.neoforge.network.payload.ModdedNetworkPayload moddedNetworkPayload) {
|
||||
+ this.initializedConnection = true;
|
||||
+ net.neoforged.neoforge.network.registration.NetworkRegistry.initializeNeoForgeConnection(this, moddedNetworkPayload.setup());
|
||||
+ net.neoforged.neoforge.client.network.registration.ClientNetworkRegistry.initializeNeoForgeConnection(this, moddedNetworkPayload.setup());
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
@ -87,7 +87,7 @@
|
||||
+ // Receiving a brand payload without having transitioned to a Neo connection implies a non-modded connection has begun.
|
||||
+ if (this.connectionType.isOther() && packet.payload() instanceof net.minecraft.network.protocol.common.custom.BrandPayload) {
|
||||
+ this.initializedConnection = true;
|
||||
+ net.neoforged.neoforge.network.registration.NetworkRegistry.initializeOtherConnection(this);
|
||||
+ net.neoforged.neoforge.client.network.registration.ClientNetworkRegistry.initializeOtherConnection(this);
|
||||
+ // Continue processing the brand payload
|
||||
+ }
|
||||
+
|
||||
|
||||
@ -5,47 +5,19 @@
|
||||
|
||||
package net.neoforged.neoforge.client.internal;
|
||||
|
||||
import java.util.Objects;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.multiplayer.ClientLevel;
|
||||
import net.minecraft.client.multiplayer.ClientPacketListener;
|
||||
import net.minecraft.core.HolderLookup;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.network.protocol.common.ClientCommonPacketListener;
|
||||
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.util.thread.BlockableEventLoop;
|
||||
import net.minecraft.world.item.TooltipFlag;
|
||||
import net.neoforged.neoforge.client.network.handlers.ClientPayloadHandler;
|
||||
import net.neoforged.neoforge.client.network.handling.ClientPayloadContext;
|
||||
import net.neoforged.neoforge.internal.NeoForgeProxy;
|
||||
import net.neoforged.neoforge.network.handling.IPayloadContext;
|
||||
import net.neoforged.neoforge.network.payload.ClientDispatchPayload;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@ApiStatus.Internal
|
||||
public class NeoForgeClientProxy extends NeoForgeProxy {
|
||||
@Override
|
||||
public void sendToServer(CustomPacketPayload payload, CustomPacketPayload... payloads) {
|
||||
ClientPacketListener listener = Objects.requireNonNull(Minecraft.getInstance().getConnection());
|
||||
listener.send(payload);
|
||||
for (CustomPacketPayload otherPayload : payloads) {
|
||||
listener.send(otherPayload);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public IPayloadContext newClientPayloadContext(ClientCommonPacketListener listener, ResourceLocation payloadId) {
|
||||
return new ClientPayloadContext(listener, payloadId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleClientPayload(ClientDispatchPayload payload, IPayloadContext context) {
|
||||
ClientPayloadHandler.dispatch(payload, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockableEventLoop<Runnable> getClientExecutor() {
|
||||
return Minecraft.getInstance();
|
||||
|
||||
@ -26,6 +26,7 @@ import net.neoforged.fml.VersionChecker;
|
||||
import net.neoforged.fml.loading.EarlyLoadingScreenController;
|
||||
import net.neoforged.neoforge.client.config.NeoForgeClientConfig;
|
||||
import net.neoforged.neoforge.client.gui.LoadingErrorScreen;
|
||||
import net.neoforged.neoforge.client.network.registration.ClientNetworkRegistry;
|
||||
import net.neoforged.neoforge.internal.CommonModLoader;
|
||||
import net.neoforged.neoforge.logging.CrashReportExtender;
|
||||
import net.neoforged.neoforge.resource.ResourcePackLoader;
|
||||
@ -97,7 +98,10 @@ public class ClientModLoader extends CommonModLoader {
|
||||
}
|
||||
|
||||
private static void finishModLoading(Executor syncExecutor, Executor parallelExecutor) {
|
||||
catchLoadingException(() -> finish(syncExecutor, parallelExecutor));
|
||||
catchLoadingException(() -> {
|
||||
finish(syncExecutor, parallelExecutor);
|
||||
ModLoader.runInitTask("Client network registry lock", syncExecutor, () -> {}, ClientNetworkRegistry::setup);
|
||||
});
|
||||
loading = false;
|
||||
loadingComplete = true;
|
||||
}
|
||||
|
||||
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (c) NeoForged and contributors
|
||||
* SPDX-License-Identifier: LGPL-2.1-only
|
||||
*/
|
||||
|
||||
package net.neoforged.neoforge.client.network;
|
||||
|
||||
import java.util.Objects;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.multiplayer.ClientPacketListener;
|
||||
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
|
||||
|
||||
/**
|
||||
* Means to distribute serverbound packets
|
||||
*/
|
||||
public final class ClientPacketDistributor {
|
||||
private ClientPacketDistributor() {}
|
||||
|
||||
/**
|
||||
* Send the given payload(s) to the server
|
||||
*/
|
||||
public static void sendToServer(CustomPacketPayload payload, CustomPacketPayload... payloads) {
|
||||
ClientPacketListener listener = Objects.requireNonNull(Minecraft.getInstance().getConnection());
|
||||
Objects.requireNonNull(payload, "Cannot send null payload");
|
||||
listener.send(payload);
|
||||
for (CustomPacketPayload otherPayload : payloads) {
|
||||
Objects.requireNonNull(otherPayload, "Cannot send null payload");
|
||||
listener.send(otherPayload);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3,7 +3,7 @@
|
||||
* SPDX-License-Identifier: LGPL-2.1-only
|
||||
*/
|
||||
|
||||
package net.neoforged.neoforge.client.network.handlers;
|
||||
package net.neoforged.neoforge.client.network;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Sets;
|
||||
@ -25,19 +25,23 @@ import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.inventory.AbstractContainerMenu;
|
||||
import net.minecraft.world.inventory.MenuType;
|
||||
import net.minecraft.world.item.crafting.RecipeMap;
|
||||
import net.neoforged.api.distmarker.Dist;
|
||||
import net.neoforged.bus.api.SubscribeEvent;
|
||||
import net.neoforged.fml.common.EventBusSubscriber;
|
||||
import net.neoforged.neoforge.client.event.RecipesReceivedEvent;
|
||||
import net.neoforged.neoforge.client.network.event.RegisterClientPayloadHandlersEvent;
|
||||
import net.neoforged.neoforge.client.registries.ClientRegistryManager;
|
||||
import net.neoforged.neoforge.common.NeoForge;
|
||||
import net.neoforged.neoforge.common.world.AuxiliaryLightManager;
|
||||
import net.neoforged.neoforge.common.world.LevelChunkAuxiliaryLightManager;
|
||||
import net.neoforged.neoforge.entity.IEntityWithComplexSpawn;
|
||||
import net.neoforged.neoforge.internal.versions.neoforge.NeoForgeVersion;
|
||||
import net.neoforged.neoforge.network.ConfigSync;
|
||||
import net.neoforged.neoforge.network.handling.IPayloadContext;
|
||||
import net.neoforged.neoforge.network.payload.AdvancedAddEntityPayload;
|
||||
import net.neoforged.neoforge.network.payload.AdvancedContainerSetDataPayload;
|
||||
import net.neoforged.neoforge.network.payload.AdvancedOpenScreenPayload;
|
||||
import net.neoforged.neoforge.network.payload.AuxiliaryLightDataPayload;
|
||||
import net.neoforged.neoforge.network.payload.ClientDispatchPayload;
|
||||
import net.neoforged.neoforge.network.payload.ClientboundCustomSetTimePayload;
|
||||
import net.neoforged.neoforge.network.payload.ConfigFilePayload;
|
||||
import net.neoforged.neoforge.network.payload.FrozenRegistryPayload;
|
||||
@ -53,28 +57,28 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@ApiStatus.Internal
|
||||
public final class ClientPayloadHandler {
|
||||
@EventBusSubscriber(modid = NeoForgeVersion.MOD_ID, value = Dist.CLIENT)
|
||||
final class ClientPayloadHandler {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(ClientPayloadHandler.class);
|
||||
private static final Set<ResourceLocation> toSynchronize = Sets.newConcurrentHashSet();
|
||||
private static final Map<ResourceLocation, RegistrySnapshot> synchronizedRegistries = Maps.newConcurrentMap();
|
||||
|
||||
private ClientPayloadHandler() {}
|
||||
|
||||
public static void dispatch(ClientDispatchPayload payload, IPayloadContext context) {
|
||||
switch (payload) {
|
||||
case AdvancedAddEntityPayload advancedAddEntityPayload -> handle(advancedAddEntityPayload, context);
|
||||
case AdvancedContainerSetDataPayload advancedContainerSetDataPayload -> handle(advancedContainerSetDataPayload, context);
|
||||
case AdvancedOpenScreenPayload advancedOpenScreenPayload -> handle(advancedOpenScreenPayload, context);
|
||||
case AuxiliaryLightDataPayload auxiliaryLightDataPayload -> handle(auxiliaryLightDataPayload, context);
|
||||
case ClientboundCustomSetTimePayload clientboundCustomSetTimePayload -> handle(clientboundCustomSetTimePayload, context);
|
||||
case ConfigFilePayload configFilePayload -> handle(configFilePayload, context);
|
||||
case FrozenRegistryPayload frozenRegistryPayload -> handle(frozenRegistryPayload, context);
|
||||
case FrozenRegistrySyncCompletedPayload frozenRegistrySyncCompletedPayload -> handle(frozenRegistrySyncCompletedPayload, context);
|
||||
case FrozenRegistrySyncStartPayload frozenRegistrySyncStartPayload -> handle(frozenRegistrySyncStartPayload, context);
|
||||
case KnownRegistryDataMapsPayload knownRegistryDataMapsPayload -> ClientRegistryManager.handleKnownDataMaps(knownRegistryDataMapsPayload, context);
|
||||
case RecipeContentPayload recipeContentPayload -> handle(recipeContentPayload, context);
|
||||
case RegistryDataMapSyncPayload<?> registryDataMapSyncPayload -> ClientRegistryManager.handleDataMapSync(registryDataMapSyncPayload, context);
|
||||
}
|
||||
@SubscribeEvent
|
||||
private static void register(RegisterClientPayloadHandlersEvent event) {
|
||||
event.register(ConfigFilePayload.TYPE, ClientPayloadHandler::handle);
|
||||
event.register(FrozenRegistrySyncStartPayload.TYPE, ClientPayloadHandler::handle);
|
||||
event.register(FrozenRegistryPayload.TYPE, ClientPayloadHandler::handle);
|
||||
event.register(FrozenRegistrySyncCompletedPayload.TYPE, ClientPayloadHandler::handle);
|
||||
event.register(KnownRegistryDataMapsPayload.TYPE, ClientRegistryManager::handleKnownDataMaps);
|
||||
event.register(AdvancedAddEntityPayload.TYPE, ClientPayloadHandler::handle);
|
||||
event.register(AdvancedOpenScreenPayload.TYPE, ClientPayloadHandler::handle);
|
||||
event.register(AuxiliaryLightDataPayload.TYPE, ClientPayloadHandler::handle);
|
||||
event.register(RegistryDataMapSyncPayload.TYPE, ClientRegistryManager::handleDataMapSync);
|
||||
event.register(AdvancedContainerSetDataPayload.TYPE, ClientPayloadHandler::handle);
|
||||
event.register(ClientboundCustomSetTimePayload.TYPE, ClientPayloadHandler::handle);
|
||||
event.register(RecipeContentPayload.TYPE, ClientPayloadHandler::handle);
|
||||
}
|
||||
|
||||
private static void handle(FrozenRegistryPayload payload, IPayloadContext context) {
|
||||
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (c) NeoForged and contributors
|
||||
* SPDX-License-Identifier: LGPL-2.1-only
|
||||
*/
|
||||
|
||||
package net.neoforged.neoforge.client.network.event;
|
||||
|
||||
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
|
||||
import net.neoforged.bus.api.Event;
|
||||
import net.neoforged.fml.event.IModBusEvent;
|
||||
import net.neoforged.neoforge.client.network.registration.ClientNetworkRegistry;
|
||||
import net.neoforged.neoforge.network.handling.IPayloadHandler;
|
||||
import net.neoforged.neoforge.network.registration.HandlerThread;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
/**
|
||||
* Event fired on the mod event bus when the {@link ClientNetworkRegistry} is being set up.
|
||||
* <p>
|
||||
* This event is used to assign payload handlers to clientbound payload types.
|
||||
*/
|
||||
public class RegisterClientPayloadHandlersEvent extends Event implements IModBusEvent {
|
||||
@ApiStatus.Internal
|
||||
public RegisterClientPayloadHandlersEvent() {}
|
||||
|
||||
/**
|
||||
* Registers the provided {@link IPayloadHandler} as the client handler to be invoked on the main thread
|
||||
* for the provided {@link CustomPacketPayload.Type}
|
||||
*
|
||||
* @param type The payload type to register the handler for
|
||||
* @param handler The client-side payload handler to register
|
||||
*/
|
||||
public <T extends CustomPacketPayload> void register(CustomPacketPayload.Type<T> type, IPayloadHandler<T> handler) {
|
||||
this.register(type, HandlerThread.MAIN, handler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the provided {@link IPayloadHandler} as the client handler to be invoked on the specified thread
|
||||
* for the provided {@link CustomPacketPayload.Type}
|
||||
*
|
||||
* @param type The payload type to register the handler for
|
||||
* @param thread The thread the handler should be invoked on
|
||||
* @param handler The client-side payload handler to register
|
||||
*/
|
||||
public <T extends CustomPacketPayload> void register(CustomPacketPayload.Type<T> type, HandlerThread thread, IPayloadHandler<T> handler) {
|
||||
ClientNetworkRegistry.register(type, thread, handler);
|
||||
}
|
||||
}
|
||||
@ -6,7 +6,7 @@
|
||||
@FieldsAreNonnullByDefault
|
||||
@MethodsReturnNonnullByDefault
|
||||
@ParametersAreNonnullByDefault
|
||||
package net.neoforged.neoforge.client.network.handlers;
|
||||
package net.neoforged.neoforge.client.network.event;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
import net.minecraft.FieldsAreNonnullByDefault;
|
||||
@ -0,0 +1,13 @@
|
||||
/*
|
||||
* Copyright (c) NeoForged and contributors
|
||||
* SPDX-License-Identifier: LGPL-2.1-only
|
||||
*/
|
||||
|
||||
@FieldsAreNonnullByDefault
|
||||
@MethodsReturnNonnullByDefault
|
||||
@ParametersAreNonnullByDefault
|
||||
package net.neoforged.neoforge.client.network;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
import net.minecraft.FieldsAreNonnullByDefault;
|
||||
import net.minecraft.MethodsReturnNonnullByDefault;
|
||||
@ -0,0 +1,272 @@
|
||||
/*
|
||||
* Copyright (c) NeoForged and contributors
|
||||
* SPDX-License-Identifier: LGPL-2.1-only
|
||||
*/
|
||||
|
||||
package net.neoforged.neoforge.client.network.registration;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.mojang.logging.LogUtils;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import net.minecraft.network.ConnectionProtocol;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.network.protocol.PacketFlow;
|
||||
import net.minecraft.network.protocol.common.ClientCommonPacketListener;
|
||||
import net.minecraft.network.protocol.common.ClientboundCustomPayloadPacket;
|
||||
import net.minecraft.network.protocol.common.custom.BrandPayload;
|
||||
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
|
||||
import net.minecraft.network.protocol.configuration.ClientConfigurationPacketListener;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.neoforged.fml.ModLoader;
|
||||
import net.neoforged.fml.config.ConfigTracker;
|
||||
import net.neoforged.neoforge.client.network.event.RegisterClientPayloadHandlersEvent;
|
||||
import net.neoforged.neoforge.client.network.handling.ClientPayloadContext;
|
||||
import net.neoforged.neoforge.internal.versions.neoforge.NeoForgeVersion;
|
||||
import net.neoforged.neoforge.network.configuration.CheckExtensibleEnums;
|
||||
import net.neoforged.neoforge.network.configuration.CheckFeatureFlags;
|
||||
import net.neoforged.neoforge.network.connection.ConnectionType;
|
||||
import net.neoforged.neoforge.network.filters.NetworkFilters;
|
||||
import net.neoforged.neoforge.network.handling.IPayloadHandler;
|
||||
import net.neoforged.neoforge.network.handling.MainThreadPayloadHandler;
|
||||
import net.neoforged.neoforge.network.negotiation.NegotiableNetworkComponent;
|
||||
import net.neoforged.neoforge.network.negotiation.NegotiationResult;
|
||||
import net.neoforged.neoforge.network.negotiation.NetworkComponentNegotiator;
|
||||
import net.neoforged.neoforge.network.payload.MinecraftRegisterPayload;
|
||||
import net.neoforged.neoforge.network.payload.ModdedNetworkPayload;
|
||||
import net.neoforged.neoforge.network.payload.ModdedNetworkQueryPayload;
|
||||
import net.neoforged.neoforge.network.registration.ChannelAttributes;
|
||||
import net.neoforged.neoforge.network.registration.HandlerThread;
|
||||
import net.neoforged.neoforge.network.registration.NetworkChannel;
|
||||
import net.neoforged.neoforge.network.registration.NetworkPayloadSetup;
|
||||
import net.neoforged.neoforge.network.registration.NetworkRegistry;
|
||||
import net.neoforged.neoforge.network.registration.PayloadRegistration;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
@ApiStatus.Internal
|
||||
public final class ClientNetworkRegistry extends NetworkRegistry {
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
|
||||
private static boolean setupClient = false;
|
||||
|
||||
private ClientNetworkRegistry() {}
|
||||
|
||||
/**
|
||||
* Sets up the client network registry by firing {@link RegisterClientPayloadHandlersEvent}, updating the payload
|
||||
* registrations for clientbound payloads in {@link #PAYLOAD_REGISTRATIONS}.
|
||||
*/
|
||||
public static void setup() {
|
||||
if (!NetworkRegistry.setup) {
|
||||
throw new IllegalStateException("ClientNetworkRegistry cannot be set up before main NetworkRegistry");
|
||||
}
|
||||
if (setupClient) {
|
||||
throw new IllegalStateException("The client network registry can only be set up once.");
|
||||
}
|
||||
|
||||
ModLoader.postEvent(new RegisterClientPayloadHandlersEvent());
|
||||
|
||||
List<ResourceLocation> missingHandlers = PAYLOAD_REGISTRATIONS.values()
|
||||
.stream()
|
||||
.map(Map::values)
|
||||
.flatMap(Collection::stream)
|
||||
.filter(reg -> {
|
||||
if (!reg.matchesFlow(PacketFlow.CLIENTBOUND)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (ConnectionProtocol protocol : reg.protocols()) {
|
||||
if (!CLIENTBOUND_HANDLERS.get(protocol).containsKey(reg.id())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
})
|
||||
.map(PayloadRegistration::id)
|
||||
.distinct()
|
||||
.toList();
|
||||
if (!missingHandlers.isEmpty()) {
|
||||
throw new IllegalStateException("Some clientbound payloads are missing client-side handlers: " + missingHandlers);
|
||||
}
|
||||
|
||||
setupClient = true;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T extends CustomPacketPayload> void register(CustomPacketPayload.Type<T> type, HandlerThread thread, IPayloadHandler<T> handler) {
|
||||
if (setupClient) {
|
||||
throw new UnsupportedOperationException("Cannot register client-side handler for payload " + type.id() + " after registration phase.");
|
||||
}
|
||||
|
||||
if (thread == HandlerThread.MAIN) {
|
||||
handler = new MainThreadPayloadHandler<>(handler);
|
||||
}
|
||||
|
||||
boolean found = false;
|
||||
for (var entry : PAYLOAD_REGISTRATIONS.entrySet()) {
|
||||
ConnectionProtocol protocol = entry.getKey();
|
||||
Map<ResourceLocation, PayloadRegistration<?>> registrations = entry.getValue();
|
||||
|
||||
PayloadRegistration<T> registration = (PayloadRegistration<T>) registrations.get(type.id());
|
||||
if (registration == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!registration.matchesFlow(PacketFlow.CLIENTBOUND)) {
|
||||
throw new IllegalArgumentException("Cannot register client handler for serverbound payload " + type);
|
||||
}
|
||||
|
||||
found = true;
|
||||
|
||||
registerHandler(CLIENTBOUND_HANDLERS, protocol, PacketFlow.CLIENTBOUND, type, handler);
|
||||
}
|
||||
if (!found) {
|
||||
throw new IllegalArgumentException("Cannot register client handler for unknown payload type " + type);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles modded payloads on the client. Invoked after built-in handling.
|
||||
* <p>
|
||||
* Called on the network thread.
|
||||
*
|
||||
* @param listener The listener which received the packet.
|
||||
* @param packet The packet that was received.
|
||||
*/
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
public static void handleModdedPayload(ClientCommonPacketListener listener, ClientboundCustomPayloadPacket packet) {
|
||||
NetworkPayloadSetup payloadSetup = ChannelAttributes.getPayloadSetup(listener.getConnection());
|
||||
// Check if channels were negotiated.
|
||||
if (payloadSetup == null) {
|
||||
LOGGER.warn("Received a modded payload before channel negotiation; disconnecting.");
|
||||
listener.getConnection().disconnect(Component.translatable("multiplayer.disconnect.incompatible", "NeoForge %s (No Payload Setup)".formatted(NeoForgeVersion.getVersion())));
|
||||
return;
|
||||
}
|
||||
|
||||
ResourceLocation payloadId = packet.payload().type().id();
|
||||
ClientPayloadContext context = new ClientPayloadContext(listener, payloadId);
|
||||
|
||||
if (CLIENTBOUND_HANDLERS.containsKey(listener.protocol())) {
|
||||
// Get the configuration channel for the packet.
|
||||
NetworkChannel channel = payloadSetup.getChannel(listener.protocol(), payloadId);
|
||||
|
||||
// Check if the channel should even be processed.
|
||||
if (channel == null && !hasAdhocChannel(listener.protocol(), packet.payload().type().id(), PacketFlow.CLIENTBOUND)) {
|
||||
LOGGER.warn("Received a modded payload with an unknown or unaccepted channel; disconnecting.");
|
||||
listener.getConnection().disconnect(Component.translatable("multiplayer.disconnect.incompatible", "NeoForge %s (No Channel for %s)".formatted(NeoForgeVersion.getVersion(), payloadId.toString())));
|
||||
return;
|
||||
}
|
||||
|
||||
IPayloadHandler handler = CLIENTBOUND_HANDLERS.get(listener.protocol()).get(payloadId);
|
||||
if (handler == null) {
|
||||
LOGGER.error("Received a modded payload with no registration; disconnecting.");
|
||||
listener.getConnection().disconnect(Component.translatable("multiplayer.disconnect.incompatible", "NeoForge %s (No Handler for %s)".formatted(NeoForgeVersion.getVersion(), payloadId.toString())));
|
||||
dumpStackToLog(); // This case is only likely when handling packets without serialization, i.e. from a compound listener, so this can help debug why.
|
||||
return;
|
||||
}
|
||||
|
||||
handler.handle(packet.payload(), context);
|
||||
} else {
|
||||
LOGGER.error("Received a modded payload while not in the configuration or play phase. Disconnecting.");
|
||||
listener.getConnection().disconnect(Component.translatable("multiplayer.disconnect.incompatible", "NeoForge %s (Invalid Protocol %s)".formatted(NeoForgeVersion.getVersion(), listener.protocol().name())));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked by the client when a modded server queries it for its available channels. The negotiation happens solely on the server side, and the result is later transmitted to the client.
|
||||
* <p>
|
||||
* Invoked on the network thread.
|
||||
*
|
||||
* @param listener The listener which received the query.
|
||||
*/
|
||||
public static void onNetworkQuery(ClientConfigurationPacketListener listener) {
|
||||
listener.send(ModdedNetworkQueryPayload.fromRegistry(PAYLOAD_REGISTRATIONS));
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked by the client to indicate that it detect a connection to a modded server, by receiving a {@link ModdedNetworkPayload}.
|
||||
* This will configure the active connection to the server to use the channels that were negotiated.
|
||||
* <p>
|
||||
* Once this method completes a {@link NetworkPayloadSetup} will be present on the connection.
|
||||
* <p>
|
||||
* Invoked on the network thread.
|
||||
*
|
||||
* @param listener The listener which received the payload.
|
||||
* @param setup The network channels that were negotiated.
|
||||
*/
|
||||
public static void initializeNeoForgeConnection(ClientConfigurationPacketListener listener, NetworkPayloadSetup setup) {
|
||||
ChannelAttributes.setPayloadSetup(listener.getConnection(), setup);
|
||||
ChannelAttributes.setConnectionType(listener.getConnection(), listener.getConnectionType());
|
||||
|
||||
// Only inject filters once the payload setup is stored, as the filters might check for available channels.
|
||||
NetworkFilters.injectIfNecessary(listener.getConnection());
|
||||
|
||||
final ImmutableSet.Builder<ResourceLocation> nowListeningOn = ImmutableSet.builder();
|
||||
nowListeningOn.addAll(getInitialListeningChannels(listener.flow()));
|
||||
nowListeningOn.addAll(setup.getChannels(ConnectionProtocol.CONFIGURATION).keySet());
|
||||
listener.send(new MinecraftRegisterPayload(nowListeningOn.build()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked by the client when no {@link ModdedNetworkQueryPayload} has been received, but instead a {@link BrandPayload} has been received as the first packet during negotiation in the configuration phase.
|
||||
* <p>
|
||||
* If this happens then the client will do a negotiation of its own internal channel configuration, to check if any mods are installed that require a modded connection to the server.
|
||||
* If those are found then the connection is aborted and the client disconnects from the server.
|
||||
* <p>
|
||||
* This method should never be invoked on a connection where the server is {@link ConnectionType#NEOFORGE}.
|
||||
* <p>
|
||||
* Invoked on the network thread.
|
||||
*
|
||||
* @param listener The listener which received the brand payload.
|
||||
*/
|
||||
public static void initializeOtherConnection(ClientConfigurationPacketListener listener) {
|
||||
// Because we are in vanilla land, no matter what we are not able to support any custom channels.
|
||||
ChannelAttributes.setPayloadSetup(listener.getConnection(), NetworkPayloadSetup.empty());
|
||||
ChannelAttributes.setConnectionType(listener.getConnection(), listener.getConnectionType());
|
||||
|
||||
for (ConnectionProtocol protocol : PAYLOAD_REGISTRATIONS.keySet()) {
|
||||
NegotiationResult negotiationResult = NetworkComponentNegotiator.negotiate(
|
||||
List.of(),
|
||||
PAYLOAD_REGISTRATIONS.get(protocol).entrySet().stream()
|
||||
.map(entry -> new NegotiableNetworkComponent(entry.getKey(), entry.getValue().version(), entry.getValue().flow(), entry.getValue().optional()))
|
||||
.toList());
|
||||
|
||||
// Negotiation failed. Disconnect the client.
|
||||
if (!negotiationResult.success()) {
|
||||
listener.getConnection().disconnect(Component.translatableWithFallback("neoforge.network.negotiation.failure.vanilla.server.not_supported",
|
||||
"You are trying to connect to a server that is not running NeoForge, but you have mods that require it. A connection could not be established.", NeoForgeVersion.getVersion()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// We are on the client, connected to a vanilla server, make sure we don't have any extended enums that may be sent to the server
|
||||
if (!CheckExtensibleEnums.handleVanillaServerConnection(listener)) {
|
||||
return;
|
||||
}
|
||||
// We are on the client, connected to a vanilla server, make sure we don't have any modded feature flags
|
||||
if (!CheckFeatureFlags.handleVanillaServerConnection(listener)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We are on the client, connected to a vanilla server, We have to load the default configs.
|
||||
ConfigTracker.INSTANCE.loadDefaultServerConfigs();
|
||||
|
||||
NetworkFilters.injectIfNecessary(listener.getConnection());
|
||||
|
||||
ImmutableSet.Builder<ResourceLocation> nowListeningOn = ImmutableSet.builder();
|
||||
nowListeningOn.addAll(getInitialListeningChannels(listener.flow()));
|
||||
PAYLOAD_REGISTRATIONS.get(ConnectionProtocol.CONFIGURATION).entrySet().stream()
|
||||
.filter(registration -> registration.getValue().matchesFlow(listener.flow()))
|
||||
.filter(registration -> registration.getValue().optional())
|
||||
.forEach(registration -> nowListeningOn.add(registration.getKey()));
|
||||
listener.send(new MinecraftRegisterPayload(nowListeningOn.build()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Used in place of {@link Thread#dumpStack()} as that logs to {@link System#err}.
|
||||
*/
|
||||
private static void dumpStackToLog() {
|
||||
LOGGER.error("", new Exception("Stack Trace"));
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,13 @@
|
||||
/*
|
||||
* Copyright (c) NeoForged and contributors
|
||||
* SPDX-License-Identifier: LGPL-2.1-only
|
||||
*/
|
||||
|
||||
@FieldsAreNonnullByDefault
|
||||
@MethodsReturnNonnullByDefault
|
||||
@ParametersAreNonnullByDefault
|
||||
package net.neoforged.neoforge.client.network.registration;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
import net.minecraft.FieldsAreNonnullByDefault;
|
||||
import net.minecraft.MethodsReturnNonnullByDefault;
|
||||
@ -7,16 +7,11 @@ package net.neoforged.neoforge.internal;
|
||||
|
||||
import net.minecraft.core.HolderLookup;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.network.protocol.common.ClientCommonPacketListener;
|
||||
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.util.thread.BlockableEventLoop;
|
||||
import net.minecraft.world.item.TooltipFlag;
|
||||
import net.neoforged.fml.loading.FMLLoader;
|
||||
import net.neoforged.neoforge.network.handling.IPayloadContext;
|
||||
import net.neoforged.neoforge.network.payload.ClientDispatchPayload;
|
||||
import net.neoforged.neoforge.server.ServerLifecycleHooks;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@ -44,18 +39,6 @@ public class NeoForgeProxy {
|
||||
};
|
||||
}
|
||||
|
||||
public void sendToServer(CustomPacketPayload payload, CustomPacketPayload... payloads) {
|
||||
throw new UnsupportedOperationException("Cannot send serverbound payloads on the server");
|
||||
}
|
||||
|
||||
public IPayloadContext newClientPayloadContext(ClientCommonPacketListener listener, ResourceLocation payloadId) {
|
||||
throw new UnsupportedOperationException("Cannot create ClientPayloadContext on the server");
|
||||
}
|
||||
|
||||
public void handleClientPayload(ClientDispatchPayload payload, IPayloadContext context) {
|
||||
throw new UnsupportedOperationException("Cannot handle client payload on the server");
|
||||
}
|
||||
|
||||
public BlockableEventLoop<Runnable> getClientExecutor() {
|
||||
throw new UnsupportedOperationException("Cannot access client on the server");
|
||||
}
|
||||
|
||||
@ -7,19 +7,15 @@ package net.neoforged.neoforge.network;
|
||||
|
||||
import net.neoforged.bus.api.SubscribeEvent;
|
||||
import net.neoforged.fml.common.EventBusSubscriber;
|
||||
import net.neoforged.neoforge.internal.NeoForgeProxy;
|
||||
import net.neoforged.neoforge.internal.versions.neoforge.NeoForgeVersion;
|
||||
import net.neoforged.neoforge.network.configuration.CheckExtensibleEnums;
|
||||
import net.neoforged.neoforge.network.configuration.CheckFeatureFlags;
|
||||
import net.neoforged.neoforge.network.event.RegisterPayloadHandlersEvent;
|
||||
import net.neoforged.neoforge.network.handlers.ServerPayloadHandler;
|
||||
import net.neoforged.neoforge.network.handling.DirectionalPayloadHandler;
|
||||
import net.neoforged.neoforge.network.handling.IPayloadHandler;
|
||||
import net.neoforged.neoforge.network.payload.AdvancedAddEntityPayload;
|
||||
import net.neoforged.neoforge.network.payload.AdvancedContainerSetDataPayload;
|
||||
import net.neoforged.neoforge.network.payload.AdvancedOpenScreenPayload;
|
||||
import net.neoforged.neoforge.network.payload.AuxiliaryLightDataPayload;
|
||||
import net.neoforged.neoforge.network.payload.ClientDispatchPayload;
|
||||
import net.neoforged.neoforge.network.payload.ClientboundCustomSetTimePayload;
|
||||
import net.neoforged.neoforge.network.payload.ConfigFilePayload;
|
||||
import net.neoforged.neoforge.network.payload.ExtensibleEnumAcknowledgePayload;
|
||||
@ -39,10 +35,8 @@ import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
@ApiStatus.Internal
|
||||
@EventBusSubscriber(modid = NeoForgeVersion.MOD_ID)
|
||||
public class NetworkInitialization {
|
||||
private static <T extends ClientDispatchPayload> IPayloadHandler<T> clientHandler() {
|
||||
return NeoForgeProxy.INSTANCE::handleClientPayload;
|
||||
}
|
||||
final class NetworkInitialization {
|
||||
private NetworkInitialization() {}
|
||||
|
||||
@SubscribeEvent
|
||||
private static void register(final RegisterPayloadHandlersEvent event) {
|
||||
@ -51,24 +45,20 @@ public class NetworkInitialization {
|
||||
registrar
|
||||
.commonToClient(
|
||||
ConfigFilePayload.TYPE,
|
||||
ConfigFilePayload.STREAM_CODEC,
|
||||
clientHandler())
|
||||
ConfigFilePayload.STREAM_CODEC)
|
||||
.configurationToClient(
|
||||
FrozenRegistrySyncStartPayload.TYPE,
|
||||
FrozenRegistrySyncStartPayload.STREAM_CODEC,
|
||||
clientHandler())
|
||||
FrozenRegistrySyncStartPayload.STREAM_CODEC)
|
||||
.configurationToClient(
|
||||
FrozenRegistryPayload.TYPE,
|
||||
FrozenRegistryPayload.STREAM_CODEC,
|
||||
clientHandler())
|
||||
FrozenRegistryPayload.STREAM_CODEC)
|
||||
.configurationBidirectional(
|
||||
FrozenRegistrySyncCompletedPayload.TYPE,
|
||||
FrozenRegistrySyncCompletedPayload.STREAM_CODEC,
|
||||
new DirectionalPayloadHandler<>(clientHandler(), ServerPayloadHandler::handle))
|
||||
ServerPayloadHandler::handle)
|
||||
.configurationToClient(
|
||||
KnownRegistryDataMapsPayload.TYPE,
|
||||
KnownRegistryDataMapsPayload.STREAM_CODEC,
|
||||
clientHandler())
|
||||
KnownRegistryDataMapsPayload.STREAM_CODEC)
|
||||
.configurationToClient(
|
||||
ExtensibleEnumDataPayload.TYPE,
|
||||
ExtensibleEnumDataPayload.STREAM_CODEC,
|
||||
@ -91,30 +81,23 @@ public class NetworkInitialization {
|
||||
CheckFeatureFlags::handleServerboundPayload)
|
||||
.playToClient(
|
||||
AdvancedAddEntityPayload.TYPE,
|
||||
AdvancedAddEntityPayload.STREAM_CODEC,
|
||||
clientHandler())
|
||||
AdvancedAddEntityPayload.STREAM_CODEC)
|
||||
.playToClient(
|
||||
AdvancedOpenScreenPayload.TYPE,
|
||||
AdvancedOpenScreenPayload.STREAM_CODEC,
|
||||
clientHandler())
|
||||
AdvancedOpenScreenPayload.STREAM_CODEC)
|
||||
.playToClient(
|
||||
AuxiliaryLightDataPayload.TYPE,
|
||||
AuxiliaryLightDataPayload.STREAM_CODEC,
|
||||
clientHandler())
|
||||
AuxiliaryLightDataPayload.STREAM_CODEC)
|
||||
.playToClient(
|
||||
RegistryDataMapSyncPayload.TYPE,
|
||||
RegistryDataMapSyncPayload.STREAM_CODEC,
|
||||
clientHandler())
|
||||
RegistryDataMapSyncPayload.STREAM_CODEC)
|
||||
.playToClient(AdvancedContainerSetDataPayload.TYPE,
|
||||
AdvancedContainerSetDataPayload.STREAM_CODEC,
|
||||
clientHandler())
|
||||
AdvancedContainerSetDataPayload.STREAM_CODEC)
|
||||
.playToClient(
|
||||
ClientboundCustomSetTimePayload.TYPE,
|
||||
ClientboundCustomSetTimePayload.STREAM_CODEC,
|
||||
clientHandler())
|
||||
ClientboundCustomSetTimePayload.STREAM_CODEC)
|
||||
.playToClient(
|
||||
RecipeContentPayload.TYPE,
|
||||
RecipeContentPayload.STREAM_CODEC,
|
||||
clientHandler());
|
||||
RecipeContentPayload.STREAM_CODEC);
|
||||
}
|
||||
}
|
||||
|
||||
@ -19,23 +19,17 @@ import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.level.ChunkPos;
|
||||
import net.neoforged.neoforge.internal.NeoForgeProxy;
|
||||
import net.neoforged.neoforge.server.ServerLifecycleHooks;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* Means to distribute packets in various ways
|
||||
* Means to distribute packets in various ways.
|
||||
* <p>
|
||||
* Serverbound payloads can be sent via {@code ClientPacketDistributor#sendToServer()}.
|
||||
*/
|
||||
public final class PacketDistributor {
|
||||
private PacketDistributor() {}
|
||||
|
||||
/**
|
||||
* Send the given payload(s) to the server
|
||||
*/
|
||||
public static void sendToServer(CustomPacketPayload payload, CustomPacketPayload... payloads) {
|
||||
NeoForgeProxy.INSTANCE.sendToServer(payload, payloads);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the given payload(s) to the given player
|
||||
*/
|
||||
@ -110,10 +104,12 @@ public final class PacketDistributor {
|
||||
}
|
||||
|
||||
private static Packet<?> makeClientboundPacket(CustomPacketPayload payload, CustomPacketPayload... payloads) {
|
||||
Objects.requireNonNull(payload, "Cannot send null payload");
|
||||
if (payloads.length > 0) {
|
||||
final List<Packet<? super ClientGamePacketListener>> packets = new ArrayList<>();
|
||||
packets.add(new ClientboundCustomPayloadPacket(payload));
|
||||
for (CustomPacketPayload otherPayload : payloads) {
|
||||
Objects.requireNonNull(otherPayload, "Cannot send null payload");
|
||||
packets.add(new ClientboundCustomPayloadPacket(otherPayload));
|
||||
}
|
||||
return new ClientboundBundlePacket(packets);
|
||||
|
||||
@ -61,7 +61,7 @@ public class GenericPacketSplitter extends MessageToMessageEncoder<Packet<?>> im
|
||||
private static void register(final RegisterPayloadHandlersEvent event) {
|
||||
event.registrar("1")
|
||||
.optional()
|
||||
.commonBidirectional(SplitPacketPayload.TYPE, SplitPacketPayload.STREAM_CODEC, GenericPacketSplitter::handle);
|
||||
.commonBidirectional(SplitPacketPayload.TYPE, SplitPacketPayload.STREAM_CODEC, GenericPacketSplitter::handle, GenericPacketSplitter::handle);
|
||||
}
|
||||
|
||||
private static void handle(SplitPacketPayload payload, IPayloadContext context) {
|
||||
|
||||
@ -1,22 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) NeoForged and contributors
|
||||
* SPDX-License-Identifier: LGPL-2.1-only
|
||||
*/
|
||||
|
||||
package net.neoforged.neoforge.network.handling;
|
||||
|
||||
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
|
||||
|
||||
/**
|
||||
* Helper class that merges two unidirectional handlers into a single bidirectional handler.
|
||||
*/
|
||||
public record DirectionalPayloadHandler<T extends CustomPacketPayload>(IPayloadHandler<T> clientSide, IPayloadHandler<T> serverSide) implements IPayloadHandler<T> {
|
||||
@Override
|
||||
public void handle(T payload, IPayloadContext context) {
|
||||
if (context.flow().isClientbound()) {
|
||||
clientSide.handle(payload, context);
|
||||
} else if (context.flow().isServerbound()) {
|
||||
serverSide.handle(payload, context);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -8,6 +8,7 @@ package net.neoforged.neoforge.network.payload;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.network.codec.ByteBufCodecs;
|
||||
import net.minecraft.network.codec.StreamCodec;
|
||||
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.neoforged.neoforge.common.util.FriendlyByteBufUtil;
|
||||
@ -23,7 +24,7 @@ import org.jetbrains.annotations.ApiStatus;
|
||||
* @param customPayload The custom data of the entity to add.
|
||||
*/
|
||||
@ApiStatus.Internal
|
||||
public record AdvancedAddEntityPayload(int entityId, byte[] customPayload) implements ClientDispatchPayload {
|
||||
public record AdvancedAddEntityPayload(int entityId, byte[] customPayload) implements CustomPacketPayload {
|
||||
public static final Type<AdvancedAddEntityPayload> TYPE = new Type<>(ResourceLocation.fromNamespaceAndPath(NeoForgeVersion.MOD_ID, "advanced_add_entity"));
|
||||
public static final StreamCodec<FriendlyByteBuf, AdvancedAddEntityPayload> STREAM_CODEC = StreamCodec.composite(
|
||||
ByteBufCodecs.VAR_INT,
|
||||
|
||||
@ -8,6 +8,7 @@ package net.neoforged.neoforge.network.payload;
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf;
|
||||
import net.minecraft.network.codec.ByteBufCodecs;
|
||||
import net.minecraft.network.codec.StreamCodec;
|
||||
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
|
||||
import net.minecraft.network.protocol.game.ClientboundContainerSetDataPacket;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.neoforged.neoforge.internal.versions.neoforge.NeoForgeVersion;
|
||||
@ -21,7 +22,7 @@ import org.jetbrains.annotations.ApiStatus;
|
||||
* @param value The value of the dataslot.
|
||||
*/
|
||||
@ApiStatus.Internal
|
||||
public record AdvancedContainerSetDataPayload(byte containerId, short dataId, int value) implements ClientDispatchPayload {
|
||||
public record AdvancedContainerSetDataPayload(byte containerId, short dataId, int value) implements CustomPacketPayload {
|
||||
|
||||
public static final Type<AdvancedContainerSetDataPayload> TYPE = new Type<>(ResourceLocation.fromNamespaceAndPath(NeoForgeVersion.MOD_ID, "advanced_container_set_data"));
|
||||
public static final StreamCodec<RegistryFriendlyByteBuf, AdvancedContainerSetDataPayload> STREAM_CODEC = StreamCodec.composite(
|
||||
|
||||
@ -11,6 +11,7 @@ import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.network.chat.ComponentSerialization;
|
||||
import net.minecraft.network.codec.ByteBufCodecs;
|
||||
import net.minecraft.network.codec.StreamCodec;
|
||||
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.inventory.MenuType;
|
||||
import net.neoforged.neoforge.internal.versions.neoforge.NeoForgeVersion;
|
||||
@ -26,7 +27,7 @@ import org.jetbrains.annotations.ApiStatus;
|
||||
* @param additionalData The additional data to pass to the screen.
|
||||
*/
|
||||
@ApiStatus.Internal
|
||||
public record AdvancedOpenScreenPayload(int windowId, MenuType<?> menuType, Component name, byte[] additionalData) implements ClientDispatchPayload {
|
||||
public record AdvancedOpenScreenPayload(int windowId, MenuType<?> menuType, Component name, byte[] additionalData) implements CustomPacketPayload {
|
||||
|
||||
public static final Type<AdvancedOpenScreenPayload> TYPE = new Type<>(ResourceLocation.fromNamespaceAndPath(NeoForgeVersion.MOD_ID, "advanced_open_screen"));
|
||||
public static final StreamCodec<RegistryFriendlyByteBuf, AdvancedOpenScreenPayload> STREAM_CODEC = StreamCodec.composite(
|
||||
|
||||
@ -11,6 +11,7 @@ import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf;
|
||||
import net.minecraft.network.codec.ByteBufCodecs;
|
||||
import net.minecraft.network.codec.StreamCodec;
|
||||
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.level.ChunkPos;
|
||||
import net.neoforged.neoforge.internal.versions.neoforge.NeoForgeVersion;
|
||||
@ -18,7 +19,7 @@ import net.neoforged.neoforge.network.codec.NeoForgeStreamCodecs;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
@ApiStatus.Internal
|
||||
public record AuxiliaryLightDataPayload(ChunkPos pos, Map<BlockPos, Byte> entries) implements ClientDispatchPayload {
|
||||
public record AuxiliaryLightDataPayload(ChunkPos pos, Map<BlockPos, Byte> entries) implements CustomPacketPayload {
|
||||
public static final Type<AuxiliaryLightDataPayload> TYPE = new Type<>(ResourceLocation.fromNamespaceAndPath(NeoForgeVersion.MOD_ID, "auxiliary_light_data"));
|
||||
public static final StreamCodec<RegistryFriendlyByteBuf, AuxiliaryLightDataPayload> STREAM_CODEC = StreamCodec.composite(
|
||||
NeoForgeStreamCodecs.CHUNK_POS,
|
||||
|
||||
@ -1,26 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) NeoForged and contributors
|
||||
* SPDX-License-Identifier: LGPL-2.1-only
|
||||
*/
|
||||
|
||||
package net.neoforged.neoforge.network.payload;
|
||||
|
||||
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
|
||||
|
||||
/**
|
||||
* Internal marker classes for packets for which the handler dispatch happens in {@code ClientPayloadHandler}.
|
||||
* This is meant to be a temporary workaround until we rework the networking API to allow for separate handler registration.
|
||||
*/
|
||||
public sealed interface ClientDispatchPayload extends CustomPacketPayload
|
||||
permits AdvancedAddEntityPayload,
|
||||
AdvancedContainerSetDataPayload,
|
||||
AdvancedOpenScreenPayload,
|
||||
AuxiliaryLightDataPayload,
|
||||
ClientboundCustomSetTimePayload,
|
||||
ConfigFilePayload,
|
||||
FrozenRegistryPayload,
|
||||
FrozenRegistrySyncCompletedPayload,
|
||||
FrozenRegistrySyncStartPayload,
|
||||
KnownRegistryDataMapsPayload,
|
||||
RecipeContentPayload,
|
||||
RegistryDataMapSyncPayload {}
|
||||
@ -8,12 +8,13 @@ package net.neoforged.neoforge.network.payload;
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf;
|
||||
import net.minecraft.network.codec.ByteBufCodecs;
|
||||
import net.minecraft.network.codec.StreamCodec;
|
||||
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.neoforged.neoforge.internal.versions.neoforge.NeoForgeVersion;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
@ApiStatus.Internal
|
||||
public record ClientboundCustomSetTimePayload(long gameTime, long dayTime, boolean gameRule, float dayTimeFraction, float dayTimePerTick) implements ClientDispatchPayload {
|
||||
public record ClientboundCustomSetTimePayload(long gameTime, long dayTime, boolean gameRule, float dayTimeFraction, float dayTimePerTick) implements CustomPacketPayload {
|
||||
|
||||
public static final Type<ClientboundCustomSetTimePayload> TYPE = new Type<>(ResourceLocation.fromNamespaceAndPath(NeoForgeVersion.MOD_ID, "custom_time_packet"));
|
||||
|
||||
|
||||
@ -8,6 +8,7 @@ package net.neoforged.neoforge.network.payload;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.network.codec.ByteBufCodecs;
|
||||
import net.minecraft.network.codec.StreamCodec;
|
||||
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.neoforged.neoforge.internal.versions.neoforge.NeoForgeVersion;
|
||||
import net.neoforged.neoforge.network.codec.NeoForgeStreamCodecs;
|
||||
@ -23,7 +24,7 @@ import org.jetbrains.annotations.ApiStatus;
|
||||
* @param contents The contents of the config file.
|
||||
*/
|
||||
@ApiStatus.Internal
|
||||
public record ConfigFilePayload(String fileName, byte[] contents) implements ClientDispatchPayload {
|
||||
public record ConfigFilePayload(String fileName, byte[] contents) implements CustomPacketPayload {
|
||||
public static final Type<ConfigFilePayload> TYPE = new Type<>(ResourceLocation.fromNamespaceAndPath(NeoForgeVersion.MOD_ID, "config_file"));
|
||||
public static final StreamCodec<FriendlyByteBuf, ConfigFilePayload> STREAM_CODEC = StreamCodec.composite(
|
||||
ByteBufCodecs.STRING_UTF8,
|
||||
|
||||
@ -7,6 +7,7 @@ package net.neoforged.neoforge.network.payload;
|
||||
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.network.codec.StreamCodec;
|
||||
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.neoforged.neoforge.internal.versions.neoforge.NeoForgeVersion;
|
||||
import net.neoforged.neoforge.registries.RegistrySnapshot;
|
||||
@ -19,7 +20,7 @@ import org.jetbrains.annotations.ApiStatus;
|
||||
* @param snapshot The snapshot of the registry
|
||||
*/
|
||||
@ApiStatus.Internal
|
||||
public record FrozenRegistryPayload(ResourceLocation registryName, RegistrySnapshot snapshot) implements ClientDispatchPayload {
|
||||
public record FrozenRegistryPayload(ResourceLocation registryName, RegistrySnapshot snapshot) implements CustomPacketPayload {
|
||||
public static final Type<FrozenRegistryPayload> TYPE = new Type<>(ResourceLocation.fromNamespaceAndPath(NeoForgeVersion.MOD_ID, "frozen_registry"));
|
||||
public static final StreamCodec<FriendlyByteBuf, FrozenRegistryPayload> STREAM_CODEC = StreamCodec.composite(
|
||||
ResourceLocation.STREAM_CODEC,
|
||||
|
||||
@ -7,6 +7,7 @@ package net.neoforged.neoforge.network.payload;
|
||||
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.network.codec.StreamCodec;
|
||||
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.neoforged.neoforge.internal.versions.neoforge.NeoForgeVersion;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
@ -15,7 +16,7 @@ import org.jetbrains.annotations.ApiStatus;
|
||||
* This payload is sent to the client when the server has finished sending all the frozen registries.
|
||||
*/
|
||||
@ApiStatus.Internal
|
||||
public final class FrozenRegistrySyncCompletedPayload implements ClientDispatchPayload {
|
||||
public final class FrozenRegistrySyncCompletedPayload implements CustomPacketPayload {
|
||||
public static final Type<FrozenRegistrySyncCompletedPayload> TYPE = new Type<>(ResourceLocation.fromNamespaceAndPath(NeoForgeVersion.MOD_ID, "frozen_registry_sync_completed"));
|
||||
public static final FrozenRegistrySyncCompletedPayload INSTANCE = new FrozenRegistrySyncCompletedPayload();
|
||||
public static final StreamCodec<FriendlyByteBuf, FrozenRegistrySyncCompletedPayload> STREAM_CODEC = StreamCodec.unit(INSTANCE);
|
||||
|
||||
@ -9,6 +9,7 @@ import java.util.List;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.network.codec.ByteBufCodecs;
|
||||
import net.minecraft.network.codec.StreamCodec;
|
||||
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.neoforged.neoforge.internal.versions.neoforge.NeoForgeVersion;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
@ -22,7 +23,7 @@ import org.jetbrains.annotations.ApiStatus;
|
||||
* @param toAccess The registries to access.
|
||||
*/
|
||||
@ApiStatus.Internal
|
||||
public record FrozenRegistrySyncStartPayload(List<ResourceLocation> toAccess) implements ClientDispatchPayload {
|
||||
public record FrozenRegistrySyncStartPayload(List<ResourceLocation> toAccess) implements CustomPacketPayload {
|
||||
public static final Type<FrozenRegistrySyncStartPayload> TYPE = new Type<>(ResourceLocation.fromNamespaceAndPath(NeoForgeVersion.MOD_ID, "frozen_registry_sync_start"));
|
||||
public static final StreamCodec<FriendlyByteBuf, FrozenRegistrySyncStartPayload> STREAM_CODEC = StreamCodec.composite(
|
||||
ResourceLocation.STREAM_CODEC.apply(ByteBufCodecs.list()),
|
||||
|
||||
@ -12,13 +12,14 @@ import net.minecraft.core.Registry;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.network.codec.ByteBufCodecs;
|
||||
import net.minecraft.network.codec.StreamCodec;
|
||||
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.neoforged.neoforge.network.codec.NeoForgeStreamCodecs;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
@ApiStatus.Internal
|
||||
public record KnownRegistryDataMapsPayload(Map<ResourceKey<? extends Registry<?>>, List<KnownDataMap>> dataMaps) implements ClientDispatchPayload {
|
||||
public record KnownRegistryDataMapsPayload(Map<ResourceKey<? extends Registry<?>>, List<KnownDataMap>> dataMaps) implements CustomPacketPayload {
|
||||
public static final Type<KnownRegistryDataMapsPayload> TYPE = new Type<>(ResourceLocation.fromNamespaceAndPath("neoforge", "known_registry_data_maps"));
|
||||
public static final StreamCodec<FriendlyByteBuf, KnownRegistryDataMapsPayload> STREAM_CODEC = StreamCodec.composite(
|
||||
ByteBufCodecs.map(
|
||||
|
||||
@ -13,6 +13,7 @@ import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf;
|
||||
import net.minecraft.network.codec.ByteBufCodecs;
|
||||
import net.minecraft.network.codec.StreamCodec;
|
||||
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.item.crafting.RecipeHolder;
|
||||
import net.minecraft.world.item.crafting.RecipeMap;
|
||||
@ -26,7 +27,7 @@ import org.jetbrains.annotations.ApiStatus;
|
||||
@ApiStatus.Internal
|
||||
public record RecipeContentPayload(
|
||||
Set<RecipeType<?>> recipeTypes,
|
||||
List<RecipeHolder<?>> recipes) implements ClientDispatchPayload {
|
||||
List<RecipeHolder<?>> recipes) implements CustomPacketPayload {
|
||||
public static final Type<RecipeContentPayload> TYPE = new Type<>(ResourceLocation.fromNamespaceAndPath(NeoForgeVersion.MOD_ID, "recipe_content"));
|
||||
|
||||
public static final StreamCodec<RegistryFriendlyByteBuf, RecipeContentPayload> STREAM_CODEC = StreamCodec.composite(
|
||||
|
||||
@ -28,7 +28,7 @@ import org.jetbrains.annotations.ApiStatus;
|
||||
@ApiStatus.Internal
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public record RegistryDataMapSyncPayload<T>(ResourceKey<? extends Registry<T>> registryKey,
|
||||
Map<ResourceLocation, Map<ResourceKey<T>, ?>> dataMaps) implements ClientDispatchPayload {
|
||||
Map<ResourceLocation, Map<ResourceKey<T>, ?>> dataMaps) implements CustomPacketPayload {
|
||||
public static final CustomPacketPayload.Type<RegistryDataMapSyncPayload<?>> TYPE = new Type<>(ResourceLocation.fromNamespaceAndPath("neoforge", "registry_data_map_sync"));
|
||||
public static final StreamCodec<RegistryFriendlyByteBuf, RegistryDataMapSyncPayload<?>> STREAM_CODEC = StreamCodec.ofMember(
|
||||
RegistryDataMapSyncPayload::write, RegistryDataMapSyncPayload::decode);
|
||||
|
||||
@ -36,20 +36,14 @@ import net.minecraft.network.protocol.common.ClientCommonPacketListener;
|
||||
import net.minecraft.network.protocol.common.ClientboundCustomPayloadPacket;
|
||||
import net.minecraft.network.protocol.common.ServerCommonPacketListener;
|
||||
import net.minecraft.network.protocol.common.ServerboundCustomPayloadPacket;
|
||||
import net.minecraft.network.protocol.common.custom.BrandPayload;
|
||||
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
|
||||
import net.minecraft.network.protocol.common.custom.DiscardedPayload;
|
||||
import net.minecraft.network.protocol.configuration.ClientConfigurationPacketListener;
|
||||
import net.minecraft.network.protocol.configuration.ServerConfigurationPacketListener;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.network.ServerConfigurationPacketListenerImpl;
|
||||
import net.neoforged.fml.ModLoader;
|
||||
import net.neoforged.fml.config.ConfigTracker;
|
||||
import net.neoforged.neoforge.common.extensions.ICommonPacketListener;
|
||||
import net.neoforged.neoforge.internal.NeoForgeProxy;
|
||||
import net.neoforged.neoforge.internal.versions.neoforge.NeoForgeVersion;
|
||||
import net.neoforged.neoforge.network.configuration.CheckExtensibleEnums;
|
||||
import net.neoforged.neoforge.network.configuration.CheckFeatureFlags;
|
||||
import net.neoforged.neoforge.network.configuration.CommonRegisterTask;
|
||||
import net.neoforged.neoforge.network.configuration.CommonVersionTask;
|
||||
import net.neoforged.neoforge.network.connection.ConnectionType;
|
||||
@ -98,7 +92,7 @@ public class NetworkRegistry {
|
||||
* Map of NeoForge payloads that may be sent before channel negotiation.
|
||||
* TODO: Separate by protocol + flow.
|
||||
*/
|
||||
private static final Map<ResourceLocation, StreamCodec<FriendlyByteBuf, ? extends CustomPacketPayload>> BUILTIN_PAYLOADS = ImmutableMap.of(
|
||||
protected static final Map<ResourceLocation, StreamCodec<FriendlyByteBuf, ? extends CustomPacketPayload>> BUILTIN_PAYLOADS = ImmutableMap.of(
|
||||
MinecraftRegisterPayload.ID, MinecraftRegisterPayload.STREAM_CODEC,
|
||||
MinecraftUnregisterPayload.ID, MinecraftUnregisterPayload.STREAM_CODEC,
|
||||
ModdedNetworkQueryPayload.ID, ModdedNetworkQueryPayload.STREAM_CODEC,
|
||||
@ -111,13 +105,19 @@ public class NetworkRegistry {
|
||||
* Registry of all custom payload handlers. The initial state of this map should reflect the protocols which support custom payloads.
|
||||
* TODO: Change key type to a combination of protocol + flow.
|
||||
*/
|
||||
private static final Map<ConnectionProtocol, Map<ResourceLocation, PayloadRegistration<?>>> PAYLOAD_REGISTRATIONS = ImmutableMap.of(
|
||||
protected static final Map<ConnectionProtocol, Map<ResourceLocation, PayloadRegistration<?>>> PAYLOAD_REGISTRATIONS = ImmutableMap.of(
|
||||
ConnectionProtocol.CONFIGURATION, new HashMap<>(),
|
||||
ConnectionProtocol.PLAY, new HashMap<>());
|
||||
protected static final Map<ConnectionProtocol, Map<ResourceLocation, IPayloadHandler<?>>> SERVERBOUND_HANDLERS = ImmutableMap.of(
|
||||
ConnectionProtocol.CONFIGURATION, new HashMap<>(),
|
||||
ConnectionProtocol.PLAY, new HashMap<>());
|
||||
protected static final Map<ConnectionProtocol, Map<ResourceLocation, IPayloadHandler<?>>> CLIENTBOUND_HANDLERS = ImmutableMap.of(
|
||||
ConnectionProtocol.CONFIGURATION, new HashMap<>(),
|
||||
ConnectionProtocol.PLAY, new HashMap<>());
|
||||
|
||||
private static boolean setup = false;
|
||||
protected static boolean setup = false;
|
||||
|
||||
private NetworkRegistry() {}
|
||||
protected NetworkRegistry() {}
|
||||
|
||||
/**
|
||||
* Sets up the network registry by firing {@link RegisterPayloadHandlersEvent}, storing the resulting payload registrations in {@link #PAYLOAD_REGISTRATIONS}.
|
||||
@ -135,19 +135,27 @@ public class NetworkRegistry {
|
||||
/**
|
||||
* Registers a new payload.
|
||||
*
|
||||
* @param <T> The class of the payload.
|
||||
* @param <B> The class of the ByteBuf. Only {@link ConnectionProtocol#PLAY play} payloads may use {@link RegistryFriendlyByteBuf}.
|
||||
* @param type The type of the payload.
|
||||
* @param codec The codec for the payload.
|
||||
* @param handler The handler for the payload. This handler should expect to receive the payload on all declared protocols and flows. It will be executed on the network thread.
|
||||
* @param protocols The protocols this payload supports being sent over. Only {@link ConnectionProtocol#CONFIGURATION configuration} and {@link ConnectionProtocol#PLAY play} are supported.
|
||||
* @param flow The flow of this payload. Specify {@link Optional#empty()} to support sending in both directions.
|
||||
* @param version The version of the payload. Increase the payload version if the codec logic or handler logic changes. Neo-Neo connections with mismatched versions are denied.
|
||||
* @param optional If the payload is optional. Any connection with missing non-optional payloads is denied.
|
||||
* @param <T> The class of the payload.
|
||||
* @param <B> The class of the ByteBuf. Only {@link ConnectionProtocol#PLAY play} payloads may use {@link RegistryFriendlyByteBuf}.
|
||||
* @param type The type of the payload.
|
||||
* @param codec The codec for the payload.
|
||||
* @param serverHandler The server-side handler for the payload. This handler will be executed on the network thread.
|
||||
* @param clientHandler The client-side handler for the payload. This handler will be executed on the network thread.
|
||||
* @param protocols The protocols this payload supports being sent over. Only {@link ConnectionProtocol#CONFIGURATION configuration} and {@link ConnectionProtocol#PLAY play} are supported.
|
||||
* @param flow The flow of this payload. Specify {@link Optional#empty()} to support sending in both directions.
|
||||
* @param version The version of the payload. Increase the payload version if the codec logic or handler logic changes. Neo-Neo connections with mismatched versions are denied.
|
||||
* @param optional If the payload is optional. Any connection with missing non-optional payloads is denied.
|
||||
*/
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public static <T extends CustomPacketPayload, B extends FriendlyByteBuf> void register(CustomPacketPayload.Type<T> type, StreamCodec<? super B, T> codec, IPayloadHandler<T> handler,
|
||||
List<ConnectionProtocol> protocols, Optional<PacketFlow> flow, String version, boolean optional) {
|
||||
public static <T extends CustomPacketPayload, B extends FriendlyByteBuf> void register(
|
||||
CustomPacketPayload.Type<T> type,
|
||||
StreamCodec<? super B, T> codec,
|
||||
@Nullable IPayloadHandler<T> serverHandler,
|
||||
@Nullable IPayloadHandler<T> clientHandler,
|
||||
List<ConnectionProtocol> protocols,
|
||||
Optional<PacketFlow> flow,
|
||||
String version,
|
||||
boolean optional) {
|
||||
if (setup) {
|
||||
throw new UnsupportedOperationException("Cannot register payload " + type.id() + " after registration phase.");
|
||||
}
|
||||
@ -164,7 +172,11 @@ public class NetworkRegistry {
|
||||
throw new UnsupportedOperationException("Cannot register payload " + type.id() + " using the domain \"minecraft\".");
|
||||
}
|
||||
|
||||
PayloadRegistration<T> reg = new PayloadRegistration(type, codec, handler, protocols, flow, version.strip(), optional);
|
||||
PayloadRegistration<T> reg = new PayloadRegistration(type, codec, protocols, flow, version.strip(), optional);
|
||||
|
||||
if (reg.matchesFlow(PacketFlow.SERVERBOUND) && serverHandler == null) {
|
||||
throw new IllegalArgumentException("Cannot register serverbound payload " + type.id() + " without a server-side handler");
|
||||
}
|
||||
|
||||
for (ConnectionProtocol protocol : protocols) {
|
||||
Map<ResourceLocation, PayloadRegistration<?>> byProtocol = PAYLOAD_REGISTRATIONS.get(protocol);
|
||||
@ -178,9 +190,34 @@ public class NetworkRegistry {
|
||||
}
|
||||
|
||||
byProtocol.put(type.id(), reg);
|
||||
|
||||
if (serverHandler != null && reg.matchesFlow(PacketFlow.SERVERBOUND)) {
|
||||
registerHandler(SERVERBOUND_HANDLERS, protocol, PacketFlow.SERVERBOUND, type, serverHandler);
|
||||
}
|
||||
if (clientHandler != null && reg.matchesFlow(PacketFlow.CLIENTBOUND)) {
|
||||
registerHandler(CLIENTBOUND_HANDLERS, protocol, PacketFlow.CLIENTBOUND, type, clientHandler);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected static <T extends CustomPacketPayload> void registerHandler(
|
||||
Map<ConnectionProtocol, Map<ResourceLocation, IPayloadHandler<?>>> handlers,
|
||||
ConnectionProtocol protocol,
|
||||
PacketFlow flow,
|
||||
CustomPacketPayload.Type<T> type,
|
||||
IPayloadHandler<T> handler) {
|
||||
Map<ResourceLocation, IPayloadHandler<?>> byProtocol = handlers.get(protocol);
|
||||
if (byProtocol == null) {
|
||||
throw new UnsupportedOperationException("Cannot register handler for payload " + type.id() + " for unsupported protocol: " + protocol.name());
|
||||
}
|
||||
|
||||
if (byProtocol.containsKey(type.id())) {
|
||||
throw new UnsupportedOperationException("Duplicate " + flow.id() + " handler registration for payload " + type.id());
|
||||
}
|
||||
|
||||
byProtocol.put(type.id(), handler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to retrieve the {@link StreamCodec} for a non-vanilla payload.
|
||||
* <p>
|
||||
@ -261,7 +298,7 @@ public class NetworkRegistry {
|
||||
|
||||
ServerPayloadContext context = new ServerPayloadContext(listener, packet.payload().type().id());
|
||||
|
||||
if (PAYLOAD_REGISTRATIONS.containsKey(listener.protocol())) {
|
||||
if (SERVERBOUND_HANDLERS.containsKey(listener.protocol())) {
|
||||
// Get the configuration channel for the packet.
|
||||
NetworkChannel channel = payloadSetup.getChannel(listener.protocol(), context.payloadId());
|
||||
|
||||
@ -272,68 +309,21 @@ public class NetworkRegistry {
|
||||
return;
|
||||
}
|
||||
|
||||
PayloadRegistration registration = PAYLOAD_REGISTRATIONS.get(listener.protocol()).get(context.payloadId());
|
||||
if (registration == null) {
|
||||
IPayloadHandler handler = SERVERBOUND_HANDLERS.get(listener.protocol()).get(context.payloadId());
|
||||
if (handler == null) {
|
||||
LOGGER.error("Received a modded payload {} with no registration; disconnecting.", context.payloadId());
|
||||
listener.disconnect(Component.translatable("multiplayer.disconnect.incompatible", "NeoForge %s (No Handler for %s)".formatted(NeoForgeVersion.getVersion(), context.payloadId().toString())));
|
||||
dumpStackToLog(); // This case is only likely when handling packets without serialization, i.e. from a compound listener, so this can help debug why.
|
||||
return;
|
||||
}
|
||||
|
||||
registration.handler().handle(packet.payload(), context);
|
||||
handler.handle(packet.payload(), context);
|
||||
} else {
|
||||
LOGGER.error("Received a modded payload {} while not in the configuration or play phase; disconnecting.", context.payloadId());
|
||||
listener.disconnect(Component.translatable("multiplayer.disconnect.incompatible", "NeoForge %s (Invalid Protocol %s)".formatted(NeoForgeVersion.getVersion(), listener.protocol().name())));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles modded payloads on the client. Invoked after built-in handling.
|
||||
* <p>
|
||||
* Called on the network thread.
|
||||
*
|
||||
* @param listener The listener which received the packet.
|
||||
* @param packet The packet that was received.
|
||||
*/
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
public static void handleModdedPayload(ClientCommonPacketListener listener, ClientboundCustomPayloadPacket packet) {
|
||||
NetworkPayloadSetup payloadSetup = ChannelAttributes.getPayloadSetup(listener.getConnection());
|
||||
// Check if channels were negotiated.
|
||||
if (payloadSetup == null) {
|
||||
LOGGER.warn("Received a modded payload before channel negotiation; disconnecting.");
|
||||
listener.getConnection().disconnect(Component.translatable("multiplayer.disconnect.incompatible", "NeoForge %s (No Payload Setup)".formatted(NeoForgeVersion.getVersion())));
|
||||
return;
|
||||
}
|
||||
|
||||
var payloadId = packet.payload().type().id();
|
||||
IPayloadContext context = NeoForgeProxy.INSTANCE.newClientPayloadContext(listener, payloadId);
|
||||
|
||||
if (PAYLOAD_REGISTRATIONS.containsKey(listener.protocol())) {
|
||||
// Get the configuration channel for the packet.
|
||||
NetworkChannel channel = payloadSetup.getChannel(listener.protocol(), payloadId);
|
||||
|
||||
// Check if the channel should even be processed.
|
||||
if (channel == null && !hasAdhocChannel(listener.protocol(), packet.payload().type().id(), PacketFlow.CLIENTBOUND)) {
|
||||
LOGGER.warn("Received a modded payload with an unknown or unaccepted channel; disconnecting.");
|
||||
listener.getConnection().disconnect(Component.translatable("multiplayer.disconnect.incompatible", "NeoForge %s (No Channel for %s)".formatted(NeoForgeVersion.getVersion(), payloadId.toString())));
|
||||
return;
|
||||
}
|
||||
|
||||
PayloadRegistration registration = PAYLOAD_REGISTRATIONS.get(listener.protocol()).get(payloadId);
|
||||
if (registration == null) {
|
||||
LOGGER.error("Received a modded payload with no registration; disconnecting.");
|
||||
listener.getConnection().disconnect(Component.translatable("multiplayer.disconnect.incompatible", "NeoForge %s (No Handler for %s)".formatted(NeoForgeVersion.getVersion(), payloadId.toString())));
|
||||
dumpStackToLog(); // This case is only likely when handling packets without serialization, i.e. from a compound listener, so this can help debug why.
|
||||
return;
|
||||
}
|
||||
|
||||
registration.handler().handle(packet.payload(), context);
|
||||
} else {
|
||||
LOGGER.error("Received a modded payload while not in the configuration or play phase. Disconnecting.");
|
||||
listener.getConnection().disconnect(Component.translatable("multiplayer.disconnect.incompatible", "NeoForge %s (Invalid Protocol %s)".formatted(NeoForgeVersion.getVersion(), listener.protocol().name())));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked by the server when it completes the negotiation with the client during the configuration phase.
|
||||
* <p>
|
||||
@ -346,9 +336,8 @@ public class NetworkRegistry {
|
||||
* <p>
|
||||
* Invoked on the network thread.
|
||||
*
|
||||
* @param listener The listener which completed the negotiation.
|
||||
* @param configuration The configuration channels that the client has available.
|
||||
* @param play The play channels that the client has available.
|
||||
* @param listener The listener which completed the negotiation.
|
||||
* @param clientChannels The network channels that the client has available.
|
||||
*/
|
||||
public static void initializeNeoForgeConnection(ServerConfigurationPacketListener listener, Map<ConnectionProtocol, Set<ModdedNetworkQueryComponent>> clientChannels) {
|
||||
ChannelAttributes.setPayloadSetup(listener.getConnection(), NetworkPayloadSetup.empty());
|
||||
@ -479,103 +468,11 @@ public class NetworkRegistry {
|
||||
* @param flow The flow of the packet.
|
||||
* @return True if the packet is ad-hoc readable, false otherwise.
|
||||
*/
|
||||
private static boolean hasAdhocChannel(ConnectionProtocol protocol, ResourceLocation id, PacketFlow flow) {
|
||||
protected static boolean hasAdhocChannel(ConnectionProtocol protocol, ResourceLocation id, PacketFlow flow) {
|
||||
PayloadRegistration<?> reg = PAYLOAD_REGISTRATIONS.getOrDefault(protocol, Collections.emptyMap()).get(id);
|
||||
return reg != null && reg.optional() && reg.matchesFlow(flow);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked by the client when a modded server queries it for its available channels. The negotiation happens solely on the server side, and the result is later transmitted to the client.
|
||||
* <p>
|
||||
* Invoked on the network thread.
|
||||
*
|
||||
* @param listener The listener which received the query.
|
||||
*/
|
||||
public static void onNetworkQuery(ClientConfigurationPacketListener listener) {
|
||||
listener.send(ModdedNetworkQueryPayload.fromRegistry(PAYLOAD_REGISTRATIONS));
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked by the client to indicate that it detect a connection to a modded server, by receiving a {@link ModdedNetworkPayload}.
|
||||
* This will configure the active connection to the server to use the channels that were negotiated.
|
||||
* <p>
|
||||
* Once this method completes a {@link NetworkPayloadSetup} will be present on the connection.
|
||||
* <p>
|
||||
* Invoked on the network thread.
|
||||
*
|
||||
* @param listener The listener which received the payload.
|
||||
* @param configuration The configuration channels that were negotiated.
|
||||
* @param play The play channels that were negotiated.
|
||||
*/
|
||||
public static void initializeNeoForgeConnection(ClientConfigurationPacketListener listener, NetworkPayloadSetup setup) {
|
||||
ChannelAttributes.setPayloadSetup(listener.getConnection(), setup);
|
||||
ChannelAttributes.setConnectionType(listener.getConnection(), listener.getConnectionType());
|
||||
|
||||
// Only inject filters once the payload setup is stored, as the filters might check for available channels.
|
||||
NetworkFilters.injectIfNecessary(listener.getConnection());
|
||||
|
||||
final ImmutableSet.Builder<ResourceLocation> nowListeningOn = ImmutableSet.builder();
|
||||
nowListeningOn.addAll(getInitialListeningChannels(listener.flow()));
|
||||
nowListeningOn.addAll(setup.getChannels(ConnectionProtocol.CONFIGURATION).keySet());
|
||||
listener.send(new MinecraftRegisterPayload(nowListeningOn.build()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked by the client when no {@link ModdedNetworkQueryPayload} has been received, but instead a {@link BrandPayload} has been received as the first packet during negotiation in the configuration phase.
|
||||
* <p>
|
||||
* If this happens then the client will do a negotiation of its own internal channel configuration, to check if any mods are installed that require a modded connection to the server.
|
||||
* If those are found then the connection is aborted and the client disconnects from the server.
|
||||
* <p>
|
||||
* This method should never be invoked on a connection where the server is {@link ConnectionType#NEOFORGE}.
|
||||
* <p>
|
||||
* Invoked on the network thread.
|
||||
*
|
||||
* @param listener The listener which received the brand payload.
|
||||
* @return True if the vanilla connection should be handled by the client, false otherwise.
|
||||
*/
|
||||
public static void initializeOtherConnection(ClientConfigurationPacketListener listener) {
|
||||
// Because we are in vanilla land, no matter what we are not able to support any custom channels.
|
||||
ChannelAttributes.setPayloadSetup(listener.getConnection(), NetworkPayloadSetup.empty());
|
||||
ChannelAttributes.setConnectionType(listener.getConnection(), listener.getConnectionType());
|
||||
|
||||
for (ConnectionProtocol protocol : PAYLOAD_REGISTRATIONS.keySet()) {
|
||||
NegotiationResult negotiationResult = NetworkComponentNegotiator.negotiate(
|
||||
List.of(),
|
||||
PAYLOAD_REGISTRATIONS.get(protocol).entrySet().stream()
|
||||
.map(entry -> new NegotiableNetworkComponent(entry.getKey(), entry.getValue().version(), entry.getValue().flow(), entry.getValue().optional()))
|
||||
.toList());
|
||||
|
||||
// Negotiation failed. Disconnect the client.
|
||||
if (!negotiationResult.success()) {
|
||||
listener.getConnection().disconnect(Component.translatableWithFallback("neoforge.network.negotiation.failure.vanilla.server.not_supported",
|
||||
"You are trying to connect to a server that is not running NeoForge, but you have mods that require it. A connection could not be established.", NeoForgeVersion.getVersion()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// We are on the client, connected to a vanilla server, make sure we don't have any extended enums that may be sent to the server
|
||||
if (!CheckExtensibleEnums.handleVanillaServerConnection(listener)) {
|
||||
return;
|
||||
}
|
||||
// We are on the client, connected to a vanilla server, make sure we don't have any modded feature flags
|
||||
if (!CheckFeatureFlags.handleVanillaServerConnection(listener)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We are on the client, connected to a vanilla server, We have to load the default configs.
|
||||
ConfigTracker.INSTANCE.loadDefaultServerConfigs();
|
||||
|
||||
NetworkFilters.injectIfNecessary(listener.getConnection());
|
||||
|
||||
ImmutableSet.Builder<ResourceLocation> nowListeningOn = ImmutableSet.builder();
|
||||
nowListeningOn.addAll(getInitialListeningChannels(listener.flow()));
|
||||
PAYLOAD_REGISTRATIONS.get(ConnectionProtocol.CONFIGURATION).entrySet().stream()
|
||||
.filter(registration -> registration.getValue().matchesFlow(listener.flow()))
|
||||
.filter(registration -> registration.getValue().optional())
|
||||
.forEach(registration -> nowListeningOn.add(registration.getKey()));
|
||||
listener.send(new MinecraftRegisterPayload(nowListeningOn.build()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the packet listener's connection can send/receive the given payload.
|
||||
*
|
||||
@ -783,7 +680,7 @@ public class NetworkRegistry {
|
||||
* <p>
|
||||
* Updates the ad-hoc channels to prepare for the game phase by removing the initial channels and building a new list based on the connection type.
|
||||
*
|
||||
* @param listener
|
||||
* @param listener The packet listener finishing the configuration phase
|
||||
*/
|
||||
public static void onConfigurationFinished(ICommonPacketListener listener) {
|
||||
NetworkPayloadSetup setup = ChannelAttributes.getPayloadSetup(listener.getConnection());
|
||||
|
||||
@ -13,9 +13,9 @@ import net.minecraft.network.RegistryFriendlyByteBuf;
|
||||
import net.minecraft.network.codec.StreamCodec;
|
||||
import net.minecraft.network.protocol.PacketFlow;
|
||||
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
|
||||
import net.neoforged.neoforge.network.handling.DirectionalPayloadHandler;
|
||||
import net.neoforged.neoforge.network.handling.IPayloadHandler;
|
||||
import net.neoforged.neoforge.network.handling.MainThreadPayloadHandler;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* Builder-style helper for registering {@link CustomPacketPayload}s, used for modded networking.
|
||||
@ -41,81 +41,132 @@ public class PayloadRegistrar {
|
||||
/**
|
||||
* Registers a client-bound payload for the play phase.
|
||||
*/
|
||||
public <T extends CustomPacketPayload> PayloadRegistrar playToClient(CustomPacketPayload.Type<T> type, StreamCodec<? super RegistryFriendlyByteBuf, T> reader, IPayloadHandler<T> handler) {
|
||||
register(type, reader, handler, List.of(ConnectionProtocol.PLAY), Optional.of(PacketFlow.CLIENTBOUND), version, optional);
|
||||
public <T extends CustomPacketPayload> PayloadRegistrar playToClient(CustomPacketPayload.Type<T> type, StreamCodec<? super RegistryFriendlyByteBuf, T> codec, IPayloadHandler<T> handler) {
|
||||
register(type, codec, null, handler, List.of(ConnectionProtocol.PLAY), Optional.of(PacketFlow.CLIENTBOUND), version, optional);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a client-bound payload for the play phase without a handler. The missing handler must be registered via {@code RegisterClientPayloadHandlersEvent}.
|
||||
*/
|
||||
public <T extends CustomPacketPayload> PayloadRegistrar playToClient(CustomPacketPayload.Type<T> type, StreamCodec<? super RegistryFriendlyByteBuf, T> codec) {
|
||||
register(type, codec, null, null, List.of(ConnectionProtocol.PLAY), Optional.of(PacketFlow.CLIENTBOUND), version, optional);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a server-bound payload for the play phase.
|
||||
*/
|
||||
public <T extends CustomPacketPayload> PayloadRegistrar playToServer(CustomPacketPayload.Type<T> type, StreamCodec<? super RegistryFriendlyByteBuf, T> reader, IPayloadHandler<T> handler) {
|
||||
register(type, reader, handler, List.of(ConnectionProtocol.PLAY), Optional.of(PacketFlow.SERVERBOUND), version, optional);
|
||||
public <T extends CustomPacketPayload> PayloadRegistrar playToServer(CustomPacketPayload.Type<T> type, StreamCodec<? super RegistryFriendlyByteBuf, T> codec, IPayloadHandler<T> handler) {
|
||||
register(type, codec, handler, null, List.of(ConnectionProtocol.PLAY), Optional.of(PacketFlow.SERVERBOUND), version, optional);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a bidirectional payload for the play phase.
|
||||
* <p>
|
||||
* Consider using {@link DirectionalPayloadHandler} to wrap client and server handlers.
|
||||
* If the provided {@linkplain IPayloadHandler client handler} is null, it must be registered via {@code RegisterClientPayloadHandlersEvent}
|
||||
*/
|
||||
public <T extends CustomPacketPayload> PayloadRegistrar playBidirectional(CustomPacketPayload.Type<T> type, StreamCodec<? super RegistryFriendlyByteBuf, T> reader, IPayloadHandler<T> handler) {
|
||||
register(type, reader, handler, List.of(ConnectionProtocol.PLAY), Optional.empty(), version, optional);
|
||||
public <T extends CustomPacketPayload> PayloadRegistrar playBidirectional(CustomPacketPayload.Type<T> type, StreamCodec<? super RegistryFriendlyByteBuf, T> codec, IPayloadHandler<T> serverHandler, @Nullable IPayloadHandler<T> clientHandler) {
|
||||
register(type, codec, serverHandler, clientHandler, List.of(ConnectionProtocol.PLAY), Optional.empty(), version, optional);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a bidirectional payload for the play phase.
|
||||
* <p>
|
||||
* The provided handler is registered for serverbound payloads and the client-side handler must be registered via {@code RegisterClientPayloadHandlersEvent}
|
||||
*/
|
||||
public <T extends CustomPacketPayload> PayloadRegistrar playBidirectional(CustomPacketPayload.Type<T> type, StreamCodec<? super RegistryFriendlyByteBuf, T> codec, IPayloadHandler<T> serverHandler) {
|
||||
return this.playBidirectional(type, codec, serverHandler, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a client-bound payload for the configuration phase.
|
||||
*/
|
||||
public <T extends CustomPacketPayload> PayloadRegistrar configurationToClient(CustomPacketPayload.Type<T> type, StreamCodec<? super FriendlyByteBuf, T> reader, IPayloadHandler<T> handler) {
|
||||
register(type, reader, handler, List.of(ConnectionProtocol.CONFIGURATION), Optional.of(PacketFlow.CLIENTBOUND), version, optional);
|
||||
public <T extends CustomPacketPayload> PayloadRegistrar configurationToClient(CustomPacketPayload.Type<T> type, StreamCodec<? super FriendlyByteBuf, T> codec, IPayloadHandler<T> handler) {
|
||||
register(type, codec, null, handler, List.of(ConnectionProtocol.CONFIGURATION), Optional.of(PacketFlow.CLIENTBOUND), version, optional);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a client-bound payload for the configuration phase without a handler. The missing handler must be registered via {@code RegisterClientPayloadHandlersEvent}.
|
||||
*/
|
||||
public <T extends CustomPacketPayload> PayloadRegistrar configurationToClient(CustomPacketPayload.Type<T> type, StreamCodec<? super FriendlyByteBuf, T> codec) {
|
||||
register(type, codec, null, null, List.of(ConnectionProtocol.CONFIGURATION), Optional.of(PacketFlow.CLIENTBOUND), version, optional);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a server-bound payload for the configuration phase.
|
||||
*/
|
||||
public <T extends CustomPacketPayload> PayloadRegistrar configurationToServer(CustomPacketPayload.Type<T> type, StreamCodec<? super FriendlyByteBuf, T> reader, IPayloadHandler<T> handler) {
|
||||
register(type, reader, handler, List.of(ConnectionProtocol.CONFIGURATION), Optional.of(PacketFlow.SERVERBOUND), version, optional);
|
||||
public <T extends CustomPacketPayload> PayloadRegistrar configurationToServer(CustomPacketPayload.Type<T> type, StreamCodec<? super FriendlyByteBuf, T> codec, IPayloadHandler<T> handler) {
|
||||
register(type, codec, handler, null, List.of(ConnectionProtocol.CONFIGURATION), Optional.of(PacketFlow.SERVERBOUND), version, optional);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a bidirectional payload for the configuration phase.
|
||||
* <p>
|
||||
* Consider using {@link DirectionalPayloadHandler} to wrap client and server handlers.
|
||||
* If the provided {@linkplain IPayloadHandler client handler} is null, it must be registered via {@code RegisterClientPayloadHandlersEvent}
|
||||
*/
|
||||
public <T extends CustomPacketPayload> PayloadRegistrar configurationBidirectional(CustomPacketPayload.Type<T> type, StreamCodec<? super FriendlyByteBuf, T> reader, IPayloadHandler<T> handler) {
|
||||
register(type, reader, handler, List.of(ConnectionProtocol.CONFIGURATION), Optional.empty(), version, optional);
|
||||
public <T extends CustomPacketPayload> PayloadRegistrar configurationBidirectional(CustomPacketPayload.Type<T> type, StreamCodec<? super FriendlyByteBuf, T> codec, IPayloadHandler<T> serverHandler, @Nullable IPayloadHandler<T> clientHandler) {
|
||||
register(type, codec, serverHandler, clientHandler, List.of(ConnectionProtocol.CONFIGURATION), Optional.empty(), version, optional);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a bidirectional payload for the configuration phase.
|
||||
* <p>
|
||||
* The provided handler is registered for serverbound payloads and the client-side handler must be registered via {@code RegisterClientPayloadHandlersEvent}
|
||||
*/
|
||||
public <T extends CustomPacketPayload> PayloadRegistrar configurationBidirectional(CustomPacketPayload.Type<T> type, StreamCodec<? super FriendlyByteBuf, T> codec, IPayloadHandler<T> serverHandler) {
|
||||
return this.configurationBidirectional(type, codec, serverHandler, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a client-bound payload for all phases.
|
||||
*/
|
||||
public <T extends CustomPacketPayload> PayloadRegistrar commonToClient(CustomPacketPayload.Type<T> type, StreamCodec<? super FriendlyByteBuf, T> reader, IPayloadHandler<T> handler) {
|
||||
register(type, reader, handler, List.of(ConnectionProtocol.PLAY, ConnectionProtocol.CONFIGURATION), Optional.of(PacketFlow.CLIENTBOUND), version, optional);
|
||||
public <T extends CustomPacketPayload> PayloadRegistrar commonToClient(CustomPacketPayload.Type<T> type, StreamCodec<? super FriendlyByteBuf, T> codec, IPayloadHandler<T> handler) {
|
||||
register(type, codec, null, handler, List.of(ConnectionProtocol.PLAY, ConnectionProtocol.CONFIGURATION), Optional.of(PacketFlow.CLIENTBOUND), version, optional);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a client-bound payload for all phases without a handler. The missing handler must be registered via {@code RegisterClientPayloadHandlersEvent}.
|
||||
*/
|
||||
public <T extends CustomPacketPayload> PayloadRegistrar commonToClient(CustomPacketPayload.Type<T> type, StreamCodec<? super FriendlyByteBuf, T> codec) {
|
||||
register(type, codec, null, null, List.of(ConnectionProtocol.PLAY, ConnectionProtocol.CONFIGURATION), Optional.of(PacketFlow.CLIENTBOUND), version, optional);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a server-bound payload for all phases.
|
||||
*/
|
||||
public <T extends CustomPacketPayload> PayloadRegistrar commonToServer(CustomPacketPayload.Type<T> type, StreamCodec<? super FriendlyByteBuf, T> reader, IPayloadHandler<T> handler) {
|
||||
register(type, reader, handler, List.of(ConnectionProtocol.PLAY, ConnectionProtocol.CONFIGURATION), Optional.of(PacketFlow.SERVERBOUND), version, optional);
|
||||
public <T extends CustomPacketPayload> PayloadRegistrar commonToServer(CustomPacketPayload.Type<T> type, StreamCodec<? super FriendlyByteBuf, T> codec, IPayloadHandler<T> handler) {
|
||||
register(type, codec, handler, null, List.of(ConnectionProtocol.PLAY, ConnectionProtocol.CONFIGURATION), Optional.of(PacketFlow.SERVERBOUND), version, optional);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a bidirectional payload for all phases.
|
||||
* <p>
|
||||
* Consider using {@link DirectionalPayloadHandler} to wrap client and server handlers.
|
||||
* If the provided {@linkplain IPayloadHandler client handler} is null, it must be registered via {@code RegisterClientPayloadHandlersEvent}
|
||||
*/
|
||||
public <T extends CustomPacketPayload> PayloadRegistrar commonBidirectional(CustomPacketPayload.Type<T> type, StreamCodec<? super FriendlyByteBuf, T> reader, IPayloadHandler<T> handler) {
|
||||
register(type, reader, handler, List.of(ConnectionProtocol.PLAY, ConnectionProtocol.CONFIGURATION), Optional.empty(), version, optional);
|
||||
public <T extends CustomPacketPayload> PayloadRegistrar commonBidirectional(CustomPacketPayload.Type<T> type, StreamCodec<? super FriendlyByteBuf, T> codec, IPayloadHandler<T> serverHandler, @Nullable IPayloadHandler<T> clientHandler) {
|
||||
register(type, codec, serverHandler, clientHandler, List.of(ConnectionProtocol.PLAY, ConnectionProtocol.CONFIGURATION), Optional.empty(), version, optional);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a bidirectional payload for all phases.
|
||||
* <p>
|
||||
* The provided handler is registered for serverbound payloads and the client-side handler must be registered via {@code RegisterClientPayloadHandlersEvent}
|
||||
*/
|
||||
public <T extends CustomPacketPayload> PayloadRegistrar commonBidirectional(CustomPacketPayload.Type<T> type, StreamCodec<? super FriendlyByteBuf, T> codec, IPayloadHandler<T> serverHandler) {
|
||||
return this.commonBidirectional(type, codec, serverHandler, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a copy of this registrar with a different default handling thread.
|
||||
* <p>
|
||||
@ -161,11 +212,23 @@ public class PayloadRegistrar {
|
||||
return clone;
|
||||
}
|
||||
|
||||
private <T extends CustomPacketPayload, B extends FriendlyByteBuf> void register(CustomPacketPayload.Type<T> type, StreamCodec<? super B, T> codec, IPayloadHandler<T> handler,
|
||||
List<ConnectionProtocol> protocols, Optional<PacketFlow> flow, String version, boolean optional) {
|
||||
private <T extends CustomPacketPayload, B extends FriendlyByteBuf> void register(
|
||||
CustomPacketPayload.Type<T> type,
|
||||
StreamCodec<? super B, T> codec,
|
||||
@Nullable IPayloadHandler<T> serverHandler,
|
||||
@Nullable IPayloadHandler<T> clientHandler,
|
||||
List<ConnectionProtocol> protocols,
|
||||
Optional<PacketFlow> flow,
|
||||
String version,
|
||||
boolean optional) {
|
||||
if (this.thread == HandlerThread.MAIN) {
|
||||
handler = new MainThreadPayloadHandler<>(handler);
|
||||
if (serverHandler != null) {
|
||||
serverHandler = new MainThreadPayloadHandler<>(serverHandler);
|
||||
}
|
||||
if (clientHandler != null) {
|
||||
clientHandler = new MainThreadPayloadHandler<>(clientHandler);
|
||||
}
|
||||
}
|
||||
NetworkRegistry.register(type, codec, handler, protocols, flow, version, optional);
|
||||
NetworkRegistry.register(type, codec, serverHandler, clientHandler, protocols, flow, version, optional);
|
||||
}
|
||||
}
|
||||
|
||||
@ -13,7 +13,6 @@ import net.minecraft.network.codec.StreamCodec;
|
||||
import net.minecraft.network.protocol.PacketFlow;
|
||||
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.neoforged.neoforge.network.handling.IPayloadHandler;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
/**
|
||||
@ -21,7 +20,6 @@ import org.jetbrains.annotations.ApiStatus;
|
||||
*
|
||||
* @param type The type of the payload
|
||||
* @param codec The codec for the payload
|
||||
* @param handler The handler for the payload
|
||||
* @param protocols The protocols this payload supports
|
||||
* @param flow The flow this payload supports (empty if both)
|
||||
* @param version The version of the payload
|
||||
@ -32,7 +30,6 @@ import org.jetbrains.annotations.ApiStatus;
|
||||
public record PayloadRegistration<T extends CustomPacketPayload>(
|
||||
CustomPacketPayload.Type<T> type,
|
||||
StreamCodec<? super RegistryFriendlyByteBuf, T> codec,
|
||||
IPayloadHandler<T> handler,
|
||||
List<ConnectionProtocol> protocols,
|
||||
Optional<PacketFlow> flow,
|
||||
String version,
|
||||
|
||||
@ -42,6 +42,7 @@ import net.neoforged.bus.api.IEventBus;
|
||||
import net.neoforged.fml.ModContainer;
|
||||
import net.neoforged.fml.loading.FMLLoader;
|
||||
import net.neoforged.neoforge.client.event.ClientPlayerNetworkEvent;
|
||||
import net.neoforged.neoforge.client.network.ClientPacketDistributor;
|
||||
import net.neoforged.neoforge.common.NeoForge;
|
||||
import net.neoforged.neoforge.event.entity.player.PlayerEvent;
|
||||
import net.neoforged.neoforge.event.server.ServerStartedEvent;
|
||||
@ -322,7 +323,7 @@ public class TestFrameworkImpl implements MutableTestFramework {
|
||||
final ChangeStatusPayload packet = new ChangeStatusPayload(this, test.id(), newStatus);
|
||||
sendPacketIfOn(
|
||||
() -> PacketDistributor.sendToAllPlayers(packet),
|
||||
() -> PacketDistributor.sendToServer(packet),
|
||||
() -> ClientPacketDistributor.sendToServer(packet),
|
||||
null);
|
||||
}
|
||||
|
||||
@ -349,7 +350,7 @@ public class TestFrameworkImpl implements MutableTestFramework {
|
||||
final ChangeEnabledPayload packet = new ChangeEnabledPayload(TestFrameworkImpl.this, test.id(), enabled);
|
||||
sendPacketIfOn(
|
||||
() -> PacketDistributor.sendToAllPlayers(packet),
|
||||
() -> PacketDistributor.sendToServer(packet),
|
||||
() -> ClientPacketDistributor.sendToServer(packet),
|
||||
null);
|
||||
}
|
||||
|
||||
|
||||
@ -21,10 +21,10 @@ public record TestFrameworkPayloadInitialization(MutableTestFramework framework)
|
||||
|
||||
registrar.playBidirectional(ChangeStatusPayload.ID,
|
||||
StreamCodec.of((RegistryFriendlyByteBuf buf, ChangeStatusPayload packet) -> packet.write(buf), buf -> ChangeStatusPayload.decode(framework, buf)),
|
||||
(payload, context) -> payload.handle(context));
|
||||
ChangeStatusPayload::handle, ChangeStatusPayload::handle);
|
||||
|
||||
registrar.playBidirectional(ChangeEnabledPayload.ID,
|
||||
StreamCodec.of((buf, packet) -> packet.write(buf), buf -> ChangeEnabledPayload.decode(framework, buf)),
|
||||
(payload, context) -> payload.handle(context));
|
||||
ChangeEnabledPayload::handle, ChangeEnabledPayload::handle);
|
||||
}
|
||||
}
|
||||
|
||||
@ -57,6 +57,7 @@ public class ModMismatchTest implements IPayloadHandler<ModMismatchTest.ModMisma
|
||||
.configurationBidirectional(
|
||||
ModMismatchPayload.TYPE,
|
||||
ModMismatchPayload.STREAM_CODEC,
|
||||
this,
|
||||
this);
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user