From 7b70ea8a7a1890a8feddcd69d035f8cf619985a3 Mon Sep 17 00:00:00 2001 From: modmuss Date: Mon, 22 Jan 2024 18:24:37 +0000 Subject: [PATCH] Port to 24w03b (#3537) * Deprecate FabricBlockSettings * Deprecate FabricItemSettings * Start on 24w03a * Main menu :) * Update mappings * PayloadTypeRegistry * Networking part 2 of many * Networking part 3 of many * Networking part 4 of many * Recipe api * Port Item API to 1.20.5 * Is this even right? * Port FabricParticleTypes to 1.20.5 * Remove redundant fuel caching logic * Remove fabric-containers-v0, deprecated since 2020 * Regsync work * Adapt screen handler to new networking * Update yarn + more work * More mapping updates * Compile fixes * Checkstyle + small fixes * Single and multiplayer fixes * Handle play packets on main thread. * Update mappings * Even more networking * Networking tests * Fix todo's * Update javadocs * Networking API improvements * Some small regsync refactors * Fix handling of null NBT in NbtIngredient * Update fabric-object-builder-api-v1/src/main/java/net/fabricmc/fabric/api/object/builder/v1/block/FabricBlockSettings.java Co-authored-by: ErrorCraft <51973682+ErrorCraft@users.noreply.github.com> * Update fabric-object-builder-api-v1/src/main/java/net/fabricmc/fabric/api/object/builder/v1/block/FabricBlockSettings.java Co-authored-by: ErrorCraft <51973682+ErrorCraft@users.noreply.github.com> * Add context objects * ChannelInfoHolder.getPendingChannelsNames -> fabric_getPendingChannelsNames * Fix crash * send `c:register` packet for play phase instead of config (#3544) * Bump version --------- Co-authored-by: ErrorCraft <51973682+ErrorCraft@users.noreply.github.com> Co-authored-by: apple502j <33279053+apple502j@users.noreply.github.com> Co-authored-by: Drex Co-authored-by: deirn --- deprecated/fabric-containers-v0/build.gradle | 6 - .../client/screen/ContainerScreenFactory.java | 29 -- .../client/screen/ScreenProviderRegistry.java | 50 --- .../container/ScreenProviderRegistryImpl.java | 93 ----- .../api/container/ContainerFactory.java | 39 -- .../container/ContainerProviderRegistry.java | 61 ---- .../impl/container/ContainerProviderImpl.java | 117 ------ .../container/ServerPlayerEntityAccessor.java | 35 -- .../container/ServerPlayerEntityMixin.java | 39 -- .../assets/fabric-containers-v0/icon.png | Bin 1579 -> 0 bytes .../fabric-containers-v0.accurate.mixins.json | 11 - .../fabric-containers-v0.mixins.json | 11 - .../src/main/resources/fabric.mod.json | 36 -- .../test/lookup/FabricApiLookupTest.java | 8 +- .../fabric/test/lookup/InspectorBlock.java | 8 +- .../content/registry/FuelRegistryImpl.java | 19 +- .../content/registry/ContentRegistryTest.java | 2 +- .../src/main/resources/fabric.mod.json | 2 +- .../api/entity/event/v1/FabricElytraItem.java | 2 +- .../event/elytra/LivingEntityMixin.java | 2 +- .../test/entity/event/TestBedBlock.java | 2 +- .../interaction/FakePlayerNetworkHandler.java | 7 +- .../impl/gametest/FabricGameTestHelper.java | 8 +- .../api/item/v1/CustomDamageHandler.java | 15 +- .../api/item/v1/EquipmentSlotProvider.java | 2 +- .../fabric/api/item/v1/FabricItem.java | 30 ++ .../api/item/v1/FabricItemSettings.java | 11 +- .../fabric/mixin/item/ItemSettingsMixin.java | 15 +- .../fabric/mixin/item/ItemStackMixin.java | 46 +-- .../resources/fabric-item-api-v1.mixins.json | 1 + .../src/main/resources/fabric.mod.json | 1 + .../fabric/test/item/CustomDamageTest.java | 5 +- .../test/item/FabricItemSettingsTests.java | 2 +- .../fabric/test/item/FoodGameInitializer.java | 5 +- .../v1/ClientConfigurationNetworking.java | 296 ++++------------ .../networking/v1/ClientLoginNetworking.java | 7 +- .../networking/v1/ClientPlayNetworking.java | 333 +++++------------- .../ClientConfigurationNetworkAddon.java | 45 ++- .../client/ClientLoginNetworkAddon.java | 22 +- .../client/ClientNetworkingImpl.java | 51 +-- .../client/ClientPlayNetworkAddon.java | 42 ++- .../ClientCommonNetworkHandlerMixin.java | 30 +- ...lientConfigurationNetworkHandlerMixin.java | 2 +- .../api/networking/v1/FabricPacket.java | 78 ---- .../api/networking/v1/FutureListeners.java | 96 ----- .../api/networking/v1/LoginPacketSender.java | 70 ++++ .../api/networking/v1/PacketSender.java | 127 +------ .../fabric/api/networking/v1/PacketType.java | 71 ---- .../networking/v1/PayloadTypeRegistry.java | 73 ++++ .../v1/ServerConfigurationNetworking.java | 288 ++++----------- .../v1/ServerLoginConnectionEvents.java | 4 +- .../networking/v1/ServerPlayNetworking.java | 325 ++++------------- .../api/networking/v1/package-info.java | 2 +- .../AbstractChanneledNetworkAddon.java | 127 +++---- .../impl/networking/AbstractNetworkAddon.java | 2 + .../impl/networking/ChannelInfoHolder.java | 4 +- .../impl/networking/CommonPacketsImpl.java | 39 +- .../networking/CommonRegisterPayload.java | 11 +- .../impl/networking/CommonVersionPayload.java | 12 +- .../networking/CustomPayloadTypeProvider.java | 18 +- ...va => FabricCustomPayloadPacketCodec.java} | 7 +- .../GenericFutureListenerHolder.java | 63 ---- .../networking/GlobalReceiverRegistry.java | 42 ++- .../impl/networking/NetworkingImpl.java | 28 +- .../networking/PayloadTypeRegistryImpl.java | 83 +++++ .../impl/networking/RegistrationPayload.java | 94 +++++ .../networking/payload/PayloadHelper.java | 13 - .../networking/payload/ResolvablePayload.java | 40 --- .../networking/payload/RetainedPayload.java | 54 --- .../impl/networking/payload/TypedPayload.java | 49 --- .../networking/payload/UntypedPayload.java | 54 --- .../ServerConfigurationNetworkAddon.java | 43 +-- .../server/ServerLoginNetworkAddon.java | 33 +- .../server/ServerNetworkingImpl.java | 34 +- .../server/ServerPlayNetworkAddon.java | 41 +-- .../networking/ClientConnectionMixin.java | 20 +- .../CustomPayloadC2SPacketMixin.java | 43 ++- .../CustomPayloadPacketCodecMixin.java | 63 ++++ .../CustomPayloadS2CPacketMixin.java | 52 ++- ...etworkStateInternalPacketHandlerMixin.java | 64 ---- .../PacketCodecDispatcherMixin.java | 50 +++ .../ServerCommonNetworkHandlerMixin.java | 30 +- .../fabric-networking-api-v1.accesswidener | 1 - .../fabric-networking-api-v1.mixins.json | 3 +- .../src/main/resources/fabric.mod.json | 3 +- .../networking/unit/CommonPacketTests.java | 125 ++++--- .../unit/PayloadTypeRegistryTests.java | 154 ++++++++ .../channeltest/NetworkingChannelTest.java | 23 +- .../NetworkingConfigurationTest.java | 41 +-- .../keybindreciever/KeybindPayload.java | 36 ++ .../NetworkingKeybindPacketTest.java | 17 +- .../login/NetworkingLoginQueryTest.java | 3 +- .../play/NetworkingPlayPacketTest.java | 86 +++-- .../NetworkingConfigurationClientTest.java | 4 +- .../NetworkingKeybindClientPacketTest.java | 6 +- .../play/NetworkingPlayPacketClientTest.java | 32 +- .../builder/v1/block/FabricBlockSettings.java | 75 +++- .../builder/BlockEntityTypeBuilderTest.java | 2 +- .../test/object/builder/TealSignTest.java | 10 +- .../api/particle/v1/FabricParticleTypes.java | 65 +++- .../client/CustomIngredientSyncClient.java | 6 +- .../CustomIngredientSerializer.java | 14 +- .../ingredient/CustomIngredientImpl.java | 29 +- .../CustomIngredientPacketCodec.java | 85 +++++ .../CustomIngredientPayloadC2S.java | 40 +++ .../CustomIngredientPayloadS2C.java | 35 ++ .../ingredient/CustomIngredientSync.java | 49 ++- .../SupportedIngredientsPacketEncoder.java | 4 +- .../builtin/CombinedIngredient.java | 31 +- .../builtin/DifferenceIngredient.java | 20 +- .../ingredient/builtin/NbtIngredient.java | 47 ++- ...derMixin.java => EncoderHandlerMixin.java} | 10 +- .../recipe/ingredient/IngredientMixin.java | 35 +- .../fabric-recipe-api-v1.mixins.json | 2 +- .../sync/FabricRegistryClientInit.java | 17 +- .../sync/client/MinecraftClientMixin.java | 4 +- .../registry/sync/FabricRegistryInit.java | 12 +- .../registry/sync/RegistrySyncManager.java | 9 +- .../registry/sync/SyncCompletePayload.java | 20 +- .../packet/DirectRegistryPacketHandler.java | 52 ++- .../sync/packet/RegistryPacketHandler.java | 18 +- .../fabric/test/renderer/FrameBlock.java | 16 +- .../fabric/test/renderer/Registration.java | 14 +- .../fabric/test/screen/SoundButton.java | 2 +- fabric-screen-handler-api-v1/build.gradle | 3 +- .../screenhandler/v1/ScreenRegistry.java | 86 ----- .../client/ClientNetworking.java | 66 ++-- .../v1/ExtendedScreenHandlerFactory.java | 7 +- .../v1/ExtendedScreenHandlerType.java | 51 ++- .../v1/ScreenHandlerRegistry.java | 145 -------- .../fabric/impl/screenhandler/Networking.java | 60 +++- .../ServerPlayerEntityMixin.java | 8 +- .../src/main/resources/fabric.mod.json | 1 + .../test/screenhandler/ScreenHandlerTest.java | 5 +- .../test/screenhandler/block/BoxBlock.java | 2 +- .../screenhandler/block/BoxBlockEntity.java | 7 +- .../screenhandler/item/PositionedBagItem.java | 12 +- .../screen/BoxScreenHandler.java | 5 +- .../screen/PositionedBagScreenHandler.java | 20 +- .../test/transfer/ingame/FluidChuteBlock.java | 8 +- .../test/access/SignBlockEntityTest.java | 6 +- gradle.properties | 107 +++--- settings.gradle | 1 - 143 files changed, 2272 insertions(+), 3480 deletions(-) delete mode 100644 deprecated/fabric-containers-v0/build.gradle delete mode 100644 deprecated/fabric-containers-v0/src/client/java/net/fabricmc/fabric/api/client/screen/ContainerScreenFactory.java delete mode 100644 deprecated/fabric-containers-v0/src/client/java/net/fabricmc/fabric/api/client/screen/ScreenProviderRegistry.java delete mode 100644 deprecated/fabric-containers-v0/src/client/java/net/fabricmc/fabric/impl/client/container/ScreenProviderRegistryImpl.java delete mode 100644 deprecated/fabric-containers-v0/src/main/java/net/fabricmc/fabric/api/container/ContainerFactory.java delete mode 100644 deprecated/fabric-containers-v0/src/main/java/net/fabricmc/fabric/api/container/ContainerProviderRegistry.java delete mode 100644 deprecated/fabric-containers-v0/src/main/java/net/fabricmc/fabric/impl/container/ContainerProviderImpl.java delete mode 100644 deprecated/fabric-containers-v0/src/main/java/net/fabricmc/fabric/mixin/container/ServerPlayerEntityAccessor.java delete mode 100644 deprecated/fabric-containers-v0/src/main/java/net/fabricmc/fabric/mixin/container/ServerPlayerEntityMixin.java delete mode 100644 deprecated/fabric-containers-v0/src/main/resources/assets/fabric-containers-v0/icon.png delete mode 100644 deprecated/fabric-containers-v0/src/main/resources/fabric-containers-v0.accurate.mixins.json delete mode 100644 deprecated/fabric-containers-v0/src/main/resources/fabric-containers-v0.mixins.json delete mode 100644 deprecated/fabric-containers-v0/src/main/resources/fabric.mod.json rename fabric-screen-handler-api-v1/src/client/java/net/fabricmc/fabric/api/client/screenhandler/v1/package-info.java => fabric-item-api-v1/src/main/java/net/fabricmc/fabric/mixin/item/ItemSettingsMixin.java (70%) delete mode 100644 fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/api/networking/v1/FabricPacket.java delete mode 100644 fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/api/networking/v1/FutureListeners.java create mode 100644 fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/api/networking/v1/LoginPacketSender.java delete mode 100644 fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/api/networking/v1/PacketType.java create mode 100644 fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/api/networking/v1/PayloadTypeRegistry.java rename deprecated/fabric-containers-v0/src/main/java/net/fabricmc/fabric/impl/container/ServerPlayerEntitySyncHook.java => fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/CustomPayloadTypeProvider.java (63%) rename fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/{payload/ResolvedPayload.java => FabricCustomPayloadPacketCodec.java} (70%) delete mode 100644 fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/GenericFutureListenerHolder.java create mode 100644 fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/PayloadTypeRegistryImpl.java create mode 100644 fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/RegistrationPayload.java delete mode 100644 fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/payload/ResolvablePayload.java delete mode 100644 fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/payload/RetainedPayload.java delete mode 100644 fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/payload/TypedPayload.java delete mode 100644 fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/payload/UntypedPayload.java create mode 100644 fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/mixin/networking/CustomPayloadPacketCodecMixin.java delete mode 100644 fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/mixin/networking/NetworkStateInternalPacketHandlerMixin.java create mode 100644 fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/mixin/networking/PacketCodecDispatcherMixin.java create mode 100644 fabric-networking-api-v1/src/test/java/net/fabricmc/fabric/test/networking/unit/PayloadTypeRegistryTests.java create mode 100644 fabric-networking-api-v1/src/testmod/java/net/fabricmc/fabric/test/networking/keybindreciever/KeybindPayload.java create mode 100644 fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/impl/recipe/ingredient/CustomIngredientPacketCodec.java create mode 100644 fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/impl/recipe/ingredient/CustomIngredientPayloadC2S.java create mode 100644 fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/impl/recipe/ingredient/CustomIngredientPayloadS2C.java rename fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/mixin/recipe/ingredient/{PacketEncoderMixin.java => EncoderHandlerMixin.java} (87%) rename fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/payload/FabricPacketLoginQueryRequestPayload.java => fabric-registry-sync-v0/src/main/java/net/fabricmc/fabric/impl/registry/sync/SyncCompletePayload.java (53%) delete mode 100644 fabric-screen-handler-api-v1/src/client/java/net/fabricmc/fabric/api/client/screenhandler/v1/ScreenRegistry.java delete mode 100644 fabric-screen-handler-api-v1/src/main/java/net/fabricmc/fabric/api/screenhandler/v1/ScreenHandlerRegistry.java diff --git a/deprecated/fabric-containers-v0/build.gradle b/deprecated/fabric-containers-v0/build.gradle deleted file mode 100644 index 70b5d0059..000000000 --- a/deprecated/fabric-containers-v0/build.gradle +++ /dev/null @@ -1,6 +0,0 @@ -version = getSubprojectVersion(project) - -moduleDependencies(project, [ - 'fabric-api-base', - 'fabric-networking-api-v1' -]) diff --git a/deprecated/fabric-containers-v0/src/client/java/net/fabricmc/fabric/api/client/screen/ContainerScreenFactory.java b/deprecated/fabric-containers-v0/src/client/java/net/fabricmc/fabric/api/client/screen/ContainerScreenFactory.java deleted file mode 100644 index 163c5a23d..000000000 --- a/deprecated/fabric-containers-v0/src/client/java/net/fabricmc/fabric/api/client/screen/ContainerScreenFactory.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * 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.screen; - -import net.minecraft.client.gui.screen.ingame.HandledScreen; -import net.minecraft.screen.ScreenHandler; - -/** - * @deprecated Use {@link net.fabricmc.fabric.api.client.screenhandler.v1.ScreenRegistry.Factory} instead. - */ -@Deprecated -@FunctionalInterface -public interface ContainerScreenFactory { - HandledScreen create(C container); -} diff --git a/deprecated/fabric-containers-v0/src/client/java/net/fabricmc/fabric/api/client/screen/ScreenProviderRegistry.java b/deprecated/fabric-containers-v0/src/client/java/net/fabricmc/fabric/api/client/screen/ScreenProviderRegistry.java deleted file mode 100644 index 03cb858bc..000000000 --- a/deprecated/fabric-containers-v0/src/client/java/net/fabricmc/fabric/api/client/screen/ScreenProviderRegistry.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * 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.screen; - -import net.minecraft.client.gui.screen.ingame.HandledScreen; -import net.minecraft.screen.ScreenHandler; -import net.minecraft.util.Identifier; - -import net.fabricmc.fabric.api.container.ContainerFactory; -import net.fabricmc.fabric.api.container.ContainerProviderRegistry; -import net.fabricmc.fabric.impl.client.container.ScreenProviderRegistryImpl; - -/** - * @deprecated Use {@link net.fabricmc.fabric.api.client.screenhandler.v1.ScreenRegistry} instead. - */ -@Deprecated -public interface ScreenProviderRegistry { - ScreenProviderRegistry INSTANCE = new ScreenProviderRegistryImpl(); - - /** - * Register a "Container -> ContainerScreen" factory. This is used only on the client side. - * - * @param identifier a shared identifier, this identifier should also be used to register a container using {@link ContainerProviderRegistry} - * @param containerScreenFactory the supplier that should be used to create the new gui - */ - void registerFactory(Identifier identifier, ContainerScreenFactory containerScreenFactory); - - /** - * Register a "packet -> ContainerScreen" factory. This is used only on the client side, and allows you - * to override the default behaviour of re-using the existing "packet -> Container" logic. - * - * @param identifier a shared identifier, this identifier should also be used to register a container using {@link ContainerProviderRegistry} - * @param factory the gui factory, this should return a new {@link HandledScreen} - */ - void registerFactory(Identifier identifier, ContainerFactory factory); -} diff --git a/deprecated/fabric-containers-v0/src/client/java/net/fabricmc/fabric/impl/client/container/ScreenProviderRegistryImpl.java b/deprecated/fabric-containers-v0/src/client/java/net/fabricmc/fabric/impl/client/container/ScreenProviderRegistryImpl.java deleted file mode 100644 index 208fd7abd..000000000 --- a/deprecated/fabric-containers-v0/src/client/java/net/fabricmc/fabric/impl/client/container/ScreenProviderRegistryImpl.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * 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.client.container; - -import java.util.HashMap; -import java.util.Map; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import net.minecraft.client.gui.screen.ingame.HandledScreen; -import net.minecraft.client.network.ClientPlayerEntity; -import net.minecraft.screen.ScreenHandler; -import net.minecraft.util.Identifier; - -import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; -import net.fabricmc.fabric.api.client.screen.ContainerScreenFactory; -import net.fabricmc.fabric.api.client.screen.ScreenProviderRegistry; -import net.fabricmc.fabric.api.container.ContainerFactory; -import net.fabricmc.fabric.api.container.ContainerProviderRegistry; -import net.fabricmc.fabric.impl.container.ContainerProviderImpl; - -public class ScreenProviderRegistryImpl implements ScreenProviderRegistry { - private static final Logger LOGGER = LoggerFactory.getLogger(ScreenProviderRegistryImpl.class); - - private static final Map> FACTORIES = new HashMap<>(); - - @Override - public void registerFactory(Identifier identifier, ContainerFactory factory) { - if (FACTORIES.containsKey(identifier)) { - throw new RuntimeException("A factory has already been registered as " + identifier + "!"); - } - - FACTORIES.put(identifier, factory); - } - - @Override - public void registerFactory(Identifier identifier, ContainerScreenFactory containerScreenFactory) { - registerFactory(identifier, (syncId, identifier1, player, buf) -> { - C container = ((ContainerProviderImpl) ContainerProviderRegistry.INSTANCE).createContainer(syncId, identifier1, player, buf); - - if (container == null) { - LOGGER.error("Could not open container for {} - a null object was created!", identifier1.toString()); - return null; - } - - return containerScreenFactory.create(container); - }); - } - - public static void init() { - ClientPlayNetworking.registerGlobalReceiver(ContainerProviderImpl.OPEN_CONTAINER, (client, handler, buf, responseSender) -> { - Identifier identifier = buf.readIdentifier(); - int syncId = buf.readUnsignedByte(); - - // Retain the buf since we must open the screen handler with it's extra modded data on the client thread - buf.retain(); - - client.execute(() -> { - try { - ContainerFactory factory = FACTORIES.get(identifier); - - if (factory == null) { - LOGGER.error("No GUI factory found for {}!", identifier.toString()); - return; - } - - ClientPlayerEntity player = client.player; - HandledScreen gui = factory.create(syncId, identifier, player, buf); - - player.currentScreenHandler = gui.getScreenHandler(); - client.setScreen(gui); - } finally { - buf.release(); - } - }); - }); - } -} diff --git a/deprecated/fabric-containers-v0/src/main/java/net/fabricmc/fabric/api/container/ContainerFactory.java b/deprecated/fabric-containers-v0/src/main/java/net/fabricmc/fabric/api/container/ContainerFactory.java deleted file mode 100644 index ec1096ed7..000000000 --- a/deprecated/fabric-containers-v0/src/main/java/net/fabricmc/fabric/api/container/ContainerFactory.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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.container; - -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.network.PacketByteBuf; -import net.minecraft.util.Identifier; - -/** - * @deprecated Use {@link net.fabricmc.fabric.api.screenhandler.v1.ScreenHandlerRegistry.ExtendedClientHandlerFactory} instead. - */ -@Deprecated -@FunctionalInterface -public interface ContainerFactory { - /** - * Creates the new object. - * - * @param syncId The container synchronization ID. - * @param identifier the Identifier is the name that was used when registering the factory - * @param player the player that is opening the gui/container - * @param buf the buffer contains the same data that was provided with {@link net.fabricmc.fabric.api.container.ContainerProviderRegistry#openContainer} - * @return the new gui or container - */ - T create(int syncId, Identifier identifier, PlayerEntity player, PacketByteBuf buf); -} diff --git a/deprecated/fabric-containers-v0/src/main/java/net/fabricmc/fabric/api/container/ContainerProviderRegistry.java b/deprecated/fabric-containers-v0/src/main/java/net/fabricmc/fabric/api/container/ContainerProviderRegistry.java deleted file mode 100644 index 3397f765e..000000000 --- a/deprecated/fabric-containers-v0/src/main/java/net/fabricmc/fabric/api/container/ContainerProviderRegistry.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * 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.container; - -import java.util.function.Consumer; - -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.network.PacketByteBuf; -import net.minecraft.screen.ScreenHandler; -import net.minecraft.server.network.ServerPlayerEntity; -import net.minecraft.util.Identifier; - -import net.fabricmc.fabric.impl.container.ContainerProviderImpl; - -/** - * @deprecated Use {@link net.fabricmc.fabric.api.screenhandler.v1.ScreenHandlerRegistry} instead. - */ -@Deprecated -public interface ContainerProviderRegistry { - ContainerProviderRegistry INSTANCE = new ContainerProviderImpl(); - - /** - * Register a "packet buffer -> container" factory. This is used both on the client and server side. - * - * @param identifier a shared identifier, this identifier should also be used to register a container using {@link net.fabricmc.fabric.api.client.screen.ScreenProviderRegistry} - * @param factory the ContainerFactory that should return a new {@link ScreenHandler} - */ - void registerFactory(Identifier identifier, ContainerFactory factory); - - /** - * Open a modded container. - * - * @param identifier the identifier that was used when registering the container - * @param player the player that should open the container - * @param writer a PacketByteBuf where data can be written to, this data is then accessible by the container factory when creating the container or the gui - */ - void openContainer(Identifier identifier, ServerPlayerEntity player, Consumer writer); - - /** - * Open a modded container. This should be called on the server side - it has no effect on the client side. - * - * @param identifier the identifier that was used when registering the container - * @param player the player that should open the container - * @param writer a PacketByteBuf where data can be written to, this data is then accessible by the container factory when creating the container or the gui - */ - void openContainer(Identifier identifier, PlayerEntity player, Consumer writer); -} diff --git a/deprecated/fabric-containers-v0/src/main/java/net/fabricmc/fabric/impl/container/ContainerProviderImpl.java b/deprecated/fabric-containers-v0/src/main/java/net/fabricmc/fabric/impl/container/ContainerProviderImpl.java deleted file mode 100644 index 6be92112e..000000000 --- a/deprecated/fabric-containers-v0/src/main/java/net/fabricmc/fabric/impl/container/ContainerProviderImpl.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * 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.container; - -import java.util.HashMap; -import java.util.Map; -import java.util.function.Consumer; - -import io.netty.buffer.Unpooled; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.network.PacketByteBuf; -import net.minecraft.screen.ScreenHandler; -import net.minecraft.server.network.ServerPlayerEntity; -import net.minecraft.util.Identifier; - -import net.fabricmc.fabric.api.container.ContainerFactory; -import net.fabricmc.fabric.api.container.ContainerProviderRegistry; -import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; -import net.fabricmc.fabric.mixin.container.ServerPlayerEntityAccessor; - -public class ContainerProviderImpl implements ContainerProviderRegistry { - public static final Identifier OPEN_CONTAINER = new Identifier("fabric", "container/open"); - - private static final Logger LOGGER = LoggerFactory.getLogger(ContainerProviderImpl.class); - - private static final Map> FACTORIES = new HashMap<>(); - - @Override - public void registerFactory(Identifier identifier, ContainerFactory factory) { - if (FACTORIES.containsKey(identifier)) { - throw new RuntimeException("A factory has already been registered as " + identifier.toString()); - } - - FACTORIES.put(identifier, factory); - } - - @Override - public void openContainer(Identifier identifier, PlayerEntity player, Consumer writer) { - if (!(player instanceof ServerPlayerEntity)) { - LOGGER.warn("Please only use ContainerProviderRegistry.openContainer() with server-sided player entities!"); - return; - } - - openContainer(identifier, (ServerPlayerEntity) player, writer); - } - - private boolean emittedNoSyncHookWarning = false; - - @Override - public void openContainer(Identifier identifier, ServerPlayerEntity player, Consumer writer) { - int syncId; - - if (player instanceof ServerPlayerEntitySyncHook) { - ServerPlayerEntitySyncHook serverPlayerEntitySyncHook = (ServerPlayerEntitySyncHook) player; - syncId = serverPlayerEntitySyncHook.fabric_incrementSyncId(); - } else if (player instanceof ServerPlayerEntityAccessor) { - if (!emittedNoSyncHookWarning) { - LOGGER.warn("ServerPlayerEntitySyncHook could not be applied - fabric-containers is using a hack!"); - emittedNoSyncHookWarning = true; - } - - syncId = (((ServerPlayerEntityAccessor) player).getScreenHandlerSyncId() + 1) % 100; - ((ServerPlayerEntityAccessor) player).setScreenHandlerSyncId(syncId); - } else { - throw new RuntimeException("Neither ServerPlayerEntitySyncHook nor Accessor present! This should not happen!"); - } - - PacketByteBuf buf = new PacketByteBuf(Unpooled.buffer()); - buf.writeIdentifier(identifier); - buf.writeByte(syncId); - - writer.accept(buf); - player.networkHandler.sendPacket(ServerPlayNetworking.createS2CPacket(OPEN_CONTAINER, buf)); - - PacketByteBuf clonedBuf = new PacketByteBuf(buf.duplicate()); - clonedBuf.readIdentifier(); - clonedBuf.readUnsignedByte(); - - ScreenHandler screenHandler = createContainer(syncId, identifier, player, clonedBuf); - - if (screenHandler == null) { - return; - } - - player.currentScreenHandler = screenHandler; - ((ServerPlayerEntityAccessor) player).callOnScreenHandlerOpened(screenHandler); - } - - public C createContainer(int syncId, Identifier identifier, PlayerEntity player, PacketByteBuf buf) { - ContainerFactory factory = FACTORIES.get(identifier); - - if (factory == null) { - LOGGER.error("No container factory found for {}!", identifier.toString()); - return null; - } - - //noinspection unchecked - return (C) factory.create(syncId, identifier, player, buf); - } -} diff --git a/deprecated/fabric-containers-v0/src/main/java/net/fabricmc/fabric/mixin/container/ServerPlayerEntityAccessor.java b/deprecated/fabric-containers-v0/src/main/java/net/fabricmc/fabric/mixin/container/ServerPlayerEntityAccessor.java deleted file mode 100644 index b2ee3b0d2..000000000 --- a/deprecated/fabric-containers-v0/src/main/java/net/fabricmc/fabric/mixin/container/ServerPlayerEntityAccessor.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * 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.container; - -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.gen.Accessor; -import org.spongepowered.asm.mixin.gen.Invoker; - -import net.minecraft.screen.ScreenHandler; -import net.minecraft.server.network.ServerPlayerEntity; - -@Mixin(ServerPlayerEntity.class) -public interface ServerPlayerEntityAccessor { - @Accessor - int getScreenHandlerSyncId(); - @Accessor - void setScreenHandlerSyncId(int syncId); - - @Invoker() - void callOnScreenHandlerOpened(ScreenHandler screenHandler); -} diff --git a/deprecated/fabric-containers-v0/src/main/java/net/fabricmc/fabric/mixin/container/ServerPlayerEntityMixin.java b/deprecated/fabric-containers-v0/src/main/java/net/fabricmc/fabric/mixin/container/ServerPlayerEntityMixin.java deleted file mode 100644 index 2295a1d39..000000000 --- a/deprecated/fabric-containers-v0/src/main/java/net/fabricmc/fabric/mixin/container/ServerPlayerEntityMixin.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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.container; - -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; - -import net.minecraft.server.network.ServerPlayerEntity; - -import net.fabricmc.fabric.impl.container.ServerPlayerEntitySyncHook; - -@Mixin(ServerPlayerEntity.class) -public abstract class ServerPlayerEntityMixin implements ServerPlayerEntitySyncHook { - @Shadow - private int screenHandlerSyncId; - - @Shadow - protected abstract void incrementScreenHandlerSyncId(); - - @Override - public int fabric_incrementSyncId() { - incrementScreenHandlerSyncId(); - return screenHandlerSyncId; - } -} diff --git a/deprecated/fabric-containers-v0/src/main/resources/assets/fabric-containers-v0/icon.png b/deprecated/fabric-containers-v0/src/main/resources/assets/fabric-containers-v0/icon.png deleted file mode 100644 index 2931efbf610873c0084debb8690902b0103d27fe..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 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@ diff --git a/deprecated/fabric-containers-v0/src/main/resources/fabric-containers-v0.accurate.mixins.json b/deprecated/fabric-containers-v0/src/main/resources/fabric-containers-v0.accurate.mixins.json deleted file mode 100644 index 3a6099a21..000000000 --- a/deprecated/fabric-containers-v0/src/main/resources/fabric-containers-v0.accurate.mixins.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "required": false, - "package": "net.fabricmc.fabric.mixin.container", - "compatibilityLevel": "JAVA_17", - "mixins": [ - "ServerPlayerEntityMixin" - ], - "injectors": { - "defaultRequire": 1 - } -} diff --git a/deprecated/fabric-containers-v0/src/main/resources/fabric-containers-v0.mixins.json b/deprecated/fabric-containers-v0/src/main/resources/fabric-containers-v0.mixins.json deleted file mode 100644 index 5786e355b..000000000 --- a/deprecated/fabric-containers-v0/src/main/resources/fabric-containers-v0.mixins.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "required": false, - "package": "net.fabricmc.fabric.mixin.container", - "compatibilityLevel": "JAVA_17", - "mixins": [ - "ServerPlayerEntityAccessor" - ], - "injectors": { - "defaultRequire": 1 - } -} diff --git a/deprecated/fabric-containers-v0/src/main/resources/fabric.mod.json b/deprecated/fabric-containers-v0/src/main/resources/fabric.mod.json deleted file mode 100644 index bca7c4efc..000000000 --- a/deprecated/fabric-containers-v0/src/main/resources/fabric.mod.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "schemaVersion": 1, - "id": "fabric-containers-v0", - "name": "Fabric Containers (v0)", - "version": "${version}", - "environment": "*", - "license": "Apache-2.0", - "icon": "assets/fabric-containers-v0/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" - ], - "depends": { - "fabricloader": ">=0.15.6", - "fabric-api-base": "*", - "fabric-networking-api-v1": "*" - }, - "description": "Adds hooks for containers.", - "mixins": [ - "fabric-containers-v0.mixins.json", - "fabric-containers-v0.accurate.mixins.json" - ], - "entrypoints": { - "client": [ - "net.fabricmc.fabric.impl.client.container.ScreenProviderRegistryImpl::init" - ] - }, - "custom": { - "fabric-api:module-lifecycle": "deprecated" - } -} diff --git a/fabric-api-lookup-api-v1/src/testmod/java/net/fabricmc/fabric/test/lookup/FabricApiLookupTest.java b/fabric-api-lookup-api-v1/src/testmod/java/net/fabricmc/fabric/test/lookup/FabricApiLookupTest.java index 116e5a5e3..ae9572b6e 100644 --- a/fabric-api-lookup-api-v1/src/testmod/java/net/fabricmc/fabric/test/lookup/FabricApiLookupTest.java +++ b/fabric-api-lookup-api-v1/src/testmod/java/net/fabricmc/fabric/test/lookup/FabricApiLookupTest.java @@ -18,6 +18,7 @@ package net.fabricmc.fabric.test.lookup; import org.jetbrains.annotations.NotNull; +import net.minecraft.block.AbstractBlock; import net.minecraft.block.entity.BlockEntityType; import net.minecraft.item.BlockItem; import net.minecraft.item.Item; @@ -28,7 +29,6 @@ import net.minecraft.util.math.Direction; import net.fabricmc.api.ModInitializer; import net.fabricmc.fabric.api.lookup.v1.block.BlockApiLookup; -import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings; import net.fabricmc.fabric.api.object.builder.v1.block.entity.FabricBlockEntityTypeBuilder; import net.fabricmc.fabric.test.lookup.api.ItemApis; import net.fabricmc.fabric.test.lookup.api.ItemInsertable; @@ -41,17 +41,17 @@ public class FabricApiLookupTest implements ModInitializer { public static final String MOD_ID = "fabric-lookup-api-v1-testmod"; // Chute - Block without model that transfers item from the container above to the container below. // It's meant to work with unsided containers: chests, dispensers, droppers and hoppers. - public static final ChuteBlock CHUTE_BLOCK = new ChuteBlock(FabricBlockSettings.create()); + public static final ChuteBlock CHUTE_BLOCK = new ChuteBlock(AbstractBlock.Settings.create()); public static final BlockItem CHUTE_ITEM = new BlockItem(CHUTE_BLOCK, new Item.Settings()); public static BlockEntityType CHUTE_BLOCK_ENTITY_TYPE; // Cobble gen - Block without model that can generate infinite cobblestone when placed above a chute. // It's meant to test BlockApiLookup#registerSelf. - public static final CobbleGenBlock COBBLE_GEN_BLOCK = new CobbleGenBlock(FabricBlockSettings.create()); + public static final CobbleGenBlock COBBLE_GEN_BLOCK = new CobbleGenBlock(AbstractBlock.Settings.create()); public static final BlockItem COBBLE_GEN_ITEM = new BlockItem(COBBLE_GEN_BLOCK, new Item.Settings()); public static BlockEntityType COBBLE_GEN_BLOCK_ENTITY_TYPE; // Testing for item api lookups is done in the `item` package. - public static final InspectorBlock INSPECTOR_BLOCK = new InspectorBlock(FabricBlockSettings.create()); + public static final InspectorBlock INSPECTOR_BLOCK = new InspectorBlock(AbstractBlock.Settings.create()); public static final BlockItem INSPECTOR_ITEM = new BlockItem(INSPECTOR_BLOCK, new Item.Settings()); @Override diff --git a/fabric-api-lookup-api-v1/src/testmod/java/net/fabricmc/fabric/test/lookup/InspectorBlock.java b/fabric-api-lookup-api-v1/src/testmod/java/net/fabricmc/fabric/test/lookup/InspectorBlock.java index 88aac01fb..e2c4a5af9 100644 --- a/fabric-api-lookup-api-v1/src/testmod/java/net/fabricmc/fabric/test/lookup/InspectorBlock.java +++ b/fabric-api-lookup-api-v1/src/testmod/java/net/fabricmc/fabric/test/lookup/InspectorBlock.java @@ -18,12 +18,12 @@ package net.fabricmc.fabric.test.lookup; import net.minecraft.block.Block; import net.minecraft.block.BlockState; -import net.minecraft.class_9062; import net.minecraft.entity.Entity; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.ItemStack; import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.util.Hand; +import net.minecraft.util.ItemActionResult; import net.minecraft.util.hit.BlockHitResult; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; @@ -38,7 +38,7 @@ public class InspectorBlock extends Block { } @Override - public class_9062 method_55765(ItemStack stack, BlockState blockState, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult blockHitResult) { + public ItemActionResult onUseWithItem(ItemStack stack, BlockState blockState, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult blockHitResult) { Inspectable inspectable = FabricItemApiLookupTest.INSPECTABLE.find(stack, null); if (inspectable != null) { @@ -46,10 +46,10 @@ public class InspectorBlock extends Block { player.sendMessage(inspectable.inspect(), true); } - return class_9062.method_55644(world.isClient()); + return ItemActionResult.success(world.isClient()); } - return class_9062.PASS_TO_DEFAULT_BLOCK_INTERACTION; + return ItemActionResult.PASS_TO_DEFAULT_BLOCK_INTERACTION; } @Override diff --git a/fabric-content-registries-v0/src/main/java/net/fabricmc/fabric/impl/content/registry/FuelRegistryImpl.java b/fabric-content-registries-v0/src/main/java/net/fabricmc/fabric/impl/content/registry/FuelRegistryImpl.java index c63061171..468f3d29d 100644 --- a/fabric-content-registries-v0/src/main/java/net/fabricmc/fabric/impl/content/registry/FuelRegistryImpl.java +++ b/fabric-content-registries-v0/src/main/java/net/fabricmc/fabric/impl/content/registry/FuelRegistryImpl.java @@ -16,7 +16,6 @@ package net.fabricmc.fabric.impl.content.registry; -import java.util.IdentityHashMap; import java.util.Map; import it.unimi.dsi.fastutil.objects.Object2IntLinkedOpenHashMap; @@ -31,7 +30,6 @@ import net.minecraft.registry.Registries; import net.minecraft.registry.entry.RegistryEntry; import net.minecraft.registry.tag.TagKey; -import net.fabricmc.fabric.api.event.lifecycle.v1.CommonLifecycleEvents; import net.fabricmc.fabric.api.registry.FuelRegistry; // TODO: Clamp values to 32767 (+ add hook for mods which extend the limit to disable the check?) @@ -39,23 +37,13 @@ public final class FuelRegistryImpl implements FuelRegistry { private static final Logger LOGGER = LoggerFactory.getLogger(FuelRegistryImpl.class); private final Object2IntMap itemCookTimes = new Object2IntLinkedOpenHashMap<>(); private final Object2IntMap> tagCookTimes = new Object2IntLinkedOpenHashMap<>(); - private volatile Map fuelTimeCache = null; // thread safe via copy-on-write mechanism public FuelRegistryImpl() { - // Reset cache after tags change since it depends on tags. - CommonLifecycleEvents.TAGS_LOADED.register((registries, client) -> { - resetCache(); - }); } public Map getFuelTimes() { - Map ret = fuelTimeCache; - - if (ret == null) { - fuelTimeCache = ret = new IdentityHashMap<>(AbstractFurnaceBlockEntity.createFuelTimeMap()); // IdentityHashMap is faster than vanilla's LinkedHashMap and suitable for Item keys - } - - return ret; + // Cached by vanilla now + return AbstractFurnaceBlockEntity.createFuelTimeMap(); } @Override @@ -138,6 +126,7 @@ public final class FuelRegistryImpl implements FuelRegistry { } public void resetCache() { - fuelTimeCache = null; + // Note: tag reload is already handled by vanilla, see DataPackContents#refresh + AbstractFurnaceBlockEntity.clearFuelTimes(); } } diff --git a/fabric-content-registries-v0/src/testmod/java/net/fabricmc/fabric/test/content/registry/ContentRegistryTest.java b/fabric-content-registries-v0/src/testmod/java/net/fabricmc/fabric/test/content/registry/ContentRegistryTest.java index b8a819301..8833025d3 100644 --- a/fabric-content-registries-v0/src/testmod/java/net/fabricmc/fabric/test/content/registry/ContentRegistryTest.java +++ b/fabric-content-registries-v0/src/testmod/java/net/fabricmc/fabric/test/content/registry/ContentRegistryTest.java @@ -168,7 +168,7 @@ public final class ContentRegistryTest implements ModInitializer { } @Override - public ActionResult method_55766(BlockState state, World world, BlockPos pos, PlayerEntity player, BlockHitResult hit) { + public ActionResult onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, BlockHitResult hit) { // Emit the test event world.emitGameEvent(player, TEST_EVENT, pos); return ActionResult.SUCCESS; diff --git a/fabric-data-attachment-api-v1/src/main/resources/fabric.mod.json b/fabric-data-attachment-api-v1/src/main/resources/fabric.mod.json index 879ae341c..9b6ae5f58 100644 --- a/fabric-data-attachment-api-v1/src/main/resources/fabric.mod.json +++ b/fabric-data-attachment-api-v1/src/main/resources/fabric.mod.json @@ -16,7 +16,7 @@ "FabricMC" ], "depends": { - "fabricloader": ">=0.15.1", + "fabricloader": ">=0.15.6", "fabric-entity-events-v1": "*", "fabric-object-builder-api-v1": "*" }, diff --git a/fabric-entity-events-v1/src/main/java/net/fabricmc/fabric/api/entity/event/v1/FabricElytraItem.java b/fabric-entity-events-v1/src/main/java/net/fabricmc/fabric/api/entity/event/v1/FabricElytraItem.java index 25734825b..472dfa6cc 100644 --- a/fabric-entity-events-v1/src/main/java/net/fabricmc/fabric/api/entity/event/v1/FabricElytraItem.java +++ b/fabric-entity-events-v1/src/main/java/net/fabricmc/fabric/api/entity/event/v1/FabricElytraItem.java @@ -56,7 +56,7 @@ public interface FabricElytraItem { if (!entity.getWorld().isClient && nextRoll % 10 == 0) { if ((nextRoll / 10) % 2 == 0) { - chestStack.damage(1, entity, p -> p.sendEquipmentBreakStatus(EquipmentSlot.CHEST)); + chestStack.damage(1, entity, EquipmentSlot.CHEST); } entity.emitGameEvent(GameEvent.ELYTRA_GLIDE); diff --git a/fabric-entity-events-v1/src/main/java/net/fabricmc/fabric/mixin/entity/event/elytra/LivingEntityMixin.java b/fabric-entity-events-v1/src/main/java/net/fabricmc/fabric/mixin/entity/event/elytra/LivingEntityMixin.java index 02e201c27..27cc7137e 100644 --- a/fabric-entity-events-v1/src/main/java/net/fabricmc/fabric/mixin/entity/event/elytra/LivingEntityMixin.java +++ b/fabric-entity-events-v1/src/main/java/net/fabricmc/fabric/mixin/entity/event/elytra/LivingEntityMixin.java @@ -40,7 +40,7 @@ abstract class LivingEntityMixin extends Entity { * Handle ALLOW and CUSTOM {@link EntityElytraEvents} when an entity is fall flying. */ @SuppressWarnings("ConstantConditions") - @Inject(at = @At(value = "FIELD", target = "Lnet/minecraft/entity/EquipmentSlot;CHEST:Lnet/minecraft/entity/EquipmentSlot;"), method = "tickFallFlying()V", allow = 1, cancellable = true) + @Inject(at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/LivingEntity;getEquippedStack(Lnet/minecraft/entity/EquipmentSlot;)Lnet/minecraft/item/ItemStack;"), method = "tickFallFlying()V", allow = 1, cancellable = true) void injectElytraTick(CallbackInfo info) { LivingEntity self = (LivingEntity) (Object) this; diff --git a/fabric-entity-events-v1/src/testmod/java/net/fabricmc/fabric/test/entity/event/TestBedBlock.java b/fabric-entity-events-v1/src/testmod/java/net/fabricmc/fabric/test/entity/event/TestBedBlock.java index cbb8c6a00..22e591b46 100644 --- a/fabric-entity-events-v1/src/testmod/java/net/fabricmc/fabric/test/entity/event/TestBedBlock.java +++ b/fabric-entity-events-v1/src/testmod/java/net/fabricmc/fabric/test/entity/event/TestBedBlock.java @@ -46,7 +46,7 @@ public class TestBedBlock extends Block { } @Override - public ActionResult method_55766(BlockState state, World world, BlockPos pos, PlayerEntity player, BlockHitResult hit) { + public ActionResult onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, BlockHitResult hit) { if (state.get(OCCUPIED)) { player.sendMessage(Text.translatable("block.minecraft.bed.occupied"), true); return ActionResult.CONSUME; diff --git a/fabric-events-interaction-v0/src/main/java/net/fabricmc/fabric/impl/event/interaction/FakePlayerNetworkHandler.java b/fabric-events-interaction-v0/src/main/java/net/fabricmc/fabric/impl/event/interaction/FakePlayerNetworkHandler.java index dd4d087a2..08550b564 100644 --- a/fabric-events-interaction-v0/src/main/java/net/fabricmc/fabric/impl/event/interaction/FakePlayerNetworkHandler.java +++ b/fabric-events-interaction-v0/src/main/java/net/fabricmc/fabric/impl/event/interaction/FakePlayerNetworkHandler.java @@ -21,7 +21,6 @@ import org.jetbrains.annotations.Nullable; import net.minecraft.network.ClientConnection; import net.minecraft.network.NetworkSide; import net.minecraft.network.PacketCallbacks; -import net.minecraft.network.listener.PacketListener; import net.minecraft.network.packet.Packet; import net.minecraft.server.network.ConnectedClientData; import net.minecraft.server.network.ServerPlayNetworkHandler; @@ -31,7 +30,7 @@ public class FakePlayerNetworkHandler extends ServerPlayNetworkHandler { private static final ClientConnection FAKE_CONNECTION = new FakeClientConnection(); public FakePlayerNetworkHandler(ServerPlayerEntity player) { - super(player.getServer(), FAKE_CONNECTION, player, ConnectedClientData.createDefault(player.getGameProfile())); + super(player.getServer(), FAKE_CONNECTION, player, ConnectedClientData.createDefault(player.getGameProfile(), false)); } @Override @@ -41,9 +40,5 @@ public class FakePlayerNetworkHandler extends ServerPlayNetworkHandler { private FakeClientConnection() { super(NetworkSide.CLIENTBOUND); } - - @Override - public void setPacketListener(PacketListener packetListener) { - } } } diff --git a/fabric-gametest-api-v1/src/main/java/net/fabricmc/fabric/impl/gametest/FabricGameTestHelper.java b/fabric-gametest-api-v1/src/main/java/net/fabricmc/fabric/impl/gametest/FabricGameTestHelper.java index 8aeb1b02c..c610f6c8d 100644 --- a/fabric-gametest-api-v1/src/main/java/net/fabricmc/fabric/impl/gametest/FabricGameTestHelper.java +++ b/fabric-gametest-api-v1/src/main/java/net/fabricmc/fabric/impl/gametest/FabricGameTestHelper.java @@ -32,13 +32,11 @@ import net.minecraft.resource.ResourceFinder; import net.minecraft.resource.ResourcePackManager; import net.minecraft.server.MinecraftServer; import net.minecraft.server.command.TestCommand; -import net.minecraft.test.GameTestBatch; import net.minecraft.test.TestContext; import net.minecraft.test.TestFailureLogger; import net.minecraft.test.TestFunction; import net.minecraft.test.TestFunctions; import net.minecraft.test.TestServer; -import net.minecraft.test.TestUtil; import net.minecraft.util.math.BlockPos; import net.minecraft.world.level.storage.LevelStorage; @@ -80,7 +78,7 @@ public final class FabricGameTestHelper { LOGGER.info("Starting test server"); MinecraftServer server = TestServer.startServer(thread -> { - return TestServer.create(thread, session, resourcePackManager, getBatches(), BlockPos.ORIGIN); + return TestServer.create(thread, session, resourcePackManager, getTestFunctions(), BlockPos.ORIGIN); }); } @@ -128,10 +126,6 @@ public final class FabricGameTestHelper { } } - private static Collection getBatches() { - return TestUtil.createBatches(getTestFunctions()); - } - private static Collection getTestFunctions() { return TestFunctions.getTestFunctions(); } diff --git a/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/api/item/v1/CustomDamageHandler.java b/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/api/item/v1/CustomDamageHandler.java index 77d1b30bc..c5e8789c2 100644 --- a/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/api/item/v1/CustomDamageHandler.java +++ b/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/api/item/v1/CustomDamageHandler.java @@ -16,26 +16,27 @@ package net.fabricmc.fabric.api.item.v1; -import java.util.function.Consumer; - +import net.minecraft.entity.EquipmentSlot; import net.minecraft.entity.LivingEntity; import net.minecraft.item.ItemStack; /** - * Allows an item to run custom logic when {@link ItemStack#damage(int, LivingEntity, Consumer)} is called. + * Allows an item to run custom logic when {@link ItemStack#damage(int, LivingEntity, EquipmentSlot)} is called. * This is useful for items that, for example, may drain durability from some other source before damaging * the stack itself. * - *

Custom damage handlers can be set with {@link FabricItemSettings#customDamage}. + *

Custom damage handlers can be set with {@link FabricItem.Settings#customDamage}. */ @FunctionalInterface public interface CustomDamageHandler { /** * Called to apply damage to the given stack. * This can be used to e.g. drain from a battery before actually damaging the item. - * @param amount The amount of damage originally requested - * @param breakCallback Callback when the stack reaches zero damage. See {@link ItemStack#damage(int, LivingEntity, Consumer)} and its callsites for more information. + * Note that this does not get called if non-entities, such as dispensers, are damaging the item. + * Calling {@code breakCallback} breaks the item, bypassing the vanilla logic. The return value is + * ignored in this case. + * @param amount the amount of damage originally requested * @return The amount of damage to pass to vanilla's logic */ - int damage(ItemStack stack, int amount, LivingEntity entity, Consumer breakCallback); + int damage(ItemStack stack, int amount, LivingEntity entity, EquipmentSlot slot, Runnable breakCallback); } diff --git a/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/api/item/v1/EquipmentSlotProvider.java b/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/api/item/v1/EquipmentSlotProvider.java index c4d0f9ea5..814cc8a3a 100644 --- a/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/api/item/v1/EquipmentSlotProvider.java +++ b/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/api/item/v1/EquipmentSlotProvider.java @@ -27,7 +27,7 @@ import net.minecraft.item.ItemStack; *

The preferred requipment slot of an item stack can be queried using * {@link net.minecraft.entity.LivingEntity#getPreferredEquipmentSlot(ItemStack) LivingEntity.getPreferredEquipmentSlot()}. * - *

Equipment slot providers can be set with {@link FabricItemSettings#equipmentSlot(EquipmentSlotProvider)}. + *

Equipment slot providers can be set with {@link FabricItem.Settings#equipmentSlot(EquipmentSlotProvider)}. * *

Note that items extending {@link net.minecraft.item.ArmorItem} don't need to use this * as there's {@link net.minecraft.item.ArmorItem#getSlotType()}. diff --git a/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/api/item/v1/FabricItem.java b/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/api/item/v1/FabricItem.java index d48f2aaff..750c68003 100644 --- a/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/api/item/v1/FabricItem.java +++ b/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/api/item/v1/FabricItem.java @@ -30,6 +30,8 @@ import net.minecraft.item.ItemStack; import net.minecraft.registry.entry.RegistryEntry; import net.minecraft.util.Hand; +import net.fabricmc.fabric.impl.item.FabricItemInternals; + /** * General-purpose Fabric-provided extensions for {@link Item} subclasses. * @@ -136,4 +138,32 @@ public interface FabricItem { default @Nullable FoodComponent getFoodComponent(ItemStack stack) { return ((Item) this).getFoodComponent(); } + + /** + * Fabric-provided extensions for {@link Item.Settings}. + * This interface is automatically implemented on all item settings via Mixin and interface injection. + */ + interface Settings { + /** + * Sets the equipment slot provider of the item. + * + * @param equipmentSlotProvider the equipment slot provider + * @return this builder + */ + default Item.Settings equipmentSlot(EquipmentSlotProvider equipmentSlotProvider) { + FabricItemInternals.computeExtraData((Item.Settings) this).equipmentSlot(equipmentSlotProvider); + return (Item.Settings) this; + } + + /** + * Sets the custom damage handler of the item. + * Note that this is only called on an ItemStack if {@link ItemStack#isDamageable()} returns true. + * + * @see CustomDamageHandler + */ + default Item.Settings customDamage(CustomDamageHandler handler) { + FabricItemInternals.computeExtraData((Item.Settings) this).customDamage(handler); + return (Item.Settings) this; + } + } } diff --git a/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/api/item/v1/FabricItemSettings.java b/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/api/item/v1/FabricItemSettings.java index 24006e338..284de396d 100644 --- a/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/api/item/v1/FabricItemSettings.java +++ b/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/api/item/v1/FabricItemSettings.java @@ -25,19 +25,18 @@ import net.minecraft.util.Rarity; import net.fabricmc.fabric.impl.item.FabricItemInternals; /** - * Fabric's version of Item.Settings. Adds additional methods and hooks - * not found in the original class. - * - *

To use it, simply replace {@code new Item.Settings()} with - * {@code new FabricItemSettings()}. + * @deprecated replace with {@link Item.Settings} */ +@Deprecated public class FabricItemSettings extends Item.Settings { /** * Sets the equipment slot provider of the item. * * @param equipmentSlotProvider the equipment slot provider * @return this builder + * @deprecated replace with {@link FabricItem.Settings#equipmentSlot(EquipmentSlotProvider)} */ + @Deprecated public FabricItemSettings equipmentSlot(EquipmentSlotProvider equipmentSlotProvider) { FabricItemInternals.computeExtraData(this).equipmentSlot(equipmentSlotProvider); return this; @@ -47,8 +46,10 @@ public class FabricItemSettings extends Item.Settings { * Sets the custom damage handler of the item. * Note that this is only called on an ItemStack if {@link ItemStack#isDamageable()} returns true. * + * @deprecated replace with {@link FabricItem.Settings#customDamage(CustomDamageHandler)} * @see CustomDamageHandler */ + @Deprecated public FabricItemSettings customDamage(CustomDamageHandler handler) { FabricItemInternals.computeExtraData(this).customDamage(handler); return this; diff --git a/fabric-screen-handler-api-v1/src/client/java/net/fabricmc/fabric/api/client/screenhandler/v1/package-info.java b/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/mixin/item/ItemSettingsMixin.java similarity index 70% rename from fabric-screen-handler-api-v1/src/client/java/net/fabricmc/fabric/api/client/screenhandler/v1/package-info.java rename to fabric-item-api-v1/src/main/java/net/fabricmc/fabric/mixin/item/ItemSettingsMixin.java index 47bd0433c..d186844bb 100644 --- a/fabric-screen-handler-api-v1/src/client/java/net/fabricmc/fabric/api/client/screenhandler/v1/package-info.java +++ b/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/mixin/item/ItemSettingsMixin.java @@ -14,7 +14,14 @@ * limitations under the License. */ -/** - * API for working with screen handlers on the client. - */ -package net.fabricmc.fabric.api.client.screenhandler.v1; +package net.fabricmc.fabric.mixin.item; + +import org.spongepowered.asm.mixin.Mixin; + +import net.minecraft.item.Item; + +import net.fabricmc.fabric.api.item.v1.FabricItem; + +@Mixin(Item.Settings.class) +public class ItemSettingsMixin implements FabricItem.Settings { +} diff --git a/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/mixin/item/ItemStackMixin.java b/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/mixin/item/ItemStackMixin.java index 530393241..8328cc58d 100644 --- a/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/mixin/item/ItemStackMixin.java +++ b/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/mixin/item/ItemStackMixin.java @@ -16,28 +16,28 @@ package net.fabricmc.fabric.mixin.item; -import java.util.function.Consumer; - import com.google.common.collect.LinkedHashMultimap; import com.google.common.collect.Multimap; +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import com.llamalad7.mixinextras.sugar.Local; +import org.apache.commons.lang3.mutable.MutableBoolean; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.ModifyArg; import org.spongepowered.asm.mixin.injection.Redirect; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import net.minecraft.block.BlockState; import net.minecraft.entity.EquipmentSlot; -import net.minecraft.entity.LivingEntity; import net.minecraft.entity.attribute.EntityAttribute; import net.minecraft.entity.attribute.EntityAttributeModifier; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.registry.entry.RegistryEntry; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.util.math.random.Random; import net.fabricmc.fabric.api.item.v1.CustomDamageHandler; import net.fabricmc.fabric.api.item.v1.FabricItemStack; @@ -48,33 +48,23 @@ import net.fabricmc.fabric.impl.item.ItemExtensions; public abstract class ItemStackMixin implements FabricItemStack { @Shadow public abstract Item getItem(); - @Unique - private LivingEntity fabric_damagingEntity; - - @Unique - private Consumer fabric_breakCallback; - - @Inject(method = "damage(ILnet/minecraft/entity/LivingEntity;Ljava/util/function/Consumer;)V", at = @At("HEAD")) - private void saveDamager(int amount, LivingEntity entity, Consumer breakCallback, CallbackInfo ci) { - this.fabric_damagingEntity = entity; - this.fabric_breakCallback = breakCallback; - } - - @ModifyArg(method = "damage(ILnet/minecraft/entity/LivingEntity;Ljava/util/function/Consumer;)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/item/ItemStack;damage(ILnet/minecraft/util/math/random/Random;Lnet/minecraft/server/network/ServerPlayerEntity;)Z"), index = 0) - private int hookDamage(int amount) { + @WrapOperation(method = "damage(ILnet/minecraft/entity/LivingEntity;Lnet/minecraft/entity/EquipmentSlot;)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/item/ItemStack;damage(ILnet/minecraft/util/math/random/Random;Lnet/minecraft/server/network/ServerPlayerEntity;Ljava/lang/Runnable;)V")) + private void hookDamage(ItemStack instance, int amount, Random random, ServerPlayerEntity serverPlayerEntity, Runnable runnable, Operation original, @Local(argsOnly = true) EquipmentSlot slot) { CustomDamageHandler handler = ((ItemExtensions) getItem()).fabric_getCustomDamageHandler(); if (handler != null) { - return handler.damage((ItemStack) (Object) this, amount, fabric_damagingEntity, fabric_breakCallback); + // Track whether an item has been broken by custom handler + MutableBoolean mut = new MutableBoolean(false); + amount = handler.damage((ItemStack) (Object) this, amount, serverPlayerEntity, slot, () -> { + mut.setTrue(); + runnable.run(); + }); + + // If item is broken, there's no reason to call the original. + if (mut.booleanValue()) return; } - return amount; - } - - @Inject(method = "damage(ILnet/minecraft/entity/LivingEntity;Ljava/util/function/Consumer;)V", at = @At("RETURN")) - private void clearDamage(int amount, T entity, Consumer breakCallback, CallbackInfo ci) { - this.fabric_damagingEntity = null; - this.fabric_breakCallback = null; + original.call(instance, amount, random, serverPlayerEntity, runnable); } @Redirect( diff --git a/fabric-item-api-v1/src/main/resources/fabric-item-api-v1.mixins.json b/fabric-item-api-v1/src/main/resources/fabric-item-api-v1.mixins.json index f762ae7b1..5b33abf6e 100644 --- a/fabric-item-api-v1/src/main/resources/fabric-item-api-v1.mixins.json +++ b/fabric-item-api-v1/src/main/resources/fabric-item-api-v1.mixins.json @@ -12,6 +12,7 @@ "FoxEntityMixin", "HungerManagerMixin", "ItemMixin", + "ItemSettingsMixin", "ItemStackMixin", "LivingEntityMixin", "RecipeMixin", diff --git a/fabric-item-api-v1/src/main/resources/fabric.mod.json b/fabric-item-api-v1/src/main/resources/fabric.mod.json index a39d70ba7..58b935dd6 100644 --- a/fabric-item-api-v1/src/main/resources/fabric.mod.json +++ b/fabric-item-api-v1/src/main/resources/fabric.mod.json @@ -31,6 +31,7 @@ "fabric-api:module-lifecycle": "stable", "loom:injected_interfaces": { "net/minecraft/class_1792": ["net/fabricmc/fabric/api/item/v1/FabricItem"], + "net/minecraft/class_1792\u0024class_1793": ["net/fabricmc/fabric/api/item/v1/FabricItem\u0024Settings"], "net/minecraft/class_1799": ["net/fabricmc/fabric/api/item/v1/FabricItemStack"] } } diff --git a/fabric-item-api-v1/src/testmod/java/net/fabricmc/fabric/test/item/CustomDamageTest.java b/fabric-item-api-v1/src/testmod/java/net/fabricmc/fabric/test/item/CustomDamageTest.java index 2cd20f963..7d5c1742f 100644 --- a/fabric-item-api-v1/src/testmod/java/net/fabricmc/fabric/test/item/CustomDamageTest.java +++ b/fabric-item-api-v1/src/testmod/java/net/fabricmc/fabric/test/item/CustomDamageTest.java @@ -30,7 +30,6 @@ import net.minecraft.util.Identifier; import net.fabricmc.api.ModInitializer; import net.fabricmc.fabric.api.item.v1.CustomDamageHandler; -import net.fabricmc.fabric.api.item.v1.FabricItemSettings; import net.fabricmc.fabric.api.registry.FabricBrewingRecipeRegistry; import net.fabricmc.fabric.api.registry.FuelRegistry; @@ -44,7 +43,7 @@ public class CustomDamageTest implements ModInitializer { FabricBrewingRecipeRegistry.registerPotionRecipe(Potions.WATER, Ingredient.ofItems(WEIRD_PICK), Potions.AWKWARD); } - public static final CustomDamageHandler WEIRD_DAMAGE_HANDLER = (stack, amount, entity, breakCallback) -> { + public static final CustomDamageHandler WEIRD_DAMAGE_HANDLER = (stack, amount, entity, slot, breakCallback) -> { // If sneaking, apply all damage to vanilla. Otherwise, increment a tag on the stack by one and don't apply any damage if (entity.isSneaking()) { return amount; @@ -57,7 +56,7 @@ public class CustomDamageTest implements ModInitializer { public static class WeirdPick extends PickaxeItem { protected WeirdPick() { - super(ToolMaterials.GOLD, 1, -2.8F, new FabricItemSettings().customDamage(WEIRD_DAMAGE_HANDLER)); + super(ToolMaterials.GOLD, 1, -2.8F, new Item.Settings().customDamage(WEIRD_DAMAGE_HANDLER)); } @Override diff --git a/fabric-item-api-v1/src/testmod/java/net/fabricmc/fabric/test/item/FabricItemSettingsTests.java b/fabric-item-api-v1/src/testmod/java/net/fabricmc/fabric/test/item/FabricItemSettingsTests.java index 76ec9a01c..1ab83af54 100644 --- a/fabric-item-api-v1/src/testmod/java/net/fabricmc/fabric/test/item/FabricItemSettingsTests.java +++ b/fabric-item-api-v1/src/testmod/java/net/fabricmc/fabric/test/item/FabricItemSettingsTests.java @@ -35,7 +35,7 @@ public class FabricItemSettingsTests implements ModInitializer { @Override public void onInitialize() { // Registers an item with a custom equipment slot. - Item testItem = new Item(new FabricItemSettings().equipmentSlot(stack -> EquipmentSlot.CHEST)); + Item testItem = new Item(new Item.Settings().equipmentSlot(stack -> EquipmentSlot.CHEST)); Registry.register(Registries.ITEM, new Identifier("fabric-item-api-v1-testmod", "test_item"), testItem); final List missingMethods = new ArrayList<>(); diff --git a/fabric-item-api-v1/src/testmod/java/net/fabricmc/fabric/test/item/FoodGameInitializer.java b/fabric-item-api-v1/src/testmod/java/net/fabricmc/fabric/test/item/FoodGameInitializer.java index 4d58c04de..515bfcbbb 100644 --- a/fabric-item-api-v1/src/testmod/java/net/fabricmc/fabric/test/item/FoodGameInitializer.java +++ b/fabric-item-api-v1/src/testmod/java/net/fabricmc/fabric/test/item/FoodGameInitializer.java @@ -26,11 +26,10 @@ import net.minecraft.registry.Registry; import net.minecraft.util.Identifier; import net.fabricmc.api.ModInitializer; -import net.fabricmc.fabric.api.item.v1.FabricItemSettings; public final class FoodGameInitializer implements ModInitializer { - public static final Item DAMAGE = Registry.register(Registries.ITEM, new Identifier("fabric-item-api-v1-testmod", "damage_food"), new DamageFood(new FabricItemSettings().maxDamage(20))); - public static final Item NAME = Registry.register(Registries.ITEM, new Identifier("fabric-item-api-v1-testmod", "name_food"), new NameFood(new FabricItemSettings())); + public static final Item DAMAGE = Registry.register(Registries.ITEM, new Identifier("fabric-item-api-v1-testmod", "damage_food"), new DamageFood(new Item.Settings().maxDamage(20))); + public static final Item NAME = Registry.register(Registries.ITEM, new Identifier("fabric-item-api-v1-testmod", "name_food"), new NameFood(new Item.Settings())); @Override public void onInitialize() { 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 fa78e9ff3..3c8faedd0 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,94 +19,55 @@ package net.fabricmc.fabric.api.client.networking.v1; import java.util.Objects; import java.util.Set; +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.PacketByteBuf; -import net.minecraft.network.listener.ServerCommonPacketListener; -import net.minecraft.network.packet.Packet; +import net.minecraft.network.packet.CustomPayload; import net.minecraft.util.Identifier; import net.minecraft.util.thread.ThreadExecutor; -import net.fabricmc.fabric.api.networking.v1.FabricPacket; import net.fabricmc.fabric.api.networking.v1.PacketSender; -import net.fabricmc.fabric.api.networking.v1.PacketType; +import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry; +import net.fabricmc.fabric.api.networking.v1.ServerConfigurationNetworking; +import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; import net.fabricmc.fabric.impl.networking.client.ClientConfigurationNetworkAddon; import net.fabricmc.fabric.impl.networking.client.ClientNetworkingImpl; -import net.fabricmc.fabric.impl.networking.payload.ResolvablePayload; -import net.fabricmc.fabric.impl.networking.payload.TypedPayload; -import net.fabricmc.fabric.impl.networking.payload.UntypedPayload; -import net.fabricmc.fabric.mixin.networking.client.accessor.ClientCommonNetworkHandlerAccessor; /** * Offers access to configuration stage client-side networking functionalities. * *

Client-side networking functionalities include receiving clientbound packets, * sending serverbound packets, and events related to client-side network handlers. + * Packets received by this class must be registered to {@link + * PayloadTypeRegistry#configurationS2C()} on both ends. + * Packets sent by this class must be registered to {@link + * PayloadTypeRegistry#configurationC2S()} on both ends. + * Packets must be registered before registering any receivers. * *

This class should be only used on the physical client and for the logical client. * - *

See {@link net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking} for information on how to use the packet + *

See {@link ServerPlayNetworking} for information on how to use the packet * object-based API. * * @see ServerConfigurationNetworking */ public final class ClientConfigurationNetworking { - /** - * Registers a handler to a channel. - * A global receiver is registered to all connections, in the present and future. - * - *

The handler runs on the network thread. After reading the buffer there, access to game state - * must be performed in the render thread by calling {@link ThreadExecutor#execute(Runnable)}. - * - *

If a handler is already registered to the {@code channel}, this method will return {@code false}, and no change will be made. - * Use {@link #unregisterGlobalReceiver(Identifier)} to unregister the existing handler. - * - *

For new code, {@link #registerGlobalReceiver(PacketType, ConfigurationPacketHandler)} - * is preferred, as it is designed in a way that prevents thread safety issues. - * - * @param channelName the id of the channel - * @param channelHandler the handler - * @return false if a handler is already registered to the channel - * @see ClientConfigurationNetworking#unregisterGlobalReceiver(Identifier) - * @see ClientConfigurationNetworking#registerReceiver(Identifier, ConfigurationChannelHandler) - */ - public static boolean registerGlobalReceiver(Identifier channelName, ConfigurationChannelHandler channelHandler) { - return ClientNetworkingImpl.CONFIGURATION.registerGlobalReceiver(channelName, wrapUntyped(channelHandler)); - } - /** * Registers a handler for a packet type. * A global receiver is registered to all connections, in the present and future. * *

If a handler is already registered for the {@code type}, this method will return {@code false}, and no change will be made. - * Use {@link #unregisterGlobalReceiver(PacketType)} to unregister the existing handler. + * Use {@link #unregisterGlobalReceiver(CustomPayload.Id)} to unregister the existing handler. * * @param type the packet type * @param handler the handler * @return false if a handler is already registered to the channel - * @see ClientConfigurationNetworking#unregisterGlobalReceiver(PacketType) - * @see ClientConfigurationNetworking#registerReceiver(PacketType, ConfigurationPacketHandler) + * @throws IllegalArgumentException if the codec for {@code type} has not been {@linkplain PayloadTypeRegistry#configurationS2C() registered} yet + * @see ClientConfigurationNetworking#unregisterGlobalReceiver(CustomPayload.Id) + * @see ClientConfigurationNetworking#registerReceiver(CustomPayload.Id, ConfigurationPayloadHandler) */ - public static boolean registerGlobalReceiver(PacketType type, ConfigurationPacketHandler handler) { - return ClientNetworkingImpl.CONFIGURATION.registerGlobalReceiver(type.getId(), wrapTyped(type, handler)); - } - - /** - * Removes the handler of a channel. - * A global receiver is registered to all connections, in the present and future. - * - *

The {@code channel} is guaranteed not to have a handler after this call. - * - * @param channelName the id of the channel - * @return the previous handler, or {@code null} if no handler was bound to the channel - * @see ClientConfigurationNetworking#registerGlobalReceiver(Identifier, ConfigurationChannelHandler) - * @see ClientConfigurationNetworking#unregisterReceiver(Identifier) - */ - @Nullable - public static ClientConfigurationNetworking.ConfigurationChannelHandler unregisterGlobalReceiver(Identifier channelName) { - return unwrapUntyped(ClientNetworkingImpl.CONFIGURATION.unregisterGlobalReceiver(channelName)); + public static boolean registerGlobalReceiver(CustomPayload.Id type, ConfigurationPayloadHandler handler) { + return ClientNetworkingImpl.CONFIGURATION.registerGlobalReceiver(type.id(), handler); } /** @@ -115,15 +76,15 @@ public final class ClientConfigurationNetworking { * *

The {@code type} is guaranteed not to have an associated handler after this call. * - * @param type the packet type + * @param id the packet id * @return the previous handler, or {@code null} if no handler was bound to the channel, - * or it was not registered using {@link #registerGlobalReceiver(PacketType, ConfigurationPacketHandler)} - * @see ClientConfigurationNetworking#registerGlobalReceiver(PacketType, ConfigurationPacketHandler) - * @see ClientConfigurationNetworking#unregisterReceiver(PacketType) + * or it was not registered using {@link #registerGlobalReceiver(CustomPayload.Id, ConfigurationPayloadHandler)} + * @see ClientConfigurationNetworking#registerGlobalReceiver(CustomPayload.Id, ConfigurationPayloadHandler) + * @see ClientConfigurationNetworking#unregisterReceiver(Identifier) */ @Nullable - public static ClientConfigurationNetworking.ConfigurationPacketHandler unregisterGlobalReceiver(PacketType type) { - return unwrapTyped(ClientNetworkingImpl.CONFIGURATION.unregisterGlobalReceiver(type.getId())); + public static ClientConfigurationNetworking.ConfigurationPayloadHandler unregisterGlobalReceiver(CustomPayload.Id id) { + return ClientNetworkingImpl.CONFIGURATION.unregisterGlobalReceiver(id.id()); } /** @@ -137,93 +98,47 @@ public final class ClientConfigurationNetworking { } /** - * Registers a handler to a channel. + * Registers a handler for a packet type. * - *

If a handler is already registered to the {@code channel}, this method will return {@code false}, and no change will be made. + *

If a handler is already registered for the {@code type}, this method will return {@code false}, and no change will be made. * Use {@link #unregisterReceiver(Identifier)} to unregister the existing handler. * *

For example, if you only register a receiver using this method when a {@linkplain ClientLoginNetworking#registerGlobalReceiver(Identifier, ClientLoginNetworking.LoginQueryRequestHandler)} * login query has been received, you should use {@link ClientPlayConnectionEvents#INIT} to register the channel handler. * - *

For new code, {@link #registerReceiver(PacketType, ConfigurationPacketHandler)} - * is preferred, as it is designed in a way that prevents thread safety issues. - * - * @param channelName the id of the channel - * @return false if a handler is already registered to the channel - * @throws IllegalStateException if the client is not connected to a server - * @see ClientPlayConnectionEvents#INIT - */ - public static boolean registerReceiver(Identifier channelName, ConfigurationChannelHandler channelHandler) { - final ClientConfigurationNetworkAddon addon = ClientNetworkingImpl.getClientConfigurationAddon(); - - if (addon != null) { - return addon.registerChannel(channelName, wrapUntyped(channelHandler)); - } - - throw new IllegalStateException("Cannot register receiver while not configuring!"); - } - - /** - * Registers a handler for a packet type. - * - *

If a handler is already registered for the {@code type}, this method will return {@code false}, and no change will be made. - * Use {@link #unregisterReceiver(PacketType)} to unregister the existing handler. - * - *

For example, if you only register a receiver using this method when a {@linkplain ClientLoginNetworking#registerGlobalReceiver(Identifier, ClientLoginNetworking.LoginQueryRequestHandler)} - * login query has been received, you should use {@link ClientPlayConnectionEvents#INIT} to register the channel handler. - * - * @param type the packet type + * @param id the payload id * @param handler the handler * @return {@code false} if a handler is already registered for the type + * @throws IllegalArgumentException if the codec for {@code type} has not been {@linkplain PayloadTypeRegistry#configurationS2C() registered} yet * @throws IllegalStateException if the client is not connected to a server * @see ClientPlayConnectionEvents#INIT */ - public static boolean registerReceiver(PacketType type, ConfigurationPacketHandler handler) { + public static boolean registerReceiver(CustomPayload.Id id, ConfigurationPayloadHandler handler) { final ClientConfigurationNetworkAddon addon = ClientNetworkingImpl.getClientConfigurationAddon(); if (addon != null) { - return addon.registerChannel(type.getId(), wrapTyped(type, handler)); + return addon.registerChannel(id.id(), handler); } throw new IllegalStateException("Cannot register receiver while not configuring!"); } - /** - * Removes the handler of a channel. - * - *

The {@code channelName} is guaranteed not to have a handler after this call. - * - * @param channelName the id of the channel - * @return the previous handler, or {@code null} if no handler was bound to the channel - * @throws IllegalStateException if the client is not connected to a server - */ - @Nullable - public static ClientConfigurationNetworking.ConfigurationChannelHandler unregisterReceiver(Identifier channelName) throws IllegalStateException { - final ClientConfigurationNetworkAddon addon = ClientNetworkingImpl.getClientConfigurationAddon(); - - if (addon != null) { - return unwrapUntyped(addon.unregisterChannel(channelName)); - } - - throw new IllegalStateException("Cannot unregister receiver while not configuring!"); - } - /** * Removes the handler for a packet type. * *

The {@code type} is guaranteed not to have an associated handler after this call. * - * @param type the packet type + * @param id the payload id to unregister * @return the previous handler, or {@code null} if no handler was bound to the channel, - * or it was not registered using {@link #registerReceiver(PacketType, ConfigurationPacketHandler)} + * or it was not registered using {@link #registerReceiver(CustomPayload.Id, ConfigurationPayloadHandler)} * @throws IllegalStateException if the client is not connected to a server */ @Nullable - public static ClientConfigurationNetworking.ConfigurationPacketHandler unregisterReceiver(PacketType type) { + public static ClientConfigurationNetworking.ConfigurationPayloadHandler unregisterReceiver(Identifier id) { final ClientConfigurationNetworkAddon addon = ClientNetworkingImpl.getClientConfigurationAddon(); if (addon != null) { - return unwrapTyped(addon.unregisterChannel(type.getId())); + return addon.unregisterChannel(id); } throw new IllegalStateException("Cannot unregister receiver while not configuring!"); @@ -285,22 +200,8 @@ public final class ClientConfigurationNetworking { * @param type the packet type * @return {@code true} if the connected server has declared the ability to receive a packet on the specified channel */ - public static boolean canSend(PacketType type) { - return canSend(type.getId()); - } - - /** - * Creates a packet which may be sent to the connected server. - * - * @param channelName the channel name - * @param buf the packet byte buf which represents the payload of the packet - * @return a new packet - */ - public static Packet createC2SPacket(Identifier channelName, PacketByteBuf buf) { - Objects.requireNonNull(channelName, "Channel name cannot be null"); - Objects.requireNonNull(buf, "Buf cannot be null"); - - return ClientNetworkingImpl.createC2SPacket(channelName, buf); + public static boolean canSend(CustomPayload.Id type) { + return canSend(type.id()); } /** @@ -322,35 +223,19 @@ public final class ClientConfigurationNetworking { /** * Sends a packet to the connected server. * - * @param channelName the channel of the packet - * @param buf the payload of the packet - * @throws IllegalStateException if the client is not connected to a server - */ - public static void send(Identifier channelName, PacketByteBuf buf) throws IllegalStateException { - final ClientConfigurationNetworkAddon addon = ClientNetworkingImpl.getClientConfigurationAddon(); - - if (addon != null) { - addon.sendPacket(createC2SPacket(channelName, buf)); - return; - } - - throw new IllegalStateException("Cannot send packet while not configuring!"); - } - - /** - * Sends a packet to the connected server. + *

Any packets sent must be {@linkplain PayloadTypeRegistry#configurationC2S() registered}.

* - * @param packet the packet + * @param payload to be sent * @throws IllegalStateException if the client is not connected to a server */ - public static void send(T packet) { - Objects.requireNonNull(packet, "Packet cannot be null"); - Objects.requireNonNull(packet.getType(), "Packet#getType cannot return null"); + public static void send(CustomPayload payload) { + Objects.requireNonNull(payload, "Payload cannot be null"); + Objects.requireNonNull(payload.getId(), "CustomPayload#getId() cannot return null for payload class: " + payload.getClass()); final ClientConfigurationNetworkAddon addon = ClientNetworkingImpl.getClientConfigurationAddon(); if (addon != null) { - addon.sendPacket(packet); + addon.sendPacket(payload); return; } @@ -360,98 +245,37 @@ public final class ClientConfigurationNetworking { private ClientConfigurationNetworking() { } - private static ResolvablePayload.Handler wrapUntyped(ConfigurationChannelHandler actualHandler) { - return new ResolvablePayload.Handler<>(null, actualHandler, (client, handler, payload, responseSender) -> { - actualHandler.receive(client, handler, ((UntypedPayload) payload).buffer(), responseSender); - }); - } - - @SuppressWarnings("unchecked") - private static ResolvablePayload.Handler wrapTyped(PacketType type, ConfigurationPacketHandler actualHandler) { - return new ResolvablePayload.Handler<>(type, actualHandler, (client, handler, payload, responseSender) -> { - T packet = (T) ((TypedPayload) payload).packet(); - - if (client.isOnThread()) { - // Do not submit to the render thread if we're already running there. - // Normally, packets are handled on the network IO thread - though it is - // not guaranteed (for example, with 1.19.4 S2C packet bundling) - // Since we're handling it right now, connection check is redundant. - actualHandler.receive(packet, responseSender); - } else { - client.execute(() -> { - if (((ClientCommonNetworkHandlerAccessor) handler).getConnection().isOpen()) { - actualHandler.receive(packet, responseSender); - } - }); - } - }); - } - - @Nullable - private static ConfigurationChannelHandler unwrapUntyped(@Nullable ResolvablePayload.Handler handler) { - if (handler == null) return null; - if (handler.actual() instanceof ConfigurationChannelHandler actual) return actual; - return null; - } - - @Nullable - @SuppressWarnings({"rawtypes", "unchecked"}) - private static ConfigurationPacketHandler unwrapTyped(@Nullable ResolvablePayload.Handler handler) { - if (handler == null) return null; - if (handler.actual() instanceof ConfigurationPacketHandler actual) return actual; - return null; - } - - @FunctionalInterface - public interface ConfigurationChannelHandler { - /** - * Handles an incoming packet. - * - *

This method is executed on {@linkplain io.netty.channel.EventLoop netty's event loops}. - * Modification to the game should be {@linkplain net.minecraft.util.thread.ThreadExecutor#submit(Runnable) scheduled} using the provided Minecraft client instance. - * - *

An example usage of this is to display an overlay message: - *

{@code
-		 * ClientConfigurationNetworking.registerReceiver(new Identifier("mymod", "overlay"), (client, handler, buf, responseSender) -> {
-		 * 	String message = buf.readString(32767);
-		 *
-		 * 	// All operations on the server or world must be executed on the server thread
-		 * 	client.execute(() -> {
-		 * 		client.inGameHud.setOverlayMessage(message, true);
-		 * 	});
-		 * });
-		 * }
- * @param client the client - * @param handler the network handler that received this packet - * @param buf the payload of the packet - * @param responseSender the packet sender - */ - void receive(MinecraftClient client, ClientConfigurationNetworkHandler handler, PacketByteBuf buf, PacketSender responseSender); - } - /** - * A thread-safe packet handler utilizing {@link FabricPacket}. + * A packet handler utilizing {@link CustomPayload}. * @param the type of the packet */ @FunctionalInterface - public interface ConfigurationPacketHandler { + public interface ConfigurationPayloadHandler { /** - * Handles the incoming packet. This is called on the render thread, and can safely - * call client methods. + * Handles the incoming packet. + * + *

Unlike {@link ClientPlayNetworking.PlayPayloadHandler} this method is executed on {@linkplain io.netty.channel.EventLoop netty's event loops}. + * Modification to the game should be {@linkplain ThreadExecutor#submit(Runnable) scheduled}. * *

An example usage of this is to display an overlay message: *

{@code
 		 * // See FabricPacket for creating the packet
-		 * ClientConfigurationNetworking.registerReceiver(OVERLAY_PACKET_TYPE, (player, packet, responseSender) -> {
-		 * 	MinecraftClient.getInstance().inGameHud.setOverlayMessage(packet.message(), true);
+		 * ClientConfigurationNetworking.registerReceiver(OVERLAY_PACKET_TYPE, (packet, responseSender) -> {
 		 * });
 		 * }
* - * - * @param packet the packet - * @param responseSender the packet sender - * @see FabricPacket + * @param payload the packet payload + * @param context the configuration networking context + * @see CustomPayload */ - void receive(T packet, PacketSender responseSender); + void receive(T payload, Context context); + } + + @ApiStatus.NonExtendable + public interface Context { + /** + * @return The packet sender + */ + PacketSender responseSender(); } } diff --git a/fabric-networking-api-v1/src/client/java/net/fabricmc/fabric/api/client/networking/v1/ClientLoginNetworking.java b/fabric-networking-api-v1/src/client/java/net/fabricmc/fabric/api/client/networking/v1/ClientLoginNetworking.java index 38a83ceaf..42b43545b 100644 --- a/fabric-networking-api-v1/src/client/java/net/fabricmc/fabric/api/client/networking/v1/ClientLoginNetworking.java +++ b/fabric-networking-api-v1/src/client/java/net/fabricmc/fabric/api/client/networking/v1/ClientLoginNetworking.java @@ -20,14 +20,13 @@ import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.function.Consumer; -import io.netty.util.concurrent.Future; -import io.netty.util.concurrent.GenericFutureListener; import org.jetbrains.annotations.Nullable; import net.minecraft.client.MinecraftClient; import net.minecraft.client.network.ClientLoginNetworkHandler; import net.minecraft.network.ClientConnection; import net.minecraft.network.PacketByteBuf; +import net.minecraft.network.PacketCallbacks; import net.minecraft.network.listener.PacketListener; import net.minecraft.util.Identifier; @@ -153,10 +152,10 @@ public final class ClientLoginNetworking { * @param client the client * @param handler the network handler that received this packet * @param buf the payload of the packet - * @param listenerAdder listeners to be called when the response packet is sent to the server + * @param callbacksConsumer listeners to be called when the response packet is sent to the server * @return a completable future which contains the payload to respond to the server with. * If the future contains {@code null}, then the server will be notified that the client did not understand the query. */ - CompletableFuture<@Nullable PacketByteBuf> receive(MinecraftClient client, ClientLoginNetworkHandler handler, PacketByteBuf buf, Consumer>> listenerAdder); + CompletableFuture<@Nullable PacketByteBuf> receive(MinecraftClient client, ClientLoginNetworkHandler handler, PacketByteBuf buf, Consumer callbacksConsumer); } } diff --git a/fabric-networking-api-v1/src/client/java/net/fabricmc/fabric/api/client/networking/v1/ClientPlayNetworking.java b/fabric-networking-api-v1/src/client/java/net/fabricmc/fabric/api/client/networking/v1/ClientPlayNetworking.java index cc056b2dd..7601a6f28 100644 --- a/fabric-networking-api-v1/src/client/java/net/fabricmc/fabric/api/client/networking/v1/ClientPlayNetworking.java +++ b/fabric-networking-api-v1/src/client/java/net/fabricmc/fabric/api/client/networking/v1/ClientPlayNetworking.java @@ -19,36 +19,34 @@ package net.fabricmc.fabric.api.client.networking.v1; import java.util.Objects; import java.util.Set; +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; import net.minecraft.client.MinecraftClient; -import net.minecraft.client.network.ClientPlayNetworkHandler; import net.minecraft.client.network.ClientPlayerEntity; -import net.minecraft.network.PacketByteBuf; import net.minecraft.network.listener.ServerCommonPacketListener; +import net.minecraft.network.packet.CustomPayload; import net.minecraft.network.packet.Packet; import net.minecraft.util.Identifier; -import net.minecraft.util.thread.ThreadExecutor; -import net.fabricmc.fabric.api.networking.v1.FabricPacket; import net.fabricmc.fabric.api.networking.v1.PacketSender; -import net.fabricmc.fabric.api.networking.v1.PacketType; +import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry; import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; import net.fabricmc.fabric.impl.networking.client.ClientNetworkingImpl; import net.fabricmc.fabric.impl.networking.client.ClientPlayNetworkAddon; -import net.fabricmc.fabric.impl.networking.payload.ResolvablePayload; -import net.fabricmc.fabric.impl.networking.payload.TypedPayload; -import net.fabricmc.fabric.impl.networking.payload.UntypedPayload; /** * Offers access to play stage client-side networking functionalities. * *

Client-side networking functionalities include receiving clientbound packets, * sending serverbound packets, and events related to client-side network handlers. + * Packets received by this class must be registered to {@link PayloadTypeRegistry#playS2C()} on both ends. + * Packets sent by this class must be registered to {@link PayloadTypeRegistry#playC2S()} on both ends. + * Packets must be registered before registering any receivers. * *

This class should be only used on the physical client and for the logical client. * - *

See {@link ServerPlayNetworking} for information on how to use the packet + *

See {@link ServerPlayNetworking} for information on how to use the payload * object-based API. * * @see ClientLoginNetworking @@ -57,76 +55,38 @@ import net.fabricmc.fabric.impl.networking.payload.UntypedPayload; */ public final class ClientPlayNetworking { /** - * Registers a handler to a channel. - * A global receiver is registered to all connections, in the present and future. - * - *

The handler runs on the network thread. After reading the buffer there, access to game state - * must be performed in the render thread by calling {@link ThreadExecutor#execute(Runnable)}. - * - *

If a handler is already registered to the {@code channel}, this method will return {@code false}, and no change will be made. - * Use {@link #unregisterGlobalReceiver(Identifier)} to unregister the existing handler. - * - *

For new code, {@link #registerGlobalReceiver(PacketType, PlayPacketHandler)} - * is preferred, as it is designed in a way that prevents thread safety issues. - * - * @param channelName the id of the channel - * @param channelHandler the handler - * @return false if a handler is already registered to the channel - * @see ClientPlayNetworking#unregisterGlobalReceiver(Identifier) - * @see ClientPlayNetworking#registerReceiver(Identifier, PlayChannelHandler) - */ - public static boolean registerGlobalReceiver(Identifier channelName, PlayChannelHandler channelHandler) { - return ClientNetworkingImpl.PLAY.registerGlobalReceiver(channelName, wrapUntyped(channelHandler)); - } - - /** - * Registers a handler for a packet type. + * Registers a handler for a payload type. * A global receiver is registered to all connections, in the present and future. * *

If a handler is already registered for the {@code type}, this method will return {@code false}, and no change will be made. - * Use {@link #unregisterGlobalReceiver(PacketType)} to unregister the existing handler. + * Use {@link #unregisterGlobalReceiver(Identifier)} to unregister the existing handler. * - * @param type the packet type + * @param type the payload type * @param handler the handler * @return false if a handler is already registered to the channel - * @see ClientPlayNetworking#unregisterGlobalReceiver(PacketType) - * @see ClientPlayNetworking#registerReceiver(PacketType, PlayPacketHandler) + * @throws IllegalArgumentException if the codec for {@code type} has not been {@linkplain PayloadTypeRegistry#playS2C() registered} yet + * @see ClientPlayNetworking#unregisterGlobalReceiver(Identifier) + * @see ClientPlayNetworking#registerReceiver(CustomPayload.Id, PlayPayloadHandler) */ - public static boolean registerGlobalReceiver(PacketType type, PlayPacketHandler handler) { - return ClientNetworkingImpl.PLAY.registerGlobalReceiver(type.getId(), wrapTyped(type, handler)); + public static boolean registerGlobalReceiver(CustomPayload.Id type, PlayPayloadHandler handler) { + return ClientNetworkingImpl.PLAY.registerGlobalReceiver(type.id(), handler); } /** - * Removes the handler of a channel. - * A global receiver is registered to all connections, in the present and future. - * - *

The {@code channel} is guaranteed not to have a handler after this call. - * - * @param channelName the id of the channel - * @return the previous handler, or {@code null} if no handler was bound to the channel - * @see ClientPlayNetworking#registerGlobalReceiver(Identifier, PlayChannelHandler) - * @see ClientPlayNetworking#unregisterReceiver(Identifier) - */ - @Nullable - public static PlayChannelHandler unregisterGlobalReceiver(Identifier channelName) { - return unwrapUntyped(ClientNetworkingImpl.PLAY.unregisterGlobalReceiver(channelName)); - } - - /** - * Removes the handler for a packet type. + * Removes the handler for a payload type. * A global receiver is registered to all connections, in the present and future. * *

The {@code type} is guaranteed not to have an associated handler after this call. * - * @param type the packet type + * @param id the payload id * @return the previous handler, or {@code null} if no handler was bound to the channel, - * or it was not registered using {@link #registerGlobalReceiver(PacketType, PlayPacketHandler)} - * @see ClientPlayNetworking#registerGlobalReceiver(PacketType, PlayPacketHandler) - * @see ClientPlayNetworking#unregisterReceiver(PacketType) + * or it was not registered using {@link #registerGlobalReceiver(CustomPayload.Id, PlayPayloadHandler)} + * @see ClientPlayNetworking#registerGlobalReceiver(CustomPayload.Id, PlayPayloadHandler) + * @see ClientPlayNetworking#unregisterReceiver(Identifier) */ @Nullable - public static PlayPacketHandler unregisterGlobalReceiver(PacketType type) { - return unwrapTyped(ClientNetworkingImpl.PLAY.unregisterGlobalReceiver(type.getId())); + public static ClientPlayNetworking.PlayPayloadHandler unregisterGlobalReceiver(Identifier id) { + return ClientNetworkingImpl.PLAY.unregisterGlobalReceiver(id); } /** @@ -140,93 +100,47 @@ public final class ClientPlayNetworking { } /** - * Registers a handler to a channel. + * Registers a handler for a payload type. * - *

If a handler is already registered to the {@code channel}, this method will return {@code false}, and no change will be made. + *

If a handler is already registered for the {@code type}, this method will return {@code false}, and no change will be made. * Use {@link #unregisterReceiver(Identifier)} to unregister the existing handler. * *

For example, if you only register a receiver using this method when a {@linkplain ClientLoginNetworking#registerGlobalReceiver(Identifier, ClientLoginNetworking.LoginQueryRequestHandler)} * login query has been received, you should use {@link ClientPlayConnectionEvents#INIT} to register the channel handler. * - *

For new code, {@link #registerReceiver(PacketType, PlayPacketHandler)} - * is preferred, as it is designed in a way that prevents thread safety issues. - * - * @param channelName the id of the channel - * @return false if a handler is already registered to the channel - * @throws IllegalStateException if the client is not connected to a server - * @see ClientPlayConnectionEvents#INIT - */ - public static boolean registerReceiver(Identifier channelName, PlayChannelHandler channelHandler) { - final ClientPlayNetworkAddon addon = ClientNetworkingImpl.getClientPlayAddon(); - - if (addon != null) { - return addon.registerChannel(channelName, wrapUntyped(channelHandler)); - } - - throw new IllegalStateException("Cannot register receiver while not in game!"); - } - - /** - * Registers a handler for a packet type. - * - *

If a handler is already registered for the {@code type}, this method will return {@code false}, and no change will be made. - * Use {@link #unregisterReceiver(PacketType)} to unregister the existing handler. - * - *

For example, if you only register a receiver using this method when a {@linkplain ClientLoginNetworking#registerGlobalReceiver(Identifier, ClientLoginNetworking.LoginQueryRequestHandler)} - * login query has been received, you should use {@link ClientPlayConnectionEvents#INIT} to register the channel handler. - * - * @param type the packet type + * @param type the payload type * @param handler the handler * @return {@code false} if a handler is already registered for the type + * @throws IllegalArgumentException if the codec for {@code type} has not been {@linkplain PayloadTypeRegistry#playS2C() registered} yet * @throws IllegalStateException if the client is not connected to a server * @see ClientPlayConnectionEvents#INIT */ - public static boolean registerReceiver(PacketType type, PlayPacketHandler handler) { + public static boolean registerReceiver(CustomPayload.Id type, PlayPayloadHandler handler) { final ClientPlayNetworkAddon addon = ClientNetworkingImpl.getClientPlayAddon(); if (addon != null) { - return addon.registerChannel(type.getId(), wrapTyped(type, handler)); + return addon.registerChannel(type.id(), handler); } throw new IllegalStateException("Cannot register receiver while not in game!"); } /** - * Removes the handler of a channel. - * - *

The {@code channelName} is guaranteed not to have a handler after this call. - * - * @param channelName the id of the channel - * @return the previous handler, or {@code null} if no handler was bound to the channel - * @throws IllegalStateException if the client is not connected to a server - */ - @Nullable - public static PlayChannelHandler unregisterReceiver(Identifier channelName) throws IllegalStateException { - final ClientPlayNetworkAddon addon = ClientNetworkingImpl.getClientPlayAddon(); - - if (addon != null) { - return unwrapUntyped(addon.unregisterChannel(channelName)); - } - - throw new IllegalStateException("Cannot unregister receiver while not in game!"); - } - - /** - * Removes the handler for a packet type. + * Removes the handler for a payload id. * *

The {@code type} is guaranteed not to have an associated handler after this call. * - * @param type the packet type + * @param id the payload id * @return the previous handler, or {@code null} if no handler was bound to the channel, - * or it was not registered using {@link #registerReceiver(PacketType, PlayPacketHandler)} + * or it was not registered using {@link #registerReceiver(CustomPayload.Id, PlayPayloadHandler)} * @throws IllegalStateException if the client is not connected to a server */ @Nullable - public static PlayPacketHandler unregisterReceiver(PacketType type) { + public static ClientPlayNetworking.PlayPayloadHandler unregisterReceiver(Identifier id) { final ClientPlayNetworkAddon addon = ClientNetworkingImpl.getClientPlayAddon(); if (addon != null) { - return unwrapTyped(addon.unregisterChannel(type.getId())); + return addon.unregisterChannel(id); } throw new IllegalStateException("Cannot unregister receiver while not in game!"); @@ -265,10 +179,10 @@ public final class ClientPlayNetworking { } /** - * Checks if the connected server declared the ability to receive a packet on a specified channel name. + * Checks if the connected server declared the ability to receive a payload on a specified channel name. * * @param channelName the channel name - * @return {@code true} if the connected server has declared the ability to receive a packet on the specified channel. + * @return {@code true} if the connected server has declared the ability to receive a payload on the specified channel. * False if the client is not in game. */ public static boolean canSend(Identifier channelName) throws IllegalArgumentException { @@ -281,44 +195,30 @@ public final class ClientPlayNetworking { } /** - * Checks if the connected server declared the ability to receive a packet on a specified channel name. + * Checks if the connected server declared the ability to receive a payload on a specified channel name. * This returns {@code false} if the client is not in game. * - * @param type the packet type - * @return {@code true} if the connected server has declared the ability to receive a packet on the specified channel + * @param type the payload type + * @return {@code true} if the connected server has declared the ability to receive a payload on the specified channel */ - public static boolean canSend(PacketType type) { - return canSend(type.getId()); + public static boolean canSend(CustomPayload.Id type) { + return canSend(type.id()); } /** - * Creates a packet which may be sent to the connected server. + * Creates a payload which may be sent to the connected server. * - * @param channelName the channel name - * @param buf the packet byte buf which represents the payload of the packet - * @return a new packet + * @param packet the fabric payload + * @return a new payload */ - public static Packet createC2SPacket(Identifier channelName, PacketByteBuf buf) { - Objects.requireNonNull(channelName, "Channel name cannot be null"); - Objects.requireNonNull(buf, "Buf cannot be null"); - - return ClientNetworkingImpl.createC2SPacket(channelName, buf); - } - - /** - * Creates a packet which may be sent to the connected server. - * - * @param packet the fabric packet - * @return a new packet - */ - public static Packet createC2SPacket(T packet) { + public static Packet createC2SPacket(T packet) { return ClientNetworkingImpl.createC2SPacket(packet); } /** - * Gets the packet sender which sends packets to the connected server. + * Gets the payload sender which sends packets to the connected server. * - * @return the client's packet sender + * @return the client's payload sender * @throws IllegalStateException if the client is not connected to a server */ public static PacketSender getSender() throws IllegalStateException { @@ -327,39 +227,24 @@ public final class ClientPlayNetworking { return ClientNetworkingImpl.getAddon(MinecraftClient.getInstance().getNetworkHandler()); } - throw new IllegalStateException("Cannot get packet sender when not in game!"); + throw new IllegalStateException("Cannot get payload sender when not in game!"); } /** - * Sends a packet to the connected server. + * Sends a payload to the connected server. * - * @param channelName the channel of the packet - * @param buf the payload of the packet + *

Any packets sent must be {@linkplain PayloadTypeRegistry#playC2S() registered}.

+ * + * @param payload the payload * @throws IllegalStateException if the client is not connected to a server */ - public static void send(Identifier channelName, PacketByteBuf buf) throws IllegalStateException { - // You cant send without a client player, so this is fine - if (MinecraftClient.getInstance().getNetworkHandler() != null) { - MinecraftClient.getInstance().getNetworkHandler().sendPacket(createC2SPacket(channelName, buf)); - return; - } - - throw new IllegalStateException("Cannot send packets when not in game!"); - } - - /** - * Sends a packet to the connected server. - * - * @param packet the packet - * @throws IllegalStateException if the client is not connected to a server - */ - public static void send(T packet) { - Objects.requireNonNull(packet, "Packet cannot be null"); - Objects.requireNonNull(packet.getType(), "Packet#getType cannot return null"); + public static void send(CustomPayload payload) { + Objects.requireNonNull(payload, "Payload cannot be null"); + Objects.requireNonNull(payload.getId(), "CustomPayload#getId() cannot return null for payload class: " + payload.getClass()); // You cant send without a client player, so this is fine if (MinecraftClient.getInstance().getNetworkHandler() != null) { - MinecraftClient.getInstance().getNetworkHandler().sendPacket(createC2SPacket(packet)); + MinecraftClient.getInstance().getNetworkHandler().sendPacket(createC2SPacket(payload)); return; } @@ -369,98 +254,48 @@ public final class ClientPlayNetworking { private ClientPlayNetworking() { } - private static ResolvablePayload.Handler wrapUntyped(PlayChannelHandler actualHandler) { - return new ResolvablePayload.Handler<>(null, actualHandler, (client, handler, payload, responseSender) -> { - actualHandler.receive(client, handler, ((UntypedPayload) payload).buffer(), responseSender); - }); - } - - @SuppressWarnings("unchecked") - private static ResolvablePayload.Handler wrapTyped(PacketType type, PlayPacketHandler actualHandler) { - return new ResolvablePayload.Handler<>(type, actualHandler, (client, handler, payload, responseSender) -> { - T packet = (T) ((TypedPayload) payload).packet(); - - if (client.isOnThread()) { - // Do not submit to the render thread if we're already running there. - // Normally, packets are handled on the network IO thread - though it is - // not guaranteed (for example, with 1.19.4 S2C packet bundling) - // Since we're handling it right now, connection check is redundant. - actualHandler.receive(packet, client.player, responseSender); - } else { - client.execute(() -> { - if (handler.getConnection().isOpen()) actualHandler.receive(packet, client.player, responseSender); - }); - } - }); - } - - @Nullable - private static PlayChannelHandler unwrapUntyped(@Nullable ResolvablePayload.Handler handler) { - if (handler == null) return null; - if (handler.actual() instanceof PlayChannelHandler actual) return actual; - return null; - } - - @Nullable - @SuppressWarnings({"rawtypes", "unchecked"}) - private static PlayPacketHandler unwrapTyped(@Nullable ResolvablePayload.Handler handler) { - if (handler == null) return null; - if (handler.actual() instanceof PlayPacketHandler actual) return actual; - return null; - } - - @FunctionalInterface - public interface PlayChannelHandler { - /** - * Handles an incoming packet. - * - *

This method is executed on {@linkplain io.netty.channel.EventLoop netty's event loops}. - * Modification to the game should be {@linkplain net.minecraft.util.thread.ThreadExecutor#submit(Runnable) scheduled} using the provided Minecraft client instance. - * - *

An example usage of this is to display an overlay message: - *

{@code
-		 * ClientPlayNetworking.registerReceiver(new Identifier("mymod", "overlay"), (client, handler, buf, responseSender) -> {
-		 * 	String message = buf.readString(32767);
-		 *
-		 * 	// All operations on the server or world must be executed on the server thread
-		 * 	client.execute(() -> {
-		 * 		client.inGameHud.setOverlayMessage(message, true);
-		 * 	});
-		 * });
-		 * }
- * @param client the client - * @param handler the network handler that received this packet - * @param buf the payload of the packet - * @param responseSender the packet sender - */ - void receive(MinecraftClient client, ClientPlayNetworkHandler handler, PacketByteBuf buf, PacketSender responseSender); - } - /** - * A thread-safe packet handler utilizing {@link FabricPacket}. - * @param the type of the packet + * A thread-safe payload handler utilizing {@link CustomPayload}. + * @param the type of the payload */ @FunctionalInterface - public interface PlayPacketHandler { + public interface PlayPayloadHandler { /** - * Handles the incoming packet. This is called on the render thread, and can safely + * Handles the incoming payload. This is called on the render thread, and can safely * call client methods. * *

An example usage of this is to display an overlay message: *

{@code
-		 * // See FabricPacket for creating the packet
-		 * ClientPlayNetworking.registerReceiver(OVERLAY_PACKET_TYPE, (player, packet, responseSender) -> {
-		 * 	MinecraftClient.getInstance().inGameHud.setOverlayMessage(packet.message(), true);
+		 * // See FabricPacket for creating the payload
+		 * ClientPlayNetworking.registerReceiver(OVERLAY_PACKET_TYPE, (player, payload, responseSender) -> {
+		 * 	MinecraftClient.getInstance().inGameHud.setOverlayMessage(payload.message(), true);
 		 * });
 		 * }
* *

The network handler can be accessed via {@link ClientPlayerEntity#networkHandler}. * - * @param packet the packet - * @param player the player that received the packet - * @param responseSender the packet sender - * @see FabricPacket + * @param payload the packet payload + * @param context the play networking context + * @see CustomPayload */ - void receive(T packet, ClientPlayerEntity player, PacketSender responseSender); + void receive(T payload, Context context); + } + + @ApiStatus.NonExtendable + public interface Context { + /** + * @return The MinecraftClient instance + */ + MinecraftClient client(); + + /** + * @return The player that received the payload + */ + ClientPlayerEntity player(); + + /** + * @return The packet sender + */ + PacketSender responseSender(); } } 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 9b598d018..16cc1e99d 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 @@ -21,36 +21,37 @@ import java.util.List; import net.minecraft.client.MinecraftClient; import net.minecraft.client.network.ClientConfigurationNetworkHandler; -import net.minecraft.network.NetworkState; -import net.minecraft.network.PacketByteBuf; +import net.minecraft.network.NetworkPhase; +import net.minecraft.network.packet.CustomPayload; import net.minecraft.network.packet.Packet; import net.minecraft.util.Identifier; import net.fabricmc.fabric.api.client.networking.v1.C2SConfigurationChannelEvents; import net.fabricmc.fabric.api.client.networking.v1.ClientConfigurationConnectionEvents; +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.FabricPacket; import net.fabricmc.fabric.api.networking.v1.PacketSender; import net.fabricmc.fabric.impl.networking.AbstractChanneledNetworkAddon; import net.fabricmc.fabric.impl.networking.ChannelInfoHolder; import net.fabricmc.fabric.impl.networking.NetworkingImpl; -import net.fabricmc.fabric.impl.networking.payload.ResolvablePayload; -import net.fabricmc.fabric.impl.networking.payload.ResolvedPayload; +import net.fabricmc.fabric.impl.networking.RegistrationPayload; import net.fabricmc.fabric.mixin.networking.client.accessor.ClientCommonNetworkHandlerAccessor; import net.fabricmc.fabric.mixin.networking.client.accessor.ClientConfigurationNetworkHandlerAccessor; -public final class ClientConfigurationNetworkAddon extends AbstractChanneledNetworkAddon { +public final class ClientConfigurationNetworkAddon extends AbstractChanneledNetworkAddon> { private final ClientConfigurationNetworkHandler handler; private final MinecraftClient client; + private final ContextImpl context; private boolean sentInitialRegisterPacket; public ClientConfigurationNetworkAddon(ClientConfigurationNetworkHandler handler, MinecraftClient client) { super(ClientNetworkingImpl.CONFIGURATION, ((ClientCommonNetworkHandlerAccessor) handler).getConnection(), "ClientPlayNetworkAddon for " + ((ClientConfigurationNetworkHandlerAccessor) handler).getProfile().getName()); this.handler = handler; this.client = client; + this.context = new ContextImpl(this); // Must register pending channels via lateinit - this.registerPendingChannels((ChannelInfoHolder) this.connection, NetworkState.CONFIGURATION); + this.registerPendingChannels((ChannelInfoHolder) this.connection, NetworkPhase.CONFIGURATION); } @Override @@ -63,8 +64,8 @@ public final class ClientConfigurationNetworkAddon extends AbstractChanneledNetw } @Override - protected void receiveRegistration(boolean register, ResolvablePayload resolvable) { - super.receiveRegistration(register, resolvable); + protected void receiveRegistration(boolean register, RegistrationPayload payload) { + super.receiveRegistration(register, payload); if (register && !this.sentInitialRegisterPacket) { this.sendInitialChannelRegistrationPacket(); @@ -73,8 +74,8 @@ public final class ClientConfigurationNetworkAddon extends AbstractChanneledNetw } @Override - protected void receive(Handler handler, ResolvedPayload payload) { - handler.receive(this.client, this.handler, payload, this); + protected void receive(ClientConfigurationNetworking.ConfigurationPayloadHandler handler, CustomPayload payload) { + ((ClientConfigurationNetworking.ConfigurationPayloadHandler) handler).receive(payload, this.context); } // impl details @@ -85,12 +86,7 @@ public final class ClientConfigurationNetworkAddon extends AbstractChanneledNetw } @Override - public Packet createPacket(Identifier channelName, PacketByteBuf buf) { - return ClientPlayNetworking.createC2SPacket(channelName, buf); - } - - @Override - public Packet createPacket(FabricPacket packet) { + public Packet createPacket(CustomPayload packet) { return ClientPlayNetworking.createC2SPacket(packet); } @@ -108,10 +104,10 @@ public final class ClientConfigurationNetworkAddon extends AbstractChanneledNetw protected void handleRegistration(Identifier channelName) { // If we can already send packets, immediately send the register packet for this channel if (this.sentInitialRegisterPacket) { - final PacketByteBuf buf = this.createRegistrationPacket(Collections.singleton(channelName)); + final RegistrationPayload payload = this.createRegistrationPayload(RegistrationPayload.REGISTER, Collections.singleton(channelName)); - if (buf != null) { - this.sendPacket(NetworkingImpl.REGISTER_CHANNEL, buf); + if (payload != null) { + this.sendPacket(payload); } } } @@ -120,10 +116,10 @@ public final class ClientConfigurationNetworkAddon extends AbstractChanneledNetw protected void handleUnregistration(Identifier channelName) { // If we can already send packets, immediately send the unregister packet for this channel if (this.sentInitialRegisterPacket) { - final PacketByteBuf buf = this.createRegistrationPacket(Collections.singleton(channelName)); + final RegistrationPayload payload = this.createRegistrationPayload(RegistrationPayload.UNREGISTER, Collections.singleton(channelName)); - if (buf != null) { - this.sendPacket(NetworkingImpl.UNREGISTER_CHANNEL, buf); + if (payload != null) { + this.sendPacket(payload); } } } @@ -147,7 +143,6 @@ public final class ClientConfigurationNetworkAddon extends AbstractChanneledNetw return (ChannelInfoHolder) ((ClientCommonNetworkHandlerAccessor) handler).getConnection(); } - public interface Handler { - void receive(MinecraftClient client, ClientConfigurationNetworkHandler handler, ResolvedPayload payload, PacketSender responseSender); + private record ContextImpl(PacketSender responseSender) implements ClientConfigurationNetworking.Context { } } 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 7056428f7..e050c0326 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 @@ -20,23 +20,20 @@ import java.util.ArrayList; import java.util.List; import java.util.concurrent.CompletableFuture; -import io.netty.util.concurrent.Future; -import io.netty.util.concurrent.GenericFutureListener; import org.jetbrains.annotations.Nullable; import net.minecraft.client.MinecraftClient; import net.minecraft.client.network.ClientLoginNetworkHandler; import net.minecraft.network.PacketByteBuf; +import net.minecraft.network.PacketCallbacks; import net.minecraft.network.packet.c2s.login.LoginQueryResponseC2SPacket; import net.minecraft.network.packet.s2c.login.LoginQueryRequestS2CPacket; import net.minecraft.util.Identifier; import net.fabricmc.fabric.api.client.networking.v1.ClientLoginConnectionEvents; import net.fabricmc.fabric.api.client.networking.v1.ClientLoginNetworking; -import net.fabricmc.fabric.api.networking.v1.FutureListeners; import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; import net.fabricmc.fabric.impl.networking.AbstractNetworkAddon; -import net.fabricmc.fabric.impl.networking.GenericFutureListenerHolder; import net.fabricmc.fabric.impl.networking.payload.PacketByteBufLoginQueryRequestPayload; import net.fabricmc.fabric.impl.networking.payload.PacketByteBufLoginQueryResponse; import net.fabricmc.fabric.mixin.networking.client.accessor.ClientLoginNetworkHandlerAccessor; @@ -77,19 +74,18 @@ public final class ClientLoginNetworkAddon extends AbstractNetworkAddon>> futureListeners = new ArrayList<>(); + List callbacks = new ArrayList<>(); try { - CompletableFuture<@Nullable PacketByteBuf> future = handler.receive(this.client, this.handler, buf, futureListeners::add); + CompletableFuture<@Nullable PacketByteBuf> future = handler.receive(this.client, this.handler, buf, callbacks::add); future.thenAccept(result -> { LoginQueryResponseC2SPacket packet = new LoginQueryResponseC2SPacket(queryId, result == null ? null : new PacketByteBufLoginQueryResponse(result)); - GenericFutureListener> listener = null; - - for (GenericFutureListener> each : futureListeners) { - listener = FutureListeners.union(listener, each); - } - - ((ClientLoginNetworkHandlerAccessor) this.handler).getConnection().send(packet, GenericFutureListenerHolder.create(listener)); + ((ClientLoginNetworkHandlerAccessor) this.handler).getConnection().send(packet, new PacketCallbacks() { + @Override + public void onSuccess() { + callbacks.forEach(PacketCallbacks::onSuccess); + } + }); }); } catch (Throwable ex) { this.logger.error("Encountered exception while handling in channel with name \"{}\"", channelName, ex); diff --git a/fabric-networking-api-v1/src/client/java/net/fabricmc/fabric/impl/networking/client/ClientNetworkingImpl.java b/fabric-networking-api-v1/src/client/java/net/fabricmc/fabric/impl/networking/client/ClientNetworkingImpl.java index af4a8c23a..0ed32b04e 100644 --- a/fabric-networking-api-v1/src/client/java/net/fabricmc/fabric/impl/networking/client/ClientNetworkingImpl.java +++ b/fabric-networking-api-v1/src/client/java/net/fabricmc/fabric/impl/networking/client/ClientNetworkingImpl.java @@ -26,19 +26,18 @@ import net.minecraft.client.network.ClientConfigurationNetworkHandler; import net.minecraft.client.network.ClientLoginNetworkHandler; import net.minecraft.client.network.ClientPlayNetworkHandler; import net.minecraft.network.ClientConnection; -import net.minecraft.network.NetworkState; -import net.minecraft.network.PacketByteBuf; +import net.minecraft.network.NetworkPhase; +import net.minecraft.network.NetworkSide; import net.minecraft.network.listener.ServerCommonPacketListener; +import net.minecraft.network.packet.CustomPayload; import net.minecraft.network.packet.Packet; import net.minecraft.network.packet.c2s.common.CustomPayloadC2SPacket; -import net.minecraft.util.Identifier; import net.fabricmc.fabric.api.client.networking.v1.ClientConfigurationConnectionEvents; import net.fabricmc.fabric.api.client.networking.v1.ClientConfigurationNetworking; import net.fabricmc.fabric.api.client.networking.v1.ClientLoginNetworking; import net.fabricmc.fabric.api.client.networking.v1.ClientPlayConnectionEvents; import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; -import net.fabricmc.fabric.api.networking.v1.FabricPacket; import net.fabricmc.fabric.api.networking.v1.PacketSender; import net.fabricmc.fabric.impl.networking.CommonPacketsImpl; import net.fabricmc.fabric.impl.networking.CommonRegisterPayload; @@ -46,17 +45,14 @@ import net.fabricmc.fabric.impl.networking.CommonVersionPayload; import net.fabricmc.fabric.impl.networking.GlobalReceiverRegistry; import net.fabricmc.fabric.impl.networking.NetworkHandlerExtensions; import net.fabricmc.fabric.impl.networking.NetworkingImpl; -import net.fabricmc.fabric.impl.networking.payload.ResolvablePayload; -import net.fabricmc.fabric.impl.networking.payload.ResolvedPayload; -import net.fabricmc.fabric.impl.networking.payload.TypedPayload; -import net.fabricmc.fabric.impl.networking.payload.UntypedPayload; +import net.fabricmc.fabric.impl.networking.PayloadTypeRegistryImpl; import net.fabricmc.fabric.mixin.networking.client.accessor.ConnectScreenAccessor; import net.fabricmc.fabric.mixin.networking.client.accessor.MinecraftClientAccessor; public final class ClientNetworkingImpl { - public static final GlobalReceiverRegistry LOGIN = new GlobalReceiverRegistry<>(NetworkState.LOGIN); - public static final GlobalReceiverRegistry> CONFIGURATION = new GlobalReceiverRegistry<>(NetworkState.CONFIGURATION); - public static final GlobalReceiverRegistry> PLAY = new GlobalReceiverRegistry<>(NetworkState.PLAY); + public static final GlobalReceiverRegistry LOGIN = new GlobalReceiverRegistry<>(NetworkSide.CLIENTBOUND, NetworkPhase.LOGIN, null); + public static final GlobalReceiverRegistry> CONFIGURATION = new GlobalReceiverRegistry<>(NetworkSide.CLIENTBOUND, NetworkPhase.CONFIGURATION, PayloadTypeRegistryImpl.CONFIGURATION_S2C); + public static final GlobalReceiverRegistry> PLAY = new GlobalReceiverRegistry<>(NetworkSide.CLIENTBOUND, NetworkPhase.PLAY, PayloadTypeRegistryImpl.PLAY_S2C); private static ClientPlayNetworkAddon currentPlayAddon; private static ClientConfigurationNetworkAddon currentConfigurationAddon; @@ -73,22 +69,15 @@ public final class ClientNetworkingImpl { return (ClientLoginNetworkAddon) ((NetworkHandlerExtensions) handler).getAddon(); } - public static Packet createC2SPacket(Identifier channelName, PacketByteBuf buf) { - return new CustomPayloadC2SPacket(new UntypedPayload(channelName, buf)); - } - - public static Packet createC2SPacket(FabricPacket packet) { - Objects.requireNonNull(packet, "Packet cannot be null"); - Objects.requireNonNull(packet.getType(), "Packet#getType cannot return null"); - - ResolvedPayload payload = new TypedPayload(packet); - if (NetworkingImpl.FORCE_PACKET_SERIALIZATION) payload = payload.resolve(null); + public static Packet createC2SPacket(CustomPayload payload) { + Objects.requireNonNull(payload, "Payload cannot be null"); + Objects.requireNonNull(payload.getId(), "CustomPayload#getId() cannot return null for payload class: " + payload.getClass()); return new CustomPayloadC2SPacket(payload); } /** - * Due to the way logging into a integrated or remote dedicated server will differ, we need to obtain the login client connection differently. + * Due to the way logging into an integrated or remote dedicated server will differ, we need to obtain the login client connection differently. */ @Nullable public static ClientConnection getLoginConnection() { @@ -153,28 +142,26 @@ public final class ClientNetworkingImpl { }); // Version packet - ClientConfigurationNetworking.registerGlobalReceiver(CommonVersionPayload.PACKET_ID, (client, handler, buf, responseSender) -> { - var payload = new CommonVersionPayload(buf); - int negotiatedVersion = handleVersionPacket(payload, responseSender); - ClientNetworkingImpl.getAddon(handler).onCommonVersionPacket(negotiatedVersion); + ClientConfigurationNetworking.registerGlobalReceiver(CommonVersionPayload.ID, (payload, context) -> { + int negotiatedVersion = handleVersionPacket(payload, context.responseSender()); + ClientNetworkingImpl.getClientConfigurationAddon().onCommonVersionPacket(negotiatedVersion); }); // Register packet - ClientConfigurationNetworking.registerGlobalReceiver(CommonRegisterPayload.PACKET_ID, (client, handler, buf, responseSender) -> { - var payload = new CommonRegisterPayload(buf); - ClientConfigurationNetworkAddon addon = ClientNetworkingImpl.getAddon(handler); + ClientConfigurationNetworking.registerGlobalReceiver(CommonRegisterPayload.ID, (payload, context) -> { + ClientConfigurationNetworkAddon addon = ClientNetworkingImpl.getClientConfigurationAddon(); if (CommonRegisterPayload.PLAY_PHASE.equals(payload.phase())) { if (payload.version() != addon.getNegotiatedVersion()) { throw new IllegalStateException("Negotiated common packet version: %d but received packet with version: %d".formatted(addon.getNegotiatedVersion(), payload.version())); } - addon.getChannelInfoHolder().getPendingChannelsNames(NetworkState.PLAY).addAll(payload.channels()); + addon.getChannelInfoHolder().fabric_getPendingChannelsNames(NetworkPhase.PLAY).addAll(payload.channels()); NetworkingImpl.LOGGER.debug("Received accepted channels from the server"); - responseSender.sendPacket(new CommonRegisterPayload(addon.getNegotiatedVersion(), CommonRegisterPayload.PLAY_PHASE, ClientPlayNetworking.getGlobalReceivers())); + context.responseSender().sendPacket(new CommonRegisterPayload(addon.getNegotiatedVersion(), CommonRegisterPayload.PLAY_PHASE, ClientPlayNetworking.getGlobalReceivers())); } else { addon.onCommonRegisterPacket(payload); - responseSender.sendPacket(addon.createRegisterPayload()); + context.responseSender().sendPacket(addon.createRegisterPayload()); } }); } diff --git a/fabric-networking-api-v1/src/client/java/net/fabricmc/fabric/impl/networking/client/ClientPlayNetworkAddon.java b/fabric-networking-api-v1/src/client/java/net/fabricmc/fabric/impl/networking/client/ClientPlayNetworkAddon.java index cfe34baae..a4c3ed3ae 100644 --- a/fabric-networking-api-v1/src/client/java/net/fabricmc/fabric/impl/networking/client/ClientPlayNetworkAddon.java +++ b/fabric-networking-api-v1/src/client/java/net/fabricmc/fabric/impl/networking/client/ClientPlayNetworkAddon.java @@ -24,24 +24,25 @@ import org.slf4j.Logger; import net.minecraft.client.MinecraftClient; import net.minecraft.client.network.ClientPlayNetworkHandler; -import net.minecraft.network.NetworkState; -import net.minecraft.network.PacketByteBuf; +import net.minecraft.client.network.ClientPlayerEntity; +import net.minecraft.network.NetworkPhase; +import net.minecraft.network.packet.CustomPayload; import net.minecraft.network.packet.Packet; import net.minecraft.util.Identifier; import net.fabricmc.fabric.api.client.networking.v1.C2SPlayChannelEvents; import net.fabricmc.fabric.api.client.networking.v1.ClientPlayConnectionEvents; import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; -import net.fabricmc.fabric.api.networking.v1.FabricPacket; import net.fabricmc.fabric.api.networking.v1.PacketSender; import net.fabricmc.fabric.impl.networking.AbstractChanneledNetworkAddon; import net.fabricmc.fabric.impl.networking.ChannelInfoHolder; import net.fabricmc.fabric.impl.networking.NetworkingImpl; -import net.fabricmc.fabric.impl.networking.payload.ResolvedPayload; +import net.fabricmc.fabric.impl.networking.RegistrationPayload; -public final class ClientPlayNetworkAddon extends AbstractChanneledNetworkAddon { +public final class ClientPlayNetworkAddon extends AbstractChanneledNetworkAddon> { private final ClientPlayNetworkHandler handler; private final MinecraftClient client; + private final ClientPlayNetworking.Context context; private boolean sentInitialRegisterPacket; private static final Logger LOGGER = LogUtils.getLogger(); @@ -50,9 +51,10 @@ public final class ClientPlayNetworkAddon extends AbstractChanneledNetworkAddon< super(ClientNetworkingImpl.PLAY, handler.getConnection(), "ClientPlayNetworkAddon for " + handler.getProfile().getName()); this.handler = handler; this.client = client; + this.context = new ContextImpl(client, client.player, this); // Must register pending channels via lateinit - this.registerPendingChannels((ChannelInfoHolder) this.connection, NetworkState.PLAY); + this.registerPendingChannels((ChannelInfoHolder) this.connection, NetworkPhase.PLAY); } @Override @@ -73,8 +75,10 @@ public final class ClientPlayNetworkAddon extends AbstractChanneledNetworkAddon< } @Override - protected void receive(Handler handler, ResolvedPayload payload) { - handler.receive(this.client, this.handler, payload, this); + protected void receive(ClientPlayNetworking.PlayPayloadHandler handler, CustomPayload payload) { + this.client.execute(() -> { + ((ClientPlayNetworking.PlayPayloadHandler) handler).receive(payload, context); + }); } // impl details @@ -85,12 +89,7 @@ public final class ClientPlayNetworkAddon extends AbstractChanneledNetworkAddon< } @Override - public Packet createPacket(Identifier channelName, PacketByteBuf buf) { - return ClientPlayNetworking.createC2SPacket(channelName, buf); - } - - @Override - public Packet createPacket(FabricPacket packet) { + public Packet createPacket(CustomPayload packet) { return ClientPlayNetworking.createC2SPacket(packet); } @@ -108,10 +107,10 @@ public final class ClientPlayNetworkAddon extends AbstractChanneledNetworkAddon< protected void handleRegistration(Identifier channelName) { // If we can already send packets, immediately send the register packet for this channel if (this.sentInitialRegisterPacket) { - final PacketByteBuf buf = this.createRegistrationPacket(Collections.singleton(channelName)); + final RegistrationPayload payload = this.createRegistrationPayload(RegistrationPayload.REGISTER, Collections.singleton(channelName)); - if (buf != null) { - this.sendPacket(NetworkingImpl.REGISTER_CHANNEL, buf); + if (payload != null) { + this.sendPacket(payload); } } } @@ -120,10 +119,10 @@ public final class ClientPlayNetworkAddon extends AbstractChanneledNetworkAddon< protected void handleUnregistration(Identifier channelName) { // If we can already send packets, immediately send the unregister packet for this channel if (this.sentInitialRegisterPacket) { - final PacketByteBuf buf = this.createRegistrationPacket(Collections.singleton(channelName)); + final RegistrationPayload payload = this.createRegistrationPayload(RegistrationPayload.UNREGISTER, Collections.singleton(channelName)); - if (buf != null) { - this.sendPacket(NetworkingImpl.UNREGISTER_CHANNEL, buf); + if (payload != null) { + this.sendPacket(payload); } } } @@ -138,7 +137,6 @@ public final class ClientPlayNetworkAddon extends AbstractChanneledNetworkAddon< return NetworkingImpl.isReservedCommonChannel(channelName); } - public interface Handler { - void receive(MinecraftClient client, ClientPlayNetworkHandler handler, ResolvedPayload payload, PacketSender responseSender); + private record ContextImpl(MinecraftClient client, ClientPlayerEntity player, PacketSender responseSender) implements ClientPlayNetworking.Context { } } diff --git a/fabric-networking-api-v1/src/client/java/net/fabricmc/fabric/mixin/networking/client/ClientCommonNetworkHandlerMixin.java b/fabric-networking-api-v1/src/client/java/net/fabricmc/fabric/mixin/networking/client/ClientCommonNetworkHandlerMixin.java index f7ce5b02f..d8c4d1bda 100644 --- a/fabric-networking-api-v1/src/client/java/net/fabricmc/fabric/mixin/networking/client/ClientCommonNetworkHandlerMixin.java +++ b/fabric-networking-api-v1/src/client/java/net/fabricmc/fabric/mixin/networking/client/ClientCommonNetworkHandlerMixin.java @@ -25,13 +25,12 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import net.minecraft.client.network.ClientCommonNetworkHandler; +import net.minecraft.network.packet.CustomPayload; import net.minecraft.network.packet.s2c.common.CustomPayloadS2CPacket; import net.fabricmc.fabric.impl.networking.NetworkHandlerExtensions; import net.fabricmc.fabric.impl.networking.client.ClientConfigurationNetworkAddon; import net.fabricmc.fabric.impl.networking.client.ClientPlayNetworkAddon; -import net.fabricmc.fabric.impl.networking.payload.ResolvablePayload; -import net.fabricmc.fabric.impl.networking.payload.RetainedPayload; @Mixin(ClientCommonNetworkHandler.class) public abstract class ClientCommonNetworkHandlerMixin implements NetworkHandlerExtensions { @@ -41,25 +40,18 @@ public abstract class ClientCommonNetworkHandlerMixin implements NetworkHandlerE @Inject(method = "onCustomPayload(Lnet/minecraft/network/packet/s2c/common/CustomPayloadS2CPacket;)V", at = @At("HEAD"), cancellable = true) public void onCustomPayload(CustomPayloadS2CPacket packet, CallbackInfo ci) { - if (packet.payload() instanceof ResolvablePayload payload) { - boolean handled; + final CustomPayload payload = packet.payload(); + boolean handled; - if (this.getAddon() instanceof ClientPlayNetworkAddon addon) { - handled = addon.handle(payload); - } else if (this.getAddon() instanceof ClientConfigurationNetworkAddon addon) { - handled = addon.handle(payload); - } else { - throw new IllegalStateException("Unknown network addon"); - } - - if (!handled && payload instanceof RetainedPayload retained && retained.buf().refCnt() > 0) { - // Duplicate the vanilla log message, as we cancel further processing. - LOGGER.warn("Unknown custom packet payload: {}", payload.id()); - - retained.buf().skipBytes(retained.buf().readableBytes()); - retained.buf().release(); - } + if (this.getAddon() instanceof ClientPlayNetworkAddon addon) { + handled = addon.handle(payload); + } else if (this.getAddon() instanceof ClientConfigurationNetworkAddon addon) { + handled = addon.handle(payload); + } else { + throw new IllegalStateException("Unknown network addon"); + } + if (handled) { ci.cancel(); } } diff --git a/fabric-networking-api-v1/src/client/java/net/fabricmc/fabric/mixin/networking/client/ClientConfigurationNetworkHandlerMixin.java b/fabric-networking-api-v1/src/client/java/net/fabricmc/fabric/mixin/networking/client/ClientConfigurationNetworkHandlerMixin.java index fc4354509..94621972c 100644 --- a/fabric-networking-api-v1/src/client/java/net/fabricmc/fabric/mixin/networking/client/ClientConfigurationNetworkHandlerMixin.java +++ b/fabric-networking-api-v1/src/client/java/net/fabricmc/fabric/mixin/networking/client/ClientConfigurationNetworkHandlerMixin.java @@ -51,7 +51,7 @@ public abstract class ClientConfigurationNetworkHandlerMixin extends ClientCommo this.addon.lateInit(); } - @Inject(method = "onReady", at = @At(value = "INVOKE", target = "Lnet/minecraft/network/ClientConnection;setPacketListener(Lnet/minecraft/network/listener/PacketListener;)V", shift = At.Shift.BEFORE)) + @Inject(method = "onReady", at = @At(value = "NEW", target = "(Lnet/minecraft/client/MinecraftClient;Lnet/minecraft/network/ClientConnection;Lnet/minecraft/client/network/ClientConnectionState;)Lnet/minecraft/client/network/ClientPlayNetworkHandler;")) public void onReady(ReadyS2CPacket packet, CallbackInfo ci) { this.addon.handleReady(); } diff --git a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/api/networking/v1/FabricPacket.java b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/api/networking/v1/FabricPacket.java deleted file mode 100644 index a0387fcd9..000000000 --- a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/api/networking/v1/FabricPacket.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * 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.networking.v1; - -import net.minecraft.network.PacketByteBuf; -import net.minecraft.server.network.ServerPlayerEntity; - -/** - * A packet to be sent using Networking API. An instance of this class is created - * each time the packet is sent. This can be used on both the client and the server. - * - *

Implementations should have fields of values sent over the network. - * For example, a packet consisting of two integers should have two {@code int} - * fields with appropriate name. This is written to the buffer in {@link #write}. - * The packet should have two constructors: one that creates a packet on the sender, - * which initializes the fields to be written, and one that takes a {@link PacketByteBuf} - * and reads the packet. - * - *

For each packet class, a corresponding {@link PacketType} instance should be created. - * The type should be stored in a {@code static final} field, and {@link #getType} should - * return that type. - * - *

Example of a packet: - *

{@code
- * public record BoomPacket(boolean fire) implements FabricPacket {
- * 	public static final PacketType TYPE = PacketType.create(new Identifier("example:boom"), BoomPacket::new);
- *
- * 	public BoomPacket(PacketByteBuf buf) {
- * 		this(buf.readBoolean());
- * 	}
- *
- * 	@Override
- * 	public void write(PacketByteBuf buf) {
- * 		buf.writeBoolean(this.fire);
- * 	}
- *
- * 	@Override
- * 	public PacketType getType() {
- * 		return TYPE;
- * 	}
- * }
- * }
- * - * @see ServerPlayNetworking#registerGlobalReceiver(PacketType, ServerPlayNetworking.PlayPacketHandler) - * @see ServerPlayNetworking#send(ServerPlayerEntity, PacketType, FabricPacket) - * @see PacketSender#sendPacket(FabricPacket) - */ -public interface FabricPacket { - /** - * Writes the contents of this packet to the buffer. - * @param buf the output buffer - */ - void write(PacketByteBuf buf); - - /** - * Returns the packet type of this packet. - * - *

Implementations should store the packet type instance in a {@code static final} - * field and return that here, instead of creating a new instance. - * - * @return the type of this packet - */ - PacketType getType(); -} diff --git a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/api/networking/v1/FutureListeners.java b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/api/networking/v1/FutureListeners.java deleted file mode 100644 index f11ed19a9..000000000 --- a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/api/networking/v1/FutureListeners.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * 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.networking.v1; - -import java.util.Objects; - -import io.netty.channel.Channel; -import io.netty.channel.ChannelFutureListener; -import io.netty.channel.local.LocalChannel; -import io.netty.channel.local.LocalServerChannel; -import io.netty.util.concurrent.Future; -import io.netty.util.concurrent.FutureListener; -import io.netty.util.concurrent.GenericFutureListener; - -import net.minecraft.network.PacketByteBuf; - -/** - * Utilities for working with netty's future listeners. - * @see FutureListener - * @see ChannelFutureListener - */ -public final class FutureListeners { - /** - * Returns a future listener that releases a packet byte buf when the buffer has been sent to a remote connection. - * - * @param buf the buffer - * @return the future listener - */ - public static ChannelFutureListener free(PacketByteBuf buf) { - Objects.requireNonNull(buf, "PacketByteBuf cannot be null"); - - return (future) -> { - if (!isLocalChannel(future.channel())) { - buf.release(); - } - }; - } - - /** - * Returns whether a netty channel performs local transportation, or if the message objects in the channel are directly passed than written to and read from a byte buf. - * - * @param channel the channel to check - * @return whether the channel is local - */ - public static boolean isLocalChannel(Channel channel) { - return channel instanceof LocalServerChannel || channel instanceof LocalChannel; - } - - /** - * Combines two future listeners. - * - * @param first the first future listener - * @param second the second future listener - * @param the future type of the first listener, used for casting - * @param the future type of the second listener, used for casting - * @return the combined future listener. - */ - // A, B exist just to allow casting - @SuppressWarnings("unchecked") - public static , B extends Future> GenericFutureListener> union(GenericFutureListener first, GenericFutureListener second) { - // Return an empty future listener in the case of both parameters somehow being null - if (first == null && second == null) { - return future -> { }; - } - - if (first == null) { - return second; - } - - if (second == null) { - return first; - } - - return future -> { - first.operationComplete((A) future); - second.operationComplete((B) future); - }; - } - - private FutureListeners() { - } -} diff --git a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/api/networking/v1/LoginPacketSender.java b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/api/networking/v1/LoginPacketSender.java new file mode 100644 index 000000000..833ac6164 --- /dev/null +++ b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/api/networking/v1/LoginPacketSender.java @@ -0,0 +1,70 @@ +/* + * 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.networking.v1; + +import java.util.Objects; + +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Nullable; + +import net.minecraft.network.PacketByteBuf; +import net.minecraft.network.PacketCallbacks; +import net.minecraft.network.packet.Packet; +import net.minecraft.util.Identifier; + +/** + * Represents something that supports sending packets to login channels. + * @see PacketSender + */ +@ApiStatus.NonExtendable +public interface LoginPacketSender extends PacketSender { + /** + * Creates a packet for sending to a login channel. + * + * @param channelName the id of the channel + * @param buf the content of the packet + * @return the created packet + */ + Packet createPacket(Identifier channelName, PacketByteBuf buf); + + /** + * Sends a packet to a channel. + * + * @param channel the id of the channel + * @param buf the content of the packet + */ + default void sendPacket(Identifier channel, PacketByteBuf buf) { + Objects.requireNonNull(channel, "Channel cannot be null"); + Objects.requireNonNull(buf, "Payload cannot be null"); + + this.sendPacket(this.createPacket(channel, buf)); + } + + /** + * Sends a packet to a channel. + * + * @param channel the id of the channel + * @param buf the content of the packet + * @param callback an optional callback to execute after the packet is sent, may be {@code null} + */ + default void sendPacket(Identifier channel, PacketByteBuf buf, @Nullable PacketCallbacks callback) { + Objects.requireNonNull(channel, "Channel cannot be null"); + Objects.requireNonNull(buf, "Payload cannot be null"); + + this.sendPacket(this.createPacket(channel, buf), callback); + } +} diff --git a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/api/networking/v1/PacketSender.java b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/api/networking/v1/PacketSender.java index 29f22c9f9..6f818dae5 100644 --- a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/api/networking/v1/PacketSender.java +++ b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/api/networking/v1/PacketSender.java @@ -16,42 +16,26 @@ package net.fabricmc.fabric.api.networking.v1; -import java.util.Objects; - -import io.netty.channel.ChannelFutureListener; -import io.netty.util.concurrent.Future; -import io.netty.util.concurrent.GenericFutureListener; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; -import net.minecraft.network.PacketByteBuf; import net.minecraft.network.PacketCallbacks; import net.minecraft.network.packet.CustomPayload; import net.minecraft.network.packet.Packet; -import net.minecraft.util.Identifier; - -import net.fabricmc.fabric.impl.networking.GenericFutureListenerHolder; +import net.minecraft.text.Text; /** * Represents something that supports sending packets to channels. - * @see PacketByteBufs + * Any packets sent must be {@linkplain PayloadTypeRegistry registered} in the appropriate registry. */ @ApiStatus.NonExtendable public interface PacketSender { /** - * Makes a packet for a channel. + * Creates a packet from a packet payload. * - * @param channelName the id of the channel - * @param buf the content of the packet + * @param payload the packet payload */ - Packet createPacket(Identifier channelName, PacketByteBuf buf); - - /** - * Makes a packet for a fabric packet. - * - * @param packet the fabric packet - */ - Packet createPacket(FabricPacket packet); + Packet createPacket(CustomPayload payload); /** * Sends a packet. @@ -59,15 +43,7 @@ public interface PacketSender { * @param packet the packet */ default void sendPacket(Packet packet) { - sendPacket(packet, (PacketCallbacks) null); - } - - /** - * Sends a packet. - * @param packet the packet - */ - default void sendPacket(T packet) { - sendPacket(createPacket(packet)); + sendPacket(packet, null); } /** @@ -75,107 +51,30 @@ public interface PacketSender { * @param payload the payload */ default void sendPacket(CustomPayload payload) { - PacketByteBuf buf = PacketByteBufs.create(); - payload.write(buf); - sendPacket(payload.id(), buf); + sendPacket(createPacket(payload)); } /** * Sends a packet. * * @param packet the packet - * @param callback an optional callback to execute after the packet is sent, may be {@code null}. The callback may also accept a {@link ChannelFutureListener}. - */ - void sendPacket(Packet packet, @Nullable GenericFutureListener> callback); - - /** - * Sends a packet. - * - * @param packet the packet - * @param callback an optional callback to execute after the packet is sent, may be {@code null}. The callback may also accept a {@link ChannelFutureListener}. - */ - default void sendPacket(T packet, @Nullable GenericFutureListener> callback) { - sendPacket(createPacket(packet), callback); - } - - /** - * Sends a packet. - * - * @param payload the payload - * @param callback an optional callback to execute after the packet is sent, may be {@code null}. The callback may also accept a {@link ChannelFutureListener}. - */ - default void sendPacket(CustomPayload payload, @Nullable GenericFutureListener> callback) { - PacketByteBuf buf = PacketByteBufs.create(); - payload.write(buf); - sendPacket(payload.id(), buf, callback); - } - - /** - * Sends a packet. - * - * @param packet the packet - * @param callback an optional callback to execute after the packet is sent, may be {@code null}. The callback may also accept a {@link ChannelFutureListener}. + * @param callback an optional callback to execute after the packet is sent, may be {@code null}. */ void sendPacket(Packet packet, @Nullable PacketCallbacks callback); - /** - * Sends a packet. - * - * @param packet the packet - * @param callback an optional callback to execute after the packet is sent, may be {@code null}. The callback may also accept a {@link ChannelFutureListener}. - */ - default void sendPacket(T packet, @Nullable PacketCallbacks callback) { - sendPacket(createPacket(packet), callback); - } - /** * Sends a packet. * * @param payload the payload - * @param callback an optional callback to execute after the packet is sent, may be {@code null}. The callback may also accept a {@link ChannelFutureListener}. + * @param callback an optional callback to execute after the packet is sent, may be {@code null}. */ default void sendPacket(CustomPayload payload, @Nullable PacketCallbacks callback) { - PacketByteBuf buf = PacketByteBufs.create(); - payload.write(buf); - sendPacket(payload.id(), buf, callback); + sendPacket(createPacket(payload), callback); } /** - * Sends a packet to a channel. - * - * @param channel the id of the channel - * @param buf the content of the packet + * Disconnects the player. + * @param disconnectReason the reason for disconnection */ - default void sendPacket(Identifier channel, PacketByteBuf buf) { - Objects.requireNonNull(channel, "Channel cannot be null"); - Objects.requireNonNull(buf, "Payload cannot be null"); - - this.sendPacket(this.createPacket(channel, buf)); - } - - /** - * Sends a packet to a channel. - * - * @param channel the id of the channel - * @param buf the content of the packet - * @param callback an optional callback to execute after the packet is sent, may be {@code null} - */ - // the generic future listener can accept ChannelFutureListener - default void sendPacket(Identifier channel, PacketByteBuf buf, @Nullable GenericFutureListener> callback) { - sendPacket(channel, buf, GenericFutureListenerHolder.create(callback)); - } - - /** - * Sends a packet to a channel. - * - * @param channel the id of the channel - * @param buf the content of the packet - * @param callback an optional callback to execute after the packet is sent, may be {@code null} - */ - default void sendPacket(Identifier channel, PacketByteBuf buf, @Nullable PacketCallbacks callback) { - Objects.requireNonNull(channel, "Channel cannot be null"); - Objects.requireNonNull(buf, "Payload cannot be null"); - - this.sendPacket(this.createPacket(channel, buf), callback); - } + void disconnect(Text disconnectReason); } diff --git a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/api/networking/v1/PacketType.java b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/api/networking/v1/PacketType.java deleted file mode 100644 index 25f6a1f5e..000000000 --- a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/api/networking/v1/PacketType.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * 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.networking.v1; - -import java.util.function.Function; - -import net.minecraft.network.PacketByteBuf; -import net.minecraft.util.Identifier; - -/** - * A type of packet. An instance of this should be created per a {@link FabricPacket} implementation. - * This holds the channel ID used for the packet. - * - * @param the type of the packet - * @see FabricPacket - */ -public final class PacketType { - private final Identifier id; - private final Function constructor; - - private PacketType(Identifier id, Function constructor) { - this.id = id; - this.constructor = constructor; - } - - /** - * Creates a new packet type. - * @param id the channel ID used for the packets - * @param constructor the reader that reads the received buffer - * @param

the type of the packet - * @return the newly created type - */ - public static

PacketType

create(Identifier id, Function constructor) { - return new PacketType<>(id, constructor); - } - - /** - * Returns the identifier of the channel used to send the packet. - * @return the identifier of the associated channel. - */ - public Identifier getId() { - return id; - } - - /** - * Reads the packet from the buffer. - * @param buf the buffer - * @return the packet - */ - public T read(PacketByteBuf buf) { - try { - return this.constructor.apply(buf); - } catch (RuntimeException e) { - throw new RuntimeException("Error while handling packet \"%s\": %s".formatted(this.id, e.getMessage()), e); - } - } -} diff --git a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/api/networking/v1/PayloadTypeRegistry.java b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/api/networking/v1/PayloadTypeRegistry.java new file mode 100644 index 000000000..0b8bb7b20 --- /dev/null +++ b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/api/networking/v1/PayloadTypeRegistry.java @@ -0,0 +1,73 @@ +/* + * 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.networking.v1; + +import org.jetbrains.annotations.ApiStatus; + +import net.minecraft.network.PacketByteBuf; +import net.minecraft.network.RegistryByteBuf; +import net.minecraft.network.codec.PacketCodec; +import net.minecraft.network.packet.CustomPayload; + +import net.fabricmc.fabric.impl.networking.PayloadTypeRegistryImpl; + +/** + * A registry for payload types. + */ +@ApiStatus.NonExtendable +public interface PayloadTypeRegistry { + /** + * Registers a custom payload type. + * + *

This must be done on both the sending and receiving side, usually during mod initialization + * and before registering a packet handler. + * + * @param id the id of the payload type + * @param codec the codec for the payload type + * @param the payload type + * @return the registered payload type + */ + CustomPayload.Type register(CustomPayload.Id id, PacketCodec codec); + + /** + * @return the {@link PayloadTypeRegistry} instance for the client to server configuration channel. + */ + static PayloadTypeRegistry configurationC2S() { + return PayloadTypeRegistryImpl.CONFIGURATION_C2S; + } + + /** + * @return the {@link PayloadTypeRegistry} instance for the server to client configuration channel. + */ + static PayloadTypeRegistry configurationS2C() { + return PayloadTypeRegistryImpl.CONFIGURATION_S2C; + } + + /** + * @return the {@link PayloadTypeRegistry} instance for the client to server play channel. + */ + static PayloadTypeRegistry playC2S() { + return PayloadTypeRegistryImpl.PLAY_C2S; + } + + /** + * @return the {@link PayloadTypeRegistry} instance for the server to client play channel. + */ + static PayloadTypeRegistry playS2C() { + return PayloadTypeRegistryImpl.PLAY_S2C; + } +} 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 218dec454..a83495ca3 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 @@ -19,20 +19,17 @@ package net.fabricmc.fabric.api.networking.v1; import java.util.Objects; import java.util.Set; +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; -import net.minecraft.network.PacketByteBuf; import net.minecraft.network.listener.ClientCommonPacketListener; +import net.minecraft.network.packet.CustomPayload; import net.minecraft.network.packet.Packet; import net.minecraft.server.MinecraftServer; import net.minecraft.server.network.ServerConfigurationNetworkHandler; import net.minecraft.util.Identifier; import net.minecraft.util.thread.ThreadExecutor; -import net.fabricmc.fabric.impl.networking.payload.ResolvablePayload; -import net.fabricmc.fabric.impl.networking.payload.TypedPayload; -import net.fabricmc.fabric.impl.networking.payload.UntypedPayload; -import net.fabricmc.fabric.impl.networking.server.ServerConfigurationNetworkAddon; import net.fabricmc.fabric.impl.networking.server.ServerNetworkingImpl; import net.fabricmc.fabric.mixin.networking.accessor.ServerCommonNetworkHandlerAccessor; @@ -40,11 +37,13 @@ import net.fabricmc.fabric.mixin.networking.accessor.ServerCommonNetworkHandlerA * Offers access to configuration stage server-side networking functionalities. * *

Server-side networking functionalities include receiving serverbound packets, sending clientbound packets, and events related to server-side network handlers. + * Packets received by this class must be registered to {@link PayloadTypeRegistry#configurationC2S()} on both ends. + * Packets sent by this class must be registered to {@link PayloadTypeRegistry#configurationS2C()} on both ends. + * Packets must be registered before registering any receivers. * *

This class should be only used for the logical server. * - *

See {@link ServerPlayNetworking} for information on how to use the packet - * object-based API. + *

See {@link ServerPlayNetworking} for information on sending and receiving play phase packets. * *

See the documentation on each class for more information. * @@ -53,76 +52,38 @@ import net.fabricmc.fabric.mixin.networking.accessor.ServerCommonNetworkHandlerA */ public final class ServerConfigurationNetworking { /** - * Registers a handler to a channel. - * A global receiver is registered to all connections, in the present and future. - * - *

The handler runs on the network thread. After reading the buffer there, the server - * must be modified in the server thread by calling {@link ThreadExecutor#execute(Runnable)}. - * - *

If a handler is already registered to the {@code channel}, this method will return {@code false}, and no change will be made. - * Use {@link #unregisterReceiver(ServerConfigurationNetworkHandler, Identifier)} to unregister the existing handler. - * - *

For new code, {@link #registerGlobalReceiver(PacketType, ConfigurationPacketHandler)} - * is preferred, as it is designed in a way that prevents thread safety issues. - * - * @param channelName the id of the channel - * @param channelHandler the handler - * @return false if a handler is already registered to the channel - * @see ServerConfigurationNetworking#unregisterGlobalReceiver(Identifier) - * @see ServerConfigurationNetworking#registerReceiver(ServerConfigurationNetworkHandler, Identifier, ConfigurationChannelHandler) - */ - public static boolean registerGlobalReceiver(Identifier channelName, ConfigurationChannelHandler channelHandler) { - return ServerNetworkingImpl.CONFIGURATION.registerGlobalReceiver(channelName, wrapUntyped(channelHandler)); - } - - /** - * Registers a handler for a packet type. + * Registers a handler for a payload type. * A global receiver is registered to all connections, in the present and future. * *

If a handler is already registered for the {@code type}, this method will return {@code false}, and no change will be made. - * Use {@link #unregisterReceiver(ServerConfigurationNetworkHandler, PacketType)} to unregister the existing handler. + * Use {@link #unregisterReceiver(ServerConfigurationNetworkHandler, Identifier)} to unregister the existing handler. * * @param type the packet type * @param handler the handler * @return {@code false} if a handler is already registered to the channel - * @see ServerConfigurationNetworking#unregisterGlobalReceiver(PacketType) - * @see ServerConfigurationNetworking#registerReceiver(ServerConfigurationNetworkHandler, PacketType, ConfigurationPacketHandler) + * @throws IllegalArgumentException if the codec for {@code type} has not been {@linkplain PayloadTypeRegistry#configurationC2S() registered} yet + * @see ServerConfigurationNetworking#unregisterGlobalReceiver(Identifier) + * @see ServerConfigurationNetworking#registerReceiver(ServerConfigurationNetworkHandler, CustomPayload.Id, ConfigurationPacketHandler) */ - public static boolean registerGlobalReceiver(PacketType type, ConfigurationPacketHandler handler) { - return ServerNetworkingImpl.CONFIGURATION.registerGlobalReceiver(type.getId(), wrapTyped(type, handler)); + public static boolean registerGlobalReceiver(CustomPayload.Id type, ConfigurationPacketHandler handler) { + return ServerNetworkingImpl.CONFIGURATION.registerGlobalReceiver(type.id(), handler); } /** - * Removes the handler of a channel. - * A global receiver is registered to all connections, in the present and future. - * - *

The {@code channel} is guaranteed not to have a handler after this call. - * - * @param channelName the id of the channel - * @return the previous handler, or {@code null} if no handler was bound to the channel - * @see ServerConfigurationNetworking#registerGlobalReceiver(Identifier, ConfigurationChannelHandler) - * @see ServerConfigurationNetworking#unregisterReceiver(ServerConfigurationNetworkHandler, Identifier) - */ - @Nullable - public static ServerConfigurationNetworking.ConfigurationChannelHandler unregisterGlobalReceiver(Identifier channelName) { - return unwrapUntyped(ServerNetworkingImpl.CONFIGURATION.unregisterGlobalReceiver(channelName)); - } - - /** - * Removes the handler for a packet type. + * Removes the handler for a payload type. * A global receiver is registered to all connections, in the present and future. * *

The {@code type} is guaranteed not to have an associated handler after this call. * - * @param type the packet type + * @param id the packet payload id * @return the previous handler, or {@code null} if no handler was bound to the channel, - * or it was not registered using {@link #registerGlobalReceiver(PacketType, ConfigurationPacketHandler)} - * @see ServerConfigurationNetworking#registerGlobalReceiver(PacketType, ConfigurationPacketHandler) - * @see ServerConfigurationNetworking#unregisterReceiver(ServerConfigurationNetworkHandler, PacketType) + * or it was not registered using {@link #registerGlobalReceiver(CustomPayload.Id, ConfigurationPacketHandler)} + * @see ServerConfigurationNetworking#registerGlobalReceiver(CustomPayload.Id, ConfigurationPacketHandler) + * @see ServerConfigurationNetworking#unregisterReceiver(ServerConfigurationNetworkHandler, Identifier) */ @Nullable - public static ServerConfigurationNetworking.ConfigurationPacketHandler unregisterGlobalReceiver(PacketType type) { - return unwrapTyped(ServerNetworkingImpl.CONFIGURATION.unregisterGlobalReceiver(type.getId())); + public static ServerConfigurationNetworking.ConfigurationPacketHandler unregisterGlobalReceiver(Identifier id) { + return ServerNetworkingImpl.CONFIGURATION.unregisterGlobalReceiver(id); } /** @@ -136,82 +97,36 @@ public final class ServerConfigurationNetworking { } /** - * Registers a handler to a channel. - * This method differs from {@link ServerConfigurationNetworking#registerGlobalReceiver(Identifier, ConfigurationChannelHandler)} since + * Registers a handler for a payload type. + * This method differs from {@link ServerConfigurationNetworking#registerGlobalReceiver(CustomPayload.Id, ConfigurationPacketHandler)} since * the channel handler will only be applied to the client represented by the {@link ServerConfigurationNetworkHandler}. * - *

The handler runs on the network thread. After reading the buffer there, the world - * must be modified in the server thread by calling {@link ThreadExecutor#execute(Runnable)}. - * - *

For example, if you only register a receiver using this method when a {@linkplain ServerLoginNetworking#registerGlobalReceiver(Identifier, ServerLoginNetworking.LoginQueryResponseHandler)} - * login response has been received, you should use {@link ServerPlayConnectionEvents#INIT} to register the channel handler. - * - *

If a handler is already registered to the {@code channelName}, this method will return {@code false}, and no change will be made. - * Use {@link #unregisterReceiver(ServerConfigurationNetworkHandler, Identifier)} to unregister the existing handler. - * - *

For new code, {@link #registerReceiver(ServerConfigurationNetworkHandler, PacketType, ConfigurationPacketHandler)} - * is preferred, as it is designed in a way that prevents thread safety issues. - * - * @param networkHandler the handler - * @param channelName the id of the channel - * @param channelHandler the handler - * @return false if a handler is already registered to the channel name - * @see ServerPlayConnectionEvents#INIT - */ - public static boolean registerReceiver(ServerConfigurationNetworkHandler networkHandler, Identifier channelName, ConfigurationChannelHandler channelHandler) { - Objects.requireNonNull(networkHandler, "Network handler cannot be null"); - - return ServerNetworkingImpl.getAddon(networkHandler).registerChannel(channelName, wrapUntyped(channelHandler)); - } - - /** - * Registers a handler for a packet type. - * This method differs from {@link ServerConfigurationNetworking#registerGlobalReceiver(PacketType, ConfigurationPacketHandler)} since - * the channel handler will only be applied to the client represented by the {@link ServerConfigurationNetworkHandler}. - * - *

For example, if you only register a receiver using this method when a {@linkplain ServerLoginNetworking#registerGlobalReceiver(Identifier, ServerLoginNetworking.LoginQueryResponseHandler)} - * login response has been received, you should use {@link ServerPlayConnectionEvents#INIT} to register the channel handler. - * *

If a handler is already registered for the {@code type}, this method will return {@code false}, and no change will be made. - * Use {@link #unregisterReceiver(ServerConfigurationNetworkHandler, PacketType)} to unregister the existing handler. + * Use {@link #unregisterReceiver(ServerConfigurationNetworkHandler, Identifier)} to unregister the existing handler. * * @param networkHandler the network handler * @param type the packet type * @param handler the handler * @return {@code false} if a handler is already registered to the channel name + * @throws IllegalArgumentException if the codec for {@code type} has not been {@linkplain PayloadTypeRegistry#configurationC2S() registered} yet * @see ServerPlayConnectionEvents#INIT */ - public static boolean registerReceiver(ServerConfigurationNetworkHandler networkHandler, PacketType type, ConfigurationPacketHandler handler) { - return ServerNetworkingImpl.getAddon(networkHandler).registerChannel(type.getId(), wrapTyped(type, handler)); + public static boolean registerReceiver(ServerConfigurationNetworkHandler networkHandler, CustomPayload.Id type, ConfigurationPacketHandler handler) { + return ServerNetworkingImpl.getAddon(networkHandler).registerChannel(type.id(), handler); } /** - * Removes the handler of a channel. - * - *

The {@code channelName} is guaranteed not to have a handler after this call. - * - * @param channelName the id of the channel - * @return the previous handler, or {@code null} if no handler was bound to the channel name - */ - @Nullable - public static ServerConfigurationNetworking.ConfigurationChannelHandler unregisterReceiver(ServerConfigurationNetworkHandler networkHandler, Identifier channelName) { - Objects.requireNonNull(networkHandler, "Network handler cannot be null"); - - return unwrapUntyped(ServerNetworkingImpl.getAddon(networkHandler).unregisterChannel(channelName)); - } - - /** - * Removes the handler for a packet type. + * Removes the handler for a payload type. * *

The {@code type} is guaranteed not to have an associated handler after this call. * - * @param type the type of the packet + * @param id the id of the payload * @return the previous handler, or {@code null} if no handler was bound to the channel, - * or it was not registered using {@link #registerReceiver(ServerConfigurationNetworkHandler, PacketType, ConfigurationPacketHandler)} + * or it was not registered using {@link #registerReceiver(ServerConfigurationNetworkHandler, CustomPayload.Id, ConfigurationPacketHandler)} */ @Nullable - public static ServerConfigurationNetworking.ConfigurationPacketHandler unregisterReceiver(ServerConfigurationNetworkHandler networkHandler, PacketType type) { - return unwrapTyped(ServerNetworkingImpl.getAddon(networkHandler).unregisterChannel(type.getId())); + public static ServerConfigurationNetworking.ConfigurationPacketHandler unregisterReceiver(ServerConfigurationNetworkHandler networkHandler, Identifier id) { + return ServerNetworkingImpl.getAddon(networkHandler).unregisterChannel(id); } /** @@ -256,41 +171,27 @@ public final class ServerConfigurationNetworking { * Checks if the connected client declared the ability to receive a specific type of packet. * * @param handler the network handler - * @param type the packet type + * @param id the payload id * @return {@code true} if the connected client has declared the ability to receive a specific type of packet */ - public static boolean canSend(ServerConfigurationNetworkHandler handler, PacketType type) { + public static boolean canSend(ServerConfigurationNetworkHandler handler, CustomPayload.Id id) { Objects.requireNonNull(handler, "Server configuration network handler cannot be null"); - Objects.requireNonNull(type, "Packet type cannot be null"); + Objects.requireNonNull(id, "Payload id cannot be null"); - return ServerNetworkingImpl.getAddon(handler).getSendableChannels().contains(type.getId()); + return ServerNetworkingImpl.getAddon(handler).getSendableChannels().contains(id.id()); } /** * Creates a packet which may be sent to a connected client. * - * @param channelName the channel name - * @param buf the packet byte buf which represents the payload of the packet + * @param payload the payload * @return a new packet */ - public static Packet createS2CPacket(Identifier channelName, PacketByteBuf buf) { - Objects.requireNonNull(channelName, "Channel cannot be null"); - Objects.requireNonNull(buf, "Buf cannot be null"); + public static Packet createS2CPacket(CustomPayload payload) { + Objects.requireNonNull(payload, "Payload cannot be null"); + Objects.requireNonNull(payload.getId(), "CustomPayload#getId() cannot return null for payload class: " + payload.getClass()); - return ServerNetworkingImpl.createS2CPacket(channelName, buf); - } - - /** - * Creates a packet which may be sent to a connected client. - * - * @param packet the fabric packet - * @return a new packet - */ - public static Packet createS2CPacket(T packet) { - Objects.requireNonNull(packet, "Packet cannot be null"); - Objects.requireNonNull(packet.getType(), "Packet#getType cannot return null"); - - return ServerNetworkingImpl.createS2CPacket(packet); + return ServerNetworkingImpl.createS2CPacket(payload); } /** @@ -308,30 +209,17 @@ public final class ServerConfigurationNetworking { /** * Sends a packet to a configuring player. * - * @param handler the handler to send the packet to - * @param channelName the channel of the packet - * @param buf the payload of the packet. - */ - public static void send(ServerConfigurationNetworkHandler handler, Identifier channelName, PacketByteBuf buf) { - Objects.requireNonNull(handler, "Server configuration entity cannot be null"); - Objects.requireNonNull(channelName, "Channel name cannot be null"); - Objects.requireNonNull(buf, "Packet byte buf cannot be null"); - - handler.sendPacket(createS2CPacket(channelName, buf)); - } - - /** - * Sends a packet to a configuring player. + *

Any packets sent must be {@linkplain PayloadTypeRegistry#configurationS2C() registered}.

* * @param handler the network handler to send the packet to - * @param packet the packet + * @param payload to be sent */ - public static void send(ServerConfigurationNetworkHandler handler, T packet) { + public static void send(ServerConfigurationNetworkHandler handler, CustomPayload payload) { Objects.requireNonNull(handler, "Server configuration handler cannot be null"); - Objects.requireNonNull(packet, "Packet cannot be null"); - Objects.requireNonNull(packet.getType(), "Packet#getType cannot return null"); + Objects.requireNonNull(payload, "Payload cannot be null"); + Objects.requireNonNull(payload.getId(), "CustomPayload#getId() cannot return null for payload class: " + payload.getClass()); - handler.sendPacket(createS2CPacket(packet)); + handler.sendPacket(createS2CPacket(payload)); } // Helper methods @@ -350,72 +238,16 @@ public final class ServerConfigurationNetworking { private ServerConfigurationNetworking() { } - private static ResolvablePayload.Handler wrapUntyped(ConfigurationChannelHandler actualHandler) { - return new ResolvablePayload.Handler<>(null, actualHandler, (server, handler, payload, responseSender) -> { - actualHandler.receive(server, handler, ((UntypedPayload) payload).buffer(), responseSender); - }); - } - - @SuppressWarnings("unchecked") - private static ResolvablePayload.Handler wrapTyped(PacketType type, ConfigurationPacketHandler actualHandler) { - return new ResolvablePayload.Handler<>(type, actualHandler, (server, handler, payload, responseSender) -> { - T packet = (T) ((TypedPayload) payload).packet(); - actualHandler.receive(packet, handler, responseSender); - }); - } - - @Nullable - private static ConfigurationChannelHandler unwrapUntyped(@Nullable ResolvablePayload.Handler handler) { - if (handler == null) return null; - if (handler.actual() instanceof ConfigurationChannelHandler actual) return actual; - return null; - } - - @Nullable - @SuppressWarnings({"rawtypes", "unchecked"}) - private static ConfigurationPacketHandler unwrapTyped(@Nullable ResolvablePayload.Handler handler) { - if (handler == null) return null; - if (handler.actual() instanceof ConfigurationPacketHandler actual) return actual; - return null; - } - - @FunctionalInterface - public interface ConfigurationChannelHandler { - /** - * Handles an incoming packet. - * - *

This method is executed on {@linkplain io.netty.channel.EventLoop netty's event loops}. - * Modification to the game should be {@linkplain ThreadExecutor#submit(Runnable) scheduled} using the server instance from {@link ServerConfigurationNetworking#getServer(ServerConfigurationNetworkHandler)}. - * - *

An example usage of this is: - *

{@code
-		 * ServerConfigurationNetworking.registerReceiver(new Identifier("mymod", "boom"), (server, handler, buf, responseSender) -> {
-		 * 	boolean fire = buf.readBoolean();
-		 *
-		 * 	// All operations on the server must be executed on the server thread
-		 * 	server.execute(() -> {
-		 *
-		 * 	});
-		 * });
-		 * }
- * @param server the server - * @param handler the network handler that received this packet, representing the client who sent the packet - * @param buf the payload of the packet - * @param responseSender the packet sender - */ - void receive(MinecraftServer server, ServerConfigurationNetworkHandler handler, PacketByteBuf buf, PacketSender responseSender); - } - /** - * A thread-safe packet handler utilizing {@link FabricPacket}. + * A packet handler utilizing {@link CustomPayload}. * @param the type of the packet */ @FunctionalInterface - public interface ConfigurationPacketHandler { + public interface ConfigurationPacketHandler { /** * Handles an incoming packet. * - *

Unlike {@link ServerPlayNetworking.PlayPacketHandler} this method is executed on {@linkplain io.netty.channel.EventLoop netty's event loops}. + *

Unlike {@link ServerPlayNetworking.PlayPayloadHandler} this method is executed on {@linkplain io.netty.channel.EventLoop netty's event loops}. * Modification to the game should be {@linkplain ThreadExecutor#submit(Runnable) scheduled} using the Minecraft server instance from {@link ServerConfigurationNetworking#getServer(ServerConfigurationNetworkHandler)}. * *

An example usage of this: @@ -427,11 +259,23 @@ public final class ServerConfigurationNetworking { * } * * - * @param packet the packet - * @param networkHandler the network handler - * @param responseSender the packet sender - * @see FabricPacket + * @param payload the packet payload + * @param context the configuration networking context + * @see CustomPayload */ - void receive(T packet, ServerConfigurationNetworkHandler networkHandler, PacketSender responseSender); + void receive(T payload, Context context); + } + + @ApiStatus.NonExtendable + public interface Context { + /** + * @return The ServerConfigurationNetworkHandler instance + */ + ServerConfigurationNetworkHandler networkHandler(); + + /** + * @return The packet sender + */ + PacketSender responseSender(); } } diff --git a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/api/networking/v1/ServerLoginConnectionEvents.java b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/api/networking/v1/ServerLoginConnectionEvents.java index bee731ae2..935f747ae 100644 --- a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/api/networking/v1/ServerLoginConnectionEvents.java +++ b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/api/networking/v1/ServerLoginConnectionEvents.java @@ -44,7 +44,7 @@ public final class ServerLoginConnectionEvents { * using {@link ServerLoginNetworking#registerReceiver(ServerLoginNetworkHandler, Identifier, ServerLoginNetworking.LoginQueryResponseHandler)} * since this event is fired just before the first login query response is processed. * - *

You may send login queries to the connected client using the provided {@link PacketSender}. + *

You may send login queries to the connected client using the provided {@link LoginPacketSender}. */ public static final Event QUERY_START = EventFactory.createArrayBacked(QueryStart.class, callbacks -> (handler, server, sender, synchronizer) -> { for (QueryStart callback : callbacks) { @@ -79,7 +79,7 @@ public final class ServerLoginConnectionEvents { */ @FunctionalInterface public interface QueryStart { - void onLoginStart(ServerLoginNetworkHandler handler, MinecraftServer server, PacketSender sender, ServerLoginNetworking.LoginSynchronizer synchronizer); + void onLoginStart(ServerLoginNetworkHandler handler, MinecraftServer server, LoginPacketSender sender, ServerLoginNetworking.LoginSynchronizer synchronizer); } /** 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 4df25147e..addf7991a 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 @@ -19,46 +19,39 @@ package net.fabricmc.fabric.api.networking.v1; import java.util.Objects; import java.util.Set; +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; -import net.minecraft.network.PacketByteBuf; import net.minecraft.network.listener.ClientCommonPacketListener; +import net.minecraft.network.packet.CustomPayload; import net.minecraft.network.packet.Packet; -import net.minecraft.server.MinecraftServer; import net.minecraft.server.network.ServerPlayNetworkHandler; import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.util.Identifier; -import net.minecraft.util.thread.ThreadExecutor; -import net.fabricmc.fabric.impl.networking.payload.ResolvablePayload; -import net.fabricmc.fabric.impl.networking.payload.TypedPayload; -import net.fabricmc.fabric.impl.networking.payload.UntypedPayload; import net.fabricmc.fabric.impl.networking.server.ServerNetworkingImpl; -import net.fabricmc.fabric.impl.networking.server.ServerPlayNetworkAddon; /** * Offers access to play stage server-side networking functionalities. * *

Server-side networking functionalities include receiving serverbound packets, sending clientbound packets, and events related to server-side network handlers. + * Packets received by this class must be registered to {@link PayloadTypeRegistry#playC2S()} on both ends. + * Packets sent by this class must be registered to {@link PayloadTypeRegistry#playS2C()} on both ends. + * Packets must be registered before registering any receivers. * *

This class should be only used for the logical server. * *

Packet object-based API

* - *

This class provides a classic registration method, {@link #registerGlobalReceiver(Identifier, PlayChannelHandler)}, - * and a newer method utilizing packet objects, {@link #registerGlobalReceiver(PacketType, PlayPacketHandler)}. - * For most mods, using the newer method will improve the readability of the code by separating packet - * reading/writing code to a separate class. Additionally, the newer method executes the callback in the - * server thread, ensuring thread safety. For this reason using the newer method is highly recommended. - * The two methods are network-compatible with each other, so long as the buffer contents are read and written - * in the same order. + *

This class provides a registration method, utilizing packet objects, {@link #registerGlobalReceiver(CustomPayload.Id, PlayPayloadHandler)}. + * This handler executes the callback in the server thread, ensuring thread safety. * - *

The newer, packet object-based API involves three classes: + *

This payload object-based API involves three classes: * *

    - *
  • A class implementing {@link FabricPacket} that is "sent" over the network
  • - *
  • {@link PacketType} instance, which represents the packet's type (and its channel)
  • - *
  • {@link PlayPacketHandler}, which handles the packet (usually implemented as a functional interface)
  • + *
  • A class implementing {@link CustomPayload} that is "sent" over the network
  • + *
  • {@link CustomPayload.Type} instance, which represents the packet's type (and its codec)
  • + *
  • {@link PlayPayloadHandler}, which handles the packet (usually implemented as a functional interface)
  • *
* *

See the documentation on each class for more information. @@ -68,76 +61,37 @@ import net.fabricmc.fabric.impl.networking.server.ServerPlayNetworkAddon; */ public final class ServerPlayNetworking { /** - * Registers a handler to a channel. - * A global receiver is registered to all connections, in the present and future. - * - *

The handler runs on the network thread. After reading the buffer there, the world - * must be modified in the server thread by calling {@link ThreadExecutor#execute(Runnable)}. - * - *

If a handler is already registered to the {@code channel}, this method will return {@code false}, and no change will be made. - * Use {@link #unregisterReceiver(ServerPlayNetworkHandler, Identifier)} to unregister the existing handler. - * - *

For new code, {@link #registerGlobalReceiver(PacketType, PlayPacketHandler)} - * is preferred, as it is designed in a way that prevents thread safety issues. - * - * @param channelName the id of the channel - * @param channelHandler the handler - * @return false if a handler is already registered to the channel - * @see ServerPlayNetworking#unregisterGlobalReceiver(Identifier) - * @see ServerPlayNetworking#registerReceiver(ServerPlayNetworkHandler, Identifier, PlayChannelHandler) - */ - public static boolean registerGlobalReceiver(Identifier channelName, PlayChannelHandler channelHandler) { - return ServerNetworkingImpl.PLAY.registerGlobalReceiver(channelName, wrapUntyped(channelHandler)); - } - - /** - * Registers a handler for a packet type. + * Registers a handler for a payload type. * A global receiver is registered to all connections, in the present and future. * *

If a handler is already registered for the {@code type}, this method will return {@code false}, and no change will be made. - * Use {@link #unregisterReceiver(ServerPlayNetworkHandler, PacketType)} to unregister the existing handler. + * Use {@link #unregisterGlobalReceiver(Identifier)} to unregister the existing handler. * * @param type the packet type * @param handler the handler * @return {@code false} if a handler is already registered to the channel - * @see ServerPlayNetworking#unregisterGlobalReceiver(PacketType) - * @see ServerPlayNetworking#registerReceiver(ServerPlayNetworkHandler, PacketType, PlayPacketHandler) + * @throws IllegalArgumentException if the codec for {@code type} has not been {@linkplain PayloadTypeRegistry#playC2S() registered} yet + * @see ServerPlayNetworking#unregisterGlobalReceiver(Identifier) */ - public static boolean registerGlobalReceiver(PacketType type, PlayPacketHandler handler) { - return ServerNetworkingImpl.PLAY.registerGlobalReceiver(type.getId(), wrapTyped(type, handler)); + public static boolean registerGlobalReceiver(CustomPayload.Id type, PlayPayloadHandler handler) { + return ServerNetworkingImpl.PLAY.registerGlobalReceiver(type.id(), handler); } /** - * Removes the handler of a channel. + * Removes the handler for a payload type. * A global receiver is registered to all connections, in the present and future. * - *

The {@code channel} is guaranteed not to have a handler after this call. + *

The {@code id} is guaranteed not to have an associated handler after this call. * - * @param channelName the id of the channel - * @return the previous handler, or {@code null} if no handler was bound to the channel - * @see ServerPlayNetworking#registerGlobalReceiver(Identifier, PlayChannelHandler) + * @param id the payload id + * @return the previous handler, or {@code null} if no handler was bound to the channel, + * or it was not registered using {@link #registerGlobalReceiver(CustomPayload.Id, PlayPayloadHandler)} + * @see ServerPlayNetworking#registerGlobalReceiver(CustomPayload.Id, PlayPayloadHandler) * @see ServerPlayNetworking#unregisterReceiver(ServerPlayNetworkHandler, Identifier) */ @Nullable - public static PlayChannelHandler unregisterGlobalReceiver(Identifier channelName) { - return unwrapUntyped(ServerNetworkingImpl.PLAY.unregisterGlobalReceiver(channelName)); - } - - /** - * Removes the handler for a packet type. - * A global receiver is registered to all connections, in the present and future. - * - *

The {@code type} is guaranteed not to have an associated handler after this call. - * - * @param type the packet type - * @return the previous handler, or {@code null} if no handler was bound to the channel, - * or it was not registered using {@link #registerGlobalReceiver(PacketType, PlayPacketHandler)} - * @see ServerPlayNetworking#registerGlobalReceiver(PacketType, PlayPacketHandler) - * @see ServerPlayNetworking#unregisterReceiver(ServerPlayNetworkHandler, PacketType) - */ - @Nullable - public static PlayPacketHandler unregisterGlobalReceiver(PacketType type) { - return unwrapTyped(ServerNetworkingImpl.PLAY.unregisterGlobalReceiver(type.getId())); + public static ServerPlayNetworking.PlayPayloadHandler unregisterGlobalReceiver(Identifier id) { + return ServerNetworkingImpl.PLAY.unregisterGlobalReceiver(id); } /** @@ -151,82 +105,39 @@ public final class ServerPlayNetworking { } /** - * Registers a handler to a channel. - * This method differs from {@link ServerPlayNetworking#registerGlobalReceiver(Identifier, PlayChannelHandler)} since - * the channel handler will only be applied to the player represented by the {@link ServerPlayNetworkHandler}. - * - *

The handler runs on the network thread. After reading the buffer there, the world - * must be modified in the server thread by calling {@link ThreadExecutor#execute(Runnable)}. - * - *

For example, if you only register a receiver using this method when a {@linkplain ServerLoginNetworking#registerGlobalReceiver(Identifier, ServerLoginNetworking.LoginQueryResponseHandler)} - * login response has been received, you should use {@link ServerPlayConnectionEvents#INIT} to register the channel handler. - * - *

If a handler is already registered to the {@code channelName}, this method will return {@code false}, and no change will be made. - * Use {@link #unregisterReceiver(ServerPlayNetworkHandler, Identifier)} to unregister the existing handler. - * - *

For new code, {@link #registerReceiver(ServerPlayNetworkHandler, PacketType, PlayPacketHandler)} - * is preferred, as it is designed in a way that prevents thread safety issues. - * - * @param networkHandler the handler - * @param channelName the id of the channel - * @param channelHandler the handler - * @return false if a handler is already registered to the channel name - * @see ServerPlayConnectionEvents#INIT - */ - public static boolean registerReceiver(ServerPlayNetworkHandler networkHandler, Identifier channelName, PlayChannelHandler channelHandler) { - Objects.requireNonNull(networkHandler, "Network handler cannot be null"); - - return ServerNetworkingImpl.getAddon(networkHandler).registerChannel(channelName, wrapUntyped(channelHandler)); - } - - /** - * Registers a handler for a packet type. - * This method differs from {@link ServerPlayNetworking#registerGlobalReceiver(PacketType, PlayPacketHandler)} since + * Registers a handler for a payload type. + * This method differs from {@link ServerPlayNetworking#registerGlobalReceiver(CustomPayload.Id, PlayPayloadHandler)} since * the channel handler will only be applied to the player represented by the {@link ServerPlayNetworkHandler}. * *

For example, if you only register a receiver using this method when a {@linkplain ServerLoginNetworking#registerGlobalReceiver(Identifier, ServerLoginNetworking.LoginQueryResponseHandler)} * login response has been received, you should use {@link ServerPlayConnectionEvents#INIT} to register the channel handler. * *

If a handler is already registered for the {@code type}, this method will return {@code false}, and no change will be made. - * Use {@link #unregisterReceiver(ServerPlayNetworkHandler, PacketType)} to unregister the existing handler. + * Use {@link #unregisterReceiver(ServerPlayNetworkHandler, Identifier)} to unregister the existing handler. * * @param networkHandler the network handler * @param type the packet type * @param handler the handler * @return {@code false} if a handler is already registered to the channel name + * @throws IllegalArgumentException if the codec for {@code type} has not been {@linkplain PayloadTypeRegistry#playC2S() registered} yet * @see ServerPlayConnectionEvents#INIT */ - public static boolean registerReceiver(ServerPlayNetworkHandler networkHandler, PacketType type, PlayPacketHandler handler) { - return ServerNetworkingImpl.getAddon(networkHandler).registerChannel(type.getId(), wrapTyped(type, handler)); - } - - /** - * Removes the handler of a channel. - * - *

The {@code channelName} is guaranteed not to have a handler after this call. - * - * @param channelName the id of the channel - * @return the previous handler, or {@code null} if no handler was bound to the channel name - */ - @Nullable - public static PlayChannelHandler unregisterReceiver(ServerPlayNetworkHandler networkHandler, Identifier channelName) { - Objects.requireNonNull(networkHandler, "Network handler cannot be null"); - - return unwrapUntyped(ServerNetworkingImpl.getAddon(networkHandler).unregisterChannel(channelName)); + public static boolean registerReceiver(ServerPlayNetworkHandler networkHandler, CustomPayload.Id type, PlayPayloadHandler handler) { + return ServerNetworkingImpl.getAddon(networkHandler).registerChannel(type.id(), handler); } /** * Removes the handler for a packet type. * - *

The {@code type} is guaranteed not to have an associated handler after this call. + *

The {@code id} is guaranteed not to have an associated handler after this call. * - * @param type the type of the packet + * @param id the id of the payload * @return the previous handler, or {@code null} if no handler was bound to the channel, - * or it was not registered using {@link #registerReceiver(ServerPlayNetworkHandler, PacketType, PlayPacketHandler)} + * or it was not registered using {@link #registerReceiver(ServerPlayNetworkHandler, CustomPayload.Id, PlayPayloadHandler)} */ @Nullable - public static PlayPacketHandler unregisterReceiver(ServerPlayNetworkHandler networkHandler, PacketType type) { - return unwrapTyped(ServerNetworkingImpl.getAddon(networkHandler).unregisterChannel(type.getId())); + public static ServerPlayNetworking.PlayPayloadHandler unregisterReceiver(ServerPlayNetworkHandler networkHandler, Identifier id) { + return ServerNetworkingImpl.getAddon(networkHandler).unregisterChannel(id); } /** @@ -297,10 +208,10 @@ public final class ServerPlayNetworking { * @param type the packet type * @return {@code true} if the connected client has declared the ability to receive a specific type of packet */ - public static boolean canSend(ServerPlayerEntity player, PacketType type) { + public static boolean canSend(ServerPlayerEntity player, CustomPayload.Id type) { Objects.requireNonNull(player, "Server player entity cannot be null"); - return canSend(player.networkHandler, type.getId()); + return canSend(player.networkHandler, type.id()); } /** @@ -324,34 +235,20 @@ public final class ServerPlayNetworking { * @param type the packet type * @return {@code true} if the connected client has declared the ability to receive a specific type of packet */ - public static boolean canSend(ServerPlayNetworkHandler handler, PacketType type) { + public static boolean canSend(ServerPlayNetworkHandler handler, CustomPayload.Id type) { Objects.requireNonNull(handler, "Server play network handler cannot be null"); Objects.requireNonNull(type, "Packet type cannot be null"); - return ServerNetworkingImpl.getAddon(handler).getSendableChannels().contains(type.getId()); + return ServerNetworkingImpl.getAddon(handler).getSendableChannels().contains(type.id()); } /** * Creates a packet which may be sent to a connected client. * - * @param channelName the channel name - * @param buf the packet byte buf which represents the payload of the packet + * @param packet the packet * @return a new packet */ - public static Packet createS2CPacket(Identifier channelName, PacketByteBuf buf) { - Objects.requireNonNull(channelName, "Channel cannot be null"); - Objects.requireNonNull(buf, "Buf cannot be null"); - - return ServerNetworkingImpl.createS2CPacket(channelName, buf); - } - - /** - * Creates a packet which may be sent to a connected client. - * - * @param packet the fabric packet - * @return a new packet - */ - public static Packet createS2CPacket(T packet) { + public static Packet createS2CPacket(T packet) { return ServerNetworkingImpl.createS2CPacket(packet); } @@ -382,142 +279,60 @@ public final class ServerPlayNetworking { /** * Sends a packet to a player. * - * @param player the player to send the packet to - * @param channelName the channel of the packet - * @param buf the payload of the packet. - */ - public static void send(ServerPlayerEntity player, Identifier channelName, PacketByteBuf buf) { - Objects.requireNonNull(player, "Server player entity cannot be null"); - Objects.requireNonNull(channelName, "Channel name cannot be null"); - Objects.requireNonNull(buf, "Packet byte buf cannot be null"); - - player.networkHandler.sendPacket(createS2CPacket(channelName, buf)); - } - - /** - * Sends a packet to a player. + *

Any packets sent must be {@linkplain PayloadTypeRegistry#playS2C() registered}.

* * @param player the player to send the packet to - * @param packet the packet + * @param payload the payload to send */ - public static void send(ServerPlayerEntity player, T packet) { + public static void send(ServerPlayerEntity player, CustomPayload payload) { Objects.requireNonNull(player, "Server player entity cannot be null"); - Objects.requireNonNull(packet, "Packet cannot be null"); - Objects.requireNonNull(packet.getType(), "Packet#getType cannot return null"); + Objects.requireNonNull(payload, "Payload cannot be null"); + Objects.requireNonNull(payload.getId(), "CustomPayload#getId() cannot return null for payload class: " + payload.getClass()); - player.networkHandler.sendPacket(createS2CPacket(packet)); - } - - // Helper methods - - /** - * Returns the Minecraft Server of a server play network handler. - * - * @param handler the server play network handler - */ - public static MinecraftServer getServer(ServerPlayNetworkHandler handler) { - Objects.requireNonNull(handler, "Network handler cannot be null"); - - return handler.player.server; + player.networkHandler.sendPacket(createS2CPacket(payload)); } private ServerPlayNetworking() { } - private static ResolvablePayload.Handler wrapUntyped(PlayChannelHandler actualHandler) { - return new ResolvablePayload.Handler<>(null, actualHandler, (server, player, handler, payload, responseSender) -> { - actualHandler.receive(server, player, handler, ((UntypedPayload) payload).buffer(), responseSender); - }); - } - - @SuppressWarnings("unchecked") - private static ResolvablePayload.Handler wrapTyped(PacketType type, PlayPacketHandler actualHandler) { - return new ResolvablePayload.Handler<>(type, actualHandler, (server, player, handler, payload, responseSender) -> { - T packet = (T) ((TypedPayload) payload).packet(); - - if (server.isOnThread()) { - // Do not submit to the server thread if we're already running there. - // Normally, packets are handled on the network IO thread - though it is - // not guaranteed (for example, with 1.19.4 S2C packet bundling) - // Since we're handling it right now, connection check is redundant. - actualHandler.receive(packet, player, responseSender); - } else { - server.execute(() -> { - if (handler.isConnectionOpen()) actualHandler.receive(packet, player, responseSender); - }); - } - }); - } - - @Nullable - private static PlayChannelHandler unwrapUntyped(@Nullable ResolvablePayload.Handler handler) { - if (handler == null) return null; - if (handler.actual() instanceof PlayChannelHandler actual) return actual; - return null; - } - - @Nullable - @SuppressWarnings({"rawtypes", "unchecked"}) - private static PlayPacketHandler unwrapTyped(@Nullable ResolvablePayload.Handler handler) { - if (handler == null) return null; - if (handler.actual() instanceof PlayPacketHandler actual) return actual; - return null; - } - - @FunctionalInterface - public interface PlayChannelHandler { - /** - * Handles an incoming packet. - * - *

This method is executed on {@linkplain io.netty.channel.EventLoop netty's event loops}. - * Modification to the game should be {@linkplain ThreadExecutor#submit(Runnable) scheduled} using the provided Minecraft server instance. - * - *

An example usage of this is to create an explosion where the player is looking: - *

{@code
-		 * ServerPlayNetworking.registerReceiver(new Identifier("mymod", "boom"), (server, player, handler, buf, responseSender) -> {
-		 * 	boolean fire = buf.readBoolean();
-		 *
-		 * 	// All operations on the server or world must be executed on the server thread
-		 * 	server.execute(() -> {
-		 * 		ModPacketHandler.createExplosion(player, fire);
-		 * 	});
-		 * });
-		 * }
- * @param server the server - * @param player the player - * @param handler the network handler that received this packet, representing the player/client who sent the packet - * @param buf the payload of the packet - * @param responseSender the packet sender - */ - void receive(MinecraftServer server, ServerPlayerEntity player, ServerPlayNetworkHandler handler, PacketByteBuf buf, PacketSender responseSender); - } - /** - * A thread-safe packet handler utilizing {@link FabricPacket}. + * A thread-safe packet handler utilizing {@link CustomPayload}. * @param the type of the packet */ @FunctionalInterface - public interface PlayPacketHandler { + public interface PlayPayloadHandler { /** * Handles the incoming packet. This is called on the server thread, and can safely * manipulate the world. * *

An example usage of this is to create an explosion where the player is looking: *

{@code
-		 * // See FabricPacket for creating the packet
-		 * ServerPlayNetworking.registerReceiver(BOOM_PACKET_TYPE, (player, packet, responseSender) -> {
-		 * 	ModPacketHandler.createExplosion(player, packet.fire());
+		 * // use PayloadTypeRegistry for registering the payload
+		 * ServerPlayNetworking.registerReceiver(BoomPayload.ID, (payload, player, responseSender) -> {
+		 * 	ModPacketHandler.createExplosion(player, payload.fire());
 		 * });
 		 * }
* *

The server and the network handler can be accessed via {@link ServerPlayerEntity#server} * and {@link ServerPlayerEntity#networkHandler}, respectively. * - * @param packet the packet - * @param player the player that received the packet - * @param responseSender the packet sender - * @see FabricPacket + * @param payload the packet payload + * @param context the play networking context + * @see CustomPayload */ - void receive(T packet, ServerPlayerEntity player, PacketSender responseSender); + void receive(T payload, Context context); + } + + @ApiStatus.NonExtendable + public interface Context { + /** + * @return The player that received the packet + */ + ServerPlayerEntity player(); + + /** + * @return The packet sender + */ + PacketSender responseSender(); } } diff --git a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/api/networking/v1/package-info.java b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/api/networking/v1/package-info.java index 551640433..cdba7d5db 100644 --- a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/api/networking/v1/package-info.java +++ b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/api/networking/v1/package-info.java @@ -44,7 +44,7 @@ * * *

In addition, this API includes helpers for {@linkplain - * net.fabricmc.fabric.api.networking.v1.PacketByteBufs buffer creations} and {@linkplain + * net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry registering custom packet payloads} and {@linkplain * net.fabricmc.fabric.api.networking.v1.PlayerLookup player lookups}. */ 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 4605a0e52..089b1221d 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 @@ -16,7 +16,6 @@ package net.fabricmc.fabric.impl.networking; -import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -25,46 +24,39 @@ import java.util.List; import java.util.Objects; import java.util.Set; -import io.netty.util.AsciiString; -import io.netty.util.concurrent.Future; -import io.netty.util.concurrent.GenericFutureListener; import org.jetbrains.annotations.Nullable; import net.minecraft.network.ClientConnection; -import net.minecraft.network.NetworkState; -import net.minecraft.network.PacketByteBuf; +import net.minecraft.network.NetworkPhase; import net.minecraft.network.PacketCallbacks; +import net.minecraft.network.packet.CustomPayload; import net.minecraft.network.packet.Packet; +import net.minecraft.text.Text; import net.minecraft.util.Identifier; -import net.minecraft.util.InvalidIdentifierException; -import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; import net.fabricmc.fabric.api.networking.v1.PacketSender; -import net.fabricmc.fabric.impl.networking.payload.ResolvablePayload; -import net.fabricmc.fabric.impl.networking.payload.ResolvedPayload; -import net.fabricmc.fabric.impl.networking.payload.UntypedPayload; /** * A network addon which is aware of the channels the other side may receive. * * @param the channel handler type */ -public abstract class AbstractChanneledNetworkAddon extends AbstractNetworkAddon> implements PacketSender, CommonPacketHandler { +public abstract class AbstractChanneledNetworkAddon extends AbstractNetworkAddon implements PacketSender, CommonPacketHandler { protected final ClientConnection connection; - protected final GlobalReceiverRegistry> receiver; + protected final GlobalReceiverRegistry receiver; protected final Set sendableChannels; protected int commonVersion = -1; - protected AbstractChanneledNetworkAddon(GlobalReceiverRegistry> receiver, ClientConnection connection, String description) { + protected AbstractChanneledNetworkAddon(GlobalReceiverRegistry receiver, ClientConnection connection, String description) { super(receiver, description); this.connection = connection; this.receiver = receiver; this.sendableChannels = Collections.synchronizedSet(new HashSet<>()); } - protected void registerPendingChannels(ChannelInfoHolder holder, NetworkState state) { - final Collection pending = holder.getPendingChannelsNames(state); + protected void registerPendingChannels(ChannelInfoHolder holder, NetworkPhase state) { + final Collection pending = holder.fabric_getPendingChannelsNames(state); if (!pending.isEmpty()) { register(new ArrayList<>(pending)); @@ -73,30 +65,31 @@ public abstract class AbstractChanneledNetworkAddon extends AbstractNetworkAd } // always supposed to handle async! - public boolean handle(ResolvablePayload resolvable) { - Identifier channelName = resolvable.id(); + public boolean handle(CustomPayload payload) { + final Identifier channelName = payload.getId().id(); this.logger.debug("Handling inbound packet from channel with name \"{}\"", channelName); // Handle reserved packets - if (NetworkingImpl.REGISTER_CHANNEL.equals(channelName)) { - this.receiveRegistration(true, resolvable); - return true; + if (payload instanceof RegistrationPayload registrationPayload) { + if (NetworkingImpl.REGISTER_CHANNEL.equals(channelName)) { + this.receiveRegistration(true, registrationPayload); + return true; + } + + if (NetworkingImpl.UNREGISTER_CHANNEL.equals(channelName)) { + this.receiveRegistration(false, registrationPayload); + return true; + } } - if (NetworkingImpl.UNREGISTER_CHANNEL.equals(channelName)) { - this.receiveRegistration(false, resolvable); - return true; - } - - @Nullable ResolvablePayload.Handler handler = this.getHandler(channelName); + @Nullable H handler = this.getHandler(channelName); if (handler == null) { return false; } try { - ResolvedPayload resolved = resolvable.resolve(handler.type()); - this.receive(handler.internal(), resolved); + this.receive(handler, payload); } catch (Throwable ex) { this.logger.error("Encountered exception while handling in channel with name \"{}\"", channelName, ex); throw ex; @@ -105,63 +98,31 @@ public abstract class AbstractChanneledNetworkAddon extends AbstractNetworkAd return true; } - protected abstract void receive(H handler, ResolvedPayload payload); + protected abstract void receive(H handler, CustomPayload payload); protected void sendInitialChannelRegistrationPacket() { - final PacketByteBuf buf = this.createRegistrationPacket(this.getReceivableChannels()); + final RegistrationPayload payload = createRegistrationPayload(RegistrationPayload.REGISTER, this.getReceivableChannels()); - if (buf != null) { - this.sendPacket(NetworkingImpl.REGISTER_CHANNEL, buf); + if (payload != null) { + this.sendPacket(payload); } } @Nullable - protected PacketByteBuf createRegistrationPacket(Collection channels) { + protected RegistrationPayload createRegistrationPayload(CustomPayload.Id id, Collection channels) { if (channels.isEmpty()) { return null; } - PacketByteBuf buf = PacketByteBufs.create(); - boolean first = true; - - for (Identifier channel : channels) { - if (first) { - first = false; - } else { - buf.writeByte(0); - } - - buf.writeBytes(channel.toString().getBytes(StandardCharsets.US_ASCII)); - } - - return buf; + return new RegistrationPayload(id, new ArrayList<>(channels)); } // wrap in try with res (buf) - protected void receiveRegistration(boolean register, ResolvablePayload resolvable) { - UntypedPayload payload = (UntypedPayload) resolvable.resolve(null); - PacketByteBuf buf = payload.buffer(); - - List ids = new ArrayList<>(); - StringBuilder active = new StringBuilder(); - - while (buf.isReadable()) { - byte b = buf.readByte(); - - if (b != 0) { - active.append(AsciiString.b2c(b)); - } else { - this.addId(ids, active); - active = new StringBuilder(); - } - } - - this.addId(ids, active); - + protected void receiveRegistration(boolean register, RegistrationPayload payload) { if (register) { - register(ids); + register(payload.channels()); } else { - unregister(ids); + unregister(payload.channels()); } } @@ -175,11 +136,6 @@ public abstract class AbstractChanneledNetworkAddon extends AbstractNetworkAd schedule(() -> this.invokeUnregisterEvent(ids)); } - @Override - public void sendPacket(Packet packet, @Nullable GenericFutureListener> callback) { - sendPacket(packet, GenericFutureListenerHolder.create(callback)); - } - @Override public void sendPacket(Packet packet, PacketCallbacks callback) { Objects.requireNonNull(packet, "Packet cannot be null"); @@ -187,6 +143,13 @@ public abstract class AbstractChanneledNetworkAddon extends AbstractNetworkAd this.connection.send(packet, callback); } + @Override + public void disconnect(Text disconnectReason) { + Objects.requireNonNull(disconnectReason, "Disconnect reason cannot be null"); + + this.connection.disconnect(disconnectReason); + } + /** * Schedules a task to run on the main thread. */ @@ -196,16 +159,6 @@ public abstract class AbstractChanneledNetworkAddon extends AbstractNetworkAd protected abstract void invokeUnregisterEvent(List ids); - private void addId(List ids, StringBuilder sb) { - String literal = sb.toString(); - - try { - ids.add(new Identifier(literal)); - } catch (InvalidIdentifierException ex) { - this.logger.warn("Received invalid channel identifier \"{}\" from connection {}", literal, this.connection); - } - } - public Set getSendableChannels() { return Collections.unmodifiableSet(this.sendableChannels); } @@ -231,7 +184,7 @@ public abstract class AbstractChanneledNetworkAddon extends AbstractNetworkAd if (currentPhase == null) { // We don't support receiving the register packet during this phase. See getPhase() for supported phases. // The normal case where the play channels are sent during configuration is handled in the client/common configuration packet handlers. - logger.warn("Received common register packet for phase {} in network state: {}", payload.phase(), receiver.getState()); + logger.warn("Received common register packet for phase {} in network state: {}", payload.phase(), receiver.getPhase()); return; } @@ -259,7 +212,7 @@ public abstract class AbstractChanneledNetworkAddon extends AbstractNetworkAd @Nullable private String getPhase() { - return switch (receiver.getState()) { + return switch (receiver.getPhase()) { case PLAY -> CommonRegisterPayload.PLAY_PHASE; case CONFIGURATION -> CommonRegisterPayload.CONFIGURATION_PHASE; default -> null; // We don't support receiving this packet on any other phase 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 c4057f878..3ce0a675c 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 @@ -102,6 +102,8 @@ public abstract class AbstractNetworkAddon { Objects.requireNonNull(handler, "Packet handler cannot be null"); assertNotReserved(channelName); + receiver.assertPayloadType(channelName); + Lock lock = this.lock.writeLock(); lock.lock(); diff --git a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/ChannelInfoHolder.java b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/ChannelInfoHolder.java index e86717d11..3a744519e 100644 --- a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/ChannelInfoHolder.java +++ b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/ChannelInfoHolder.java @@ -18,12 +18,12 @@ package net.fabricmc.fabric.impl.networking; import java.util.Collection; -import net.minecraft.network.NetworkState; +import net.minecraft.network.NetworkPhase; import net.minecraft.util.Identifier; public interface ChannelInfoHolder { /** * @return Channels which are declared as receivable by the other side but have not been declared yet. */ - Collection getPendingChannelsNames(NetworkState state); + Collection fabric_getPendingChannelsNames(NetworkPhase state); } diff --git a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/CommonPacketsImpl.java b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/CommonPacketsImpl.java index 66a0052ef..289e5d2e4 100644 --- a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/CommonPacketsImpl.java +++ b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/CommonPacketsImpl.java @@ -19,12 +19,14 @@ package net.fabricmc.fabric.impl.networking; import java.util.Arrays; import java.util.function.Consumer; -import net.minecraft.network.NetworkState; +import net.minecraft.network.NetworkPhase; import net.minecraft.network.packet.Packet; import net.minecraft.server.network.ServerPlayerConfigurationTask; +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.api.networking.v1.ServerPlayNetworking; import net.fabricmc.fabric.impl.networking.server.ServerConfigurationNetworkAddon; import net.fabricmc.fabric.impl.networking.server.ServerNetworkingImpl; @@ -33,16 +35,23 @@ public class CommonPacketsImpl { public static final int[] SUPPORTED_COMMON_PACKET_VERSIONS = new int[]{ PACKET_VERSION_1 }; public static void init() { - ServerConfigurationNetworking.registerGlobalReceiver(CommonVersionPayload.PACKET_ID, (server, handler, buf, responseSender) -> { - var payload = new CommonVersionPayload(buf); - ServerConfigurationNetworkAddon addon = ServerNetworkingImpl.getAddon(handler); + PayloadTypeRegistry.configurationC2S().register(CommonVersionPayload.ID, CommonVersionPayload.CODEC); + PayloadTypeRegistry.configurationS2C().register(CommonVersionPayload.ID, CommonVersionPayload.CODEC); + PayloadTypeRegistry.playC2S().register(CommonVersionPayload.ID, CommonVersionPayload.CODEC); + PayloadTypeRegistry.playS2C().register(CommonVersionPayload.ID, CommonVersionPayload.CODEC); + PayloadTypeRegistry.configurationC2S().register(CommonRegisterPayload.ID, CommonRegisterPayload.CODEC); + PayloadTypeRegistry.configurationS2C().register(CommonRegisterPayload.ID, CommonRegisterPayload.CODEC); + PayloadTypeRegistry.playC2S().register(CommonRegisterPayload.ID, CommonRegisterPayload.CODEC); + PayloadTypeRegistry.playS2C().register(CommonRegisterPayload.ID, CommonRegisterPayload.CODEC); + + ServerConfigurationNetworking.registerGlobalReceiver(CommonVersionPayload.ID, (payload, context) -> { + ServerConfigurationNetworkAddon addon = ServerNetworkingImpl.getAddon(context.networkHandler()); addon.onCommonVersionPacket(getNegotiatedVersion(payload)); - handler.completeTask(CommonVersionConfigurationTask.KEY); + context.networkHandler().completeTask(CommonVersionConfigurationTask.KEY); }); - ServerConfigurationNetworking.registerGlobalReceiver(CommonRegisterPayload.PACKET_ID, (server, handler, buf, responseSender) -> { - var payload = new CommonRegisterPayload(buf); - ServerConfigurationNetworkAddon addon = ServerNetworkingImpl.getAddon(handler); + ServerConfigurationNetworking.registerGlobalReceiver(CommonRegisterPayload.ID, (payload, context) -> { + ServerConfigurationNetworkAddon addon = ServerNetworkingImpl.getAddon(context.networkHandler()); if (CommonRegisterPayload.PLAY_PHASE.equals(payload.phase())) { if (payload.version() != addon.getNegotiatedVersion()) { @@ -50,24 +59,24 @@ public class CommonPacketsImpl { } // Play phase hasnt started yet, add them to the pending names. - addon.getChannelInfoHolder().getPendingChannelsNames(NetworkState.PLAY).addAll(payload.channels()); + addon.getChannelInfoHolder().fabric_getPendingChannelsNames(NetworkPhase.PLAY).addAll(payload.channels()); NetworkingImpl.LOGGER.debug("Received accepted channels from the client for play phase"); } else { addon.onCommonRegisterPacket(payload); } - handler.completeTask(CommonRegisterConfigurationTask.KEY); + context.networkHandler().completeTask(CommonRegisterConfigurationTask.KEY); }); // Create a configuration task to send and receive the common packets ServerConfigurationConnectionEvents.CONFIGURE.register((handler, server) -> { final ServerConfigurationNetworkAddon addon = ServerNetworkingImpl.getAddon(handler); - if (ServerConfigurationNetworking.canSend(handler, CommonVersionPayload.PACKET_ID)) { + if (ServerConfigurationNetworking.canSend(handler, CommonVersionPayload.ID)) { // Tasks are processed in order. handler.addTask(new CommonVersionConfigurationTask(addon)); - if (ServerConfigurationNetworking.canSend(handler, CommonRegisterPayload.PACKET_ID)) { + if (ServerConfigurationNetworking.canSend(handler, CommonRegisterPayload.ID)) { handler.addTask(new CommonRegisterConfigurationTask(addon)); } } @@ -76,7 +85,7 @@ public class CommonPacketsImpl { // A configuration phase task to send and receive the version packets. private record CommonVersionConfigurationTask(ServerConfigurationNetworkAddon addon) implements ServerPlayerConfigurationTask { - public static final Key KEY = new Key(CommonVersionPayload.PACKET_ID.toString()); + public static final Key KEY = new Key(CommonVersionPayload.ID.id().toString()); @Override public void sendPacket(Consumer> sender) { @@ -91,11 +100,11 @@ public class CommonPacketsImpl { // A configuration phase task to send and receive the registration packets. private record CommonRegisterConfigurationTask(ServerConfigurationNetworkAddon addon) implements ServerPlayerConfigurationTask { - public static final Key KEY = new Key(CommonRegisterPayload.PACKET_ID.toString()); + public static final Key KEY = new Key(CommonRegisterPayload.ID.id().toString()); @Override public void sendPacket(Consumer> sender) { - addon.sendPacket(addon.createRegisterPayload()); + addon.sendPacket(new CommonRegisterPayload(addon.getNegotiatedVersion(), CommonRegisterPayload.PLAY_PHASE, ServerPlayNetworking.getGlobalReceivers())); } @Override diff --git a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/CommonRegisterPayload.java b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/CommonRegisterPayload.java index 071f5568e..7a3a2c895 100644 --- a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/CommonRegisterPayload.java +++ b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/CommonRegisterPayload.java @@ -20,16 +20,18 @@ import java.util.HashSet; import java.util.Set; import net.minecraft.network.PacketByteBuf; +import net.minecraft.network.codec.PacketCodec; import net.minecraft.network.packet.CustomPayload; import net.minecraft.util.Identifier; public record CommonRegisterPayload(int version, String phase, Set channels) implements CustomPayload { - public static final Identifier PACKET_ID = new Identifier("c", "register"); + public static final CustomPayload.Id ID = CustomPayload.id("c:register"); + public static final PacketCodec CODEC = CustomPayload.codecOf(CommonRegisterPayload::write, CommonRegisterPayload::new); public static final String PLAY_PHASE = "play"; public static final String CONFIGURATION_PHASE = "configuration"; - public CommonRegisterPayload(PacketByteBuf buf) { + private CommonRegisterPayload(PacketByteBuf buf) { this( buf.readVarInt(), buf.readString(), @@ -37,7 +39,6 @@ public record CommonRegisterPayload(int version, String phase, Set c ); } - @Override public void write(PacketByteBuf buf) { buf.writeVarInt(version); buf.writeString(phase); @@ -45,7 +46,7 @@ public record CommonRegisterPayload(int version, String phase, Set c } @Override - public Identifier id() { - return PACKET_ID; + public Id getId() { + return ID; } } diff --git a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/CommonVersionPayload.java b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/CommonVersionPayload.java index a319b487e..c900b4ee6 100644 --- a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/CommonVersionPayload.java +++ b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/CommonVersionPayload.java @@ -17,23 +17,23 @@ package net.fabricmc.fabric.impl.networking; import net.minecraft.network.PacketByteBuf; +import net.minecraft.network.codec.PacketCodec; import net.minecraft.network.packet.CustomPayload; -import net.minecraft.util.Identifier; public record CommonVersionPayload(int[] versions) implements CustomPayload { - public static final Identifier PACKET_ID = new Identifier("c", "version"); + public static final PacketCodec CODEC = CustomPayload.codecOf(CommonVersionPayload::write, CommonVersionPayload::new); + public static final CustomPayload.Id ID = CustomPayload.id("c:version"); - public CommonVersionPayload(PacketByteBuf buf) { + private CommonVersionPayload(PacketByteBuf buf) { this(buf.readIntArray()); } - @Override public void write(PacketByteBuf buf) { buf.writeIntArray(versions); } @Override - public Identifier id() { - return PACKET_ID; + public Id getId() { + return ID; } } diff --git a/deprecated/fabric-containers-v0/src/main/java/net/fabricmc/fabric/impl/container/ServerPlayerEntitySyncHook.java b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/CustomPayloadTypeProvider.java similarity index 63% rename from deprecated/fabric-containers-v0/src/main/java/net/fabricmc/fabric/impl/container/ServerPlayerEntitySyncHook.java rename to fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/CustomPayloadTypeProvider.java index 9f0117590..157a63d2d 100644 --- a/deprecated/fabric-containers-v0/src/main/java/net/fabricmc/fabric/impl/container/ServerPlayerEntitySyncHook.java +++ b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/CustomPayloadTypeProvider.java @@ -14,16 +14,12 @@ * limitations under the License. */ -package net.fabricmc.fabric.impl.container; +package net.fabricmc.fabric.impl.networking; -/** - * This is a interface that is present on a ServerPlayerEntity, it allows access to the sync id. - */ -public interface ServerPlayerEntitySyncHook { - /** - * Gets and sets the new player sync id, and returns the new value. - * - * @return the new sync id of the player - */ - int fabric_incrementSyncId(); +import net.minecraft.network.PacketByteBuf; +import net.minecraft.network.packet.CustomPayload; +import net.minecraft.util.Identifier; + +public interface CustomPayloadTypeProvider { + CustomPayload.Type get(B packetByteBuf, Identifier identifier); } diff --git a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/payload/ResolvedPayload.java b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/FabricCustomPayloadPacketCodec.java similarity index 70% rename from fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/payload/ResolvedPayload.java rename to fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/FabricCustomPayloadPacketCodec.java index 04b5e7d33..40382170e 100644 --- a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/payload/ResolvedPayload.java +++ b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/FabricCustomPayloadPacketCodec.java @@ -14,7 +14,10 @@ * limitations under the License. */ -package net.fabricmc.fabric.impl.networking.payload; +package net.fabricmc.fabric.impl.networking; -public sealed interface ResolvedPayload extends ResolvablePayload permits TypedPayload, UntypedPayload { +import net.minecraft.network.PacketByteBuf; + +public interface FabricCustomPayloadPacketCodec { + void fabric_setPacketCodecProvider(CustomPayloadTypeProvider customPayloadTypeProvider); } diff --git a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/GenericFutureListenerHolder.java b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/GenericFutureListenerHolder.java deleted file mode 100644 index 239d587fa..000000000 --- a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/GenericFutureListenerHolder.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * 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.networking; - -import java.util.Objects; - -import io.netty.util.concurrent.Future; -import io.netty.util.concurrent.GenericFutureListener; -import org.jetbrains.annotations.Nullable; - -import net.minecraft.network.ClientConnection; -import net.minecraft.network.PacketCallbacks; -import net.minecraft.network.packet.Packet; - -/** - * We still need to support {@link GenericFutureListener} so we use this disguise impl {@link PacketCallbacks} - * to get our {@link GenericFutureListener} to into {@link ClientConnection}. - */ -public final class GenericFutureListenerHolder implements PacketCallbacks { - private final GenericFutureListener> delegate; - - private GenericFutureListenerHolder(GenericFutureListener> delegate) { - this.delegate = Objects.requireNonNull(delegate); - } - - @Nullable - public static GenericFutureListenerHolder create(@Nullable GenericFutureListener> delegate) { - if (delegate == null) { - return null; - } - - return new GenericFutureListenerHolder(delegate); - } - - public GenericFutureListener> getDelegate() { - return delegate; - } - - @Override - public void onSuccess() { - throw new AssertionError("Should not be called"); - } - - @Nullable - @Override - public Packet getFailurePacket() { - throw new AssertionError("Should not be called"); - } -} diff --git a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/GlobalReceiverRegistry.java b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/GlobalReceiverRegistry.java index 8f1cf1de7..5cbc025f2 100644 --- a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/GlobalReceiverRegistry.java +++ b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/GlobalReceiverRegistry.java @@ -29,25 +29,31 @@ import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import net.minecraft.network.NetworkState; +import net.minecraft.network.NetworkPhase; +import net.minecraft.network.NetworkSide; import net.minecraft.util.Identifier; public final class GlobalReceiverRegistry { private static final Logger LOGGER = LoggerFactory.getLogger(GlobalReceiverRegistry.class); - private final NetworkState state; + private final NetworkSide side; + private final NetworkPhase phase; + @Nullable + private final PayloadTypeRegistryImpl payloadTypeRegistry; private final ReadWriteLock lock = new ReentrantReadWriteLock(); - private final Map handlers; + private final Map handlers = new HashMap<>(); private final Set> trackedAddons = new HashSet<>(); - public GlobalReceiverRegistry(NetworkState state) { - this(state, new HashMap<>()); // sync map should be fine as there is little read write competitions - } + public GlobalReceiverRegistry(NetworkSide side, NetworkPhase phase, @Nullable PayloadTypeRegistryImpl payloadTypeRegistry) { + this.side = side; + this.phase = phase; + this.payloadTypeRegistry = payloadTypeRegistry; - public GlobalReceiverRegistry(NetworkState state, Map map) { - this.state = state; - this.handlers = map; + if (payloadTypeRegistry != null) { + assert phase == payloadTypeRegistry.getPhase(); + assert side == payloadTypeRegistry.getSide(); + } } @Nullable @@ -70,6 +76,8 @@ public final class GlobalReceiverRegistry { throw new IllegalArgumentException(String.format("Cannot register handler for reserved channel with name \"%s\"", channelName)); } + assertPayloadType(channelName); + Lock lock = this.lock.writeLock(); lock.lock(); @@ -166,7 +174,7 @@ public final class GlobalReceiverRegistry { */ private void logTrackedAddonSize() { if (LOGGER.isTraceEnabled() && this.trackedAddons.size() > 1) { - LOGGER.trace("{} receiver registry tracks {} addon instances", state.getId(), trackedAddons.size()); + LOGGER.trace("{} receiver registry tracks {} addon instances", phase.getId(), trackedAddons.size()); } } @@ -200,7 +208,17 @@ public final class GlobalReceiverRegistry { } } - public NetworkState getState() { - return state; + public void assertPayloadType(Identifier channelName) { + if (payloadTypeRegistry == null) { + return; + } + + if (payloadTypeRegistry.get(channelName) == null) { + throw new IllegalArgumentException(String.format("Cannot register handler as no payload type has been registered with name \"%s\" for %s %s", channelName, side, phase)); + } + } + + public NetworkPhase getPhase() { + return phase; } } diff --git a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/NetworkingImpl.java b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/NetworkingImpl.java index 6ad65ef56..dba589b7a 100644 --- a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/NetworkingImpl.java +++ b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/NetworkingImpl.java @@ -21,23 +21,12 @@ import org.slf4j.LoggerFactory; import net.minecraft.util.Identifier; -import net.fabricmc.fabric.impl.networking.payload.TypedPayload; -import net.fabricmc.fabric.impl.networking.payload.UntypedPayload; -import net.fabricmc.loader.api.FabricLoader; +import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry; public final class NetworkingImpl { public static final String MOD_ID = "fabric-networking-api-v1"; public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID); - /** - * Force {@link TypedPayload} to be serialized into {@link UntypedPayload}, mimicking remote connection. - * - *

Defaults to {@code true} in dev env and {@code false} in production. - */ - public static final boolean FORCE_PACKET_SERIALIZATION = Boolean.parseBoolean(System.getProperty( - "fabric-api.networking.force-packet-serialization", - Boolean.toString(FabricLoader.getInstance().isDevelopmentEnvironment()))); - /** * Id of packet used to register supported channels. */ @@ -48,15 +37,18 @@ public final class NetworkingImpl { */ public static final Identifier UNREGISTER_CHANNEL = new Identifier("minecraft", "unregister"); - public static final ThreadLocal FACTORY_RETAIN = ThreadLocal.withInitial(() -> Boolean.FALSE); - public static boolean isReservedCommonChannel(Identifier channelName) { return channelName.equals(REGISTER_CHANNEL) || channelName.equals(UNREGISTER_CHANNEL); } - static { - if (FORCE_PACKET_SERIALIZATION) { - LOGGER.info("Force Packet Serialization is enabled to mimic remote connection on single player, this is the default behaviour on dev env. Add -Dfabric-api.networking.force-packet-serialization=false JVM arg to disable it."); - } + public static void init() { + PayloadTypeRegistry.configurationS2C().register(RegistrationPayload.REGISTER, RegistrationPayload.REGISTER_CODEC); + PayloadTypeRegistry.configurationS2C().register(RegistrationPayload.UNREGISTER, RegistrationPayload.UNREGISTER_CODEC); + PayloadTypeRegistry.configurationC2S().register(RegistrationPayload.REGISTER, RegistrationPayload.REGISTER_CODEC); + PayloadTypeRegistry.configurationC2S().register(RegistrationPayload.UNREGISTER, RegistrationPayload.UNREGISTER_CODEC); + PayloadTypeRegistry.playS2C().register(RegistrationPayload.REGISTER, RegistrationPayload.REGISTER_CODEC); + PayloadTypeRegistry.playS2C().register(RegistrationPayload.UNREGISTER, RegistrationPayload.UNREGISTER_CODEC); + PayloadTypeRegistry.playC2S().register(RegistrationPayload.REGISTER, RegistrationPayload.REGISTER_CODEC); + PayloadTypeRegistry.playC2S().register(RegistrationPayload.UNREGISTER, RegistrationPayload.UNREGISTER_CODEC); } } diff --git a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/PayloadTypeRegistryImpl.java b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/PayloadTypeRegistryImpl.java new file mode 100644 index 000000000..4b749a01c --- /dev/null +++ b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/PayloadTypeRegistryImpl.java @@ -0,0 +1,83 @@ +/* + * 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.networking; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +import org.jetbrains.annotations.Nullable; + +import net.minecraft.network.NetworkPhase; +import net.minecraft.network.NetworkSide; +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.util.Identifier; + +import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry; + +public class PayloadTypeRegistryImpl implements PayloadTypeRegistry { + public static final PayloadTypeRegistryImpl CONFIGURATION_C2S = new PayloadTypeRegistryImpl<>(NetworkPhase.CONFIGURATION, NetworkSide.SERVERBOUND); + public static final PayloadTypeRegistryImpl CONFIGURATION_S2C = new PayloadTypeRegistryImpl<>(NetworkPhase.CONFIGURATION, NetworkSide.CLIENTBOUND); + public static final PayloadTypeRegistryImpl PLAY_C2S = new PayloadTypeRegistryImpl<>(NetworkPhase.PLAY, NetworkSide.SERVERBOUND); + public static final PayloadTypeRegistryImpl PLAY_S2C = new PayloadTypeRegistryImpl<>(NetworkPhase.PLAY, NetworkSide.CLIENTBOUND); + + private final Map> packetTypes = new HashMap<>(); + private final NetworkPhase state; + private final NetworkSide side; + + private PayloadTypeRegistryImpl(NetworkPhase state, NetworkSide side) { + this.state = state; + this.side = side; + } + + @Override + public CustomPayload.Type register(CustomPayload.Id id, PacketCodec codec) { + Objects.requireNonNull(id, "id"); + Objects.requireNonNull(codec, "codec"); + + final CustomPayload.Type payloadType = new CustomPayload.Type<>(id, codec.cast()); + + if (packetTypes.containsKey(id.id())) { + throw new IllegalArgumentException("Packet type " + id + " is already registered!"); + } + + packetTypes.put(id.id(), payloadType); + return payloadType; + } + + @Nullable + public CustomPayload.Type get(Identifier id) { + return packetTypes.get(id); + } + + @Nullable + public CustomPayload.Type get(CustomPayload.Id id) { + //noinspection unchecked + return (CustomPayload.Type) packetTypes.get(id.id()); + } + + public NetworkPhase getPhase() { + return state; + } + + public NetworkSide getSide() { + return side; + } +} diff --git a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/RegistrationPayload.java b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/RegistrationPayload.java new file mode 100644 index 000000000..e8bee3f0d --- /dev/null +++ b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/RegistrationPayload.java @@ -0,0 +1,94 @@ +/* + * 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.networking; + +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import io.netty.util.AsciiString; + +import net.minecraft.network.PacketByteBuf; +import net.minecraft.network.codec.PacketCodec; +import net.minecraft.network.packet.CustomPayload; +import net.minecraft.util.Identifier; +import net.minecraft.util.InvalidIdentifierException; + +public record RegistrationPayload(Id id, List channels) implements CustomPayload { + public static final CustomPayload.Id REGISTER = new CustomPayload.Id<>(NetworkingImpl.REGISTER_CHANNEL); + public static final CustomPayload.Id UNREGISTER = new CustomPayload.Id<>(NetworkingImpl.UNREGISTER_CHANNEL); + public static final PacketCodec REGISTER_CODEC = codec(REGISTER); + public static final PacketCodec UNREGISTER_CODEC = codec(UNREGISTER); + + private RegistrationPayload(Id id, PacketByteBuf buf) { + this(id, read(buf)); + } + + private void write(PacketByteBuf buf) { + boolean first = true; + + for (Identifier channel : channels) { + if (first) { + first = false; + } else { + buf.writeByte(0); + } + + buf.writeBytes(channel.toString().getBytes(StandardCharsets.US_ASCII)); + } + } + + private static List read(PacketByteBuf buf) { + List ids = new ArrayList<>(); + StringBuilder active = new StringBuilder(); + + while (buf.isReadable()) { + byte b = buf.readByte(); + + if (b != 0) { + active.append(AsciiString.b2c(b)); + } else { + addId(ids, active); + active = new StringBuilder(); + } + } + + addId(ids, active); + + return Collections.unmodifiableList(ids); + } + + private static void addId(List ids, StringBuilder sb) { + String literal = sb.toString(); + + try { + ids.add(new Identifier(literal)); + } catch (InvalidIdentifierException ex) { + NetworkingImpl.LOGGER.warn("Received invalid channel identifier \"{}\"", literal); + } + } + + @Override + public Id getId() { + return id; + } + + private static PacketCodec codec(Id id) { + return CustomPayload.codecOf(RegistrationPayload::write, buf -> new RegistrationPayload(id, buf)); + } +} diff --git a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/payload/PayloadHelper.java b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/payload/PayloadHelper.java index 96077bbbd..7a02f4b4e 100644 --- a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/payload/PayloadHelper.java +++ b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/payload/PayloadHelper.java @@ -17,7 +17,6 @@ package net.fabricmc.fabric.impl.networking.payload; import net.minecraft.network.PacketByteBuf; -import net.minecraft.util.Identifier; import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; @@ -35,18 +34,6 @@ public class PayloadHelper { return newBuf; } - public static ResolvablePayload readCustom(Identifier id, PacketByteBuf buf, int maxSize, boolean retain) { - assertSize(buf, maxSize); - - if (retain) { - RetainedPayload payload = new RetainedPayload(id, PacketByteBufs.retainedSlice(buf)); - buf.skipBytes(buf.readableBytes()); - return payload; - } else { - return new UntypedPayload(id, read(buf, maxSize)); - } - } - private static void assertSize(PacketByteBuf buf, int maxSize) { int size = buf.readableBytes(); diff --git a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/payload/ResolvablePayload.java b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/payload/ResolvablePayload.java deleted file mode 100644 index 2f766ec35..000000000 --- a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/payload/ResolvablePayload.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * 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.networking.payload; - -import org.jetbrains.annotations.Nullable; - -import net.minecraft.network.packet.CustomPayload; - -import net.fabricmc.fabric.api.networking.v1.PacketType; - -public sealed interface ResolvablePayload extends CustomPayload permits ResolvedPayload, RetainedPayload { - /** - * Resolve the payload to one of the resolved types. - * - * @return {@link UntypedPayload} if type is {@code null}, {@link TypedPayload} if otherwise. - */ - ResolvedPayload resolve(@Nullable PacketType type); - - /** - * @param type the packet type, if it has any - * @param actual the public handler that exposed to API consumer - * @param internal the internal handler - */ - record Handler(@Nullable PacketType type, Object actual, H internal) { - } -} diff --git a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/payload/RetainedPayload.java b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/payload/RetainedPayload.java deleted file mode 100644 index 8e4f0113d..000000000 --- a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/payload/RetainedPayload.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * 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.networking.payload; - -import org.jetbrains.annotations.Nullable; - -import net.minecraft.network.PacketByteBuf; -import net.minecraft.util.Identifier; - -import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; -import net.fabricmc.fabric.api.networking.v1.PacketType; - -public record RetainedPayload(Identifier id, PacketByteBuf buf) implements ResolvablePayload { - @Override - public ResolvedPayload resolve(@Nullable PacketType type) { - try { - if (type == null) { - PacketByteBuf copy = PacketByteBufs.create(); - copy.writeBytes(buf); - return new UntypedPayload(this.id, copy); - } else { - TypedPayload typed = new TypedPayload(type.read(buf)); - int dangling = buf.readableBytes(); - - if (dangling > 0) { - throw new IllegalStateException("Found " + dangling + " extra bytes when reading packet " + id); - } - - return typed; - } - } finally { - buf.release(); - } - } - - @Override - public void write(PacketByteBuf buf) { - throw new UnsupportedOperationException("RetainedPayload shouldn't be used to send"); - } -} diff --git a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/payload/TypedPayload.java b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/payload/TypedPayload.java deleted file mode 100644 index 4240ee991..000000000 --- a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/payload/TypedPayload.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * 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.networking.payload; - -import org.jetbrains.annotations.Nullable; - -import net.minecraft.network.PacketByteBuf; -import net.minecraft.util.Identifier; - -import net.fabricmc.fabric.api.networking.v1.FabricPacket; -import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; -import net.fabricmc.fabric.api.networking.v1.PacketType; - -public record TypedPayload(FabricPacket packet) implements ResolvedPayload { - @Override - public ResolvedPayload resolve(@Nullable PacketType type) { - if (type == null) { - PacketByteBuf buf = PacketByteBufs.create(); - write(buf); - return new UntypedPayload(packet.getType().getId(), buf); - } else { - return this; - } - } - - @Override - public void write(PacketByteBuf buf) { - packet.write(buf); - } - - @Override - public Identifier id() { - return packet.getType().getId(); - } -} diff --git a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/payload/UntypedPayload.java b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/payload/UntypedPayload.java deleted file mode 100644 index 856b348e4..000000000 --- a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/payload/UntypedPayload.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * 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.networking.payload; - -import org.jetbrains.annotations.Nullable; - -import net.minecraft.network.PacketByteBuf; -import net.minecraft.util.Identifier; - -import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; -import net.fabricmc.fabric.api.networking.v1.PacketType; - -public record UntypedPayload(Identifier id, PacketByteBuf buffer) implements ResolvedPayload { - @Override - public ResolvedPayload resolve(@Nullable PacketType type) { - if (type == null) { - return this; - } else { - PacketByteBuf copy = PacketByteBufs.copy(buffer); - TypedPayload typed = new TypedPayload(type.read(copy)); - int dangling = copy.readableBytes(); - - if (dangling > 0) { - throw new IllegalStateException("Found " + dangling + " extra bytes when reading packet " + id); - } - - return typed; - } - } - - @Override - public void write(PacketByteBuf buf) { - buf.writeBytes(buffer.copy()); - } - - @Override - public PacketByteBuf buffer() { - return PacketByteBufs.copy(buffer); - } -} diff --git a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/server/ServerConfigurationNetworkAddon.java b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/server/ServerConfigurationNetworkAddon.java index 338a2d621..75085bdcd 100644 --- a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/server/ServerConfigurationNetworkAddon.java +++ b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/server/ServerConfigurationNetworkAddon.java @@ -19,39 +19,40 @@ package net.fabricmc.fabric.impl.networking.server; import java.util.Collections; import java.util.List; -import net.minecraft.network.NetworkState; -import net.minecraft.network.PacketByteBuf; +import net.minecraft.network.NetworkPhase; import net.minecraft.network.PacketCallbacks; +import net.minecraft.network.packet.CustomPayload; import net.minecraft.network.packet.Packet; import net.minecraft.network.packet.s2c.common.CommonPingS2CPacket; import net.minecraft.server.MinecraftServer; import net.minecraft.server.network.ServerConfigurationNetworkHandler; import net.minecraft.util.Identifier; -import net.fabricmc.fabric.api.networking.v1.FabricPacket; import net.fabricmc.fabric.api.networking.v1.PacketSender; import net.fabricmc.fabric.api.networking.v1.S2CConfigurationChannelEvents; import net.fabricmc.fabric.api.networking.v1.ServerConfigurationConnectionEvents; +import net.fabricmc.fabric.api.networking.v1.ServerConfigurationNetworking; import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; import net.fabricmc.fabric.impl.networking.AbstractChanneledNetworkAddon; import net.fabricmc.fabric.impl.networking.ChannelInfoHolder; import net.fabricmc.fabric.impl.networking.NetworkingImpl; -import net.fabricmc.fabric.impl.networking.payload.ResolvablePayload; -import net.fabricmc.fabric.impl.networking.payload.ResolvedPayload; +import net.fabricmc.fabric.impl.networking.RegistrationPayload; import net.fabricmc.fabric.mixin.networking.accessor.ServerCommonNetworkHandlerAccessor; -public final class ServerConfigurationNetworkAddon extends AbstractChanneledNetworkAddon { +public final class ServerConfigurationNetworkAddon extends AbstractChanneledNetworkAddon> { private final ServerConfigurationNetworkHandler handler; private final MinecraftServer server; + private final ServerConfigurationNetworking.Context context; private RegisterState registerState = RegisterState.NOT_SENT; public ServerConfigurationNetworkAddon(ServerConfigurationNetworkHandler handler, MinecraftServer server) { super(ServerNetworkingImpl.CONFIGURATION, ((ServerCommonNetworkHandlerAccessor) handler).getConnection(), "ServerConfigurationNetworkAddon for " + handler.getDebugProfile().getName()); this.handler = handler; this.server = server; + this.context = new ContextImpl(handler, this); // Must register pending channels via lateinit - this.registerPendingChannels((ChannelInfoHolder) this.connection, NetworkState.CONFIGURATION); + this.registerPendingChannels((ChannelInfoHolder) this.connection, NetworkPhase.CONFIGURATION); } @Override @@ -84,7 +85,7 @@ public final class ServerConfigurationNetworkAddon extends AbstractChanneledNetw } @Override - protected void receiveRegistration(boolean register, ResolvablePayload resolvable) { + protected void receiveRegistration(boolean register, RegistrationPayload resolvable) { super.receiveRegistration(register, resolvable); if (register && registerState == RegisterState.SENT) { @@ -103,8 +104,8 @@ public final class ServerConfigurationNetworkAddon extends AbstractChanneledNetw } @Override - protected void receive(Handler handler, ResolvedPayload payload) { - handler.receive(this.server, this.handler, payload, this); + protected void receive(ServerConfigurationNetworking.ConfigurationPacketHandler handler, CustomPayload payload) { + ((ServerConfigurationNetworking.ConfigurationPacketHandler) handler).receive(payload, this.context); } // impl details @@ -115,12 +116,7 @@ public final class ServerConfigurationNetworkAddon extends AbstractChanneledNetw } @Override - public Packet createPacket(Identifier channelName, PacketByteBuf buf) { - return ServerPlayNetworking.createS2CPacket(channelName, buf); - } - - @Override - public Packet createPacket(FabricPacket packet) { + public Packet createPacket(CustomPayload packet) { return ServerPlayNetworking.createS2CPacket(packet); } @@ -138,10 +134,10 @@ public final class ServerConfigurationNetworkAddon extends AbstractChanneledNetw protected void handleRegistration(Identifier channelName) { // If we can already send packets, immediately send the register packet for this channel if (this.registerState != RegisterState.NOT_SENT) { - final PacketByteBuf buf = this.createRegistrationPacket(Collections.singleton(channelName)); + RegistrationPayload registrationPayload = this.createRegistrationPayload(RegistrationPayload.REGISTER, Collections.singleton(channelName)); - if (buf != null) { - this.sendPacket(NetworkingImpl.REGISTER_CHANNEL, buf); + if (registrationPayload != null) { + this.sendPacket(registrationPayload); } } } @@ -150,10 +146,10 @@ public final class ServerConfigurationNetworkAddon extends AbstractChanneledNetw protected void handleUnregistration(Identifier channelName) { // If we can already send packets, immediately send the unregister packet for this channel if (this.registerState != RegisterState.NOT_SENT) { - final PacketByteBuf buf = this.createRegistrationPacket(Collections.singleton(channelName)); + RegistrationPayload registrationPayload = this.createRegistrationPayload(RegistrationPayload.UNREGISTER, Collections.singleton(channelName)); - if (buf != null) { - this.sendPacket(NetworkingImpl.UNREGISTER_CHANNEL, buf); + if (registrationPayload != null) { + this.sendPacket(registrationPayload); } } } @@ -184,7 +180,6 @@ public final class ServerConfigurationNetworkAddon extends AbstractChanneledNetw return (ChannelInfoHolder) ((ServerCommonNetworkHandlerAccessor) handler).getConnection(); } - public interface Handler { - void receive(MinecraftServer server, ServerConfigurationNetworkHandler handler, ResolvedPayload payload, PacketSender responseSender); + private record ContextImpl(ServerConfigurationNetworkHandler networkHandler, PacketSender responseSender) implements ServerConfigurationNetworking.Context { } } 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 897a7a0a4..8615467f4 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 @@ -26,33 +26,31 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.concurrent.atomic.AtomicReference; -import io.netty.util.concurrent.GenericFutureListener; import org.jetbrains.annotations.Nullable; import net.minecraft.network.ClientConnection; import net.minecraft.network.PacketByteBuf; import net.minecraft.network.PacketCallbacks; +import net.minecraft.network.packet.CustomPayload; import net.minecraft.network.packet.Packet; import net.minecraft.network.packet.c2s.login.LoginQueryResponseC2SPacket; import net.minecraft.network.packet.s2c.login.LoginCompressionS2CPacket; import net.minecraft.network.packet.s2c.login.LoginQueryRequestS2CPacket; import net.minecraft.server.MinecraftServer; import net.minecraft.server.network.ServerLoginNetworkHandler; +import net.minecraft.text.Text; import net.minecraft.util.Identifier; -import net.fabricmc.fabric.api.networking.v1.FabricPacket; +import net.fabricmc.fabric.api.networking.v1.LoginPacketSender; import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; -import net.fabricmc.fabric.api.networking.v1.PacketSender; import net.fabricmc.fabric.api.networking.v1.ServerLoginConnectionEvents; import net.fabricmc.fabric.api.networking.v1.ServerLoginNetworking; import net.fabricmc.fabric.impl.networking.AbstractNetworkAddon; -import net.fabricmc.fabric.impl.networking.GenericFutureListenerHolder; -import net.fabricmc.fabric.impl.networking.payload.FabricPacketLoginQueryRequestPayload; import net.fabricmc.fabric.impl.networking.payload.PacketByteBufLoginQueryRequestPayload; import net.fabricmc.fabric.impl.networking.payload.PacketByteBufLoginQueryResponse; import net.fabricmc.fabric.mixin.networking.accessor.ServerLoginNetworkHandlerAccessor; -public final class ServerLoginNetworkAddon extends AbstractNetworkAddon implements PacketSender { +public final class ServerLoginNetworkAddon extends AbstractNetworkAddon implements LoginPacketSender { private final ClientConnection connection; private final ServerLoginNetworkHandler handler; private final MinecraftServer server; @@ -160,23 +158,17 @@ public final class ServerLoginNetworkAddon extends AbstractNetworkAddon createPacket(CustomPayload packet) { + throw new UnsupportedOperationException("Cannot send CustomPayload during login"); + } + @Override public Packet createPacket(Identifier channelName, PacketByteBuf buf) { int queryId = this.queryIdFactory.nextId(); return new LoginQueryRequestS2CPacket(queryId, new PacketByteBufLoginQueryRequestPayload(channelName, buf)); } - @Override - public Packet createPacket(FabricPacket packet) { - int queryId = this.queryIdFactory.nextId(); - return new LoginQueryRequestS2CPacket(queryId, new FabricPacketLoginQueryRequestPayload(packet)); - } - - @Override - public void sendPacket(Packet packet, @Nullable GenericFutureListener> callback) { - sendPacket(packet, GenericFutureListenerHolder.create(callback)); - } - @Override public void sendPacket(Packet packet, PacketCallbacks callback) { Objects.requireNonNull(packet, "Packet cannot be null"); @@ -184,6 +176,13 @@ public final class ServerLoginNetworkAddon extends AbstractNetworkAddon LOGIN = new GlobalReceiverRegistry<>(NetworkState.LOGIN); - public static final GlobalReceiverRegistry> CONFIGURATION = new GlobalReceiverRegistry<>(NetworkState.CONFIGURATION); - public static final GlobalReceiverRegistry> PLAY = new GlobalReceiverRegistry<>(NetworkState.PLAY); + public static final GlobalReceiverRegistry LOGIN = new GlobalReceiverRegistry<>(NetworkSide.SERVERBOUND, NetworkPhase.LOGIN, null); + public static final GlobalReceiverRegistry> CONFIGURATION = new GlobalReceiverRegistry<>(NetworkSide.SERVERBOUND, NetworkPhase.CONFIGURATION, PayloadTypeRegistryImpl.CONFIGURATION_C2S); + public static final GlobalReceiverRegistry> PLAY = new GlobalReceiverRegistry<>(NetworkSide.SERVERBOUND, NetworkPhase.PLAY, PayloadTypeRegistryImpl.PLAY_C2S); public static ServerPlayNetworkAddon getAddon(ServerPlayNetworkHandler handler) { return (ServerPlayNetworkAddon) ((NetworkHandlerExtensions) handler).getAddon(); @@ -55,16 +52,9 @@ public final class ServerNetworkingImpl { return (ServerConfigurationNetworkAddon) ((NetworkHandlerExtensions) handler).getAddon(); } - public static Packet createS2CPacket(Identifier channel, PacketByteBuf buf) { - return new CustomPayloadS2CPacket(new UntypedPayload(channel, buf)); - } - - public static Packet createS2CPacket(FabricPacket packet) { - Objects.requireNonNull(packet, "Packet cannot be null"); - Objects.requireNonNull(packet.getType(), "Packet#getType cannot return null"); - - ResolvedPayload payload = new TypedPayload(packet); - if (NetworkingImpl.FORCE_PACKET_SERIALIZATION) payload = payload.resolve(null); + public static Packet createS2CPacket(CustomPayload payload) { + Objects.requireNonNull(payload, "Payload cannot be null"); + Objects.requireNonNull(payload.getId(), "CustomPayload#getId() cannot return null for payload class: " + payload.getClass()); return new CustomPayloadS2CPacket(payload); } diff --git a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/server/ServerPlayNetworkAddon.java b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/server/ServerPlayNetworkAddon.java index c055c7b28..abf09c0a4 100644 --- a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/server/ServerPlayNetworkAddon.java +++ b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/server/ServerPlayNetworkAddon.java @@ -20,15 +20,14 @@ import java.util.Collections; import java.util.List; import net.minecraft.network.ClientConnection; -import net.minecraft.network.NetworkState; -import net.minecraft.network.PacketByteBuf; +import net.minecraft.network.NetworkPhase; +import net.minecraft.network.packet.CustomPayload; import net.minecraft.network.packet.Packet; import net.minecraft.server.MinecraftServer; import net.minecraft.server.network.ServerPlayNetworkHandler; import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.util.Identifier; -import net.fabricmc.fabric.api.networking.v1.FabricPacket; import net.fabricmc.fabric.api.networking.v1.PacketSender; import net.fabricmc.fabric.api.networking.v1.S2CPlayChannelEvents; import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents; @@ -36,20 +35,22 @@ import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; import net.fabricmc.fabric.impl.networking.AbstractChanneledNetworkAddon; import net.fabricmc.fabric.impl.networking.ChannelInfoHolder; import net.fabricmc.fabric.impl.networking.NetworkingImpl; -import net.fabricmc.fabric.impl.networking.payload.ResolvedPayload; +import net.fabricmc.fabric.impl.networking.RegistrationPayload; -public final class ServerPlayNetworkAddon extends AbstractChanneledNetworkAddon { +public final class ServerPlayNetworkAddon extends AbstractChanneledNetworkAddon> { private final ServerPlayNetworkHandler handler; private final MinecraftServer server; private boolean sentInitialRegisterPacket; + private final ServerPlayNetworking.Context context; public ServerPlayNetworkAddon(ServerPlayNetworkHandler handler, ClientConnection connection, MinecraftServer server) { super(ServerNetworkingImpl.PLAY, connection, "ServerPlayNetworkAddon for " + handler.player.getDisplayName()); this.handler = handler; this.server = server; + this.context = new ContextImpl(handler.player, this); // Must register pending channels via lateinit - this.registerPendingChannels((ChannelInfoHolder) this.connection, NetworkState.PLAY); + this.registerPendingChannels((ChannelInfoHolder) this.connection, NetworkPhase.PLAY); } @Override @@ -65,8 +66,10 @@ public final class ServerPlayNetworkAddon extends AbstractChanneledNetworkAddon< } @Override - protected void receive(Handler handler, ResolvedPayload payload) { - handler.receive(this.server, this.handler.player, this.handler, payload, this); + protected void receive(ServerPlayNetworking.PlayPayloadHandler payloadHandler, CustomPayload payload) { + this.server.execute(() -> { + ((ServerPlayNetworking.PlayPayloadHandler) payloadHandler).receive(payload, ServerPlayNetworkAddon.this.context); + }); } // impl details @@ -77,12 +80,7 @@ public final class ServerPlayNetworkAddon extends AbstractChanneledNetworkAddon< } @Override - public Packet createPacket(Identifier channelName, PacketByteBuf buf) { - return ServerPlayNetworking.createS2CPacket(channelName, buf); - } - - @Override - public Packet createPacket(FabricPacket packet) { + public Packet createPacket(CustomPayload packet) { return ServerPlayNetworking.createS2CPacket(packet); } @@ -100,10 +98,10 @@ public final class ServerPlayNetworkAddon extends AbstractChanneledNetworkAddon< protected void handleRegistration(Identifier channelName) { // If we can already send packets, immediately send the register packet for this channel if (this.sentInitialRegisterPacket) { - final PacketByteBuf buf = this.createRegistrationPacket(Collections.singleton(channelName)); + RegistrationPayload registrationPayload = this.createRegistrationPayload(RegistrationPayload.REGISTER, Collections.singleton(channelName)); - if (buf != null) { - this.sendPacket(NetworkingImpl.REGISTER_CHANNEL, buf); + if (registrationPayload != null) { + this.sendPacket(registrationPayload); } } } @@ -112,10 +110,10 @@ public final class ServerPlayNetworkAddon extends AbstractChanneledNetworkAddon< protected void handleUnregistration(Identifier channelName) { // If we can already send packets, immediately send the unregister packet for this channel if (this.sentInitialRegisterPacket) { - final PacketByteBuf buf = this.createRegistrationPacket(Collections.singleton(channelName)); + RegistrationPayload registrationPayload = this.createRegistrationPayload(RegistrationPayload.UNREGISTER, Collections.singleton(channelName)); - if (buf != null) { - this.sendPacket(NetworkingImpl.UNREGISTER_CHANNEL, buf); + if (registrationPayload != null) { + this.sendPacket(registrationPayload); } } } @@ -130,7 +128,6 @@ public final class ServerPlayNetworkAddon extends AbstractChanneledNetworkAddon< return NetworkingImpl.isReservedCommonChannel(channelName); } - public interface Handler { - void receive(MinecraftServer server, ServerPlayerEntity player, ServerPlayNetworkHandler handler, ResolvedPayload payload, PacketSender responseSender); + private record ContextImpl(ServerPlayerEntity player, PacketSender responseSender) implements ServerPlayNetworking.Context { } } diff --git a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/mixin/networking/ClientConnectionMixin.java b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/mixin/networking/ClientConnectionMixin.java index f5feb9d39..3fdd1c4de 100644 --- a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/mixin/networking/ClientConnectionMixin.java +++ b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/mixin/networking/ClientConnectionMixin.java @@ -21,8 +21,6 @@ import java.util.Collections; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; -import io.netty.channel.ChannelFuture; -import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelHandlerContext; import org.jetbrains.annotations.Nullable; import org.spongepowered.asm.mixin.Mixin; @@ -32,9 +30,9 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Redirect; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import org.spongepowered.asm.mixin.injection.callback.LocalCapture; import net.minecraft.network.ClientConnection; +import net.minecraft.network.NetworkPhase; import net.minecraft.network.NetworkSide; import net.minecraft.network.NetworkState; import net.minecraft.network.PacketCallbacks; @@ -45,7 +43,6 @@ import net.minecraft.util.Identifier; import net.fabricmc.fabric.impl.networking.ChannelInfoHolder; import net.fabricmc.fabric.impl.networking.DisconnectPacketSource; -import net.fabricmc.fabric.impl.networking.GenericFutureListenerHolder; import net.fabricmc.fabric.impl.networking.NetworkHandlerExtensions; import net.fabricmc.fabric.impl.networking.PacketCallbackListener; @@ -61,7 +58,7 @@ abstract class ClientConnectionMixin implements ChannelInfoHolder { public abstract void send(Packet packet, @Nullable PacketCallbacks arg); @Unique - private Map> playChannels; + private Map> playChannels; @Inject(method = "", at = @At("RETURN")) private void initAddedFields(NetworkSide side, CallbackInfo ci) { @@ -89,7 +86,7 @@ abstract class ClientConnectionMixin implements ChannelInfoHolder { } @Inject(method = "setPacketListener", at = @At("HEAD")) - private void unwatchAddon(PacketListener packetListener, CallbackInfo ci) { + private void unwatchAddon(NetworkState state, PacketListener listener, CallbackInfo ci) { if (this.packetListener instanceof NetworkHandlerExtensions oldListener) { oldListener.getAddon().endSession(); } @@ -109,17 +106,8 @@ abstract class ClientConnectionMixin implements ChannelInfoHolder { } } - @Inject(method = "sendInternal", at = @At(value = "INVOKE", target = "Lio/netty/channel/ChannelFuture;addListener(Lio/netty/util/concurrent/GenericFutureListener;)Lio/netty/channel/ChannelFuture;", remap = false), locals = LocalCapture.CAPTURE_FAILHARD, cancellable = true) - private void sendInternal(Packet packet, @Nullable PacketCallbacks callbacks, boolean flush, CallbackInfo ci, ChannelFuture channelFuture) { - if (callbacks instanceof GenericFutureListenerHolder holder) { - channelFuture.addListener(holder.getDelegate()); - channelFuture.addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE); - ci.cancel(); - } - } - @Override - public Collection getPendingChannelsNames(NetworkState state) { + public Collection fabric_getPendingChannelsNames(NetworkPhase state) { return this.playChannels.computeIfAbsent(state, (key) -> Collections.newSetFromMap(new ConcurrentHashMap<>())); } } diff --git a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/mixin/networking/CustomPayloadC2SPacketMixin.java b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/mixin/networking/CustomPayloadC2SPacketMixin.java index 4ea32db59..34b48c6b7 100644 --- a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/mixin/networking/CustomPayloadC2SPacketMixin.java +++ b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/mixin/networking/CustomPayloadC2SPacketMixin.java @@ -16,33 +16,42 @@ package net.fabricmc.fabric.mixin.networking; -import org.spongepowered.asm.mixin.Final; +import java.util.List; + +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 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.network.packet.c2s.common.CustomPayloadC2SPacket; -import net.minecraft.util.Identifier; -import net.fabricmc.fabric.impl.networking.NetworkingImpl; -import net.fabricmc.fabric.impl.networking.payload.PayloadHelper; +import net.fabricmc.fabric.impl.networking.FabricCustomPayloadPacketCodec; +import net.fabricmc.fabric.impl.networking.PayloadTypeRegistryImpl; @Mixin(CustomPayloadC2SPacket.class) public class CustomPayloadC2SPacketMixin { - @Shadow - @Final - private static int MAX_PAYLOAD_SIZE; - - @Inject( - method = "readPayload", - at = @At(value = "INVOKE", target = "Lnet/minecraft/network/packet/c2s/common/CustomPayloadC2SPacket;readUnknownPayload(Lnet/minecraft/util/Identifier;Lnet/minecraft/network/PacketByteBuf;)Lnet/minecraft/network/packet/UnknownCustomPayload;"), - cancellable = true + @WrapOperation( + method = "", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/network/packet/CustomPayload;createCodec(Lnet/minecraft/network/packet/CustomPayload$CodecFactory;Ljava/util/List;)Lnet/minecraft/network/codec/PacketCodec;" + ) ) - private static void readPayload(Identifier id, PacketByteBuf buf, CallbackInfoReturnable cir) { - cir.setReturnValue(PayloadHelper.readCustom(id, buf, MAX_PAYLOAD_SIZE, NetworkingImpl.FACTORY_RETAIN.get())); + private static PacketCodec wrapCodec(CustomPayload.CodecFactory unknownCodecFactory, List> types, Operation> original) { + PacketCodec codec = original.call(unknownCodecFactory, types); + FabricCustomPayloadPacketCodec fabricCodec = (FabricCustomPayloadPacketCodec) codec; + fabricCodec.fabric_setPacketCodecProvider((packetByteBuf, identifier) -> { + // CustomPayloadC2SPacket does not have a separate codec for play/configuration. We know if the packetByteBuf is a PacketByteBuf we are in the play phase. + if (packetByteBuf instanceof RegistryByteBuf) { + return (CustomPayload.Type) (Object) PayloadTypeRegistryImpl.PLAY_C2S.get(identifier); + } + + return PayloadTypeRegistryImpl.CONFIGURATION_C2S.get(identifier); + }); + return codec; } } diff --git a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/mixin/networking/CustomPayloadPacketCodecMixin.java b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/mixin/networking/CustomPayloadPacketCodecMixin.java new file mode 100644 index 000000000..539264541 --- /dev/null +++ b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/mixin/networking/CustomPayloadPacketCodecMixin.java @@ -0,0 +1,63 @@ +/* + * 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.networking; + +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Coerce; + +import net.minecraft.network.PacketByteBuf; +import net.minecraft.network.codec.PacketCodec; +import net.minecraft.network.packet.CustomPayload; +import net.minecraft.util.Identifier; + +import net.fabricmc.fabric.impl.networking.CustomPayloadTypeProvider; +import net.fabricmc.fabric.impl.networking.FabricCustomPayloadPacketCodec; + +@Mixin(targets = "net/minecraft/network/packet/CustomPayload$1") +public abstract class CustomPayloadPacketCodecMixin implements PacketCodec, FabricCustomPayloadPacketCodec { + @Unique + private CustomPayloadTypeProvider customPayloadTypeProvider; + + @Override + public void fabric_setPacketCodecProvider(CustomPayloadTypeProvider customPayloadTypeProvider) { + if (this.customPayloadTypeProvider != null) { + throw new IllegalStateException("Payload codec provider is already set!"); + } + + this.customPayloadTypeProvider = customPayloadTypeProvider; + } + + @WrapOperation(method = { + "encode(Lnet/minecraft/network/PacketByteBuf;Lnet/minecraft/network/packet/CustomPayload$Id;Lnet/minecraft/network/packet/CustomPayload;)V", + "decode(Lnet/minecraft/network/PacketByteBuf;)Lnet/minecraft/network/packet/CustomPayload;" + }, at = @At(value = "INVOKE", target = "Lnet/minecraft/network/packet/CustomPayload$1;getCodec(Lnet/minecraft/util/Identifier;)Lnet/minecraft/network/codec/PacketCodec;")) + private PacketCodec wrapGetCodec(@Coerce PacketCodec instance, Identifier identifier, Operation> original, B packetByteBuf) { + if (customPayloadTypeProvider != null) { + CustomPayload.Type payloadType = customPayloadTypeProvider.get(packetByteBuf, identifier); + + if (payloadType != null) { + return payloadType.codec(); + } + } + + return original.call(instance, identifier); + } +} diff --git a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/mixin/networking/CustomPayloadS2CPacketMixin.java b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/mixin/networking/CustomPayloadS2CPacketMixin.java index 261de56cf..2be96e8ca 100644 --- a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/mixin/networking/CustomPayloadS2CPacketMixin.java +++ b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/mixin/networking/CustomPayloadS2CPacketMixin.java @@ -16,33 +16,51 @@ package net.fabricmc.fabric.mixin.networking; -import org.spongepowered.asm.mixin.Final; +import java.util.List; + +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 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.network.packet.s2c.common.CustomPayloadS2CPacket; -import net.minecraft.util.Identifier; -import net.fabricmc.fabric.impl.networking.NetworkingImpl; -import net.fabricmc.fabric.impl.networking.payload.PayloadHelper; +import net.fabricmc.fabric.impl.networking.FabricCustomPayloadPacketCodec; +import net.fabricmc.fabric.impl.networking.PayloadTypeRegistryImpl; @Mixin(CustomPayloadS2CPacket.class) public class CustomPayloadS2CPacketMixin { - @Shadow - @Final - private static int MAX_PAYLOAD_SIZE; - - @Inject( - method = "readPayload", - at = @At(value = "INVOKE", target = "Lnet/minecraft/network/packet/s2c/common/CustomPayloadS2CPacket;readUnknownPayload(Lnet/minecraft/util/Identifier;Lnet/minecraft/network/PacketByteBuf;)Lnet/minecraft/network/packet/UnknownCustomPayload;"), - cancellable = true + @WrapOperation( + method = "", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/network/packet/CustomPayload;createCodec(Lnet/minecraft/network/packet/CustomPayload$CodecFactory;Ljava/util/List;)Lnet/minecraft/network/codec/PacketCodec;", + ordinal = 0 + ) ) - private static void readPayload(Identifier id, PacketByteBuf buf, CallbackInfoReturnable cir) { - cir.setReturnValue(PayloadHelper.readCustom(id, buf, MAX_PAYLOAD_SIZE, NetworkingImpl.FACTORY_RETAIN.get())); + private static PacketCodec wrapPlayCodec(CustomPayload.CodecFactory unknownCodecFactory, List> types, Operation> original) { + PacketCodec codec = original.call(unknownCodecFactory, types); + FabricCustomPayloadPacketCodec fabricCodec = (FabricCustomPayloadPacketCodec) codec; + fabricCodec.fabric_setPacketCodecProvider((packetByteBuf, identifier) -> PayloadTypeRegistryImpl.PLAY_S2C.get(identifier)); + return codec; + } + + @WrapOperation( + method = "", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/network/packet/CustomPayload;createCodec(Lnet/minecraft/network/packet/CustomPayload$CodecFactory;Ljava/util/List;)Lnet/minecraft/network/codec/PacketCodec;", + ordinal = 1 + ) + ) + private static PacketCodec wrapConfigCodec(CustomPayload.CodecFactory unknownCodecFactory, List> types, Operation> original) { + PacketCodec codec = original.call(unknownCodecFactory, types); + FabricCustomPayloadPacketCodec fabricCodec = (FabricCustomPayloadPacketCodec) codec; + fabricCodec.fabric_setPacketCodecProvider((packetByteBuf, identifier) -> PayloadTypeRegistryImpl.CONFIGURATION_S2C.get(identifier)); + return codec; } } diff --git a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/mixin/networking/NetworkStateInternalPacketHandlerMixin.java b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/mixin/networking/NetworkStateInternalPacketHandlerMixin.java deleted file mode 100644 index 5a0c10021..000000000 --- a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/mixin/networking/NetworkStateInternalPacketHandlerMixin.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * 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.networking; - -import java.util.function.Function; - -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.ModifyVariable; - -import net.minecraft.network.PacketByteBuf; -import net.minecraft.network.packet.Packet; -import net.minecraft.network.packet.c2s.common.CustomPayloadC2SPacket; -import net.minecraft.network.packet.s2c.common.CustomPayloadS2CPacket; - -import net.fabricmc.fabric.impl.networking.NetworkingImpl; -import net.fabricmc.fabric.impl.networking.payload.RetainedPayload; -import net.fabricmc.fabric.impl.networking.payload.UntypedPayload; - -@Mixin(targets = "net.minecraft.network.NetworkState$InternalPacketHandler") -public class NetworkStateInternalPacketHandlerMixin { - /** - * Only retain custom packet buffer to {@link RetainedPayload} on the receiving side, - * otherwise resolve to {@link UntypedPayload}. - */ - @ModifyVariable(method = "register", at = @At("HEAD"), argsOnly = true) - private Function> replaceCustomPayloadFactory(Function> original, Class type) { - if (type == CustomPayloadC2SPacket.class) { - return buf -> { - try { - NetworkingImpl.FACTORY_RETAIN.set(true); - return new CustomPayloadC2SPacket(buf); - } finally { - NetworkingImpl.FACTORY_RETAIN.set(false); - } - }; - } else if (type == CustomPayloadS2CPacket.class) { - return buf -> { - try { - NetworkingImpl.FACTORY_RETAIN.set(true); - return new CustomPayloadS2CPacket(buf); - } finally { - NetworkingImpl.FACTORY_RETAIN.set(false); - } - }; - } - - return original; - } -} diff --git a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/mixin/networking/PacketCodecDispatcherMixin.java b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/mixin/networking/PacketCodecDispatcherMixin.java new file mode 100644 index 000000000..267abf119 --- /dev/null +++ b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/mixin/networking/PacketCodecDispatcherMixin.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.mixin.networking; + +import com.llamalad7.mixinextras.sugar.Local; +import io.netty.buffer.ByteBuf; +import io.netty.handler.codec.EncoderException; +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.network.codec.PacketCodec; +import net.minecraft.network.handler.PacketCodecDispatcher; +import net.minecraft.network.packet.CustomPayload; +import net.minecraft.network.packet.c2s.common.CustomPayloadC2SPacket; +import net.minecraft.network.packet.s2c.common.CustomPayloadS2CPacket; + +@Mixin(PacketCodecDispatcher.class) +public abstract class PacketCodecDispatcherMixin implements PacketCodec { + // Add the custom payload id to the error message + @Inject(method = "encode(Lio/netty/buffer/ByteBuf;Ljava/lang/Object;)V", at = @At(value = "NEW", target = "(Ljava/lang/String;Ljava/lang/Throwable;)Lio/netty/handler/codec/EncoderException;")) + public void encode(B byteBuf, V packet, CallbackInfo ci, @Local(ordinal = 1) T packetId, @Local Exception e) { + CustomPayload payload = null; + + if (packet instanceof CustomPayloadC2SPacket customPayloadC2SPacket) { + payload = customPayloadC2SPacket.payload(); + } else if (packet instanceof CustomPayloadS2CPacket customPayloadS2CPacket) { + payload = customPayloadS2CPacket.payload(); + } + + if (payload != null && payload.getId() != null) { + throw new EncoderException("Failed to encode packet '%s' (%s)".formatted(packetId, payload.getId().id().toString()), e); + } + } +} diff --git a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/mixin/networking/ServerCommonNetworkHandlerMixin.java b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/mixin/networking/ServerCommonNetworkHandlerMixin.java index 2d90a2e21..ab3575156 100644 --- a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/mixin/networking/ServerCommonNetworkHandlerMixin.java +++ b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/mixin/networking/ServerCommonNetworkHandlerMixin.java @@ -21,13 +21,12 @@ 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.network.packet.CustomPayload; import net.minecraft.network.packet.c2s.common.CommonPongC2SPacket; import net.minecraft.network.packet.c2s.common.CustomPayloadC2SPacket; import net.minecraft.server.network.ServerCommonNetworkHandler; import net.fabricmc.fabric.impl.networking.NetworkHandlerExtensions; -import net.fabricmc.fabric.impl.networking.payload.ResolvablePayload; -import net.fabricmc.fabric.impl.networking.payload.RetainedPayload; import net.fabricmc.fabric.impl.networking.server.ServerConfigurationNetworkAddon; import net.fabricmc.fabric.impl.networking.server.ServerPlayNetworkAddon; @@ -35,23 +34,20 @@ import net.fabricmc.fabric.impl.networking.server.ServerPlayNetworkAddon; public abstract class ServerCommonNetworkHandlerMixin implements NetworkHandlerExtensions { @Inject(method = "onCustomPayload", at = @At("HEAD"), cancellable = true) private void handleCustomPayloadReceivedAsync(CustomPayloadC2SPacket packet, CallbackInfo ci) { - if (packet.payload() instanceof ResolvablePayload payload) { - boolean handled; + final CustomPayload payload = packet.payload(); - if (getAddon() instanceof ServerPlayNetworkAddon addon) { - handled = addon.handle(payload); - } else if (getAddon() instanceof ServerConfigurationNetworkAddon addon) { - handled = addon.handle(payload); - } else { - throw new IllegalStateException("Unknown addon"); - } + boolean handled; - if (handled) { - ci.cancel(); - } else if (payload instanceof RetainedPayload retained) { - retained.buf().skipBytes(retained.buf().readableBytes()); - retained.buf().release(); - } + if (getAddon() instanceof ServerPlayNetworkAddon addon) { + handled = addon.handle(payload); + } else if (getAddon() instanceof ServerConfigurationNetworkAddon addon) { + handled = addon.handle(payload); + } else { + throw new IllegalStateException("Unknown addon"); + } + + if (handled) { + ci.cancel(); } } diff --git a/fabric-networking-api-v1/src/main/resources/fabric-networking-api-v1.accesswidener b/fabric-networking-api-v1/src/main/resources/fabric-networking-api-v1.accesswidener index 0c67f5c9a..16130ceb7 100644 --- a/fabric-networking-api-v1/src/main/resources/fabric-networking-api-v1.accesswidener +++ b/fabric-networking-api-v1/src/main/resources/fabric-networking-api-v1.accesswidener @@ -1,3 +1,2 @@ accessWidener v2 named -accessible class net/minecraft/network/NetworkState$InternalPacketHandler diff --git a/fabric-networking-api-v1/src/main/resources/fabric-networking-api-v1.mixins.json b/fabric-networking-api-v1/src/main/resources/fabric-networking-api-v1.mixins.json index 163f5999b..73c21a558 100644 --- a/fabric-networking-api-v1/src/main/resources/fabric-networking-api-v1.mixins.json +++ b/fabric-networking-api-v1/src/main/resources/fabric-networking-api-v1.mixins.json @@ -3,14 +3,15 @@ "package": "net.fabricmc.fabric.mixin.networking", "compatibilityLevel": "JAVA_17", "mixins": [ + "PacketCodecDispatcherMixin", "ClientConnectionMixin", "CommandManagerMixin", "CustomPayloadC2SPacketMixin", "CustomPayloadS2CPacketMixin", + "CustomPayloadPacketCodecMixin", "EntityTrackerEntryMixin", "LoginQueryRequestS2CPacketMixin", "LoginQueryResponseC2SPacketMixin", - "NetworkStateInternalPacketHandlerMixin", "PlayerManagerMixin", "ServerCommonNetworkHandlerMixin", "ServerConfigurationNetworkHandlerMixin", diff --git a/fabric-networking-api-v1/src/main/resources/fabric.mod.json b/fabric-networking-api-v1/src/main/resources/fabric.mod.json index f86833993..2c9982b43 100644 --- a/fabric-networking-api-v1/src/main/resources/fabric.mod.json +++ b/fabric-networking-api-v1/src/main/resources/fabric.mod.json @@ -17,7 +17,8 @@ ], "entrypoints": { "main": [ - "net.fabricmc.fabric.impl.networking.CommonPacketsImpl::init" + "net.fabricmc.fabric.impl.networking.CommonPacketsImpl::init", + "net.fabricmc.fabric.impl.networking.NetworkingImpl::init" ], "client": [ "net.fabricmc.fabric.impl.networking.client.ClientNetworkingImpl::clientInit" 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 5702c9efc..f5a1a1a73 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 @@ -21,7 +21,7 @@ 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.Mockito.any; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -41,8 +41,10 @@ import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; import net.minecraft.client.network.ClientConfigurationNetworkHandler; -import net.minecraft.network.NetworkState; +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.network.ServerConfigurationNetworkHandler; import net.minecraft.util.Identifier; @@ -51,6 +53,7 @@ import net.fabricmc.fabric.api.client.networking.v1.ClientConfigurationNetworkin 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; @@ -59,11 +62,13 @@ 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.payload.ResolvablePayload; import net.fabricmc.fabric.impl.networking.server.ServerConfigurationNetworkAddon; import net.fabricmc.fabric.impl.networking.server.ServerNetworkingImpl; public class CommonPacketTests { + private static final CustomPayload.Type VERSION_PAYLOAD_TYPE = new CustomPayload.Type<>(CommonVersionPayload.ID, CommonVersionPayload.CODEC); + private static final CustomPayload.Type REGISTER_PAYLOAD_TYPE = new CustomPayload.Type<>(CommonRegisterPayload.ID, CommonRegisterPayload.CODEC); + private PacketSender packetSender; private ChannelInfoHolder channelInfoHolder; @@ -73,16 +78,41 @@ public class CommonPacketTests { private ServerConfigurationNetworkHandler serverNetworkHandler; private ServerConfigurationNetworkAddon serverAddon; + private ClientConfigurationNetworking.Context clientContext; + private ServerConfigurationNetworking.Context serverContext; + @BeforeAll static void beforeAll() { CommonPacketsImpl.init(); ClientNetworkingImpl.clientInit(); - // Register a receiver to send in the play registry response - ClientPlayNetworking.registerGlobalReceiver(new Identifier("fabric", "global_client"), (client, handler, buf, responseSender) -> { + // Register the packet codec on both sides + PayloadTypeRegistry.playS2C().register(TestPayload.ID, TestPayload.CODEC); + + // Listen for the payload on the client + ClientPlayNetworking.registerGlobalReceiver(TestPayload.ID, (payload, context) -> { + System.out.println(payload.data()); }); } + private record TestPayload(String data) implements CustomPayload { + static final CustomPayload.Id ID = new CustomPayload.Id<>(new Identifier("fabric", "global_client")); + static final PacketCodec CODEC = CustomPayload.codecOf(TestPayload::write, TestPayload::new); + + TestPayload(RegistryByteBuf buf) { + this(buf.readString()); + } + + private void write(RegistryByteBuf buf) { + buf.writeString(data); + } + + @Override + public Id getId() { + return ID; + } + } + @BeforeEach void setUp() { packetSender = mock(PacketSender.class); @@ -97,27 +127,41 @@ public class CommonPacketTests { serverAddon = mock(ServerConfigurationNetworkAddon.class); when(ServerNetworkingImpl.getAddon(serverNetworkHandler)).thenReturn(serverAddon); when(serverAddon.getChannelInfoHolder()).thenReturn(channelInfoHolder); + + ClientNetworkingImpl.setClientConfigurationAddon(clientAddon); + + clientContext = () -> packetSender; + serverContext = new ServerConfigurationNetworking.Context() { + @Override + public ServerConfigurationNetworkHandler networkHandler() { + return serverNetworkHandler; + } + + @Override + public PacketSender responseSender() { + return packetSender; + } + }; } // Test handling the version packet on the client @Test void handleVersionPacketClient() { - ResolvablePayload.Handler packetHandler = ClientNetworkingImpl.CONFIGURATION.getHandler(CommonVersionPayload.PACKET_ID); + ClientConfigurationNetworking.ConfigurationPayloadHandler packetHandler = (ClientConfigurationNetworking.ConfigurationPayloadHandler) ClientNetworkingImpl.CONFIGURATION.getHandler(CommonVersionPayload.ID.id()); assertNotNull(packetHandler); // Receive a packet from the server PacketByteBuf buf = PacketByteBufs.create(); buf.writeIntArray(new int[]{1, 2, 3}); - // The actual handler doesn't copy the buffer - ClientConfigurationNetworking.ConfigurationChannelHandler actualHandler = (ClientConfigurationNetworking.ConfigurationChannelHandler) packetHandler.actual(); - actualHandler.receive(null, clientNetworkHandler, buf, packetSender); + CommonVersionPayload payload = CommonVersionPayload.CODEC.decode(buf); + packetHandler.receive(payload, clientContext); // Assert the entire packet was read assertEquals(0, buf.readableBytes()); // Check the response we are sending back to the server - PacketByteBuf response = readResponse(packetSender); + PacketByteBuf response = readResponse(packetSender, VERSION_PAYLOAD_TYPE); assertArrayEquals(new int[]{1}, response.readIntArray()); assertEquals(0, response.readableBytes()); @@ -127,7 +171,7 @@ public class CommonPacketTests { // Test handling the version packet on the client, when the server sends unsupported versions @Test void handleVersionPacketClientUnsupported() { - ResolvablePayload.Handler packetHandler = ClientNetworkingImpl.CONFIGURATION.getHandler(CommonVersionPayload.PACKET_ID); + ClientConfigurationNetworking.ConfigurationPayloadHandler packetHandler = (ClientConfigurationNetworking.ConfigurationPayloadHandler) ClientNetworkingImpl.CONFIGURATION.getHandler(CommonVersionPayload.ID.id()); assertNotNull(packetHandler); // Receive a packet from the server @@ -135,8 +179,8 @@ public class CommonPacketTests { buf.writeIntArray(new int[]{2, 3}); // We only support version 1 assertThrows(UnsupportedOperationException.class, () -> { - ClientConfigurationNetworking.ConfigurationChannelHandler actualHandler = (ClientConfigurationNetworking.ConfigurationChannelHandler) packetHandler.actual(); - actualHandler.receive(null, clientNetworkHandler, buf, packetSender); + CommonVersionPayload payload = CommonVersionPayload.CODEC.decode(buf); + packetHandler.receive(payload, clientContext); }); // Assert the entire packet was read @@ -146,15 +190,15 @@ public class CommonPacketTests { // Test handling the version packet on the server @Test void handleVersionPacketServer() { - ResolvablePayload.Handler packetHandler = ServerNetworkingImpl.CONFIGURATION.getHandler(CommonVersionPayload.PACKET_ID); + ServerConfigurationNetworking.ConfigurationPacketHandler packetHandler = (ServerConfigurationNetworking.ConfigurationPacketHandler) ServerNetworkingImpl.CONFIGURATION.getHandler(CommonVersionPayload.ID.id()); assertNotNull(packetHandler); // Receive a packet from the client PacketByteBuf buf = PacketByteBufs.create(); buf.writeIntArray(new int[]{1, 2, 3}); - ServerConfigurationNetworking.ConfigurationChannelHandler actualHandler = (ServerConfigurationNetworking.ConfigurationChannelHandler) packetHandler.actual(); - actualHandler.receive(null, serverNetworkHandler, buf, null); + CommonVersionPayload payload = CommonVersionPayload.CODEC.decode(buf); + packetHandler.receive(payload, serverContext); // Assert the entire packet was read assertEquals(0, buf.readableBytes()); @@ -164,7 +208,7 @@ public class CommonPacketTests { // Test handling the version packet on the server unsupported version @Test void handleVersionPacketServerUnsupported() { - ResolvablePayload.Handler packetHandler = ServerNetworkingImpl.CONFIGURATION.getHandler(CommonVersionPayload.PACKET_ID); + ServerConfigurationNetworking.ConfigurationPacketHandler packetHandler = (ServerConfigurationNetworking.ConfigurationPacketHandler) ServerNetworkingImpl.CONFIGURATION.getHandler(CommonVersionPayload.ID.id()); assertNotNull(packetHandler); // Receive a packet from the client @@ -172,8 +216,8 @@ public class CommonPacketTests { buf.writeIntArray(new int[]{3}); // Server only supports version 1 assertThrows(UnsupportedOperationException.class, () -> { - ServerConfigurationNetworking.ConfigurationChannelHandler actualHandler = (ServerConfigurationNetworking.ConfigurationChannelHandler) packetHandler.actual(); - actualHandler.receive(null, serverNetworkHandler, buf, null); + CommonVersionPayload payload = CommonVersionPayload.CODEC.decode(buf); + packetHandler.receive(payload, serverContext); }); // Assert the entire packet was read @@ -183,7 +227,7 @@ public class CommonPacketTests { // Test handing the play registry packet on the client configuration handler @Test void handlePlayRegistryClient() { - ResolvablePayload.Handler packetHandler = ClientNetworkingImpl.CONFIGURATION.getHandler(CommonRegisterPayload.PACKET_ID); + ClientConfigurationNetworking.ConfigurationPayloadHandler packetHandler = (ClientConfigurationNetworking.ConfigurationPayloadHandler) ClientNetworkingImpl.CONFIGURATION.getHandler(CommonRegisterPayload.ID.id()); assertNotNull(packetHandler); when(clientAddon.getNegotiatedVersion()).thenReturn(1); @@ -194,15 +238,15 @@ public class CommonPacketTests { buf.writeString("play"); // Target phase buf.writeCollection(List.of(new Identifier("fabric", "test")), PacketByteBuf::writeIdentifier); - ClientConfigurationNetworking.ConfigurationChannelHandler actualHandler = (ClientConfigurationNetworking.ConfigurationChannelHandler) packetHandler.actual(); - actualHandler.receive(null, clientNetworkHandler, buf, packetSender); + CommonRegisterPayload payload = CommonRegisterPayload.CODEC.decode(buf); + packetHandler.receive(payload, clientContext); // Assert the entire packet was read assertEquals(0, buf.readableBytes()); - assertIterableEquals(List.of(new Identifier("fabric", "test")), channelInfoHolder.getPendingChannelsNames(NetworkState.PLAY)); + assertIterableEquals(List.of(new Identifier("fabric", "test")), channelInfoHolder.fabric_getPendingChannelsNames(NetworkPhase.PLAY)); // Check the response we are sending back to the server - PacketByteBuf response = readResponse(packetSender); + PacketByteBuf response = readResponse(packetSender, REGISTER_PAYLOAD_TYPE); assertEquals(1, response.readVarInt()); assertEquals("play", response.readString()); assertIterableEquals(List.of(new Identifier("fabric", "global_client")), response.readCollection(HashSet::new, PacketByteBuf::readIdentifier)); @@ -212,7 +256,7 @@ public class CommonPacketTests { // Test handling the configuration registry packet on the client configuration handler @Test void handleConfigurationRegistryClient() { - ResolvablePayload.Handler packetHandler = ClientNetworkingImpl.CONFIGURATION.getHandler(CommonRegisterPayload.PACKET_ID); + ClientConfigurationNetworking.ConfigurationPayloadHandler packetHandler = (ClientConfigurationNetworking.ConfigurationPayloadHandler) ClientNetworkingImpl.CONFIGURATION.getHandler(CommonRegisterPayload.ID.id()); assertNotNull(packetHandler); when(clientAddon.getNegotiatedVersion()).thenReturn(1); @@ -224,15 +268,15 @@ public class CommonPacketTests { buf.writeString("configuration"); // Target phase buf.writeCollection(List.of(new Identifier("fabric", "test")), PacketByteBuf::writeIdentifier); - ClientConfigurationNetworking.ConfigurationChannelHandler actualHandler = (ClientConfigurationNetworking.ConfigurationChannelHandler) packetHandler.actual(); - actualHandler.receive(null, clientNetworkHandler, buf, packetSender); + CommonRegisterPayload payload = CommonRegisterPayload.CODEC.decode(buf); + packetHandler.receive(payload, clientContext); // Assert the entire packet was read assertEquals(0, buf.readableBytes()); verify(clientAddon, times(1)).onCommonRegisterPacket(any()); // Check the response we are sending back to the server - PacketByteBuf response = readResponse(packetSender); + PacketByteBuf response = readResponse(packetSender, REGISTER_PAYLOAD_TYPE); assertEquals(1, response.readVarInt()); assertEquals("configuration", response.readString()); assertIterableEquals(List.of(new Identifier("fabric", "global_configuration_client")), response.readCollection(HashSet::new, PacketByteBuf::readIdentifier)); @@ -242,7 +286,7 @@ public class CommonPacketTests { // Test handing the play registry packet on the server configuration handler @Test void handlePlayRegistryServer() { - ResolvablePayload.Handler packetHandler = ServerNetworkingImpl.CONFIGURATION.getHandler(CommonRegisterPayload.PACKET_ID); + ServerConfigurationNetworking.ConfigurationPacketHandler packetHandler = (ServerConfigurationNetworking.ConfigurationPacketHandler) ServerNetworkingImpl.CONFIGURATION.getHandler(CommonRegisterPayload.ID.id()); assertNotNull(packetHandler); when(serverAddon.getNegotiatedVersion()).thenReturn(1); @@ -253,18 +297,18 @@ public class CommonPacketTests { buf.writeString("play"); // Target phase buf.writeCollection(List.of(new Identifier("fabric", "test")), PacketByteBuf::writeIdentifier); - ServerConfigurationNetworking.ConfigurationChannelHandler actualHandler = (ServerConfigurationNetworking.ConfigurationChannelHandler) packetHandler.actual(); - actualHandler.receive(null, serverNetworkHandler, buf, null); + CommonRegisterPayload payload = CommonRegisterPayload.CODEC.decode(buf); + packetHandler.receive(payload, serverContext); // Assert the entire packet was read assertEquals(0, buf.readableBytes()); - assertIterableEquals(List.of(new Identifier("fabric", "test")), channelInfoHolder.getPendingChannelsNames(NetworkState.PLAY)); + assertIterableEquals(List.of(new Identifier("fabric", "test")), channelInfoHolder.fabric_getPendingChannelsNames(NetworkPhase.PLAY)); } // Test handing the configuration registry packet on the server configuration handler @Test void handleConfigurationRegistryServer() { - ResolvablePayload.Handler packetHandler = ServerNetworkingImpl.CONFIGURATION.getHandler(CommonRegisterPayload.PACKET_ID); + ServerConfigurationNetworking.ConfigurationPacketHandler packetHandler = (ServerConfigurationNetworking.ConfigurationPacketHandler) ServerNetworkingImpl.CONFIGURATION.getHandler(CommonRegisterPayload.ID.id()); assertNotNull(packetHandler); when(serverAddon.getNegotiatedVersion()).thenReturn(1); @@ -275,8 +319,8 @@ public class CommonPacketTests { buf.writeString("configuration"); // Target phase buf.writeCollection(List.of(new Identifier("fabric", "test")), PacketByteBuf::writeIdentifier); - ServerConfigurationNetworking.ConfigurationChannelHandler actualHandler = (ServerConfigurationNetworking.ConfigurationChannelHandler) packetHandler.actual(); - actualHandler.receive(null, serverNetworkHandler, buf, null); + CommonRegisterPayload payload = CommonRegisterPayload.CODEC.decode(buf); + packetHandler.receive(payload, serverContext); // Assert the entire packet was read assertEquals(0, buf.readableBytes()); @@ -318,12 +362,13 @@ public class CommonPacketTests { assertEquals(3, CommonPacketsImpl.getHighestCommonVersion(a, b)); } - private static PacketByteBuf readResponse(PacketSender packetSender) { + private static PacketByteBuf readResponse(PacketSender packetSender, CustomPayload.Type type) { ArgumentCaptor responseCaptor = ArgumentCaptor.forClass(CustomPayload.class); verify(packetSender, times(1)).sendPacket(responseCaptor.capture()); - PacketByteBuf buf = PacketByteBufs.create(); - responseCaptor.getValue().write(buf); + final T payload = (T) responseCaptor.getValue(); + final PacketByteBuf buf = PacketByteBufs.create(); + type.codec().encode(buf, payload); return buf; } @@ -335,10 +380,10 @@ public class CommonPacketTests { } private static class MockChannelInfoHolder implements ChannelInfoHolder { - private final Map> playChannels = new ConcurrentHashMap<>(); + private final Map> playChannels = new ConcurrentHashMap<>(); @Override - public Collection getPendingChannelsNames(NetworkState state) { + public Collection fabric_getPendingChannelsNames(NetworkPhase state) { return this.playChannels.computeIfAbsent(state, (key) -> Collections.newSetFromMap(new ConcurrentHashMap<>())); } } diff --git a/fabric-networking-api-v1/src/test/java/net/fabricmc/fabric/test/networking/unit/PayloadTypeRegistryTests.java b/fabric-networking-api-v1/src/test/java/net/fabricmc/fabric/test/networking/unit/PayloadTypeRegistryTests.java new file mode 100644 index 000000000..60032215a --- /dev/null +++ b/fabric-networking-api-v1/src/test/java/net/fabricmc/fabric/test/networking/unit/PayloadTypeRegistryTests.java @@ -0,0 +1,154 @@ +/* + * 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.networking.unit; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.fail; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import net.minecraft.Bootstrap; +import net.minecraft.SharedConstants; +import net.minecraft.network.PacketByteBuf; +import net.minecraft.network.RegistryByteBuf; +import net.minecraft.network.codec.PacketCodec; +import net.minecraft.network.codec.PacketCodecs; +import net.minecraft.network.packet.CustomPayload; +import net.minecraft.network.packet.c2s.common.CustomPayloadC2SPacket; +import net.minecraft.network.packet.s2c.common.CustomPayloadS2CPacket; + +import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; +import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry; + +public class PayloadTypeRegistryTests { + @BeforeAll + static void beforeAll() { + SharedConstants.createGameVersion(); + Bootstrap.initialize(); + + PayloadTypeRegistry.playC2S().register(C2SPlayPayload.ID, C2SPlayPayload.CODEC); + PayloadTypeRegistry.playS2C().register(S2CPlayPayload.ID, S2CPlayPayload.CODEC); + + PayloadTypeRegistry.configurationC2S().register(C2SConfigPayload.ID, C2SConfigPayload.CODEC); + PayloadTypeRegistry.configurationS2C().register(S2CConfigPayload.ID, S2CConfigPayload.CODEC); + } + + @Test + void C2SPlay() { + RegistryByteBuf buf = new RegistryByteBuf(PacketByteBufs.create(), null); + + var packetToSend = new CustomPayloadC2SPacket(new C2SPlayPayload("Hello")); + CustomPayloadC2SPacket.CODEC.encode(buf, packetToSend); + + CustomPayloadC2SPacket decodedPacket = CustomPayloadC2SPacket.CODEC.decode(buf); + + if (decodedPacket.payload() instanceof C2SPlayPayload payload) { + assertEquals("Hello", payload.value()); + } else { + fail(); + } + } + + @Test + void S2CPlay() { + RegistryByteBuf buf = new RegistryByteBuf(PacketByteBufs.create(), null); + + var packetToSend = new CustomPayloadS2CPacket(new S2CPlayPayload("Hello")); + CustomPayloadS2CPacket.PLAY_CODEC.encode(buf, packetToSend); + + CustomPayloadS2CPacket decodedPacket = CustomPayloadS2CPacket.PLAY_CODEC.decode(buf); + + if (decodedPacket.payload() instanceof S2CPlayPayload payload) { + assertEquals("Hello", payload.value()); + } else { + fail(); + } + } + + @Test + void C2SConfig() { + PacketByteBuf buf = PacketByteBufs.create(); + + var packetToSend = new CustomPayloadC2SPacket(new C2SConfigPayload("Hello")); + CustomPayloadC2SPacket.CODEC.encode(buf, packetToSend); + + CustomPayloadC2SPacket decodedPacket = CustomPayloadC2SPacket.CODEC.decode(buf); + + if (decodedPacket.payload() instanceof C2SConfigPayload payload) { + assertEquals("Hello", payload.value()); + } else { + fail(); + } + } + + @Test + void S2CConfig() { + PacketByteBuf buf = PacketByteBufs.create(); + + var packetToSend = new CustomPayloadS2CPacket(new S2CConfigPayload("Hello")); + CustomPayloadS2CPacket.CONFIGURATION_CODEC.encode(buf, packetToSend); + + CustomPayloadS2CPacket decodedPacket = CustomPayloadS2CPacket.CONFIGURATION_CODEC.decode(buf); + + if (decodedPacket.payload() instanceof S2CConfigPayload payload) { + assertEquals("Hello", payload.value()); + } else { + fail(); + } + } + + private record C2SPlayPayload(String value) implements CustomPayload { + public static final CustomPayload.Id ID = CustomPayload.id("fabric:c2s_play"); + public static final PacketCodec CODEC = PacketCodecs.STRING.xmap(C2SPlayPayload::new, C2SPlayPayload::value).cast(); + + @Override + public Id getId() { + return ID; + } + } + + private record S2CPlayPayload(String value) implements CustomPayload { + public static final CustomPayload.Id ID = CustomPayload.id("fabric:s2c_play"); + public static final PacketCodec CODEC = PacketCodecs.STRING.xmap(S2CPlayPayload::new, S2CPlayPayload::value).cast(); + + @Override + public Id getId() { + return ID; + } + } + + private record C2SConfigPayload(String value) implements CustomPayload { + public static final CustomPayload.Id ID = CustomPayload.id("fabric:c2s_config"); + public static final PacketCodec CODEC = PacketCodecs.STRING.xmap(C2SConfigPayload::new, C2SConfigPayload::value).cast(); + + @Override + public Id getId() { + return ID; + } + } + + private record S2CConfigPayload(String value) implements CustomPayload { + public static final CustomPayload.Id ID = CustomPayload.id("fabric:s2c_config"); + public static final PacketCodec CODEC = PacketCodecs.STRING.xmap(S2CConfigPayload::new, S2CConfigPayload::value).cast(); + + @Override + public Id getId() { + return ID; + } + } +} diff --git a/fabric-networking-api-v1/src/testmod/java/net/fabricmc/fabric/test/networking/channeltest/NetworkingChannelTest.java b/fabric-networking-api-v1/src/testmod/java/net/fabricmc/fabric/test/networking/channeltest/NetworkingChannelTest.java index 4cdc241f2..f75d09d3e 100644 --- a/fabric-networking-api-v1/src/testmod/java/net/fabricmc/fabric/test/networking/channeltest/NetworkingChannelTest.java +++ b/fabric-networking-api-v1/src/testmod/java/net/fabricmc/fabric/test/networking/channeltest/NetworkingChannelTest.java @@ -35,6 +35,8 @@ import com.mojang.brigadier.tree.LiteralCommandNode; import net.minecraft.command.CommandSource; import net.minecraft.command.EntitySelector; +import net.minecraft.network.RegistryByteBuf; +import net.minecraft.network.packet.CustomPayload; import net.minecraft.server.command.ServerCommandSource; import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.text.Text; @@ -43,6 +45,7 @@ import net.minecraft.util.Identifier; import net.fabricmc.api.ModInitializer; import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback; import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; +import net.fabricmc.fabric.impl.networking.PayloadTypeRegistryImpl; public final class NetworkingChannelTest implements ModInitializer { @Override @@ -88,7 +91,7 @@ public final class NetworkingChannelTest implements ModInitializer { }); } - private static CompletableFuture suggestReceivableChannels(CommandContext context, SuggestionsBuilder builder) throws CommandSyntaxException { + private static CompletableFuture suggestReceivableChannels(CommandContext context, SuggestionsBuilder builder) { final ServerPlayerEntity player = context.getSource().getPlayer(); return CommandSource.suggestIdentifiers(ServerPlayNetworking.getReceived(player), builder); @@ -101,20 +104,24 @@ public final class NetworkingChannelTest implements ModInitializer { throw new SimpleCommandExceptionType(Text.literal(String.format("Cannot register channel %s twice for server player", channel))).create(); } - ServerPlayNetworking.registerReceiver(executor.networkHandler, channel, (server, player, handler, buf, sender) -> { - System.out.printf("Received packet on channel %s%n", channel); - }); + CustomPayload.Type payloadType = PayloadTypeRegistryImpl.PLAY_C2S.get(channel); - context.getSource().sendFeedback(() -> Text.literal(String.format("Registered channel %s for %s", channel, executor.getDisplayName())), false); - - return 1; + if (payloadType != null) { + ServerPlayNetworking.registerReceiver(executor.networkHandler, payloadType.id(), (payload, ctx) -> { + System.out.printf("Received packet on channel %s%n", payloadType.id().id()); + }); + context.getSource().sendFeedback(() -> Text.literal(String.format("Registered channel %s for %s", channel, executor.getDisplayName())), false); + return 1; + } else { + throw new SimpleCommandExceptionType(Text.literal("Unknown channel id")).create(); + } } private static int unregisterChannel(CommandContext context, ServerPlayerEntity player) throws CommandSyntaxException { final Identifier channel = getIdentifier(context, "channel"); if (!ServerPlayNetworking.getReceived(player).contains(channel)) { - throw new SimpleCommandExceptionType(Text.literal("Cannot unregister channel the server player entity cannot recieve packets on")).create(); + throw new SimpleCommandExceptionType(Text.literal("Cannot unregister channel the server player entity cannot receive packets on")).create(); } ServerPlayNetworking.unregisterReceiver(player.networkHandler, channel); diff --git a/fabric-networking-api-v1/src/testmod/java/net/fabricmc/fabric/test/networking/configuration/NetworkingConfigurationTest.java b/fabric-networking-api-v1/src/testmod/java/net/fabricmc/fabric/test/networking/configuration/NetworkingConfigurationTest.java index 01313569c..5191d1e99 100644 --- a/fabric-networking-api-v1/src/testmod/java/net/fabricmc/fabric/test/networking/configuration/NetworkingConfigurationTest.java +++ b/fabric-networking-api-v1/src/testmod/java/net/fabricmc/fabric/test/networking/configuration/NetworkingConfigurationTest.java @@ -19,14 +19,15 @@ package net.fabricmc.fabric.test.networking.configuration; import java.util.function.Consumer; import net.minecraft.network.PacketByteBuf; +import net.minecraft.network.codec.PacketCodec; +import net.minecraft.network.packet.CustomPayload; import net.minecraft.network.packet.Packet; import net.minecraft.server.network.ServerPlayerConfigurationTask; import net.minecraft.text.Text; import net.minecraft.util.Identifier; import net.fabricmc.api.ModInitializer; -import net.fabricmc.fabric.api.networking.v1.FabricPacket; -import net.fabricmc.fabric.api.networking.v1.PacketType; +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.test.networking.NetworkingTestmods; @@ -37,9 +38,12 @@ import net.fabricmc.fabric.test.networking.NetworkingTestmods; public class NetworkingConfigurationTest implements ModInitializer { @Override public void onInitialize() { + PayloadTypeRegistry.configurationS2C().register(ConfigurationPacket.ID, ConfigurationPacket.CODEC); + PayloadTypeRegistry.configurationC2S().register(ConfigurationCompletePacket.ID, ConfigurationCompletePacket.CODEC); + ServerConfigurationConnectionEvents.CONFIGURE.register((handler, server) -> { // You must check to see if the client can handle your config task - if (ServerConfigurationNetworking.canSend(handler, ConfigurationPacket.PACKET_TYPE)) { + if (ServerConfigurationNetworking.canSend(handler, ConfigurationPacket.ID)) { handler.addTask(new TestConfigurationTask("Example data")); } else { // You can opt to disconnect the client if it cannot handle the configuration task @@ -47,8 +51,8 @@ public class NetworkingConfigurationTest implements ModInitializer { } }); - ServerConfigurationNetworking.registerGlobalReceiver(ConfigurationCompletePacket.PACKET_TYPE, (packet, networkHandler, responseSender) -> { - networkHandler.completeTask(TestConfigurationTask.KEY); + ServerConfigurationNetworking.registerGlobalReceiver(ConfigurationCompletePacket.ID, (packet, context) -> { + context.networkHandler().completeTask(TestConfigurationTask.KEY); }); } @@ -67,38 +71,35 @@ public class NetworkingConfigurationTest implements ModInitializer { } } - public record ConfigurationPacket(String data) implements FabricPacket { - public static final PacketType PACKET_TYPE = PacketType.create(new Identifier(NetworkingTestmods.ID, "configure"), ConfigurationPacket::new); + public record ConfigurationPacket(String data) implements CustomPayload { + public static final CustomPayload.Id ID = new Id<>(new Identifier(NetworkingTestmods.ID, "configure")); + public static final PacketCodec CODEC = CustomPayload.codecOf(ConfigurationPacket::write, ConfigurationPacket::new); public ConfigurationPacket(PacketByteBuf buf) { this(buf.readString()); } - @Override public void write(PacketByteBuf buf) { buf.writeString(data); } @Override - public PacketType getType() { - return PACKET_TYPE; + public Id getId() { + return ID; } } - public record ConfigurationCompletePacket() implements FabricPacket { - public static final PacketType PACKET_TYPE = PacketType.create(new Identifier(NetworkingTestmods.ID, "configure_complete"), ConfigurationCompletePacket::new); + public static class ConfigurationCompletePacket implements CustomPayload { + public static final ConfigurationCompletePacket INSTANCE = new ConfigurationCompletePacket(); + public static final CustomPayload.Id ID = new Id<>(new Identifier(NetworkingTestmods.ID, "configure_complete")); + public static final PacketCodec CODEC = PacketCodec.unit(INSTANCE); - public ConfigurationCompletePacket(PacketByteBuf buf) { - this(); + private ConfigurationCompletePacket() { } @Override - public void write(PacketByteBuf buf) { - } - - @Override - public PacketType getType() { - return PACKET_TYPE; + public Id getId() { + return ID; } } } diff --git a/fabric-networking-api-v1/src/testmod/java/net/fabricmc/fabric/test/networking/keybindreciever/KeybindPayload.java b/fabric-networking-api-v1/src/testmod/java/net/fabricmc/fabric/test/networking/keybindreciever/KeybindPayload.java new file mode 100644 index 000000000..f1e51210b --- /dev/null +++ b/fabric-networking-api-v1/src/testmod/java/net/fabricmc/fabric/test/networking/keybindreciever/KeybindPayload.java @@ -0,0 +1,36 @@ +/* + * 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.networking.keybindreciever; + +import net.minecraft.network.RegistryByteBuf; +import net.minecraft.network.codec.PacketCodec; +import net.minecraft.network.packet.CustomPayload; + +import net.fabricmc.fabric.test.networking.NetworkingTestmods; + +public class KeybindPayload implements CustomPayload { + public static final KeybindPayload INSTANCE = new KeybindPayload(); + public static final CustomPayload.Id ID = new CustomPayload.Id<>(NetworkingTestmods.id("keybind_press_test")); + public static final PacketCodec CODEC = PacketCodec.unit(INSTANCE); + + private KeybindPayload() { } + + @Override + public Id getId() { + return ID; + } +} diff --git a/fabric-networking-api-v1/src/testmod/java/net/fabricmc/fabric/test/networking/keybindreciever/NetworkingKeybindPacketTest.java b/fabric-networking-api-v1/src/testmod/java/net/fabricmc/fabric/test/networking/keybindreciever/NetworkingKeybindPacketTest.java index 64fc63acf..0c4c86599 100644 --- a/fabric-networking-api-v1/src/testmod/java/net/fabricmc/fabric/test/networking/keybindreciever/NetworkingKeybindPacketTest.java +++ b/fabric-networking-api-v1/src/testmod/java/net/fabricmc/fabric/test/networking/keybindreciever/NetworkingKeybindPacketTest.java @@ -16,31 +16,24 @@ package net.fabricmc.fabric.test.networking.keybindreciever; -import net.minecraft.network.PacketByteBuf; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.network.ServerPlayNetworkHandler; -import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.text.Text; import net.minecraft.util.Formatting; -import net.minecraft.util.Identifier; import net.fabricmc.api.ModInitializer; -import net.fabricmc.fabric.api.networking.v1.PacketSender; +import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry; import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents; import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; -import net.fabricmc.fabric.test.networking.NetworkingTestmods; // Listens for a packet from the client which is sent to the server when a keybinding is pressed. // In response the server will send a message containing the keybind text letting the client know it pressed that key. public final class NetworkingKeybindPacketTest implements ModInitializer { - public static final Identifier KEYBINDING_PACKET_ID = NetworkingTestmods.id("keybind_press_test"); - - private static void receive(MinecraftServer server, ServerPlayerEntity player, ServerPlayNetworkHandler handler, PacketByteBuf buf, PacketSender responseSender) { - server.execute(() -> player.sendMessage(Text.literal("So you pressed ").append(Text.keybind("fabric-networking-api-v1-testmod-keybind").styled(style -> style.withFormatting(Formatting.BLUE))), false)); + private static void receive(KeybindPayload payload, ServerPlayNetworking.Context context) { + context.player().server.execute(() -> context.player().sendMessage(Text.literal("So you pressed ").append(Text.keybind("fabric-networking-api-v1-testmod-keybind").styled(style -> style.withFormatting(Formatting.BLUE))), false)); } @Override public void onInitialize() { - ServerPlayConnectionEvents.INIT.register((handler, server) -> ServerPlayNetworking.registerReceiver(handler, KEYBINDING_PACKET_ID, NetworkingKeybindPacketTest::receive)); + PayloadTypeRegistry.playC2S().register(KeybindPayload.ID, KeybindPayload.CODEC); + ServerPlayConnectionEvents.INIT.register((handler, server) -> ServerPlayNetworking.registerReceiver(handler, KeybindPayload.ID, NetworkingKeybindPacketTest::receive)); } } diff --git a/fabric-networking-api-v1/src/testmod/java/net/fabricmc/fabric/test/networking/login/NetworkingLoginQueryTest.java b/fabric-networking-api-v1/src/testmod/java/net/fabricmc/fabric/test/networking/login/NetworkingLoginQueryTest.java index aaafd5d2c..7aec94109 100644 --- a/fabric-networking-api-v1/src/testmod/java/net/fabricmc/fabric/test/networking/login/NetworkingLoginQueryTest.java +++ b/fabric-networking-api-v1/src/testmod/java/net/fabricmc/fabric/test/networking/login/NetworkingLoginQueryTest.java @@ -25,6 +25,7 @@ import net.minecraft.util.Identifier; import net.minecraft.util.Util; import net.fabricmc.api.ModInitializer; +import net.fabricmc.fabric.api.networking.v1.LoginPacketSender; import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; import net.fabricmc.fabric.api.networking.v1.PacketSender; import net.fabricmc.fabric.api.networking.v1.ServerLoginConnectionEvents; @@ -94,7 +95,7 @@ public final class NetworkingLoginQueryTest implements ModInitializer { } } - private void onLoginStart(ServerLoginNetworkHandler networkHandler, MinecraftServer server, PacketSender sender, ServerLoginNetworking.LoginSynchronizer synchronizer) { + private void onLoginStart(ServerLoginNetworkHandler networkHandler, MinecraftServer server, LoginPacketSender sender, ServerLoginNetworking.LoginSynchronizer synchronizer) { // Send a dummy query when the client starts accepting queries. sender.sendPacket(GLOBAL_TEST_CHANNEL, PacketByteBufs.empty()); // dummy packet } diff --git a/fabric-networking-api-v1/src/testmod/java/net/fabricmc/fabric/test/networking/play/NetworkingPlayPacketTest.java b/fabric-networking-api-v1/src/testmod/java/net/fabricmc/fabric/test/networking/play/NetworkingPlayPacketTest.java index b9ada312d..678a719bf 100644 --- a/fabric-networking-api-v1/src/testmod/java/net/fabricmc/fabric/test/networking/play/NetworkingPlayPacketTest.java +++ b/fabric-networking-api-v1/src/testmod/java/net/fabricmc/fabric/test/networking/play/NetworkingPlayPacketTest.java @@ -21,50 +21,42 @@ import static net.minecraft.server.command.CommandManager.argument; import static net.minecraft.server.command.CommandManager.literal; import java.util.List; -import java.util.UUID; import com.mojang.brigadier.Command; import com.mojang.brigadier.CommandDispatcher; import com.mojang.brigadier.arguments.StringArgumentType; import net.minecraft.network.PacketByteBuf; -import net.minecraft.network.listener.ClientPlayPacketListener; -import net.minecraft.network.packet.Packet; -import net.minecraft.network.packet.s2c.common.CustomPayloadS2CPacket; +import net.minecraft.network.PacketCallbacks; +import net.minecraft.network.RegistryByteBuf; +import net.minecraft.network.codec.PacketCodec; +import net.minecraft.network.codec.PacketCodecs; +import net.minecraft.network.packet.CustomPayload; import net.minecraft.network.packet.s2c.play.BundleS2CPacket; import net.minecraft.server.command.ServerCommandSource; import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.text.Text; -import net.minecraft.util.Identifier; +import net.fabricmc.api.EnvType; import net.fabricmc.api.ModInitializer; import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents; -import net.fabricmc.fabric.api.networking.v1.FabricPacket; -import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; -import net.fabricmc.fabric.api.networking.v1.PacketType; +import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry; import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; import net.fabricmc.fabric.test.networking.NetworkingTestmods; +import net.fabricmc.loader.api.FabricLoader; public final class NetworkingPlayPacketTest implements ModInitializer { - public static final Identifier TEST_CHANNEL = NetworkingTestmods.id("test_channel"); - private static final Identifier UNKNOWN_TEST_CHANNEL = NetworkingTestmods.id("unknown_test_channel"); private static boolean spamUnknownPackets = false; public static void sendToTestChannel(ServerPlayerEntity player, String stuff) { - ServerPlayNetworking.getSender(player).sendPacket(new OverlayPacket(Text.literal(stuff)), future -> { - NetworkingTestmods.LOGGER.info("Sent custom payload packet in {}", TEST_CHANNEL); - }); + ServerPlayNetworking.getSender(player).sendPacket(new OverlayPacket(Text.literal(stuff)), PacketCallbacks.always(() -> { + NetworkingTestmods.LOGGER.info("Sent custom payload packet"); + })); } private static void sendToUnknownChannel(ServerPlayerEntity player) { - PacketByteBuf buf = PacketByteBufs.create(); - - for (int i = 0; i < 20; i++) { - buf.writeUuid(UUID.randomUUID()); - } - - ServerPlayNetworking.getSender(player).sendPacket(UNKNOWN_TEST_CHANNEL, buf); + ServerPlayNetworking.getSender(player).sendPacket(new UnknownPayload("Hello")); } public static void registerCommand(CommandDispatcher dispatcher) { @@ -85,30 +77,16 @@ public final class NetworkingPlayPacketTest implements ModInitializer { ctx.getSource().sendMessage(Text.literal("Spamming unknown packets state:" + spamUnknownPackets)); return Command.SINGLE_SUCCESS; })) - .then(literal("bufctor").executes(ctx -> { - PacketByteBuf buf = PacketByteBufs.create(); - buf.writeIdentifier(TEST_CHANNEL); - buf.writeText(Text.literal("bufctor")); - ctx.getSource().getPlayer().networkHandler.sendPacket(new CustomPayloadS2CPacket(buf)); - return Command.SINGLE_SUCCESS; - })) - .then(literal("repeat").executes(ctx -> { - PacketByteBuf buf = PacketByteBufs.create(); - buf.writeText(Text.literal("repeat")); - ServerPlayNetworking.send(ctx.getSource().getPlayer(), TEST_CHANNEL, buf); - ServerPlayNetworking.send(ctx.getSource().getPlayer(), TEST_CHANNEL, buf); + .then(literal("simple").executes(ctx -> { + ServerPlayNetworking.send(ctx.getSource().getPlayer(), new OverlayPacket(Text.literal("simple"))); return Command.SINGLE_SUCCESS; })) .then(literal("bundled").executes(ctx -> { - PacketByteBuf buf1 = PacketByteBufs.create(); - buf1.writeText(Text.literal("bundled #1")); - PacketByteBuf buf2 = PacketByteBufs.create(); - buf2.writeText(Text.literal("bundled #2")); - - BundleS2CPacket packet = new BundleS2CPacket((List>) (Object) List.of( - ServerPlayNetworking.createS2CPacket(TEST_CHANNEL, buf1), - ServerPlayNetworking.createS2CPacket(TEST_CHANNEL, buf2))); - ctx.getSource().getPlayer().networkHandler.sendPacket(packet); + BundleS2CPacket packet = new BundleS2CPacket(List.of( + ServerPlayNetworking.createS2CPacket(new OverlayPacket(Text.literal("bundled #1"))), + ServerPlayNetworking.createS2CPacket(new OverlayPacket(Text.literal("bundled #2"))) + )); + ServerPlayNetworking.getSender(ctx.getSource().getPlayer()).sendPacket(packet); return Command.SINGLE_SUCCESS; }))); } @@ -117,6 +95,12 @@ public final class NetworkingPlayPacketTest implements ModInitializer { public void onInitialize() { NetworkingTestmods.LOGGER.info("Hello from networking user!"); + PayloadTypeRegistry.playS2C().register(OverlayPacket.ID, OverlayPacket.CODEC); + + if (FabricLoader.getInstance().getEnvironmentType() == EnvType.SERVER) { + PayloadTypeRegistry.playS2C().register(UnknownPayload.ID, UnknownPayload.CODEC); + } + CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> { NetworkingPlayPacketTest.registerCommand(dispatcher); }); @@ -135,21 +119,31 @@ public final class NetworkingPlayPacketTest implements ModInitializer { }); } - public record OverlayPacket(Text message) implements FabricPacket { - public static final PacketType PACKET_TYPE = PacketType.create(TEST_CHANNEL, OverlayPacket::new); + public record OverlayPacket(Text message) implements CustomPayload { + public static final CustomPayload.Id ID = new Id<>(NetworkingTestmods.id("test_channel")); + public static final PacketCodec CODEC = CustomPayload.codecOf(OverlayPacket::write, OverlayPacket::new); public OverlayPacket(PacketByteBuf buf) { this(buf.readText()); } - @Override public void write(PacketByteBuf buf) { buf.writeText(this.message); } @Override - public PacketType getType() { - return PACKET_TYPE; + public Id getId() { + return ID; + } + } + + private record UnknownPayload(String data) implements CustomPayload { + private static final CustomPayload.Id ID = new Id<>(NetworkingTestmods.id("unknown_test_channel_s2c")); + private static final PacketCodec CODEC = PacketCodecs.STRING.xmap(UnknownPayload::new, UnknownPayload::data).cast(); + + @Override + public Id getId() { + return ID; } } } diff --git a/fabric-networking-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/networking/client/configuration/NetworkingConfigurationClientTest.java b/fabric-networking-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/networking/client/configuration/NetworkingConfigurationClientTest.java index 3a1d4acb1..01055ab12 100644 --- a/fabric-networking-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/networking/client/configuration/NetworkingConfigurationClientTest.java +++ b/fabric-networking-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/networking/client/configuration/NetworkingConfigurationClientTest.java @@ -23,11 +23,11 @@ import net.fabricmc.fabric.test.networking.configuration.NetworkingConfiguration public class NetworkingConfigurationClientTest implements ClientModInitializer { @Override public void onInitializeClient() { - ClientConfigurationNetworking.registerGlobalReceiver(NetworkingConfigurationTest.ConfigurationPacket.PACKET_TYPE, (packet, responseSender) -> { + ClientConfigurationNetworking.registerGlobalReceiver(NetworkingConfigurationTest.ConfigurationPacket.ID, (packet, context) -> { // Handle stuff here // Respond back to the server that the task is complete - responseSender.sendPacket(new NetworkingConfigurationTest.ConfigurationCompletePacket()); + context.responseSender().sendPacket(NetworkingConfigurationTest.ConfigurationCompletePacket.INSTANCE); }); } } diff --git a/fabric-networking-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/networking/client/keybindreciever/NetworkingKeybindClientPacketTest.java b/fabric-networking-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/networking/client/keybindreciever/NetworkingKeybindClientPacketTest.java index 8aee7c3f7..d965e7d95 100644 --- a/fabric-networking-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/networking/client/keybindreciever/NetworkingKeybindClientPacketTest.java +++ b/fabric-networking-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/networking/client/keybindreciever/NetworkingKeybindClientPacketTest.java @@ -25,8 +25,7 @@ import net.fabricmc.api.ClientModInitializer; import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper; import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; -import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; -import net.fabricmc.fabric.test.networking.keybindreciever.NetworkingKeybindPacketTest; +import net.fabricmc.fabric.test.networking.keybindreciever.KeybindPayload; // Sends a packet to the server when a keybinding was pressed // The server in response will send a chat message to the client. @@ -40,7 +39,8 @@ public class NetworkingKeybindClientPacketTest implements ClientModInitializer { if (client.getNetworkHandler() != null) { if (TEST_BINDING.wasPressed()) { // Send an empty payload, server just needs to be told when packet is sent - ClientPlayNetworking.send(NetworkingKeybindPacketTest.KEYBINDING_PACKET_ID, PacketByteBufs.empty()); + // Since KeybindPayload is an empty payload, it can be a singleton. + ClientPlayNetworking.send(KeybindPayload.INSTANCE); } } }); diff --git a/fabric-networking-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/networking/client/play/NetworkingPlayPacketClientTest.java b/fabric-networking-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/networking/client/play/NetworkingPlayPacketClientTest.java index e87babc83..112c6cc95 100644 --- a/fabric-networking-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/networking/client/play/NetworkingPlayPacketClientTest.java +++ b/fabric-networking-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/networking/client/play/NetworkingPlayPacketClientTest.java @@ -18,38 +18,44 @@ package net.fabricmc.fabric.test.networking.client.play; import com.mojang.brigadier.Command; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.network.ClientPlayerEntity; -import net.minecraft.util.Identifier; +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.fabricmc.api.ClientModInitializer; import net.fabricmc.fabric.api.client.command.v2.ClientCommandManager; import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback; import net.fabricmc.fabric.api.client.networking.v1.ClientPlayConnectionEvents; 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.test.networking.NetworkingTestmods; import net.fabricmc.fabric.test.networking.play.NetworkingPlayPacketTest; -public final class NetworkingPlayPacketClientTest implements ClientModInitializer, ClientPlayNetworking.PlayPacketHandler { - private static final Identifier UNKNOWN_TEST_CHANNEL = NetworkingTestmods.id("unknown_test_channel"); - +public final class NetworkingPlayPacketClientTest implements ClientModInitializer { @Override public void onInitializeClient() { - ClientPlayConnectionEvents.INIT.register((handler, client) -> ClientPlayNetworking.registerReceiver(NetworkingPlayPacketTest.OverlayPacket.PACKET_TYPE, this)); + // Register the payload only on the client. + PayloadTypeRegistry.playC2S().register(UnknownPayload.ID, UnknownPayload.CODEC); + + ClientPlayConnectionEvents.INIT.register((handler, client) -> ClientPlayNetworking.registerReceiver(NetworkingPlayPacketTest.OverlayPacket.ID, (payload, context) -> context.client().inGameHud.setOverlayMessage(payload.message(), true))); ClientCommandRegistrationCallback.EVENT.register((dispatcher, dedicated) -> dispatcher.register( ClientCommandManager.literal("clientnetworktestcommand") .then(ClientCommandManager.literal("unknown").executes(context -> { - ClientPlayNetworking.send(UNKNOWN_TEST_CHANNEL, PacketByteBufs.create()); + ClientPlayNetworking.send(new UnknownPayload("Hello")); return Command.SINGLE_SUCCESS; } )))); } - @Override - public void receive(NetworkingPlayPacketTest.OverlayPacket packet, ClientPlayerEntity player, PacketSender sender) { - MinecraftClient.getInstance().inGameHud.setOverlayMessage(packet.message(), true); + private record UnknownPayload(String data) implements CustomPayload { + private static final CustomPayload.Id ID = new Id<>(NetworkingTestmods.id("unknown_test_channel_c2s")); + private static final PacketCodec CODEC = PacketCodecs.STRING.xmap(UnknownPayload::new, UnknownPayload::data).cast(); + + @Override + public Id getId() { + return ID; + } } } diff --git a/fabric-object-builder-api-v1/src/main/java/net/fabricmc/fabric/api/object/builder/v1/block/FabricBlockSettings.java b/fabric-object-builder-api-v1/src/main/java/net/fabricmc/fabric/api/object/builder/v1/block/FabricBlockSettings.java index c2a89fb3a..720e8b6aa 100644 --- a/fabric-object-builder-api-v1/src/main/java/net/fabricmc/fabric/api/object/builder/v1/block/FabricBlockSettings.java +++ b/fabric-object-builder-api-v1/src/main/java/net/fabricmc/fabric/api/object/builder/v1/block/FabricBlockSettings.java @@ -35,15 +35,9 @@ import net.fabricmc.fabric.mixin.object.builder.AbstractBlockAccessor; import net.fabricmc.fabric.mixin.object.builder.AbstractBlockSettingsAccessor; /** - * Fabric's version of Block.Settings. Adds additional methods and hooks - * not found in the original class. - * - *

Make note that this behaves slightly different from the - * vanilla counterpart, copying some settings that vanilla does not. - * - *

To use it, simply replace Block.Settings.of() with - * FabricBlockSettings.of(). + * @deprecated replace with {@link AbstractBlock.Settings} */ +@Deprecated public class FabricBlockSettings extends AbstractBlock.Settings { protected FabricBlockSettings() { super(); @@ -97,56 +91,74 @@ public class FabricBlockSettings extends AbstractBlock.Settings { this.postProcess(otherAccessor.getPostProcessPredicate()); } + /** + * @deprecated replace with {@link AbstractBlock.Settings#create()} + */ + @Deprecated public static FabricBlockSettings create() { return new FabricBlockSettings(); } /** - * @deprecated Use {@link FabricBlockSettings#create()} instead. + * @deprecated replace with {@link AbstractBlock.Settings#create()} */ @Deprecated public static FabricBlockSettings of() { return create(); } + /** + * @deprecated replace with {@link AbstractBlock.Settings#copy(AbstractBlock)} + */ + @Deprecated public static FabricBlockSettings copyOf(AbstractBlock block) { return new FabricBlockSettings(((AbstractBlockAccessor) block).getSettings()); } + /** + * @deprecated replace with {@link AbstractBlock.Settings#copy(AbstractBlock)} + */ + @Deprecated public static FabricBlockSettings copyOf(AbstractBlock.Settings settings) { return new FabricBlockSettings(settings); } + @Deprecated @Override public FabricBlockSettings noCollision() { super.noCollision(); return this; } + @Deprecated @Override public FabricBlockSettings nonOpaque() { super.nonOpaque(); return this; } + @Deprecated @Override public FabricBlockSettings slipperiness(float value) { super.slipperiness(value); return this; } + @Deprecated @Override public FabricBlockSettings velocityMultiplier(float velocityMultiplier) { super.velocityMultiplier(velocityMultiplier); return this; } + @Deprecated @Override public FabricBlockSettings jumpVelocityMultiplier(float jumpVelocityMultiplier) { super.jumpVelocityMultiplier(jumpVelocityMultiplier); return this; } + @Deprecated @Override public FabricBlockSettings sounds(BlockSoundGroup group) { super.sounds(group); @@ -161,89 +173,105 @@ public class FabricBlockSettings extends AbstractBlock.Settings { return this.luminance(levelFunction); } + @Deprecated @Override public FabricBlockSettings luminance(ToIntFunction luminanceFunction) { super.luminance(luminanceFunction); return this; } + @Deprecated @Override public FabricBlockSettings strength(float hardness, float resistance) { super.strength(hardness, resistance); return this; } + @Deprecated @Override public FabricBlockSettings breakInstantly() { super.breakInstantly(); return this; } + @Deprecated + @Override public FabricBlockSettings strength(float strength) { super.strength(strength); return this; } + @Deprecated @Override public FabricBlockSettings ticksRandomly() { super.ticksRandomly(); return this; } + @Deprecated @Override public FabricBlockSettings dynamicBounds() { super.dynamicBounds(); return this; } + @Deprecated @Override public FabricBlockSettings dropsNothing() { super.dropsNothing(); return this; } + @Deprecated @Override public FabricBlockSettings dropsLike(Block block) { super.dropsLike(block); return this; } + @Deprecated @Override public FabricBlockSettings air() { super.air(); return this; } + @Deprecated @Override public FabricBlockSettings allowsSpawning(AbstractBlock.TypedContextPredicate> predicate) { super.allowsSpawning(predicate); return this; } + @Deprecated @Override public FabricBlockSettings solidBlock(AbstractBlock.ContextPredicate predicate) { super.solidBlock(predicate); return this; } + @Deprecated @Override public FabricBlockSettings suffocates(AbstractBlock.ContextPredicate predicate) { super.suffocates(predicate); return this; } + @Deprecated @Override public FabricBlockSettings blockVision(AbstractBlock.ContextPredicate predicate) { super.blockVision(predicate); return this; } + @Deprecated @Override public FabricBlockSettings postProcess(AbstractBlock.ContextPredicate predicate) { super.postProcess(predicate); return this; } + @Deprecated @Override public FabricBlockSettings emissiveLighting(AbstractBlock.ContextPredicate predicate) { super.emissiveLighting(predicate); @@ -253,90 +281,105 @@ public class FabricBlockSettings extends AbstractBlock.Settings { /** * Make the block require tool to drop and slows down mining speed if the incorrect tool is used. */ + @Deprecated @Override public FabricBlockSettings requiresTool() { super.requiresTool(); return this; } + @Deprecated @Override public FabricBlockSettings mapColor(MapColor color) { super.mapColor(color); return this; } + @Deprecated @Override public FabricBlockSettings hardness(float hardness) { super.hardness(hardness); return this; } + @Deprecated @Override public FabricBlockSettings resistance(float resistance) { super.resistance(resistance); return this; } + @Deprecated @Override public FabricBlockSettings offset(AbstractBlock.OffsetType offsetType) { super.offset(offsetType); return this; } + @Deprecated @Override public FabricBlockSettings noBlockBreakParticles() { super.noBlockBreakParticles(); return this; } + @Deprecated @Override public FabricBlockSettings requires(FeatureFlag... features) { super.requires(features); return this; } + @Deprecated @Override public FabricBlockSettings mapColor(Function mapColorProvider) { super.mapColor(mapColorProvider); return this; } + @Deprecated @Override public FabricBlockSettings burnable() { super.burnable(); return this; } + @Deprecated @Override public FabricBlockSettings liquid() { super.liquid(); return this; } + @Deprecated @Override public FabricBlockSettings solid() { super.solid(); return this; } + @Deprecated @Override public FabricBlockSettings notSolid() { super.notSolid(); return this; } + @Deprecated @Override public FabricBlockSettings pistonBehavior(PistonBehavior pistonBehavior) { super.pistonBehavior(pistonBehavior); return this; } + @Deprecated @Override public FabricBlockSettings instrument(Instrument instrument) { super.instrument(instrument); return this; } + @Deprecated @Override public FabricBlockSettings replaceable() { super.replaceable(); @@ -354,11 +397,16 @@ public class FabricBlockSettings extends AbstractBlock.Settings { return this; } + /** + * @deprecated replace with {@link AbstractBlock.Settings#luminance(ToIntFunction)} + */ + @Deprecated public FabricBlockSettings luminance(int luminance) { this.luminance(ignored -> luminance); return this; } + @Deprecated public FabricBlockSettings drops(Identifier dropTableId) { ((AbstractBlockSettingsAccessor) this).setLootTableId(dropTableId); return this; @@ -367,7 +415,7 @@ public class FabricBlockSettings extends AbstractBlock.Settings { /* FABRIC DELEGATE WRAPPERS */ /** - * @deprecated Please migrate to {@link FabricBlockSettings#mapColor(MapColor)} + * @deprecated Please migrate to {@link AbstractBlock.Settings#mapColor(MapColor)} */ @Deprecated public FabricBlockSettings materialColor(MapColor color) { @@ -375,17 +423,22 @@ public class FabricBlockSettings extends AbstractBlock.Settings { } /** - * @deprecated Please migrate to {@link FabricBlockSettings#mapColor(DyeColor)} + * @deprecated Please migrate to {@link AbstractBlock.Settings#mapColor(DyeColor)} */ @Deprecated public FabricBlockSettings materialColor(DyeColor color) { return this.mapColor(color); } + /** + * @deprecated Please migrate to {@link AbstractBlock.Settings#mapColor(DyeColor)} + */ + @Deprecated public FabricBlockSettings mapColor(DyeColor color) { return this.mapColor(color.getMapColor()); } + @Deprecated public FabricBlockSettings collidable(boolean collidable) { ((AbstractBlockSettingsAccessor) this).setCollidable(collidable); return this; diff --git a/fabric-object-builder-api-v1/src/testmod/java/net/fabricmc/fabric/test/object/builder/BlockEntityTypeBuilderTest.java b/fabric-object-builder-api-v1/src/testmod/java/net/fabricmc/fabric/test/object/builder/BlockEntityTypeBuilderTest.java index dabf0e90a..699195756 100644 --- a/fabric-object-builder-api-v1/src/testmod/java/net/fabricmc/fabric/test/object/builder/BlockEntityTypeBuilderTest.java +++ b/fabric-object-builder-api-v1/src/testmod/java/net/fabricmc/fabric/test/object/builder/BlockEntityTypeBuilderTest.java @@ -81,7 +81,7 @@ public class BlockEntityTypeBuilderTest implements ModInitializer { } @Override - public ActionResult method_55766(BlockState state, World world, BlockPos pos, PlayerEntity player, BlockHitResult hit) { + public ActionResult onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, BlockHitResult hit) { if (!world.isClient()) { BlockEntity blockEntity = world.getBlockEntity(pos); diff --git a/fabric-object-builder-api-v1/src/testmod/java/net/fabricmc/fabric/test/object/builder/TealSignTest.java b/fabric-object-builder-api-v1/src/testmod/java/net/fabricmc/fabric/test/object/builder/TealSignTest.java index a6b0a6800..ccbdc84cd 100644 --- a/fabric-object-builder-api-v1/src/testmod/java/net/fabricmc/fabric/test/object/builder/TealSignTest.java +++ b/fabric-object-builder-api-v1/src/testmod/java/net/fabricmc/fabric/test/object/builder/TealSignTest.java @@ -16,6 +16,7 @@ package net.fabricmc.fabric.test.object.builder; +import net.minecraft.block.AbstractBlock; import net.minecraft.block.BlockSetType; import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; @@ -36,7 +37,6 @@ import net.minecraft.util.Identifier; import net.minecraft.util.math.BlockPos; import net.fabricmc.api.ModInitializer; -import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings; import net.fabricmc.fabric.api.object.builder.v1.block.entity.FabricBlockEntityTypeBuilder; import net.fabricmc.fabric.api.object.builder.v1.block.type.BlockSetTypeBuilder; import net.fabricmc.fabric.api.object.builder.v1.block.type.WoodTypeBuilder; @@ -45,25 +45,25 @@ public class TealSignTest implements ModInitializer { public static final Identifier TEAL_TYPE_ID = ObjectBuilderTestConstants.id("teal"); public static final BlockSetType TEAL_BLOCK_SET_TYPE = BlockSetTypeBuilder.copyOf(BlockSetType.OAK).build(TEAL_TYPE_ID); public static final WoodType TEAL_WOOD_TYPE = WoodTypeBuilder.copyOf(WoodType.OAK).build(TEAL_TYPE_ID, TEAL_BLOCK_SET_TYPE); - public static final SignBlock TEAL_SIGN = new SignBlock(TEAL_WOOD_TYPE, FabricBlockSettings.copy(Blocks.OAK_SIGN)) { + public static final SignBlock TEAL_SIGN = new SignBlock(TEAL_WOOD_TYPE, AbstractBlock.Settings.copy(Blocks.OAK_SIGN)) { @Override public TealSign createBlockEntity(BlockPos pos, BlockState state) { return new TealSign(pos, state); } }; - public static final WallSignBlock TEAL_WALL_SIGN = new WallSignBlock(TEAL_WOOD_TYPE, FabricBlockSettings.copy(Blocks.OAK_SIGN)) { + public static final WallSignBlock TEAL_WALL_SIGN = new WallSignBlock(TEAL_WOOD_TYPE, AbstractBlock.Settings.copy(Blocks.OAK_SIGN)) { @Override public TealSign createBlockEntity(BlockPos pos, BlockState state) { return new TealSign(pos, state); } }; - public static final HangingSignBlock TEAL_HANGING_SIGN = new HangingSignBlock(TEAL_WOOD_TYPE, FabricBlockSettings.copy(Blocks.OAK_HANGING_SIGN)) { + public static final HangingSignBlock TEAL_HANGING_SIGN = new HangingSignBlock(TEAL_WOOD_TYPE, AbstractBlock.Settings.copy(Blocks.OAK_HANGING_SIGN)) { @Override public TealHangingSign createBlockEntity(BlockPos pos, BlockState state) { return new TealHangingSign(pos, state); } }; - public static final WallHangingSignBlock TEAL_WALL_HANGING_SIGN = new WallHangingSignBlock(TEAL_WOOD_TYPE, FabricBlockSettings.copy(Blocks.OAK_HANGING_SIGN)) { + public static final WallHangingSignBlock TEAL_WALL_HANGING_SIGN = new WallHangingSignBlock(TEAL_WOOD_TYPE, AbstractBlock.Settings.copy(Blocks.OAK_HANGING_SIGN)) { @Override public TealHangingSign createBlockEntity(BlockPos pos, BlockState state) { return new TealHangingSign(pos, state); diff --git a/fabric-particles-v1/src/main/java/net/fabricmc/fabric/api/particle/v1/FabricParticleTypes.java b/fabric-particles-v1/src/main/java/net/fabricmc/fabric/api/particle/v1/FabricParticleTypes.java index 95dc16b52..71a33d3d7 100644 --- a/fabric-particles-v1/src/main/java/net/fabricmc/fabric/api/particle/v1/FabricParticleTypes.java +++ b/fabric-particles-v1/src/main/java/net/fabricmc/fabric/api/particle/v1/FabricParticleTypes.java @@ -16,8 +16,12 @@ package net.fabricmc.fabric.api.particle.v1; +import java.util.function.Function; + import com.mojang.serialization.Codec; +import net.minecraft.network.RegistryByteBuf; +import net.minecraft.network.codec.PacketCodec; import net.minecraft.particle.DefaultParticleType; import net.minecraft.particle.ParticleEffect; import net.minecraft.particle.ParticleType; @@ -59,26 +63,69 @@ public final class FabricParticleTypes { } /** - * Creates a new particle type with a custom factory for packet/data serialization. + * Creates a new particle type with a custom factory and codecs for packet/data serialization. * - * @param factory A factory for serializing packet data and string command parameters into a particle effect. + * @param factory A factory for serializing string command parameters into a particle effect. + * @param codec The codec for serialization. + * @param packetCodec The packet codec for network serialization. */ - public static ParticleType complex(ParticleEffect.Factory factory) { - return complex(false, factory); + public static ParticleType complex(ParticleEffect.Factory factory, final Function, Codec> codecGetter, final Codec codec, final PacketCodec packetCodec) { + return complex(false, factory, codec, packetCodec); } /** - * Creates a new particle type with a custom factory for packet/data serialization. + * Creates a new particle type with a custom factory and codecs for packet/data serialization. * * @param alwaysSpawn True to always spawn the particle regardless of distance. - * @param factory A factory for serializing packet data and string command parameters into a particle effect. + * @param factory A factory for serializing string command parameters into a particle effect. + * @param codec The codec for serialization. + * @param packetCodec The packet codec for network serialization. */ - public static ParticleType complex(boolean alwaysSpawn, ParticleEffect.Factory factory) { + public static ParticleType complex(boolean alwaysSpawn, ParticleEffect.Factory factory, final Codec codec, final PacketCodec packetCodec) { return new ParticleType(alwaysSpawn, factory) { @Override public Codec getCodec() { - //TODO fix me - return null; + return codec; + } + + @Override + public PacketCodec getPacketCodec() { + return packetCodec; + } + }; + } + + /** + * Creates a new particle type with a custom factory and codecs for packet/data serialization. + * This method is useful when two different {@link ParticleType}s share the same {@link ParticleEffect} implementation. + * + * @param factory A factory for serializing string command parameters into a particle effect. + * @param codecGetter A function that, given the newly created type, returns the codec for serialization. + * @param packetCodecGetter A function that, given the newly created type, returns the packet codec for network serialization. + */ + public static ParticleType complex(ParticleEffect.Factory factory, final Function, Codec> codecGetter, final Function, PacketCodec> packetCodecGetter) { + return complex(false, factory, codecGetter, packetCodecGetter); + } + + /** + * Creates a new particle type with a custom factory and codecs for packet/data serialization. + * This method is useful when two different {@link ParticleType}s share the same {@link ParticleEffect} implementation. + * + * @param alwaysSpawn True to always spawn the particle regardless of distance. + * @param factory A factory for serializing string command parameters into a particle effect. + * @param codecGetter A function that, given the newly created type, returns the codec for serialization. + * @param packetCodecGetter A function that, given the newly created type, returns the packet codec for network serialization. + */ + public static ParticleType complex(boolean alwaysSpawn, ParticleEffect.Factory factory, final Function, Codec> codecGetter, final Function, PacketCodec> packetCodecGetter) { + return new ParticleType(alwaysSpawn, factory) { + @Override + public Codec getCodec() { + return codecGetter.apply(this); + } + + @Override + public PacketCodec getPacketCodec() { + return packetCodecGetter.apply(this); } }; } diff --git a/fabric-recipe-api-v1/src/client/java/net/fabricmc/fabric/impl/recipe/ingredient/client/CustomIngredientSyncClient.java b/fabric-recipe-api-v1/src/client/java/net/fabricmc/fabric/impl/recipe/ingredient/client/CustomIngredientSyncClient.java index ecbbf35dd..513775dcd 100644 --- a/fabric-recipe-api-v1/src/client/java/net/fabricmc/fabric/impl/recipe/ingredient/client/CustomIngredientSyncClient.java +++ b/fabric-recipe-api-v1/src/client/java/net/fabricmc/fabric/impl/recipe/ingredient/client/CustomIngredientSyncClient.java @@ -18,6 +18,7 @@ package net.fabricmc.fabric.impl.recipe.ingredient.client; import net.fabricmc.api.ClientModInitializer; import net.fabricmc.fabric.api.client.networking.v1.ClientConfigurationNetworking; +import net.fabricmc.fabric.impl.recipe.ingredient.CustomIngredientPayloadS2C; import net.fabricmc.fabric.impl.recipe.ingredient.CustomIngredientSync; /** @@ -26,9 +27,8 @@ import net.fabricmc.fabric.impl.recipe.ingredient.CustomIngredientSync; public class CustomIngredientSyncClient implements ClientModInitializer { @Override public void onInitializeClient() { - ClientConfigurationNetworking.registerGlobalReceiver(CustomIngredientSync.PACKET_ID, (client, handler, buf, responseSender) -> { - int protocolVersion = buf.readVarInt(); - handler.sendPacket(ClientConfigurationNetworking.createC2SPacket(CustomIngredientSync.PACKET_ID, CustomIngredientSync.createResponsePacket(protocolVersion))); + ClientConfigurationNetworking.registerGlobalReceiver(CustomIngredientPayloadS2C.ID, (payload, context) -> { + context.responseSender().sendPacket(CustomIngredientSync.createResponsePayload(payload.protocolVersion())); }); } } diff --git a/fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/api/recipe/v1/ingredient/CustomIngredientSerializer.java b/fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/api/recipe/v1/ingredient/CustomIngredientSerializer.java index 0cf05d289..bc6664d04 100644 --- a/fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/api/recipe/v1/ingredient/CustomIngredientSerializer.java +++ b/fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/api/recipe/v1/ingredient/CustomIngredientSerializer.java @@ -19,7 +19,8 @@ package net.fabricmc.fabric.api.recipe.v1.ingredient; import com.mojang.serialization.Codec; import org.jetbrains.annotations.Nullable; -import net.minecraft.network.PacketByteBuf; +import net.minecraft.network.RegistryByteBuf; +import net.minecraft.network.codec.PacketCodec; import net.minecraft.recipe.Ingredient; import net.minecraft.util.Identifier; @@ -66,12 +67,9 @@ public interface CustomIngredientSerializer { Codec getCodec(boolean allowEmpty); /** - * Deserializes the custom ingredient from a packet buffer. + * {@return the packet codec for serializing this ingredient}. + * + * @see Ingredient#PACKET_CODEC */ - T read(PacketByteBuf buf); - - /** - * Serializes the custom ingredient to a packet buffer. - */ - void write(PacketByteBuf buf, T ingredient); + PacketCodec getPacketCodec(); } diff --git a/fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/impl/recipe/ingredient/CustomIngredientImpl.java b/fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/impl/recipe/ingredient/CustomIngredientImpl.java index 8a9c97017..9826cda05 100644 --- a/fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/impl/recipe/ingredient/CustomIngredientImpl.java +++ b/fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/impl/recipe/ingredient/CustomIngredientImpl.java @@ -19,7 +19,6 @@ package net.fabricmc.fabric.impl.recipe.ingredient; import java.util.Map; import java.util.Objects; import java.util.Optional; -import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Stream; @@ -28,7 +27,6 @@ import com.mojang.serialization.DataResult; import org.jetbrains.annotations.Nullable; import net.minecraft.item.ItemStack; -import net.minecraft.network.PacketByteBuf; import net.minecraft.recipe.Ingredient; import net.minecraft.util.Identifier; @@ -43,14 +41,13 @@ public class CustomIngredientImpl extends Ingredient { // Static helpers used by the API public static final String TYPE_KEY = "fabric:type"; - public static final int PACKET_MARKER = -1; static final Map> REGISTERED_SERIALIZERS = new ConcurrentHashMap<>(); public static final Codec> CODEC = Identifier.CODEC.flatXmap(identifier -> Optional.ofNullable(REGISTERED_SERIALIZERS.get(identifier)) - .map(DataResult::success) - .orElseGet(() -> DataResult.error(() -> "Unknown custom ingredient serializer: " + identifier)), + .map(DataResult::success) + .orElseGet(() -> DataResult.error(() -> "Unknown custom ingredient serializer: " + identifier)), serializer -> DataResult.success(serializer.getIdentifier()) ); @@ -103,24 +100,6 @@ public class CustomIngredientImpl extends Ingredient { return stack != null && customIngredient.test(stack); } - @Override - public void write(PacketByteBuf buf) { - // Can be null if we're not writing a packet from the PacketEncoder; in that case, always write the full ingredient. - // Chances are this is a mod's doing and the client has the Ingredient API with the relevant ingredients. - Set supportedIngredients = CustomIngredientSync.CURRENT_SUPPORTED_INGREDIENTS.get(); - - if (supportedIngredients != null && !supportedIngredients.contains(customIngredient.getSerializer().getIdentifier())) { - // The client doesn't support this custom ingredient, so we send the matching stacks as a regular ingredient. - // Conveniently, this is exactly what the super call does. - super.write(buf); - } else { - // The client supports this custom ingredient, so we send it as a custom ingredient. - buf.writeVarInt(PACKET_MARKER); - buf.writeIdentifier(customIngredient.getSerializer().getIdentifier()); - customIngredient.getSerializer().write(buf, coerceIngredient()); - } - } - @Override public boolean isEmpty() { // We don't want to resolve the matching stacks, @@ -128,8 +107,4 @@ public class CustomIngredientImpl extends Ingredient { // So we just return false when the matching stacks haven't been resolved yet (i.e. when the field is null). return matchingStacks != null && matchingStacks.length == 0; } - - private T coerceIngredient() { - return (T) customIngredient; - } } diff --git a/fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/impl/recipe/ingredient/CustomIngredientPacketCodec.java b/fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/impl/recipe/ingredient/CustomIngredientPacketCodec.java new file mode 100644 index 000000000..7003d71b1 --- /dev/null +++ b/fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/impl/recipe/ingredient/CustomIngredientPacketCodec.java @@ -0,0 +1,85 @@ +/* + * 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.recipe.ingredient; + +import java.util.Set; + +import net.minecraft.network.RegistryByteBuf; +import net.minecraft.network.codec.PacketCodec; +import net.minecraft.recipe.Ingredient; +import net.minecraft.util.Identifier; + +import net.fabricmc.fabric.api.recipe.v1.ingredient.CustomIngredient; +import net.fabricmc.fabric.api.recipe.v1.ingredient.CustomIngredientSerializer; + +public class CustomIngredientPacketCodec implements PacketCodec { + private static final int PACKET_MARKER = -1; + private final PacketCodec fallback; + + public CustomIngredientPacketCodec(PacketCodec fallback) { + this.fallback = fallback; + } + + @Override + public Ingredient decode(RegistryByteBuf buf) { + int index = buf.readerIndex(); + + if (buf.readVarInt() != PACKET_MARKER) { + // Reset index for vanilla's normal deserialization logic. + buf.readerIndex(index); + return this.fallback.decode(buf); + } + + Identifier type = buf.readIdentifier(); + CustomIngredientSerializer serializer = CustomIngredientSerializer.get(type); + + if (serializer == null) { + throw new IllegalArgumentException("Cannot deserialize custom ingredient of unknown type " + type); + } + + return serializer.getPacketCodec().decode(buf).toVanilla(); + } + + @Override + @SuppressWarnings("unchecked") + public void encode(RegistryByteBuf buf, Ingredient value) { + CustomIngredient customIngredient = value.getCustomIngredient(); + + if (shouldEncodeFallback(customIngredient)) { + // The client doesn't support this custom ingredient, so we send the matching stacks as a regular ingredient. + this.fallback.encode(buf, value); + return; + } + + // The client supports this custom ingredient, so we send it as a custom ingredient. + buf.writeVarInt(PACKET_MARKER); + buf.writeIdentifier(customIngredient.getSerializer().getIdentifier()); + PacketCodec packetCodec = (PacketCodec) customIngredient.getSerializer().getPacketCodec(); + packetCodec.encode(buf, customIngredient); + } + + private static boolean shouldEncodeFallback(CustomIngredient customIngredient) { + if (customIngredient == null) { + return true; + } + + // Can be null if we're not writing a packet from the PacketEncoder; in that case, always write the full ingredient. + // Chances are this is a mod's doing and the client has the Ingredient API with the relevant ingredients. + Set supportedIngredients = CustomIngredientSync.CURRENT_SUPPORTED_INGREDIENTS.get(); + return supportedIngredients != null && !supportedIngredients.contains(customIngredient.getSerializer().getIdentifier()); + } +} diff --git a/fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/impl/recipe/ingredient/CustomIngredientPayloadC2S.java b/fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/impl/recipe/ingredient/CustomIngredientPayloadC2S.java new file mode 100644 index 000000000..c4448e0e3 --- /dev/null +++ b/fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/impl/recipe/ingredient/CustomIngredientPayloadC2S.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.impl.recipe.ingredient; + +import java.util.HashSet; +import java.util.Set; + +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; + +public record CustomIngredientPayloadC2S(int protocolVersion, Set registeredSerializers) implements CustomPayload { + public static final PacketCodec CODEC = PacketCodec.tuple( + PacketCodecs.VAR_INT, CustomIngredientPayloadC2S::protocolVersion, + PacketCodecs.collection(HashSet::new, Identifier.PACKET_CODEC), CustomIngredientPayloadC2S::registeredSerializers, + CustomIngredientPayloadC2S::new + ); + public static final CustomPayload.Id ID = new Id<>(CustomIngredientSync.PACKET_ID); + + @Override + public Id getId() { + return ID; + } +} diff --git a/fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/impl/recipe/ingredient/CustomIngredientPayloadS2C.java b/fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/impl/recipe/ingredient/CustomIngredientPayloadS2C.java new file mode 100644 index 000000000..730b6c169 --- /dev/null +++ b/fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/impl/recipe/ingredient/CustomIngredientPayloadS2C.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.impl.recipe.ingredient; + +import net.minecraft.network.PacketByteBuf; +import net.minecraft.network.codec.PacketCodec; +import net.minecraft.network.codec.PacketCodecs; +import net.minecraft.network.packet.CustomPayload; + +public record CustomIngredientPayloadS2C(int protocolVersion) implements CustomPayload { + public static final PacketCodec CODEC = PacketCodec.tuple( + PacketCodecs.VAR_INT, CustomIngredientPayloadS2C::protocolVersion, + CustomIngredientPayloadS2C::new + ); + public static final CustomPayload.Id ID = new Id<>(CustomIngredientSync.PACKET_ID); + + @Override + public Id getId() { + return ID; + } +} diff --git a/fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/impl/recipe/ingredient/CustomIngredientSync.java b/fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/impl/recipe/ingredient/CustomIngredientSync.java index f7be0e000..e3620677f 100644 --- a/fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/impl/recipe/ingredient/CustomIngredientSync.java +++ b/fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/impl/recipe/ingredient/CustomIngredientSync.java @@ -16,25 +16,22 @@ package net.fabricmc.fabric.impl.recipe.ingredient; -import java.util.HashSet; import java.util.Set; import java.util.function.Consumer; import io.netty.channel.ChannelHandler; -import org.jetbrains.annotations.Nullable; -import net.minecraft.network.PacketByteBuf; -import net.minecraft.network.handler.PacketEncoder; +import net.minecraft.network.handler.EncoderHandler; import net.minecraft.network.packet.Packet; import net.minecraft.server.network.ServerPlayerConfigurationTask; import net.minecraft.util.Identifier; import net.fabricmc.api.ModInitializer; -import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; +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.mixin.networking.accessor.ServerCommonNetworkHandlerAccessor; -import net.fabricmc.fabric.mixin.recipe.ingredient.PacketEncoderMixin; +import net.fabricmc.fabric.mixin.recipe.ingredient.EncoderHandlerMixin; /** * To reasonably support server-side only custom ingredients, we only send custom ingredients to clients that support them. @@ -43,8 +40,8 @@ import net.fabricmc.fabric.mixin.recipe.ingredient.PacketEncoderMixin; * *

    *
  • Each client sends a packet with the set of custom ingredients it supports.
  • - *
  • We store that set inside the {@link PacketEncoder} using {@link PacketEncoderMixin}.
  • - *
  • When serializing a custom ingredient, we get access to the current {@link PacketEncoder}, + *
  • We store that set inside the {@link EncoderHandler} using {@link EncoderHandlerMixin}.
  • + *
  • When serializing a custom ingredient, we get access to the current {@link EncoderHandler}, * and based on that we decide whether to send the custom ingredient, or a vanilla ingredient with the matching stacks.
  • *
*/ @@ -53,29 +50,24 @@ public class CustomIngredientSync implements ModInitializer { public static final int PROTOCOL_VERSION_1 = 1; public static final ThreadLocal> CURRENT_SUPPORTED_INGREDIENTS = new ThreadLocal<>(); - @Nullable - public static PacketByteBuf createResponsePacket(int serverProtocolVersion) { + public static CustomIngredientPayloadC2S createResponsePayload(int serverProtocolVersion) { if (serverProtocolVersion < PROTOCOL_VERSION_1) { // Not supposed to happen - notify the server that we didn't understand the query. return null; } // Always send protocol 1 - the server should support it even if it supports more recent protocols. - PacketByteBuf buf = PacketByteBufs.create(); - buf.writeVarInt(PROTOCOL_VERSION_1); - buf.writeCollection(CustomIngredientImpl.REGISTERED_SERIALIZERS.keySet(), PacketByteBuf::writeIdentifier); - return buf; + return new CustomIngredientPayloadC2S(PROTOCOL_VERSION_1, CustomIngredientImpl.REGISTERED_SERIALIZERS.keySet()); } - public static Set decodeResponsePacket(PacketByteBuf buf) { - int protocolVersion = buf.readVarInt(); - + public static Set decodeResponsePayload(CustomIngredientPayloadC2S payload) { + int protocolVersion = payload.protocolVersion(); switch (protocolVersion) { case PROTOCOL_VERSION_1 -> { - Set identifiers = buf.readCollection(HashSet::new, PacketByteBuf::readIdentifier); + Set serializers = payload.registeredSerializers(); // Remove unknown keys to save memory - identifiers.removeIf(id -> !CustomIngredientImpl.REGISTERED_SERIALIZERS.containsKey(id)); - return identifiers; + serializers.removeIf(id -> !CustomIngredientImpl.REGISTERED_SERIALIZERS.containsKey(id)); + return serializers; } default -> { throw new IllegalArgumentException("Unknown ingredient sync protocol version: " + protocolVersion); @@ -85,21 +77,26 @@ public class CustomIngredientSync implements ModInitializer { @Override public void onInitialize() { + PayloadTypeRegistry.configurationC2S() + .register(CustomIngredientPayloadC2S.ID, CustomIngredientPayloadC2S.CODEC); + PayloadTypeRegistry.configurationS2C() + .register(CustomIngredientPayloadS2C.ID, CustomIngredientPayloadS2C.CODEC); + ServerConfigurationConnectionEvents.CONFIGURE.register((handler, server) -> { if (ServerConfigurationNetworking.canSend(handler, PACKET_ID)) { handler.addTask(new IngredientSyncTask()); } }); - ServerConfigurationNetworking.registerGlobalReceiver(PACKET_ID, (server, handler, buf, responseSender) -> { - Set supportedCustomIngredients = decodeResponsePacket(buf); - ChannelHandler packetEncoder = ((ServerCommonNetworkHandlerAccessor) handler).getConnection().channel.pipeline().get("encoder"); + ServerConfigurationNetworking.registerGlobalReceiver(CustomIngredientPayloadC2S.ID, (payload, context) -> { + Set supportedCustomIngredients = decodeResponsePayload(payload); + ChannelHandler packetEncoder = ((ServerCommonNetworkHandlerAccessor) context.networkHandler()).getConnection().channel.pipeline().get("encoder"); if (packetEncoder != null) { // Null in singleplayer ((SupportedIngredientsPacketEncoder) packetEncoder).fabric_setSupportedCustomIngredients(supportedCustomIngredients); } - handler.completeTask(IngredientSyncTask.KEY); + context.networkHandler().completeTask(IngredientSyncTask.KEY); }); } @@ -110,9 +107,7 @@ public class CustomIngredientSync implements ModInitializer { public void sendPacket(Consumer> sender) { // Send packet with 1 so the client can send us back the list of supported tags. // 1 is sent in case we need a different protocol later for some reason. - PacketByteBuf buf = PacketByteBufs.create(); - buf.writeVarInt(PROTOCOL_VERSION_1); // max supported server protocol version - sender.accept(ServerConfigurationNetworking.createS2CPacket(PACKET_ID, buf)); + sender.accept(ServerConfigurationNetworking.createS2CPacket(new CustomIngredientPayloadS2C(PROTOCOL_VERSION_1))); } @Override diff --git a/fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/impl/recipe/ingredient/SupportedIngredientsPacketEncoder.java b/fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/impl/recipe/ingredient/SupportedIngredientsPacketEncoder.java index ac75f6dbe..d260439a5 100644 --- a/fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/impl/recipe/ingredient/SupportedIngredientsPacketEncoder.java +++ b/fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/impl/recipe/ingredient/SupportedIngredientsPacketEncoder.java @@ -18,11 +18,11 @@ package net.fabricmc.fabric.impl.recipe.ingredient; import java.util.Set; -import net.minecraft.network.handler.PacketEncoder; +import net.minecraft.network.handler.EncoderHandler; import net.minecraft.util.Identifier; /** - * Implemented on {@link PacketEncoder} to store which custom ingredients the client supports. + * Implemented on {@link EncoderHandler} to store which custom ingredients the client supports. */ public interface SupportedIngredientsPacketEncoder { void fabric_setSupportedCustomIngredients(Set supportedCustomIngredients); diff --git a/fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/impl/recipe/ingredient/builtin/CombinedIngredient.java b/fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/impl/recipe/ingredient/builtin/CombinedIngredient.java index 6f768d427..9b04d8a8a 100644 --- a/fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/impl/recipe/ingredient/builtin/CombinedIngredient.java +++ b/fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/impl/recipe/ingredient/builtin/CombinedIngredient.java @@ -16,14 +16,14 @@ package net.fabricmc.fabric.impl.recipe.ingredient.builtin; -import java.util.ArrayList; -import java.util.Collections; import java.util.List; import java.util.function.Function; import com.mojang.serialization.Codec; -import net.minecraft.network.PacketByteBuf; +import net.minecraft.network.RegistryByteBuf; +import net.minecraft.network.codec.PacketCodec; +import net.minecraft.network.codec.PacketCodecs; import net.minecraft.recipe.Ingredient; import net.minecraft.util.Identifier; @@ -61,15 +61,16 @@ abstract class CombinedIngredient implements CustomIngredient { static class Serializer implements CustomIngredientSerializer { private final Identifier identifier; - private final Function, I> factory; private final Codec allowEmptyCodec; private final Codec disallowEmptyCodec; + private final PacketCodec packetCodec; Serializer(Identifier identifier, Function, I> factory, Codec allowEmptyCodec, Codec disallowEmptyCodec) { this.identifier = identifier; - this.factory = factory; this.allowEmptyCodec = allowEmptyCodec; this.disallowEmptyCodec = disallowEmptyCodec; + this.packetCodec = Ingredient.PACKET_CODEC.collect(PacketCodecs.toList()) + .xmap(factory, I::getIngredients); } @Override @@ -83,24 +84,8 @@ abstract class CombinedIngredient implements CustomIngredient { } @Override - public I read(PacketByteBuf buf) { - int size = buf.readVarInt(); - List ingredients = new ArrayList<>(size); - - for (int i = 0; i < size; i++) { - ingredients.add(Ingredient.fromPacket(buf)); - } - - return factory.apply(Collections.unmodifiableList(ingredients)); - } - - @Override - public void write(PacketByteBuf buf, I ingredient) { - buf.writeVarInt(ingredient.ingredients.size()); - - for (Ingredient value : ingredient.ingredients) { - value.write(buf); - } + public PacketCodec getPacketCodec() { + return this.packetCodec; } } } diff --git a/fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/impl/recipe/ingredient/builtin/DifferenceIngredient.java b/fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/impl/recipe/ingredient/builtin/DifferenceIngredient.java index 0b0be2a51..83b7030ae 100644 --- a/fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/impl/recipe/ingredient/builtin/DifferenceIngredient.java +++ b/fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/impl/recipe/ingredient/builtin/DifferenceIngredient.java @@ -23,7 +23,8 @@ import com.mojang.serialization.Codec; import com.mojang.serialization.codecs.RecordCodecBuilder; import net.minecraft.item.ItemStack; -import net.minecraft.network.PacketByteBuf; +import net.minecraft.network.RegistryByteBuf; +import net.minecraft.network.codec.PacketCodec; import net.minecraft.recipe.Ingredient; import net.minecraft.util.Identifier; @@ -75,6 +76,11 @@ public class DifferenceIngredient implements CustomIngredient { private static final Identifier ID = new Identifier("fabric", "difference"); private static final Codec ALLOW_EMPTY_CODEC = createCodec(Ingredient.ALLOW_EMPTY_CODEC); private static final Codec DISALLOW_EMPTY_CODEC = createCodec(Ingredient.DISALLOW_EMPTY_CODEC); + private static final PacketCodec PACKET_CODEC = PacketCodec.tuple( + Ingredient.PACKET_CODEC, DifferenceIngredient::getBase, + Ingredient.PACKET_CODEC, DifferenceIngredient::getSubtracted, + DifferenceIngredient::new + ); private static Codec createCodec(Codec ingredientCodec) { return RecordCodecBuilder.create(instance -> @@ -96,16 +102,8 @@ public class DifferenceIngredient implements CustomIngredient { } @Override - public DifferenceIngredient read(PacketByteBuf buf) { - Ingredient base = Ingredient.fromPacket(buf); - Ingredient subtracted = Ingredient.fromPacket(buf); - return new DifferenceIngredient(base, subtracted); - } - - @Override - public void write(PacketByteBuf buf, DifferenceIngredient ingredient) { - ingredient.base.write(buf); - ingredient.subtracted.write(buf); + public PacketCodec getPacketCodec() { + return PACKET_CODEC; } } } diff --git a/fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/impl/recipe/ingredient/builtin/NbtIngredient.java b/fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/impl/recipe/ingredient/builtin/NbtIngredient.java index cf2d0a539..70d5676c3 100644 --- a/fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/impl/recipe/ingredient/builtin/NbtIngredient.java +++ b/fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/impl/recipe/ingredient/builtin/NbtIngredient.java @@ -30,8 +30,12 @@ import org.jetbrains.annotations.Nullable; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NbtCompound; import net.minecraft.nbt.NbtHelper; +import net.minecraft.nbt.NbtSizeTracker; import net.minecraft.nbt.StringNbtReader; import net.minecraft.network.PacketByteBuf; +import net.minecraft.network.RegistryByteBuf; +import net.minecraft.network.codec.PacketCodec; +import net.minecraft.network.codec.PacketCodecs; import net.minecraft.recipe.Ingredient; import net.minecraft.util.Identifier; import net.minecraft.util.dynamic.Codecs; @@ -98,6 +102,7 @@ public class NbtIngredient implements CustomIngredient { return base; } + @Nullable private NbtCompound getNbt() { return nbt; } @@ -122,6 +127,34 @@ public class NbtIngredient implements CustomIngredient { private static final Codec ALLOW_EMPTY_CODEC = createCodec(Ingredient.ALLOW_EMPTY_CODEC); private static final Codec DISALLOW_EMPTY_CODEC = createCodec(Ingredient.DISALLOW_EMPTY_CODEC); + private static final PacketCodec NULLABLE_NBT_PACKET_CODEC = new PacketCodec<>() { + private static final NbtSizeTracker SIZE_TRACKER = NbtSizeTracker.of(PacketByteBuf.MAX_READ_NBT_SIZE); + @Override + @Nullable + public NbtCompound decode(RegistryByteBuf buf) { + if (buf.readBoolean() && buf.readNbt(SIZE_TRACKER) instanceof NbtCompound nbt) { + return nbt; + } + + return null; + } + + @Override + public void encode(RegistryByteBuf buf, @Nullable NbtCompound value) { + if (value == null) { + buf.writeBoolean(false); + } else { + buf.writeBoolean(true); + buf.writeNbt(value); + } + } + }; + private static final PacketCodec PACKET_CODEC = PacketCodec.tuple( + Ingredient.PACKET_CODEC, NbtIngredient::getBase, + NULLABLE_NBT_PACKET_CODEC, NbtIngredient::getNbt, + PacketCodecs.BOOL, NbtIngredient::isStrict, + NbtIngredient::new + ); private static Codec createCodec(Codec ingredientCodec) { return RecordCodecBuilder.create(instance -> @@ -144,18 +177,8 @@ public class NbtIngredient implements CustomIngredient { } @Override - public NbtIngredient read(PacketByteBuf buf) { - Ingredient base = Ingredient.fromPacket(buf); - NbtCompound nbt = buf.readNbt(); - boolean strict = buf.readBoolean(); - return new NbtIngredient(base, nbt, strict); - } - - @Override - public void write(PacketByteBuf buf, NbtIngredient ingredient) { - ingredient.base.write(buf); - buf.writeNbt(ingredient.nbt); - buf.writeBoolean(ingredient.strict); + public PacketCodec getPacketCodec() { + return PACKET_CODEC; } } } diff --git a/fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/mixin/recipe/ingredient/PacketEncoderMixin.java b/fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/mixin/recipe/ingredient/EncoderHandlerMixin.java similarity index 87% rename from fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/mixin/recipe/ingredient/PacketEncoderMixin.java rename to fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/mixin/recipe/ingredient/EncoderHandlerMixin.java index 351833e38..d2a033105 100644 --- a/fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/mixin/recipe/ingredient/PacketEncoderMixin.java +++ b/fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/mixin/recipe/ingredient/EncoderHandlerMixin.java @@ -26,15 +26,15 @@ 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.network.handler.PacketEncoder; +import net.minecraft.network.handler.EncoderHandler; import net.minecraft.network.packet.Packet; import net.minecraft.util.Identifier; import net.fabricmc.fabric.impl.recipe.ingredient.CustomIngredientSync; import net.fabricmc.fabric.impl.recipe.ingredient.SupportedIngredientsPacketEncoder; -@Mixin(PacketEncoder.class) -public class PacketEncoderMixin implements SupportedIngredientsPacketEncoder { +@Mixin(EncoderHandler.class) +public class EncoderHandlerMixin implements SupportedIngredientsPacketEncoder { @Unique private Set fabric_supportedCustomIngredients = Set.of(); @@ -46,7 +46,7 @@ public class PacketEncoderMixin implements SupportedIngredientsPacketEncoder { @Inject( at = @At( value = "INVOKE", - target = "net/minecraft/network/packet/Packet.write(Lnet/minecraft/network/PacketByteBuf;)V" + target = "Lnet/minecraft/network/codec/PacketCodec;encode(Ljava/lang/Object;Ljava/lang/Object;)V" ), method = "encode(Lio/netty/channel/ChannelHandlerContext;Lnet/minecraft/network/packet/Packet;Lio/netty/buffer/ByteBuf;)V" ) @@ -59,7 +59,7 @@ public class PacketEncoderMixin implements SupportedIngredientsPacketEncoder { // Normal target after writing @At( value = "INVOKE", - target = "net/minecraft/network/packet/Packet.write(Lnet/minecraft/network/PacketByteBuf;)V", + target = "Lnet/minecraft/network/codec/PacketCodec;encode(Ljava/lang/Object;Ljava/lang/Object;)V", shift = At.Shift.AFTER, by = 1 ), diff --git a/fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/mixin/recipe/ingredient/IngredientMixin.java b/fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/mixin/recipe/ingredient/IngredientMixin.java index bde2169e9..96bbe748c 100644 --- a/fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/mixin/recipe/ingredient/IngredientMixin.java +++ b/fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/mixin/recipe/ingredient/IngredientMixin.java @@ -16,6 +16,7 @@ package net.fabricmc.fabric.mixin.recipe.ingredient; +import com.llamalad7.mixinextras.injector.ModifyExpressionValue; import com.mojang.datafixers.util.Either; import com.mojang.serialization.Codec; import org.spongepowered.asm.mixin.Mixin; @@ -23,15 +24,15 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -import net.minecraft.network.PacketByteBuf; +import net.minecraft.network.RegistryByteBuf; +import net.minecraft.network.codec.PacketCodec; import net.minecraft.recipe.Ingredient; -import net.minecraft.util.Identifier; import net.minecraft.util.dynamic.Codecs; import net.fabricmc.fabric.api.recipe.v1.ingredient.CustomIngredient; -import net.fabricmc.fabric.api.recipe.v1.ingredient.CustomIngredientSerializer; import net.fabricmc.fabric.api.recipe.v1.ingredient.FabricIngredient; import net.fabricmc.fabric.impl.recipe.ingredient.CustomIngredientImpl; +import net.fabricmc.fabric.impl.recipe.ingredient.CustomIngredientPacketCodec; @Mixin(Ingredient.class) public class IngredientMixin implements FabricIngredient { @@ -51,26 +52,14 @@ public class IngredientMixin implements FabricIngredient { )); } - @Inject( - at = @At("HEAD"), - method = "fromPacket", - cancellable = true + @ModifyExpressionValue( + method = "", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/network/codec/PacketCodec;xmap(Ljava/util/function/Function;Ljava/util/function/Function;)Lnet/minecraft/network/codec/PacketCodec;" + ) ) - private static void injectFromPacket(PacketByteBuf buf, CallbackInfoReturnable cir) { - int index = buf.readerIndex(); - - if (buf.readVarInt() == CustomIngredientImpl.PACKET_MARKER) { - Identifier type = buf.readIdentifier(); - CustomIngredientSerializer serializer = CustomIngredientSerializer.get(type); - - if (serializer == null) { - throw new IllegalArgumentException("Cannot deserialize custom ingredient of unknown type " + type); - } - - cir.setReturnValue(serializer.read(buf).toVanilla()); - } else { - // Reset index for vanilla's normal deserialization logic. - buf.readerIndex(index); - } + private static PacketCodec useCustomIngredientPacketCodec(PacketCodec original) { + return new CustomIngredientPacketCodec(original); } } diff --git a/fabric-recipe-api-v1/src/main/resources/fabric-recipe-api-v1.mixins.json b/fabric-recipe-api-v1/src/main/resources/fabric-recipe-api-v1.mixins.json index fd0be6ff6..5b7bd4030 100644 --- a/fabric-recipe-api-v1/src/main/resources/fabric-recipe-api-v1.mixins.json +++ b/fabric-recipe-api-v1/src/main/resources/fabric-recipe-api-v1.mixins.json @@ -4,7 +4,7 @@ "compatibilityLevel": "JAVA_17", "mixins": [ "ingredient.IngredientMixin", - "ingredient.PacketEncoderMixin", + "ingredient.EncoderHandlerMixin", "ingredient.ShapelessRecipeMixin" ], "injectors": { diff --git a/fabric-registry-sync-v0/src/client/java/net/fabricmc/fabric/impl/client/registry/sync/FabricRegistryClientInit.java b/fabric-registry-sync-v0/src/client/java/net/fabricmc/fabric/impl/client/registry/sync/FabricRegistryClientInit.java index acc73102b..5fe4a864f 100644 --- a/fabric-registry-sync-v0/src/client/java/net/fabricmc/fabric/impl/client/registry/sync/FabricRegistryClientInit.java +++ b/fabric-registry-sync-v0/src/client/java/net/fabricmc/fabric/impl/client/registry/sync/FabricRegistryClientInit.java @@ -21,16 +21,15 @@ import java.util.concurrent.CompletionException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import net.minecraft.client.MinecraftClient; import net.minecraft.text.Text; import net.fabricmc.api.ClientModInitializer; import net.fabricmc.fabric.api.client.networking.v1.ClientConfigurationNetworking; -import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; -import net.fabricmc.fabric.impl.registry.sync.FabricRegistryInit; import net.fabricmc.fabric.impl.registry.sync.RegistrySyncManager; import net.fabricmc.fabric.impl.registry.sync.RemapException; +import net.fabricmc.fabric.impl.registry.sync.SyncCompletePayload; import net.fabricmc.fabric.impl.registry.sync.packet.RegistryPacketHandler; -import net.fabricmc.fabric.mixin.networking.client.accessor.ClientCommonNetworkHandlerAccessor; public class FabricRegistryClientInit implements ClientModInitializer { private static final Logger LOGGER = LoggerFactory.getLogger(FabricRegistryClientInit.class); @@ -40,18 +39,20 @@ public class FabricRegistryClientInit implements ClientModInitializer { registerSyncPacketReceiver(RegistrySyncManager.DIRECT_PACKET_HANDLER); } - private void registerSyncPacketReceiver(RegistryPacketHandler packetHandler) { - ClientConfigurationNetworking.registerGlobalReceiver(packetHandler.getPacketId(), (client, handler, buf, responseSender) -> { - RegistrySyncManager.receivePacket(client, packetHandler, buf, RegistrySyncManager.DEBUG || !client.isInSingleplayer()) + private void registerSyncPacketReceiver(RegistryPacketHandler packetHandler) { + ClientConfigurationNetworking.registerGlobalReceiver(packetHandler.getPacketId(), (payload, context) -> { + MinecraftClient client = MinecraftClient.getInstance(); + + RegistrySyncManager.receivePacket(client, packetHandler, payload, RegistrySyncManager.DEBUG || !client.isInSingleplayer()) .whenComplete((complete, throwable) -> { if (throwable != null) { LOGGER.error("Registry remapping failed!", throwable); - client.execute(() -> ((ClientCommonNetworkHandlerAccessor) handler).getConnection().disconnect(getText(throwable))); + client.execute(() -> context.responseSender().disconnect(getText(throwable))); return; } if (complete) { - handler.sendPacket(ClientConfigurationNetworking.createC2SPacket(FabricRegistryInit.SYNC_COMPLETE_ID, PacketByteBufs.create())); + context.responseSender().sendPacket(SyncCompletePayload.INSTANCE); } }); }); diff --git a/fabric-registry-sync-v0/src/client/java/net/fabricmc/fabric/mixin/registry/sync/client/MinecraftClientMixin.java b/fabric-registry-sync-v0/src/client/java/net/fabricmc/fabric/mixin/registry/sync/client/MinecraftClientMixin.java index 5d3de75d2..a11f34d9e 100644 --- a/fabric-registry-sync-v0/src/client/java/net/fabricmc/fabric/mixin/registry/sync/client/MinecraftClientMixin.java +++ b/fabric-registry-sync-v0/src/client/java/net/fabricmc/fabric/mixin/registry/sync/client/MinecraftClientMixin.java @@ -39,8 +39,8 @@ public class MinecraftClientMixin { private static Logger FABRIC_LOGGER = LoggerFactory.getLogger(MinecraftClientMixin.class); // Unmap the registry before loading a new SP/MP setup. - @Inject(at = @At("RETURN"), method = "disconnect(Lnet/minecraft/client/gui/screen/Screen;)V") - public void disconnectAfter(Screen screen_1, CallbackInfo info) { + @Inject(at = @At("RETURN"), method = "disconnect(Lnet/minecraft/client/gui/screen/Screen;Z)V") + public void disconnectAfter(Screen disconnectionScreen, boolean bl, CallbackInfo ci) { try { RegistrySyncManager.unmap(); } catch (RemapException e) { 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 3a0245248..acf23e724 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 @@ -17,22 +17,24 @@ package net.fabricmc.fabric.impl.registry.sync; import net.minecraft.registry.Registries; -import net.minecraft.util.Identifier; import net.fabricmc.api.ModInitializer; import net.fabricmc.fabric.api.event.registry.RegistryAttribute; import net.fabricmc.fabric.api.event.registry.RegistryAttributeHolder; +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.registry.sync.packet.DirectRegistryPacketHandler; public class FabricRegistryInit implements ModInitializer { - public static final Identifier SYNC_COMPLETE_ID = new Identifier("fabric", "registry/sync/complete"); - @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); - ServerConfigurationNetworking.registerGlobalReceiver(SYNC_COMPLETE_ID, (server, handler, buf, responseSender) -> { - handler.completeTask(RegistrySyncManager.SyncConfigurationTask.KEY); + ServerConfigurationNetworking.registerGlobalReceiver(SyncCompletePayload.ID, (payload, context) -> { + context.networkHandler().completeTask(RegistrySyncManager.SyncConfigurationTask.KEY); }); // Synced in PlaySoundS2CPacket. diff --git a/fabric-registry-sync-v0/src/main/java/net/fabricmc/fabric/impl/registry/sync/RegistrySyncManager.java b/fabric-registry-sync-v0/src/main/java/net/fabricmc/fabric/impl/registry/sync/RegistrySyncManager.java index 73c3d3290..7ddb8bcbe 100644 --- a/fabric-registry-sync-v0/src/main/java/net/fabricmc/fabric/impl/registry/sync/RegistrySyncManager.java +++ b/fabric-registry-sync-v0/src/main/java/net/fabricmc/fabric/impl/registry/sync/RegistrySyncManager.java @@ -43,7 +43,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import net.minecraft.nbt.NbtCompound; -import net.minecraft.network.PacketByteBuf; import net.minecraft.network.packet.Packet; import net.minecraft.registry.Registries; import net.minecraft.registry.Registry; @@ -66,7 +65,7 @@ import net.fabricmc.fabric.impl.registry.sync.packet.RegistryPacketHandler; public final class RegistrySyncManager { public static final boolean DEBUG = Boolean.getBoolean("fabric.registry.debug"); - public static final RegistryPacketHandler DIRECT_PACKET_HANDLER = new DirectRegistryPacketHandler(); + public static final DirectRegistryPacketHandler DIRECT_PACKET_HANDLER = new DirectRegistryPacketHandler(); private static final Logger LOGGER = LoggerFactory.getLogger("FabricRegistrySync"); private static final boolean DEBUG_WRITE_REGISTRY_DATA = Boolean.getBoolean("fabric.registry.debug.writeContentsAsCsv"); @@ -105,7 +104,7 @@ public final class RegistrySyncManager { @Override public void sendPacket(Consumer> sender) { - DIRECT_PACKET_HANDLER.sendPacket(handler::sendPacket, map); + DIRECT_PACKET_HANDLER.sendPacket(payload -> handler.sendPacket(ServerConfigurationNetworking.createS2CPacket(payload)), map); } @Override @@ -114,8 +113,8 @@ public final class RegistrySyncManager { } } - public static CompletableFuture receivePacket(ThreadExecutor executor, RegistryPacketHandler handler, PacketByteBuf buf, boolean accept) { - handler.receivePacket(buf); + public static CompletableFuture receivePacket(ThreadExecutor executor, RegistryPacketHandler handler, T payload, boolean accept) { + handler.receivePayload(payload); if (!handler.isPacketFinished()) { return CompletableFuture.completedFuture(false); diff --git a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/payload/FabricPacketLoginQueryRequestPayload.java b/fabric-registry-sync-v0/src/main/java/net/fabricmc/fabric/impl/registry/sync/SyncCompletePayload.java similarity index 53% rename from fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/payload/FabricPacketLoginQueryRequestPayload.java rename to fabric-registry-sync-v0/src/main/java/net/fabricmc/fabric/impl/registry/sync/SyncCompletePayload.java index 0d3c4dcee..cde42b9ea 100644 --- a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/payload/FabricPacketLoginQueryRequestPayload.java +++ b/fabric-registry-sync-v0/src/main/java/net/fabricmc/fabric/impl/registry/sync/SyncCompletePayload.java @@ -14,22 +14,22 @@ * limitations under the License. */ -package net.fabricmc.fabric.impl.networking.payload; +package net.fabricmc.fabric.impl.registry.sync; import net.minecraft.network.PacketByteBuf; -import net.minecraft.network.packet.s2c.login.LoginQueryRequestPayload; +import net.minecraft.network.codec.PacketCodec; +import net.minecraft.network.packet.CustomPayload; import net.minecraft.util.Identifier; -import net.fabricmc.fabric.api.networking.v1.FabricPacket; +public class SyncCompletePayload implements CustomPayload { + public static final SyncCompletePayload INSTANCE = new SyncCompletePayload(); + public static final CustomPayload.Id ID = new CustomPayload.Id<>(new Identifier("fabric", "registry/sync/complete")); + public static final PacketCodec CODEC = PacketCodec.unit(INSTANCE); -public record FabricPacketLoginQueryRequestPayload(FabricPacket fabricPacket) implements LoginQueryRequestPayload { - @Override - public void write(PacketByteBuf buf) { - fabricPacket.write(buf); - } + private SyncCompletePayload() { } @Override - public Identifier id() { - return fabricPacket.getType().getId(); + public Id getId() { + return ID; } } diff --git a/fabric-registry-sync-v0/src/main/java/net/fabricmc/fabric/impl/registry/sync/packet/DirectRegistryPacketHandler.java b/fabric-registry-sync-v0/src/main/java/net/fabricmc/fabric/impl/registry/sync/packet/DirectRegistryPacketHandler.java index a83692a6d..77125b7ff 100644 --- a/fabric-registry-sync-v0/src/main/java/net/fabricmc/fabric/impl/registry/sync/packet/DirectRegistryPacketHandler.java +++ b/fabric-registry-sync-v0/src/main/java/net/fabricmc/fabric/impl/registry/sync/packet/DirectRegistryPacketHandler.java @@ -31,14 +31,15 @@ import it.unimi.dsi.fastutil.objects.Object2IntMap; import org.jetbrains.annotations.Nullable; import net.minecraft.network.PacketByteBuf; -import net.minecraft.network.packet.Packet; +import net.minecraft.network.codec.PacketCodec; +import net.minecraft.network.packet.CustomPayload; import net.minecraft.util.Identifier; import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; /** * A more optimized method to sync registry ids to client. - * Produce smaller packet than old {@link NbtRegistryPacketHandler nbt-based} method. + * Produce smaller packet than old nbt-based method. * *

This method optimize the packet in multiple way: *

    @@ -51,13 +52,12 @@ import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; * *

    This method also split into multiple packets if it exceeds the limit, defaults to 1 MB. */ -public class DirectRegistryPacketHandler extends RegistryPacketHandler { +public class DirectRegistryPacketHandler extends RegistryPacketHandler { /** * @see net.minecraft.network.packet.s2c.play.CustomPayloadS2CPacket#MAX_PAYLOAD_SIZE */ @SuppressWarnings("JavadocReference") private static final int MAX_PAYLOAD_SIZE = Integer.getInteger("fabric.registry.direct.maxPayloadSize", 0x100000); - private static final Identifier ID = new Identifier("fabric", "registry/sync/direct"); @Nullable private PacketByteBuf combinedBuf; @@ -69,12 +69,12 @@ public class DirectRegistryPacketHandler extends RegistryPacketHandler { private int totalPacketReceived = 0; @Override - public Identifier getPacketId() { - return ID; + public CustomPayload.Id getPacketId() { + return Payload.ID; } @Override - public void sendPacket(Consumer> sender, Map> registryMap) { + public void sendPacket(Consumer sender, Map> registryMap) { PacketByteBuf buf = PacketByteBufs.create(); // Group registry ids with same namespace. @@ -153,16 +153,16 @@ public class DirectRegistryPacketHandler extends RegistryPacketHandler { while (sliceIndex < readableBytes) { int sliceSize = Math.min(readableBytes - sliceIndex, MAX_PAYLOAD_SIZE); PacketByteBuf slicedBuf = PacketByteBufs.slice(buf, sliceIndex, sliceSize); - sendPacket(sender, slicedBuf); + sender.accept(createPayload(slicedBuf)); sliceIndex += sliceSize; } // Send an empty buffer to mark the end of the split. - sendPacket(sender, PacketByteBufs.empty()); + sender.accept(createPayload(PacketByteBufs.empty())); } @Override - public void receivePacket(PacketByteBuf slicedBuf) { + public void receivePayload(Payload payload) { Preconditions.checkState(!isPacketFinished); totalPacketReceived++; @@ -170,8 +170,10 @@ public class DirectRegistryPacketHandler extends RegistryPacketHandler { combinedBuf = PacketByteBufs.create(); } - if (slicedBuf.readableBytes() != 0) { - combinedBuf.writeBytes(slicedBuf); + byte[] data = payload.data(); + + if (data.length != 0) { + combinedBuf.writeBytes(data); return; } @@ -242,6 +244,14 @@ public class DirectRegistryPacketHandler extends RegistryPacketHandler { return map; } + private DirectRegistryPacketHandler.Payload createPayload(PacketByteBuf buf) { + if (buf.readableBytes() == 0) { + return new Payload(new byte[0]); + } + + return new Payload(buf.readByteArray()); + } + private static String optimizeNamespace(String namespace) { return namespace.equals(Identifier.DEFAULT_NAMESPACE) ? "" : namespace; } @@ -249,4 +259,22 @@ public class DirectRegistryPacketHandler extends RegistryPacketHandler { private static String unoptimizeNamespace(String namespace) { return namespace.isEmpty() ? Identifier.DEFAULT_NAMESPACE : namespace; } + + public record Payload(byte[] data) implements RegistrySyncPayload { + public static CustomPayload.Id ID = new Id<>(new Identifier("fabric", "registry/sync/direct")); + public static PacketCodec CODEC = CustomPayload.codecOf(Payload::write, Payload::new); + + Payload(PacketByteBuf buf) { + this(buf.readByteArray()); + } + + private void write(PacketByteBuf buf) { + buf.writeByteArray(data); + } + + @Override + public Id getId() { + return ID; + } + } } diff --git a/fabric-registry-sync-v0/src/main/java/net/fabricmc/fabric/impl/registry/sync/packet/RegistryPacketHandler.java b/fabric-registry-sync-v0/src/main/java/net/fabricmc/fabric/impl/registry/sync/packet/RegistryPacketHandler.java index 3772d934f..7151465da 100644 --- a/fabric-registry-sync-v0/src/main/java/net/fabricmc/fabric/impl/registry/sync/packet/RegistryPacketHandler.java +++ b/fabric-registry-sync-v0/src/main/java/net/fabricmc/fabric/impl/registry/sync/packet/RegistryPacketHandler.java @@ -25,22 +25,21 @@ import it.unimi.dsi.fastutil.objects.Object2IntMap; import org.jetbrains.annotations.Nullable; import net.minecraft.network.PacketByteBuf; -import net.minecraft.network.packet.Packet; +import net.minecraft.network.packet.CustomPayload; import net.minecraft.util.Identifier; import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; -import net.fabricmc.fabric.api.networking.v1.ServerConfigurationNetworking; import net.fabricmc.fabric.impl.registry.sync.RegistrySyncManager; -public abstract class RegistryPacketHandler { +public abstract class RegistryPacketHandler { private int rawBufSize = 0; private int deflatedBufSize = 0; - public abstract Identifier getPacketId(); + public abstract CustomPayload.Id getPacketId(); - public abstract void sendPacket(Consumer> sender, Map> registryMap); + public abstract void sendPacket(Consumer sender, Map> registryMap); - public abstract void receivePacket(PacketByteBuf buf); + public abstract void receivePayload(T payload); public abstract int getTotalPacketReceived(); @@ -49,10 +48,6 @@ public abstract class RegistryPacketHandler { @Nullable public abstract Map> getSyncedRegistryMap(); - protected final void sendPacket(Consumer> sender, PacketByteBuf buf) { - sender.accept(ServerConfigurationNetworking.createS2CPacket(getPacketId(), buf)); - } - protected final void computeBufSize(PacketByteBuf buf) { if (!RegistrySyncManager.DEBUG) { return; @@ -94,4 +89,7 @@ public abstract class RegistryPacketHandler { public final int getDeflatedBufSize() { return deflatedBufSize; } + + public interface RegistrySyncPayload extends CustomPayload { + } } diff --git a/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/FrameBlock.java b/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/FrameBlock.java index 345c65a77..7400df0d8 100644 --- a/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/FrameBlock.java +++ b/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/FrameBlock.java @@ -23,10 +23,10 @@ import net.minecraft.block.BlockEntityProvider; import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; import net.minecraft.block.entity.BlockEntity; -import net.minecraft.class_9062; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.ItemStack; import net.minecraft.util.Hand; +import net.minecraft.util.ItemActionResult; import net.minecraft.util.hit.BlockHitResult; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Direction; @@ -43,7 +43,7 @@ public class FrameBlock extends Block implements BlockEntityProvider, FabricBloc } @Override - public class_9062 method_55765(ItemStack stack, BlockState blockState, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult blockHitResult) { + public ItemActionResult onUseWithItem(ItemStack stack, BlockState blockState, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult blockHitResult) { if (world.getBlockEntity(pos) instanceof FrameBlockEntity frame) { Block handBlock = Block.getBlockFromItem(stack.getItem()); @@ -58,20 +58,20 @@ public class FrameBlock extends Block implements BlockEntityProvider, FabricBloc frame.setBlock(null); } - return class_9062.method_55644(world.isClient()); + return ItemActionResult.success(world.isClient()); } - return class_9062.SKIP_DEFAULT_BLOCK_INTERACTION; + return ItemActionResult.SKIP_DEFAULT_BLOCK_INTERACTION; } // getBlockFromItem will return air if we do not have a block item in hand if (handBlock == Blocks.AIR) { - return class_9062.FAIL; + return ItemActionResult.FAIL; } // Do not allow blocks that may have a block entity if (handBlock instanceof BlockEntityProvider) { - return class_9062.FAIL; + return ItemActionResult.FAIL; } stack.decrement(1); @@ -84,10 +84,10 @@ public class FrameBlock extends Block implements BlockEntityProvider, FabricBloc frame.setBlock(handBlock); } - return class_9062.method_55644(world.isClient()); + return ItemActionResult.success(world.isClient()); } - return class_9062.FAIL; + return ItemActionResult.FAIL; } @Nullable diff --git a/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/Registration.java b/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/Registration.java index aca7347d6..9463c25af 100644 --- a/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/Registration.java +++ b/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/Registration.java @@ -16,6 +16,7 @@ package net.fabricmc.fabric.test.renderer; +import net.minecraft.block.AbstractBlock; import net.minecraft.block.Block; import net.minecraft.block.Blocks; import net.minecraft.block.entity.BlockEntityType; @@ -24,16 +25,15 @@ import net.minecraft.item.Item; import net.minecraft.registry.Registries; import net.minecraft.registry.Registry; -import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings; import net.fabricmc.fabric.api.object.builder.v1.block.entity.FabricBlockEntityTypeBuilder; public final class Registration { - public static final FrameBlock FRAME_BLOCK = register("frame", new FrameBlock(FabricBlockSettings.copyOf(Blocks.IRON_BLOCK).nonOpaque())); - public static final FrameBlock FRAME_MULTIPART_BLOCK = register("frame_multipart", new FrameBlock(FabricBlockSettings.copyOf(Blocks.IRON_BLOCK).nonOpaque())); - public static final FrameBlock FRAME_VARIANT_BLOCK = register("frame_variant", new FrameBlock(FabricBlockSettings.copyOf(Blocks.IRON_BLOCK).nonOpaque())); - public static final Block PILLAR_BLOCK = register("pillar", new Block(FabricBlockSettings.create())); - public static final Block OCTAGONAL_COLUMN_BLOCK = register("octagonal_column", new Block(FabricBlockSettings.create().nonOpaque().strength(1.8F))); - public static final Block RIVERSTONE_BLOCK = register("riverstone", new Block(FabricBlockSettings.copyOf(Blocks.STONE))); + public static final FrameBlock FRAME_BLOCK = register("frame", new FrameBlock(AbstractBlock.Settings.copy(Blocks.IRON_BLOCK).nonOpaque())); + public static final FrameBlock FRAME_MULTIPART_BLOCK = register("frame_multipart", new FrameBlock(AbstractBlock.Settings.copy(Blocks.IRON_BLOCK).nonOpaque())); + public static final FrameBlock FRAME_VARIANT_BLOCK = register("frame_variant", new FrameBlock(AbstractBlock.Settings.copy(Blocks.IRON_BLOCK).nonOpaque())); + public static final Block PILLAR_BLOCK = register("pillar", new Block(AbstractBlock.Settings.create())); + public static final Block OCTAGONAL_COLUMN_BLOCK = register("octagonal_column", new Block(AbstractBlock.Settings.create().nonOpaque().strength(1.8F))); + public static final Block RIVERSTONE_BLOCK = register("riverstone", new Block(AbstractBlock.Settings.copy(Blocks.STONE))); public static final FrameBlock[] FRAME_BLOCKS = new FrameBlock[] { FRAME_BLOCK, diff --git a/fabric-screen-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/screen/SoundButton.java b/fabric-screen-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/screen/SoundButton.java index 364c70de5..1e925e501 100644 --- a/fabric-screen-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/screen/SoundButton.java +++ b/fabric-screen-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/screen/SoundButton.java @@ -36,7 +36,7 @@ class SoundButton extends PressableWidget { @Override public void onPress() { - final SoundEvent event = Registries.SOUND_EVENT.getRandom(RANDOM).map(RegistryEntry::value).orElse(SoundEvents.ENTITY_GENERIC_EXPLODE); + final SoundEvent event = Registries.SOUND_EVENT.getRandom(RANDOM).map(RegistryEntry::value).orElse(SoundEvents.ENTITY_GENERIC_EXPLODE.value()); MinecraftClient.getInstance().getSoundManager().play(PositionedSoundInstance.master(event, 1.0F, 1.0F)); } diff --git a/fabric-screen-handler-api-v1/build.gradle b/fabric-screen-handler-api-v1/build.gradle index ac72cee2e..7f43382d7 100644 --- a/fabric-screen-handler-api-v1/build.gradle +++ b/fabric-screen-handler-api-v1/build.gradle @@ -6,7 +6,8 @@ loom { moduleDependencies(project, [ 'fabric-api-base', - 'fabric-networking-api-v1' + 'fabric-networking-api-v1', + 'fabric-registry-sync-v0' ]) testDependencies(project, [ diff --git a/fabric-screen-handler-api-v1/src/client/java/net/fabricmc/fabric/api/client/screenhandler/v1/ScreenRegistry.java b/fabric-screen-handler-api-v1/src/client/java/net/fabricmc/fabric/api/client/screenhandler/v1/ScreenRegistry.java deleted file mode 100644 index 8d3f327b6..000000000 --- a/fabric-screen-handler-api-v1/src/client/java/net/fabricmc/fabric/api/client/screenhandler/v1/ScreenRegistry.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * 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.screenhandler.v1; - -import net.minecraft.client.gui.screen.Screen; -import net.minecraft.client.gui.screen.ingame.HandledScreens; -import net.minecraft.client.gui.screen.ingame.ScreenHandlerProvider; -import net.minecraft.entity.player.PlayerInventory; -import net.minecraft.screen.ScreenHandler; -import net.minecraft.screen.ScreenHandlerType; -import net.minecraft.text.Text; - -/** - * An API for registering handled screens that represent screen handlers on the client. - * Exposes vanilla's private {@link HandledScreens#register HandledScreens.register()} to modders as {@link #register ScreenRegistry.register()}. - * - *

    Example

    - *
    - * {@code
    - * // In a client-side initialization method:
    - * ScreenRegistry.register(MyScreenHandlers.OVEN, OvenScreen::new);
    - *
    - * // Screen class
    - * public class OvenScreen extends HandledScreen {
    - * 	public OvenScreen(OvenScreenHandler handler, PlayerInventory inventory, Text title) {
    - * 		super(handler, inventory, title);
    - * 	}
    - * }
    - * }
    - * 
    - * - * @see net.fabricmc.fabric.api.screenhandler.v1.ScreenHandlerRegistry registering screen handlers - * @deprecated Replaced by access wideners for {@link HandledScreens#register(ScreenHandlerType, HandledScreens.Provider)} - * and {@link HandledScreens.Provider} in Fabric Transitive Access Wideners (v1). - */ -@Deprecated -public final class ScreenRegistry { - private ScreenRegistry() { - } - - /** - * Registers a new screen factory for a screen handler type. - * - * @param type the screen handler type object - * @param screenFactory the screen handler factory - * @param the screen handler type - * @param the screen type - */ - public static > void register(ScreenHandlerType type, Factory screenFactory) { - // Convert our factory to the vanilla provider here as the vanilla interface won't be available to modders. - HandledScreens.register(type, screenFactory::create); - } - - /** - * A factory for handled screens. - * - * @param the screen handler type - * @param the screen type - */ - @FunctionalInterface - public interface Factory> { - /** - * Creates a new handled screen. - * - * @param handler the screen handler - * @param inventory the player inventory - * @param title the title of the screen - * @return the created screen - */ - S create(H handler, PlayerInventory inventory, Text title); - } -} diff --git a/fabric-screen-handler-api-v1/src/client/java/net/fabricmc/fabric/impl/screenhandler/client/ClientNetworking.java b/fabric-screen-handler-api-v1/src/client/java/net/fabricmc/fabric/impl/screenhandler/client/ClientNetworking.java index a6e6d146e..c02e269f0 100644 --- a/fabric-screen-handler-api-v1/src/client/java/net/fabricmc/fabric/impl/screenhandler/client/ClientNetworking.java +++ b/fabric-screen-handler-api-v1/src/client/java/net/fabricmc/fabric/impl/screenhandler/client/ClientNetworking.java @@ -24,7 +24,6 @@ import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.screen.ingame.HandledScreens; import net.minecraft.client.gui.screen.ingame.ScreenHandlerProvider; import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.network.PacketByteBuf; import net.minecraft.registry.Registries; import net.minecraft.screen.ScreenHandlerType; import net.minecraft.text.Text; @@ -40,52 +39,45 @@ public final class ClientNetworking implements ClientModInitializer { @Override public void onInitializeClient() { - ClientPlayNetworking.registerGlobalReceiver(Networking.OPEN_ID, (client, handler, buf, responseSender) -> { - Identifier typeId = buf.readIdentifier(); - int syncId = buf.readVarInt(); - Text title = buf.readText(); - // Retain the buf since we must open the screen handler with it's extra modded data on the client thread - // The buf will be released after the screen is opened - buf.retain(); - - client.execute(() -> this.openScreen(typeId, syncId, title, buf)); + ClientPlayNetworking.registerGlobalReceiver(Networking.OpenScreenPayload.ID, (payload, context) -> { + this.openScreen(payload); }); } @SuppressWarnings({"rawtypes", "unchecked"}) - private void openScreen(Identifier typeId, int syncId, Text title, PacketByteBuf buf) { - try { - ScreenHandlerType type = Registries.SCREEN_HANDLER.get(typeId); + private void openScreen(Networking.OpenScreenPayload payload) { + Identifier typeId = payload.identifier(); + int syncId = payload.syncId(); + Text title = payload.title(); - if (type == null) { - LOGGER.warn("Unknown screen handler ID: {}", typeId); - return; - } + ScreenHandlerType type = Registries.SCREEN_HANDLER.get(typeId); - if (!(type instanceof ExtendedScreenHandlerType)) { - LOGGER.warn("Received extended opening packet for non-extended screen handler {}", typeId); - return; - } + if (type == null || payload.data() == null) { + LOGGER.warn("Unknown screen handler ID: {}", typeId); + return; + } - HandledScreens.Provider screenFactory = HandledScreens.getProvider(type); + if (!(type instanceof ExtendedScreenHandlerType)) { + LOGGER.warn("Received extended opening packet for non-extended screen handler {}", typeId); + return; + } - if (screenFactory != null) { - MinecraftClient client = MinecraftClient.getInstance(); - PlayerEntity player = client.player; + HandledScreens.Provider screenFactory = HandledScreens.getProvider(type); - Screen screen = screenFactory.create( - ((ExtendedScreenHandlerType) type).create(syncId, player.getInventory(), buf), - player.getInventory(), - title - ); + if (screenFactory != null) { + MinecraftClient client = MinecraftClient.getInstance(); + PlayerEntity player = client.player; - player.currentScreenHandler = ((ScreenHandlerProvider) screen).getScreenHandler(); - client.setScreen(screen); - } else { - LOGGER.warn("Screen not registered for screen handler {}!", typeId); - } - } finally { - buf.release(); // Release the buf + Screen screen = screenFactory.create( + ((ExtendedScreenHandlerType) type).create(syncId, player.getInventory(), payload.data()), + player.getInventory(), + title + ); + + player.currentScreenHandler = ((ScreenHandlerProvider) screen).getScreenHandler(); + client.setScreen(screen); + } else { + LOGGER.warn("Screen not registered for screen handler {}!", typeId); } } } diff --git a/fabric-screen-handler-api-v1/src/main/java/net/fabricmc/fabric/api/screenhandler/v1/ExtendedScreenHandlerFactory.java b/fabric-screen-handler-api-v1/src/main/java/net/fabricmc/fabric/api/screenhandler/v1/ExtendedScreenHandlerFactory.java index 4ffb7cbc2..0f087cb57 100644 --- a/fabric-screen-handler-api-v1/src/main/java/net/fabricmc/fabric/api/screenhandler/v1/ExtendedScreenHandlerFactory.java +++ b/fabric-screen-handler-api-v1/src/main/java/net/fabricmc/fabric/api/screenhandler/v1/ExtendedScreenHandlerFactory.java @@ -16,7 +16,6 @@ package net.fabricmc.fabric.api.screenhandler.v1; -import net.minecraft.network.PacketByteBuf; import net.minecraft.screen.NamedScreenHandlerFactory; import net.minecraft.server.network.ServerPlayerEntity; @@ -26,12 +25,12 @@ import net.minecraft.server.network.ServerPlayerEntity; * * @see ExtendedScreenHandlerType usage examples */ -public interface ExtendedScreenHandlerFactory extends NamedScreenHandlerFactory { +public interface ExtendedScreenHandlerFactory extends NamedScreenHandlerFactory { /** * Writes additional server -> client screen opening data to the buffer. * * @param player the player that is opening the screen - * @param buf the packet buffer + * @return the screen opening data */ - void writeScreenOpeningData(ServerPlayerEntity player, PacketByteBuf buf); + D getScreenOpeningData(ServerPlayerEntity player); } diff --git a/fabric-screen-handler-api-v1/src/main/java/net/fabricmc/fabric/api/screenhandler/v1/ExtendedScreenHandlerType.java b/fabric-screen-handler-api-v1/src/main/java/net/fabricmc/fabric/api/screenhandler/v1/ExtendedScreenHandlerType.java index 305d3f4ec..f61be3e43 100644 --- a/fabric-screen-handler-api-v1/src/main/java/net/fabricmc/fabric/api/screenhandler/v1/ExtendedScreenHandlerType.java +++ b/fabric-screen-handler-api-v1/src/main/java/net/fabricmc/fabric/api/screenhandler/v1/ExtendedScreenHandlerType.java @@ -19,7 +19,8 @@ package net.fabricmc.fabric.api.screenhandler.v1; import java.util.Objects; import net.minecraft.entity.player.PlayerInventory; -import net.minecraft.network.PacketByteBuf; +import net.minecraft.network.RegistryByteBuf; +import net.minecraft.network.codec.PacketCodec; import net.minecraft.resource.featuretoggle.FeatureFlags; import net.minecraft.screen.NamedScreenHandlerFactory; import net.minecraft.screen.ScreenHandler; @@ -37,9 +38,18 @@ import net.minecraft.screen.ScreenHandlerType; *

    Example

    *
      * {@code
    + * // Data class
    + * public record OvenData(String label) {
    + *     public static final PacketCodec PACKET_CODEC = PacketCodec.tuple(
    + *     	PacketCodecs.STRING,
    + *     	OvenData::label,
    + *     	OvenData::new
    + *     );
    + * }
    + *
      * // Creating and registering the type
      * public static final ExtendedScreenHandlerType OVEN =
    - * 	new ExtendedScreenHandlerType((syncId, inventory, buf) -> ...);
    + * 	new ExtendedScreenHandlerType((syncId, inventory, data) -> ..., OvenData.PACKET_CODEC);
      * Registry.register(Registry.SCREEN_HANDLER, new Identifier(...), OVEN);
      *
      * // Note: remember to also register the screen using vanilla's HandledScreens!
    @@ -60,23 +70,26 @@ import net.minecraft.screen.ScreenHandlerType;
      * 
    * * @param the type of screen handler created by this type + * @param the type of the data */ -public class ExtendedScreenHandlerType extends ScreenHandlerType { - private final ExtendedFactory factory; +public class ExtendedScreenHandlerType extends ScreenHandlerType { + private final ExtendedFactory factory; + private final PacketCodec packetCodec; /** * Constructs an extended screen handler type. * - * @param factory the screen handler factory used for {@link #create(int, PlayerInventory, PacketByteBuf)} + * @param factory the screen handler factory used for {@link #create(int, PlayerInventory, Object)} */ - public ExtendedScreenHandlerType(ExtendedFactory factory) { + public ExtendedScreenHandlerType(ExtendedFactory factory, PacketCodec packetCodec) { super(null, FeatureFlags.VANILLA_FEATURES); this.factory = Objects.requireNonNull(factory, "screen handler factory cannot be null"); + this.packetCodec = Objects.requireNonNull(packetCodec, "packet codec cannot be null"); } /** - * @throws UnsupportedOperationException always; use {@link #create(int, PlayerInventory, PacketByteBuf)} - * @deprecated Use {@link #create(int, PlayerInventory, PacketByteBuf)} instead. + * @throws UnsupportedOperationException always; use {@link #create(int, PlayerInventory, Object)} + * @deprecated Use {@link #create(int, PlayerInventory, Object)} instead. */ @Deprecated @Override @@ -89,11 +102,18 @@ public class ExtendedScreenHandlerType extends ScreenHa * * @param syncId the sync ID * @param inventory the player inventory - * @param buf the buffer containing the synced opening data + * @param data the synced opening data * @return the created screen handler */ - public T create(int syncId, PlayerInventory inventory, PacketByteBuf buf) { - return factory.create(syncId, inventory, buf); + public T create(int syncId, PlayerInventory inventory, D data) { + return factory.create(syncId, inventory, data); + } + + /** + * @return the packet codec for serializing the data of this screen handler + */ + public PacketCodec getPacketCodec() { + return packetCodec; } /** @@ -103,18 +123,19 @@ public class ExtendedScreenHandlerType extends ScreenHa * server too. * * @param the type of screen handlers created - * @see #create(int, PlayerInventory, PacketByteBuf) + * @param the type of the data + * @see #create(int, PlayerInventory, Object) */ @FunctionalInterface - public interface ExtendedFactory { + public interface ExtendedFactory { /** * Creates a new screen handler with additional screen opening data. * * @param syncId the synchronization ID * @param inventory the player inventory - * @param buf the packet buffer + * @param data the synced data * @return the created screen handler */ - T create(int syncId, PlayerInventory inventory, PacketByteBuf buf); + T create(int syncId, PlayerInventory inventory, D data); } } diff --git a/fabric-screen-handler-api-v1/src/main/java/net/fabricmc/fabric/api/screenhandler/v1/ScreenHandlerRegistry.java b/fabric-screen-handler-api-v1/src/main/java/net/fabricmc/fabric/api/screenhandler/v1/ScreenHandlerRegistry.java deleted file mode 100644 index dd0a2dfb8..000000000 --- a/fabric-screen-handler-api-v1/src/main/java/net/fabricmc/fabric/api/screenhandler/v1/ScreenHandlerRegistry.java +++ /dev/null @@ -1,145 +0,0 @@ -/* - * 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.screenhandler.v1; - -import net.minecraft.entity.player.PlayerInventory; -import net.minecraft.registry.Registries; -import net.minecraft.registry.Registry; -import net.minecraft.resource.featuretoggle.FeatureFlags; -import net.minecraft.screen.ScreenHandler; -import net.minecraft.screen.ScreenHandlerType; -import net.minecraft.util.Identifier; - -/** - * An API for creating and registering {@linkplain ScreenHandlerType screen handler types}. - * - *

    This class exposes the private {@link ScreenHandlerType} constructor, - * as well as adds support for creating types using Fabric's extended screen handler API. - * - *

    Screen handlers types are used to synchronize {@linkplain ScreenHandler screen handlers} - * between the server and the client. Screen handlers manage the items and integer properties that are - * needed to show on screens, such as the items in a chest or the progress of a furnace. - * - *

    Simple and extended screen handlers

    - * Simple screen handlers are the type of screen handlers used in vanilla. - * They can automatically synchronize items and integer properties between the server and the client, - * but they don't support having custom data sent in the opening packet. - * - *

    This module adds extended screen handlers that can synchronize their own custom data - * when they are opened, which can be useful for defining additional properties of a screen on the server. - * For example, a mod can synchronize text that will show up as a label. - * - *

    Example

    - *
    - * {@code
    - * // Creating the screen handler type
    - * public static final ScreenHandlerType OVEN = ScreenHandlerRegistry.registerSimple(new Identifier("my_mod", "oven"), OvenScreenHandler::new);
    - *
    - * // Screen handler class
    - * public class OvenScreenHandler extends ScreenHandler {
    - * 	public OvenScreenHandler(int syncId) {
    - * 		super(MyScreenHandlers.OVEN, syncId);
    - * 	}
    - * }
    - *
    - * // Opening the screen
    - * NamedScreenHandlerFactory factory = ...;
    - * player.openHandledScreen(factory); // only works on ServerPlayerEntity instances
    - * }
    - * 
    - * - * @see net.fabricmc.fabric.api.client.screenhandler.v1.ScreenRegistry registering screens for screen handlers - * @deprecated Replaced by
      - *
    • Creating simple screen handler types directly with {@link ScreenHandlerType} - * using an access widener in Fabric Transitive Access Wideners (v1)
    • - *
    • Creating extended screen handler types with {@link ExtendedScreenHandlerType}
    • - *
    • Registering using {@link Registries#SCREEN_HANDLER} directly
    • - *
    - */ -@Deprecated -public final class ScreenHandlerRegistry { - private ScreenHandlerRegistry() { - } - - /** - * Creates and registers a new {@code ScreenHandlerType} that creates client-sided screen handlers using the factory. - * - * @param id the registry ID - * @param factory the client-sided screen handler factory - * @param the screen handler type - * @return the created type object - * @deprecated Replaced by access widener for {@link ScreenHandlerType#ScreenHandlerType(ScreenHandlerType.Factory)} in Fabric Transitive Access Wideners (v1). - */ - @Deprecated - public static ScreenHandlerType registerSimple(Identifier id, SimpleClientHandlerFactory factory) { - // Wrap our factory in vanilla's factory; it will not be public for users. - // noinspection Convert2MethodRef - Must be a lambda or else dedicated server will crash - ScreenHandlerType type = new ScreenHandlerType<>((syncId, inventory) -> factory.create(syncId, inventory), FeatureFlags.VANILLA_FEATURES); - return Registry.register(Registries.SCREEN_HANDLER, id, type); - } - - /** - * Creates and registers a new {@code ScreenHandlerType} that creates client-sided screen handlers with additional - * networked opening data. - * - *

    These screen handlers must be opened with a {@link ExtendedScreenHandlerFactory}. - * - * @param id the registry ID - * @param factory the client-sided screen handler factory - * @param the screen handler type - * @return the created type object - * @deprecated Replaced with creating an {@link ExtendedScreenHandlerType} manually and registering it - * in the vanilla registry. - */ - @Deprecated - public static ScreenHandlerType registerExtended(Identifier id, ExtendedClientHandlerFactory factory) { - ScreenHandlerType type = new ExtendedScreenHandlerType<>(factory); - return Registry.register(Registries.SCREEN_HANDLER, id, type); - } - - /** - * A factory for screen handler instances. - * This is typically used on the client but is also available on the server. - * - * @param the screen handler type - * @deprecated Replaced by access widener for {@link ScreenHandlerType.Factory} in Fabric Transitive Access Wideners (v1). - */ - @Deprecated - public interface SimpleClientHandlerFactory { - /** - * Creates a new client-sided screen handler. - * - * @param syncId the synchronization ID - * @param inventory the player inventory - * @return the created screen handler - */ - T create(int syncId, PlayerInventory inventory); - } - - /** - * A factory for screen handler instances - * with additional screen opening data. - * This is typically used on the client but is also available on the server. - * - * @param the screen handler type - * @see ExtendedScreenHandlerFactory - * @deprecated Replaced with {@link ExtendedScreenHandlerType.ExtendedFactory}. - */ - @Deprecated - public interface ExtendedClientHandlerFactory extends ExtendedScreenHandlerType.ExtendedFactory { - } -} diff --git a/fabric-screen-handler-api-v1/src/main/java/net/fabricmc/fabric/impl/screenhandler/Networking.java b/fabric-screen-handler-api-v1/src/main/java/net/fabricmc/fabric/impl/screenhandler/Networking.java index 39277259f..135b066ab 100644 --- a/fabric-screen-handler-api-v1/src/main/java/net/fabricmc/fabric/impl/screenhandler/Networking.java +++ b/fabric-screen-handler-api-v1/src/main/java/net/fabricmc/fabric/impl/screenhandler/Networking.java @@ -16,22 +16,30 @@ package net.fabricmc.fabric.impl.screenhandler; +import java.util.HashMap; +import java.util.Map; import java.util.Objects; -import io.netty.buffer.Unpooled; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -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.registry.Registries; import net.minecraft.screen.ScreenHandler; import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.text.Text; import net.minecraft.util.Identifier; +import net.fabricmc.api.ModInitializer; +import net.fabricmc.fabric.api.event.registry.RegistryEntryAddedCallback; +import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry; import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; import net.fabricmc.fabric.api.screenhandler.v1.ExtendedScreenHandlerFactory; +import net.fabricmc.fabric.api.screenhandler.v1.ExtendedScreenHandlerType; -public final class Networking { +public final class Networking implements ModInitializer { private static final Logger LOGGER = LoggerFactory.getLogger("fabric-screen-handler-api-v1/server"); // [Packet format] @@ -40,6 +48,7 @@ public final class Networking { // title: text // customData: buf public static final Identifier OPEN_ID = new Identifier("fabric-screen-handler-api-v1", "open_screen"); + public static final Map> CODEC_BY_ID = new HashMap<>(); /** * Opens an extended screen handler by sending a custom packet to the client. @@ -49,7 +58,8 @@ public final class Networking { * @param handler the screen handler instance * @param syncId the synchronization ID */ - public static void sendOpenPacket(ServerPlayerEntity player, ExtendedScreenHandlerFactory factory, ScreenHandler handler, int syncId) { + @SuppressWarnings("unchecked") + public static void sendOpenPacket(ServerPlayerEntity player, ExtendedScreenHandlerFactory factory, ScreenHandler handler, int syncId) { Objects.requireNonNull(player, "player is null"); Objects.requireNonNull(factory, "factory is null"); Objects.requireNonNull(handler, "handler is null"); @@ -61,12 +71,42 @@ public final class Networking { return; } - PacketByteBuf buf = new PacketByteBuf(Unpooled.buffer()); - buf.writeIdentifier(typeId); - buf.writeVarInt(syncId); - buf.writeText(factory.getDisplayName()); - factory.writeScreenOpeningData(player, buf); + PacketCodec codec = (PacketCodec) Objects.requireNonNull(CODEC_BY_ID.get(typeId), () -> "Codec for " + typeId + " is not registered!"); + D data = factory.getScreenOpeningData(player); - ServerPlayNetworking.send(player, OPEN_ID, buf); + ServerPlayNetworking.send(player, new OpenScreenPayload<>(typeId, syncId, factory.getDisplayName(), codec, data)); + } + + @Override + public void onInitialize() { + PayloadTypeRegistry.playS2C().register(OpenScreenPayload.ID, OpenScreenPayload.CODEC); + RegistryEntryAddedCallback.event(Registries.SCREEN_HANDLER).register((rawId, id, type) -> { + if (type instanceof ExtendedScreenHandlerType extended) { + CODEC_BY_ID.put(id, extended.getPacketCodec()); + } + }); + } + + public record OpenScreenPayload(Identifier identifier, int syncId, Text title, PacketCodec innerCodec, D data) implements CustomPayload { + public static final PacketCodec> CODEC = CustomPayload.codecOf(OpenScreenPayload::write, OpenScreenPayload::fromBuf); + public static final CustomPayload.Id> ID = new Id<>(OPEN_ID); + + @SuppressWarnings("unchecked") + private static OpenScreenPayload fromBuf(RegistryByteBuf buf) { + Identifier id = buf.readIdentifier(); + PacketCodec codec = (PacketCodec) CODEC_BY_ID.get(id); + return new OpenScreenPayload<>(id, buf.readByte(), buf.readText(), codec, codec == null ? null : codec.decode(buf)); + } + + private void write(RegistryByteBuf buf) { + buf.writeIdentifier(this.identifier); + buf.writeByte(this.syncId); + this.innerCodec.encode(buf, this.data); + } + + @Override + public Id getId() { + return ID; + } } } diff --git a/fabric-screen-handler-api-v1/src/main/java/net/fabricmc/fabric/mixin/screenhandler/ServerPlayerEntityMixin.java b/fabric-screen-handler-api-v1/src/main/java/net/fabricmc/fabric/mixin/screenhandler/ServerPlayerEntityMixin.java index c6fb3e591..f0f6056e3 100644 --- a/fabric-screen-handler-api-v1/src/main/java/net/fabricmc/fabric/mixin/screenhandler/ServerPlayerEntityMixin.java +++ b/fabric-screen-handler-api-v1/src/main/java/net/fabricmc/fabric/mixin/screenhandler/ServerPlayerEntityMixin.java @@ -71,7 +71,7 @@ public abstract class ServerPlayerEntityMixin extends PlayerEntity { if (factory instanceof ExtendedScreenHandlerFactory || (factory instanceof SimpleNamedScreenHandlerFactory simpleFactory && simpleFactory.baseFactory instanceof ExtendedScreenHandlerFactory)) { // Set the screen handler, so the factory method can access it through the player. currentScreenHandler = handler; - } else if (handler.getType() instanceof ExtendedScreenHandlerType) { + } else if (handler.getType() instanceof ExtendedScreenHandlerType) { Identifier id = Registries.SCREEN_HANDLER.getId(handler.getType()); throw new IllegalArgumentException("[Fabric] Extended screen handler " + id + " must be opened with an ExtendedScreenHandlerFactory!"); } @@ -79,14 +79,14 @@ public abstract class ServerPlayerEntityMixin extends PlayerEntity { @Redirect(method = "openHandledScreen(Lnet/minecraft/screen/NamedScreenHandlerFactory;)Ljava/util/OptionalInt;", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/network/ServerPlayNetworkHandler;sendPacket(Lnet/minecraft/network/packet/Packet;)V")) private void fabric_replaceVanillaScreenPacket(ServerPlayNetworkHandler networkHandler, Packet packet, NamedScreenHandlerFactory factory) { - if (factory instanceof SimpleNamedScreenHandlerFactory simpleFactory && simpleFactory.baseFactory instanceof ExtendedScreenHandlerFactory extendedFactory) { + if (factory instanceof SimpleNamedScreenHandlerFactory simpleFactory && simpleFactory.baseFactory instanceof ExtendedScreenHandlerFactory extendedFactory) { factory = extendedFactory; } - if (factory instanceof ExtendedScreenHandlerFactory extendedFactory) { + if (factory instanceof ExtendedScreenHandlerFactory extendedFactory) { ScreenHandler handler = Objects.requireNonNull(currentScreenHandler); - if (handler.getType() instanceof ExtendedScreenHandlerType) { + if (handler.getType() instanceof ExtendedScreenHandlerType) { Networking.sendOpenPacket((ServerPlayerEntity) (Object) this, extendedFactory, handler, screenHandlerSyncId); } else { Identifier id = Registries.SCREEN_HANDLER.getId(handler.getType()); diff --git a/fabric-screen-handler-api-v1/src/main/resources/fabric.mod.json b/fabric-screen-handler-api-v1/src/main/resources/fabric.mod.json index f87626cca..434b2a783 100644 --- a/fabric-screen-handler-api-v1/src/main/resources/fabric.mod.json +++ b/fabric-screen-handler-api-v1/src/main/resources/fabric.mod.json @@ -21,6 +21,7 @@ "fabric-networking-api-v1": "*" }, "entrypoints": { + "main": ["net.fabricmc.fabric.impl.screenhandler.Networking"], "client": ["net.fabricmc.fabric.impl.screenhandler.client.ClientNetworking"] }, "description": "Hooks and extensions for creating screen handlers.", diff --git a/fabric-screen-handler-api-v1/src/testmod/java/net/fabricmc/fabric/test/screenhandler/ScreenHandlerTest.java b/fabric-screen-handler-api-v1/src/testmod/java/net/fabricmc/fabric/test/screenhandler/ScreenHandlerTest.java index 404c40028..f500f81af 100644 --- a/fabric-screen-handler-api-v1/src/testmod/java/net/fabricmc/fabric/test/screenhandler/ScreenHandlerTest.java +++ b/fabric-screen-handler-api-v1/src/testmod/java/net/fabricmc/fabric/test/screenhandler/ScreenHandlerTest.java @@ -27,6 +27,7 @@ import net.minecraft.registry.Registry; import net.minecraft.resource.featuretoggle.FeatureFlags; import net.minecraft.screen.ScreenHandlerType; import net.minecraft.util.Identifier; +import net.minecraft.util.math.BlockPos; import net.fabricmc.api.ModInitializer; import net.fabricmc.fabric.api.object.builder.v1.block.entity.FabricBlockEntityTypeBuilder; @@ -48,8 +49,8 @@ public class ScreenHandlerTest implements ModInitializer { public static final Item BOX_ITEM = new BlockItem(BOX, new Item.Settings()); public static final BlockEntityType BOX_ENTITY = FabricBlockEntityTypeBuilder.create(BoxBlockEntity::new, BOX).build(); public static final ScreenHandlerType BAG_SCREEN_HANDLER = new ScreenHandlerType<>(BagScreenHandler::new, FeatureFlags.VANILLA_FEATURES); - public static final ScreenHandlerType POSITIONED_BAG_SCREEN_HANDLER = new ExtendedScreenHandlerType<>(PositionedBagScreenHandler::new); - public static final ScreenHandlerType BOX_SCREEN_HANDLER = new ExtendedScreenHandlerType<>(BoxScreenHandler::new); + public static final ScreenHandlerType POSITIONED_BAG_SCREEN_HANDLER = new ExtendedScreenHandlerType<>(PositionedBagScreenHandler::new, PositionedBagScreenHandler.BagData.PACKET_CODEC); + public static final ScreenHandlerType BOX_SCREEN_HANDLER = new ExtendedScreenHandlerType<>(BoxScreenHandler::new, BlockPos.PACKET_CODEC.cast()); public static Identifier id(String path) { return new Identifier(ID, path); diff --git a/fabric-screen-handler-api-v1/src/testmod/java/net/fabricmc/fabric/test/screenhandler/block/BoxBlock.java b/fabric-screen-handler-api-v1/src/testmod/java/net/fabricmc/fabric/test/screenhandler/block/BoxBlock.java index 4774620d3..3011487d9 100644 --- a/fabric-screen-handler-api-v1/src/testmod/java/net/fabricmc/fabric/test/screenhandler/block/BoxBlock.java +++ b/fabric-screen-handler-api-v1/src/testmod/java/net/fabricmc/fabric/test/screenhandler/block/BoxBlock.java @@ -43,7 +43,7 @@ public class BoxBlock extends BlockWithEntity { } @Override - public ActionResult method_55766(BlockState state, World world, BlockPos pos, PlayerEntity player, BlockHitResult hit) { + public ActionResult onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, BlockHitResult hit) { if (!world.isClient) { NamedScreenHandlerFactory screenHandlerFactory = state.createScreenHandlerFactory(world, pos); diff --git a/fabric-screen-handler-api-v1/src/testmod/java/net/fabricmc/fabric/test/screenhandler/block/BoxBlockEntity.java b/fabric-screen-handler-api-v1/src/testmod/java/net/fabricmc/fabric/test/screenhandler/block/BoxBlockEntity.java index c3dbc7a68..6237979f2 100644 --- a/fabric-screen-handler-api-v1/src/testmod/java/net/fabricmc/fabric/test/screenhandler/block/BoxBlockEntity.java +++ b/fabric-screen-handler-api-v1/src/testmod/java/net/fabricmc/fabric/test/screenhandler/block/BoxBlockEntity.java @@ -20,7 +20,6 @@ import net.minecraft.block.BlockState; import net.minecraft.block.entity.LootableContainerBlockEntity; import net.minecraft.entity.player.PlayerInventory; import net.minecraft.item.ItemStack; -import net.minecraft.network.PacketByteBuf; import net.minecraft.screen.ScreenHandler; import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.text.Text; @@ -31,7 +30,7 @@ import net.fabricmc.fabric.api.screenhandler.v1.ExtendedScreenHandlerFactory; import net.fabricmc.fabric.test.screenhandler.ScreenHandlerTest; import net.fabricmc.fabric.test.screenhandler.screen.BoxScreenHandler; -public class BoxBlockEntity extends LootableContainerBlockEntity implements ExtendedScreenHandlerFactory { +public class BoxBlockEntity extends LootableContainerBlockEntity implements ExtendedScreenHandlerFactory { private DefaultedList items = DefaultedList.ofSize(size(), ItemStack.EMPTY); public BoxBlockEntity(BlockPos blockPos, BlockState blockState) { @@ -64,7 +63,7 @@ public class BoxBlockEntity extends LootableContainerBlockEntity implements Exte } @Override - public void writeScreenOpeningData(ServerPlayerEntity player, PacketByteBuf buf) { - buf.writeBlockPos(pos); + public BlockPos getScreenOpeningData(ServerPlayerEntity player) { + return pos; } } diff --git a/fabric-screen-handler-api-v1/src/testmod/java/net/fabricmc/fabric/test/screenhandler/item/PositionedBagItem.java b/fabric-screen-handler-api-v1/src/testmod/java/net/fabricmc/fabric/test/screenhandler/item/PositionedBagItem.java index 13373b385..bbd33e821 100644 --- a/fabric-screen-handler-api-v1/src/testmod/java/net/fabricmc/fabric/test/screenhandler/item/PositionedBagItem.java +++ b/fabric-screen-handler-api-v1/src/testmod/java/net/fabricmc/fabric/test/screenhandler/item/PositionedBagItem.java @@ -16,11 +16,12 @@ package net.fabricmc.fabric.test.screenhandler.item; +import java.util.Optional; + import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerInventory; import net.minecraft.item.ItemStack; import net.minecraft.item.ItemUsageContext; -import net.minecraft.network.PacketByteBuf; import net.minecraft.screen.ScreenHandler; import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.text.Text; @@ -54,8 +55,8 @@ public class PositionedBagItem extends BagItem { return ActionResult.SUCCESS; } - private ExtendedScreenHandlerFactory createScreenHandlerFactory(ItemStack stack, BlockPos pos) { - return new ExtendedScreenHandlerFactory() { + private ExtendedScreenHandlerFactory createScreenHandlerFactory(ItemStack stack, BlockPos pos) { + return new ExtendedScreenHandlerFactory<>() { @Override public ScreenHandler createMenu(int syncId, PlayerInventory inventory, PlayerEntity player) { return new PositionedBagScreenHandler(syncId, inventory, new BagInventory(stack), pos); @@ -67,9 +68,8 @@ public class PositionedBagItem extends BagItem { } @Override - public void writeScreenOpeningData(ServerPlayerEntity player, PacketByteBuf buf) { - buf.writeBoolean(pos != null); - buf.writeBlockPos(pos != null ? pos : BlockPos.ORIGIN); + public PositionedBagScreenHandler.BagData getScreenOpeningData(ServerPlayerEntity player) { + return new PositionedBagScreenHandler.BagData(Optional.of(pos)); } }; } diff --git a/fabric-screen-handler-api-v1/src/testmod/java/net/fabricmc/fabric/test/screenhandler/screen/BoxScreenHandler.java b/fabric-screen-handler-api-v1/src/testmod/java/net/fabricmc/fabric/test/screenhandler/screen/BoxScreenHandler.java index 6d3dc7e13..7f2c00433 100644 --- a/fabric-screen-handler-api-v1/src/testmod/java/net/fabricmc/fabric/test/screenhandler/screen/BoxScreenHandler.java +++ b/fabric-screen-handler-api-v1/src/testmod/java/net/fabricmc/fabric/test/screenhandler/screen/BoxScreenHandler.java @@ -18,7 +18,6 @@ package net.fabricmc.fabric.test.screenhandler.screen; import net.minecraft.entity.player.PlayerInventory; import net.minecraft.inventory.Inventory; -import net.minecraft.network.PacketByteBuf; import net.minecraft.screen.Generic3x3ContainerScreenHandler; import net.minecraft.screen.ScreenHandlerType; import net.minecraft.util.math.BlockPos; @@ -28,9 +27,9 @@ import net.fabricmc.fabric.test.screenhandler.ScreenHandlerTest; public class BoxScreenHandler extends Generic3x3ContainerScreenHandler implements PositionedScreenHandler { private final BlockPos pos; - public BoxScreenHandler(int syncId, PlayerInventory playerInventory, PacketByteBuf buf) { + public BoxScreenHandler(int syncId, PlayerInventory playerInventory, BlockPos pos) { super(syncId, playerInventory); - this.pos = buf.readBlockPos(); + this.pos = pos; } public BoxScreenHandler(int syncId, PlayerInventory playerInventory, Inventory inventory) { diff --git a/fabric-screen-handler-api-v1/src/testmod/java/net/fabricmc/fabric/test/screenhandler/screen/PositionedBagScreenHandler.java b/fabric-screen-handler-api-v1/src/testmod/java/net/fabricmc/fabric/test/screenhandler/screen/PositionedBagScreenHandler.java index 2c7102f94..c387fc857 100644 --- a/fabric-screen-handler-api-v1/src/testmod/java/net/fabricmc/fabric/test/screenhandler/screen/PositionedBagScreenHandler.java +++ b/fabric-screen-handler-api-v1/src/testmod/java/net/fabricmc/fabric/test/screenhandler/screen/PositionedBagScreenHandler.java @@ -16,10 +16,14 @@ package net.fabricmc.fabric.test.screenhandler.screen; +import java.util.Optional; + import net.minecraft.entity.player.PlayerInventory; import net.minecraft.inventory.Inventory; import net.minecraft.inventory.SimpleInventory; -import net.minecraft.network.PacketByteBuf; +import net.minecraft.network.RegistryByteBuf; +import net.minecraft.network.codec.PacketCodec; +import net.minecraft.network.codec.PacketCodecs; import net.minecraft.util.math.BlockPos; import net.fabricmc.fabric.test.screenhandler.ScreenHandlerTest; @@ -27,14 +31,8 @@ import net.fabricmc.fabric.test.screenhandler.ScreenHandlerTest; public class PositionedBagScreenHandler extends BagScreenHandler implements PositionedScreenHandler { private final BlockPos pos; - public PositionedBagScreenHandler(int syncId, PlayerInventory playerInventory, PacketByteBuf buf) { - this(syncId, playerInventory, new SimpleInventory(9), readOptionalPos(buf)); - } - - private static BlockPos readOptionalPos(PacketByteBuf buf) { - boolean hasPos = buf.readBoolean(); - BlockPos pos = buf.readBlockPos(); - return hasPos ? pos : null; + public PositionedBagScreenHandler(int syncId, PlayerInventory playerInventory, BagData data) { + this(syncId, playerInventory, new SimpleInventory(9), data.pos().orElse(null)); } public PositionedBagScreenHandler(int syncId, PlayerInventory playerInventory, Inventory inventory, BlockPos pos) { @@ -46,4 +44,8 @@ public class PositionedBagScreenHandler extends BagScreenHandler implements Posi public BlockPos getPos() { return pos; } + + public record BagData(Optional pos) { + public static final PacketCodec PACKET_CODEC = BlockPos.PACKET_CODEC.collect(PacketCodecs::optional).xmap(BagData::new, BagData::pos).cast(); + } } diff --git a/fabric-transfer-api-v1/src/testmod/java/net/fabricmc/fabric/test/transfer/ingame/FluidChuteBlock.java b/fabric-transfer-api-v1/src/testmod/java/net/fabricmc/fabric/test/transfer/ingame/FluidChuteBlock.java index e57dfb120..b6a2e5a0c 100644 --- a/fabric-transfer-api-v1/src/testmod/java/net/fabricmc/fabric/test/transfer/ingame/FluidChuteBlock.java +++ b/fabric-transfer-api-v1/src/testmod/java/net/fabricmc/fabric/test/transfer/ingame/FluidChuteBlock.java @@ -25,11 +25,11 @@ import net.minecraft.block.ShapeContext; import net.minecraft.block.entity.BlockEntity; import net.minecraft.block.entity.BlockEntityTicker; import net.minecraft.block.entity.BlockEntityType; -import net.minecraft.class_9062; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.ItemStack; import net.minecraft.text.Text; import net.minecraft.util.Hand; +import net.minecraft.util.ItemActionResult; import net.minecraft.util.hit.BlockHitResult; import net.minecraft.util.math.BlockPos; import net.minecraft.util.shape.VoxelShape; @@ -65,7 +65,7 @@ public class FluidChuteBlock extends Block implements BlockEntityProvider { } @Override - public class_9062 method_55765(ItemStack stack, BlockState blockState, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult blockHitResult) { + public ItemActionResult onUseWithItem(ItemStack stack, BlockState blockState, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult blockHitResult) { if (world.getBlockEntity(pos) instanceof FluidChuteBlockEntity chute) { if (!FluidStorageUtil.interactWithFluidStorage(chute.storage, player, hand)) { if (!world.isClient()) { @@ -77,10 +77,10 @@ public class FluidChuteBlock extends Block implements BlockEntityProvider { ); } - return class_9062.CONSUME; + return ItemActionResult.CONSUME; } } - return class_9062.method_55644(world.isClient()); + return ItemActionResult.success(world.isClient()); } } diff --git a/fabric-transitive-access-wideners-v1/src/testmod/java/net/fabricmc/fabric/test/access/SignBlockEntityTest.java b/fabric-transitive-access-wideners-v1/src/testmod/java/net/fabricmc/fabric/test/access/SignBlockEntityTest.java index 4855b6308..ee43426d5 100644 --- a/fabric-transitive-access-wideners-v1/src/testmod/java/net/fabricmc/fabric/test/access/SignBlockEntityTest.java +++ b/fabric-transitive-access-wideners-v1/src/testmod/java/net/fabricmc/fabric/test/access/SignBlockEntityTest.java @@ -16,6 +16,7 @@ package net.fabricmc.fabric.test.access; +import net.minecraft.block.AbstractBlock; import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; import net.minecraft.block.SignBlock; @@ -32,18 +33,17 @@ import net.minecraft.util.Identifier; import net.minecraft.util.math.BlockPos; import net.fabricmc.api.ModInitializer; -import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings; import net.fabricmc.fabric.api.object.builder.v1.block.entity.FabricBlockEntityTypeBuilder; public final class SignBlockEntityTest implements ModInitializer { public static final String MOD_ID = "fabric-transitive-access-wideners-v1-testmod"; - public static final SignBlock TEST_SIGN = new SignBlock(WoodType.OAK, FabricBlockSettings.copy(Blocks.OAK_SIGN)) { + public static final SignBlock TEST_SIGN = new SignBlock(WoodType.OAK, AbstractBlock.Settings.copy(Blocks.OAK_SIGN)) { @Override public BlockEntity createBlockEntity(BlockPos pos, BlockState state) { return new TestSign(pos, state); } }; - public static final WallSignBlock TEST_WALL_SIGN = new WallSignBlock(WoodType.OAK, FabricBlockSettings.copy(Blocks.OAK_SIGN)) { + public static final WallSignBlock TEST_WALL_SIGN = new WallSignBlock(WoodType.OAK, AbstractBlock.Settings.copy(Blocks.OAK_SIGN)) { @Override public BlockEntity createBlockEntity(BlockPos pos, BlockState state) { return new TestSign(pos, state); diff --git a/gradle.properties b/gradle.properties index f4194341d..78f3d442a 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,9 +2,9 @@ org.gradle.jvmargs=-Xmx2560M org.gradle.parallel=true fabric.loom.multiProjectOptimisation=true -version=0.94.0 -minecraft_version=23w51b -yarn_version=+build.1 +version=0.95.1 +minecraft_version=24w03b +yarn_version=+build.6 loader_version=0.15.6 installer_version=0.11.1 @@ -12,54 +12,53 @@ prerelease=true curseforge_minecraft_version=1.20.5-Snapshot # Do not manually update, use the bumpversions task: -fabric-api-base-version=0.4.37 -fabric-api-lookup-api-v1-version=1.6.48 -fabric-biome-api-v1-version=13.0.17 -fabric-block-api-v1-version=1.0.16 -fabric-block-view-api-v2-version=1.0.5 -fabric-blockrenderlayer-v1-version=1.1.47 -fabric-command-api-v1-version=1.2.42 -fabric-command-api-v2-version=2.2.21 -fabric-commands-v0-version=0.2.59 -fabric-containers-v0-version=0.1.85 -fabric-content-registries-v0-version=6.0.1 -fabric-crash-report-info-v1-version=0.2.24 -fabric-data-attachment-api-v1-version=1.0.0 -fabric-data-generation-api-v1-version=14.0.3 -fabric-dimensions-v1-version=2.1.62 -fabric-entity-events-v1-version=1.6.0 -fabric-events-interaction-v0-version=0.7.1 -fabric-events-lifecycle-v0-version=0.2.73 -fabric-game-rule-api-v1-version=1.0.47 -fabric-gametest-api-v1-version=1.3.1 -fabric-item-api-v1-version=3.1.0 -fabric-item-group-api-v1-version=4.0.22 -fabric-key-binding-api-v1-version=1.0.42 -fabric-keybindings-v0-version=0.2.40 -fabric-lifecycle-events-v1-version=2.2.31 -fabric-loot-api-v2-version=2.1.6 -fabric-message-api-v1-version=6.0.6 -fabric-mining-level-api-v1-version=2.1.61 -fabric-model-loading-api-v1-version=1.0.9 -fabric-models-v0-version=0.4.8 -fabric-networking-api-v1-version=3.1.6 -fabric-object-builder-api-v1-version=13.0.10 -fabric-particles-v1-version=1.1.8 -fabric-recipe-api-v1-version=2.0.19 -fabric-registry-sync-v0-version=4.0.17 -fabric-renderer-api-v1-version=3.2.5 -fabric-renderer-indigo-version=1.5.5 -fabric-renderer-registries-v1-version=3.2.52 -fabric-rendering-data-attachment-v1-version=0.3.43 -fabric-rendering-fluids-v1-version=3.0.34 -fabric-rendering-v0-version=1.1.55 -fabric-rendering-v1-version=3.0.14 -fabric-resource-conditions-api-v1-version=2.3.15 -fabric-resource-loader-v0-version=0.11.17 -fabric-screen-api-v1-version=2.0.18 -fabric-screen-handler-api-v1-version=1.3.54 -fabric-sound-api-v1-version=1.0.18 -fabric-transfer-api-v1-version=4.0.9 -fabric-transitive-access-wideners-v1-version=6.0.1 -fabric-convention-tags-v1-version=1.5.11 -fabric-client-tags-api-v1-version=1.1.8 +fabric-api-base-version=0.4.38 +fabric-api-lookup-api-v1-version=1.6.49 +fabric-biome-api-v1-version=13.0.18 +fabric-block-api-v1-version=1.0.17 +fabric-block-view-api-v2-version=1.0.6 +fabric-blockrenderlayer-v1-version=1.1.48 +fabric-command-api-v1-version=1.2.43 +fabric-command-api-v2-version=2.2.22 +fabric-commands-v0-version=0.2.60 +fabric-content-registries-v0-version=6.0.2 +fabric-crash-report-info-v1-version=0.2.25 +fabric-data-attachment-api-v1-version=1.0.1 +fabric-data-generation-api-v1-version=14.0.4 +fabric-dimensions-v1-version=2.1.63 +fabric-entity-events-v1-version=1.6.1 +fabric-events-interaction-v0-version=0.7.2 +fabric-events-lifecycle-v0-version=0.2.74 +fabric-game-rule-api-v1-version=1.0.48 +fabric-gametest-api-v1-version=1.3.2 +fabric-item-api-v1-version=4.0.0 +fabric-item-group-api-v1-version=4.0.23 +fabric-key-binding-api-v1-version=1.0.43 +fabric-keybindings-v0-version=0.2.41 +fabric-lifecycle-events-v1-version=2.2.32 +fabric-loot-api-v2-version=2.1.7 +fabric-message-api-v1-version=6.0.7 +fabric-mining-level-api-v1-version=2.1.62 +fabric-model-loading-api-v1-version=1.0.10 +fabric-models-v0-version=0.4.9 +fabric-networking-api-v1-version=4.0.0 +fabric-object-builder-api-v1-version=13.0.11 +fabric-particles-v1-version=2.0.0 +fabric-recipe-api-v1-version=3.0.0 +fabric-registry-sync-v0-version=4.0.18 +fabric-renderer-api-v1-version=3.2.6 +fabric-renderer-indigo-version=1.5.6 +fabric-renderer-registries-v1-version=3.2.53 +fabric-rendering-data-attachment-v1-version=0.3.44 +fabric-rendering-fluids-v1-version=3.0.35 +fabric-rendering-v0-version=1.1.56 +fabric-rendering-v1-version=3.0.15 +fabric-resource-conditions-api-v1-version=2.3.16 +fabric-resource-loader-v0-version=0.11.18 +fabric-screen-api-v1-version=2.0.19 +fabric-screen-handler-api-v1-version=1.3.55 +fabric-sound-api-v1-version=1.0.19 +fabric-transfer-api-v1-version=4.0.10 +fabric-transitive-access-wideners-v1-version=6.0.2 +fabric-convention-tags-v1-version=1.5.12 +fabric-client-tags-api-v1-version=1.1.9 diff --git a/settings.gradle b/settings.gradle index 59f646592..3e984e1ee 100644 --- a/settings.gradle +++ b/settings.gradle @@ -61,7 +61,6 @@ include 'fabric-transitive-access-wideners-v1' include 'deprecated' include 'deprecated:fabric-command-api-v1' include 'deprecated:fabric-commands-v0' -include 'deprecated:fabric-containers-v0' include 'deprecated:fabric-events-lifecycle-v0' include 'deprecated:fabric-keybindings-v0' include 'deprecated:fabric-models-v0'