diff --git a/ConnectionMessage.cs b/ConnectionMessage.cs
index 9f397d6..3edf1d3 100644
--- a/ConnectionMessage.cs
+++ b/ConnectionMessage.cs
@@ -1,5 +1,5 @@
using System.Text.RegularExpressions;
-
+using System;
namespace Phi_MGUS
{
public static class ConnectionMessage
@@ -45,20 +45,50 @@ public class JoinServerSuccess : Message
}
///
- /// Room add failed message | 房间新建失败消息
+ /// Room new failed message | 房间新建失败消息
///
- public class AddRoomFailed : Message
+ public class NewRoomFailed : Message
{
- public new readonly string action = "addRoomFailed";
+ public new readonly string action = "newRoomFailed";
public string reason = "unknown";
}
///
- /// Room success message | 房间新建成功消息
+ /// Room new success message | 房间新建成功消息
+ ///
+ public class NewRoomSuccess : Message
+ {
+ public new readonly string action = "newRoomSuccess";
+ }
+ ///
+ /// Room join failed message | 房间加入成功消息
+ ///
+ public class JoinRoomFailed : Message
+ {
+ public new readonly string action = "joinRoomFaild";
+ public string reason = "unknown";
+ }
+ ///
+ /// Room join success message | 房间加入成功消息
+ ///
+ public class JoinRoomSuccess : Message
+ {
+ public new readonly string action = "joinRoomSuccess";
+ }
+ ///
+ /// Leave room failed message | 离开房间失败消息
///
- public class AddRoomSuccess : Message
+ public class LeaveRoomFailed : Message
{
- public new readonly string action = "addRoomSuccess";
+ public new readonly string action = "leaveRoomFailed";
+ public string reason = "unknown";
+ }
+ ///
+ /// Leave room success message | 离开房间成功消息
+ ///
+ public class LeaveRoomSuccess : Message
+ {
+ public new readonly string action = "leaveRoomSuccess";
}
}
@@ -107,7 +137,7 @@ public class NewRoom : Message
public Data data = new Data
{
//RoomID is a random string, length is 16 | 房间ID是随机字符串,长度为16
- roomID = Guid.NewGuid().ToString().Substring(0, 16)
+ roomID = Guid.NewGuid().ToString().Replace("-", "").Substring(0, 16)
};
public class Data
@@ -135,6 +165,25 @@ public string roomID
}// Only English or numbers can be used, and cannot exceed 32 digits | 只能使用英文或数字,且不超过32位
}
+ public NewRoom(int? maxUser = 8, string roomID = null)
+ {
+ if (roomID == null)
+ {
+ roomID = Guid.NewGuid().ToString().Replace("-", "").Substring(0, 16);
+ }
+ else
+ {
+ data.roomID = roomID;
+ }
+ if (maxUser == null)
+ {
+ maxUser = 8;
+ }
+ else
+ {
+ data.maxUser = maxUser.Value;
+ }
+ }
}
///
@@ -149,6 +198,11 @@ public class Data
{
public string roomID = "";
}
+
+ public JoinRoom(string roomID)
+ {
+ data.roomID = roomID;
+ }
}
///
/// Leave room | 离开房间
diff --git a/GameManager.cs b/GameManager.cs
index aba3d5c..b462013 100644
--- a/GameManager.cs
+++ b/GameManager.cs
@@ -10,22 +10,51 @@ public static class GameManager
///
public static class RoomManager
{
- private static readonly List roomList = new();
+ public static readonly List roomList = new();
public static void AddRoom(User user, string roomID)
{
roomList.Add(new Room(user, roomID));
+ user.userStatus = User.Status.InRoom;
}
- public static void RemoveRoom(Room instance)
+ ///
+ /// Dissolve the room | 解散房间
+ ///
+ /// 房间
+ public static void RemoveRoom(Room room)
+ {
+ for(var i = roomList.Count - 1; i >= 0; i--)
+ {
+ if(roomList[i] == room)
+ {
+ roomList.RemoveAt(i);
+ }
+ }
+ }
+ ///
+ /// Remove room by roomID | 根据房间ID删除房间
+ ///
+ /// 房间ID
+ public static void RemoveRoom(string roomID)
{
- for(int i = roomList.Count - 1; i >= 0; i--)
+ for(var i = roomList.Count - 1; i >= 0; i--)
{
- if(roomList[i] == instance)
+ if(roomList[i].roomID == roomID)
{
roomList.RemoveAt(i);
}
}
}
+
+ ///
+ /// Get room by roomID | 根据房间ID获取房间
+ ///
+ /// 房间ID
+ /// Room | 房间
+ public static Room? GetRoom(string roomID)
+ {
+ return roomList.FirstOrDefault(x => x.roomID == roomID);
+ }
}
///
@@ -48,7 +77,7 @@ public static void Drop(IWebSocketConnection socket)
///
/// Remove user | 移除用户
///
- ///
+ /// 用户对应Socket
public static void RemoveUser(IWebSocketConnection socket)
{
for(int i = userList.Count - 1; i >= 0; i--)
@@ -73,7 +102,6 @@ public static User GetUser(IWebSocketConnection socket)
{
return userList.First(x => x.userSocket == socket);
}
-
}
///
@@ -87,22 +115,24 @@ public class Room
///
/// Create room | 创建房间
///
- ///
- ///
+ /// 房间所有者
+ /// 房间ID
/// Illegal room ID | 非法房间ID
public Room(User owner, string roomID)
{
if (roomID.Length > 32)
{
- throw new ArgumentException("RoomIdentifier cannot exceed 32 digits.");
+ throw new ArgumentException("RoomIdentifier cannot exceed 32 digits."); // 房间ID长度不能超过32位
}
- if (!Regex.IsMatch(this.roomID, @"^[a-zA-Z0-9]+$"))
+ if (!Regex.IsMatch(roomID, @"^[a-zA-Z0-9]+$"))
{
- throw new ArgumentException("RoomIdentifier can only use pure English or numbers.");
+ throw new ArgumentException("RoomIdentifier can only use English or numbers.");// 房间ID只能使用英文或数字
}
this.owner = owner;
+ owner.userRoom = this;
this.roomID = roomID;
- userList = new List();
+ userList = new();
+ LogManager.WriteLog($"New room created: {roomID} by {owner.userName}");
}
///
/// User join room | 用户加入房间
@@ -111,6 +141,7 @@ public Room(User owner, string roomID)
public void Join(User user)
{
userList.Add(user);
+ user.userRoom = this;
}
///
/// User leave room | 用户离开房间
@@ -119,6 +150,11 @@ public void Join(User user)
public void Leave(User user)
{
userList.Remove(user);
+ if (userList.Count == 0)
+ {
+ RoomManager.RemoveRoom(this);
+ LogManager.WriteLog($"{roomID} user all left, room removed.");
+ }
}
///
/// Broadcast message to room | 广播消息到房间
@@ -145,11 +181,8 @@ public void Broadcast(string message,User? exceptUser)
/// 索引
public User this[int index]
{
- get { return userList[index]; }
- set
- {
- userList[index] = value;
- }
+ get => userList[index];
+ set => userList[index] = value;
}
}
@@ -213,9 +246,21 @@ public void LeaveRoom()
userStatus = Status.AFK;
}
+ ///
+ /// New Room | 创建房间
+ ///
+ /// 房间ID
+ /// 房间已存在
public void CreateRoom(string roomID)
{
- RoomManager.AddRoom(this, roomID);
+ if (RoomManager.GetRoom(roomID) != null)
+ {
+ throw new ArgumentException("RoomID already exists.");
+ }
+ else
+ {
+ RoomManager.AddRoom(this, roomID);
+ }
}
public void Remove()
diff --git a/Program.cs b/Program.cs
index 3cb0d34..1a64047 100644
--- a/Program.cs
+++ b/Program.cs
@@ -12,10 +12,6 @@ public class Program
isDebug = true
};
- //private static GameManager.ClientList clients = new();
- //private static GameManager.UserList users = new();
-
-
private static void Main(string[] args)
{
//Load config | 读取配置
@@ -47,6 +43,8 @@ private static void Main(string[] args)
{
// set cert
wssserver.Certificate = new X509Certificate2(config.certPath, config.certPassword);
+ wssserver.EnabledSslProtocols = System.Security.Authentication.SslProtocols.Tls12 |
+ System.Security.Authentication.SslProtocols.Tls13;
}
catch (Exception e)
{
@@ -86,6 +84,7 @@ private static void Main(string[] args)
};
});
}
+
if (config.ws)
{
wsserver.Start(socket =>
@@ -117,18 +116,20 @@ private static void Main(string[] args)
LogManager.WriteLog(
"Is it expected that both secure and insecure connections will be enabled simultaneously?",
LogManager.LogLevel.Warning
- );
+ );
}
-
+
LogManager.WriteLog("The server has been started");
if (config.ws)
{
LogManager.WriteLog($"The server is listening on ws://{config.wsOptions.Host}:{config.wsOptions.Port}");
}
+
if (config.wss)
{
LogManager.WriteLog($"The server is listening on wss://{config.wssOptions.Host}:{config.wssOptions.Port}");
}
+
while (true)
{
var command = Console.ReadLine();
@@ -142,6 +143,14 @@ private static void Main(string[] args)
LogManager.WriteLog($"{user.userName} Joined at {user.joinTime.ToString("yyyy-mm-dd hh:mm:ss")}");
}
}
+ else if (command == "roomlist")
+ {
+ LogManager.WriteLog("Room List:");
+ foreach (var room in GameManager.RoomManager.roomList)
+ {
+ LogManager.WriteLog($"{room.roomID} Owner: {room.owner.userName}");
+ }
+ }
}
}
@@ -156,7 +165,8 @@ private static async Task ServerOnMessage(string message, IWebSocketConnection s
{
LogManager.WriteLog("illegal data received, Drop.", LogManager.LogLevel.Warning);
//Drop | 丢弃并断开连接
- GameManager.UserManager.RemoveUser(socket);
+ if (GameManager.UserManager.Contains(socket))
+ GameManager.UserManager.RemoveUser(socket);
socket.Close();
return;
}
@@ -171,11 +181,14 @@ private static async Task ServerOnMessage(string message, IWebSocketConnection s
{
//illegal client, Drop it | 非法客户端,丢弃并断开连接
LogManager.WriteLog("illegal client, Drop it.", LogManager.LogLevel.Warning);
- await socket.Send(JsonConvert.SerializeObject(new ConnectionMessage.Server.JoinServerFailed()
+ await socket.Send(JsonConvert.SerializeObject(new ConnectionMessage.Server.JoinServerFailed
{
- reason = "The client is already connected to the server.\nYour connection will be closed.",
+ reason =
+ "The client is already connected to the server.\nYour connection will be closed." //客户端已经连接服务器,您的连接将被关闭。
}));
- GameManager.UserManager.Drop(socket);
+ LogManager.WriteLog(
+ $"There are illegal clients attempting to pass metadata multiple times: {GameManager.UserManager.GetUser(socket).userName}");
+ GameManager.UserManager.RemoveUser(socket);
socket.Close();
return;
}
@@ -185,17 +198,20 @@ await socket.Send(JsonConvert.SerializeObject(new ConnectionMessage.Server.JoinS
{
if (string.IsNullOrEmpty(data.password) || data.password != config.Password)
{
- await socket.Send(JsonConvert.SerializeObject(new ConnectionMessage.Server.JoinServerFailed()
+ await socket.Send(JsonConvert.SerializeObject(new ConnectionMessage.Server.JoinServerFailed
{
reason =
- "The server is private, but no password was provided or the password is invalid.\nYour connection will be closed.",
+ "The server is private, but no password was provided or the password is invalid.\nYour connection will be closed." //服务器是私有的,但没有提供密码或密码无效。您的连接将被关闭。
}));
+ LogManager.WriteLog(
+ $"The client attempted to connect to the server, but authentication failed: {data.userName}");
//Authentication failed, Drop and disconnect | 认证失败,丢弃并断开连接
- GameManager.UserManager.Drop(socket);
+ GameManager.UserManager.RemoveUser(socket);
socket.Close();
return;
}
}
+
// Add user | 添加用户
LogManager.WriteLog($"User {clientMetaData.data.userName} connected.");
LogManager.WriteLog($"Raw Message: {message}", LogManager.LogLevel.Debug);
@@ -209,7 +225,7 @@ await socket.Send(JsonConvert.SerializeObject(new ConnectionMessage.Server.JoinS
await socket.Send(JsonConvert.SerializeObject(new ConnectionMessage.Server.JoinServerSuccess()));
return;
}
-
+
// Check if the user has completed the return of metadata | 检查用户是否已经返回元数据
if (!GameManager.UserManager.Contains(socket))
{
@@ -221,26 +237,99 @@ await socket.Send(JsonConvert.SerializeObject(new ConnectionMessage.Server.JoinS
if (msg.action == "newRoom")
{
// To ConnectionMessage.Client.NewRoom | 将客户端发送的消息转换为 ConnectionMessage.Client.NewRoom
- ConnectionMessage.Client.NewRoom newRoom = JsonConvert.DeserializeObject(message)!;
+ ConnectionMessage.Client.NewRoom newRoom =
+ JsonConvert.DeserializeObject(message)!;
// TODO: User creates room logic | 创建房间逻辑
var user = GameManager.UserManager.GetUser(socket);
if (user.userStatus == GameManager.User.Status.InRoom)
{
- await socket.Send(JsonConvert.SerializeObject(new ConnectionMessage.Server.AddRoomFailed
+ await socket.Send(JsonConvert.SerializeObject(new ConnectionMessage.Server.NewRoomFailed
{
reason = "You are already in a room." // 你已经在房间里了。
}));
+ LogManager.WriteLog($"User {user.userName} tried to create a room while in a room."); // 用户尝试在房间里创建房间。
return;
}
+
+ var room = GameManager.RoomManager.GetRoom(newRoom.data.roomID);
+ if (room != null)
+ {
+ await socket.Send(JsonConvert.SerializeObject(new ConnectionMessage.Server.NewRoomFailed
+ {
+ reason = "The room already exists." // 房间已存在。
+ }));
+ LogManager.WriteLog(
+ $"User {user.userName} tried to create a room with the same name."); // 用户尝试使用相同的名称创建房间。
+ return;
+ }
+
GameManager.UserManager.GetUser(socket).CreateRoom(newRoom.data.roomID);
+ await socket.Send(JsonConvert.SerializeObject(new ConnectionMessage.Server.NewRoomSuccess()));
+ LogManager.WriteLog($"User {user.userName} has created a new room {user.userRoom!.roomID}.");
+ }
+
+ if (msg.action == "joinRoom")
+ {
+ // To ConnectionMessage.Client.JoinRoom | 将客户端发送的消息转换为 ConnectionMessage.Client.JoinRoom
+ ConnectionMessage.Client.JoinRoom joinRoom =
+ JsonConvert.DeserializeObject(message)!;
+ var user = GameManager.UserManager.GetUser(socket);
+ if (user.userStatus == GameManager.User.Status.InRoom)
+ {
+ await socket.Send(JsonConvert.SerializeObject(new ConnectionMessage.Server.JoinRoomFailed
+ {
+ reason = "You are already in a room." // 你已经在房间里了。
+ }));
+ LogManager.WriteLog($"User {user.userName} tried to join a room while in a room."); // 用户尝试在房间里加入房间。
+ return;
+ }
+
+ //Find the room | 查找房间
+ var room = GameManager.RoomManager.GetRoom(joinRoom.data.roomID);
+ if (room != null)
+ {
+ await socket.Send(JsonConvert.SerializeObject(new ConnectionMessage.Server.JoinRoomFailed
+ {
+ reason = "You are already in a room." // 你已经在房间里了。
+ }));
+ LogManager.WriteLog($"User {user.userName} tried to join a room while in a room."); // 用户尝试在房间里加入房间。
+ }
+ else
+ {
+ await socket.Send(JsonConvert.SerializeObject(new ConnectionMessage.Server.JoinRoomFailed
+ {
+ reason = "The room does not exist." // 房间不存在。
+ }));
+ LogManager.WriteLog($"User {user.userName} tried to join a room that does not exist.");// 用户尝试加入不存在的房间。
+ }
+ }
+
+ if (msg.action == "leaveRoom")
+ {
+ var user = GameManager.UserManager.GetUser(socket);
+ if (user.userStatus == GameManager.User.Status.InRoom)
+ {
+ user.LeaveRoom();
+ LogManager.WriteLog($"User {user.userName} has left the {user.userRoom!.roomID} room.");
+ await socket.Send(JsonConvert.SerializeObject(new ConnectionMessage.Server.LeaveRoomSuccess()));
+ }
+ else
+ {
+ await socket.Send(JsonConvert.SerializeObject(new ConnectionMessage.Server.LeaveRoomFailed
+ {
+ reason = "You are not in a room." // 你不在房间里。
+ }));
+ LogManager.WriteLog($"User {user.userName} tried to leave a room while not in a room.");// 用户尝试离开房间,但未在房间里。
+ }
}
}
private static async Task ServerOnOpen(IWebSocketConnection socket)
{
+ // Send GetData message, get metadata. | 发送 GetData 消息,获取元数据
await socket.Send(
JsonConvert.SerializeObject(
- new ConnectionMessage.Server.GetData()
+ new ConnectionMessage.Server.GetData
{
needPassword = config.isPrivate
}
@@ -251,18 +340,19 @@ await socket.Send(
private static async Task ServerOnError(Exception e, IWebSocketConnection socket)
{
LogManager.WriteLog(e.Message, LogManager.LogLevel.Debug);
- //WriteLog | 输出日志
- LogManager.WriteLog("Socket has been drop, because of an error: " + e.Message, LogManager.LogLevel.Error);
-
+ //WriteLog, Socket has been drop | 输出日志,连接被丢弃
+ LogManager.WriteLog("Socket has been drop, because of an error: " + e.Message, LogManager.LogLevel.Debug);
+ LogManager.WriteLog($"User {GameManager.UserManager.GetUser(socket).userName} unexpectedly disconnected",
+ LogManager.LogLevel.Warning);
//Drop and disconnect | 丢弃并断开连接
- GameManager.UserManager.Drop(socket);
+ GameManager.UserManager.RemoveUser(socket);
socket.Close();
}
-
+
private static async Task ServerOnClose(IWebSocketConnection socket)
{
- LogManager.WriteLog("Client disconnected.");
+ LogManager.WriteLog($"user{GameManager.UserManager.GetUser(socket).userName} disconnected.");
GameManager.UserManager.RemoveUser(socket);
}
@@ -277,16 +367,19 @@ public class Config
public string Password = "";
public bool ws = true;
public bool wss = false;
+
public dynamic wsOptions = new
{
Host = "0.0.0.0",
Port = 14156
};
+
public dynamic wssOptions = new
{
Host = "0.0.0.0",
Port = 14157
};
+
public string certPath = "path/to/your/certificate.pfx";
public string certPassword = "your_certificate_password";
public string userDefauletAvatarUrl = "";