Skip to content

Commit 8990d83

Browse files
authored
Implement preconditions check on connecting (#9)
1 parent 2339093 commit 8990d83

19 files changed

+608
-77
lines changed

CS2M.API/Networking/Player.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ protected set
2424
}
2525
}
2626

27-
private PlayerType _playerType;
27+
private PlayerType _playerType = PlayerType.NONE;
2828
public PlayerType PlayerType
2929
{
3030
get => _playerType;

CS2M.API/Networking/PlayerStatus.cs

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ public enum PlayerStatus
1717
GET_SERVER_INFO,
1818

1919
/// <summary>
20-
/// The client is trying to connect NAT punchthrough to coonect to the server
20+
/// The client is trying to connect through NAT hole punching to the server
2121
/// </summary>
2222
NAT_CONNECT,
2323

@@ -26,6 +26,16 @@ public enum PlayerStatus
2626
/// </summary>
2727
DIRECT_CONNECT,
2828

29+
/// <summary>
30+
/// The client connected on network level, but has not joined the game
31+
/// </summary>
32+
CONNECTION_ESTABLISHED,
33+
34+
/// <summary>
35+
/// The client fulfilled all preconditions and is waiting to join the game
36+
/// </summary>
37+
WAITING_TO_JOIN,
38+
2939
/// <summary>
3040
/// The player is connected and downloading the map/save from
3141
/// the server
@@ -45,8 +55,8 @@ public enum PlayerStatus
4555
PLAYING,
4656

4757
/// <summary>
48-
/// The player is blocked from interacting with the game
58+
/// The players game is blocked, because a new player is joining or a resync is in progress
4959
/// </summary>
50-
BLOCKED
60+
BLOCKED,
5161
}
5262
}

CS2M.API/Networking/PlayerType.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
{
33
public enum PlayerType
44
{
5+
NONE,
56
CLIENT,
67
SERVER,
78
}

CS2M/Commands/CommandInternal.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,11 @@ public byte[] Serialize(CommandBase command)
125125
return MessagePackSerializer.Serialize(command, _model);
126126
}
127127

128+
public CommandBase Deserialize(byte[] bytes)
129+
{
130+
return MessagePackSerializer.Deserialize<CommandBase>(bytes, _model);
131+
}
132+
128133
public void RefreshModel()
129134
{
130135
_cmdMapping.Clear();
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
namespace CS2M.Commands.Data.Internal
2+
{
3+
public class PreconditionsCheckCommand : PreconditionsDataCommand
4+
{
5+
/// <summary>
6+
/// The username this user will be playing as, important
7+
/// as the server will keep track of this user.
8+
/// </summary>
9+
public string Username { get; set; }
10+
11+
/// <summary>
12+
/// An optional password if the server is set up to
13+
/// require a password.
14+
/// </summary>
15+
public string Password { get; set; }
16+
}
17+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
using System.Collections.Generic;
2+
using CS2M.API.Commands;
3+
4+
namespace CS2M.Commands.Data.Internal
5+
{
6+
public abstract class PreconditionsDataCommand : CommandBase
7+
{
8+
/// <summary>
9+
/// What version of the mod the sender has installed.
10+
/// </summary>
11+
public System.Version ModVersion { get; set; }
12+
13+
/// <summary>
14+
/// What version of the game the sender is running.
15+
/// </summary>
16+
public Colossal.Version GameVersion { get; set; }
17+
18+
/// <summary>
19+
/// A list of mods with multiplayer support that were loaded.
20+
/// </summary>
21+
public List<string> Mods { get; set; }
22+
23+
/// <summary>
24+
/// A list of DLCs that were loaded.
25+
/// </summary>
26+
public List<int> DlcIds { get; set; }
27+
}
28+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
using CS2M.Util;
2+
3+
namespace CS2M.Commands.Data.Internal
4+
{
5+
public class PreconditionsErrorCommand : PreconditionsDataCommand
6+
{
7+
/// <summary>
8+
/// A bitfield of errors from preconditions checking (can be multiple)
9+
/// </summary>
10+
public PreconditionsUtil.Errors Errors { get; set; }
11+
}
12+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
using CS2M.API.Commands;
2+
3+
namespace CS2M.Commands.Data.Internal
4+
{
5+
public class PreconditionsSuccessCommand : CommandBase
6+
{
7+
}
8+
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
using System.Collections.Generic;
2+
using System.Linq;
3+
using CS2M.API.Commands;
4+
using CS2M.API.Networking;
5+
using CS2M.Commands.Data.Internal;
6+
using CS2M.Mods;
7+
using CS2M.Networking;
8+
using CS2M.Util;
9+
using LiteNetLib;
10+
11+
namespace CS2M.Commands.Handler.Internal
12+
{
13+
public class PreconditionsCheckHandler : CommandHandler<PreconditionsCheckCommand>
14+
{
15+
public PreconditionsCheckHandler()
16+
{
17+
TransactionCmd = false;
18+
}
19+
20+
protected override void Handle(PreconditionsCheckCommand command)
21+
{
22+
}
23+
24+
public void HandleOnServer(PreconditionsCheckCommand command, NetPeer peer)
25+
{
26+
Log.Debug($"Received Preconditions Check [PeerId: {peer.Id}]");
27+
28+
PreconditionsUtil.Result result = PreconditionsUtil.CheckPreconditions(command);
29+
30+
// Check the client username to see if anyone on the server already have a username
31+
if (NetworkInterface.Instance.PlayerListConnected.Any(p => p.Username.Equals(command.Username)))
32+
{
33+
Log.Debug($"[Preconditions Check] Username '{command.Username}' is already connected.");
34+
result.Errors |= PreconditionsUtil.Errors.USERNAME_NOT_AVAILABLE;
35+
}
36+
37+
// Check the password to see if it matches (only if the server has provided a password).
38+
if (!string.IsNullOrEmpty(NetworkInterface.Instance.LocalPlayer.GetConnectionPassword()))
39+
{
40+
if (!NetworkInterface.Instance.LocalPlayer.GetConnectionPassword().Equals(command.Password))
41+
{
42+
Log.Debug($"[Preconditions Check] Password '{command.Password}' is not correct.");
43+
result.Errors |= PreconditionsUtil.Errors.PASSWORD_INCORRECT;
44+
}
45+
}
46+
47+
if (result.Errors == PreconditionsUtil.Errors.NONE)
48+
{
49+
NetworkInterface.Instance.LocalPlayer.SendToClient(peer, new PreconditionsSuccessCommand());
50+
51+
// Add the new player as a connected player
52+
NetworkInterface.Instance.PlayerConnected(new RemotePlayer(peer, command.Username, PlayerType.CLIENT));
53+
}
54+
else
55+
{
56+
NetworkInterface.Instance.LocalPlayer.SendToClient(peer, new PreconditionsErrorCommand()
57+
{
58+
Errors = result.Errors,
59+
ModVersion = VersionUtil.GetModVersion(),
60+
GameVersion = VersionUtil.GetGameVersion(),
61+
Mods = ModSupport.Instance.RequiredModsForSync,
62+
DlcIds = new List<int>(), //TODO: Update with correct DLC List
63+
});
64+
}
65+
}
66+
}
67+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
using CS2M.API.Commands;
2+
using CS2M.Commands.Data.Internal;
3+
using CS2M.Networking;
4+
5+
namespace CS2M.Commands.Handler.Internal
6+
{
7+
public class PreconditionsErrorHandler : CommandHandler<PreconditionsErrorCommand>
8+
{
9+
public PreconditionsErrorHandler()
10+
{
11+
TransactionCmd = false;
12+
}
13+
14+
protected override void Handle(PreconditionsErrorCommand command)
15+
{
16+
Log.Debug($"[Preconditions Error] {command.Errors.ToString()}");
17+
18+
NetworkInterface.Instance.LocalPlayer.Inactive();
19+
}
20+
}
21+
}

0 commit comments

Comments
 (0)