package net.md_5.bungee.forge;
import java.util.Map;
import net.md_5.bungee.ServerConnector;
import net.md_5.bungee.UserConnection;
import net.md_5.bungee.protocol.packet.PluginMessage;
/**
* Handshake sequence manager for the Bungee - Forge Client (Upstream) link.
* Modelled after the Forge implementation. See
* https://github.com/MinecraftForge/FML/blob/master/src/main/java/cpw/mods/fml/common/network/handshake/FMLHandshakeClientState.java
*/
enum ForgeClientHandshakeState implements IForgeClientPacketHandler<ForgeClientHandshakeState>
{
/**
* Initiated at the start of a client handshake. This is a special case
* where we don't want to use a {@link PluginMessage}, we're just sending
* stuff out here.
*
* Transitions into the HELLO state upon completion.
*
* Requires: {@link UserConnection}.
*/
START
{
@Override
public ForgeClientHandshakeState handle(PluginMessage message, UserConnection con)
{
ForgeLogger.logClient( ForgeLogger.LogDirection.RECEIVED, this.name(), message );
con.unsafe().sendPacket( message );
con.getForgeClientHandler().setState( HELLO );
return HELLO;
}
@Override
public ForgeClientHandshakeState send(PluginMessage message, UserConnection con)
{
return HELLO;
}
},
/**
* Waiting to receive a client HELLO and the mod list. Upon receiving the
* mod list, return the mod list of the server.
*
* We will be stuck in this state if we don't have a forge client. This is
* OK.
*
* Transitions to the WAITINGCACK state upon completion.
*
* Requires:
* {@link PluginMessage}, {@link UserConnection}, {@link ServerConnector}
*/
HELLO
{
@Override
public ForgeClientHandshakeState handle(PluginMessage message, UserConnection con)
{
ForgeLogger.logClient( ForgeLogger.LogDirection.RECEIVED, this.name(), message );
// Server Hello.
if ( message.getData()[0] == 0 )
{
con.unsafe().sendPacket( message );
}
return this;
}
@Override
public ForgeClientHandshakeState send(PluginMessage message, UserConnection con)
{
// Client Hello.
if ( message.getData()[0] == 1 )
{
return this;
}
// Mod list.
if ( message.getData()[0] == 2 )
{
if ( con.getForgeClientHandler().getClientModList() == null )
{
// This is the first Forge connection - so get the mods now.
// Once we've done it, no point doing it again.
Map<String, String> clientModList = ForgeUtils.readModList( message );
con.getForgeClientHandler().setClientModList( clientModList );
}
return WAITINGSERVERDATA;
}
return this;
}
},
WAITINGSERVERDATA
{
@Override
public ForgeClientHandshakeState handle(PluginMessage message, UserConnection con)
{
ForgeLogger.logClient( ForgeLogger.LogDirection.RECEIVED, this.name(), message );
// Mod list.
if ( message.getData()[0] == 2 )
{
con.unsafe().sendPacket( message );
}
return this;
}
@Override
public ForgeClientHandshakeState send(PluginMessage message, UserConnection con)
{
// ACK
return WAITINGSERVERCOMPLETE;
}
},
WAITINGSERVERCOMPLETE
{
@Override
public ForgeClientHandshakeState handle(PluginMessage message, UserConnection con)
{
ForgeLogger.logClient( ForgeLogger.LogDirection.RECEIVED, this.name(), message );
// Mod ID's.
if ( message.getData()[0] == 3 )
{
con.unsafe().sendPacket( message );
return this;
}
con.unsafe().sendPacket( message ); // pass everything else
return this;
}
@Override
public ForgeClientHandshakeState send(PluginMessage message, UserConnection con)
{
// Send ACK.
return PENDINGCOMPLETE;
}
},
PENDINGCOMPLETE
{
@Override
public ForgeClientHandshakeState handle(PluginMessage message, UserConnection con)
{
// Ack.
if ( message.getData()[0] == -1 )
{
ForgeLogger.logClient( ForgeLogger.LogDirection.RECEIVED, this.name(), message );
con.unsafe().sendPacket( message );
}
return this;
}
@Override
public ForgeClientHandshakeState send(PluginMessage message, UserConnection con)
{
// Send an ACK
return COMPLETE;
}
},
COMPLETE
{
@Override
public ForgeClientHandshakeState handle(PluginMessage message, UserConnection con)
{
// Ack.
if ( message.getData()[0] == -1 )
{
ForgeLogger.logClient( ForgeLogger.LogDirection.RECEIVED, this.name(), message );
con.unsafe().sendPacket( message );
}
return this;
}
@Override
public ForgeClientHandshakeState send(PluginMessage message, UserConnection con)
{
return DONE;
}
},
/**
* Handshake has been completed. Ignores any future handshake packets.
*/
DONE
{
@Override
public ForgeClientHandshakeState handle(PluginMessage message, UserConnection con)
{
ForgeLogger.logClient( ForgeLogger.LogDirection.RECEIVED, this.name(), message );
return this;
}
@Override
public ForgeClientHandshakeState send(PluginMessage message, UserConnection con)
{
return this;
}
}
}