New login process + a little bit of cleanup
No reliability required :) Will get to the client soon
This commit is contained in:
@@ -114,10 +114,7 @@ namespace Barotrauma.Networking
|
||||
client = new NetClient(config);
|
||||
netPeer = client;
|
||||
client.Start();
|
||||
|
||||
NetOutgoingMessage outmsg = client.CreateMessage();
|
||||
|
||||
|
||||
|
||||
System.Net.IPEndPoint IPEndPoint = null;
|
||||
try
|
||||
{
|
||||
@@ -133,8 +130,7 @@ namespace Barotrauma.Networking
|
||||
// Connect client, to ip previously requested from user
|
||||
try
|
||||
{
|
||||
client.Connect(IPEndPoint, outmsg);
|
||||
|
||||
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -446,11 +442,6 @@ namespace Barotrauma.Networking
|
||||
|
||||
public bool SpectateClicked(GUIButton button, object userData)
|
||||
{
|
||||
NetOutgoingMessage msg = client.CreateMessage();
|
||||
|
||||
|
||||
client.SendMessage(msg, NetDeliveryMethod.ReliableUnordered);
|
||||
|
||||
if (button != null) button.Enabled = false;
|
||||
|
||||
return false;
|
||||
|
||||
@@ -28,6 +28,8 @@ namespace Barotrauma.Networking
|
||||
private NetServer server;
|
||||
private NetPeerConfiguration config;
|
||||
|
||||
private int MaxPlayers;
|
||||
|
||||
private DateTime sparseUpdateTimer;
|
||||
private DateTime refreshMasterTimer;
|
||||
|
||||
@@ -80,6 +82,7 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
|
||||
config.MaximumConnections = maxPlayers;
|
||||
MaxPlayers = maxPlayers;
|
||||
|
||||
config.DisableMessageType(NetIncomingMessageType.DebugMessage |
|
||||
NetIncomingMessageType.WarningMessage | NetIncomingMessageType.Receipt |
|
||||
@@ -444,47 +447,57 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
|
||||
sparseUpdateTimer = DateTime.Now + sparseUpdateInterval;
|
||||
}
|
||||
|
||||
public bool StartGameClicked(GUIButton button, object obj)
|
||||
}
|
||||
|
||||
private byte GetNewClientID()
|
||||
{
|
||||
Submarine selectedSub = null;
|
||||
Submarine selectedShuttle = GameMain.NetLobbyScreen.SelectedShuttle;
|
||||
|
||||
if (Voting.AllowSubVoting)
|
||||
{
|
||||
selectedSub = Voting.HighestVoted<Submarine>(VoteType.Sub, connectedClients);
|
||||
if (selectedSub == null) selectedSub = GameMain.NetLobbyScreen.SelectedSub;
|
||||
byte userID = 1;
|
||||
while (connectedClients.Any(c => c.ID == userID))
|
||||
{
|
||||
userID++;
|
||||
}
|
||||
else
|
||||
{
|
||||
selectedSub = GameMain.NetLobbyScreen.SelectedSub;
|
||||
}
|
||||
|
||||
if (selectedSub == null)
|
||||
{
|
||||
GameMain.NetLobbyScreen.SubList.Flash();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (selectedShuttle == null)
|
||||
{
|
||||
GameMain.NetLobbyScreen.ShuttleList.Flash();
|
||||
return false;
|
||||
}
|
||||
|
||||
GameModePreset selectedMode = Voting.HighestVoted<GameModePreset>(VoteType.Mode, connectedClients);
|
||||
if (selectedMode == null) selectedMode = GameMain.NetLobbyScreen.SelectedMode;
|
||||
|
||||
if (selectedMode == null)
|
||||
{
|
||||
GameMain.NetLobbyScreen.ModeList.Flash();
|
||||
return false;
|
||||
}
|
||||
|
||||
//CoroutineManager.StartCoroutine(WaitForPlayersReady(selectedSub, selectedShuttle, selectedMode), "WaitForPlayersReady");
|
||||
|
||||
return true;
|
||||
return userID;
|
||||
}
|
||||
|
||||
public bool StartGameClicked(GUIButton button, object obj)
|
||||
{
|
||||
Submarine selectedSub = null;
|
||||
Submarine selectedShuttle = GameMain.NetLobbyScreen.SelectedShuttle;
|
||||
|
||||
if (Voting.AllowSubVoting)
|
||||
{
|
||||
selectedSub = Voting.HighestVoted<Submarine>(VoteType.Sub, connectedClients);
|
||||
if (selectedSub == null) selectedSub = GameMain.NetLobbyScreen.SelectedSub;
|
||||
}
|
||||
else
|
||||
{
|
||||
selectedSub = GameMain.NetLobbyScreen.SelectedSub;
|
||||
}
|
||||
|
||||
if (selectedSub == null)
|
||||
{
|
||||
GameMain.NetLobbyScreen.SubList.Flash();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (selectedShuttle == null)
|
||||
{
|
||||
GameMain.NetLobbyScreen.ShuttleList.Flash();
|
||||
return false;
|
||||
}
|
||||
|
||||
GameModePreset selectedMode = Voting.HighestVoted<GameModePreset>(VoteType.Mode, connectedClients);
|
||||
if (selectedMode == null) selectedMode = GameMain.NetLobbyScreen.SelectedMode;
|
||||
|
||||
if (selectedMode == null)
|
||||
{
|
||||
GameMain.NetLobbyScreen.ModeList.Flash();
|
||||
return false;
|
||||
}
|
||||
|
||||
//CoroutineManager.StartCoroutine(WaitForPlayersReady(selectedSub, selectedShuttle, selectedMode), "WaitForPlayersReady");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void EndGame()
|
||||
@@ -528,29 +541,29 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
|
||||
CoroutineManager.StartCoroutine(EndCinematic());
|
||||
}
|
||||
|
||||
public IEnumerable<object> EndCinematic()
|
||||
{
|
||||
float endPreviewLength = 10.0f;
|
||||
|
||||
var cinematic = new TransitionCinematic(Submarine.MainSub, GameMain.GameScreen.Cam, endPreviewLength);
|
||||
|
||||
float secondsLeft = endPreviewLength;
|
||||
|
||||
do
|
||||
{
|
||||
secondsLeft -= CoroutineManager.UnscaledDeltaTime;
|
||||
|
||||
yield return CoroutineStatus.Running;
|
||||
} while (secondsLeft > 0.0f);
|
||||
|
||||
Submarine.Unload();
|
||||
|
||||
GameMain.NetLobbyScreen.Select();
|
||||
|
||||
yield return CoroutineStatus.Success;
|
||||
CoroutineManager.StartCoroutine(EndCinematic());
|
||||
}
|
||||
|
||||
public IEnumerable<object> EndCinematic()
|
||||
{
|
||||
float endPreviewLength = 10.0f;
|
||||
|
||||
var cinematic = new TransitionCinematic(Submarine.MainSub, GameMain.GameScreen.Cam, endPreviewLength);
|
||||
|
||||
float secondsLeft = endPreviewLength;
|
||||
|
||||
do
|
||||
{
|
||||
secondsLeft -= CoroutineManager.UnscaledDeltaTime;
|
||||
|
||||
yield return CoroutineStatus.Running;
|
||||
} while (secondsLeft > 0.0f);
|
||||
|
||||
Submarine.Unload();
|
||||
|
||||
GameMain.NetLobbyScreen.Select();
|
||||
|
||||
yield return CoroutineStatus.Success;
|
||||
}
|
||||
|
||||
private void UpdateCrewFrame()
|
||||
|
||||
@@ -13,6 +13,8 @@ namespace Barotrauma.Networking
|
||||
public NetConnection Connection;
|
||||
public int Nonce;
|
||||
|
||||
public int failedAttempts;
|
||||
|
||||
public float AuthTimer;
|
||||
|
||||
public UnauthenticatedClient(NetConnection connection, int nonce)
|
||||
@@ -21,12 +23,172 @@ namespace Barotrauma.Networking
|
||||
Nonce = nonce;
|
||||
|
||||
AuthTimer = 5.0f;
|
||||
|
||||
failedAttempts = 0;
|
||||
}
|
||||
}
|
||||
|
||||
partial class GameServer : NetworkMember, IPropertyObject
|
||||
{
|
||||
List<UnauthenticatedClient> unauthenticatedClients = new List<UnauthenticatedClient>();
|
||||
|
||||
List<UnauthenticatedClient> unauthenticatedClients = new List<UnauthenticatedClient>();
|
||||
|
||||
private void ClientPasswordRequest(NetConnection conn)
|
||||
{
|
||||
//client wants to know if server requires password
|
||||
|
||||
if (ConnectedClients.Count > MaxPlayers)
|
||||
{
|
||||
//server is full, can't allow new connection
|
||||
conn.Disconnect("Server full");
|
||||
}
|
||||
|
||||
if (ConnectedClients.Find(c => c.Connection == conn) != null)
|
||||
{
|
||||
//this client has already been authenticated
|
||||
return;
|
||||
}
|
||||
UnauthenticatedClient unauthClient = unauthenticatedClients.Find(uc => uc.Connection == conn);
|
||||
if (unauthClient == null)
|
||||
{
|
||||
//new client, generate nonce and add to unauth queue
|
||||
int nonce = CryptoRandom.Instance.Next();
|
||||
unauthClient = new UnauthenticatedClient(conn, nonce);
|
||||
unauthenticatedClients.Add(unauthClient);
|
||||
}
|
||||
//if the client is already in the queue, getting another unauth request means that our response was lost; resend
|
||||
NetOutgoingMessage nonceMsg = server.CreateMessage();
|
||||
if (string.IsNullOrEmpty(password))
|
||||
{
|
||||
nonceMsg.Write(false); //false = no password
|
||||
}
|
||||
else
|
||||
{
|
||||
nonceMsg.Write(true); //true = password
|
||||
nonceMsg.Write(unauthClient.Nonce); //here's nonce, encrypt with this
|
||||
}
|
||||
server.SendMessage(nonceMsg, conn, NetDeliveryMethod.Unreliable);
|
||||
}
|
||||
|
||||
private void ClientInitialize(NetIncomingMessage inc)
|
||||
{
|
||||
if (ConnectedClients.Find(c => c.Connection == inc.SenderConnection) != null)
|
||||
{
|
||||
//this client was already authenticated
|
||||
//another init request means they didn't get any update packets yet
|
||||
return;
|
||||
}
|
||||
|
||||
UnauthenticatedClient unauthClient = unauthenticatedClients.Find(uc => uc.Connection == inc.SenderConnection);
|
||||
if (unauthClient == null)
|
||||
{
|
||||
//client did not ask for nonce first, can't authorize
|
||||
inc.SenderConnection.Disconnect("Client did not properly request authentication.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(password))
|
||||
{
|
||||
//decrypt message and compare password
|
||||
string saltedPw = password;
|
||||
saltedPw = saltedPw + Convert.ToString(unauthClient.Nonce);
|
||||
saltedPw = Encoding.UTF8.GetString(NetUtility.ComputeSHAHash(Encoding.UTF8.GetBytes(saltedPw)));
|
||||
NetEncryption algo = new NetXtea(server, saltedPw);
|
||||
inc.Decrypt(algo);
|
||||
string clPw = inc.ReadString();
|
||||
if (clPw != saltedPw)
|
||||
{
|
||||
unauthClient.failedAttempts++;
|
||||
if (unauthClient.failedAttempts > 3)
|
||||
{
|
||||
//disconnect after too many failed attempts
|
||||
unauthClient.Connection.Disconnect("Too many failed login attempts.");
|
||||
unauthenticatedClients.Remove(unauthClient);
|
||||
unauthClient = null;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
//not disconnecting the player here, because they'll still use the same connection and nonce if they try logging in again
|
||||
NetOutgoingMessage reject = server.CreateMessage();
|
||||
reject.Write((byte)ServerPacketHeader.AUTH_FAILURE);
|
||||
reject.Write("Wrong password!");
|
||||
server.SendMessage(reject, unauthClient.Connection, NetDeliveryMethod.Unreliable);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
string clVersion = inc.ReadString();
|
||||
string clPackageName = inc.ReadString();
|
||||
string clPackageHash = inc.ReadString();
|
||||
|
||||
if (clVersion != GameMain.Version.ToString())
|
||||
{
|
||||
inc.SenderConnection.Disconnect("Version " + GameMain.Version + " required to connect to the server (Your version: " + clVersion + ")");
|
||||
unauthenticatedClients.Remove(unauthClient);
|
||||
unauthClient = null;
|
||||
DebugConsole.NewMessage(name + " couldn't join the server (wrong game version)", Color.Red);
|
||||
return;
|
||||
}
|
||||
if (clPackageName != GameMain.SelectedPackage.Name)
|
||||
{
|
||||
inc.SenderConnection.Disconnect("Your content package (" + clPackageName + ") doesn't match the server's version (" + GameMain.SelectedPackage.Name + ")");
|
||||
unauthenticatedClients.Remove(unauthClient);
|
||||
unauthClient = null;
|
||||
DebugConsole.NewMessage(name + " couldn't join the server (wrong content package name)", Color.Red);
|
||||
return;
|
||||
}
|
||||
if (clPackageHash != GameMain.SelectedPackage.MD5hash.Hash)
|
||||
{
|
||||
unauthClient.Connection.Disconnect("Your content package (MD5: " + clPackageHash + ") doesn't match the server's version (MD5: " + GameMain.SelectedPackage.MD5hash.Hash + ")");
|
||||
unauthenticatedClients.Remove(unauthClient);
|
||||
unauthClient = null;
|
||||
DebugConsole.NewMessage(name + " couldn't join the server (wrong content package hash)", Color.Red);
|
||||
return;
|
||||
}
|
||||
|
||||
string clName = Client.SanitizeName(inc.ReadString());
|
||||
if (string.IsNullOrWhiteSpace(clName))
|
||||
{
|
||||
unauthClient.Connection.Disconnect("You need a name.");
|
||||
unauthenticatedClients.Remove(unauthClient);
|
||||
unauthClient = null;
|
||||
return;
|
||||
}
|
||||
if (!Client.IsValidName(name))
|
||||
{
|
||||
unauthClient.Connection.Disconnect("Your name contains illegal symbols.");
|
||||
unauthenticatedClients.Remove(unauthClient);
|
||||
unauthClient = null;
|
||||
return;
|
||||
}
|
||||
Client nameTaken = ConnectedClients.Find(c => c.name.ToLower() == clName.ToLower());
|
||||
if (nameTaken != null)
|
||||
{
|
||||
if (nameTaken.Connection.RemoteEndPoint.Address.ToString() == inc.SenderEndPoint.Address.ToString())
|
||||
{
|
||||
//both name and IP address match, replace this player's connection
|
||||
nameTaken.Connection.Disconnect("Your session was taken by a new connection on the same IP address.");
|
||||
nameTaken.Connection = unauthClient.Connection;
|
||||
unauthenticatedClients.Remove(unauthClient);
|
||||
unauthClient = null;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
//can't authorize this client
|
||||
unauthClient.Connection.Disconnect("That name is taken.");
|
||||
unauthenticatedClients.Remove(unauthClient);
|
||||
unauthClient = null;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//new client
|
||||
Client newClient = new Client(clName, GetNewClientID());
|
||||
newClient.Connection = unauthClient.Connection;
|
||||
unauthenticatedClients.Remove(unauthClient);
|
||||
unauthClient = null;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,23 @@ using Barotrauma.Items.Components;
|
||||
|
||||
namespace Barotrauma.Networking
|
||||
{
|
||||
enum ClientPacketHeader
|
||||
{
|
||||
REQUEST_AUTH, //ask the server if a password is needed, if so we'll get nonce for encryption
|
||||
REQUEST_INIT, //ask the server to give you initialization
|
||||
UPDATE_LOBBY, //update state in lobby
|
||||
UPDATE_INGAME_ALIVE, //update state ingame while alive (allow character input)
|
||||
UPDATE_INGAME_SPECTATING, //update state ingame while spectating/dead
|
||||
}
|
||||
enum ServerPacketHeader
|
||||
{
|
||||
AUTH_RESPONSE, //tell the player if they require a password to log in
|
||||
AUTH_FAILURE, //the server won't authorize player yet, however connection is still alive
|
||||
UPDATE_LOBBY, //update state in lobby (votes and chat messages)
|
||||
UPDATE_INGAME_ALIVE, //update state ingame while alive (character input and chat messages)
|
||||
UPDATE_INGAME_SPECTATING, //update state ingame while spectating/dead (chat messages)
|
||||
}
|
||||
|
||||
enum VoteType
|
||||
{
|
||||
Unknown,
|
||||
|
||||
Reference in New Issue
Block a user