From 605d85891fb939b930d1cf9cad686e3af6071e31 Mon Sep 17 00:00:00 2001 From: Patbox <39821509+Patbox@users.noreply.github.com> Date: Tue, 6 Aug 2024 11:40:14 +0200 Subject: [PATCH 01/11] Start working on Mod Protocol API --- fabric-mod-protocol-api-v1/build.gradle | 3 + .../client/modprotocol/v1/package-info.java | 23 ++++ .../client/ClientModProtocolInit.java | 47 +++++++ .../ClientCommonNetworkHandlerMixin.java | 31 +++++ ...ric-mod-protocol-api-v1.client.mixins.json | 11 ++ .../fabric/impl/modprotocol/ModProtocol.java | 72 ++++++++++ .../impl/modprotocol/ModProtocolInit.java | 50 +++++++ .../impl/modprotocol/ModProtocolLocator.java | 129 ++++++++++++++++++ .../impl/modprotocol/ModProtocolManager.java | 125 +++++++++++++++++ .../modprotocol/RemoteProtocolStorage.java | 8 ++ .../modprotocol/ServerMetadataExtension.java | 18 +++ .../payload/ModProtocolRequestS2CPayload.java | 38 ++++++ .../ModProtocolResponseC2SPayload.java | 46 +++++++ .../modprotocol/ClientConnectionMixin.java | 28 ++++ .../modprotocol/MinecraftServerMixin.java | 24 ++++ .../ServerCommonNetworkHandlerMixin.java | 29 ++++ .../modprotocol/ServerMetadataMixin.java | 71 ++++++++++ .../fabric-mod-protocol-api-v1/icon.png | Bin 0 -> 1579 bytes .../fabric-mod-protocol-api-v1.mixins.json | 14 ++ .../src/main/resources/fabric.mod.json | 42 ++++++ .../unit/VersionMatchingTests.java | 87 ++++++++++++ .../test/modprotocol/ModProtocolTestmods.java | 34 +++++ .../lang/en_us.json | 5 + .../src/testmod/resources/fabric.mod.json | 22 +++ .../v1/ClientConfigurationNetworking.java | 7 + .../ClientConfigurationNetworkAddon.java | 5 +- .../client/ClientLoginNetworkAddon.java | 5 + .../v1/ServerConfigurationNetworking.java | 13 ++ .../networking/v1/ServerPlayNetworking.java | 26 ++++ .../AbstractChanneledNetworkAddon.java | 17 +++ .../impl/networking/AbstractNetworkAddon.java | 3 + .../server/ServerLoginNetworkAddon.java | 5 + .../ServerPlayNetworkHandlerMixin.java | 6 +- .../networking/unit/CommonPacketTests.java | 5 + gradle.properties | 1 + settings.gradle | 1 + 36 files changed, 1048 insertions(+), 3 deletions(-) create mode 100644 fabric-mod-protocol-api-v1/build.gradle create mode 100644 fabric-mod-protocol-api-v1/src/client/java/net/fabricmc/fabric/api/client/modprotocol/v1/package-info.java create mode 100644 fabric-mod-protocol-api-v1/src/client/java/net/fabricmc/fabric/impl/modprotocol/client/ClientModProtocolInit.java create mode 100644 fabric-mod-protocol-api-v1/src/client/java/net/fabricmc/fabric/mixin/modprotocol/client/ClientCommonNetworkHandlerMixin.java create mode 100644 fabric-mod-protocol-api-v1/src/client/resources/fabric-mod-protocol-api-v1.client.mixins.json create mode 100644 fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/ModProtocol.java create mode 100644 fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/ModProtocolInit.java create mode 100644 fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/ModProtocolLocator.java create mode 100644 fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/ModProtocolManager.java create mode 100644 fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/RemoteProtocolStorage.java create mode 100644 fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/ServerMetadataExtension.java create mode 100644 fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/payload/ModProtocolRequestS2CPayload.java create mode 100644 fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/payload/ModProtocolResponseC2SPayload.java create mode 100644 fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/mixin/modprotocol/ClientConnectionMixin.java create mode 100644 fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/mixin/modprotocol/MinecraftServerMixin.java create mode 100644 fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/mixin/modprotocol/ServerCommonNetworkHandlerMixin.java create mode 100644 fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/mixin/modprotocol/ServerMetadataMixin.java create mode 100644 fabric-mod-protocol-api-v1/src/main/resources/assets/fabric-mod-protocol-api-v1/icon.png create mode 100644 fabric-mod-protocol-api-v1/src/main/resources/fabric-mod-protocol-api-v1.mixins.json create mode 100644 fabric-mod-protocol-api-v1/src/main/resources/fabric.mod.json create mode 100644 fabric-mod-protocol-api-v1/src/test/java/net/fabricmc/fabric/test/modprotocol/unit/VersionMatchingTests.java create mode 100644 fabric-mod-protocol-api-v1/src/testmod/java/net/fabricmc/fabric/test/modprotocol/ModProtocolTestmods.java create mode 100644 fabric-mod-protocol-api-v1/src/testmod/resources/assets/fabric-networking-api-v1-testmod/lang/en_us.json create mode 100644 fabric-mod-protocol-api-v1/src/testmod/resources/fabric.mod.json diff --git a/fabric-mod-protocol-api-v1/build.gradle b/fabric-mod-protocol-api-v1/build.gradle new file mode 100644 index 0000000000..60da64c69a --- /dev/null +++ b/fabric-mod-protocol-api-v1/build.gradle @@ -0,0 +1,3 @@ +version = getSubprojectVersion(project) + +moduleDependencies(project, ['fabric-api-base', 'fabric-networking-api-v1']) diff --git a/fabric-mod-protocol-api-v1/src/client/java/net/fabricmc/fabric/api/client/modprotocol/v1/package-info.java b/fabric-mod-protocol-api-v1/src/client/java/net/fabricmc/fabric/api/client/modprotocol/v1/package-info.java new file mode 100644 index 0000000000..6189214552 --- /dev/null +++ b/fabric-mod-protocol-api-v1/src/client/java/net/fabricmc/fabric/api/client/modprotocol/v1/package-info.java @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * The Mod Protocol API (client side), version 1. + * + * Todo + */ + +package net.fabricmc.fabric.api.client.modprotocol.v1; diff --git a/fabric-mod-protocol-api-v1/src/client/java/net/fabricmc/fabric/impl/modprotocol/client/ClientModProtocolInit.java b/fabric-mod-protocol-api-v1/src/client/java/net/fabricmc/fabric/impl/modprotocol/client/ClientModProtocolInit.java new file mode 100644 index 0000000000..ddaae30186 --- /dev/null +++ b/fabric-mod-protocol-api-v1/src/client/java/net/fabricmc/fabric/impl/modprotocol/client/ClientModProtocolInit.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.impl.modprotocol.client; + +import net.fabricmc.fabric.api.client.networking.v1.ClientConfigurationNetworking; +import net.fabricmc.fabric.impl.modprotocol.ModProtocol; +import net.fabricmc.fabric.impl.modprotocol.ModProtocolManager; +import net.fabricmc.fabric.impl.modprotocol.RemoteProtocolStorage; +import net.fabricmc.fabric.impl.modprotocol.payload.ModProtocolRequestS2CPayload; +import net.fabricmc.fabric.impl.modprotocol.payload.ModProtocolResponseC2SPayload; + +import net.minecraft.text.Text; + +import java.util.HashMap; + +public final class ClientModProtocolInit { + + public static void clientInit() { + ClientConfigurationNetworking.registerGlobalReceiver(ModProtocolRequestS2CPayload.ID, (payload, context) -> { + var map = new HashMap(payload.modProtocol().size()); + for (var protocol : payload.modProtocol()) { + map.put(protocol.id(), protocol); + } + var validate = ModProtocolManager.validateClient(map); + if (validate.isSuccess()) { + ((RemoteProtocolStorage) context.networkHandler()).fabric$setRemoteProtocol(validate.supportedProtocols()); + context.responseSender().sendPacket(new ModProtocolResponseC2SPayload(validate.supportedProtocols())); + return; + } + context.responseSender().disconnect(Text.literal("Todo wrong protocol text")); + }); + } +} diff --git a/fabric-mod-protocol-api-v1/src/client/java/net/fabricmc/fabric/mixin/modprotocol/client/ClientCommonNetworkHandlerMixin.java b/fabric-mod-protocol-api-v1/src/client/java/net/fabricmc/fabric/mixin/modprotocol/client/ClientCommonNetworkHandlerMixin.java new file mode 100644 index 0000000000..4a3e87054e --- /dev/null +++ b/fabric-mod-protocol-api-v1/src/client/java/net/fabricmc/fabric/mixin/modprotocol/client/ClientCommonNetworkHandlerMixin.java @@ -0,0 +1,31 @@ +package net.fabricmc.fabric.mixin.modprotocol.client; + +import it.unimi.dsi.fastutil.objects.Object2IntMap; + +import net.minecraft.client.network.ClientCommonNetworkHandler; + +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +import net.minecraft.network.ClientConnection; +import net.minecraft.server.network.ServerCommonNetworkHandler; + +import net.fabricmc.fabric.impl.modprotocol.RemoteProtocolStorage; + +@Mixin(ClientCommonNetworkHandler.class) +public class ClientCommonNetworkHandlerMixin implements RemoteProtocolStorage { + @Shadow + @Final + protected ClientConnection connection; + + @Override + public Object2IntMap fabric$getRemoteProtocol() { + return ((RemoteProtocolStorage) this.connection).fabric$getRemoteProtocol(); + } + + @Override + public void fabric$setRemoteProtocol(Object2IntMap protocol) { + ((RemoteProtocolStorage) this.connection).fabric$setRemoteProtocol(protocol); + } +} diff --git a/fabric-mod-protocol-api-v1/src/client/resources/fabric-mod-protocol-api-v1.client.mixins.json b/fabric-mod-protocol-api-v1/src/client/resources/fabric-mod-protocol-api-v1.client.mixins.json new file mode 100644 index 0000000000..f5f8b0ed45 --- /dev/null +++ b/fabric-mod-protocol-api-v1/src/client/resources/fabric-mod-protocol-api-v1.client.mixins.json @@ -0,0 +1,11 @@ +{ + "required": true, + "package": "net.fabricmc.fabric.mixin.modprotocol.client", + "compatibilityLevel": "JAVA_17", + "mixins": [ + "ClientCommonNetworkHandlerMixin" + ], + "injectors": { + "defaultRequire": 1 + } +} diff --git a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/ModProtocol.java b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/ModProtocol.java new file mode 100644 index 0000000000..561de5669c --- /dev/null +++ b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/ModProtocol.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.impl.modprotocol; + +import java.util.List; +import java.util.stream.IntStream; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import it.unimi.dsi.fastutil.ints.IntList; + +import net.minecraft.network.PacketByteBuf; +import net.minecraft.network.codec.PacketCodec; + +public record ModProtocol(String id, String displayName, String displayVersion, IntList protocols, boolean requiredClient, boolean requiredServer) { + public static final int UNSUPPORTED = -1; + public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( + Codec.STRING.fieldOf("id").forGetter(ModProtocol::id), + Codec.STRING.fieldOf("name").forGetter(ModProtocol::displayName), + Codec.STRING.fieldOf("version").forGetter(ModProtocol::displayVersion), + Codec.INT_STREAM.xmap(x -> IntList.of(x.toArray()), x -> IntStream.of(x.toIntArray())).fieldOf("protocol").forGetter(ModProtocol::protocols), + Codec.BOOL.fieldOf("require_client").forGetter(ModProtocol::requiredClient), + Codec.BOOL.fieldOf("require_server").forGetter(ModProtocol::requiredServer) + ).apply(instance, ModProtocol::new)); + public static final Codec> LIST_CODEC = CODEC.listOf(); + public int getHighestVersion(IntList list) { + int value = UNSUPPORTED; + for (int i = 0; i < list.size(); i++) { + var proto = list.getInt(i); + if (this.protocols.contains(proto) && value < proto) { + value = proto; + } + } + + return value; + } + + public static final PacketCodec PACKET_CODEC = PacketCodec.ofStatic(ModProtocol::encode, ModProtocol::decode); + + private static ModProtocol decode(PacketByteBuf buf) { + var id = buf.readString(); + var name = buf.readString(); + var version = buf.readString(); + var protocols = IntList.of(buf.readIntArray()); + var b = buf.readByte(); + var requireClient = (b & 0b10) != 0; + var requireServer = (b & 0b01) != 0; + return new ModProtocol(id, name, version, protocols, requireClient, requireServer); + } + + private static void encode(PacketByteBuf buf, ModProtocol protocol) { + buf.writeString(protocol.id); + buf.writeString(protocol.displayName); + buf.writeString(protocol.displayVersion); + buf.writeIntArray(protocol.protocols.toIntArray()); + buf.writeByte((protocol.requiredClient ? 0b10 : 0) | (protocol.requiredServer ? 0b01 : 0)); + } +} diff --git a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/ModProtocolInit.java b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/ModProtocolInit.java new file mode 100644 index 0000000000..e27c8a867e --- /dev/null +++ b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/ModProtocolInit.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.impl.modprotocol; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import net.minecraft.util.Identifier; + +import net.fabricmc.fabric.api.event.Event; +import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry; +import net.fabricmc.fabric.api.networking.v1.ServerConfigurationConnectionEvents; +import net.fabricmc.fabric.api.networking.v1.ServerConfigurationNetworking; +import net.fabricmc.fabric.impl.modprotocol.payload.ModProtocolRequestS2CPayload; +import net.fabricmc.fabric.impl.modprotocol.payload.ModProtocolResponseC2SPayload; + +public final class ModProtocolInit { + public static final String MOD_ID = "fabric-mod-protocol-api-v1"; + public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID); + + + public static void init() { + var phase = Identifier.of("fabric", "mod_protocol"); + ServerConfigurationConnectionEvents.BEFORE_CONFIGURE.addPhaseOrdering(phase, Event.DEFAULT_PHASE); + ServerConfigurationConnectionEvents.BEFORE_CONFIGURE.register(ModProtocolManager::setupClient); + ModProtocolManager.collectModProtocols(); + PayloadTypeRegistry.configurationC2S().register(ModProtocolResponseC2SPayload.ID, ModProtocolResponseC2SPayload.PACKET_CODEC); + PayloadTypeRegistry.configurationS2C().register(ModProtocolRequestS2CPayload.ID, ModProtocolRequestS2CPayload.PACKET_CODEC); + + ServerConfigurationNetworking.registerGlobalReceiver(ModProtocolResponseC2SPayload.ID, (payload, context) -> { + // Todo: store result on the connection for further usage/api + ((RemoteProtocolStorage) context.networkHandler()).fabric$setRemoteProtocol(payload.supported()); + context.networkHandler().completeTask(ModProtocolManager.SyncConfigurationTask.KEY); + }); + } +} diff --git a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/ModProtocolLocator.java b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/ModProtocolLocator.java new file mode 100644 index 0000000000..e1e8eddd5d --- /dev/null +++ b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/ModProtocolLocator.java @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.impl.modprotocol; + +import java.util.function.BiConsumer; + +import it.unimi.dsi.fastutil.ints.IntArrayList; +import it.unimi.dsi.fastutil.ints.IntList; + +import net.fabricmc.loader.api.FabricLoader; +import net.fabricmc.loader.api.ModContainer; +import net.fabricmc.loader.api.metadata.CustomValue; +import net.fabricmc.loader.api.metadata.ModMetadata; + +public class ModProtocolLocator { + public static void provide(BiConsumer consumer) { + for (var mod : FabricLoader.getInstance().getAllMods()) { + create(mod, consumer); + } + } + private static void create(ModContainer container, BiConsumer consumer) { + var meta = container.getMetadata(); + var definition = meta.getCustomValue("fabric:mod_protocol"); + if (definition == null) { + return; + } + + if (definition.getType() == CustomValue.CvType.ARRAY) { + for (var entry : definition.getAsArray()) { + consumer.accept(container, decodeFullDefinition(entry, meta, true)); + } + } else if (definition.getType() == CustomValue.CvType.NUMBER) { + consumer.accept(container, new ModProtocol(meta.getId(), meta.getName(), meta.getVersion().getFriendlyString(), IntList.of(definition.getAsNumber().intValue()), true, true)); + } else { + consumer.accept(container, decodeFullDefinition(definition, meta, false)); + } + } + + private static ModProtocol decodeFullDefinition(CustomValue entry, ModMetadata meta, boolean requireFullData) { + if (entry.getType() != CustomValue.CvType.OBJECT) { + throw new RuntimeException("Mod Protocol entry provided by '" + meta.getId() + "' is not valid!"); + } + var object = entry.getAsObject(); + String id; + String name; + String version; + boolean requiredClient; + boolean requiredServer; + IntList protocols = new IntArrayList(); + + var idField = object.get("id"); + var nameField = object.get("name"); + var versionField = object.get("version"); + var protocolField = object.get("protocol"); + var requiredClientField = object.get("require_client"); + var requiredServerField = object.get("require_server"); + + if (!requireFullData && idField == null) { + id = meta.getId(); + } else if (idField.getType() == CustomValue.CvType.STRING) { + id = idField.getAsString(); + } else { + throw new RuntimeException("Mod Protocol entry provided by '" + meta.getId() + "' is not valid!"); + } + + if (protocolField.getType() == CustomValue.CvType.NUMBER) { + protocols.add(protocolField.getAsNumber().intValue()); + } else if (protocolField.getType() == CustomValue.CvType.ARRAY) { + for (var value : protocolField.getAsArray()) { + if (value.getType() == CustomValue.CvType.NUMBER) { + protocols.add(value.getAsNumber().intValue()); + } else { + throw new RuntimeException("Mod Protocol entry provided by '" + meta.getId() + "' is not valid!"); + } + } + } else { + throw new RuntimeException("Mod Protocol entry provided by '" + meta.getId() + "' is not valid!"); + } + + if (!requireFullData && nameField == null) { + name = meta.getName(); + } else if (nameField.getType() == CustomValue.CvType.STRING) { + name = nameField.getAsString(); + } else { + throw new RuntimeException("Mod Protocol entry provided by '" + meta.getId() + "' is not valid!"); + } + + if (!requireFullData && versionField == null) { + version = meta.getName(); + } else if (versionField.getType() == CustomValue.CvType.STRING) { + version = versionField.getAsString(); + } else { + throw new RuntimeException("Mod Protocol entry provided by '" + meta.getId() + "' is not valid!"); + } + + if (requiredClientField == null) { + requiredClient = true; + } else if (requiredClientField.getType() == CustomValue.CvType.BOOLEAN) { + requiredClient = requiredClientField.getAsBoolean(); + } else { + throw new RuntimeException("Mod Protocol entry provided by '" + meta.getId() + "' is not valid!"); + } + + if (requiredServerField == null) { + requiredServer = true; + } else if (requiredServerField.getType() == CustomValue.CvType.BOOLEAN) { + requiredServer = requiredServerField.getAsBoolean(); + } else { + throw new RuntimeException("Mod Protocol entry provided by '" + meta.getId() + "' is not valid!"); + } + + + return new ModProtocol(id, name, version, protocols, requiredClient, requiredServer); + } +} diff --git a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/ModProtocolManager.java b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/ModProtocolManager.java new file mode 100644 index 0000000000..8c30248a8f --- /dev/null +++ b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/ModProtocolManager.java @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.impl.modprotocol; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Consumer; + +import it.unimi.dsi.fastutil.objects.Object2IntMap; +import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; + +import net.minecraft.network.packet.Packet; +import net.minecraft.network.packet.s2c.common.CustomPayloadS2CPacket; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.network.ServerConfigurationNetworkHandler; +import net.minecraft.server.network.ServerPlayerConfigurationTask; +import net.minecraft.text.Text; + +import net.fabricmc.fabric.api.networking.v1.ServerConfigurationNetworking; +import net.fabricmc.fabric.impl.modprotocol.payload.ModProtocolRequestS2CPayload; +import net.fabricmc.loader.api.ModContainer; + +public final class ModProtocolManager { + public static final Map LOCAL_MOD_PROTOCOLS_BY_ID = new HashMap<>(); + public static final List LOCAL_MOD_PROTOCOLS = new ArrayList<>(); + public static final List CLIENT_REQUIRED = new ArrayList<>(); + public static final List SERVER_REQUIRED = new ArrayList<>(); + + public static void setupClient(ServerConfigurationNetworkHandler handler, MinecraftServer server) { + if (!ServerConfigurationNetworking.canSend(handler, ModProtocolRequestS2CPayload.ID)) { + if (CLIENT_REQUIRED.isEmpty()) { + return; + } else { + handler.disconnect(Text.literal("Server requires mods // todo better message")); + } + } + + handler.addTask(new SyncConfigurationTask()); + } + + public static ValidationResult validateClient(Map received) { + return validate(received, LOCAL_MOD_PROTOCOLS_BY_ID, SERVER_REQUIRED); + } + + public static ValidationResult validate(Map received, Map localById, List requiredRemote) { + var supported = new Object2IntOpenHashMap(); + var missingLocal = new ArrayList(); + var missingRemote = new ArrayList(); + + for (var modProtocol : received.values()) { + var local = localById.get(modProtocol.id()); + if (local != null) { + supported.put(modProtocol.id(), local.getHighestVersion(modProtocol.protocols())); + } else if (modProtocol.requiredClient()) { + missingLocal.add(modProtocol); + } + } + + for (var modProtocol : requiredRemote) { + var remote = received.get(modProtocol.id()); + if (remote == null || supported.getOrDefault(modProtocol.id(), -1) == -1) { + missingRemote.add(modProtocol); + } + } + + + return new ValidationResult(supported, missingLocal, missingRemote); + } + + public static void collectModProtocols() { + ModProtocolLocator.provide(ModProtocolManager::add); + + } + + private static void add(ModContainer container, ModProtocol protocol) { + if (LOCAL_MOD_PROTOCOLS_BY_ID.containsKey(protocol.id())) { + ModProtocolInit.LOGGER.warn("Found duplicate protocol id '{}' provided by mod '{}'", protocol.id(), container.getMetadata().getId()); + return; + } + LOCAL_MOD_PROTOCOLS_BY_ID.put(protocol.id(), protocol); + LOCAL_MOD_PROTOCOLS.add(protocol); + + if (protocol.requiredClient()) { + CLIENT_REQUIRED.add(protocol); + } + if (protocol.requiredServer()) { + SERVER_REQUIRED.add(protocol); + } + } + + public static class SyncConfigurationTask implements ServerPlayerConfigurationTask { + public static final Key KEY = new Key("fabric:mod_protocol_sync"); + @Override + public void sendPacket(Consumer> sender) { + sender.accept(new CustomPayloadS2CPacket(new ModProtocolRequestS2CPayload(LOCAL_MOD_PROTOCOLS))); + } + + @Override + public Key getKey() { + return KEY; + } + } + + public record ValidationResult(Object2IntMap supportedProtocols, List missingLocal, List missingRemote) { + public boolean isSuccess() { + return missingLocal.isEmpty() && missingRemote.isEmpty(); + } + } +} diff --git a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/RemoteProtocolStorage.java b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/RemoteProtocolStorage.java new file mode 100644 index 0000000000..716b54b34c --- /dev/null +++ b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/RemoteProtocolStorage.java @@ -0,0 +1,8 @@ +package net.fabricmc.fabric.impl.modprotocol; + +import it.unimi.dsi.fastutil.objects.Object2IntMap; + +public interface RemoteProtocolStorage { + Object2IntMap fabric$getRemoteProtocol(); + void fabric$setRemoteProtocol(Object2IntMap protocol); +} diff --git a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/ServerMetadataExtension.java b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/ServerMetadataExtension.java new file mode 100644 index 0000000000..678210e84a --- /dev/null +++ b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/ServerMetadataExtension.java @@ -0,0 +1,18 @@ +package net.fabricmc.fabric.impl.modprotocol; + +import net.minecraft.server.ServerMetadata; + +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +public interface ServerMetadataExtension { + static ServerMetadataExtension of(ServerMetadata input) { + return (ServerMetadataExtension) (Object) input; + } + + @Nullable + List fabric$getModProtocol(); + void fabric$setModProtocol(List protocol); + +} diff --git a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/payload/ModProtocolRequestS2CPayload.java b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/payload/ModProtocolRequestS2CPayload.java new file mode 100644 index 0000000000..2afdeeb547 --- /dev/null +++ b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/payload/ModProtocolRequestS2CPayload.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.impl.modprotocol.payload; + +import java.util.List; + +import net.minecraft.network.PacketByteBuf; +import net.minecraft.network.codec.PacketCodec; +import net.minecraft.network.codec.PacketCodecs; +import net.minecraft.network.packet.CustomPayload; +import net.minecraft.util.Identifier; + +import net.fabricmc.fabric.impl.modprotocol.ModProtocol; + +public record ModProtocolRequestS2CPayload(List modProtocol) implements CustomPayload { + public static final Id ID = new Id<>(Identifier.of("fabric", "mod_protocol_request")); + public static final PacketCodec PACKET_CODEC = ModProtocol.PACKET_CODEC.collect(PacketCodecs.toList()) + .xmap(ModProtocolRequestS2CPayload::new, ModProtocolRequestS2CPayload::modProtocol); + + @Override + public Id getId() { + return ID; + } +} diff --git a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/payload/ModProtocolResponseC2SPayload.java b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/payload/ModProtocolResponseC2SPayload.java new file mode 100644 index 0000000000..af8fea211c --- /dev/null +++ b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/payload/ModProtocolResponseC2SPayload.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.impl.modprotocol.payload; + + + +import it.unimi.dsi.fastutil.objects.Object2IntMap; +import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; + +import net.minecraft.network.PacketByteBuf; +import net.minecraft.network.codec.PacketCodec; +import net.minecraft.network.codec.PacketCodecs; +import net.minecraft.network.packet.CustomPayload; +import net.minecraft.util.Identifier; + +import java.util.Map; + + +public record ModProtocolResponseC2SPayload(Object2IntMap supported) implements CustomPayload { + public static final Id ID = new Id<>(Identifier.of("fabric", "mod_protocol/response")); + public static final PacketCodec PACKET_CODEC = PacketCodecs.map(ModProtocolResponseC2SPayload::createMap, PacketCodecs.STRING, PacketCodecs.INTEGER) + .xmap(ModProtocolResponseC2SPayload::new, ModProtocolResponseC2SPayload::supported).cast(); + + private static Object2IntMap createMap(int i) { + return new Object2IntOpenHashMap<>(i); + } + + @Override + public Id getId() { + return ID; + } +} diff --git a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/mixin/modprotocol/ClientConnectionMixin.java b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/mixin/modprotocol/ClientConnectionMixin.java new file mode 100644 index 0000000000..02a096f746 --- /dev/null +++ b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/mixin/modprotocol/ClientConnectionMixin.java @@ -0,0 +1,28 @@ +package net.fabricmc.fabric.mixin.modprotocol; + +import it.unimi.dsi.fastutil.objects.Object2IntMap; + +import it.unimi.dsi.fastutil.objects.Object2IntMaps; + +import net.fabricmc.fabric.impl.modprotocol.RemoteProtocolStorage; + +import net.minecraft.network.ClientConnection; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; + +@Mixin(ClientConnection.class) +public class ClientConnectionMixin implements RemoteProtocolStorage { + @Unique + private Object2IntMap remoteProtocol = Object2IntMaps.emptyMap(); + + @Override + public Object2IntMap fabric$getRemoteProtocol() { + return this.remoteProtocol; + } + + @Override + public void fabric$setRemoteProtocol(Object2IntMap protocol) { + this.remoteProtocol = protocol; + } +} diff --git a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/mixin/modprotocol/MinecraftServerMixin.java b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/mixin/modprotocol/MinecraftServerMixin.java new file mode 100644 index 0000000000..7d7f34814e --- /dev/null +++ b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/mixin/modprotocol/MinecraftServerMixin.java @@ -0,0 +1,24 @@ +package net.fabricmc.fabric.mixin.modprotocol; + +import com.llamalad7.mixinextras.injector.ModifyReturnValue; + +import net.fabricmc.fabric.impl.modprotocol.ModProtocolManager; +import net.fabricmc.fabric.impl.modprotocol.ServerMetadataExtension; + +import net.minecraft.server.MinecraftServer; + +import net.minecraft.server.ServerMetadata; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; + +@Mixin(MinecraftServer.class) +public class MinecraftServerMixin { + @ModifyReturnValue(method = "createMetadata", at = @At("RETURN")) + private ServerMetadata addModProtocol(ServerMetadata original) { + if (!ModProtocolManager.CLIENT_REQUIRED.isEmpty()) { + ServerMetadataExtension.of(original).fabric$setModProtocol(ModProtocolManager.CLIENT_REQUIRED); + } + return original; + } +} diff --git a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/mixin/modprotocol/ServerCommonNetworkHandlerMixin.java b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/mixin/modprotocol/ServerCommonNetworkHandlerMixin.java new file mode 100644 index 0000000000..cad91b377a --- /dev/null +++ b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/mixin/modprotocol/ServerCommonNetworkHandlerMixin.java @@ -0,0 +1,29 @@ +package net.fabricmc.fabric.mixin.modprotocol; + +import it.unimi.dsi.fastutil.objects.Object2IntMap; + +import net.fabricmc.fabric.impl.modprotocol.RemoteProtocolStorage; + +import net.minecraft.network.ClientConnection; +import net.minecraft.server.network.ServerCommonNetworkHandler; + +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +@Mixin(ServerCommonNetworkHandler.class) +public class ServerCommonNetworkHandlerMixin implements RemoteProtocolStorage { + @Shadow + @Final + protected ClientConnection connection; + + @Override + public Object2IntMap fabric$getRemoteProtocol() { + return ((RemoteProtocolStorage) this.connection).fabric$getRemoteProtocol(); + } + + @Override + public void fabric$setRemoteProtocol(Object2IntMap protocol) { + ((RemoteProtocolStorage) this.connection).fabric$setRemoteProtocol(protocol); + } +} diff --git a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/mixin/modprotocol/ServerMetadataMixin.java b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/mixin/modprotocol/ServerMetadataMixin.java new file mode 100644 index 0000000000..7f4165ac24 --- /dev/null +++ b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/mixin/modprotocol/ServerMetadataMixin.java @@ -0,0 +1,71 @@ +package net.fabricmc.fabric.mixin.modprotocol; + +import com.llamalad7.mixinextras.injector.ModifyExpressionValue; + +import com.mojang.datafixers.util.Pair; +import com.mojang.serialization.Codec; + +import com.mojang.serialization.DataResult; +import com.mojang.serialization.DynamicOps; + +import net.fabricmc.fabric.impl.modprotocol.ModProtocol; +import net.fabricmc.fabric.impl.modprotocol.ServerMetadataExtension; + +import net.minecraft.server.ServerMetadata; + +import org.jetbrains.annotations.Nullable; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; + +import java.util.List; + +@Mixin(ServerMetadata.class) +public class ServerMetadataMixin implements ServerMetadataExtension { + @Unique + @Nullable + private List modProtocol; + + @Override + public List fabric$getModProtocol() { + return this.modProtocol; + } + + @Override + public void fabric$setModProtocol(List protocol) { + this.modProtocol = protocol; + } + + @ModifyExpressionValue(method = "", at = @At(value = "INVOKE", target = "Lcom/mojang/serialization/codecs/RecordCodecBuilder;create(Ljava/util/function/Function;)Lcom/mojang/serialization/Codec;")) + private static Codec extendCodec(Codec original) { + return new Codec<>() { + @Override + public DataResult> decode(DynamicOps ops, T input) { + var decoded = original.decode(ops, input); + if (decoded.isSuccess()) { + var protocol = ops.get(input, "fabric:mod_protocol"); + if (protocol.isSuccess()) { + var result = ModProtocol.LIST_CODEC.decode(ops, protocol.getOrThrow()); + if (result.isSuccess()) { + ServerMetadataExtension.of(decoded.getOrThrow().getFirst()).fabric$setModProtocol(result.getOrThrow().getFirst()); + } + } + } + return decoded; + } + + @Override + public DataResult encode(ServerMetadata input, DynamicOps ops, T prefix) { + var encode = original.encode(input, ops, prefix); + if (encode.isSuccess() && ServerMetadataExtension.of(input).fabric$getModProtocol() != null) { + var protocol = ModProtocol.LIST_CODEC.encodeStart(ops, ServerMetadataExtension.of(input).fabric$getModProtocol()); + if (protocol.isSuccess()) { + encode = ops.mergeToMap(encode.getOrThrow(), ops.createString("fabric:mod_protocol"), protocol.getOrThrow()); + } + } + + return encode; + } + }; + } +} diff --git a/fabric-mod-protocol-api-v1/src/main/resources/assets/fabric-mod-protocol-api-v1/icon.png b/fabric-mod-protocol-api-v1/src/main/resources/assets/fabric-mod-protocol-api-v1/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..2931efbf610873c0084debb8690902b0103d27fe GIT binary patch literal 1579 zcmbVMTWB0r7@iGm)TAXsYw<=rnU=;v=W=GRbL=!tc4Brl6GO7t2vVJ$IlDV#XU;e? z+r2ymsZdMQqAyaFLLUo;RumtE8Z@?uf_*4nP^4;o6fOFoSkN+o1$K?f2nE9_*b5G-l)AV)k5Qhb^- zU{V4ZnTKgnmXdpcB*Kg!W(1hvM2N&RO30x1u~eI9meGQGe@_?PDQq%q1CiV$8~M7 z?MQ_mOdqCh^a65Sv|ntwSXjV5se1;VK1|Kr8G7TQoQL&*ctt{L{fClG}xPK5k^yK3%T69N6J=>3jBqc zDNvZsrJ-yOXI^^mWf1cmY^XST)CVzIGjvEPENowmy}ax zvJ8_(Cf#+H-dBlH53`_u-~6BVAMz|(g?jCVdBWNZ(+A}(pFV7>S3QgPiQcMaflkIC z-3Ti|VT~{au*vq0ts9O&m$p&Gl=L6+q6_m$IcVq}o~+Pl{g>1esQp4%wp~|*zk1n` zZ7T6Toc4`y88s}riCP|ZXrJ?FLz@^KTcyqLjey zu95Yz%F&S{<0~f)Iomek?+hQ%MhCu%T^zsg>C_L`1`Br`xNY&))k9yTQb$JC>)w_f zpU(^tu^Q)y%W~lVz`jz;_ jF?g&s@Y=Qe&c#kW|JbvqK0Y=Rw)4XDoVqsk_>;c_`@;F@ literal 0 HcmV?d00001 diff --git a/fabric-mod-protocol-api-v1/src/main/resources/fabric-mod-protocol-api-v1.mixins.json b/fabric-mod-protocol-api-v1/src/main/resources/fabric-mod-protocol-api-v1.mixins.json new file mode 100644 index 0000000000..c74094c62b --- /dev/null +++ b/fabric-mod-protocol-api-v1/src/main/resources/fabric-mod-protocol-api-v1.mixins.json @@ -0,0 +1,14 @@ +{ + "required": true, + "package": "net.fabricmc.fabric.mixin.modprotocol", + "compatibilityLevel": "JAVA_17", + "mixins": [ + "ClientConnectionMixin", + "MinecraftServerMixin", + "ServerCommonNetworkHandlerMixin", + "ServerMetadataMixin" + ], + "injectors": { + "defaultRequire": 1 + } +} diff --git a/fabric-mod-protocol-api-v1/src/main/resources/fabric.mod.json b/fabric-mod-protocol-api-v1/src/main/resources/fabric.mod.json new file mode 100644 index 0000000000..688b591323 --- /dev/null +++ b/fabric-mod-protocol-api-v1/src/main/resources/fabric.mod.json @@ -0,0 +1,42 @@ +{ + "schemaVersion": 1, + "id": "fabric-mod-protocol-api-v1", + "name": "Fabric Mod Protocol API (v1)", + "version": "${version}", + "environment": "*", + "license": "Apache-2.0", + "icon": "assets/fabric-mod-protocol-api-v1/icon.png", + "contact": { + "homepage": "https://fabricmc.net", + "irc": "irc://irc.esper.net:6667/fabric", + "issues": "https://github.com/FabricMC/fabric/issues", + "sources": "https://github.com/FabricMC/fabric" + }, + "authors": [ + "FabricMC" + ], + "entrypoints": { + "main": [ + "net.fabricmc.fabric.impl.modprotocol.ModProtocolInit::init" + ], + "client": [ + "net.fabricmc.fabric.impl.modprotocol.client.ClientModProtocolInit::clientInit" + ] + }, + "mixins": [ + "fabric-mod-protocol-api-v1.mixins.json", + { + "config": "fabric-mod-protocol-api-v1.client.mixins.json", + "environment": "client" + } +], + "depends": { + "fabricloader": ">=0.15.11", + "fabric-api-base": "*", + "fabric-networking-api-v1": "*" + }, + "description": "Low-level, vanilla protocol oriented networking hooks.", + "custom": { + "fabric-api:module-lifecycle": "experimental" + } +} diff --git a/fabric-mod-protocol-api-v1/src/test/java/net/fabricmc/fabric/test/modprotocol/unit/VersionMatchingTests.java b/fabric-mod-protocol-api-v1/src/test/java/net/fabricmc/fabric/test/modprotocol/unit/VersionMatchingTests.java new file mode 100644 index 0000000000..10bf23fe40 --- /dev/null +++ b/fabric-mod-protocol-api-v1/src/test/java/net/fabricmc/fabric/test/modprotocol/unit/VersionMatchingTests.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.test.modprotocol.unit; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertIterableEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; + +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.network.ClientConfigurationNetworkHandler; +import net.minecraft.network.NetworkPhase; +import net.minecraft.network.PacketByteBuf; +import net.minecraft.network.RegistryByteBuf; +import net.minecraft.network.codec.PacketCodec; +import net.minecraft.network.packet.CustomPayload; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.network.ServerConfigurationNetworkHandler; +import net.minecraft.util.Identifier; + +import net.fabricmc.fabric.api.client.networking.v1.ClientConfigurationNetworking; +import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; +import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; +import net.fabricmc.fabric.api.networking.v1.PacketSender; +import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry; +import net.fabricmc.fabric.api.networking.v1.ServerConfigurationNetworking; +import net.fabricmc.fabric.impl.networking.ChannelInfoHolder; +import net.fabricmc.fabric.impl.networking.CommonPacketHandler; +import net.fabricmc.fabric.impl.networking.CommonPacketsImpl; +import net.fabricmc.fabric.impl.networking.CommonRegisterPayload; +import net.fabricmc.fabric.impl.networking.CommonVersionPayload; +import net.fabricmc.fabric.impl.networking.client.ClientConfigurationNetworkAddon; +import net.fabricmc.fabric.impl.networking.client.ClientNetworkingImpl; +import net.fabricmc.fabric.impl.networking.server.ServerConfigurationNetworkAddon; +import net.fabricmc.fabric.impl.networking.server.ServerNetworkingImpl; + +public class VersionMatchingTests { + @BeforeAll + static void beforeAll() { + + } + + + @BeforeEach + void setUp() { + + } + + // Test handling the version packet on the client + @Test + void handleVersionPacketClient() { + + } +} diff --git a/fabric-mod-protocol-api-v1/src/testmod/java/net/fabricmc/fabric/test/modprotocol/ModProtocolTestmods.java b/fabric-mod-protocol-api-v1/src/testmod/java/net/fabricmc/fabric/test/modprotocol/ModProtocolTestmods.java new file mode 100644 index 0000000000..ff1bf5cfe7 --- /dev/null +++ b/fabric-mod-protocol-api-v1/src/testmod/java/net/fabricmc/fabric/test/modprotocol/ModProtocolTestmods.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.test.modprotocol; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import net.minecraft.util.Identifier; + +public final class ModProtocolTestmods { + public static final String ID = "fabric-modprotocol-api-v1-testmod"; + public static final Logger LOGGER = LoggerFactory.getLogger(ID); + + public static Identifier id(String name) { + return Identifier.of(ID, name); + } + + private ModProtocolTestmods() { + } +} diff --git a/fabric-mod-protocol-api-v1/src/testmod/resources/assets/fabric-networking-api-v1-testmod/lang/en_us.json b/fabric-mod-protocol-api-v1/src/testmod/resources/assets/fabric-networking-api-v1-testmod/lang/en_us.json new file mode 100644 index 0000000000..e8773318a1 --- /dev/null +++ b/fabric-mod-protocol-api-v1/src/testmod/resources/assets/fabric-networking-api-v1-testmod/lang/en_us.json @@ -0,0 +1,5 @@ +{ + "key.category.fabric-networking-api-v1-testmod": "Fabric Network Test", + "key.fabric-networking-api-v1-testmod.test": "Send test packet", + "key.fabric-networking-api-v1-testmod.open": "Open channel tester" +} diff --git a/fabric-mod-protocol-api-v1/src/testmod/resources/fabric.mod.json b/fabric-mod-protocol-api-v1/src/testmod/resources/fabric.mod.json new file mode 100644 index 0000000000..b66665c5df --- /dev/null +++ b/fabric-mod-protocol-api-v1/src/testmod/resources/fabric.mod.json @@ -0,0 +1,22 @@ +{ + "schemaVersion": 1, + "id": "fabric-mod-protocol-api-v1-testmod", + "name": "Fabric Mod Protocol API (v1) Test Mod", + "version": "1.0.0", + "environment": "*", + "license": "Apache-2.0", + "depends": { + "fabric-mod-protocol-api-v1": "*" + }, + "entrypoints": { + "main": [ + + ], + "client": [ + + ] + }, + "custom": { + "fabric:mod_protocol": 5 + } +} diff --git a/fabric-networking-api-v1/src/client/java/net/fabricmc/fabric/api/client/networking/v1/ClientConfigurationNetworking.java b/fabric-networking-api-v1/src/client/java/net/fabricmc/fabric/api/client/networking/v1/ClientConfigurationNetworking.java index 4bf48a9948..52f20c0018 100644 --- a/fabric-networking-api-v1/src/client/java/net/fabricmc/fabric/api/client/networking/v1/ClientConfigurationNetworking.java +++ b/fabric-networking-api-v1/src/client/java/net/fabricmc/fabric/api/client/networking/v1/ClientConfigurationNetworking.java @@ -19,6 +19,8 @@ import java.util.Objects; import java.util.Set; +import net.minecraft.client.network.ClientConfigurationNetworkHandler; + import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; @@ -280,6 +282,11 @@ public interface Context { */ MinecraftClient client(); + /** + * @return The ClientConfigurationNetworkHandler instance + */ + ClientConfigurationNetworkHandler networkHandler(); + /** * @return The packet sender */ diff --git a/fabric-networking-api-v1/src/client/java/net/fabricmc/fabric/impl/networking/client/ClientConfigurationNetworkAddon.java b/fabric-networking-api-v1/src/client/java/net/fabricmc/fabric/impl/networking/client/ClientConfigurationNetworkAddon.java index d391223bb3..17cbcab37b 100644 --- a/fabric-networking-api-v1/src/client/java/net/fabricmc/fabric/impl/networking/client/ClientConfigurationNetworkAddon.java +++ b/fabric-networking-api-v1/src/client/java/net/fabricmc/fabric/impl/networking/client/ClientConfigurationNetworkAddon.java @@ -44,7 +44,7 @@ public final class ClientConfigurationNetworkAddon extends ClientCommonNetworkAd public ClientConfigurationNetworkAddon(ClientConfigurationNetworkHandler handler, MinecraftClient client) { super(ClientNetworkingImpl.CONFIGURATION, ((ClientCommonNetworkHandlerAccessor) handler).getConnection(), "ClientPlayNetworkAddon for " + ((ClientConfigurationNetworkHandlerAccessor) handler).getProfile().getName(), handler, client); - this.context = new ContextImpl(client, this); + this.context = new ContextImpl(client, handler, this); // Must register pending channels via lateinit this.registerPendingChannels((ChannelInfoHolder) this.connection, NetworkPhase.CONFIGURATION); @@ -128,9 +128,10 @@ public ChannelInfoHolder getChannelInfoHolder() { return (ChannelInfoHolder) ((ClientCommonNetworkHandlerAccessor) handler).getConnection(); } - private record ContextImpl(MinecraftClient client, PacketSender responseSender) implements ClientConfigurationNetworking.Context { + private record ContextImpl(MinecraftClient client, ClientConfigurationNetworkHandler networkHandler, PacketSender responseSender) implements ClientConfigurationNetworking.Context { private ContextImpl { Objects.requireNonNull(client, "client"); + Objects.requireNonNull(networkHandler, "networkHandler"); Objects.requireNonNull(responseSender, "responseSender"); } } diff --git a/fabric-networking-api-v1/src/client/java/net/fabricmc/fabric/impl/networking/client/ClientLoginNetworkAddon.java b/fabric-networking-api-v1/src/client/java/net/fabricmc/fabric/impl/networking/client/ClientLoginNetworkAddon.java index e050c0326c..f4e46131aa 100644 --- a/fabric-networking-api-v1/src/client/java/net/fabricmc/fabric/impl/networking/client/ClientLoginNetworkAddon.java +++ b/fabric-networking-api-v1/src/client/java/net/fabricmc/fabric/impl/networking/client/ClientLoginNetworkAddon.java @@ -103,6 +103,11 @@ protected void handleRegistration(Identifier channelName) { protected void handleUnregistration(Identifier channelName) { } + @Override + public @Nullable String getBrand() { + return null; + } + @Override protected void invokeDisconnectEvent() { ClientLoginConnectionEvents.DISCONNECT.invoker().onLoginDisconnect(this.handler, this.client); diff --git a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/api/networking/v1/ServerConfigurationNetworking.java b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/api/networking/v1/ServerConfigurationNetworking.java index 7f6c36cef8..37e0766804 100644 --- a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/api/networking/v1/ServerConfigurationNetworking.java +++ b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/api/networking/v1/ServerConfigurationNetworking.java @@ -224,6 +224,19 @@ public static void send(ServerConfigurationNetworkHandler handler, CustomPayload // Helper methods + /** + * Gets the brand of the client player connected with. + * + * @param handler the network handler, representing the connection to the player/client + * @return client's brand, which might be null if not sent. + */ + @Nullable + public static String getBrand(ServerConfigurationNetworkHandler handler) { + Objects.requireNonNull(handler, "Server configuration network handler cannot be null"); + + return ServerNetworkingImpl.getAddon(handler).getBrand(); + } + /** * Returns the Minecraft Server of a server configuration network handler. * diff --git a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/api/networking/v1/ServerPlayNetworking.java b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/api/networking/v1/ServerPlayNetworking.java index 23d415919b..1574caf87a 100644 --- a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/api/networking/v1/ServerPlayNetworking.java +++ b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/api/networking/v1/ServerPlayNetworking.java @@ -293,6 +293,32 @@ public static void send(ServerPlayerEntity player, CustomPayload payload) { player.networkHandler.sendPacket(createS2CPacket(payload)); } + /** + * Gets the brand of the client player connected with. + * + * @param player the player + * @return client's brand, which might be null if not sent. + */ + @Nullable + public static String getBrand(ServerPlayerEntity player) { + Objects.requireNonNull(player, "Server player entity cannot be null"); + + return getBrand(player.networkHandler); + } + + /** + * Gets the brand of the client player connected with. + * + * @param handler the network handler, representing the connection to the player/client + * @return client's brand, which might be null if not sent. + */ + @Nullable + public static String getBrand(ServerPlayNetworkHandler handler) { + Objects.requireNonNull(handler, "Server play network handler cannot be null"); + + return ServerNetworkingImpl.getAddon(handler).getBrand(); + } + private ServerPlayNetworking() { } diff --git a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/AbstractChanneledNetworkAddon.java b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/AbstractChanneledNetworkAddon.java index efae4a474b..c84031f2c8 100644 --- a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/AbstractChanneledNetworkAddon.java +++ b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/AbstractChanneledNetworkAddon.java @@ -24,6 +24,8 @@ import java.util.Objects; import java.util.Set; +import net.minecraft.network.packet.BrandCustomPayload; + import org.jetbrains.annotations.Nullable; import net.minecraft.network.ClientConnection; @@ -52,6 +54,8 @@ public abstract class AbstractChanneledNetworkAddon extends AbstractNetworkAd protected final Set sendableChannels; protected int commonVersion = -1; + @Nullable + protected String brand = null; protected AbstractChanneledNetworkAddon(GlobalReceiverRegistry receiver, ClientConnection connection, String description) { super(receiver, description); @@ -87,6 +91,10 @@ public boolean handle(CustomPayload payload) { } } + if (payload instanceof BrandCustomPayload brand) { + this.brand = brand.brand(); + } + @Nullable H handler = this.getHandler(channelName); if (handler == null) { @@ -218,6 +226,11 @@ public CommonRegisterPayload createRegisterPayload() { return new CommonRegisterPayload(getNegotiatedVersion(), getPhase(), this.getReceivableChannels()); } + @Nullable + public String getBrand() { + return this.brand; + } + @Override public int getNegotiatedVersion() { if (commonVersion == -1) { @@ -235,4 +248,8 @@ private String getPhase() { default -> null; // We don't support receiving this packet on any other phase }; } + + public void setBrand(String brand) { + this.brand = brand; + } } diff --git a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/AbstractNetworkAddon.java b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/AbstractNetworkAddon.java index 3ce0a675c9..2266c8b8c9 100644 --- a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/AbstractNetworkAddon.java +++ b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/AbstractNetworkAddon.java @@ -155,6 +155,9 @@ public Set getReceivableChannels() { protected abstract void handleUnregistration(Identifier channelName); + @Nullable + public abstract String getBrand(); + public final void handleDisconnect() { if (disconnected.compareAndSet(false, true)) { invokeDisconnectEvent(); diff --git a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/server/ServerLoginNetworkAddon.java b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/server/ServerLoginNetworkAddon.java index 8615467f45..0d214db343 100644 --- a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/server/ServerLoginNetworkAddon.java +++ b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/server/ServerLoginNetworkAddon.java @@ -195,6 +195,11 @@ protected void handleRegistration(Identifier channelName) { protected void handleUnregistration(Identifier channelName) { } + @Override + public @Nullable String getBrand() { + return null; + } + @Override protected void invokeDisconnectEvent() { ServerLoginConnectionEvents.DISCONNECT.invoker().onLoginDisconnect(this.handler, this.server); diff --git a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/mixin/networking/ServerPlayNetworkHandlerMixin.java b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/mixin/networking/ServerPlayNetworkHandlerMixin.java index 7fae773f1d..6207c47ed7 100644 --- a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/mixin/networking/ServerPlayNetworkHandlerMixin.java +++ b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/mixin/networking/ServerPlayNetworkHandlerMixin.java @@ -16,6 +16,7 @@ package net.fabricmc.fabric.mixin.networking; +import com.llamalad7.mixinextras.sugar.Local; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; @@ -44,8 +45,11 @@ abstract class ServerPlayNetworkHandlerMixin extends ServerCommonNetworkHandler } @Inject(method = "", at = @At("RETURN")) - private void initAddon(CallbackInfo ci) { + private void initAddon(CallbackInfo ci, @Local(argsOnly = true) ClientConnection connection) { this.addon = new ServerPlayNetworkAddon((ServerPlayNetworkHandler) (Object) this, connection, server); + if (connection.getPacketListener() instanceof NetworkHandlerExtensions extension) { + this.addon.setBrand(extension.getAddon().getBrand()); + } if (!(this instanceof UntrackedNetworkHandler)) { // A bit of a hack but it allows the field above to be set in case someone registers handlers during INIT event which refers to said field diff --git a/fabric-networking-api-v1/src/test/java/net/fabricmc/fabric/test/networking/unit/CommonPacketTests.java b/fabric-networking-api-v1/src/test/java/net/fabricmc/fabric/test/networking/unit/CommonPacketTests.java index 1674ef82cc..16ff78a53b 100644 --- a/fabric-networking-api-v1/src/test/java/net/fabricmc/fabric/test/networking/unit/CommonPacketTests.java +++ b/fabric-networking-api-v1/src/test/java/net/fabricmc/fabric/test/networking/unit/CommonPacketTests.java @@ -138,6 +138,11 @@ public MinecraftClient client() { return null; } + @Override + public ClientConfigurationNetworkHandler networkHandler() { + return null; + } + @Override public PacketSender responseSender() { return packetSender; diff --git a/gradle.properties b/gradle.properties index a0fa0fa48d..cc59ac5171 100644 --- a/gradle.properties +++ b/gradle.properties @@ -38,6 +38,7 @@ fabric-lifecycle-events-v1-version=2.3.12 fabric-loot-api-v2-version=3.0.14 fabric-loot-api-v3-version=1.0.2 fabric-message-api-v1-version=6.0.13 +fabric-mod-protocol-api-v1-version=0.0.0 fabric-model-loading-api-v1-version=2.0.0 fabric-networking-api-v1-version=4.2.2 fabric-object-builder-api-v1-version=15.1.14 diff --git a/settings.gradle b/settings.gradle index 30f7ff72cb..a033c2d74c 100644 --- a/settings.gradle +++ b/settings.gradle @@ -40,6 +40,7 @@ include 'fabric-lifecycle-events-v1' include 'fabric-loot-api-v3' include 'fabric-message-api-v1' include 'fabric-model-loading-api-v1' +include 'fabric-mod-protocol-api-v1' include 'fabric-networking-api-v1' include 'fabric-object-builder-api-v1' include 'fabric-particles-v1' From 5d1f97080ffde3685181b84ace3db24cc4ad6ec7 Mon Sep 17 00:00:00 2001 From: Patbox <39821509+Patbox@users.noreply.github.com> Date: Tue, 6 Aug 2024 22:23:51 +0200 Subject: [PATCH 02/11] Implement error messages, move ids to Identifier --- .../client/ClientModProtocolInit.java | 19 +++-- .../ClientCommonNetworkHandlerMixin.java | 26 ++++-- .../fabric/impl/modprotocol/ModProtocol.java | 13 ++- .../impl/modprotocol/ModProtocolHolder.java | 34 ++++++++ .../impl/modprotocol/ModProtocolInit.java | 1 - .../impl/modprotocol/ModProtocolLocator.java | 10 ++- .../impl/modprotocol/ModProtocolManager.java | 81 ++++++++++++++++--- .../modprotocol/RemoteProtocolStorage.java | 24 +++++- .../modprotocol/ServerMetadataExtension.java | 18 ----- .../fabric/impl/modprotocol/TextUtil.java | 54 +++++++++++++ .../ModProtocolResponseC2SPayload.java | 8 +- .../modprotocol/ClientConnectionMixin.java | 34 +++++--- .../modprotocol/MinecraftServerMixin.java | 30 +++++-- .../ServerCommonNetworkHandlerMixin.java | 30 +++++-- .../modprotocol/ServerMetadataMixin.java | 39 ++++++--- .../lang/en_us.json | 8 ++ 16 files changed, 336 insertions(+), 93 deletions(-) create mode 100644 fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/ModProtocolHolder.java delete mode 100644 fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/ServerMetadataExtension.java create mode 100644 fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/TextUtil.java create mode 100644 fabric-mod-protocol-api-v1/src/main/resources/assets/fabric-mod-protocol-api-v1/lang/en_us.json diff --git a/fabric-mod-protocol-api-v1/src/client/java/net/fabricmc/fabric/impl/modprotocol/client/ClientModProtocolInit.java b/fabric-mod-protocol-api-v1/src/client/java/net/fabricmc/fabric/impl/modprotocol/client/ClientModProtocolInit.java index ddaae30186..e59f6e8346 100644 --- a/fabric-mod-protocol-api-v1/src/client/java/net/fabricmc/fabric/impl/modprotocol/client/ClientModProtocolInit.java +++ b/fabric-mod-protocol-api-v1/src/client/java/net/fabricmc/fabric/impl/modprotocol/client/ClientModProtocolInit.java @@ -16,22 +16,24 @@ package net.fabricmc.fabric.impl.modprotocol.client; +import java.util.HashMap; + +import net.minecraft.util.Identifier; + import net.fabricmc.fabric.api.client.networking.v1.ClientConfigurationNetworking; import net.fabricmc.fabric.impl.modprotocol.ModProtocol; +import net.fabricmc.fabric.impl.modprotocol.ModProtocolInit; import net.fabricmc.fabric.impl.modprotocol.ModProtocolManager; import net.fabricmc.fabric.impl.modprotocol.RemoteProtocolStorage; import net.fabricmc.fabric.impl.modprotocol.payload.ModProtocolRequestS2CPayload; import net.fabricmc.fabric.impl.modprotocol.payload.ModProtocolResponseC2SPayload; -import net.minecraft.text.Text; - -import java.util.HashMap; - public final class ClientModProtocolInit { + public static void clientInit() { ClientConfigurationNetworking.registerGlobalReceiver(ModProtocolRequestS2CPayload.ID, (payload, context) -> { - var map = new HashMap(payload.modProtocol().size()); + var map = new HashMap(payload.modProtocol().size()); for (var protocol : payload.modProtocol()) { map.put(protocol.id(), protocol); } @@ -41,7 +43,12 @@ public static void clientInit() { context.responseSender().sendPacket(new ModProtocolResponseC2SPayload(validate.supportedProtocols())); return; } - context.responseSender().disconnect(Text.literal("Todo wrong protocol text")); + var b = new StringBuilder(); + b.append("Disconnected due to mismatched protocols!").append('\n'); + b.append("Missing entries:").append('\n'); + ModProtocolManager.appendTextEntries(validate.missing(), ModProtocolManager.LOCAL_MOD_PROTOCOLS_BY_ID, -1, text -> b.append(" - ").append(text.getString())); + context.responseSender().disconnect(ModProtocolManager.constructMessage(validate.missing(), ModProtocolManager.LOCAL_MOD_PROTOCOLS_BY_ID)); + ModProtocolInit.LOGGER.warn(b.toString()); }); } } diff --git a/fabric-mod-protocol-api-v1/src/client/java/net/fabricmc/fabric/mixin/modprotocol/client/ClientCommonNetworkHandlerMixin.java b/fabric-mod-protocol-api-v1/src/client/java/net/fabricmc/fabric/mixin/modprotocol/client/ClientCommonNetworkHandlerMixin.java index 4a3e87054e..33cca449e6 100644 --- a/fabric-mod-protocol-api-v1/src/client/java/net/fabricmc/fabric/mixin/modprotocol/client/ClientCommonNetworkHandlerMixin.java +++ b/fabric-mod-protocol-api-v1/src/client/java/net/fabricmc/fabric/mixin/modprotocol/client/ClientCommonNetworkHandlerMixin.java @@ -1,15 +1,29 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package net.fabricmc.fabric.mixin.modprotocol.client; import it.unimi.dsi.fastutil.objects.Object2IntMap; - -import net.minecraft.client.network.ClientCommonNetworkHandler; - import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; +import net.minecraft.client.network.ClientCommonNetworkHandler; import net.minecraft.network.ClientConnection; -import net.minecraft.server.network.ServerCommonNetworkHandler; +import net.minecraft.util.Identifier; import net.fabricmc.fabric.impl.modprotocol.RemoteProtocolStorage; @@ -20,12 +34,12 @@ public class ClientCommonNetworkHandlerMixin implements RemoteProtocolStorage { protected ClientConnection connection; @Override - public Object2IntMap fabric$getRemoteProtocol() { + public Object2IntMap fabric$getRemoteProtocol() { return ((RemoteProtocolStorage) this.connection).fabric$getRemoteProtocol(); } @Override - public void fabric$setRemoteProtocol(Object2IntMap protocol) { + public void fabric$setRemoteProtocol(Object2IntMap protocol) { ((RemoteProtocolStorage) this.connection).fabric$setRemoteProtocol(protocol); } } diff --git a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/ModProtocol.java b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/ModProtocol.java index 561de5669c..01594667ab 100644 --- a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/ModProtocol.java +++ b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/ModProtocol.java @@ -25,11 +25,12 @@ import net.minecraft.network.PacketByteBuf; import net.minecraft.network.codec.PacketCodec; +import net.minecraft.util.Identifier; -public record ModProtocol(String id, String displayName, String displayVersion, IntList protocols, boolean requiredClient, boolean requiredServer) { +public record ModProtocol(Identifier id, String displayName, String displayVersion, IntList protocols, boolean requiredClient, boolean requiredServer) { public static final int UNSUPPORTED = -1; public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( - Codec.STRING.fieldOf("id").forGetter(ModProtocol::id), + Identifier.CODEC.fieldOf("id").forGetter(ModProtocol::id), Codec.STRING.fieldOf("name").forGetter(ModProtocol::displayName), Codec.STRING.fieldOf("version").forGetter(ModProtocol::displayVersion), Codec.INT_STREAM.xmap(x -> IntList.of(x.toArray()), x -> IntStream.of(x.toIntArray())).fieldOf("protocol").forGetter(ModProtocol::protocols), @@ -52,7 +53,7 @@ public int getHighestVersion(IntList list) { public static final PacketCodec PACKET_CODEC = PacketCodec.ofStatic(ModProtocol::encode, ModProtocol::decode); private static ModProtocol decode(PacketByteBuf buf) { - var id = buf.readString(); + var id = buf.readIdentifier(); var name = buf.readString(); var version = buf.readString(); var protocols = IntList.of(buf.readIntArray()); @@ -63,10 +64,14 @@ private static ModProtocol decode(PacketByteBuf buf) { } private static void encode(PacketByteBuf buf, ModProtocol protocol) { - buf.writeString(protocol.id); + buf.writeIdentifier(protocol.id); buf.writeString(protocol.displayName); buf.writeString(protocol.displayVersion); buf.writeIntArray(protocol.protocols.toIntArray()); buf.writeByte((protocol.requiredClient ? 0b10 : 0) | (protocol.requiredServer ? 0b01 : 0)); } + + public boolean syncWithServerMetadata() { + return this.requiredClient() || this.requiredServer(); + } } diff --git a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/ModProtocolHolder.java b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/ModProtocolHolder.java new file mode 100644 index 0000000000..d855cee3bb --- /dev/null +++ b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/ModProtocolHolder.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.impl.modprotocol; + +import java.util.List; + +import org.jetbrains.annotations.Nullable; + +import net.minecraft.server.ServerMetadata; + +public interface ModProtocolHolder { + static ModProtocolHolder of(ServerMetadata input) { + return (ModProtocolHolder) (Object) input; + } + + @Nullable + List fabric$getModProtocol(); + void fabric$setModProtocol(List protocol); + +} diff --git a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/ModProtocolInit.java b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/ModProtocolInit.java index e27c8a867e..5ff1ea4e1e 100644 --- a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/ModProtocolInit.java +++ b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/ModProtocolInit.java @@ -40,7 +40,6 @@ public static void init() { ModProtocolManager.collectModProtocols(); PayloadTypeRegistry.configurationC2S().register(ModProtocolResponseC2SPayload.ID, ModProtocolResponseC2SPayload.PACKET_CODEC); PayloadTypeRegistry.configurationS2C().register(ModProtocolRequestS2CPayload.ID, ModProtocolRequestS2CPayload.PACKET_CODEC); - ServerConfigurationNetworking.registerGlobalReceiver(ModProtocolResponseC2SPayload.ID, (payload, context) -> { // Todo: store result on the connection for further usage/api ((RemoteProtocolStorage) context.networkHandler()).fabric$setRemoteProtocol(payload.supported()); diff --git a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/ModProtocolLocator.java b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/ModProtocolLocator.java index e1e8eddd5d..b3267429f0 100644 --- a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/ModProtocolLocator.java +++ b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/ModProtocolLocator.java @@ -21,6 +21,8 @@ import it.unimi.dsi.fastutil.ints.IntArrayList; import it.unimi.dsi.fastutil.ints.IntList; +import net.minecraft.util.Identifier; + import net.fabricmc.loader.api.FabricLoader; import net.fabricmc.loader.api.ModContainer; import net.fabricmc.loader.api.metadata.CustomValue; @@ -44,7 +46,7 @@ private static void create(ModContainer container, BiConsumer LOCAL_MOD_PROTOCOLS_BY_ID = new HashMap<>(); + public static final List NAMESPACE_PRIORITY = new ArrayList<>(List.of("special", "mod", "feature")); + public static final Comparator MOD_PROTOCOL_COMPARATOR = Comparator.comparingInt(x -> { + var out = NAMESPACE_PRIORITY.indexOf(x.id().getNamespace()); + return out == -1 ? NAMESPACE_PRIORITY.size() : out; + }).thenComparing(ModProtocol::id); + + public static final Map LOCAL_MOD_PROTOCOLS_BY_ID = new HashMap<>(); public static final List LOCAL_MOD_PROTOCOLS = new ArrayList<>(); + public static final List PING_SYNCED_PROTOCOLS = new ArrayList<>(); public static final List CLIENT_REQUIRED = new ArrayList<>(); public static final List SERVER_REQUIRED = new ArrayList<>(); @@ -47,26 +57,66 @@ public static void setupClient(ServerConfigurationNetworkHandler handler, Minecr if (CLIENT_REQUIRED.isEmpty()) { return; } else { - handler.disconnect(Text.literal("Server requires mods // todo better message")); + handler.disconnect(constructMessage(CLIENT_REQUIRED, Map.of())); } } handler.addTask(new SyncConfigurationTask()); } - public static ValidationResult validateClient(Map received) { + public static Text constructMessage(List missingProtocols, Map localProtocols) { + var text = Text.empty(); + text.append(TextUtil.translatable("text.fabric.mod_protocol.mismatched.title").formatted(Formatting.GOLD)).append("\n"); + text.append(TextUtil.translatable("text.fabric.mod_protocol.mismatched.desc").formatted(Formatting.YELLOW)).append("\n\n"); + text.append(TextUtil.translatable("text.fabric.mod_protocol.mismatched.entries.title").formatted(Formatting.RED)).append("\n"); + appendTextEntries(missingProtocols, localProtocols, 6, text::append); + return text; + } + + public static void appendTextEntries(List missingProtocols, Map localProtocols, int limit, Consumer consumer) { + missingProtocols.sort(MOD_PROTOCOL_COMPARATOR); + if (limit == -1) { + limit = missingProtocols.size(); + } + var size = Math.min(limit, missingProtocols.size()); + for (int i = 0; i < size; i++) { + var protocol = missingProtocols.get(i); + var local = localProtocols.get(protocol.id()); + var localVersion = local == null ? TextUtil.translatable("text.fabric.mod_protocol.missing").formatted(Formatting.DARK_RED) + : Text.literal(local.displayVersion()).formatted(Formatting.YELLOW); + var remoteVersion = local == protocol ? TextUtil.translatable("text.fabric.mod_protocol.missing").formatted(Formatting.DARK_RED) + : Text.literal(protocol.displayVersion()).formatted(Formatting.YELLOW); + + var text = TextUtil.translatable("text.fabric.mod_protocol.entry", + Text.literal(protocol.displayName()).formatted(Formatting.WHITE), localVersion, remoteVersion).formatted(Formatting.GRAY); + if (i + 1 < size) { + text.append("\n"); + } + consumer.accept(text); + } + if (limit < missingProtocols.size()) { + consumer.accept(Text.literal("\n").append(TextUtil.translatable("text.fabric.mod_protocol.and_x_more", missingProtocols.size() - size).formatted(Formatting.GRAY, Formatting.ITALIC))); + } + } + + public static ValidationResult validateClient(Map received) { return validate(received, LOCAL_MOD_PROTOCOLS_BY_ID, SERVER_REQUIRED); } - public static ValidationResult validate(Map received, Map localById, List requiredRemote) { - var supported = new Object2IntOpenHashMap(); + public static ValidationResult validate(Map received, Map localById, List requiredRemote) { + var supported = new Object2IntOpenHashMap(); var missingLocal = new ArrayList(); var missingRemote = new ArrayList(); for (var modProtocol : received.values()) { var local = localById.get(modProtocol.id()); if (local != null) { - supported.put(modProtocol.id(), local.getHighestVersion(modProtocol.protocols())); + var version = local.getHighestVersion(modProtocol.protocols()); + if (version != -1) { + supported.put(modProtocol.id(), version); + } else if (modProtocol.requiredClient()) { + missingLocal.add(modProtocol); + } } else if (modProtocol.requiredClient()) { missingLocal.add(modProtocol); } @@ -74,7 +124,7 @@ public static ValidationResult validate(Map received, Map received, Map")); return; } LOCAL_MOD_PROTOCOLS_BY_ID.put(protocol.id(), protocol); @@ -102,6 +151,9 @@ private static void add(ModContainer container, ModProtocol protocol) { if (protocol.requiredServer()) { SERVER_REQUIRED.add(protocol); } + if (protocol.syncWithServerMetadata()) { + PING_SYNCED_PROTOCOLS.add(protocol); + } } public static class SyncConfigurationTask implements ServerPlayerConfigurationTask { @@ -117,9 +169,16 @@ public Key getKey() { } } - public record ValidationResult(Object2IntMap supportedProtocols, List missingLocal, List missingRemote) { + public record ValidationResult(Object2IntMap supportedProtocols, List missingLocal, List missingRemote) { public boolean isSuccess() { return missingLocal.isEmpty() && missingRemote.isEmpty(); } + + public List missing() { + var arr = new ArrayList(); + arr.addAll(missingLocal); + arr.addAll(missingRemote); + return arr; + } } } diff --git a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/RemoteProtocolStorage.java b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/RemoteProtocolStorage.java index 716b54b34c..fd70bb1716 100644 --- a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/RemoteProtocolStorage.java +++ b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/RemoteProtocolStorage.java @@ -1,8 +1,28 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package net.fabricmc.fabric.impl.modprotocol; import it.unimi.dsi.fastutil.objects.Object2IntMap; +import org.jetbrains.annotations.Nullable; + +import net.minecraft.util.Identifier; public interface RemoteProtocolStorage { - Object2IntMap fabric$getRemoteProtocol(); - void fabric$setRemoteProtocol(Object2IntMap protocol); + @Nullable + Object2IntMap fabric$getRemoteProtocol(); + void fabric$setRemoteProtocol(Object2IntMap protocol); } diff --git a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/ServerMetadataExtension.java b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/ServerMetadataExtension.java deleted file mode 100644 index 678210e84a..0000000000 --- a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/ServerMetadataExtension.java +++ /dev/null @@ -1,18 +0,0 @@ -package net.fabricmc.fabric.impl.modprotocol; - -import net.minecraft.server.ServerMetadata; - -import org.jetbrains.annotations.Nullable; - -import java.util.List; - -public interface ServerMetadataExtension { - static ServerMetadataExtension of(ServerMetadata input) { - return (ServerMetadataExtension) (Object) input; - } - - @Nullable - List fabric$getModProtocol(); - void fabric$setModProtocol(List protocol); - -} diff --git a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/TextUtil.java b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/TextUtil.java new file mode 100644 index 0000000000..6a9bdc3ce7 --- /dev/null +++ b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/TextUtil.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.impl.modprotocol; + +import java.nio.file.Files; +import java.util.HashMap; +import java.util.Map; + +import com.google.gson.JsonParser; + +import net.minecraft.text.MutableText; +import net.minecraft.text.Text; + +import net.fabricmc.loader.api.FabricLoader; + +public class TextUtil { + private static final Map FALLBACK_TRANSLATIONS = new HashMap<>(); + + public static MutableText translatable(String key, Object... args) { + return Text.translatableWithFallback(key, FALLBACK_TRANSLATIONS.get(key), args); + } + + public static MutableText translatable(String key) { + return Text.translatableWithFallback(key, FALLBACK_TRANSLATIONS.get(key)); + } + + static { + try { + var container = FabricLoader.getInstance().getModContainer(ModProtocolInit.MOD_ID); + var path = container.get().findPath("assets/fabric-mod-protocol-api-v1/lang/en_us.json"); + var lang = JsonParser.parseString(Files.readString(path.get())).getAsJsonObject(); + + for (var key : lang.keySet()) { + FALLBACK_TRANSLATIONS.put(key, lang.get(key).getAsString()); + } + } catch (Throwable e) { + ModProtocolInit.LOGGER.error("Failed to load translation file!", e); + } + } +} diff --git a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/payload/ModProtocolResponseC2SPayload.java b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/payload/ModProtocolResponseC2SPayload.java index af8fea211c..d832cc4a0b 100644 --- a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/payload/ModProtocolResponseC2SPayload.java +++ b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/payload/ModProtocolResponseC2SPayload.java @@ -27,15 +27,15 @@ import net.minecraft.network.packet.CustomPayload; import net.minecraft.util.Identifier; -import java.util.Map; -public record ModProtocolResponseC2SPayload(Object2IntMap supported) implements CustomPayload { +public record ModProtocolResponseC2SPayload(Object2IntMap supported) implements CustomPayload { public static final Id ID = new Id<>(Identifier.of("fabric", "mod_protocol/response")); - public static final PacketCodec PACKET_CODEC = PacketCodecs.map(ModProtocolResponseC2SPayload::createMap, PacketCodecs.STRING, PacketCodecs.INTEGER) + public static final PacketCodec PACKET_CODEC = + PacketCodecs.map(ModProtocolResponseC2SPayload::createMap, Identifier.PACKET_CODEC, PacketCodecs.INTEGER) .xmap(ModProtocolResponseC2SPayload::new, ModProtocolResponseC2SPayload::supported).cast(); - private static Object2IntMap createMap(int i) { + private static Object2IntMap createMap(int i) { return new Object2IntOpenHashMap<>(i); } diff --git a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/mixin/modprotocol/ClientConnectionMixin.java b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/mixin/modprotocol/ClientConnectionMixin.java index 02a096f746..822ebb9dfd 100644 --- a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/mixin/modprotocol/ClientConnectionMixin.java +++ b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/mixin/modprotocol/ClientConnectionMixin.java @@ -1,28 +1,44 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package net.fabricmc.fabric.mixin.modprotocol; import it.unimi.dsi.fastutil.objects.Object2IntMap; - -import it.unimi.dsi.fastutil.objects.Object2IntMaps; - -import net.fabricmc.fabric.impl.modprotocol.RemoteProtocolStorage; +import org.jetbrains.annotations.Nullable; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; import net.minecraft.network.ClientConnection; +import net.minecraft.util.Identifier; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Unique; +import net.fabricmc.fabric.impl.modprotocol.RemoteProtocolStorage; @Mixin(ClientConnection.class) public class ClientConnectionMixin implements RemoteProtocolStorage { @Unique - private Object2IntMap remoteProtocol = Object2IntMaps.emptyMap(); + @Nullable + private Object2IntMap remoteProtocol = null; @Override - public Object2IntMap fabric$getRemoteProtocol() { + public Object2IntMap fabric$getRemoteProtocol() { return this.remoteProtocol; } @Override - public void fabric$setRemoteProtocol(Object2IntMap protocol) { + public void fabric$setRemoteProtocol(Object2IntMap protocol) { this.remoteProtocol = protocol; } } diff --git a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/mixin/modprotocol/MinecraftServerMixin.java b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/mixin/modprotocol/MinecraftServerMixin.java index 7d7f34814e..03966bb365 100644 --- a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/mixin/modprotocol/MinecraftServerMixin.java +++ b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/mixin/modprotocol/MinecraftServerMixin.java @@ -1,23 +1,37 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package net.fabricmc.fabric.mixin.modprotocol; import com.llamalad7.mixinextras.injector.ModifyReturnValue; - -import net.fabricmc.fabric.impl.modprotocol.ModProtocolManager; -import net.fabricmc.fabric.impl.modprotocol.ServerMetadataExtension; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; import net.minecraft.server.MinecraftServer; - import net.minecraft.server.ServerMetadata; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; +import net.fabricmc.fabric.impl.modprotocol.ModProtocolHolder; +import net.fabricmc.fabric.impl.modprotocol.ModProtocolManager; @Mixin(MinecraftServer.class) public class MinecraftServerMixin { @ModifyReturnValue(method = "createMetadata", at = @At("RETURN")) private ServerMetadata addModProtocol(ServerMetadata original) { - if (!ModProtocolManager.CLIENT_REQUIRED.isEmpty()) { - ServerMetadataExtension.of(original).fabric$setModProtocol(ModProtocolManager.CLIENT_REQUIRED); + if (!ModProtocolManager.PING_SYNCED_PROTOCOLS.isEmpty()) { + ModProtocolHolder.of(original).fabric$setModProtocol(ModProtocolManager.PING_SYNCED_PROTOCOLS); } return original; } diff --git a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/mixin/modprotocol/ServerCommonNetworkHandlerMixin.java b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/mixin/modprotocol/ServerCommonNetworkHandlerMixin.java index cad91b377a..9b07f101c3 100644 --- a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/mixin/modprotocol/ServerCommonNetworkHandlerMixin.java +++ b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/mixin/modprotocol/ServerCommonNetworkHandlerMixin.java @@ -1,15 +1,31 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package net.fabricmc.fabric.mixin.modprotocol; import it.unimi.dsi.fastutil.objects.Object2IntMap; - -import net.fabricmc.fabric.impl.modprotocol.RemoteProtocolStorage; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; import net.minecraft.network.ClientConnection; import net.minecraft.server.network.ServerCommonNetworkHandler; +import net.minecraft.util.Identifier; -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; +import net.fabricmc.fabric.impl.modprotocol.RemoteProtocolStorage; @Mixin(ServerCommonNetworkHandler.class) public class ServerCommonNetworkHandlerMixin implements RemoteProtocolStorage { @@ -18,12 +34,12 @@ public class ServerCommonNetworkHandlerMixin implements RemoteProtocolStorage { protected ClientConnection connection; @Override - public Object2IntMap fabric$getRemoteProtocol() { + public Object2IntMap fabric$getRemoteProtocol() { return ((RemoteProtocolStorage) this.connection).fabric$getRemoteProtocol(); } @Override - public void fabric$setRemoteProtocol(Object2IntMap protocol) { + public void fabric$setRemoteProtocol(Object2IntMap protocol) { ((RemoteProtocolStorage) this.connection).fabric$setRemoteProtocol(protocol); } } diff --git a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/mixin/modprotocol/ServerMetadataMixin.java b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/mixin/modprotocol/ServerMetadataMixin.java index 7f4165ac24..b37b9be6a6 100644 --- a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/mixin/modprotocol/ServerMetadataMixin.java +++ b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/mixin/modprotocol/ServerMetadataMixin.java @@ -1,27 +1,40 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package net.fabricmc.fabric.mixin.modprotocol; -import com.llamalad7.mixinextras.injector.ModifyExpressionValue; +import java.util.List; +import com.llamalad7.mixinextras.injector.ModifyExpressionValue; import com.mojang.datafixers.util.Pair; import com.mojang.serialization.Codec; - import com.mojang.serialization.DataResult; import com.mojang.serialization.DynamicOps; - -import net.fabricmc.fabric.impl.modprotocol.ModProtocol; -import net.fabricmc.fabric.impl.modprotocol.ServerMetadataExtension; - -import net.minecraft.server.ServerMetadata; - import org.jetbrains.annotations.Nullable; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; -import java.util.List; +import net.minecraft.server.ServerMetadata; + +import net.fabricmc.fabric.impl.modprotocol.ModProtocol; +import net.fabricmc.fabric.impl.modprotocol.ModProtocolHolder; @Mixin(ServerMetadata.class) -public class ServerMetadataMixin implements ServerMetadataExtension { +public class ServerMetadataMixin implements ModProtocolHolder { @Unique @Nullable private List modProtocol; @@ -47,7 +60,7 @@ public DataResult> decode(DynamicOps ops, T input if (protocol.isSuccess()) { var result = ModProtocol.LIST_CODEC.decode(ops, protocol.getOrThrow()); if (result.isSuccess()) { - ServerMetadataExtension.of(decoded.getOrThrow().getFirst()).fabric$setModProtocol(result.getOrThrow().getFirst()); + ModProtocolHolder.of(decoded.getOrThrow().getFirst()).fabric$setModProtocol(result.getOrThrow().getFirst()); } } } @@ -57,8 +70,8 @@ public DataResult> decode(DynamicOps ops, T input @Override public DataResult encode(ServerMetadata input, DynamicOps ops, T prefix) { var encode = original.encode(input, ops, prefix); - if (encode.isSuccess() && ServerMetadataExtension.of(input).fabric$getModProtocol() != null) { - var protocol = ModProtocol.LIST_CODEC.encodeStart(ops, ServerMetadataExtension.of(input).fabric$getModProtocol()); + if (encode.isSuccess() && ModProtocolHolder.of(input).fabric$getModProtocol() != null) { + var protocol = ModProtocol.LIST_CODEC.encodeStart(ops, ModProtocolHolder.of(input).fabric$getModProtocol()); if (protocol.isSuccess()) { encode = ops.mergeToMap(encode.getOrThrow(), ops.createString("fabric:mod_protocol"), protocol.getOrThrow()); } diff --git a/fabric-mod-protocol-api-v1/src/main/resources/assets/fabric-mod-protocol-api-v1/lang/en_us.json b/fabric-mod-protocol-api-v1/src/main/resources/assets/fabric-mod-protocol-api-v1/lang/en_us.json new file mode 100644 index 0000000000..02b67a2a94 --- /dev/null +++ b/fabric-mod-protocol-api-v1/src/main/resources/assets/fabric-mod-protocol-api-v1/lang/en_us.json @@ -0,0 +1,8 @@ +{ + "text.fabric.mod_protocol.mismatched.title": "Required protocols are mismatched!", + "text.fabric.mod_protocol.mismatched.desc": "This usually means mods on your client don't match with the server!", + "text.fabric.mod_protocol.mismatched.entries.title": "== Mismatched entries ==", + "text.fabric.mod_protocol.and_x_more": "...and %s more...", + "text.fabric.mod_protocol.missing": "Missing!", + "text.fabric.mod_protocol.entry": "%s (Local: %s, Remote: %s)" +} From dbcdcaad286e68f2b8bdc32c9bebe3729d9f9616 Mon Sep 17 00:00:00 2001 From: Patbox <39821509+Patbox@users.noreply.github.com> Date: Wed, 7 Aug 2024 20:46:53 +0200 Subject: [PATCH 03/11] Implement apis and document them --- .../v1/ClientModProtocolLookup.java | 103 ++++++++++++++ .../client/modprotocol/v1/package-info.java | 5 +- .../client/ClientModProtocolInit.java | 4 +- .../api/modprotocol/v1/ModProtocol.java | 53 +++++++ .../api/modprotocol/v1/ModProtocolIds.java | 40 ++++++ .../modprotocol/v1/ModProtocolRegistry.java | 80 +++++++++++ .../v1/ServerModProtocolLookup.java | 131 ++++++++++++++++++ .../api/modprotocol/v1/package-info.java | 75 ++++++++++ .../impl/modprotocol/ModProtocolHolder.java | 4 +- ...{ModProtocol.java => ModProtocolImpl.java} | 40 +++--- .../impl/modprotocol/ModProtocolInit.java | 6 +- .../impl/modprotocol/ModProtocolLocator.java | 20 +-- .../impl/modprotocol/ModProtocolManager.java | 84 +++++++---- .../modprotocol/RemoteProtocolStorage.java | 25 ++++ .../payload/ModProtocolRequestS2CPayload.java | 6 +- .../mixin/modprotocol/RegistriesMixin.java | 35 +++++ .../modprotocol/ServerMetadataMixin.java | 12 +- .../fabric-mod-protocol-api-v1.mixins.json | 1 + .../unit/VersionMatchingTests.java | 50 ------- .../test/modprotocol/ModProtocolTestmods.java | 31 ++++- .../src/testmod/resources/fabric.mod.json | 15 +- .../registry/sync/FabricRegistryInit.java | 9 +- 22 files changed, 700 insertions(+), 129 deletions(-) create mode 100644 fabric-mod-protocol-api-v1/src/client/java/net/fabricmc/fabric/api/client/modprotocol/v1/ClientModProtocolLookup.java create mode 100644 fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/api/modprotocol/v1/ModProtocol.java create mode 100644 fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/api/modprotocol/v1/ModProtocolIds.java create mode 100644 fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/api/modprotocol/v1/ModProtocolRegistry.java create mode 100644 fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/api/modprotocol/v1/ServerModProtocolLookup.java create mode 100644 fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/api/modprotocol/v1/package-info.java rename fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/{ModProtocol.java => ModProtocolImpl.java} (52%) create mode 100644 fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/mixin/modprotocol/RegistriesMixin.java diff --git a/fabric-mod-protocol-api-v1/src/client/java/net/fabricmc/fabric/api/client/modprotocol/v1/ClientModProtocolLookup.java b/fabric-mod-protocol-api-v1/src/client/java/net/fabricmc/fabric/api/client/modprotocol/v1/ClientModProtocolLookup.java new file mode 100644 index 0000000000..7335ddf397 --- /dev/null +++ b/fabric-mod-protocol-api-v1/src/client/java/net/fabricmc/fabric/api/client/modprotocol/v1/ClientModProtocolLookup.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.api.client.modprotocol.v1; + +import it.unimi.dsi.fastutil.objects.Object2IntMap; + +import net.minecraft.client.network.ClientCommonNetworkHandler; +import net.minecraft.network.ClientConnection; +import net.minecraft.server.network.ServerCommonNetworkHandler; +import net.minecraft.util.Identifier; + +import net.fabricmc.fabric.api.modprotocol.v1.ModProtocol; +import net.fabricmc.fabric.api.modprotocol.v1.ModProtocolIds; +import net.fabricmc.fabric.impl.modprotocol.RemoteProtocolStorage; + +/** + * Utility methods allowing to get protocol versions supported by the server. + * + *

Protocol identifier's can be any valid identifier, through by default mods defining it will use "mod" namespace and path equal to its id. + * See {@link ModProtocolIds} for more information. + */ +public final class ClientModProtocolLookup { + public static final int UNSUPPORTED = -1; + private ClientModProtocolLookup() {} + + /** + * Gets protocol version supported by the server + * + * @param handler the network handler connected to the server + * @param protocolId protocol's id + * @return Protocol version supported by the server + */ + public static int getSupportedProtocol(ClientCommonNetworkHandler handler, Identifier protocolId) { + return RemoteProtocolStorage.getProtocol(handler, protocolId); + } + + /** + * Gets protocol version supported by the server + * + * @param connection the ClientConnection connected to the server + * @param protocolId protocol's id + * @return Protocol version supported by the server + */ + public static int getSupportedProtocol(ClientConnection connection, Identifier protocolId) { + return RemoteProtocolStorage.getProtocol(connection, protocolId); + } + + /** + * Gets protocol version supported by the server + * + * @param handler the network handler connected to the server + * @param protocol protocol to check against + * @return Protocol version supported by the server + */ + public static int getSupportedProtocol(ClientCommonNetworkHandler handler, ModProtocol protocol) { + return RemoteProtocolStorage.getProtocol(handler, protocol.id()); + } + + /** + * Gets protocol version supported by the server + * + * @param connection the ClientConnection connected to the server + * @param protocol protocol to check against + * @return Protocol version supported by the server + */ + public static int getSupportedProtocol(ClientConnection connection, ModProtocol protocol) { + return RemoteProtocolStorage.getProtocol(connection, protocol.id()); + } + + /** + * Gets all protocols supported by the server + * + * @param handler the network handler connected to the server + * @return Map of protocols supported by the server + */ + public static Object2IntMap getAllSupportedProtocols(ServerCommonNetworkHandler handler) { + return RemoteProtocolStorage.getMap(handler); + } + + /** + * Gets all protocols supported by the server + * + * @param connection the ClientConnection connected to the server + * @return Map of protocols supported by the server + */ + public static Object2IntMap getAllSupportedProtocols(ClientConnection connection) { + return RemoteProtocolStorage.getMap(connection); + } +} diff --git a/fabric-mod-protocol-api-v1/src/client/java/net/fabricmc/fabric/api/client/modprotocol/v1/package-info.java b/fabric-mod-protocol-api-v1/src/client/java/net/fabricmc/fabric/api/client/modprotocol/v1/package-info.java index 6189214552..4cc2d51d00 100644 --- a/fabric-mod-protocol-api-v1/src/client/java/net/fabricmc/fabric/api/client/modprotocol/v1/package-info.java +++ b/fabric-mod-protocol-api-v1/src/client/java/net/fabricmc/fabric/api/client/modprotocol/v1/package-info.java @@ -17,7 +17,10 @@ /** * The Mod Protocol API (client side), version 1. * - * Todo + * See {@link net.fabricmc.fabric.api.modprotocol.v1} */ +@ApiStatus.Experimental package net.fabricmc.fabric.api.client.modprotocol.v1; + +import org.jetbrains.annotations.ApiStatus; diff --git a/fabric-mod-protocol-api-v1/src/client/java/net/fabricmc/fabric/impl/modprotocol/client/ClientModProtocolInit.java b/fabric-mod-protocol-api-v1/src/client/java/net/fabricmc/fabric/impl/modprotocol/client/ClientModProtocolInit.java index e59f6e8346..67523602ff 100644 --- a/fabric-mod-protocol-api-v1/src/client/java/net/fabricmc/fabric/impl/modprotocol/client/ClientModProtocolInit.java +++ b/fabric-mod-protocol-api-v1/src/client/java/net/fabricmc/fabric/impl/modprotocol/client/ClientModProtocolInit.java @@ -21,7 +21,7 @@ import net.minecraft.util.Identifier; import net.fabricmc.fabric.api.client.networking.v1.ClientConfigurationNetworking; -import net.fabricmc.fabric.impl.modprotocol.ModProtocol; +import net.fabricmc.fabric.impl.modprotocol.ModProtocolImpl; import net.fabricmc.fabric.impl.modprotocol.ModProtocolInit; import net.fabricmc.fabric.impl.modprotocol.ModProtocolManager; import net.fabricmc.fabric.impl.modprotocol.RemoteProtocolStorage; @@ -33,7 +33,7 @@ public final class ClientModProtocolInit { public static void clientInit() { ClientConfigurationNetworking.registerGlobalReceiver(ModProtocolRequestS2CPayload.ID, (payload, context) -> { - var map = new HashMap(payload.modProtocol().size()); + var map = new HashMap(payload.modProtocol().size()); for (var protocol : payload.modProtocol()) { map.put(protocol.id(), protocol); } diff --git a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/api/modprotocol/v1/ModProtocol.java b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/api/modprotocol/v1/ModProtocol.java new file mode 100644 index 0000000000..8f2bf4ab20 --- /dev/null +++ b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/api/modprotocol/v1/ModProtocol.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.api.modprotocol.v1; + +import it.unimi.dsi.fastutil.ints.IntList; +import org.jetbrains.annotations.ApiStatus; + +import net.minecraft.util.Identifier; + +/** + * Interface representing registered ModProtocol. Can be used for further lookups. + */ +@ApiStatus.NonExtendable +public interface ModProtocol { + /** + * @return Identifier associated with this Mod Protocol + */ + Identifier id(); + /** + * @return Display name of this protocol + */ + String name(); + /** + * @return Display version of this protocol + */ + String version(); + /** + * @return Protocol versions supported by this protocol + */ + IntList protocol(); + /** + * @return Client requirement of this protocol + */ + boolean requireClient(); + /** + * @return Server requirement of this protocol + */ + boolean requireServer(); +} diff --git a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/api/modprotocol/v1/ModProtocolIds.java b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/api/modprotocol/v1/ModProtocolIds.java new file mode 100644 index 0000000000..75d91a36f4 --- /dev/null +++ b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/api/modprotocol/v1/ModProtocolIds.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.api.modprotocol.v1; + +import net.minecraft.util.Identifier; + +/** + * Utility methods allowing to create Identifiers targeting default protocols. + */ +public final class ModProtocolIds { + public static final String MOD = "mod"; + public static final String SPECIAL = "special"; + public static final String FEATURE = "feature"; + private ModProtocolIds() {} + public static Identifier mod(String modId) { + return Identifier.of(MOD, modId); + } + + public static Identifier special(String path) { + return Identifier.of(SPECIAL, path); + } + + public static Identifier feature(String path) { + return Identifier.of(FEATURE, path); + } +} diff --git a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/api/modprotocol/v1/ModProtocolRegistry.java b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/api/modprotocol/v1/ModProtocolRegistry.java new file mode 100644 index 0000000000..b8f0274fcb --- /dev/null +++ b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/api/modprotocol/v1/ModProtocolRegistry.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.api.modprotocol.v1; + +import java.util.Collection; +import java.util.Collections; + +import it.unimi.dsi.fastutil.ints.IntList; +import org.jetbrains.annotations.Nullable; + +import net.minecraft.util.Identifier; + +import net.fabricmc.fabric.impl.modprotocol.ModProtocolImpl; +import net.fabricmc.fabric.impl.modprotocol.ModProtocolManager; + +/** + * Utility methods allowing to lookup or register new protocols. + * + *

While lookup can be done anytime, registration is only possible before registries are frozen. + */ +public final class ModProtocolRegistry { + private ModProtocolRegistry() {} + + /** + * Allows to get a locally registered protocol + * @param identifier protocol's id + * @return requested ModProtocol or null if not found + */ + @Nullable + public static ModProtocol get(Identifier identifier) { + return ModProtocolManager.LOCAL_MOD_PROTOCOLS_BY_ID.get(identifier); + } + + /** + * @return All registered protocols + */ + public static Collection getAll() { + return Collections.unmodifiableCollection(ModProtocolManager.LOCAL_MOD_PROTOCOLS); + } + + /** + * Registers new mod protocol with its own unique settings. + * + * @param identifier the identifier of protocol + * @param name display name in protocol, shown if it's missing + * @param version display version of the protocol, shown if it's missing + * @param protocol list of protocol versions + * @param requireClient marks protocol as required on client + * @param requireServer marks protocol as required on server + * @return registered Mod Protocol + */ + public static ModProtocol register(Identifier identifier, String name, String version, IntList protocol, boolean requireClient, boolean requireServer) { + return ModProtocolManager.add(null, new ModProtocolImpl(identifier, name, version, IntList.of(protocol.toIntArray()), requireClient, requireServer)); + } + + + /** + * Allows to customise priority of namespaces when displaying missing protocols. + * @param firstNamespace namespace that should display first + * @param secondNamespace namespace that should display second + * @return true if change occurred, false if it didn't + */ + public static boolean addDisplayOrdering(String firstNamespace, String secondNamespace) { + return ModProtocolManager.registerOrder(firstNamespace, secondNamespace); + } +} diff --git a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/api/modprotocol/v1/ServerModProtocolLookup.java b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/api/modprotocol/v1/ServerModProtocolLookup.java new file mode 100644 index 0000000000..7e26544e79 --- /dev/null +++ b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/api/modprotocol/v1/ServerModProtocolLookup.java @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.api.modprotocol.v1; + + +import it.unimi.dsi.fastutil.objects.Object2IntMap; + +import net.minecraft.network.ClientConnection; +import net.minecraft.server.network.ServerCommonNetworkHandler; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.util.Identifier; + +import net.fabricmc.fabric.impl.modprotocol.RemoteProtocolStorage; + +/** + * Utility methods allowing to get protocol versions supported by the player. + * + *

Protocol identifier's can be any valid identifier, through by default mods defining it will use "mod" namespace and path equal to its id. + * See {@link ModProtocolIds} for more information. + */ +public final class ServerModProtocolLookup { + public static final int UNSUPPORTED = -1; + private ServerModProtocolLookup() {} + + /** + * Gets protocol version supported by the player + * + * @param player the player + * @param protocolId protocol's id + * @return Protocol version supported by the player + */ + public static int getSupportedProtocol(ServerPlayerEntity player, Identifier protocolId) { + return RemoteProtocolStorage.getProtocol(player.networkHandler, protocolId); + } + /** + * Gets protocol version supported by the player + * + * @param handler the network handler owned by the player you want to check protocol for + * @param protocolId protocol's id + * @return Protocol version supported by the player + */ + public static int getSupportedProtocol(ServerCommonNetworkHandler handler, Identifier protocolId) { + return RemoteProtocolStorage.getProtocol(handler, protocolId); + } + + /** + * Gets protocol version supported by the server + * + * @param connection the ClientConnection connected to the server + * @param protocolId protocol's id + * @return Protocol version supported by the server + */ + public static int getSupportedProtocol(ClientConnection connection, Identifier protocolId) { + return RemoteProtocolStorage.getProtocol(connection, protocolId); + } + + /** + * Gets protocol version supported by the player + * + * @param player the player + * @param protocol protocol to check against + * @return Protocol version supported by the player + */ + public static int getSupportedProtocol(ServerPlayerEntity player, ModProtocol protocol) { + return RemoteProtocolStorage.getProtocol(player.networkHandler, protocol.id()); + } + /** + * Gets protocol version supported by the player + * + * @param handler the network handler owned by the player you want to check protocol for + * @param protocol protocol to check against + * @return Protocol version supported by the player + */ + public static int getSupportedProtocol(ServerCommonNetworkHandler handler, ModProtocol protocol) { + return RemoteProtocolStorage.getProtocol(handler, protocol.id()); + } + + /** + * Gets protocol version supported by the server + * + * @param connection the ClientConnection connected to the server + * @param protocol protocol to check against + * @return Protocol version supported by the server + */ + public static int getSupportedProtocol(ClientConnection connection, ModProtocol protocol) { + return RemoteProtocolStorage.getProtocol(connection, protocol.id()); + } + + /** + * Gets all protocols supported by the player + * + * @param player the player + * @return Map of protocols supported by the player + */ + public static Object2IntMap getAllSupportedProtocols(ServerPlayerEntity player) { + return RemoteProtocolStorage.getMap(player.networkHandler); + } + /** + * Gets all protocols supported by the player + * + * @param handler the network handler owned by the player you want to check protocol for + * @return Map of protocols supported by the player + */ + public static Object2IntMap getAllSupportedProtocols(ServerCommonNetworkHandler handler) { + return RemoteProtocolStorage.getMap(handler); + } + + /** + * Gets all protocols supported by the player + * + * @param connection the ClientConnection connected to the server + * @return Map of protocols supported by the player + */ + public static Object2IntMap getAllSupportedProtocols(ClientConnection connection) { + return RemoteProtocolStorage.getMap(connection); + } +} diff --git a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/api/modprotocol/v1/package-info.java b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/api/modprotocol/v1/package-info.java new file mode 100644 index 0000000000..32f9b74e75 --- /dev/null +++ b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/api/modprotocol/v1/package-info.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * The Mod Protocol API, version 1. + * + *

Mod Protocol is an additional syncing system allowing mods to define their protocol, with simple utilities + * allowing to check supported version and use it for networking or safeguards against using mismatched/incompatible + * mod versions on client and server. Exact configuration can differ from mod to mod.

+ * + *

The mod protocol can be defined in two ways: + *

+ *
fabric.mod.json
+ *
This is the simplest way to define it. Can be useful when you don't need to change it depending on mods configuration + * or external dependencies. It is set within custom field of that file under "fabric:mod_protocol" key. + * + * It can be defined in multiple ways: + *
+ *
"fabric:mod_protocol": 1
+ *

This will automatically use mods id with "mod" namespace as the protocol identifier, as a single supported protocol version, + * with display name and version being copied form mods metadata. It also marks the protocol as required on both client and server. + *

+ *
"fabric:mod_protocol": { + * "protocol": [1, 2], + * "id: "custom:id", + * "name": "Mod Name", + * "version": "v1.2.3", + * "require_client": false, + * "require_server": true + * }
+ *

Full object. Only required value is "protocol", which can be set directly for single version or as an array for multiple.

+ *

"id" is protocols identifiers, which can have any namespace and path, as long as it's valid. + * It's optional and defaults to id with "mod" namespace and path equal to mod's id. + *

+ *

"name" is a name displayed if protocol doesn't match. It's optional and by default it uses one from mod's metadata.

+ *

"version" is a version displayed if protocol doesn't match. It's optional and by default it uses one from mod's metadata.

+ *

"require_client" controls if clients without this protocol can join the server, defaults to true, preventing joining

+ *

"require_server" controls if clients can join servers without this mod, defaults to true, preventing joining

+ *
+ *
"fabric:mod_protocol": [{ + * "protocol": [1, 2], + * "id: "custom:id", + * "name": "Mod Name", + * "version": "v1.2.3", + * "require_client": false, + * "require_server": true + * }]
+ *

Array of full objects. Allows to define multiple versions of the protocol. The inner objects use the same format as single-full object format, + * with main exception being that fields "id", "name" and "version" aren't defaulted and need to be always set

+ *
+ *
+ *
{@link net.fabricmc.fabric.api.modprotocol.v1.ModProtocolRegistry}
+ *
This is the simplest way to define it. Can be useful when you don't need to change it depending on mods configuration + * or external dependencies. It is set within custom field of that file under "fabric:mod_protocol" key. + *
+ *
+ *

+ */ +@ApiStatus.Experimental +package net.fabricmc.fabric.api.modprotocol.v1; + +import org.jetbrains.annotations.ApiStatus; diff --git a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/ModProtocolHolder.java b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/ModProtocolHolder.java index d855cee3bb..5f62b6d92a 100644 --- a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/ModProtocolHolder.java +++ b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/ModProtocolHolder.java @@ -28,7 +28,7 @@ static ModProtocolHolder of(ServerMetadata input) { } @Nullable - List fabric$getModProtocol(); - void fabric$setModProtocol(List protocol); + List fabric$getModProtocol(); + void fabric$setModProtocol(List protocol); } diff --git a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/ModProtocol.java b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/ModProtocolImpl.java similarity index 52% rename from fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/ModProtocol.java rename to fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/ModProtocolImpl.java index 01594667ab..560c2dce9a 100644 --- a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/ModProtocol.java +++ b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/ModProtocolImpl.java @@ -27,22 +27,22 @@ import net.minecraft.network.codec.PacketCodec; import net.minecraft.util.Identifier; -public record ModProtocol(Identifier id, String displayName, String displayVersion, IntList protocols, boolean requiredClient, boolean requiredServer) { +public record ModProtocolImpl(Identifier id, String name, String version, IntList protocol, boolean requireClient, boolean requireServer) implements net.fabricmc.fabric.api.modprotocol.v1.ModProtocol { public static final int UNSUPPORTED = -1; - public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( - Identifier.CODEC.fieldOf("id").forGetter(ModProtocol::id), - Codec.STRING.fieldOf("name").forGetter(ModProtocol::displayName), - Codec.STRING.fieldOf("version").forGetter(ModProtocol::displayVersion), - Codec.INT_STREAM.xmap(x -> IntList.of(x.toArray()), x -> IntStream.of(x.toIntArray())).fieldOf("protocol").forGetter(ModProtocol::protocols), - Codec.BOOL.fieldOf("require_client").forGetter(ModProtocol::requiredClient), - Codec.BOOL.fieldOf("require_server").forGetter(ModProtocol::requiredServer) - ).apply(instance, ModProtocol::new)); - public static final Codec> LIST_CODEC = CODEC.listOf(); + public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( + Identifier.CODEC.fieldOf("id").forGetter(ModProtocolImpl::id), + Codec.STRING.fieldOf("name").forGetter(ModProtocolImpl::name), + Codec.STRING.fieldOf("version").forGetter(ModProtocolImpl::version), + Codec.INT_STREAM.xmap(x -> IntList.of(x.toArray()), x -> IntStream.of(x.toIntArray())).fieldOf("protocol").forGetter(ModProtocolImpl::protocol), + Codec.BOOL.fieldOf("require_client").forGetter(ModProtocolImpl::requireClient), + Codec.BOOL.fieldOf("require_server").forGetter(ModProtocolImpl::requireServer) + ).apply(instance, ModProtocolImpl::new)); + public static final Codec> LIST_CODEC = CODEC.listOf(); public int getHighestVersion(IntList list) { int value = UNSUPPORTED; for (int i = 0; i < list.size(); i++) { var proto = list.getInt(i); - if (this.protocols.contains(proto) && value < proto) { + if (this.protocol.contains(proto) && value < proto) { value = proto; } } @@ -50,9 +50,9 @@ public int getHighestVersion(IntList list) { return value; } - public static final PacketCodec PACKET_CODEC = PacketCodec.ofStatic(ModProtocol::encode, ModProtocol::decode); + public static final PacketCodec PACKET_CODEC = PacketCodec.ofStatic(ModProtocolImpl::encode, ModProtocolImpl::decode); - private static ModProtocol decode(PacketByteBuf buf) { + private static ModProtocolImpl decode(PacketByteBuf buf) { var id = buf.readIdentifier(); var name = buf.readString(); var version = buf.readString(); @@ -60,18 +60,18 @@ private static ModProtocol decode(PacketByteBuf buf) { var b = buf.readByte(); var requireClient = (b & 0b10) != 0; var requireServer = (b & 0b01) != 0; - return new ModProtocol(id, name, version, protocols, requireClient, requireServer); + return new ModProtocolImpl(id, name, version, protocols, requireClient, requireServer); } - private static void encode(PacketByteBuf buf, ModProtocol protocol) { + private static void encode(PacketByteBuf buf, ModProtocolImpl protocol) { buf.writeIdentifier(protocol.id); - buf.writeString(protocol.displayName); - buf.writeString(protocol.displayVersion); - buf.writeIntArray(protocol.protocols.toIntArray()); - buf.writeByte((protocol.requiredClient ? 0b10 : 0) | (protocol.requiredServer ? 0b01 : 0)); + buf.writeString(protocol.name); + buf.writeString(protocol.version); + buf.writeIntArray(protocol.protocol.toIntArray()); + buf.writeByte((protocol.requireClient ? 0b10 : 0) | (protocol.requireServer ? 0b01 : 0)); } public boolean syncWithServerMetadata() { - return this.requiredClient() || this.requiredServer(); + return this.requireClient() || this.requireServer(); } } diff --git a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/ModProtocolInit.java b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/ModProtocolInit.java index 5ff1ea4e1e..74fd5033ed 100644 --- a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/ModProtocolInit.java +++ b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/ModProtocolInit.java @@ -31,17 +31,19 @@ public final class ModProtocolInit { public static final String MOD_ID = "fabric-mod-protocol-api-v1"; public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID); + public static boolean frozen = false; public static void init() { var phase = Identifier.of("fabric", "mod_protocol"); + var registrySync = Identifier.of("fabric", "registry_sync"); ServerConfigurationConnectionEvents.BEFORE_CONFIGURE.addPhaseOrdering(phase, Event.DEFAULT_PHASE); - ServerConfigurationConnectionEvents.BEFORE_CONFIGURE.register(ModProtocolManager::setupClient); + ServerConfigurationConnectionEvents.BEFORE_CONFIGURE.addPhaseOrdering(phase, registrySync); + ServerConfigurationConnectionEvents.BEFORE_CONFIGURE.register(phase, ModProtocolManager::setupClient); ModProtocolManager.collectModProtocols(); PayloadTypeRegistry.configurationC2S().register(ModProtocolResponseC2SPayload.ID, ModProtocolResponseC2SPayload.PACKET_CODEC); PayloadTypeRegistry.configurationS2C().register(ModProtocolRequestS2CPayload.ID, ModProtocolRequestS2CPayload.PACKET_CODEC); ServerConfigurationNetworking.registerGlobalReceiver(ModProtocolResponseC2SPayload.ID, (payload, context) -> { - // Todo: store result on the connection for further usage/api ((RemoteProtocolStorage) context.networkHandler()).fabric$setRemoteProtocol(payload.supported()); context.networkHandler().completeTask(ModProtocolManager.SyncConfigurationTask.KEY); }); diff --git a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/ModProtocolLocator.java b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/ModProtocolLocator.java index b3267429f0..1a347bfd2c 100644 --- a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/ModProtocolLocator.java +++ b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/ModProtocolLocator.java @@ -29,12 +29,12 @@ import net.fabricmc.loader.api.metadata.ModMetadata; public class ModProtocolLocator { - public static void provide(BiConsumer consumer) { + public static void provide(BiConsumer consumer) { for (var mod : FabricLoader.getInstance().getAllMods()) { create(mod, consumer); } } - private static void create(ModContainer container, BiConsumer consumer) { + private static void create(ModContainer container, BiConsumer consumer) { var meta = container.getMetadata(); var definition = meta.getCustomValue("fabric:mod_protocol"); if (definition == null) { @@ -46,13 +46,13 @@ private static void create(ModContainer container, BiConsumer NAMESPACE_PRIORITY = new ArrayList<>(List.of("special", "mod", "feature")); - public static final Comparator MOD_PROTOCOL_COMPARATOR = Comparator.comparingInt(x -> { + public static final Comparator MOD_PROTOCOL_COMPARATOR = Comparator.comparingInt(x -> { var out = NAMESPACE_PRIORITY.indexOf(x.id().getNamespace()); return out == -1 ? NAMESPACE_PRIORITY.size() : out; - }).thenComparing(ModProtocol::id); + }).thenComparing(ModProtocolImpl::id); - public static final Map LOCAL_MOD_PROTOCOLS_BY_ID = new HashMap<>(); - public static final List LOCAL_MOD_PROTOCOLS = new ArrayList<>(); - public static final List PING_SYNCED_PROTOCOLS = new ArrayList<>(); - public static final List CLIENT_REQUIRED = new ArrayList<>(); - public static final List SERVER_REQUIRED = new ArrayList<>(); + public static final Map LOCAL_MOD_PROTOCOLS_BY_ID = new HashMap<>(); + public static final List LOCAL_MOD_PROTOCOLS = new ArrayList<>(); + public static final List PING_SYNCED_PROTOCOLS = new ArrayList<>(); + public static final List CLIENT_REQUIRED = new ArrayList<>(); + public static final List SERVER_REQUIRED = new ArrayList<>(); public static void setupClient(ServerConfigurationNetworkHandler handler, MinecraftServer server) { if (!ServerConfigurationNetworking.canSend(handler, ModProtocolRequestS2CPayload.ID)) { @@ -64,7 +65,7 @@ public static void setupClient(ServerConfigurationNetworkHandler handler, Minecr handler.addTask(new SyncConfigurationTask()); } - public static Text constructMessage(List missingProtocols, Map localProtocols) { + public static Text constructMessage(List missingProtocols, Map localProtocols) { var text = Text.empty(); text.append(TextUtil.translatable("text.fabric.mod_protocol.mismatched.title").formatted(Formatting.GOLD)).append("\n"); text.append(TextUtil.translatable("text.fabric.mod_protocol.mismatched.desc").formatted(Formatting.YELLOW)).append("\n\n"); @@ -73,7 +74,7 @@ public static Text constructMessage(List missingProtocols, Map missingProtocols, Map localProtocols, int limit, Consumer consumer) { + public static void appendTextEntries(List missingProtocols, Map localProtocols, int limit, Consumer consumer) { missingProtocols.sort(MOD_PROTOCOL_COMPARATOR); if (limit == -1) { limit = missingProtocols.size(); @@ -83,12 +84,12 @@ public static void appendTextEntries(List missingProtocols, Map missingProtocols, Map received) { + public static ValidationResult validateClient(Map received) { return validate(received, LOCAL_MOD_PROTOCOLS_BY_ID, SERVER_REQUIRED); } - public static ValidationResult validate(Map received, Map localById, List requiredRemote) { + public static ValidationResult validate(Map received, Map localById, List requiredRemote) { var supported = new Object2IntOpenHashMap(); - var missingLocal = new ArrayList(); - var missingRemote = new ArrayList(); + var missingLocal = new ArrayList(); + var missingRemote = new ArrayList(); for (var modProtocol : received.values()) { var local = localById.get(modProtocol.id()); if (local != null) { - var version = local.getHighestVersion(modProtocol.protocols()); + var version = local.getHighestVersion(modProtocol.protocol()); if (version != -1) { supported.put(modProtocol.id(), version); - } else if (modProtocol.requiredClient()) { + } else if (modProtocol.requireClient()) { missingLocal.add(modProtocol); } - } else if (modProtocol.requiredClient()) { + } else if (modProtocol.requireClient()) { missingLocal.add(modProtocol); } } @@ -137,23 +138,52 @@ public static void collectModProtocols() { ModProtocolLocator.provide(ModProtocolManager::add); } - public static void add(ModContainer container, ModProtocol protocol) { + public static ModProtocolImpl add(@Nullable ModContainer container, ModProtocolImpl protocol) { if (LOCAL_MOD_PROTOCOLS_BY_ID.containsKey(protocol.id())) { - ModProtocolInit.LOGGER.warn("Found duplicate protocol id '{}' provided by mod '{}'", protocol.id(), (container != null ? container.getMetadata().getId() : "")); - return; + if (container != null) { + ModProtocolInit.LOGGER.warn("Found duplicate protocol id '{}' provided by mod '{}'", protocol.id(), container.getMetadata().getId()); + } else { + ModProtocolInit.LOGGER.warn("Found duplicate protocol id '{}' registered by a mod!'", protocol.id(), new RuntimeException()); + } + return LOCAL_MOD_PROTOCOLS_BY_ID.get(protocol); } LOCAL_MOD_PROTOCOLS_BY_ID.put(protocol.id(), protocol); LOCAL_MOD_PROTOCOLS.add(protocol); - if (protocol.requiredClient()) { + if (protocol.requireClient()) { CLIENT_REQUIRED.add(protocol); } - if (protocol.requiredServer()) { + if (protocol.requireServer()) { SERVER_REQUIRED.add(protocol); } if (protocol.syncWithServerMetadata()) { PING_SYNCED_PROTOCOLS.add(protocol); } + return null; + } + + @SuppressWarnings("ConstantValue") + public static boolean registerOrder(String firstNamespace, String secondNamespace) { + if (firstNamespace.equals(secondNamespace)) { + return false; + } + var firstIndex = NAMESPACE_PRIORITY.indexOf(firstNamespace); + var secondIndex = NAMESPACE_PRIORITY.indexOf(secondNamespace); + if (firstIndex != -1 && secondIndex != -1) { + if (firstIndex > secondIndex) { + ModProtocolInit.LOGGER.warn("Protocol '{}' is already set to display after '{}'!", firstNamespace, secondNamespace); + return false; + } + return true; + } else if (firstIndex == -1) { + NAMESPACE_PRIORITY.add(secondIndex, firstNamespace); + } else if (secondIndex == -1) { + NAMESPACE_PRIORITY.add(firstIndex + 1, secondNamespace); + } else { + NAMESPACE_PRIORITY.add(firstNamespace); + NAMESPACE_PRIORITY.add(secondNamespace); + } + return true; } public static class SyncConfigurationTask implements ServerPlayerConfigurationTask { @@ -169,13 +199,13 @@ public Key getKey() { } } - public record ValidationResult(Object2IntMap supportedProtocols, List missingLocal, List missingRemote) { + public record ValidationResult(Object2IntMap supportedProtocols, List missingLocal, List missingRemote) { public boolean isSuccess() { return missingLocal.isEmpty() && missingRemote.isEmpty(); } - public List missing() { - var arr = new ArrayList(); + public List missing() { + var arr = new ArrayList(); arr.addAll(missingLocal); arr.addAll(missingRemote); return arr; diff --git a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/RemoteProtocolStorage.java b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/RemoteProtocolStorage.java index fd70bb1716..6e32cf0c42 100644 --- a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/RemoteProtocolStorage.java +++ b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/RemoteProtocolStorage.java @@ -17,11 +17,36 @@ package net.fabricmc.fabric.impl.modprotocol; import it.unimi.dsi.fastutil.objects.Object2IntMap; +import it.unimi.dsi.fastutil.objects.Object2IntMaps; import org.jetbrains.annotations.Nullable; import net.minecraft.util.Identifier; public interface RemoteProtocolStorage { + static int getProtocol(Object object, Identifier identifier) { + if (object instanceof RemoteProtocolStorage storage) { + var map = storage.fabric$getRemoteProtocol(); + + if (map != null) { + return map.getOrDefault(identifier, -1); + } + } + + return -1; + } + + static Object2IntMap getMap(Object object) { + if (object instanceof RemoteProtocolStorage storage) { + var map = storage.fabric$getRemoteProtocol(); + + if (map != null) { + return Object2IntMaps.unmodifiable(map); + } + } + + return Object2IntMaps.emptyMap(); + } + @Nullable Object2IntMap fabric$getRemoteProtocol(); void fabric$setRemoteProtocol(Object2IntMap protocol); diff --git a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/payload/ModProtocolRequestS2CPayload.java b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/payload/ModProtocolRequestS2CPayload.java index 2afdeeb547..d170f00d94 100644 --- a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/payload/ModProtocolRequestS2CPayload.java +++ b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/payload/ModProtocolRequestS2CPayload.java @@ -24,11 +24,11 @@ import net.minecraft.network.packet.CustomPayload; import net.minecraft.util.Identifier; -import net.fabricmc.fabric.impl.modprotocol.ModProtocol; +import net.fabricmc.fabric.impl.modprotocol.ModProtocolImpl; -public record ModProtocolRequestS2CPayload(List modProtocol) implements CustomPayload { +public record ModProtocolRequestS2CPayload(List modProtocol) implements CustomPayload { public static final Id ID = new Id<>(Identifier.of("fabric", "mod_protocol_request")); - public static final PacketCodec PACKET_CODEC = ModProtocol.PACKET_CODEC.collect(PacketCodecs.toList()) + public static final PacketCodec PACKET_CODEC = ModProtocolImpl.PACKET_CODEC.collect(PacketCodecs.toList()) .xmap(ModProtocolRequestS2CPayload::new, ModProtocolRequestS2CPayload::modProtocol); @Override diff --git a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/mixin/modprotocol/RegistriesMixin.java b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/mixin/modprotocol/RegistriesMixin.java new file mode 100644 index 0000000000..f5200a7b1b --- /dev/null +++ b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/mixin/modprotocol/RegistriesMixin.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.mixin.modprotocol; + + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import net.minecraft.registry.Registries; + +import net.fabricmc.fabric.impl.modprotocol.ModProtocolInit; + +@Mixin(Registries.class) +public class RegistriesMixin { + @Inject(method = "freezeRegistries", at = @At("TAIL")) + private static void onRegistryFrozen(CallbackInfo ci) { + ModProtocolInit.frozen = true; + } +} diff --git a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/mixin/modprotocol/ServerMetadataMixin.java b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/mixin/modprotocol/ServerMetadataMixin.java index b37b9be6a6..6a03a107cd 100644 --- a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/mixin/modprotocol/ServerMetadataMixin.java +++ b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/mixin/modprotocol/ServerMetadataMixin.java @@ -30,22 +30,22 @@ import net.minecraft.server.ServerMetadata; -import net.fabricmc.fabric.impl.modprotocol.ModProtocol; import net.fabricmc.fabric.impl.modprotocol.ModProtocolHolder; +import net.fabricmc.fabric.impl.modprotocol.ModProtocolImpl; @Mixin(ServerMetadata.class) public class ServerMetadataMixin implements ModProtocolHolder { @Unique @Nullable - private List modProtocol; + private List modProtocol; @Override - public List fabric$getModProtocol() { + public List fabric$getModProtocol() { return this.modProtocol; } @Override - public void fabric$setModProtocol(List protocol) { + public void fabric$setModProtocol(List protocol) { this.modProtocol = protocol; } @@ -58,7 +58,7 @@ public DataResult> decode(DynamicOps ops, T input if (decoded.isSuccess()) { var protocol = ops.get(input, "fabric:mod_protocol"); if (protocol.isSuccess()) { - var result = ModProtocol.LIST_CODEC.decode(ops, protocol.getOrThrow()); + var result = ModProtocolImpl.LIST_CODEC.decode(ops, protocol.getOrThrow()); if (result.isSuccess()) { ModProtocolHolder.of(decoded.getOrThrow().getFirst()).fabric$setModProtocol(result.getOrThrow().getFirst()); } @@ -71,7 +71,7 @@ public DataResult> decode(DynamicOps ops, T input public DataResult encode(ServerMetadata input, DynamicOps ops, T prefix) { var encode = original.encode(input, ops, prefix); if (encode.isSuccess() && ModProtocolHolder.of(input).fabric$getModProtocol() != null) { - var protocol = ModProtocol.LIST_CODEC.encodeStart(ops, ModProtocolHolder.of(input).fabric$getModProtocol()); + var protocol = ModProtocolImpl.LIST_CODEC.encodeStart(ops, ModProtocolHolder.of(input).fabric$getModProtocol()); if (protocol.isSuccess()) { encode = ops.mergeToMap(encode.getOrThrow(), ops.createString("fabric:mod_protocol"), protocol.getOrThrow()); } diff --git a/fabric-mod-protocol-api-v1/src/main/resources/fabric-mod-protocol-api-v1.mixins.json b/fabric-mod-protocol-api-v1/src/main/resources/fabric-mod-protocol-api-v1.mixins.json index c74094c62b..af5ef83df3 100644 --- a/fabric-mod-protocol-api-v1/src/main/resources/fabric-mod-protocol-api-v1.mixins.json +++ b/fabric-mod-protocol-api-v1/src/main/resources/fabric-mod-protocol-api-v1.mixins.json @@ -5,6 +5,7 @@ "mixins": [ "ClientConnectionMixin", "MinecraftServerMixin", + "RegistriesMixin", "ServerCommonNetworkHandlerMixin", "ServerMetadataMixin" ], diff --git a/fabric-mod-protocol-api-v1/src/test/java/net/fabricmc/fabric/test/modprotocol/unit/VersionMatchingTests.java b/fabric-mod-protocol-api-v1/src/test/java/net/fabricmc/fabric/test/modprotocol/unit/VersionMatchingTests.java index 10bf23fe40..ab8f81c615 100644 --- a/fabric-mod-protocol-api-v1/src/test/java/net/fabricmc/fabric/test/modprotocol/unit/VersionMatchingTests.java +++ b/fabric-mod-protocol-api-v1/src/test/java/net/fabricmc/fabric/test/modprotocol/unit/VersionMatchingTests.java @@ -16,56 +16,12 @@ package net.fabricmc.fabric.test.modprotocol.unit; -import static org.junit.jupiter.api.Assertions.assertArrayEquals; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertIterableEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.mockito.ArgumentCaptor; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.network.ClientConfigurationNetworkHandler; -import net.minecraft.network.NetworkPhase; -import net.minecraft.network.PacketByteBuf; -import net.minecraft.network.RegistryByteBuf; -import net.minecraft.network.codec.PacketCodec; -import net.minecraft.network.packet.CustomPayload; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.network.ServerConfigurationNetworkHandler; -import net.minecraft.util.Identifier; -import net.fabricmc.fabric.api.client.networking.v1.ClientConfigurationNetworking; -import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; -import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; -import net.fabricmc.fabric.api.networking.v1.PacketSender; -import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry; -import net.fabricmc.fabric.api.networking.v1.ServerConfigurationNetworking; -import net.fabricmc.fabric.impl.networking.ChannelInfoHolder; -import net.fabricmc.fabric.impl.networking.CommonPacketHandler; -import net.fabricmc.fabric.impl.networking.CommonPacketsImpl; -import net.fabricmc.fabric.impl.networking.CommonRegisterPayload; -import net.fabricmc.fabric.impl.networking.CommonVersionPayload; -import net.fabricmc.fabric.impl.networking.client.ClientConfigurationNetworkAddon; -import net.fabricmc.fabric.impl.networking.client.ClientNetworkingImpl; -import net.fabricmc.fabric.impl.networking.server.ServerConfigurationNetworkAddon; -import net.fabricmc.fabric.impl.networking.server.ServerNetworkingImpl; public class VersionMatchingTests { @BeforeAll @@ -78,10 +34,4 @@ static void beforeAll() { void setUp() { } - - // Test handling the version packet on the client - @Test - void handleVersionPacketClient() { - - } } diff --git a/fabric-mod-protocol-api-v1/src/testmod/java/net/fabricmc/fabric/test/modprotocol/ModProtocolTestmods.java b/fabric-mod-protocol-api-v1/src/testmod/java/net/fabricmc/fabric/test/modprotocol/ModProtocolTestmods.java index ff1bf5cfe7..92c2130c38 100644 --- a/fabric-mod-protocol-api-v1/src/testmod/java/net/fabricmc/fabric/test/modprotocol/ModProtocolTestmods.java +++ b/fabric-mod-protocol-api-v1/src/testmod/java/net/fabricmc/fabric/test/modprotocol/ModProtocolTestmods.java @@ -16,19 +16,46 @@ package net.fabricmc.fabric.test.modprotocol; +import it.unimi.dsi.fastutil.ints.IntList; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import net.minecraft.util.Identifier; +import net.fabricmc.fabric.api.modprotocol.v1.ModProtocolIds; +import net.fabricmc.fabric.api.modprotocol.v1.ModProtocolRegistry; +import net.fabricmc.fabric.api.modprotocol.v1.ServerModProtocolLookup; +import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents; +import net.fabricmc.fabric.impl.modprotocol.ModProtocolLocator; +import net.fabricmc.loader.api.FabricLoader; + public final class ModProtocolTestmods { - public static final String ID = "fabric-modprotocol-api-v1-testmod"; + public static final String ID = "fabric-mod-protocol-api-v1-testmod"; public static final Logger LOGGER = LoggerFactory.getLogger(ID); public static Identifier id(String name) { return Identifier.of(ID, name); } - private ModProtocolTestmods() { + public static void init() { + var modContainer = FabricLoader.getInstance().getModContainer(ID).get(); + + ModProtocolRegistry.register(ModProtocolIds.special("test_modification"), "Hello there", "1.12.2", IntList.of(1, 2, 3), true, false); + + var testificate = modContainer.getMetadata().getCustomValue("test_fabric:mod_protocol"); + var defaulted = modContainer.getMetadata().getCustomValue("test2_fabric:mod_protocol"); + + ServerPlayConnectionEvents.JOIN.register(((handler, sender, server) -> { + var protocols = ServerModProtocolLookup.getAllSupportedProtocols(handler); + LOGGER.info("Protocols supported by {}", handler.getDebugProfile().getName()); + for (var entry : protocols.object2IntEntrySet()) { + LOGGER.info(" - {}: {}", entry.getKey(), entry.getIntValue()); + } + + })); + + LOGGER.info("Parser full array-like, {}", ModProtocolLocator.decodeFullDefinition(testificate, modContainer.getMetadata(), true)); + LOGGER.info("Parser default, no defaults: {}", ModProtocolLocator.decodeFullDefinition(testificate, modContainer.getMetadata(), false)); + LOGGER.info("Parser default, with defaults: {}", ModProtocolLocator.decodeFullDefinition(defaulted, modContainer.getMetadata(), false)); } } diff --git a/fabric-mod-protocol-api-v1/src/testmod/resources/fabric.mod.json b/fabric-mod-protocol-api-v1/src/testmod/resources/fabric.mod.json index b66665c5df..856a9294e6 100644 --- a/fabric-mod-protocol-api-v1/src/testmod/resources/fabric.mod.json +++ b/fabric-mod-protocol-api-v1/src/testmod/resources/fabric.mod.json @@ -10,13 +10,24 @@ }, "entrypoints": { "main": [ - + "net.fabricmc.fabric.test.modprotocol.ModProtocolTestmods::init" ], "client": [ ] }, "custom": { - "fabric:mod_protocol": 5 + "fabric:mod_protocol": 5, + "test_fabric:mod_protocol": { + "name": "Name", + "id": "special:id", + "protocol": [0, 1, 2, 3], + "version": "Tater", + "require_client": false, + "require_server": false + }, + "test2_fabric:mod_protocol": { + "protocol": [0, 1, 2, 3] + } } } diff --git a/fabric-registry-sync-v0/src/main/java/net/fabricmc/fabric/impl/registry/sync/FabricRegistryInit.java b/fabric-registry-sync-v0/src/main/java/net/fabricmc/fabric/impl/registry/sync/FabricRegistryInit.java index ef20ab4160..e0ba6aa058 100644 --- a/fabric-registry-sync-v0/src/main/java/net/fabricmc/fabric/impl/registry/sync/FabricRegistryInit.java +++ b/fabric-registry-sync-v0/src/main/java/net/fabricmc/fabric/impl/registry/sync/FabricRegistryInit.java @@ -16,6 +16,8 @@ package net.fabricmc.fabric.impl.registry.sync; +import net.fabricmc.fabric.api.event.Event; + import net.minecraft.registry.Registries; import net.fabricmc.api.ModInitializer; @@ -26,13 +28,16 @@ import net.fabricmc.fabric.api.networking.v1.ServerConfigurationNetworking; import net.fabricmc.fabric.impl.registry.sync.packet.DirectRegistryPacketHandler; +import net.minecraft.util.Identifier; + public class FabricRegistryInit implements ModInitializer { @Override public void onInitialize() { PayloadTypeRegistry.configurationC2S().register(SyncCompletePayload.ID, SyncCompletePayload.CODEC); PayloadTypeRegistry.configurationS2C().register(DirectRegistryPacketHandler.Payload.ID, DirectRegistryPacketHandler.Payload.CODEC); - - ServerConfigurationConnectionEvents.BEFORE_CONFIGURE.register(RegistrySyncManager::configureClient); + var registrySync = Identifier.of("fabric", "registry_sync"); + ServerConfigurationConnectionEvents.BEFORE_CONFIGURE.addPhaseOrdering(registrySync, Event.DEFAULT_PHASE); + ServerConfigurationConnectionEvents.BEFORE_CONFIGURE.register(registrySync, RegistrySyncManager::configureClient); ServerConfigurationNetworking.registerGlobalReceiver(SyncCompletePayload.ID, (payload, context) -> { context.networkHandler().completeTask(RegistrySyncManager.SyncConfigurationTask.KEY); }); From 685051a789af3e28201ee60e51be6048cd3f850c Mon Sep 17 00:00:00 2001 From: Patbox <39821509+Patbox@users.noreply.github.com> Date: Wed, 7 Aug 2024 21:07:45 +0200 Subject: [PATCH 04/11] Prevent joining to vanilla clients if server mods are required. --- ...lientConfigurationNetworkHandlerMixin.java | 48 +++++++++++++++++++ ...ric-mod-protocol-api-v1.client.mixins.json | 5 +- .../test/modprotocol/ModProtocolTestmods.java | 6 +++ 3 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 fabric-mod-protocol-api-v1/src/client/java/net/fabricmc/fabric/mixin/modprotocol/client/ClientConfigurationNetworkHandlerMixin.java diff --git a/fabric-mod-protocol-api-v1/src/client/java/net/fabricmc/fabric/mixin/modprotocol/client/ClientConfigurationNetworkHandlerMixin.java b/fabric-mod-protocol-api-v1/src/client/java/net/fabricmc/fabric/mixin/modprotocol/client/ClientConfigurationNetworkHandlerMixin.java new file mode 100644 index 0000000000..bab7952185 --- /dev/null +++ b/fabric-mod-protocol-api-v1/src/client/java/net/fabricmc/fabric/mixin/modprotocol/client/ClientConfigurationNetworkHandlerMixin.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.mixin.modprotocol.client; + +import net.fabricmc.fabric.impl.modprotocol.ModProtocolManager; +import net.fabricmc.fabric.impl.modprotocol.RemoteProtocolStorage; + +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.network.ClientCommonNetworkHandler; +import net.minecraft.client.network.ClientConnectionState; +import net.minecraft.network.ClientConnection; +import net.minecraft.network.packet.s2c.config.FeaturesS2CPacket; +import net.minecraft.network.packet.s2c.config.SelectKnownPacksS2CPacket; + +import org.spongepowered.asm.mixin.Mixin; +import net.minecraft.client.network.ClientConfigurationNetworkHandler; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(ClientConfigurationNetworkHandler.class) +public abstract class ClientConfigurationNetworkHandlerMixin extends ClientCommonNetworkHandler { + protected ClientConfigurationNetworkHandlerMixin(MinecraftClient client, ClientConnection connection, ClientConnectionState connectionState) { + super(client, connection, connectionState); + } + + @Inject(method = "onSelectKnownPacks", at = @At("HEAD"), cancellable = true) + private void preventJoiningIncompatibleServers(SelectKnownPacksS2CPacket packet, CallbackInfo ci) { + if (((RemoteProtocolStorage) this.connection).fabric$getRemoteProtocol() == null && !ModProtocolManager.SERVER_REQUIRED.isEmpty()) { + this.client.execute(() -> this.connection.disconnect(ModProtocolManager.constructMessage(ModProtocolManager.SERVER_REQUIRED, ModProtocolManager.LOCAL_MOD_PROTOCOLS_BY_ID))); + ci.cancel(); + } + } +} diff --git a/fabric-mod-protocol-api-v1/src/client/resources/fabric-mod-protocol-api-v1.client.mixins.json b/fabric-mod-protocol-api-v1/src/client/resources/fabric-mod-protocol-api-v1.client.mixins.json index f5f8b0ed45..13c1d91ba3 100644 --- a/fabric-mod-protocol-api-v1/src/client/resources/fabric-mod-protocol-api-v1.client.mixins.json +++ b/fabric-mod-protocol-api-v1/src/client/resources/fabric-mod-protocol-api-v1.client.mixins.json @@ -7,5 +7,8 @@ ], "injectors": { "defaultRequire": 1 - } + }, + "client": [ + "ClientConfigurationNetworkHandlerMixin" + ] } diff --git a/fabric-mod-protocol-api-v1/src/testmod/java/net/fabricmc/fabric/test/modprotocol/ModProtocolTestmods.java b/fabric-mod-protocol-api-v1/src/testmod/java/net/fabricmc/fabric/test/modprotocol/ModProtocolTestmods.java index 92c2130c38..aa32b01c9d 100644 --- a/fabric-mod-protocol-api-v1/src/testmod/java/net/fabricmc/fabric/test/modprotocol/ModProtocolTestmods.java +++ b/fabric-mod-protocol-api-v1/src/testmod/java/net/fabricmc/fabric/test/modprotocol/ModProtocolTestmods.java @@ -41,6 +41,12 @@ public static void init() { var modContainer = FabricLoader.getInstance().getModContainer(ID).get(); ModProtocolRegistry.register(ModProtocolIds.special("test_modification"), "Hello there", "1.12.2", IntList.of(1, 2, 3), true, false); + ModProtocolRegistry.register(ModProtocolIds.special("test_modification2"), "Test2", "1.0", IntList.of(1), false, true); + ModProtocolRegistry.register(ModProtocolIds.special("test_modification3"), "Test3", "2.0", IntList.of(2), true, true); + ModProtocolRegistry.register(ModProtocolIds.special("test_modification4"), "Test4", "2.0", IntList.of(2), true, true); + //ModProtocolRegistry.register(ModProtocolIds.special("test_modification5"), "Test5", "1.0", IntList.of(1), true, true); + ModProtocolRegistry.register(ModProtocolIds.special("test_modification6"), "Test6", "1.0", IntList.of(1), true, true); + ModProtocolRegistry.register(ModProtocolIds.special("test_modification7"), "Test7", "1.0", IntList.of(1), true, true); var testificate = modContainer.getMetadata().getCustomValue("test_fabric:mod_protocol"); var defaulted = modContainer.getMetadata().getCustomValue("test2_fabric:mod_protocol"); From d16dbc4a9a413f64207a56a02f076eb799f71e16 Mon Sep 17 00:00:00 2001 From: Patbox <39821509+Patbox@users.noreply.github.com> Date: Wed, 7 Aug 2024 21:19:00 +0200 Subject: [PATCH 05/11] Fix style check --- .../ClientConfigurationNetworkHandlerMixin.java | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/fabric-mod-protocol-api-v1/src/client/java/net/fabricmc/fabric/mixin/modprotocol/client/ClientConfigurationNetworkHandlerMixin.java b/fabric-mod-protocol-api-v1/src/client/java/net/fabricmc/fabric/mixin/modprotocol/client/ClientConfigurationNetworkHandlerMixin.java index bab7952185..96bac544b5 100644 --- a/fabric-mod-protocol-api-v1/src/client/java/net/fabricmc/fabric/mixin/modprotocol/client/ClientConfigurationNetworkHandlerMixin.java +++ b/fabric-mod-protocol-api-v1/src/client/java/net/fabricmc/fabric/mixin/modprotocol/client/ClientConfigurationNetworkHandlerMixin.java @@ -16,21 +16,20 @@ package net.fabricmc.fabric.mixin.modprotocol.client; -import net.fabricmc.fabric.impl.modprotocol.ModProtocolManager; -import net.fabricmc.fabric.impl.modprotocol.RemoteProtocolStorage; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import net.minecraft.client.MinecraftClient; import net.minecraft.client.network.ClientCommonNetworkHandler; +import net.minecraft.client.network.ClientConfigurationNetworkHandler; import net.minecraft.client.network.ClientConnectionState; import net.minecraft.network.ClientConnection; -import net.minecraft.network.packet.s2c.config.FeaturesS2CPacket; import net.minecraft.network.packet.s2c.config.SelectKnownPacksS2CPacket; -import org.spongepowered.asm.mixin.Mixin; -import net.minecraft.client.network.ClientConfigurationNetworkHandler; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import net.fabricmc.fabric.impl.modprotocol.ModProtocolManager; +import net.fabricmc.fabric.impl.modprotocol.RemoteProtocolStorage; @Mixin(ClientConfigurationNetworkHandler.class) public abstract class ClientConfigurationNetworkHandlerMixin extends ClientCommonNetworkHandler { From 781a8da93dcd6a3a0ed164440d503a0e630a3251 Mon Sep 17 00:00:00 2001 From: Patbox <39821509+Patbox@users.noreply.github.com> Date: Wed, 7 Aug 2024 22:18:30 +0200 Subject: [PATCH 06/11] Actually fix the checkstyle --- .../v1/ClientModProtocolLookup.java | 16 +++--- .../client/modprotocol/v1/package-info.java | 2 +- .../client/ClientModProtocolInit.java | 11 ++-- .../api/modprotocol/v1/ModProtocolIds.java | 3 +- .../modprotocol/v1/ModProtocolRegistry.java | 7 +-- .../v1/ServerModProtocolLookup.java | 30 +++++----- .../api/modprotocol/v1/package-info.java | 2 +- .../impl/modprotocol/ModProtocolHolder.java | 1 - .../impl/modprotocol/ModProtocolImpl.java | 57 ++++++++++--------- .../impl/modprotocol/ModProtocolInit.java | 10 ++-- .../impl/modprotocol/ModProtocolLocator.java | 28 ++++----- .../impl/modprotocol/ModProtocolManager.java | 53 +++++++++++------ .../modprotocol/RemoteProtocolStorage.java | 4 +- .../fabric/impl/modprotocol/TextUtil.java | 28 +++++---- .../ModProtocolResponseC2SPayload.java | 4 -- .../modprotocol/MinecraftServerMixin.java | 1 + .../mixin/modprotocol/RegistriesMixin.java | 1 - .../modprotocol/ServerMetadataMixin.java | 16 ++++-- .../unit/VersionMatchingTests.java | 13 +---- .../test/modprotocol/ModProtocolTestmods.java | 15 +++-- 20 files changed, 168 insertions(+), 134 deletions(-) diff --git a/fabric-mod-protocol-api-v1/src/client/java/net/fabricmc/fabric/api/client/modprotocol/v1/ClientModProtocolLookup.java b/fabric-mod-protocol-api-v1/src/client/java/net/fabricmc/fabric/api/client/modprotocol/v1/ClientModProtocolLookup.java index 7335ddf397..a93836e394 100644 --- a/fabric-mod-protocol-api-v1/src/client/java/net/fabricmc/fabric/api/client/modprotocol/v1/ClientModProtocolLookup.java +++ b/fabric-mod-protocol-api-v1/src/client/java/net/fabricmc/fabric/api/client/modprotocol/v1/ClientModProtocolLookup.java @@ -31,14 +31,14 @@ * Utility methods allowing to get protocol versions supported by the server. * *

Protocol identifier's can be any valid identifier, through by default mods defining it will use "mod" namespace and path equal to its id. - * See {@link ModProtocolIds} for more information. + * See {@link ModProtocolIds} for more information.

*/ public final class ClientModProtocolLookup { public static final int UNSUPPORTED = -1; - private ClientModProtocolLookup() {} + private ClientModProtocolLookup() { } /** - * Gets protocol version supported by the server + * Gets protocol version supported by the server. * * @param handler the network handler connected to the server * @param protocolId protocol's id @@ -49,7 +49,7 @@ public static int getSupportedProtocol(ClientCommonNetworkHandler handler, Ident } /** - * Gets protocol version supported by the server + * Gets protocol version supported by the server. * * @param connection the ClientConnection connected to the server * @param protocolId protocol's id @@ -60,7 +60,7 @@ public static int getSupportedProtocol(ClientConnection connection, Identifier p } /** - * Gets protocol version supported by the server + * Gets protocol version supported by the server. * * @param handler the network handler connected to the server * @param protocol protocol to check against @@ -71,7 +71,7 @@ public static int getSupportedProtocol(ClientCommonNetworkHandler handler, ModPr } /** - * Gets protocol version supported by the server + * Gets protocol version supported by the server. * * @param connection the ClientConnection connected to the server * @param protocol protocol to check against @@ -82,7 +82,7 @@ public static int getSupportedProtocol(ClientConnection connection, ModProtocol } /** - * Gets all protocols supported by the server + * Gets all protocols supported by the server. * * @param handler the network handler connected to the server * @return Map of protocols supported by the server @@ -92,7 +92,7 @@ public static Object2IntMap getAllSupportedProtocols(ServerCommonNet } /** - * Gets all protocols supported by the server + * Gets all protocols supported by the server. * * @param connection the ClientConnection connected to the server * @return Map of protocols supported by the server diff --git a/fabric-mod-protocol-api-v1/src/client/java/net/fabricmc/fabric/api/client/modprotocol/v1/package-info.java b/fabric-mod-protocol-api-v1/src/client/java/net/fabricmc/fabric/api/client/modprotocol/v1/package-info.java index 4cc2d51d00..f39de72ade 100644 --- a/fabric-mod-protocol-api-v1/src/client/java/net/fabricmc/fabric/api/client/modprotocol/v1/package-info.java +++ b/fabric-mod-protocol-api-v1/src/client/java/net/fabricmc/fabric/api/client/modprotocol/v1/package-info.java @@ -17,7 +17,7 @@ /** * The Mod Protocol API (client side), version 1. * - * See {@link net.fabricmc.fabric.api.modprotocol.v1} + *

See {@link net.fabricmc.fabric.api.modprotocol.v1}

*/ @ApiStatus.Experimental diff --git a/fabric-mod-protocol-api-v1/src/client/java/net/fabricmc/fabric/impl/modprotocol/client/ClientModProtocolInit.java b/fabric-mod-protocol-api-v1/src/client/java/net/fabricmc/fabric/impl/modprotocol/client/ClientModProtocolInit.java index 67523602ff..5b6bf7cab2 100644 --- a/fabric-mod-protocol-api-v1/src/client/java/net/fabricmc/fabric/impl/modprotocol/client/ClientModProtocolInit.java +++ b/fabric-mod-protocol-api-v1/src/client/java/net/fabricmc/fabric/impl/modprotocol/client/ClientModProtocolInit.java @@ -29,24 +29,27 @@ import net.fabricmc.fabric.impl.modprotocol.payload.ModProtocolResponseC2SPayload; public final class ClientModProtocolInit { - - public static void clientInit() { ClientConfigurationNetworking.registerGlobalReceiver(ModProtocolRequestS2CPayload.ID, (payload, context) -> { var map = new HashMap(payload.modProtocol().size()); - for (var protocol : payload.modProtocol()) { + + for (ModProtocolImpl protocol : payload.modProtocol()) { map.put(protocol.id(), protocol); } - var validate = ModProtocolManager.validateClient(map); + + ModProtocolManager.ValidationResult validate = ModProtocolManager.validateClient(map); + if (validate.isSuccess()) { ((RemoteProtocolStorage) context.networkHandler()).fabric$setRemoteProtocol(validate.supportedProtocols()); context.responseSender().sendPacket(new ModProtocolResponseC2SPayload(validate.supportedProtocols())); return; } + var b = new StringBuilder(); b.append("Disconnected due to mismatched protocols!").append('\n'); b.append("Missing entries:").append('\n'); ModProtocolManager.appendTextEntries(validate.missing(), ModProtocolManager.LOCAL_MOD_PROTOCOLS_BY_ID, -1, text -> b.append(" - ").append(text.getString())); + context.responseSender().disconnect(ModProtocolManager.constructMessage(validate.missing(), ModProtocolManager.LOCAL_MOD_PROTOCOLS_BY_ID)); ModProtocolInit.LOGGER.warn(b.toString()); }); diff --git a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/api/modprotocol/v1/ModProtocolIds.java b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/api/modprotocol/v1/ModProtocolIds.java index 75d91a36f4..ccdada3882 100644 --- a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/api/modprotocol/v1/ModProtocolIds.java +++ b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/api/modprotocol/v1/ModProtocolIds.java @@ -25,7 +25,8 @@ public final class ModProtocolIds { public static final String MOD = "mod"; public static final String SPECIAL = "special"; public static final String FEATURE = "feature"; - private ModProtocolIds() {} + private ModProtocolIds() { } + public static Identifier mod(String modId) { return Identifier.of(MOD, modId); } diff --git a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/api/modprotocol/v1/ModProtocolRegistry.java b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/api/modprotocol/v1/ModProtocolRegistry.java index b8f0274fcb..46b1f551a5 100644 --- a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/api/modprotocol/v1/ModProtocolRegistry.java +++ b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/api/modprotocol/v1/ModProtocolRegistry.java @@ -30,13 +30,13 @@ /** * Utility methods allowing to lookup or register new protocols. * - *

While lookup can be done anytime, registration is only possible before registries are frozen. + *

While lookup can be done anytime, registration is only possible before registries are frozen.

*/ public final class ModProtocolRegistry { - private ModProtocolRegistry() {} + private ModProtocolRegistry() { } /** - * Allows to get a locally registered protocol + * Allows to get a locally registered protocol. * @param identifier protocol's id * @return requested ModProtocol or null if not found */ @@ -67,7 +67,6 @@ public static ModProtocol register(Identifier identifier, String name, String ve return ModProtocolManager.add(null, new ModProtocolImpl(identifier, name, version, IntList.of(protocol.toIntArray()), requireClient, requireServer)); } - /** * Allows to customise priority of namespaces when displaying missing protocols. * @param firstNamespace namespace that should display first diff --git a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/api/modprotocol/v1/ServerModProtocolLookup.java b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/api/modprotocol/v1/ServerModProtocolLookup.java index 7e26544e79..507ce1cea7 100644 --- a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/api/modprotocol/v1/ServerModProtocolLookup.java +++ b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/api/modprotocol/v1/ServerModProtocolLookup.java @@ -16,7 +16,6 @@ package net.fabricmc.fabric.api.modprotocol.v1; - import it.unimi.dsi.fastutil.objects.Object2IntMap; import net.minecraft.network.ClientConnection; @@ -30,14 +29,16 @@ * Utility methods allowing to get protocol versions supported by the player. * *

Protocol identifier's can be any valid identifier, through by default mods defining it will use "mod" namespace and path equal to its id. - * See {@link ModProtocolIds} for more information. + * See {@link ModProtocolIds} for more information.

*/ public final class ServerModProtocolLookup { public static final int UNSUPPORTED = -1; - private ServerModProtocolLookup() {} + + private ServerModProtocolLookup() { + } /** - * Gets protocol version supported by the player + * Gets protocol version supported by the player. * * @param player the player * @param protocolId protocol's id @@ -46,8 +47,9 @@ private ServerModProtocolLookup() {} public static int getSupportedProtocol(ServerPlayerEntity player, Identifier protocolId) { return RemoteProtocolStorage.getProtocol(player.networkHandler, protocolId); } + /** - * Gets protocol version supported by the player + * Gets protocol version supported by the player. * * @param handler the network handler owned by the player you want to check protocol for * @param protocolId protocol's id @@ -58,7 +60,7 @@ public static int getSupportedProtocol(ServerCommonNetworkHandler handler, Ident } /** - * Gets protocol version supported by the server + * Gets protocol version supported by the server. * * @param connection the ClientConnection connected to the server * @param protocolId protocol's id @@ -69,7 +71,7 @@ public static int getSupportedProtocol(ClientConnection connection, Identifier p } /** - * Gets protocol version supported by the player + * Gets protocol version supported by the player. * * @param player the player * @param protocol protocol to check against @@ -78,8 +80,9 @@ public static int getSupportedProtocol(ClientConnection connection, Identifier p public static int getSupportedProtocol(ServerPlayerEntity player, ModProtocol protocol) { return RemoteProtocolStorage.getProtocol(player.networkHandler, protocol.id()); } + /** - * Gets protocol version supported by the player + * Gets protocol version supported by the player. * * @param handler the network handler owned by the player you want to check protocol for * @param protocol protocol to check against @@ -90,9 +93,9 @@ public static int getSupportedProtocol(ServerCommonNetworkHandler handler, ModPr } /** - * Gets protocol version supported by the server + * Gets protocol version supported by the server. * - * @param connection the ClientConnection connected to the server + * @param connection the ClientConnection connected to the server. * @param protocol protocol to check against * @return Protocol version supported by the server */ @@ -101,7 +104,7 @@ public static int getSupportedProtocol(ClientConnection connection, ModProtocol } /** - * Gets all protocols supported by the player + * Gets all protocols supported by the player. * * @param player the player * @return Map of protocols supported by the player @@ -109,8 +112,9 @@ public static int getSupportedProtocol(ClientConnection connection, ModProtocol public static Object2IntMap getAllSupportedProtocols(ServerPlayerEntity player) { return RemoteProtocolStorage.getMap(player.networkHandler); } + /** - * Gets all protocols supported by the player + * Gets all protocols supported by the player. * * @param handler the network handler owned by the player you want to check protocol for * @return Map of protocols supported by the player @@ -120,7 +124,7 @@ public static Object2IntMap getAllSupportedProtocols(ServerCommonNet } /** - * Gets all protocols supported by the player + * Gets all protocols supported by the player. * * @param connection the ClientConnection connected to the server * @return Map of protocols supported by the player diff --git a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/api/modprotocol/v1/package-info.java b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/api/modprotocol/v1/package-info.java index 32f9b74e75..7a86d14baf 100644 --- a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/api/modprotocol/v1/package-info.java +++ b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/api/modprotocol/v1/package-info.java @@ -31,7 +31,7 @@ *
*
"fabric:mod_protocol": 1
*

This will automatically use mods id with "mod" namespace as the protocol identifier, as a single supported protocol version, - * with display name and version being copied form mods metadata. It also marks the protocol as required on both client and server. + * with display name and version being copied form mods metadata. It also marks the protocol as required on both client and server.

*
*
"fabric:mod_protocol": { * "protocol": [1, 2], diff --git a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/ModProtocolHolder.java b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/ModProtocolHolder.java index 5f62b6d92a..e783a9dc94 100644 --- a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/ModProtocolHolder.java +++ b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/ModProtocolHolder.java @@ -30,5 +30,4 @@ static ModProtocolHolder of(ServerMetadata input) { @Nullable List fabric$getModProtocol(); void fabric$setModProtocol(List protocol); - } diff --git a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/ModProtocolImpl.java b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/ModProtocolImpl.java index 560c2dce9a..4e13786391 100644 --- a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/ModProtocolImpl.java +++ b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/ModProtocolImpl.java @@ -27,39 +27,29 @@ import net.minecraft.network.codec.PacketCodec; import net.minecraft.util.Identifier; -public record ModProtocolImpl(Identifier id, String name, String version, IntList protocol, boolean requireClient, boolean requireServer) implements net.fabricmc.fabric.api.modprotocol.v1.ModProtocol { +import net.fabricmc.fabric.api.modprotocol.v1.ModProtocol; + +public record ModProtocolImpl(Identifier id, String name, String version, IntList protocol, boolean requireClient, boolean requireServer) implements ModProtocol { public static final int UNSUPPORTED = -1; public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( - Identifier.CODEC.fieldOf("id").forGetter(ModProtocolImpl::id), - Codec.STRING.fieldOf("name").forGetter(ModProtocolImpl::name), - Codec.STRING.fieldOf("version").forGetter(ModProtocolImpl::version), - Codec.INT_STREAM.xmap(x -> IntList.of(x.toArray()), x -> IntStream.of(x.toIntArray())).fieldOf("protocol").forGetter(ModProtocolImpl::protocol), - Codec.BOOL.fieldOf("require_client").forGetter(ModProtocolImpl::requireClient), - Codec.BOOL.fieldOf("require_server").forGetter(ModProtocolImpl::requireServer) + Identifier.CODEC.fieldOf("id").forGetter(ModProtocolImpl::id), + Codec.STRING.fieldOf("name").forGetter(ModProtocolImpl::name), + Codec.STRING.fieldOf("version").forGetter(ModProtocolImpl::version), + Codec.INT_STREAM.xmap(x -> IntList.of(x.toArray()), x -> IntStream.of(x.toIntArray())).fieldOf("protocol").forGetter(ModProtocolImpl::protocol), + Codec.BOOL.fieldOf("require_client").forGetter(ModProtocolImpl::requireClient), + Codec.BOOL.fieldOf("require_server").forGetter(ModProtocolImpl::requireServer) ).apply(instance, ModProtocolImpl::new)); public static final Codec> LIST_CODEC = CODEC.listOf(); - public int getHighestVersion(IntList list) { - int value = UNSUPPORTED; - for (int i = 0; i < list.size(); i++) { - var proto = list.getInt(i); - if (this.protocol.contains(proto) && value < proto) { - value = proto; - } - } - - return value; - } - public static final PacketCodec PACKET_CODEC = PacketCodec.ofStatic(ModProtocolImpl::encode, ModProtocolImpl::decode); private static ModProtocolImpl decode(PacketByteBuf buf) { - var id = buf.readIdentifier(); - var name = buf.readString(); - var version = buf.readString(); - var protocols = IntList.of(buf.readIntArray()); - var b = buf.readByte(); - var requireClient = (b & 0b10) != 0; - var requireServer = (b & 0b01) != 0; + Identifier id = buf.readIdentifier(); + String name = buf.readString(); + String version = buf.readString(); + IntList protocols = IntList.of(buf.readIntArray()); + byte b = buf.readByte(); + boolean requireClient = (b & 0b10) != 0; + boolean requireServer = (b & 0b01) != 0; return new ModProtocolImpl(id, name, version, protocols, requireClient, requireServer); } @@ -71,6 +61,21 @@ private static void encode(PacketByteBuf buf, ModProtocolImpl protocol) { buf.writeByte((protocol.requireClient ? 0b10 : 0) | (protocol.requireServer ? 0b01 : 0)); } + public int getHighestVersion(IntList list) { + int value = UNSUPPORTED; + int size = list.size(); + + for (int i = 0; i < size; i++) { + int proto = list.getInt(i); + + if (this.protocol.contains(proto) && value < proto) { + value = proto; + } + } + + return value; + } + public boolean syncWithServerMetadata() { return this.requireClient() || this.requireServer(); } diff --git a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/ModProtocolInit.java b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/ModProtocolInit.java index 74fd5033ed..445f26ffae 100644 --- a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/ModProtocolInit.java +++ b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/ModProtocolInit.java @@ -33,19 +33,21 @@ public final class ModProtocolInit { public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID); public static boolean frozen = false; - public static void init() { - var phase = Identifier.of("fabric", "mod_protocol"); - var registrySync = Identifier.of("fabric", "registry_sync"); + Identifier phase = Identifier.of("fabric", "mod_protocol"); + Identifier registrySync = Identifier.of("fabric", "registry_sync"); + ServerConfigurationConnectionEvents.BEFORE_CONFIGURE.addPhaseOrdering(phase, Event.DEFAULT_PHASE); ServerConfigurationConnectionEvents.BEFORE_CONFIGURE.addPhaseOrdering(phase, registrySync); ServerConfigurationConnectionEvents.BEFORE_CONFIGURE.register(phase, ModProtocolManager::setupClient); - ModProtocolManager.collectModProtocols(); + PayloadTypeRegistry.configurationC2S().register(ModProtocolResponseC2SPayload.ID, ModProtocolResponseC2SPayload.PACKET_CODEC); PayloadTypeRegistry.configurationS2C().register(ModProtocolRequestS2CPayload.ID, ModProtocolRequestS2CPayload.PACKET_CODEC); ServerConfigurationNetworking.registerGlobalReceiver(ModProtocolResponseC2SPayload.ID, (payload, context) -> { ((RemoteProtocolStorage) context.networkHandler()).fabric$setRemoteProtocol(payload.supported()); context.networkHandler().completeTask(ModProtocolManager.SyncConfigurationTask.KEY); }); + + ModProtocolManager.collectModProtocols(); } } diff --git a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/ModProtocolLocator.java b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/ModProtocolLocator.java index 1a347bfd2c..fa15d54d87 100644 --- a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/ModProtocolLocator.java +++ b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/ModProtocolLocator.java @@ -30,19 +30,21 @@ public class ModProtocolLocator { public static void provide(BiConsumer consumer) { - for (var mod : FabricLoader.getInstance().getAllMods()) { + for (ModContainer mod : FabricLoader.getInstance().getAllMods()) { create(mod, consumer); } } + private static void create(ModContainer container, BiConsumer consumer) { - var meta = container.getMetadata(); - var definition = meta.getCustomValue("fabric:mod_protocol"); + ModMetadata meta = container.getMetadata(); + CustomValue definition = meta.getCustomValue("fabric:mod_protocol"); + if (definition == null) { return; } if (definition.getType() == CustomValue.CvType.ARRAY) { - for (var entry : definition.getAsArray()) { + for (CustomValue entry : definition.getAsArray()) { consumer.accept(container, decodeFullDefinition(entry, meta, true)); } } else if (definition.getType() == CustomValue.CvType.NUMBER) { @@ -56,7 +58,8 @@ public static ModProtocolImpl decodeFullDefinition(CustomValue entry, ModMetadat if (entry.getType() != CustomValue.CvType.OBJECT) { throw new RuntimeException("Mod Protocol entry provided by '" + meta.getId() + "' is not valid!"); } - var object = entry.getAsObject(); + + CustomValue.CvObject object = entry.getAsObject(); Identifier id; String name; String version; @@ -64,12 +67,12 @@ public static ModProtocolImpl decodeFullDefinition(CustomValue entry, ModMetadat boolean requiredServer; IntList protocols = new IntArrayList(); - var idField = object.get("id"); - var nameField = object.get("name"); - var versionField = object.get("version"); - var protocolField = object.get("protocol"); - var requiredClientField = object.get("require_client"); - var requiredServerField = object.get("require_server"); + CustomValue idField = object.get("id"); + CustomValue nameField = object.get("name"); + CustomValue versionField = object.get("version"); + CustomValue protocolField = object.get("protocol"); + CustomValue requiredClientField = object.get("require_client"); + CustomValue requiredServerField = object.get("require_server"); if (!requireFullData && idField == null) { id = Identifier.of("mod", meta.getId()); @@ -82,7 +85,7 @@ public static ModProtocolImpl decodeFullDefinition(CustomValue entry, ModMetadat if (protocolField != null && protocolField.getType() == CustomValue.CvType.NUMBER) { protocols.add(protocolField.getAsNumber().intValue()); } else if (protocolField != null && protocolField.getType() == CustomValue.CvType.ARRAY) { - for (var value : protocolField.getAsArray()) { + for (CustomValue value : protocolField.getAsArray()) { if (value.getType() == CustomValue.CvType.NUMBER) { protocols.add(value.getAsNumber().intValue()); } else { @@ -125,7 +128,6 @@ public static ModProtocolImpl decodeFullDefinition(CustomValue entry, ModMetadat throw new RuntimeException("Mod Protocol entry provided by '" + meta.getId() + "' is not valid!"); } - return new ModProtocolImpl(id, name, version, IntList.of(protocols.toIntArray()), requiredClient, requiredServer); } } diff --git a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/ModProtocolManager.java b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/ModProtocolManager.java index 298492d33d..4e26092529 100644 --- a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/ModProtocolManager.java +++ b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/ModProtocolManager.java @@ -32,6 +32,7 @@ import net.minecraft.server.MinecraftServer; import net.minecraft.server.network.ServerConfigurationNetworkHandler; import net.minecraft.server.network.ServerPlayerConfigurationTask; +import net.minecraft.text.MutableText; import net.minecraft.text.Text; import net.minecraft.util.Formatting; import net.minecraft.util.Identifier; @@ -43,7 +44,7 @@ public final class ModProtocolManager { public static final List NAMESPACE_PRIORITY = new ArrayList<>(List.of("special", "mod", "feature")); public static final Comparator MOD_PROTOCOL_COMPARATOR = Comparator.comparingInt(x -> { - var out = NAMESPACE_PRIORITY.indexOf(x.id().getNamespace()); + int out = NAMESPACE_PRIORITY.indexOf(x.id().getNamespace()); return out == -1 ? NAMESPACE_PRIORITY.size() : out; }).thenComparing(ModProtocolImpl::id); @@ -66,35 +67,41 @@ public static void setupClient(ServerConfigurationNetworkHandler handler, Minecr } public static Text constructMessage(List missingProtocols, Map localProtocols) { - var text = Text.empty(); + MutableText text = Text.empty(); text.append(TextUtil.translatable("text.fabric.mod_protocol.mismatched.title").formatted(Formatting.GOLD)).append("\n"); text.append(TextUtil.translatable("text.fabric.mod_protocol.mismatched.desc").formatted(Formatting.YELLOW)).append("\n\n"); text.append(TextUtil.translatable("text.fabric.mod_protocol.mismatched.entries.title").formatted(Formatting.RED)).append("\n"); - appendTextEntries(missingProtocols, localProtocols, 6, text::append); + appendTextEntries(missingProtocols, localProtocols, 6, text::append); return text; } public static void appendTextEntries(List missingProtocols, Map localProtocols, int limit, Consumer consumer) { missingProtocols.sort(MOD_PROTOCOL_COMPARATOR); + if (limit == -1) { limit = missingProtocols.size(); } - var size = Math.min(limit, missingProtocols.size()); + + int size = Math.min(limit, missingProtocols.size()); + for (int i = 0; i < size; i++) { - var protocol = missingProtocols.get(i); - var local = localProtocols.get(protocol.id()); - var localVersion = local == null ? TextUtil.translatable("text.fabric.mod_protocol.missing").formatted(Formatting.DARK_RED) + ModProtocolImpl protocol = missingProtocols.get(i); + ModProtocolImpl local = localProtocols.get(protocol.id()); + Text localVersion = local == null ? TextUtil.translatable("text.fabric.mod_protocol.missing").formatted(Formatting.DARK_RED) : Text.literal(local.version()).formatted(Formatting.YELLOW); - var remoteVersion = local == protocol ? TextUtil.translatable("text.fabric.mod_protocol.missing").formatted(Formatting.DARK_RED) + Text remoteVersion = local == protocol ? TextUtil.translatable("text.fabric.mod_protocol.missing").formatted(Formatting.DARK_RED) : Text.literal(protocol.version()).formatted(Formatting.YELLOW); - var text = TextUtil.translatable("text.fabric.mod_protocol.entry", + MutableText text = TextUtil.translatable("text.fabric.mod_protocol.entry", Text.literal(protocol.name()).formatted(Formatting.WHITE), localVersion, remoteVersion).formatted(Formatting.GRAY); + if (i + 1 < size) { text.append("\n"); } + consumer.accept(text); } + if (limit < missingProtocols.size()) { consumer.accept(Text.literal("\n").append(TextUtil.translatable("text.fabric.mod_protocol.and_x_more", missingProtocols.size() - size).formatted(Formatting.GRAY, Formatting.ITALIC))); } @@ -109,10 +116,12 @@ public static ValidationResult validate(Map receive var missingLocal = new ArrayList(); var missingRemote = new ArrayList(); - for (var modProtocol : received.values()) { - var local = localById.get(modProtocol.id()); + for (ModProtocolImpl modProtocol : received.values()) { + ModProtocolImpl local = localById.get(modProtocol.id()); + if (local != null) { - var version = local.getHighestVersion(modProtocol.protocol()); + int version = local.getHighestVersion(modProtocol.protocol()); + if (version != -1) { supported.put(modProtocol.id(), version); } else if (modProtocol.requireClient()) { @@ -123,14 +132,14 @@ public static ValidationResult validate(Map receive } } - for (var modProtocol : requiredRemote) { - var remote = received.get(modProtocol.id()); + for (ModProtocolImpl modProtocol : requiredRemote) { + ModProtocolImpl remote = received.get(modProtocol.id()); + if (remote == null) { missingRemote.add(modProtocol); } } - return new ValidationResult(supported, missingLocal, missingRemote); } @@ -145,20 +154,25 @@ public static ModProtocolImpl add(@Nullable ModContainer container, ModProtocolI } else { ModProtocolInit.LOGGER.warn("Found duplicate protocol id '{}' registered by a mod!'", protocol.id(), new RuntimeException()); } + return LOCAL_MOD_PROTOCOLS_BY_ID.get(protocol); } + LOCAL_MOD_PROTOCOLS_BY_ID.put(protocol.id(), protocol); LOCAL_MOD_PROTOCOLS.add(protocol); if (protocol.requireClient()) { CLIENT_REQUIRED.add(protocol); } + if (protocol.requireServer()) { SERVER_REQUIRED.add(protocol); } + if (protocol.syncWithServerMetadata()) { PING_SYNCED_PROTOCOLS.add(protocol); } + return null; } @@ -167,13 +181,16 @@ public static boolean registerOrder(String firstNamespace, String secondNamespac if (firstNamespace.equals(secondNamespace)) { return false; } - var firstIndex = NAMESPACE_PRIORITY.indexOf(firstNamespace); - var secondIndex = NAMESPACE_PRIORITY.indexOf(secondNamespace); + + int firstIndex = NAMESPACE_PRIORITY.indexOf(firstNamespace); + int secondIndex = NAMESPACE_PRIORITY.indexOf(secondNamespace); + if (firstIndex != -1 && secondIndex != -1) { if (firstIndex > secondIndex) { ModProtocolInit.LOGGER.warn("Protocol '{}' is already set to display after '{}'!", firstNamespace, secondNamespace); return false; } + return true; } else if (firstIndex == -1) { NAMESPACE_PRIORITY.add(secondIndex, firstNamespace); @@ -183,11 +200,13 @@ public static boolean registerOrder(String firstNamespace, String secondNamespac NAMESPACE_PRIORITY.add(firstNamespace); NAMESPACE_PRIORITY.add(secondNamespace); } + return true; } public static class SyncConfigurationTask implements ServerPlayerConfigurationTask { public static final Key KEY = new Key("fabric:mod_protocol_sync"); + @Override public void sendPacket(Consumer> sender) { sender.accept(new CustomPayloadS2CPacket(new ModProtocolRequestS2CPayload(LOCAL_MOD_PROTOCOLS))); diff --git a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/RemoteProtocolStorage.java b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/RemoteProtocolStorage.java index 6e32cf0c42..860bdd1c2d 100644 --- a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/RemoteProtocolStorage.java +++ b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/RemoteProtocolStorage.java @@ -25,7 +25,7 @@ public interface RemoteProtocolStorage { static int getProtocol(Object object, Identifier identifier) { if (object instanceof RemoteProtocolStorage storage) { - var map = storage.fabric$getRemoteProtocol(); + Object2IntMap map = storage.fabric$getRemoteProtocol(); if (map != null) { return map.getOrDefault(identifier, -1); @@ -37,7 +37,7 @@ static int getProtocol(Object object, Identifier identifier) { static Object2IntMap getMap(Object object) { if (object instanceof RemoteProtocolStorage storage) { - var map = storage.fabric$getRemoteProtocol(); + Object2IntMap map = storage.fabric$getRemoteProtocol(); if (map != null) { return Object2IntMaps.unmodifiable(map); diff --git a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/TextUtil.java b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/TextUtil.java index 6a9bdc3ce7..d9d13c1a3c 100644 --- a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/TextUtil.java +++ b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/TextUtil.java @@ -17,38 +17,42 @@ package net.fabricmc.fabric.impl.modprotocol; import java.nio.file.Files; +import java.nio.file.Path; import java.util.HashMap; import java.util.Map; +import java.util.Optional; +import com.google.gson.JsonObject; import com.google.gson.JsonParser; import net.minecraft.text.MutableText; import net.minecraft.text.Text; import net.fabricmc.loader.api.FabricLoader; +import net.fabricmc.loader.api.ModContainer; public class TextUtil { private static final Map FALLBACK_TRANSLATIONS = new HashMap<>(); - public static MutableText translatable(String key, Object... args) { - return Text.translatableWithFallback(key, FALLBACK_TRANSLATIONS.get(key), args); - } - - public static MutableText translatable(String key) { - return Text.translatableWithFallback(key, FALLBACK_TRANSLATIONS.get(key)); - } - static { try { - var container = FabricLoader.getInstance().getModContainer(ModProtocolInit.MOD_ID); - var path = container.get().findPath("assets/fabric-mod-protocol-api-v1/lang/en_us.json"); - var lang = JsonParser.parseString(Files.readString(path.get())).getAsJsonObject(); + Optional container = FabricLoader.getInstance().getModContainer(ModProtocolInit.MOD_ID); + Optional path = container.get().findPath("assets/fabric-mod-protocol-api-v1/lang/en_us.json"); + JsonObject lang = JsonParser.parseString(Files.readString(path.get())).getAsJsonObject(); - for (var key : lang.keySet()) { + for (String key : lang.keySet()) { FALLBACK_TRANSLATIONS.put(key, lang.get(key).getAsString()); } } catch (Throwable e) { ModProtocolInit.LOGGER.error("Failed to load translation file!", e); } } + + public static MutableText translatable(String key, Object... args) { + return Text.translatableWithFallback(key, FALLBACK_TRANSLATIONS.get(key), args); + } + + public static MutableText translatable(String key) { + return Text.translatableWithFallback(key, FALLBACK_TRANSLATIONS.get(key)); + } } diff --git a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/payload/ModProtocolResponseC2SPayload.java b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/payload/ModProtocolResponseC2SPayload.java index d832cc4a0b..b16f9cdf0b 100644 --- a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/payload/ModProtocolResponseC2SPayload.java +++ b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/payload/ModProtocolResponseC2SPayload.java @@ -16,8 +16,6 @@ package net.fabricmc.fabric.impl.modprotocol.payload; - - import it.unimi.dsi.fastutil.objects.Object2IntMap; import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; @@ -27,8 +25,6 @@ import net.minecraft.network.packet.CustomPayload; import net.minecraft.util.Identifier; - - public record ModProtocolResponseC2SPayload(Object2IntMap supported) implements CustomPayload { public static final Id ID = new Id<>(Identifier.of("fabric", "mod_protocol/response")); public static final PacketCodec PACKET_CODEC = diff --git a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/mixin/modprotocol/MinecraftServerMixin.java b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/mixin/modprotocol/MinecraftServerMixin.java index 03966bb365..c7fd9b2b7b 100644 --- a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/mixin/modprotocol/MinecraftServerMixin.java +++ b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/mixin/modprotocol/MinecraftServerMixin.java @@ -33,6 +33,7 @@ private ServerMetadata addModProtocol(ServerMetadata original) { if (!ModProtocolManager.PING_SYNCED_PROTOCOLS.isEmpty()) { ModProtocolHolder.of(original).fabric$setModProtocol(ModProtocolManager.PING_SYNCED_PROTOCOLS); } + return original; } } diff --git a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/mixin/modprotocol/RegistriesMixin.java b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/mixin/modprotocol/RegistriesMixin.java index f5200a7b1b..affb107254 100644 --- a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/mixin/modprotocol/RegistriesMixin.java +++ b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/mixin/modprotocol/RegistriesMixin.java @@ -16,7 +16,6 @@ package net.fabricmc.fabric.mixin.modprotocol; - import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; diff --git a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/mixin/modprotocol/ServerMetadataMixin.java b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/mixin/modprotocol/ServerMetadataMixin.java index 6a03a107cd..c2c4a0833f 100644 --- a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/mixin/modprotocol/ServerMetadataMixin.java +++ b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/mixin/modprotocol/ServerMetadataMixin.java @@ -54,24 +54,30 @@ private static Codec extendCodec(Codec original) return new Codec<>() { @Override public DataResult> decode(DynamicOps ops, T input) { - var decoded = original.decode(ops, input); + DataResult> decoded = original.decode(ops, input); + if (decoded.isSuccess()) { - var protocol = ops.get(input, "fabric:mod_protocol"); + DataResult protocol = ops.get(input, "fabric:mod_protocol"); + if (protocol.isSuccess()) { - var result = ModProtocolImpl.LIST_CODEC.decode(ops, protocol.getOrThrow()); + DataResult, T>> result = ModProtocolImpl.LIST_CODEC.decode(ops, protocol.getOrThrow()); + if (result.isSuccess()) { ModProtocolHolder.of(decoded.getOrThrow().getFirst()).fabric$setModProtocol(result.getOrThrow().getFirst()); } } } + return decoded; } @Override public DataResult encode(ServerMetadata input, DynamicOps ops, T prefix) { - var encode = original.encode(input, ops, prefix); + DataResult encode = original.encode(input, ops, prefix); + if (encode.isSuccess() && ModProtocolHolder.of(input).fabric$getModProtocol() != null) { - var protocol = ModProtocolImpl.LIST_CODEC.encodeStart(ops, ModProtocolHolder.of(input).fabric$getModProtocol()); + DataResult protocol = ModProtocolImpl.LIST_CODEC.encodeStart(ops, ModProtocolHolder.of(input).fabric$getModProtocol()); + if (protocol.isSuccess()) { encode = ops.mergeToMap(encode.getOrThrow(), ops.createString("fabric:mod_protocol"), protocol.getOrThrow()); } diff --git a/fabric-mod-protocol-api-v1/src/test/java/net/fabricmc/fabric/test/modprotocol/unit/VersionMatchingTests.java b/fabric-mod-protocol-api-v1/src/test/java/net/fabricmc/fabric/test/modprotocol/unit/VersionMatchingTests.java index ab8f81c615..1ec71c4a69 100644 --- a/fabric-mod-protocol-api-v1/src/test/java/net/fabricmc/fabric/test/modprotocol/unit/VersionMatchingTests.java +++ b/fabric-mod-protocol-api-v1/src/test/java/net/fabricmc/fabric/test/modprotocol/unit/VersionMatchingTests.java @@ -16,22 +16,13 @@ package net.fabricmc.fabric.test.modprotocol.unit; - - import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; - - public class VersionMatchingTests { @BeforeAll - static void beforeAll() { - - } - + static void beforeAll() { } @BeforeEach - void setUp() { - - } + void setUp() { } } diff --git a/fabric-mod-protocol-api-v1/src/testmod/java/net/fabricmc/fabric/test/modprotocol/ModProtocolTestmods.java b/fabric-mod-protocol-api-v1/src/testmod/java/net/fabricmc/fabric/test/modprotocol/ModProtocolTestmods.java index aa32b01c9d..7406129b74 100644 --- a/fabric-mod-protocol-api-v1/src/testmod/java/net/fabricmc/fabric/test/modprotocol/ModProtocolTestmods.java +++ b/fabric-mod-protocol-api-v1/src/testmod/java/net/fabricmc/fabric/test/modprotocol/ModProtocolTestmods.java @@ -17,6 +17,7 @@ package net.fabricmc.fabric.test.modprotocol; import it.unimi.dsi.fastutil.ints.IntList; +import it.unimi.dsi.fastutil.objects.Object2IntMap; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -28,6 +29,8 @@ import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents; import net.fabricmc.fabric.impl.modprotocol.ModProtocolLocator; import net.fabricmc.loader.api.FabricLoader; +import net.fabricmc.loader.api.ModContainer; +import net.fabricmc.loader.api.metadata.CustomValue; public final class ModProtocolTestmods { public static final String ID = "fabric-mod-protocol-api-v1-testmod"; @@ -38,7 +41,7 @@ public static Identifier id(String name) { } public static void init() { - var modContainer = FabricLoader.getInstance().getModContainer(ID).get(); + ModContainer modContainer = FabricLoader.getInstance().getModContainer(ID).get(); ModProtocolRegistry.register(ModProtocolIds.special("test_modification"), "Hello there", "1.12.2", IntList.of(1, 2, 3), true, false); ModProtocolRegistry.register(ModProtocolIds.special("test_modification2"), "Test2", "1.0", IntList.of(1), false, true); @@ -48,16 +51,16 @@ public static void init() { ModProtocolRegistry.register(ModProtocolIds.special("test_modification6"), "Test6", "1.0", IntList.of(1), true, true); ModProtocolRegistry.register(ModProtocolIds.special("test_modification7"), "Test7", "1.0", IntList.of(1), true, true); - var testificate = modContainer.getMetadata().getCustomValue("test_fabric:mod_protocol"); - var defaulted = modContainer.getMetadata().getCustomValue("test2_fabric:mod_protocol"); + CustomValue testificate = modContainer.getMetadata().getCustomValue("test_fabric:mod_protocol"); + CustomValue defaulted = modContainer.getMetadata().getCustomValue("test2_fabric:mod_protocol"); ServerPlayConnectionEvents.JOIN.register(((handler, sender, server) -> { - var protocols = ServerModProtocolLookup.getAllSupportedProtocols(handler); + Object2IntMap protocols = ServerModProtocolLookup.getAllSupportedProtocols(handler); LOGGER.info("Protocols supported by {}", handler.getDebugProfile().getName()); - for (var entry : protocols.object2IntEntrySet()) { + + for (Object2IntMap.Entry entry : protocols.object2IntEntrySet()) { LOGGER.info(" - {}: {}", entry.getKey(), entry.getIntValue()); } - })); LOGGER.info("Parser full array-like, {}", ModProtocolLocator.decodeFullDefinition(testificate, modContainer.getMetadata(), true)); From 822bdb2af4c36d2aaf17f385307b29a70be0453c Mon Sep 17 00:00:00 2001 From: Patbox <39821509+Patbox@users.noreply.github.com> Date: Wed, 7 Aug 2024 22:45:18 +0200 Subject: [PATCH 07/11] Check-styles aren't my passion --- .../networking/v1/ClientConfigurationNetworking.java | 3 +-- .../networking/AbstractChanneledNetworkAddon.java | 11 +++++------ .../networking/ServerPlayNetworkHandlerMixin.java | 1 + .../fabric/impl/registry/sync/FabricRegistryInit.java | 10 +++++----- 4 files changed, 12 insertions(+), 13 deletions(-) diff --git a/fabric-networking-api-v1/src/client/java/net/fabricmc/fabric/api/client/networking/v1/ClientConfigurationNetworking.java b/fabric-networking-api-v1/src/client/java/net/fabricmc/fabric/api/client/networking/v1/ClientConfigurationNetworking.java index 52f20c0018..ac8b0cb663 100644 --- a/fabric-networking-api-v1/src/client/java/net/fabricmc/fabric/api/client/networking/v1/ClientConfigurationNetworking.java +++ b/fabric-networking-api-v1/src/client/java/net/fabricmc/fabric/api/client/networking/v1/ClientConfigurationNetworking.java @@ -19,12 +19,11 @@ import java.util.Objects; import java.util.Set; -import net.minecraft.client.network.ClientConfigurationNetworkHandler; - import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; import net.minecraft.client.MinecraftClient; +import net.minecraft.client.network.ClientConfigurationNetworkHandler; import net.minecraft.network.packet.CustomPayload; import net.minecraft.util.Identifier; import net.minecraft.util.thread.ThreadExecutor; diff --git a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/AbstractChanneledNetworkAddon.java b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/AbstractChanneledNetworkAddon.java index c84031f2c8..de59ad37f3 100644 --- a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/AbstractChanneledNetworkAddon.java +++ b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/AbstractChanneledNetworkAddon.java @@ -24,13 +24,12 @@ import java.util.Objects; import java.util.Set; -import net.minecraft.network.packet.BrandCustomPayload; - import org.jetbrains.annotations.Nullable; import net.minecraft.network.ClientConnection; import net.minecraft.network.NetworkPhase; import net.minecraft.network.PacketCallbacks; +import net.minecraft.network.packet.BrandCustomPayload; import net.minecraft.network.packet.CustomPayload; import net.minecraft.network.packet.Packet; import net.minecraft.text.Text; @@ -231,6 +230,10 @@ public String getBrand() { return this.brand; } + public void setBrand(String brand) { + this.brand = brand; + } + @Override public int getNegotiatedVersion() { if (commonVersion == -1) { @@ -248,8 +251,4 @@ private String getPhase() { default -> null; // We don't support receiving this packet on any other phase }; } - - public void setBrand(String brand) { - this.brand = brand; - } } diff --git a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/mixin/networking/ServerPlayNetworkHandlerMixin.java b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/mixin/networking/ServerPlayNetworkHandlerMixin.java index 6207c47ed7..d2e0ae5967 100644 --- a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/mixin/networking/ServerPlayNetworkHandlerMixin.java +++ b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/mixin/networking/ServerPlayNetworkHandlerMixin.java @@ -47,6 +47,7 @@ abstract class ServerPlayNetworkHandlerMixin extends ServerCommonNetworkHandler @Inject(method = "", at = @At("RETURN")) private void initAddon(CallbackInfo ci, @Local(argsOnly = true) ClientConnection connection) { this.addon = new ServerPlayNetworkAddon((ServerPlayNetworkHandler) (Object) this, connection, server); + if (connection.getPacketListener() instanceof NetworkHandlerExtensions extension) { this.addon.setBrand(extension.getAddon().getBrand()); } diff --git a/fabric-registry-sync-v0/src/main/java/net/fabricmc/fabric/impl/registry/sync/FabricRegistryInit.java b/fabric-registry-sync-v0/src/main/java/net/fabricmc/fabric/impl/registry/sync/FabricRegistryInit.java index e0ba6aa058..3bc0a7b039 100644 --- a/fabric-registry-sync-v0/src/main/java/net/fabricmc/fabric/impl/registry/sync/FabricRegistryInit.java +++ b/fabric-registry-sync-v0/src/main/java/net/fabricmc/fabric/impl/registry/sync/FabricRegistryInit.java @@ -16,11 +16,11 @@ package net.fabricmc.fabric.impl.registry.sync; -import net.fabricmc.fabric.api.event.Event; - import net.minecraft.registry.Registries; +import net.minecraft.util.Identifier; import net.fabricmc.api.ModInitializer; +import net.fabricmc.fabric.api.event.Event; import net.fabricmc.fabric.api.event.registry.RegistryAttribute; import net.fabricmc.fabric.api.event.registry.RegistryAttributeHolder; import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry; @@ -28,14 +28,14 @@ import net.fabricmc.fabric.api.networking.v1.ServerConfigurationNetworking; import net.fabricmc.fabric.impl.registry.sync.packet.DirectRegistryPacketHandler; -import net.minecraft.util.Identifier; - public class FabricRegistryInit implements ModInitializer { @Override public void onInitialize() { PayloadTypeRegistry.configurationC2S().register(SyncCompletePayload.ID, SyncCompletePayload.CODEC); PayloadTypeRegistry.configurationS2C().register(DirectRegistryPacketHandler.Payload.ID, DirectRegistryPacketHandler.Payload.CODEC); - var registrySync = Identifier.of("fabric", "registry_sync"); + + Identifier registrySync = Identifier.of("fabric", "registry_sync"); + ServerConfigurationConnectionEvents.BEFORE_CONFIGURE.addPhaseOrdering(registrySync, Event.DEFAULT_PHASE); ServerConfigurationConnectionEvents.BEFORE_CONFIGURE.register(registrySync, RegistrySyncManager::configureClient); ServerConfigurationNetworking.registerGlobalReceiver(SyncCompletePayload.ID, (payload, context) -> { From 73affdf24e3d33f8e43ac2f8eb0a0eacc960a8ea Mon Sep 17 00:00:00 2001 From: Patbox <39821509+Patbox@users.noreply.github.com> Date: Thu, 8 Aug 2024 09:40:05 +0200 Subject: [PATCH 08/11] Prevent mutating static array that can be accessed from multiple threads, use id to get the protocol from the map --- .../fabricmc/fabric/impl/modprotocol/ModProtocolManager.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/ModProtocolManager.java b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/ModProtocolManager.java index 4e26092529..3d22b9fb14 100644 --- a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/ModProtocolManager.java +++ b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/ModProtocolManager.java @@ -59,7 +59,7 @@ public static void setupClient(ServerConfigurationNetworkHandler handler, Minecr if (CLIENT_REQUIRED.isEmpty()) { return; } else { - handler.disconnect(constructMessage(CLIENT_REQUIRED, Map.of())); + handler.disconnect(constructMessage(new ArrayList<>(CLIENT_REQUIRED), Map.of())); } } @@ -155,7 +155,7 @@ public static ModProtocolImpl add(@Nullable ModContainer container, ModProtocolI ModProtocolInit.LOGGER.warn("Found duplicate protocol id '{}' registered by a mod!'", protocol.id(), new RuntimeException()); } - return LOCAL_MOD_PROTOCOLS_BY_ID.get(protocol); + return LOCAL_MOD_PROTOCOLS_BY_ID.get(protocol.id()); } LOCAL_MOD_PROTOCOLS_BY_ID.put(protocol.id(), protocol); From a770fb7ff671f1316c98ddf2d017646d6e3aa039 Mon Sep 17 00:00:00 2001 From: Patbox <39821509+Patbox@users.noreply.github.com> Date: Thu, 8 Aug 2024 19:21:48 +0200 Subject: [PATCH 09/11] Apply suggestions from code review Co-authored-by: apple502j <33279053+apple502j@users.noreply.github.com> --- .../v1/ClientModProtocolLookup.java | 24 +++++++++---------- .../modprotocol/v1/ModProtocolRegistry.java | 4 ++-- .../api/modprotocol/v1/package-info.java | 4 ++-- .../v1/ServerConfigurationNetworking.java | 4 ++-- .../networking/v1/ServerPlayNetworking.java | 8 +++---- 5 files changed, 22 insertions(+), 22 deletions(-) diff --git a/fabric-mod-protocol-api-v1/src/client/java/net/fabricmc/fabric/api/client/modprotocol/v1/ClientModProtocolLookup.java b/fabric-mod-protocol-api-v1/src/client/java/net/fabricmc/fabric/api/client/modprotocol/v1/ClientModProtocolLookup.java index a93836e394..550fae34a6 100644 --- a/fabric-mod-protocol-api-v1/src/client/java/net/fabricmc/fabric/api/client/modprotocol/v1/ClientModProtocolLookup.java +++ b/fabric-mod-protocol-api-v1/src/client/java/net/fabricmc/fabric/api/client/modprotocol/v1/ClientModProtocolLookup.java @@ -30,52 +30,52 @@ /** * Utility methods allowing to get protocol versions supported by the server. * - *

Protocol identifier's can be any valid identifier, through by default mods defining it will use "mod" namespace and path equal to its id. - * See {@link ModProtocolIds} for more information.

+ *

Protocol identifiers can be any valid {@link Identifier}. The default is {@code mod:(mod ID)}. + * @see ModProtocolIds */ public final class ClientModProtocolLookup { public static final int UNSUPPORTED = -1; private ClientModProtocolLookup() { } /** - * Gets protocol version supported by the server. + * Gets the protocol version supported by the server. * * @param handler the network handler connected to the server * @param protocolId protocol's id - * @return Protocol version supported by the server + * @return the protocol version supported by the server */ public static int getSupportedProtocol(ClientCommonNetworkHandler handler, Identifier protocolId) { return RemoteProtocolStorage.getProtocol(handler, protocolId); } /** - * Gets protocol version supported by the server. + * Gets the protocol version supported by the server. * * @param connection the ClientConnection connected to the server * @param protocolId protocol's id - * @return Protocol version supported by the server + * @return the protocol version supported by the server */ public static int getSupportedProtocol(ClientConnection connection, Identifier protocolId) { return RemoteProtocolStorage.getProtocol(connection, protocolId); } /** - * Gets protocol version supported by the server. + * Gets the protocol version supported by the server. * * @param handler the network handler connected to the server * @param protocol protocol to check against - * @return Protocol version supported by the server + * @return the protocol version supported by the server */ public static int getSupportedProtocol(ClientCommonNetworkHandler handler, ModProtocol protocol) { return RemoteProtocolStorage.getProtocol(handler, protocol.id()); } /** - * Gets protocol version supported by the server. + * Gets the protocol version supported by the server. * * @param connection the ClientConnection connected to the server * @param protocol protocol to check against - * @return Protocol version supported by the server + * @return the protocol version supported by the server */ public static int getSupportedProtocol(ClientConnection connection, ModProtocol protocol) { return RemoteProtocolStorage.getProtocol(connection, protocol.id()); @@ -85,7 +85,7 @@ public static int getSupportedProtocol(ClientConnection connection, ModProtocol * Gets all protocols supported by the server. * * @param handler the network handler connected to the server - * @return Map of protocols supported by the server + * @return the map of protocols to the versions supported by the server */ public static Object2IntMap getAllSupportedProtocols(ServerCommonNetworkHandler handler) { return RemoteProtocolStorage.getMap(handler); @@ -95,7 +95,7 @@ public static Object2IntMap getAllSupportedProtocols(ServerCommonNet * Gets all protocols supported by the server. * * @param connection the ClientConnection connected to the server - * @return Map of protocols supported by the server + * @return the map of protocols to the versions supported by the server */ public static Object2IntMap getAllSupportedProtocols(ClientConnection connection) { return RemoteProtocolStorage.getMap(connection); diff --git a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/api/modprotocol/v1/ModProtocolRegistry.java b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/api/modprotocol/v1/ModProtocolRegistry.java index 46b1f551a5..9471a364e0 100644 --- a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/api/modprotocol/v1/ModProtocolRegistry.java +++ b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/api/modprotocol/v1/ModProtocolRegistry.java @@ -38,7 +38,7 @@ private ModProtocolRegistry() { } /** * Allows to get a locally registered protocol. * @param identifier protocol's id - * @return requested ModProtocol or null if not found + * @return the requested ModProtocol or {@code null} if not found */ @Nullable public static ModProtocol get(Identifier identifier) { @@ -68,7 +68,7 @@ public static ModProtocol register(Identifier identifier, String name, String ve } /** - * Allows to customise priority of namespaces when displaying missing protocols. + * Allows to customize priority of namespaces when displaying missing protocols. * @param firstNamespace namespace that should display first * @param secondNamespace namespace that should display second * @return true if change occurred, false if it didn't diff --git a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/api/modprotocol/v1/package-info.java b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/api/modprotocol/v1/package-info.java index 7a86d14baf..7b5a75821e 100644 --- a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/api/modprotocol/v1/package-info.java +++ b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/api/modprotocol/v1/package-info.java @@ -42,8 +42,8 @@ * "require_server": true * }

*

Full object. Only required value is "protocol", which can be set directly for single version or as an array for multiple.

- *

"id" is protocols identifiers, which can have any namespace and path, as long as it's valid. - * It's optional and defaults to id with "mod" namespace and path equal to mod's id. + *

"id" is the protocols identifier, which can have any namespace and path, as long as it's valid. + * It is optional and defaults to an ID with "mod" namespace and path equal to mod's id. *

*

"name" is a name displayed if protocol doesn't match. It's optional and by default it uses one from mod's metadata.

*

"version" is a version displayed if protocol doesn't match. It's optional and by default it uses one from mod's metadata.

diff --git a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/api/networking/v1/ServerConfigurationNetworking.java b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/api/networking/v1/ServerConfigurationNetworking.java index 37e0766804..79d8e7632c 100644 --- a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/api/networking/v1/ServerConfigurationNetworking.java +++ b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/api/networking/v1/ServerConfigurationNetworking.java @@ -225,10 +225,10 @@ public static void send(ServerConfigurationNetworkHandler handler, CustomPayload // Helper methods /** - * Gets the brand of the client player connected with. + * Gets the brand of the client the player connected with. * * @param handler the network handler, representing the connection to the player/client - * @return client's brand, which might be null if not sent. + * @return client's brand, or {@code null} if not sent */ @Nullable public static String getBrand(ServerConfigurationNetworkHandler handler) { diff --git a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/api/networking/v1/ServerPlayNetworking.java b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/api/networking/v1/ServerPlayNetworking.java index 1574caf87a..9b498c35fa 100644 --- a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/api/networking/v1/ServerPlayNetworking.java +++ b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/api/networking/v1/ServerPlayNetworking.java @@ -294,10 +294,10 @@ public static void send(ServerPlayerEntity player, CustomPayload payload) { } /** - * Gets the brand of the client player connected with. + * Gets the brand of the client the player connected with. * * @param player the player - * @return client's brand, which might be null if not sent. + * @return client's brand, or {@code null} if not sent */ @Nullable public static String getBrand(ServerPlayerEntity player) { @@ -307,10 +307,10 @@ public static String getBrand(ServerPlayerEntity player) { } /** - * Gets the brand of the client player connected with. + * Gets the brand of the client the player connected with. * * @param handler the network handler, representing the connection to the player/client - * @return client's brand, which might be null if not sent. + * @return client's brand, or {@code null} if not sent */ @Nullable public static String getBrand(ServerPlayNetworkHandler handler) { From a08bffaaa7d2c5e3bf6270659e4263324efc517e Mon Sep 17 00:00:00 2001 From: Patbox <39821509+Patbox@users.noreply.github.com> Date: Thu, 8 Aug 2024 22:06:43 +0200 Subject: [PATCH 10/11] Java docs on the UNSUPPORTED, use (Client)ModInitializer, also set description --- .../v1/ClientModProtocolLookup.java | 3 +++ .../client/ClientModProtocolInit.java | 5 +++-- .../v1/ServerModProtocolLookup.java | 3 +++ .../impl/modprotocol/ModProtocolInit.java | 5 +++-- .../src/main/resources/fabric.mod.json | 18 +++++++++--------- .../test/modprotocol/ModProtocolTestmods.java | 5 +++-- .../src/testmod/resources/fabric.mod.json | 5 +---- 7 files changed, 25 insertions(+), 19 deletions(-) diff --git a/fabric-mod-protocol-api-v1/src/client/java/net/fabricmc/fabric/api/client/modprotocol/v1/ClientModProtocolLookup.java b/fabric-mod-protocol-api-v1/src/client/java/net/fabricmc/fabric/api/client/modprotocol/v1/ClientModProtocolLookup.java index 550fae34a6..51a37200b4 100644 --- a/fabric-mod-protocol-api-v1/src/client/java/net/fabricmc/fabric/api/client/modprotocol/v1/ClientModProtocolLookup.java +++ b/fabric-mod-protocol-api-v1/src/client/java/net/fabricmc/fabric/api/client/modprotocol/v1/ClientModProtocolLookup.java @@ -34,6 +34,9 @@ * @see ModProtocolIds */ public final class ClientModProtocolLookup { + /** + * A protocol version returned by {@code getSupportedProtocol} methods, when the server doesn't support the requested protocol. + */ public static final int UNSUPPORTED = -1; private ClientModProtocolLookup() { } diff --git a/fabric-mod-protocol-api-v1/src/client/java/net/fabricmc/fabric/impl/modprotocol/client/ClientModProtocolInit.java b/fabric-mod-protocol-api-v1/src/client/java/net/fabricmc/fabric/impl/modprotocol/client/ClientModProtocolInit.java index 5b6bf7cab2..c3716930be 100644 --- a/fabric-mod-protocol-api-v1/src/client/java/net/fabricmc/fabric/impl/modprotocol/client/ClientModProtocolInit.java +++ b/fabric-mod-protocol-api-v1/src/client/java/net/fabricmc/fabric/impl/modprotocol/client/ClientModProtocolInit.java @@ -20,6 +20,7 @@ import net.minecraft.util.Identifier; +import net.fabricmc.api.ClientModInitializer; import net.fabricmc.fabric.api.client.networking.v1.ClientConfigurationNetworking; import net.fabricmc.fabric.impl.modprotocol.ModProtocolImpl; import net.fabricmc.fabric.impl.modprotocol.ModProtocolInit; @@ -28,8 +29,8 @@ import net.fabricmc.fabric.impl.modprotocol.payload.ModProtocolRequestS2CPayload; import net.fabricmc.fabric.impl.modprotocol.payload.ModProtocolResponseC2SPayload; -public final class ClientModProtocolInit { - public static void clientInit() { +public final class ClientModProtocolInit implements ClientModInitializer { + public void onInitializeClient() { ClientConfigurationNetworking.registerGlobalReceiver(ModProtocolRequestS2CPayload.ID, (payload, context) -> { var map = new HashMap(payload.modProtocol().size()); diff --git a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/api/modprotocol/v1/ServerModProtocolLookup.java b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/api/modprotocol/v1/ServerModProtocolLookup.java index 507ce1cea7..63557d79de 100644 --- a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/api/modprotocol/v1/ServerModProtocolLookup.java +++ b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/api/modprotocol/v1/ServerModProtocolLookup.java @@ -32,6 +32,9 @@ * See {@link ModProtocolIds} for more information.

*/ public final class ServerModProtocolLookup { + /** + * A protocol version returned by {@code getSupportedProtocol} methods, when the player doesn't support the requested protocol. + */ public static final int UNSUPPORTED = -1; private ServerModProtocolLookup() { diff --git a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/ModProtocolInit.java b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/ModProtocolInit.java index 445f26ffae..8019b52aef 100644 --- a/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/ModProtocolInit.java +++ b/fabric-mod-protocol-api-v1/src/main/java/net/fabricmc/fabric/impl/modprotocol/ModProtocolInit.java @@ -21,6 +21,7 @@ import net.minecraft.util.Identifier; +import net.fabricmc.api.ModInitializer; import net.fabricmc.fabric.api.event.Event; import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry; import net.fabricmc.fabric.api.networking.v1.ServerConfigurationConnectionEvents; @@ -28,12 +29,12 @@ import net.fabricmc.fabric.impl.modprotocol.payload.ModProtocolRequestS2CPayload; import net.fabricmc.fabric.impl.modprotocol.payload.ModProtocolResponseC2SPayload; -public final class ModProtocolInit { +public final class ModProtocolInit implements ModInitializer { public static final String MOD_ID = "fabric-mod-protocol-api-v1"; public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID); public static boolean frozen = false; - public static void init() { + public void onInitialize() { Identifier phase = Identifier.of("fabric", "mod_protocol"); Identifier registrySync = Identifier.of("fabric", "registry_sync"); diff --git a/fabric-mod-protocol-api-v1/src/main/resources/fabric.mod.json b/fabric-mod-protocol-api-v1/src/main/resources/fabric.mod.json index 688b591323..2cf3c76866 100644 --- a/fabric-mod-protocol-api-v1/src/main/resources/fabric.mod.json +++ b/fabric-mod-protocol-api-v1/src/main/resources/fabric.mod.json @@ -2,6 +2,7 @@ "schemaVersion": 1, "id": "fabric-mod-protocol-api-v1", "name": "Fabric Mod Protocol API (v1)", + "description": "Versioned network protocol sync, validation and requirement system.", "version": "${version}", "environment": "*", "license": "Apache-2.0", @@ -17,25 +18,24 @@ ], "entrypoints": { "main": [ - "net.fabricmc.fabric.impl.modprotocol.ModProtocolInit::init" + "net.fabricmc.fabric.impl.modprotocol.ModProtocolInit" ], "client": [ - "net.fabricmc.fabric.impl.modprotocol.client.ClientModProtocolInit::clientInit" + "net.fabricmc.fabric.impl.modprotocol.client.ClientModProtocolInit" ] }, "mixins": [ - "fabric-mod-protocol-api-v1.mixins.json", - { - "config": "fabric-mod-protocol-api-v1.client.mixins.json", - "environment": "client" - } -], + "fabric-mod-protocol-api-v1.mixins.json", + { + "config": "fabric-mod-protocol-api-v1.client.mixins.json", + "environment": "client" + } + ], "depends": { "fabricloader": ">=0.15.11", "fabric-api-base": "*", "fabric-networking-api-v1": "*" }, - "description": "Low-level, vanilla protocol oriented networking hooks.", "custom": { "fabric-api:module-lifecycle": "experimental" } diff --git a/fabric-mod-protocol-api-v1/src/testmod/java/net/fabricmc/fabric/test/modprotocol/ModProtocolTestmods.java b/fabric-mod-protocol-api-v1/src/testmod/java/net/fabricmc/fabric/test/modprotocol/ModProtocolTestmods.java index 7406129b74..b9c7760e94 100644 --- a/fabric-mod-protocol-api-v1/src/testmod/java/net/fabricmc/fabric/test/modprotocol/ModProtocolTestmods.java +++ b/fabric-mod-protocol-api-v1/src/testmod/java/net/fabricmc/fabric/test/modprotocol/ModProtocolTestmods.java @@ -23,6 +23,7 @@ import net.minecraft.util.Identifier; +import net.fabricmc.api.ModInitializer; import net.fabricmc.fabric.api.modprotocol.v1.ModProtocolIds; import net.fabricmc.fabric.api.modprotocol.v1.ModProtocolRegistry; import net.fabricmc.fabric.api.modprotocol.v1.ServerModProtocolLookup; @@ -32,7 +33,7 @@ import net.fabricmc.loader.api.ModContainer; import net.fabricmc.loader.api.metadata.CustomValue; -public final class ModProtocolTestmods { +public final class ModProtocolTestmods implements ModInitializer { public static final String ID = "fabric-mod-protocol-api-v1-testmod"; public static final Logger LOGGER = LoggerFactory.getLogger(ID); @@ -40,7 +41,7 @@ public static Identifier id(String name) { return Identifier.of(ID, name); } - public static void init() { + public void onInitialize() { ModContainer modContainer = FabricLoader.getInstance().getModContainer(ID).get(); ModProtocolRegistry.register(ModProtocolIds.special("test_modification"), "Hello there", "1.12.2", IntList.of(1, 2, 3), true, false); diff --git a/fabric-mod-protocol-api-v1/src/testmod/resources/fabric.mod.json b/fabric-mod-protocol-api-v1/src/testmod/resources/fabric.mod.json index 856a9294e6..e75a481e0c 100644 --- a/fabric-mod-protocol-api-v1/src/testmod/resources/fabric.mod.json +++ b/fabric-mod-protocol-api-v1/src/testmod/resources/fabric.mod.json @@ -10,10 +10,7 @@ }, "entrypoints": { "main": [ - "net.fabricmc.fabric.test.modprotocol.ModProtocolTestmods::init" - ], - "client": [ - + "net.fabricmc.fabric.test.modprotocol.ModProtocolTestmods" ] }, "custom": { From ae341a5e7eb2d90ceace63327f534efe062fdc8e Mon Sep 17 00:00:00 2001 From: Patbox <39821509+Patbox@users.noreply.github.com> Date: Thu, 8 Aug 2024 22:15:33 +0200 Subject: [PATCH 11/11] Set version of the module to 1.0.0 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 7be263ed48..e1545cd567 100644 --- a/gradle.properties +++ b/gradle.properties @@ -38,7 +38,7 @@ fabric-lifecycle-events-v1-version=2.3.12 fabric-loot-api-v2-version=3.0.14 fabric-loot-api-v3-version=1.0.2 fabric-message-api-v1-version=6.0.13 -fabric-mod-protocol-api-v1-version=0.0.0 +fabric-mod-protocol-api-v1-version=1.0.0 fabric-model-loading-api-v1-version=2.0.0 fabric-networking-api-v1-version=4.2.2 fabric-object-builder-api-v1-version=15.2.0