package net.minecraftforge.fml.common.network.handshake; import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; import net.minecraftforge.fml.common.FMLLog; import net.minecraftforge.fml.common.Loader; import net.minecraftforge.fml.common.network.NetworkRegistry; import net.minecraftforge.fml.common.network.internal.FMLMessage; import net.minecraftforge.fml.common.network.internal.FMLNetworkHandler; import net.minecraftforge.fml.common.registry.GameData; import net.minecraftforge.fml.relauncher.Side; import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelHandlerContext; enum FMLHandshakeServerState implements IHandshakeState<FMLHandshakeServerState> { START { @Override public FMLHandshakeServerState accept(ChannelHandlerContext ctx, FMLHandshakeMessage msg) { NetworkDispatcher dispatcher = ctx.channel().attr(NetworkDispatcher.FML_DISPATCHER).get(); int overrideDim = dispatcher.serverInitiateHandshake(); ctx.writeAndFlush(FMLHandshakeMessage.makeCustomChannelRegistration(NetworkRegistry.INSTANCE.channelNamesFor(Side.SERVER))).addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE); ctx.writeAndFlush(new FMLHandshakeMessage.ServerHello(overrideDim)).addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE); return HELLO; } }, HELLO { @Override public FMLHandshakeServerState accept(ChannelHandlerContext ctx, FMLHandshakeMessage msg) { // Hello packet first if (msg instanceof FMLHandshakeMessage.ClientHello) { FMLLog.info("Client protocol version %x", ((FMLHandshakeMessage.ClientHello)msg).protocolVersion()); return this; } FMLHandshakeMessage.ModList client = (FMLHandshakeMessage.ModList)msg; NetworkDispatcher dispatcher = ctx.channel().attr(NetworkDispatcher.FML_DISPATCHER).get(); dispatcher.setModList(client.modList()); FMLLog.info("Client attempting to join with %d mods : %s", client.modListSize(), client.modListAsString()); String result = FMLNetworkHandler.checkModList(client, Side.CLIENT); if (result != null) { dispatcher.rejectHandshake(result); return ERROR; } ctx.writeAndFlush(new FMLHandshakeMessage.ModList(Loader.instance().getActiveModList())); return WAITINGCACK; } }, WAITINGCACK { @Override public FMLHandshakeServerState accept(ChannelHandlerContext ctx, FMLHandshakeMessage msg) { if (!ctx.channel().attr(NetworkDispatcher.IS_LOCAL).get()) { GameData.GameDataSnapshot snapshot = GameData.takeSnapshot(); Iterator<Map.Entry<String, GameData.GameDataSnapshot.Entry>> itr = snapshot.entries.entrySet().iterator(); while (itr.hasNext()) { Entry<String, GameData.GameDataSnapshot.Entry> e = itr.next(); ctx.writeAndFlush(new FMLHandshakeMessage.RegistryData(itr.hasNext(), e.getKey(), e.getValue())).addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE); } } ctx.writeAndFlush(new FMLHandshakeMessage.HandshakeAck(ordinal())).addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE); NetworkRegistry.INSTANCE.fireNetworkHandshake(ctx.channel().attr(NetworkDispatcher.FML_DISPATCHER).get(), Side.SERVER); return COMPLETE; } }, COMPLETE { @Override public FMLHandshakeServerState accept(ChannelHandlerContext ctx, FMLHandshakeMessage msg) { // Poke the client ctx.writeAndFlush(new FMLHandshakeMessage.HandshakeAck(ordinal())).addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE); FMLMessage.CompleteHandshake complete = new FMLMessage.CompleteHandshake(Side.SERVER); ctx.fireChannelRead(complete); return DONE; } }, DONE { @Override public FMLHandshakeServerState accept(ChannelHandlerContext ctx, FMLHandshakeMessage msg) { return this; } }, ERROR { @Override public FMLHandshakeServerState accept(ChannelHandlerContext ctx, FMLHandshakeMessage msg) { return this; } }; }