diff --git a/src/main/java/net/minecraftforge/fml/ModLoader.java b/src/main/java/net/minecraftforge/fml/ModLoader.java index 473b61ca9d..3887c498db 100644 --- a/src/main/java/net/minecraftforge/fml/ModLoader.java +++ b/src/main/java/net/minecraftforge/fml/ModLoader.java @@ -31,6 +31,7 @@ import net.minecraftforge.fml.loading.FMLPaths; import net.minecraftforge.fml.loading.LoadingModList; import net.minecraftforge.fml.loading.moddiscovery.ModFile; import net.minecraftforge.fml.loading.moddiscovery.ModFileInfo; +import net.minecraftforge.fml.network.FMLNetworkConstants; import net.minecraftforge.forgespi.language.IModInfo; import net.minecraftforge.forgespi.language.IModLanguageProvider; import net.minecraftforge.registries.GameData; @@ -99,6 +100,7 @@ public class ModLoader this.loadingModList = FMLLoader.getLoadingModList(); this.loadingExceptions = FMLLoader.getLoadingModList(). getErrors().stream().flatMap(ModLoadingException::fromEarlyException).collect(Collectors.toList()); + LOGGER.info(CORE, "Loading Network data for FML net version: {}", FMLNetworkConstants.NETVERSION); } public static ModLoader get() diff --git a/src/main/java/net/minecraftforge/fml/network/FMLHandshakeHandler.java b/src/main/java/net/minecraftforge/fml/network/FMLHandshakeHandler.java index 1e9a7fdc7d..7a8cb91c98 100644 --- a/src/main/java/net/minecraftforge/fml/network/FMLHandshakeHandler.java +++ b/src/main/java/net/minecraftforge/fml/network/FMLHandshakeHandler.java @@ -19,7 +19,6 @@ package net.minecraftforge.fml.network; -import io.netty.util.AttributeKey; import net.minecraft.network.NetworkManager; import net.minecraft.network.PacketBuffer; import net.minecraft.network.NetHandlerLoginServer; @@ -27,9 +26,7 @@ import net.minecraft.util.ResourceLocation; import net.minecraft.util.text.TextComponentString; import net.minecraftforge.fml.config.ConfigTracker; import net.minecraftforge.fml.network.simple.SimpleChannel; -import net.minecraftforge.fml.util.ThreeConsumer; import net.minecraftforge.registries.ForgeRegistry; -import net.minecraftforge.registries.RegistryManager; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Marker; @@ -37,8 +34,12 @@ import org.apache.logging.log4j.MarkerManager; import com.google.common.collect.Maps; -import java.util.*; -import java.util.function.BiConsumer; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; import java.util.function.Supplier; import static net.minecraftforge.registries.ForgeRegistry.REGISTRIES; @@ -47,9 +48,9 @@ import static net.minecraftforge.registries.ForgeRegistry.REGISTRIES; * Instance responsible for handling the overall FML network handshake. * *

An instance is created during {@link net.minecraft.network.handshake.client.CPacketHandshake} handling, and attached - * to the {@link NetworkManager#channel} via {@link #FML_HANDSHAKE_HANDLER_ATTRIBUTE_KEY}. + * to the {@link NetworkManager#channel} via {@link FMLNetworkConstants#FML_HANDSHAKE_HANDLER}. * - *

The {@link #channel} is a {@link SimpleChannel} with standard messages flowing in both directions. + *

The {@link FMLNetworkConstants#handshakeChannel} is a {@link SimpleChannel} with standard messages flowing in both directions. * *

The {@link #loginWrapper} transforms these messages into {@link net.minecraft.network.login.client.CPacketCustomPayloadLogin} * and {@link net.minecraft.network.login.server.SPacketCustomPayloadLogin} compatible messages, by means of wrapping. @@ -76,75 +77,10 @@ import static net.minecraftforge.registries.ForgeRegistry.REGISTRIES; public class FMLHandshakeHandler { static final Marker FMLHSMARKER = MarkerManager.getMarker("FMLHANDSHAKE").setParents(FMLNetworkConstants.NETWORK); private static final Logger LOGGER = LogManager.getLogger(); - static final ResourceLocation FML_HANDSHAKE_RESOURCE = new ResourceLocation("fml:handshake"); - private static final AttributeKey FML_HANDSHAKE_HANDLER_ATTRIBUTE_KEY = AttributeKey.newInstance("fml:handshake"); private static final FMLLoginWrapper loginWrapper = new FMLLoginWrapper(); - private static SimpleChannel channel; + static { - channel = NetworkRegistry.ChannelBuilder.named(FML_HANDSHAKE_RESOURCE). - clientAcceptedVersions(a -> true). - serverAcceptedVersions(a -> true). - networkProtocolVersion(() -> FMLNetworkConstants.NETVERSION). - simpleChannel(); - channel.messageBuilder(FMLHandshakeMessages.C2SAcknowledge.class, 99). - loginIndex(FMLHandshakeMessages.LoginIndexedMessage::getLoginIndex, FMLHandshakeMessages.LoginIndexedMessage::setLoginIndex). - decoder(FMLHandshakeMessages.C2SAcknowledge::decode). - encoder(FMLHandshakeMessages.C2SAcknowledge::encode). - consumer(indexFirst(FMLHandshakeHandler::handleClientAck)). - add(); - channel.messageBuilder(FMLHandshakeMessages.S2CModList.class, 1). - loginIndex(FMLHandshakeMessages.LoginIndexedMessage::getLoginIndex, FMLHandshakeMessages.LoginIndexedMessage::setLoginIndex). - decoder(FMLHandshakeMessages.S2CModList::decode). - encoder(FMLHandshakeMessages.S2CModList::encode). - markAsLoginPacket(). - consumer(biConsumerFor(FMLHandshakeHandler::handleServerModListOnClient)). - add(); - channel.messageBuilder(FMLHandshakeMessages.C2SModListReply.class, 2). - loginIndex(FMLHandshakeMessages.LoginIndexedMessage::getLoginIndex, FMLHandshakeMessages.LoginIndexedMessage::setLoginIndex). - decoder(FMLHandshakeMessages.C2SModListReply::decode). - encoder(FMLHandshakeMessages.C2SModListReply::encode). - consumer(indexFirst(FMLHandshakeHandler::handleClientModListOnServer)). - add(); - channel.messageBuilder(FMLHandshakeMessages.S2CRegistry.class, 3). - loginIndex(FMLHandshakeMessages.LoginIndexedMessage::getLoginIndex, FMLHandshakeMessages.LoginIndexedMessage::setLoginIndex). - decoder(FMLHandshakeMessages.S2CRegistry::decode). - encoder(FMLHandshakeMessages.S2CRegistry::encode). - buildLoginPacketList(RegistryManager::generateRegistryPackets). //TODO: Make this non-static, and store a cache on the client. - consumer(biConsumerFor(FMLHandshakeHandler::handleRegistryMessage)). - add(); - channel.messageBuilder(FMLHandshakeMessages.S2CConfigData.class, 4). - loginIndex(FMLHandshakeMessages.LoginIndexedMessage::getLoginIndex, FMLHandshakeMessages.LoginIndexedMessage::setLoginIndex). - decoder(FMLHandshakeMessages.S2CConfigData::decode). - encoder(FMLHandshakeMessages.S2CConfigData::encode). - buildLoginPacketList(ConfigTracker.INSTANCE::syncConfigs). - consumer(biConsumerFor(FMLHandshakeHandler::handleConfigSync)). - add(); - } - - /** - * Transforms a two-argument instance method reference into a {@link BiConsumer} based on the {@link #getHandshake(Supplier)} function. - * - * @param consumer A two argument instance method reference - * @param message type - * @return A {@link BiConsumer} for use in message handling - */ - private static BiConsumer> biConsumerFor(ThreeConsumer> consumer) - { - return (m, c) -> ThreeConsumer.bindArgs(consumer, m, c).accept(getHandshake(c)); - } - - /** - * Transforms a two-argument instance method reference into a {@link BiConsumer} {@link #biConsumerFor(ThreeConsumer)}, first calling the {@link #handleIndexedMessage(FMLHandshakeMessages.LoginIndexedMessage, Supplier)} - * method to handle index tracking. Used for client to server replies. - * @param next The method reference to call after index handling - * @param message type - * @return A {@link BiConsumer} for use in message handling - */ - private static BiConsumer> indexFirst(ThreeConsumer> next) - { - final BiConsumer> loginIndexedMessageSupplierBiConsumer = biConsumerFor(FMLHandshakeHandler::handleIndexedMessage); - return loginIndexedMessageSupplierBiConsumer.andThen(biConsumerFor(next)); } /** @@ -155,22 +91,12 @@ public class FMLHandshakeHandler { * @param direction The {@link NetworkDirection} for this connection: {@link NetworkDirection#LOGIN_TO_SERVER} or {@link NetworkDirection#LOGIN_TO_CLIENT} */ static void registerHandshake(NetworkManager manager, NetworkDirection direction) { - manager.channel().attr(FML_HANDSHAKE_HANDLER_ATTRIBUTE_KEY).compareAndSet(null, new FMLHandshakeHandler(manager, direction)); - } - - /** - * Retrieve the handshake from the {@link NetworkEvent.Context} - * - * @param contextSupplier the {@link NetworkEvent.Context} - * @return The handshake handler for the connection - */ - private static FMLHandshakeHandler getHandshake(Supplier contextSupplier) { - return contextSupplier.get().attr(FML_HANDSHAKE_HANDLER_ATTRIBUTE_KEY).get(); + manager.channel().attr(FMLNetworkConstants.FML_HANDSHAKE_HANDLER).compareAndSet(null, new FMLHandshakeHandler(manager, direction)); } static boolean tickLogin(NetworkManager networkManager) { - return networkManager.channel().attr(FML_HANDSHAKE_HANDLER_ATTRIBUTE_KEY).get().tickServer(); + return networkManager.channel().attr(FMLNetworkConstants.FML_HANDSHAKE_HANDLER).get().tickServer(); } private List messageList; @@ -197,7 +123,7 @@ public class FMLHandshakeHandler { } } - private void handleServerModListOnClient(FMLHandshakeMessages.S2CModList serverModList, Supplier c) + void handleServerModListOnClient(FMLHandshakeMessages.S2CModList serverModList, Supplier c) { LOGGER.debug(FMLHSMARKER, "Logging into server with mod list [{}]", String.join(", ", serverModList.getModList())); boolean accepted = NetworkRegistry.validateClientChannels(serverModList.getChannels()); @@ -207,18 +133,18 @@ public class FMLHandshakeHandler { c.get().getNetworkManager().closeChannel(new TextComponentString("Connection closed - mismatched mod channel list")); return; } - channel.reply(new FMLHandshakeMessages.C2SModListReply(), c.get()); + FMLNetworkConstants.handshakeChannel.reply(new FMLHandshakeMessages.C2SModListReply(), c.get()); LOGGER.debug(FMLHSMARKER, "Accepted server connection"); // Set the modded marker on the channel so we know we got packets - c.get().getNetworkManager().channel().attr(FMLNetworkConstants.FML_MARKER).set(FMLNetworkConstants.NETVERSION); + c.get().getNetworkManager().channel().attr(FMLNetworkConstants.FML_NETVERSION).set(FMLNetworkConstants.NETVERSION); this.registriesToReceive = new HashSet<>(serverModList.getRegistries()); this.registrySnapshots = Maps.newHashMap(); LOGGER.debug(REGISTRIES, "Expecting {} registries: {}", ()->this.registriesToReceive.size(), ()->this.registriesToReceive); } - private void handleIndexedMessage(MSG message, Supplier c) + void handleIndexedMessage(MSG message, Supplier c) { LOGGER.debug(FMLHSMARKER, "Received client indexed reply {} of type {}", message.getLoginIndex(), message.getClass().getName()); boolean removed = this.sentMessages.removeIf(i->i==message.getLoginIndex()); @@ -227,7 +153,7 @@ public class FMLHandshakeHandler { } } - private void handleClientModListOnServer(FMLHandshakeMessages.C2SModListReply clientModList, Supplier c) + void handleClientModListOnServer(FMLHandshakeMessages.C2SModListReply clientModList, Supplier c) { LOGGER.debug(FMLHSMARKER, "Received client connection with modlist [{}]", String.join(", ", clientModList.getModList())); boolean accepted = NetworkRegistry.validateServerChannels(clientModList.getChannels()); @@ -240,12 +166,12 @@ public class FMLHandshakeHandler { LOGGER.debug(FMLHSMARKER, "Accepted client connection mod list"); } - private void handleRegistryMessage(final FMLHandshakeMessages.S2CRegistry registryPacket, final Supplier contextSupplier){ + void handleRegistryMessage(final FMLHandshakeMessages.S2CRegistry registryPacket, final Supplier contextSupplier){ LOGGER.debug(FMLHSMARKER,"Received registry packet for {}", registryPacket.getRegistryName()); this.registriesToReceive.remove(registryPacket.getRegistryName()); this.registrySnapshots.put(registryPacket.getRegistryName(), registryPacket.getSnapshot()); contextSupplier.get().setPacketHandled(true); - channel.reply(new FMLHandshakeMessages.C2SAcknowledge(), contextSupplier.get()); + FMLNetworkConstants.handshakeChannel.reply(new FMLHandshakeMessages.C2SAcknowledge(), contextSupplier.get()); if (this.registriesToReceive.isEmpty()) { //TODO: @cpw injectSnapshot Needs to be on the world thread. And maybe block the network/login so we don't get world data before we finish? @@ -253,16 +179,16 @@ public class FMLHandshakeHandler { } } - private void handleClientAck(final FMLHandshakeMessages.C2SAcknowledge msg, final Supplier contextSupplier) { + void handleClientAck(final FMLHandshakeMessages.C2SAcknowledge msg, final Supplier contextSupplier) { LOGGER.debug(FMLHSMARKER, "Received acknowledgement from client"); contextSupplier.get().setPacketHandled(true); } - private void handleConfigSync(final FMLHandshakeMessages.S2CConfigData msg, final Supplier contextSupplier) { + void handleConfigSync(final FMLHandshakeMessages.S2CConfigData msg, final Supplier contextSupplier) { LOGGER.debug(FMLHSMARKER, "Received config sync from server"); ConfigTracker.INSTANCE.receiveSyncedConfig(msg, contextSupplier); contextSupplier.get().setPacketHandled(true); - channel.reply(new FMLHandshakeMessages.C2SAcknowledge(), contextSupplier.get()); + FMLNetworkConstants.handshakeChannel.reply(new FMLHandshakeMessages.C2SAcknowledge(), contextSupplier.get()); } /** * FML will send packets, from Server to Client, from the messages queue until the queue is drained. Each message @@ -289,7 +215,7 @@ public class FMLHandshakeHandler { // we're done when sentMessages is empty if (sentMessages.isEmpty() && packetPosition >= messageList.size()-1) { // clear ourselves - we're done! - this.manager.channel().attr(FML_HANDSHAKE_HANDLER_ATTRIBUTE_KEY).set(null); + this.manager.channel().attr(FMLNetworkConstants.FML_HANDSHAKE_HANDLER).set(null); LOGGER.debug(FMLHSMARKER, "Handshake complete!"); return true; } diff --git a/src/main/java/net/minecraftforge/fml/network/FMLHandshakeMessages.java b/src/main/java/net/minecraftforge/fml/network/FMLHandshakeMessages.java index de4cc93fc0..373df14f61 100644 --- a/src/main/java/net/minecraftforge/fml/network/FMLHandshakeMessages.java +++ b/src/main/java/net/minecraftforge/fml/network/FMLHandshakeMessages.java @@ -21,7 +21,6 @@ package net.minecraftforge.fml.network; import net.minecraft.network.PacketBuffer; import net.minecraft.util.ResourceLocation; -import net.minecraftforge.common.util.HexDumper; import net.minecraftforge.fml.ModList; import net.minecraftforge.fml.loading.moddiscovery.ModInfo; import net.minecraftforge.registries.ForgeRegistry; diff --git a/src/main/java/net/minecraftforge/fml/network/FMLLoginWrapper.java b/src/main/java/net/minecraftforge/fml/network/FMLLoginWrapper.java index d282839d29..682c10e70c 100644 --- a/src/main/java/net/minecraftforge/fml/network/FMLLoginWrapper.java +++ b/src/main/java/net/minecraftforge/fml/network/FMLLoginWrapper.java @@ -49,7 +49,7 @@ public class FMLLoginWrapper { private void wrapperReceived(final T packet) { final NetworkEvent.Context wrappedContext = packet.getSource().get(); final PacketBuffer payload = packet.getPayload(); - ResourceLocation targetNetworkReceiver = FMLHandshakeHandler.FML_HANDSHAKE_RESOURCE; + ResourceLocation targetNetworkReceiver = FMLNetworkConstants.FML_HANDSHAKE_RESOURCE; PacketBuffer data = null; if (payload != null) { targetNetworkReceiver = payload.readResourceLocation(); diff --git a/src/main/java/net/minecraftforge/fml/network/FMLNetworkConstants.java b/src/main/java/net/minecraftforge/fml/network/FMLNetworkConstants.java index 9c02758d2d..0c2dbe298e 100644 --- a/src/main/java/net/minecraftforge/fml/network/FMLNetworkConstants.java +++ b/src/main/java/net/minecraftforge/fml/network/FMLNetworkConstants.java @@ -20,6 +20,8 @@ package net.minecraftforge.fml.network; import io.netty.util.AttributeKey; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.fml.network.simple.SimpleChannel; import org.apache.logging.log4j.Marker; import org.apache.logging.log4j.MarkerManager; @@ -32,6 +34,12 @@ public class FMLNetworkConstants public static final int FMLNETVERSION = 2; public static final String NETVERSION = FMLNETMARKER + FMLNETVERSION; public static final String NOVERSION = "NONE"; + static final Marker NETWORK = MarkerManager.getMarker("FMLNETWORK"); - static final AttributeKey FML_MARKER = AttributeKey.valueOf("fml:marker"); + static final AttributeKey FML_NETVERSION = AttributeKey.valueOf("fml:netversion"); + static final AttributeKey FML_HANDSHAKE_HANDLER = AttributeKey.valueOf("fml:handshake"); + static final ResourceLocation FML_HANDSHAKE_RESOURCE = new ResourceLocation("fml:handshake"); + static final ResourceLocation FML_PLAY_RESOURCE = new ResourceLocation("fml:play"); + static final SimpleChannel handshakeChannel = NetworkInitialization.getHandshakeChannel(); + static final SimpleChannel playChannel = NetworkInitialization.getPlayChannel(); } diff --git a/src/main/java/net/minecraftforge/fml/network/FMLPlayHandler.java b/src/main/java/net/minecraftforge/fml/network/FMLPlayHandler.java deleted file mode 100644 index 052f03e1ff..0000000000 --- a/src/main/java/net/minecraftforge/fml/network/FMLPlayHandler.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Minecraft Forge - * Copyright (c) 2016-2019. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation version 2.1 - * of the License. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -package net.minecraftforge.fml.network; - -import net.minecraft.util.ResourceLocation; -import net.minecraftforge.fml.network.simple.SimpleChannel; - -public class FMLPlayHandler -{ - public static final SimpleChannel channel = NetworkRegistry.ChannelBuilder - .named(new ResourceLocation("fml", "play")) - .clientAcceptedVersions(a -> true) - .serverAcceptedVersions(a -> true) - .networkProtocolVersion(() -> FMLNetworkConstants.NETVERSION) - .simpleChannel(); - static - { - channel.registerMessage(0, FMLPlayMessages.SpawnEntity.class, FMLPlayMessages.SpawnEntity::encode, FMLPlayMessages.SpawnEntity::decode, FMLPlayMessages.SpawnEntity::handle); - channel.registerMessage(1, FMLPlayMessages.OpenContainer.class, FMLPlayMessages.OpenContainer::encode, FMLPlayMessages.OpenContainer::decode, FMLPlayMessages.OpenContainer::handle); - } -} diff --git a/src/main/java/net/minecraftforge/fml/network/NetworkHooks.java b/src/main/java/net/minecraftforge/fml/network/NetworkHooks.java index f76e9e812d..4d9f27aaf6 100644 --- a/src/main/java/net/minecraftforge/fml/network/NetworkHooks.java +++ b/src/main/java/net/minecraftforge/fml/network/NetworkHooks.java @@ -52,14 +52,14 @@ public class NetworkHooks public static ConnectionType getConnectionType(final Supplier connection) { - return ConnectionType.forVersionFlag(connection.get().channel().attr(FMLNetworkConstants.FML_MARKER).get()); + return ConnectionType.forVersionFlag(connection.get().channel().attr(FMLNetworkConstants.FML_NETVERSION).get()); } public static Packet getEntitySpawningPacket(Entity entity) { if (!entity.getType().usesVanillaSpawning()) { - return FMLPlayHandler.channel.toVanillaPacket(new FMLPlayMessages.SpawnEntity(entity), NetworkDirection.PLAY_TO_CLIENT); + return FMLNetworkConstants.playChannel.toVanillaPacket(new FMLPlayMessages.SpawnEntity(entity), NetworkDirection.PLAY_TO_CLIENT); } return null; } @@ -71,14 +71,14 @@ public class NetworkHooks public static void registerServerLoginChannel(NetworkManager manager, CPacketHandshake packet) { - manager.channel().attr(FMLNetworkConstants.FML_MARKER).set(packet.getFMLVersion()); + manager.channel().attr(FMLNetworkConstants.FML_NETVERSION).set(packet.getFMLVersion()); FMLHandshakeHandler.registerHandshake(manager, NetworkDirection.LOGIN_TO_CLIENT); } public static void registerClientLoginChannel(NetworkManager manager) { if (manager == null || manager.channel() == null) return; - manager.channel().attr(FMLNetworkConstants.FML_MARKER).set(FMLNetworkConstants.NOVERSION); + manager.channel().attr(FMLNetworkConstants.FML_NETVERSION).set(FMLNetworkConstants.NOVERSION); FMLHandshakeHandler.registerHandshake(manager, NetworkDirection.LOGIN_TO_SERVER); } @@ -167,7 +167,7 @@ public class NetworkHooks throw new IllegalArgumentException("Invalid PacketBuffer for openGui, found "+ output.readableBytes()+ " bytes"); } FMLPlayMessages.OpenContainer msg = new FMLPlayMessages.OpenContainer(id, openContainerId, output); - FMLPlayHandler.channel.sendTo(msg, player.connection.getNetworkManager(), NetworkDirection.PLAY_TO_CLIENT); + FMLNetworkConstants.playChannel.sendTo(msg, player.connection.getNetworkManager(), NetworkDirection.PLAY_TO_CLIENT); Container c = containerSupplier.createContainer(player.inventory, player); player.openContainer = c; diff --git a/src/main/java/net/minecraftforge/fml/network/NetworkInitialization.java b/src/main/java/net/minecraftforge/fml/network/NetworkInitialization.java new file mode 100644 index 0000000000..b9d7c9000c --- /dev/null +++ b/src/main/java/net/minecraftforge/fml/network/NetworkInitialization.java @@ -0,0 +1,139 @@ +/* + * Minecraft Forge + * Copyright (c) 2016-2019. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package net.minecraftforge.fml.network; + +import net.minecraftforge.fml.config.ConfigTracker; +import net.minecraftforge.fml.network.simple.SimpleChannel; +import net.minecraftforge.fml.util.ThreeConsumer; +import net.minecraftforge.registries.RegistryManager; + +import java.util.function.BiConsumer; +import java.util.function.Supplier; + +class NetworkInitialization { + + public static SimpleChannel getHandshakeChannel() { + SimpleChannel handshakeChannel = NetworkRegistry.ChannelBuilder. + named(FMLNetworkConstants.FML_HANDSHAKE_RESOURCE). + clientAcceptedVersions(a -> true). + serverAcceptedVersions(a -> true). + networkProtocolVersion(() -> FMLNetworkConstants.NETVERSION). + simpleChannel(); + + handshakeChannel.messageBuilder(FMLHandshakeMessages.C2SAcknowledge.class, 99). + loginIndex(FMLHandshakeMessages.LoginIndexedMessage::getLoginIndex, FMLHandshakeMessages.LoginIndexedMessage::setLoginIndex). + decoder(FMLHandshakeMessages.C2SAcknowledge::decode). + encoder(FMLHandshakeMessages.C2SAcknowledge::encode). + consumer(indexFirst(FMLHandshakeHandler::handleClientAck)). + add(); + + handshakeChannel.messageBuilder(FMLHandshakeMessages.S2CModList.class, 1). + loginIndex(FMLHandshakeMessages.LoginIndexedMessage::getLoginIndex, FMLHandshakeMessages.LoginIndexedMessage::setLoginIndex). + decoder(FMLHandshakeMessages.S2CModList::decode). + encoder(FMLHandshakeMessages.S2CModList::encode). + markAsLoginPacket(). + consumer(biConsumerFor(FMLHandshakeHandler::handleServerModListOnClient)). + add(); + + handshakeChannel.messageBuilder(FMLHandshakeMessages.C2SModListReply.class, 2). + loginIndex(FMLHandshakeMessages.LoginIndexedMessage::getLoginIndex, FMLHandshakeMessages.LoginIndexedMessage::setLoginIndex). + decoder(FMLHandshakeMessages.C2SModListReply::decode). + encoder(FMLHandshakeMessages.C2SModListReply::encode). + consumer(indexFirst(FMLHandshakeHandler::handleClientModListOnServer)). + add(); + + handshakeChannel.messageBuilder(FMLHandshakeMessages.S2CRegistry.class, 3). + loginIndex(FMLHandshakeMessages.LoginIndexedMessage::getLoginIndex, FMLHandshakeMessages.LoginIndexedMessage::setLoginIndex). + decoder(FMLHandshakeMessages.S2CRegistry::decode). + encoder(FMLHandshakeMessages.S2CRegistry::encode). + buildLoginPacketList(RegistryManager::generateRegistryPackets). //TODO: Make this non-static, and store a cache on the client. + consumer(biConsumerFor(FMLHandshakeHandler::handleRegistryMessage)). + add(); + + handshakeChannel.messageBuilder(FMLHandshakeMessages.S2CConfigData.class, 4). + loginIndex(FMLHandshakeMessages.LoginIndexedMessage::getLoginIndex, FMLHandshakeMessages.LoginIndexedMessage::setLoginIndex). + decoder(FMLHandshakeMessages.S2CConfigData::decode). + encoder(FMLHandshakeMessages.S2CConfigData::encode). + buildLoginPacketList(ConfigTracker.INSTANCE::syncConfigs). + consumer(biConsumerFor(FMLHandshakeHandler::handleConfigSync)). + add(); + + return handshakeChannel; + } + + public static SimpleChannel getPlayChannel() { + SimpleChannel playChannel = NetworkRegistry.ChannelBuilder + .named(FMLNetworkConstants.FML_PLAY_RESOURCE) + .clientAcceptedVersions(a -> true) + .serverAcceptedVersions(a -> true) + .networkProtocolVersion(() -> FMLNetworkConstants.NETVERSION) + .simpleChannel(); + + playChannel.messageBuilder(FMLPlayMessages.SpawnEntity.class, 0). + decoder(FMLPlayMessages.SpawnEntity::decode). + encoder(FMLPlayMessages.SpawnEntity::encode). + consumer(FMLPlayMessages.SpawnEntity::handle). + add(); + + playChannel.messageBuilder(FMLPlayMessages.OpenContainer.class,1). + decoder(FMLPlayMessages.OpenContainer::decode). + encoder(FMLPlayMessages.OpenContainer::encode). + consumer(FMLPlayMessages.OpenContainer::handle). + add(); + + return playChannel; + } + + + /** + * Transforms a two-argument instance method reference into a {@link BiConsumer} based on the {@link #getHandshake(Supplier)} function. + * + * @param consumer A two argument instance method reference + * @param message type + * @return A {@link BiConsumer} for use in message handling + */ + private static BiConsumer> biConsumerFor(ThreeConsumer> consumer) + { + return (m, c) -> ThreeConsumer.bindArgs(consumer, m, c).accept(getHandshake(c)); + } + + /** + * Transforms a two-argument instance method reference into a {@link BiConsumer} {@link #biConsumerFor(ThreeConsumer)}, first calling the {@link #handleIndexedMessage(FMLHandshakeMessages.LoginIndexedMessage, Supplier)} + * method to handle index tracking. Used for client to server replies. + * @param next The method reference to call after index handling + * @param message type + * @return A {@link BiConsumer} for use in message handling + */ + private static BiConsumer> indexFirst(ThreeConsumer> next) + { + final BiConsumer> loginIndexedMessageSupplierBiConsumer = biConsumerFor(FMLHandshakeHandler::handleIndexedMessage); + return loginIndexedMessageSupplierBiConsumer.andThen(biConsumerFor(next)); + } + + /** + * Retrieve the handshake from the {@link NetworkEvent.Context} + * + * @param contextSupplier the {@link NetworkEvent.Context} + * @return The handshake handler for the connection + */ + private static FMLHandshakeHandler getHandshake(Supplier contextSupplier) { + return contextSupplier.get().attr(FMLNetworkConstants.FML_HANDSHAKE_HANDLER).get(); + } +}