diff --git a/FunGame.Server/Controllers/Authenticator.cs b/FunGame.Server/Controllers/Authenticator.cs
index 0799c0c..1423d01 100644
--- a/FunGame.Server/Controllers/Authenticator.cs
+++ b/FunGame.Server/Controllers/Authenticator.cs
@@ -1,7 +1,7 @@
using Milimoe.FunGame.Core.Api.Transmittal;
using Milimoe.FunGame.Core.Api.Utility;
+using Milimoe.FunGame.Core.Interface.Base;
using Milimoe.FunGame.Core.Library.Constant;
-using Milimoe.FunGame.Server.Model;
namespace Milimoe.FunGame.Server.Controller
{
@@ -9,11 +9,11 @@ namespace Milimoe.FunGame.Server.Controller
{
public TwoFactorAuthenticator Login2FA = new();
- private readonly ServerModel Server;
+ private readonly IServerModel Server;
private readonly SQLHelper SQLHelper;
private readonly MailSender? MailSender;
- public Authenticator(ServerModel Server, SQLHelper SQLHelper, MailSender? MailSender) : base(SQLHelper)
+ public Authenticator(IServerModel Server, SQLHelper SQLHelper, MailSender? MailSender) : base(SQLHelper)
{
this.Server = Server;
this.SQLHelper = SQLHelper;
diff --git a/FunGame.Server/Controllers/ConnectController.cs b/FunGame.Server/Controllers/ConnectController.cs
new file mode 100644
index 0000000..4e3de9c
--- /dev/null
+++ b/FunGame.Server/Controllers/ConnectController.cs
@@ -0,0 +1,134 @@
+using Milimoe.FunGame.Core.Interface.Base;
+using Milimoe.FunGame.Core.Library.Common.Network;
+using Milimoe.FunGame.Core.Library.Constant;
+using Milimoe.FunGame.Server.Others;
+using Milimoe.FunGame.Server.Utility;
+
+namespace Milimoe.FunGame.Server.Controller
+{
+ public class ConnectController
+ {
+ ///
+ /// 因为异步函数无法使用 ref 变量,因此使用元组返回
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// [0]isConnected;[1]isDebugMode
+ public static async Task<(bool, bool)> Connect(ISocketListener listener, ISocketMessageProcessor socket, Guid token, string clientip, IEnumerable objs) where T : ISocketMessageProcessor
+ {
+ try
+ {
+ bool isConnected = false;
+ bool isDebugMode = false;
+ foreach (SocketObject obj in objs)
+ {
+ if (obj.SocketType == SocketMessageType.Connect)
+ {
+ if (Config.ConnectingPlayerCount + Config.OnlinePlayerCount > Config.MaxPlayers)
+ {
+ await SendRefuseConnect(socket, "服务器可接受的连接数量已上限!");
+ ServerHelper.WriteLine("服务器可接受的连接数量已上限!", InvokeMessageType.Core);
+ return (isConnected, isDebugMode);
+ }
+ ServerHelper.WriteLine(ServerHelper.MakeClientName(clientip) + " 正在连接服务器 . . .", InvokeMessageType.Core);
+ if (IsIPBanned(listener, clientip))
+ {
+ await SendRefuseConnect(socket, "服务器已拒绝黑名单用户连接。");
+ ServerHelper.WriteLine("检测到 " + ServerHelper.MakeClientName(clientip) + " 为黑名单用户,已禁止其连接!", InvokeMessageType.Core);
+ return (isConnected, isDebugMode);
+ }
+
+ ServerHelper.WriteLine("[" + SocketSet.GetTypeString(obj.SocketType) + "] " + ServerHelper.MakeClientName(socket.ClientIP), InvokeMessageType.Core);
+
+ // 读取参数
+ // 参数1:客户端的游戏模组列表,没有服务器的需要拒绝
+ string[] modes = obj.GetParam(0) ?? [];
+ // 参数2:客户端是否开启了开发者模式,开启开发者模式部分功能不可用
+ isDebugMode = obj.GetParam(1);
+ if (isDebugMode) ServerHelper.WriteLine("客户端已开启开发者模式");
+
+ string msg = "";
+ List ClientDontHave = [];
+ string strDontHave = string.Join("\r\n", Config.GameModuleSupported.Where(mode => !modes.Contains(mode)));
+ if (strDontHave != "")
+ {
+ strDontHave = "客户端缺少服务器所需的模组:" + strDontHave;
+ ServerHelper.WriteLine(strDontHave, InvokeMessageType.Core);
+ msg += strDontHave;
+ }
+
+ if (msg == "" && await socket.SendAsync(SocketMessageType.Connect, true, msg, token, Config.ServerName, Config.ServerNotice) == SocketResult.Success)
+ {
+ isConnected = true;
+ ServerHelper.WriteLine(ServerHelper.MakeClientName(socket.ClientIP) + " <- " + "已确认连接", InvokeMessageType.Core);
+ return (isConnected, isDebugMode);
+ }
+ else if (msg != "" && await socket.SendAsync(SocketMessageType.Connect, false, msg) == SocketResult.Success)
+ {
+ ServerHelper.WriteLine(ServerHelper.MakeClientName(socket.ClientIP) + " <- " + "拒绝连接", InvokeMessageType.Core);
+ return (isConnected, isDebugMode);
+ }
+ else
+ {
+ ServerHelper.WriteLine("无法传输数据,与客户端的连接可能丢失。", InvokeMessageType.Core);
+ return (isConnected, isDebugMode);
+ }
+ }
+ }
+
+ await SendRefuseConnect(socket, "服务器已拒绝连接。");
+ ServerHelper.WriteLine("客户端发送了不符合FunGame规定的字符,拒绝连接。", InvokeMessageType.Core);
+ return (isConnected, isDebugMode);
+ }
+ catch (Exception e)
+ {
+ ServerHelper.Error(e);
+ await SendRefuseConnect(socket, "请勿发送错误的数据,请保持FunGame版本为最新。");
+ throw new SocketWrongInfoException();
+ }
+ }
+
+ ///
+ /// 回复拒绝连接消息
+ ///
+ ///
+ ///
+ ///
+ private static async Task SendRefuseConnect(ISocketMessageProcessor socket, string msg)
+ {
+ // 发送消息给客户端
+ msg = "连接被拒绝,如有疑问请联系服务器管理员:" + msg;
+ if (await socket.SendAsync(SocketMessageType.Connect, false, msg) == SocketResult.Success)
+ {
+ ServerHelper.WriteLine(ServerHelper.MakeClientName(socket.ClientIP) + " <- " + "已拒绝连接", InvokeMessageType.Core);
+ return true;
+ }
+ else
+ {
+ ServerHelper.WriteLine("无法传输数据,与客户端的连接可能丢失。", InvokeMessageType.Core);
+ return false;
+ }
+ }
+
+ ///
+ /// 判断是否是黑名单里的IP
+ ///
+ ///
+ ///
+ ///
+ ///
+ private static bool IsIPBanned(ISocketListener server, string ip) where T : ISocketMessageProcessor
+ {
+ string[] strs = ip.Split(":");
+ if (strs.Length == 2 && server.BannedList.Contains(strs[0]))
+ {
+ return true;
+ }
+ return false;
+ }
+ }
+}
diff --git a/FunGame.Server/Controllers/DataRequestController.cs b/FunGame.Server/Controllers/DataRequestController.cs
index 6a694e0..5fef652 100644
--- a/FunGame.Server/Controllers/DataRequestController.cs
+++ b/FunGame.Server/Controllers/DataRequestController.cs
@@ -1,8 +1,8 @@
-using System.Collections;
-using System.Data;
+using System.Data;
using Milimoe.FunGame.Core.Api.Transmittal;
using Milimoe.FunGame.Core.Api.Utility;
using Milimoe.FunGame.Core.Entity;
+using Milimoe.FunGame.Core.Interface.Base;
using Milimoe.FunGame.Core.Library.Constant;
using Milimoe.FunGame.Core.Library.SQLScript.Common;
using Milimoe.FunGame.Core.Library.SQLScript.Entity;
@@ -12,29 +12,47 @@ using Milimoe.FunGame.Server.Utility;
namespace Milimoe.FunGame.Server.Controller
{
- public class DataRequestController
+ ///
+ /// 继承自
+ ///
+ ///
+ public class DataRequestController where T : ISocketMessageProcessor
{
- public ServerModel Server { get; }
- public MySQLHelper SQLHelper => Server.SQLHelper ?? throw new MySQLConfigException();
+ public ServerModel Server { get; }
+ public SQLHelper? SQLHelper => Server.SQLHelper;
public MailSender? MailSender => Server.MailSender;
- public Authenticator Authenticator { get; }
- public DataRequestType LastRequest => _LastRequest;
+ public Authenticator? Authenticator { get; }
+ public DataRequestType LastRequest => _lastRequest;
- private string ForgetVerify = "";
- private string RegVerify = "";
- private DataRequestType _LastRequest = DataRequestType.UnKnown;
- private readonly bool[] isReadyCheckCD = [false, false];
+ private string _forgetVerify = "";
+ private string _regVerify = "";
+ private DataRequestType _lastRequest = DataRequestType.UnKnown;
+ private readonly bool[] _isReadyCheckCD = [false, false];
+ protected DataSet _dsUser = new();
+ protected string _username = "";
+ protected Guid _checkLoginKey = Guid.Empty;
+ protected bool _isMatching;
- public DataRequestController(ServerModel server)
+ ///
+ /// 数据请求控制器
+ ///
+ ///
+ public DataRequestController(ServerModel server)
{
Server = server;
- Authenticator = new(Server, SQLHelper, MailSender);
+ if (SQLHelper != null) Authenticator = new(Server, SQLHelper, MailSender);
}
- public Hashtable GetResultData(DataRequestType type, Hashtable data)
+ ///
+ /// 处理客户端的数据请求
+ ///
+ ///
+ ///
+ ///
+ public async Task> GetResultData(DataRequestType type, Dictionary data)
{
- Hashtable result = [];
- _LastRequest = type;
+ Dictionary result = [];
+ _lastRequest = type;
switch (type)
{
@@ -58,11 +76,11 @@ namespace Milimoe.FunGame.Server.Controller
break;
case DataRequestType.Main_IntoRoom:
- IntoRoom(data, result);
+ await IntoRoom(data, result);
break;
case DataRequestType.Main_QuitRoom:
- QuitRoom(data, result);
+ await QuitRoom(data, result);
break;
case DataRequestType.Main_MatchRoom:
@@ -70,7 +88,7 @@ namespace Milimoe.FunGame.Server.Controller
break;
case DataRequestType.Main_Chat:
- Chat(data);
+ await Chat(data);
break;
case DataRequestType.Main_Ready:
@@ -85,12 +103,12 @@ namespace Milimoe.FunGame.Server.Controller
StartGame(data, result);
break;
- case DataRequestType.Reg_GetRegVerifyCode:
+ case DataRequestType.Reg_Reg:
Reg(data, result);
break;
case DataRequestType.Login_Login:
- Login(data, result);
+ await Login(data, result);
break;
case DataRequestType.Login_GetFindPasswordVerifyCode:
@@ -123,24 +141,27 @@ namespace Milimoe.FunGame.Server.Controller
///
/// 退出登录
///
- ///
- ///
- private void LogOut(Hashtable RequestData, Hashtable ResultData)
+ ///
+ ///
+ private void LogOut(Dictionary requestData, Dictionary resultData)
{
string msg = "";
Guid key = Guid.Empty;
- if (RequestData.Count >= 1)
+ if (requestData.Count >= 1)
{
- ServerHelper.WriteLine(Server.GetClientName() + " -> " + DataRequestSet.GetTypeString(_LastRequest), InvokeMessageType.DataRequest);
- key = DataRequest.GetHashtableJsonObject(RequestData, "key");
- if (Server.IsLoginKey(key))
+ ServerHelper.WriteLine(Server.GetClientName() + " -> " + DataRequestSet.GetTypeString(_lastRequest), InvokeMessageType.DataRequest);
+ key = DataRequest.GetDictionaryJsonObject(requestData, "key");
+ if (IsLoginKey(key))
{
- Server.LogOut();
+ // 从玩家列表移除
+ Server.RemoveUser();
+ Server.GetUsersCount();
+ _checkLoginKey = Guid.Empty;
msg = "你已成功退出登录! ";
}
}
- ResultData.Add("msg", msg);
- ResultData.Add("key", key);
+ resultData.Add("msg", msg);
+ resultData.Add("key", key);
}
#endregion
@@ -150,242 +171,264 @@ namespace Milimoe.FunGame.Server.Controller
///
/// 获取公告
///
- ///
- private void GetServerNotice(Hashtable ResultData)
+ ///
+ private void GetServerNotice(Dictionary resultData)
{
- ServerHelper.WriteLine(Server.GetClientName() + " -> " + DataRequestSet.GetTypeString(_LastRequest), InvokeMessageType.DataRequest);
- ResultData.Add("notice", Config.ServerNotice);
+ ServerHelper.WriteLine(Server.GetClientName() + " -> " + DataRequestSet.GetTypeString(_lastRequest), InvokeMessageType.DataRequest);
+ resultData.Add("notice", Config.ServerNotice);
}
///
/// 创建房间
///
- ///
- ///
- private void CreateRoom(Hashtable RequestData, Hashtable ResultData)
+ ///
+ ///
+ private void CreateRoom(Dictionary requestData, Dictionary resultData)
{
Room room = General.HallInstance;
- if (RequestData.Count >= 3)
+ if (requestData.Count >= 3)
{
- RoomType type = DataRequest.GetHashtableJsonObject(RequestData, "roomtype");
- string GameModule = DataRequest.GetHashtableJsonObject(RequestData, "GameModule") ?? "";
- string gamemap = DataRequest.GetHashtableJsonObject(RequestData, "gamemap") ?? "";
- bool isrank = DataRequest.GetHashtableJsonObject(RequestData, "isrank");
- ServerHelper.WriteLine(Server.GetClientName() + " -> " + DataRequestSet.GetTypeString(_LastRequest) + " : " + RoomSet.GetTypeString(type) + " (" + string.Join(", ", [GameModule, gamemap]) + ")", InvokeMessageType.DataRequest);
- if (GameModule == "" || gamemap == "")
+ RoomType type = DataRequest.GetDictionaryJsonObject(requestData, "roomtype");
+ string gamemodule = DataRequest.GetDictionaryJsonObject(requestData, "gamemoduleserver") ?? "";
+ string gamemap = DataRequest.GetDictionaryJsonObject(requestData, "gamemap") ?? "";
+ bool isrank = DataRequest.GetDictionaryJsonObject(requestData, "isrank");
+ ServerHelper.WriteLine(Server.GetClientName() + " -> " + DataRequestSet.GetTypeString(_lastRequest) + " : " + RoomSet.GetTypeString(type) + " (" + string.Join(", ", [gamemodule, gamemap]) + ")", InvokeMessageType.DataRequest);
+ if (gamemodule == "" || gamemap == "" || Config.GameModuleLoader is null || !Config.GameModuleLoader.ModuleServers.ContainsKey(gamemodule) || !Config.GameModuleLoader.Maps.ContainsKey(gamemap))
{
ServerHelper.WriteLine("缺少对应的模组或地图,无法创建房间。");
- ResultData.Add("room", room);
+ resultData.Add("room", room);
return;
}
- User user = DataRequest.GetHashtableJsonObject(RequestData, "master") ?? Factory.GetUser();
- string password = DataRequest.GetHashtableJsonObject(RequestData, "password") ?? "";
+ User user = DataRequest.GetDictionaryJsonObject(requestData, "master") ?? Factory.GetUser();
+ string password = DataRequest.GetDictionaryJsonObject(requestData, "password") ?? "";
+ int maxusers = DataRequest.GetDictionaryJsonObject(requestData, "maxusers");
if (user.Id != 0)
{
- string roomid = Verification.CreateVerifyCode(VerifyCodeType.MixVerifyCode, 7).ToUpper();
- SQLHelper.Execute(RoomQuery.Insert_CreateRoom(roomid, user.Id, type, GameModule, gamemap, isrank, password ?? ""));
- if (SQLHelper.Result == SQLResult.Success)
+ string roomid;
+ while (true)
{
- ServerHelper.WriteLine("[CreateRoom] Master: " + user.Username + " RoomID: " + roomid);
- SQLHelper.ExecuteDataSet(RoomQuery.Select_IsExistRoom(roomid));
- if (SQLHelper.Result == SQLResult.Success && SQLHelper.DataSet.Tables[0].Rows.Count > 0)
+ // 防止重复
+ roomid = Verification.CreateVerifyCode(VerifyCodeType.MixVerifyCode, 7).ToUpper();
+ if (Config.RoomList.GetRoom(roomid).Roomid == "-1")
{
- room = Factory.GetRoom(SQLHelper.DataSet.Tables[0].Rows[0], user);
- Config.RoomList.AddRoom(room);
+ break;
+ }
+ }
+ if (roomid != "-1" && SQLHelper != null)
+ {
+ SQLHelper.Execute(RoomQuery.Insert_CreateRoom(roomid, user.Id, type, gamemodule, gamemap, isrank, password, maxusers));
+ if (SQLHelper.Result == SQLResult.Success)
+ {
+ ServerHelper.WriteLine("[CreateRoom] Master: " + user.Username + " RoomID: " + roomid);
+ SQLHelper.ExecuteDataSet(RoomQuery.Select_IsExistRoom(roomid));
+ if (SQLHelper.Result == SQLResult.Success && SQLHelper.DataSet.Tables[0].Rows.Count > 0)
+ {
+ room = Factory.GetRoom(SQLHelper.DataSet.Tables[0].Rows[0], user);
+ Config.RoomList.AddRoom(room);
+ }
}
}
}
}
- ResultData.Add("room", room);
+ resultData.Add("room", room);
}
///
/// 更新房间列表
///
- ///
- private void UpdateRoom(Hashtable ResultData)
+ ///
+ private void UpdateRoom(Dictionary resultData)
{
- ServerHelper.WriteLine(Server.GetClientName() + " -> " + DataRequestSet.GetTypeString(_LastRequest), InvokeMessageType.DataRequest);
- ResultData.Add("rooms", Config.RoomList.ListRoom); // 传RoomList
+ ServerHelper.WriteLine(Server.GetClientName() + " -> " + DataRequestSet.GetTypeString(_lastRequest), InvokeMessageType.DataRequest);
+ resultData.Add("rooms", Config.RoomList.ListRoom); // 传RoomList
}
///
/// 退出房间,并更新房主
///
- ///
- ///
- private void QuitRoom(Hashtable RequestData, Hashtable ResultData)
+ ///
+ ///
+ private async Task QuitRoom(Dictionary requestData, Dictionary resultData)
{
bool result = false;
- if (RequestData.Count >= 2)
+ if (requestData.Count >= 2)
{
- ServerHelper.WriteLine(Server.GetClientName() + " -> " + DataRequestSet.GetTypeString(_LastRequest), InvokeMessageType.DataRequest);
- string roomid = DataRequest.GetHashtableJsonObject(RequestData, "roomid") ?? "-1";
- bool isMaster = DataRequest.GetHashtableJsonObject(RequestData, "isMaster");
+ ServerHelper.WriteLine(Server.GetClientName() + " -> " + DataRequestSet.GetTypeString(_lastRequest), InvokeMessageType.DataRequest);
+ string roomid = DataRequest.GetDictionaryJsonObject(requestData, "roomid") ?? "-1";
+ bool isMaster = DataRequest.GetDictionaryJsonObject(requestData, "isMaster");
if (roomid != "-1" && Config.RoomList.IsExist(roomid))
{
- result = Server.QuitRoom(roomid, isMaster);
+ result = await Server.QuitRoom(roomid, isMaster);
}
}
- ResultData.Add("result", result);
+ resultData.Add("result", result);
}
///
/// 进入房间
///
- ///
- ///
- private void IntoRoom(Hashtable RequestData, Hashtable ResultData)
+ ///
+ ///
+ private async Task IntoRoom(Dictionary requestData, Dictionary resultData)
{
bool result = false;
- if (RequestData.Count >= 1)
+ if (requestData.Count >= 1)
{
- ServerHelper.WriteLine(Server.GetClientName() + " -> " + DataRequestSet.GetTypeString(_LastRequest), InvokeMessageType.DataRequest);
- string roomid = DataRequest.GetHashtableJsonObject(RequestData, "roomid") ?? "-1";
+ ServerHelper.WriteLine(Server.GetClientName() + " -> " + DataRequestSet.GetTypeString(_lastRequest), InvokeMessageType.DataRequest);
+ string roomid = DataRequest.GetDictionaryJsonObject(requestData, "roomid") ?? "-1";
if (roomid != "-1")
{
- SQLHelper.ExecuteDataSet(RoomQuery.Select_IsExistRoom(roomid));
- if (SQLHelper.Success)
+ if (SQLHelper != null)
{
- Config.RoomList.IntoRoom(roomid, Server.User);
- Server.IntoRoom(roomid);
- result = true;
- }
- else
- {
- Config.RoomList.RemoveRoom(roomid);
+ SQLHelper.ExecuteDataSet(RoomQuery.Select_IsExistRoom(roomid));
+ if (SQLHelper.Success)
+ {
+ Config.RoomList.IntoRoom(roomid, Server.User);
+ Server.InRoom = Config.RoomList[roomid];
+ await Server.SendClients(Server.Listener.ClientList.Where(c => c != null && roomid == c.InRoom.Roomid && c.User.Id != 0),
+ SocketMessageType.Chat, Server.User.Username, DateTimeUtility.GetNowShortTime() + " [ " + Server.User.Username + " ] 进入了房间。");
+ result = true;
+ }
+ else
+ {
+ Config.RoomList.RemoveRoom(roomid);
+ }
}
}
}
- ResultData.Add("result", result);
+ resultData.Add("result", result);
}
///
/// 匹配房间
///
- ///
- ///
- private void MatchRoom(Hashtable RequestData, Hashtable ResultData)
+ ///
+ ///
+ private void MatchRoom(Dictionary requestData, Dictionary resultData)
{
bool result = true;
- if (RequestData.Count >= 1)
+ if (requestData.Count >= 1)
{
- bool iscancel = DataRequest.GetHashtableJsonObject(RequestData, "iscancel");
+ bool iscancel = DataRequest.GetDictionaryJsonObject(requestData, "iscancel");
if (!iscancel)
{
- ServerHelper.WriteLine(Server.GetClientName() + " -> " + DataRequestSet.GetTypeString(_LastRequest) + " : Start", InvokeMessageType.DataRequest);
- RoomType type = DataRequest.GetHashtableJsonObject(RequestData, "roomtype");
- User user = DataRequest.GetHashtableJsonObject(RequestData, "matcher") ?? Factory.GetUser();
- Server.StartMatching(type, user);
+ ServerHelper.WriteLine(Server.GetClientName() + " -> " + DataRequestSet.GetTypeString(_lastRequest) + " : Start", InvokeMessageType.DataRequest);
+ RoomType type = DataRequest.GetDictionaryJsonObject(requestData, "roomtype");
+ User user = DataRequest.GetDictionaryJsonObject(requestData, "matcher") ?? Factory.GetUser();
+ StartMatching(type, user);
}
else
{
// 取消匹配
- ServerHelper.WriteLine(Server.GetClientName() + " -> " + DataRequestSet.GetTypeString(_LastRequest) + " : Cancel", InvokeMessageType.DataRequest);
- Server.StopMatching();
+ ServerHelper.WriteLine(Server.GetClientName() + " -> " + DataRequestSet.GetTypeString(_lastRequest) + " : Cancel", InvokeMessageType.DataRequest);
+ StopMatching();
}
}
- ResultData.Add("result", result);
+ resultData.Add("result", result);
}
///
/// 设置已准备状态
///
- ///
- ///
- private void SetReady(Hashtable RequestData, Hashtable ResultData)
+ ///
+ ///
+ private void SetReady(Dictionary requestData, Dictionary resultData)
{
bool result = false;
string roomid = "-1";
- if (RequestData.Count >= 1)
+ if (requestData.Count >= 1)
{
- ServerHelper.WriteLine(Server.GetClientName() + " -> " + DataRequestSet.GetTypeString(_LastRequest), InvokeMessageType.DataRequest);
- roomid = DataRequest.GetHashtableJsonObject(RequestData, "roomid") ?? "-1";
+ ServerHelper.WriteLine(Server.GetClientName() + " -> " + DataRequestSet.GetTypeString(_lastRequest), InvokeMessageType.DataRequest);
+ roomid = DataRequest.GetDictionaryJsonObject(requestData, "roomid") ?? "-1";
User user = Server.User;
- if (roomid != "-1" && user.Id != 0 && !Config.RoomList.GetReadyPlayerList(roomid).Contains(user))
+ if (roomid != "-1" && user.Id != 0 && user.Id != Config.RoomList.GetRoomMaster(roomid).Id && !Config.RoomList.GetReadyUserList(roomid).Contains(user))
{
Config.RoomList.SetReady(roomid, user);
result = true;
}
}
- ResultData.Add("result", result);
- ResultData.Add("ready", Config.RoomList.GetReadyPlayerList(roomid));
- ResultData.Add("notready", Config.RoomList.GetNotReadyPlayerList(roomid));
+ resultData.Add("result", result);
+ resultData.Add("ready", Config.RoomList.GetReadyUserList(roomid));
+ resultData.Add("notready", Config.RoomList.GetNotReadyUserList(roomid));
}
///
/// 取消已准备状态
///
- ///
- ///
- private void CancelReady(Hashtable RequestData, Hashtable ResultData)
+ ///
+ ///
+ private void CancelReady(Dictionary requestData, Dictionary resultData)
{
bool result = false;
string roomid = "-1";
- if (RequestData.Count >= 1)
+ if (requestData.Count >= 1)
{
- ServerHelper.WriteLine(Server.GetClientName() + " -> " + DataRequestSet.GetTypeString(_LastRequest), InvokeMessageType.DataRequest);
- roomid = DataRequest.GetHashtableJsonObject(RequestData, "roomid") ?? "-1";
+ ServerHelper.WriteLine(Server.GetClientName() + " -> " + DataRequestSet.GetTypeString(_lastRequest), InvokeMessageType.DataRequest);
+ roomid = DataRequest.GetDictionaryJsonObject(requestData, "roomid") ?? "-1";
User user = Server.User;
- if (roomid != "-1" && user.Id != 0 && Config.RoomList.GetReadyPlayerList(roomid).Contains(user))
+ if (roomid != "-1" && user.Id != 0 && user.Id != Config.RoomList.GetRoomMaster(roomid).Id && Config.RoomList.GetReadyUserList(roomid).Contains(user))
{
Config.RoomList.CancelReady(roomid, user);
result = true;
}
}
- ResultData.Add("result", result);
- ResultData.Add("ready", Config.RoomList.GetReadyPlayerList(roomid));
- ResultData.Add("notready", Config.RoomList.GetNotReadyPlayerList(roomid));
+ resultData.Add("result", result);
+ resultData.Add("ready", Config.RoomList.GetReadyUserList(roomid));
+ resultData.Add("notready", Config.RoomList.GetNotReadyUserList(roomid));
}
///
/// 发送聊天消息
///
- ///
- private void Chat(Hashtable RequestData)
+ ///
+ private async Task Chat(Dictionary requestData)
{
- if (RequestData.Count >= 1)
+ if (requestData.Count >= 1)
{
- string msg = DataRequest.GetHashtableJsonObject(RequestData, "msg") ?? "";
- if (msg.Trim() != "") Server.Chat(msg);
+ string msg = DataRequest.GetDictionaryJsonObject(requestData, "msg") ?? "";
+ if (msg.Trim() != "")
+ {
+ await Server.SendClients(Server.Listener.ClientList.Where(c => c != null && Server.InRoom.Roomid == c.InRoom.Roomid && c.User.Id != 0),
+ SocketMessageType.Chat, Server.User.Username, msg);
+ }
}
}
///
/// 开始游戏
///
- ///
- ///
- private void StartGame(Hashtable RequestData, Hashtable ResultData)
+ ///
+ ///
+ private void StartGame(Dictionary requestData, Dictionary resultData)
{
bool result = false;
- if (RequestData.Count >= 2)
+ if (requestData.Count >= 2)
{
- ServerHelper.WriteLine(Server.GetClientName() + " -> " + DataRequestSet.GetTypeString(_LastRequest), InvokeMessageType.DataRequest);
- string roomid = DataRequest.GetHashtableJsonObject(RequestData, "roomid") ?? "-1";
- bool isMaster = DataRequest.GetHashtableJsonObject(RequestData, "isMaster");
+ ServerHelper.WriteLine(Server.GetClientName() + " -> " + DataRequestSet.GetTypeString(_lastRequest), InvokeMessageType.DataRequest);
+ string roomid = DataRequest.GetDictionaryJsonObject(requestData, "roomid") ?? "-1";
+ bool isMaster = DataRequest.GetDictionaryJsonObject(requestData, "isMaster");
if (roomid != "-1")
{
if (isMaster)
{
- string[] usernames = Config.RoomList.GetNotReadyPlayerList(roomid).Select(user => user.Username).ToArray();
+ string[] usernames = Config.RoomList.GetNotReadyUserList(roomid).Select(user => user.Username).ToArray();
if (usernames.Length > 0)
{
- if (isReadyCheckCD[0] == false)
+ if (_isReadyCheckCD[0] == false)
{
// 提醒玩家准备
Server.SendSystemMessage(ShowMessageType.None, "还有玩家尚未准备,无法开始游戏。", "", 0, Server.User.Username);
Server.SendSystemMessage(ShowMessageType.Tip, "房主即将开始游戏,请准备!", "请准备就绪", 10, usernames);
- isReadyCheckCD[0] = true;
+ _isReadyCheckCD[0] = true;
TaskUtility.RunTimer(() =>
{
- isReadyCheckCD[0] = false;
+ _isReadyCheckCD[0] = false;
}, 15000);
}
else
@@ -395,7 +438,7 @@ namespace Milimoe.FunGame.Server.Controller
}
else
{
- List users = Config.RoomList.GetPlayerList(roomid);
+ List users = Config.RoomList.GetUsers(roomid);
if (users.Count < 2)
{
Server.SendSystemMessage(ShowMessageType.None, "玩家数量不足,无法开始游戏。", "", 0, Server.User.Username);
@@ -404,20 +447,20 @@ namespace Milimoe.FunGame.Server.Controller
{
usernames = users.Select(user => user.Username).ToArray();
Server.SendSystemMessage(ShowMessageType.None, "所有玩家均已准备,游戏将在10秒后开始。", "", 0, usernames);
- Server.StartGame(roomid, users, usernames);
+ StartGame(roomid, users, usernames);
result = true;
}
}
}
- else if (isReadyCheckCD[1] == false)
+ else if (_isReadyCheckCD[1] == false)
{
// 提醒房主开始游戏
Server.SendSystemMessage(ShowMessageType.None, "已提醒房主立即开始游戏。", "", 0, Server.User.Username);
Server.SendSystemMessage(ShowMessageType.Tip, "房间中的玩家已请求你立即开始游戏。", "请求开始", 10, Config.RoomList[roomid].RoomMaster.Username);
- isReadyCheckCD[1] = true;
+ _isReadyCheckCD[1] = true;
TaskUtility.RunTimer(() =>
{
- isReadyCheckCD[1] = false;
+ _isReadyCheckCD[1] = false;
}, 15000);
}
else
@@ -426,7 +469,42 @@ namespace Milimoe.FunGame.Server.Controller
}
}
}
- ResultData.Add("result", result);
+ resultData.Add("result", result);
+ }
+
+ private void StartGame(string roomid, List users, params string[] usernames)
+ {
+ Room room = General.HallInstance;
+ if (roomid != "-1")
+ {
+ room = Config.RoomList[roomid];
+ }
+ if (room.Roomid == "-1") return;
+ // 启动服务器
+ TaskUtility.NewTask(() =>
+ {
+ if (Config.GameModuleLoader != null && Config.GameModuleLoader.ModuleServers.ContainsKey(room.GameModule))
+ {
+ Server.NowGamingServer = Config.GameModuleLoader.GetServerMode(room.GameModule);
+ Dictionary all = Server.Listener.UserList.Cast().ToDictionary(k => k.User.Username, v => v);
+ // 给其他玩家赋值模组服务器
+ foreach (IServerModel model in all.Values.Where(s => s.User.Username != Server.User.Username))
+ {
+ model.NowGamingServer = Server.NowGamingServer;
+ }
+ if (Server.NowGamingServer.StartServer(room.GameModule, room, users, Server, all))
+ {
+ foreach (IServerModel serverTask in Server.Listener.UserList.Where(model => usernames.Contains(model.User.Username)))
+ {
+ if (serverTask != null && serverTask.Socket != null)
+ {
+ Config.RoomList.CancelReady(roomid, serverTask.User);
+ serverTask.Send(SocketMessageType.StartGame, room, users);
+ }
+ }
+ }
+ }
+ });
}
#endregion
@@ -436,139 +514,142 @@ namespace Milimoe.FunGame.Server.Controller
///
/// 接收并验证注册验证码
///
- ///
- ///
- private void Reg(Hashtable RequestData, Hashtable ResultData)
+ ///
+ ///
+ private void Reg(Dictionary requestData, Dictionary resultData)
{
string msg = "";
RegInvokeType returnType = RegInvokeType.None;
bool success = false;
- if (RequestData.Count >= 4)
+ if (requestData.Count >= 4)
{
- ServerHelper.WriteLine(Server.GetClientName() + " -> " + DataRequestSet.GetTypeString(_LastRequest), InvokeMessageType.DataRequest);
- string username = DataRequest.GetHashtableJsonObject(RequestData, "username") ?? "";
- string password = DataRequest.GetHashtableJsonObject(RequestData, "password") ?? "";
- string email = DataRequest.GetHashtableJsonObject(RequestData, "email") ?? "";
- string verifycode = DataRequest.GetHashtableJsonObject(RequestData, "verifycode") ?? "";
+ ServerHelper.WriteLine(Server.GetClientName() + " -> " + DataRequestSet.GetTypeString(_lastRequest), InvokeMessageType.DataRequest);
+ string username = DataRequest.GetDictionaryJsonObject(requestData, "username") ?? "";
+ string password = DataRequest.GetDictionaryJsonObject(requestData, "password") ?? "";
+ string email = DataRequest.GetDictionaryJsonObject(requestData, "email") ?? "";
+ string verifycode = DataRequest.GetDictionaryJsonObject(requestData, "verifycode") ?? "";
- // 如果没发验证码,就生成验证码
- if (verifycode.Trim() == "")
+ if (SQLHelper != null)
{
- // 先检查账号是否重复
- SQLHelper.ExecuteDataSet(UserQuery.Select_IsExistUsername(username));
- if (SQLHelper.Result == SQLResult.Success)
+ // 如果没发验证码,就生成验证码
+ if (verifycode.Trim() == "")
{
- ServerHelper.WriteLine(Server.GetClientName() + " 账号已被注册");
- msg = "此账号名已被使用!";
- returnType = RegInvokeType.DuplicateUserName;
- }
- else
- {
- // 检查邮箱是否重复
- SQLHelper.ExecuteDataSet(UserQuery.Select_IsExistEmail(email));
+ // 先检查账号是否重复
+ SQLHelper.ExecuteDataSet(UserQuery.Select_IsExistUsername(username));
if (SQLHelper.Result == SQLResult.Success)
{
- ServerHelper.WriteLine(Server.GetClientName() + " 邮箱已被注册");
- msg = "此邮箱已被注册!";
- returnType = RegInvokeType.DuplicateEmail;
+ ServerHelper.WriteLine(Server.GetClientName() + " 账号已被注册");
+ msg = "此账号名已被使用!";
+ returnType = RegInvokeType.DuplicateUserName;
}
else
{
- // 检查验证码是否发送过
- SQLHelper.ExecuteDataSet(RegVerifyCodes.Select_HasSentRegVerifyCode(username, email));
+ // 检查邮箱是否重复
+ SQLHelper.ExecuteDataSet(UserQuery.Select_IsExistEmail(email));
if (SQLHelper.Result == SQLResult.Success)
{
- DateTime RegTime = (DateTime)SQLHelper.DataSet.Tables[0].Rows[0][RegVerifyCodes.Column_RegTime];
- string RegVerifyCode = (string)SQLHelper.DataSet.Tables[0].Rows[0][RegVerifyCodes.Column_RegVerifyCode];
- if ((DateTime.Now - RegTime).TotalMinutes < 10)
- {
- ServerHelper.WriteLine(Server.GetClientName() + $" 十分钟内已向{email}发送过验证码:{RegVerifyCode}");
- }
- returnType = RegInvokeType.InputVerifyCode;
+ ServerHelper.WriteLine(Server.GetClientName() + " 邮箱已被注册");
+ msg = "此邮箱已被注册!";
+ returnType = RegInvokeType.DuplicateEmail;
}
else
{
- // 发送验证码,需要先删除之前过期的验证码
- SQLHelper.NewTransaction();
- SQLHelper.Execute(RegVerifyCodes.Delete_RegVerifyCode(username, email));
- RegVerify = Verification.CreateVerifyCode(VerifyCodeType.NumberVerifyCode, 6);
- SQLHelper.Execute(RegVerifyCodes.Insert_RegVerifyCode(username, email, RegVerify));
+ // 检查验证码是否发送过
+ SQLHelper.ExecuteDataSet(RegVerifyCodes.Select_HasSentRegVerifyCode(username, email));
if (SQLHelper.Result == SQLResult.Success)
{
- SQLHelper.Commit();
- if (MailSender != null)
+ DateTime RegTime = (DateTime)SQLHelper.DataSet.Tables[0].Rows[0][RegVerifyCodes.Column_RegTime];
+ string RegVerifyCode = (string)SQLHelper.DataSet.Tables[0].Rows[0][RegVerifyCodes.Column_RegVerifyCode];
+ if ((DateTime.Now - RegTime).TotalMinutes < 10)
{
- // 发送验证码
- string ServerName = Config.ServerName;
- string Subject = $"[{ServerName}] FunGame 注册验证码";
- string Body = $"亲爱的 {username},
感谢您注册[{ServerName}],您的验证码是 {RegVerify} ,10分钟内有效,请及时输入!
{ServerName}
{DateTimeUtility.GetDateTimeToString(TimeType.LongDateOnly)}";
- string[] To = [email];
- if (MailSender.Send(MailSender.CreateMail(Subject, Body, System.Net.Mail.MailPriority.Normal, true, To)) == MailSendResult.Success)
- {
- ServerHelper.WriteLine(Server.GetClientName() + $" 已向{email}发送验证码:{RegVerify}");
- }
- else
- {
- ServerHelper.WriteLine(Server.GetClientName() + " 无法发送验证码", InvokeMessageType.Error);
- ServerHelper.WriteLine(MailSender.ErrorMsg, InvokeMessageType.Error);
- }
- }
- else // 不使用MailSender的情况
- {
- ServerHelper.WriteLine(Server.GetClientName() + $" 验证码为:{RegVerify},请服务器管理员告知此用户");
+ ServerHelper.WriteLine(Server.GetClientName() + $" 十分钟内已向{email}发送过验证码:{RegVerifyCode}");
}
returnType = RegInvokeType.InputVerifyCode;
}
- else SQLHelper.Rollback();
- }
- }
- }
- }
- else
- {
- // 先检查验证码
- SQLHelper.ExecuteDataSet(RegVerifyCodes.Select_RegVerifyCode(username, email, verifycode));
- if (SQLHelper.Result == SQLResult.Success)
- {
- // 检查验证码是否过期
- DateTime RegTime = (DateTime)SQLHelper.DataSet.Tables[0].Rows[0][RegVerifyCodes.Column_RegTime];
- if ((DateTime.Now - RegTime).TotalMinutes >= 10)
- {
- ServerHelper.WriteLine(Server.GetClientName() + " 验证码已过期");
- msg = "此验证码已过期,请重新注册。";
- SQLHelper.Execute(RegVerifyCodes.Delete_RegVerifyCode(username, email));
- }
- else
- {
- // 注册
- if (RegVerify.Equals(SQLHelper.DataSet.Tables[0].Rows[0][RegVerifyCodes.Column_RegVerifyCode]))
- {
- SQLHelper.NewTransaction();
- ServerHelper.WriteLine("[Reg] UserName: " + username + " Email: " + email);
- SQLHelper.Execute(UserQuery.Insert_Register(username, password, email, Server.Socket?.ClientIP ?? ""));
- if (SQLHelper.Result == SQLResult.Success)
- {
- success = true;
- msg = "注册成功!请牢记您的账号与密码!";
- SQLHelper.Execute(RegVerifyCodes.Delete_RegVerifyCode(username, email));
- SQLHelper.Commit();
- }
else
{
- SQLHelper.Rollback();
- msg = "服务器无法处理您的注册,注册失败!";
+ // 发送验证码,需要先删除之前过期的验证码
+ SQLHelper.NewTransaction();
+ SQLHelper.Execute(RegVerifyCodes.Delete_RegVerifyCode(username, email));
+ _regVerify = Verification.CreateVerifyCode(VerifyCodeType.NumberVerifyCode, 6);
+ SQLHelper.Execute(RegVerifyCodes.Insert_RegVerifyCode(username, email, _regVerify));
+ if (SQLHelper.Result == SQLResult.Success)
+ {
+ SQLHelper.Commit();
+ if (MailSender != null)
+ {
+ // 发送验证码
+ string ServerName = Config.ServerName;
+ string Subject = $"[{ServerName}] FunGame 注册验证码";
+ string Body = $"亲爱的 {username},
感谢您注册[{ServerName}],您的验证码是 {_regVerify} ,10分钟内有效,请及时输入!
{ServerName}
{DateTimeUtility.GetDateTimeToString(TimeType.LongDateOnly)}";
+ string[] To = [email];
+ if (MailSender.Send(MailSender.CreateMail(Subject, Body, System.Net.Mail.MailPriority.Normal, true, To)) == MailSendResult.Success)
+ {
+ ServerHelper.WriteLine(Server.GetClientName() + $" 已向{email}发送验证码:{_regVerify}");
+ }
+ else
+ {
+ ServerHelper.WriteLine(Server.GetClientName() + " 无法发送验证码", InvokeMessageType.Error);
+ ServerHelper.WriteLine(MailSender.ErrorMsg, InvokeMessageType.Error);
+ }
+ }
+ else // 不使用MailSender的情况
+ {
+ ServerHelper.WriteLine(Server.GetClientName() + $" 验证码为:{_regVerify},请服务器管理员告知此用户");
+ }
+ returnType = RegInvokeType.InputVerifyCode;
+ }
+ else SQLHelper.Rollback();
}
}
- else msg = "验证码不正确,请重新输入!";
}
}
- else if (SQLHelper.Result == SQLResult.NotFound) msg = "验证码不正确,请重新输入!";
- else msg = "服务器无法处理您的注册,注册失败!";
+ else
+ {
+ // 先检查验证码
+ SQLHelper.ExecuteDataSet(RegVerifyCodes.Select_RegVerifyCode(username, email, verifycode));
+ if (SQLHelper.Result == SQLResult.Success)
+ {
+ // 检查验证码是否过期
+ DateTime RegTime = (DateTime)SQLHelper.DataSet.Tables[0].Rows[0][RegVerifyCodes.Column_RegTime];
+ if ((DateTime.Now - RegTime).TotalMinutes >= 10)
+ {
+ ServerHelper.WriteLine(Server.GetClientName() + " 验证码已过期");
+ msg = "此验证码已过期,请重新注册。";
+ SQLHelper.Execute(RegVerifyCodes.Delete_RegVerifyCode(username, email));
+ }
+ else
+ {
+ // 注册
+ if (_regVerify.Equals(SQLHelper.DataSet.Tables[0].Rows[0][RegVerifyCodes.Column_RegVerifyCode]))
+ {
+ SQLHelper.NewTransaction();
+ ServerHelper.WriteLine("[Reg] Username: " + username + " Email: " + email);
+ SQLHelper.Execute(UserQuery.Insert_Register(username, password, email, Server.Socket?.ClientIP ?? ""));
+ if (SQLHelper.Result == SQLResult.Success)
+ {
+ success = true;
+ msg = "注册成功!请牢记您的账号与密码!";
+ SQLHelper.Execute(RegVerifyCodes.Delete_RegVerifyCode(username, email));
+ SQLHelper.Commit();
+ }
+ else
+ {
+ SQLHelper.Rollback();
+ msg = "服务器无法处理您的注册,注册失败!";
+ }
+ }
+ else msg = "验证码不正确,请重新输入!";
+ }
+ }
+ else if (SQLHelper.Result == SQLResult.NotFound) msg = "验证码不正确,请重新输入!";
+ else msg = "服务器无法处理您的注册,注册失败!";
+ }
}
}
- ResultData.Add("msg", msg);
- ResultData.Add("type", returnType);
- ResultData.Add("success", success);
+ resultData.Add("msg", msg);
+ resultData.Add("type", returnType);
+ resultData.Add("success", success);
}
#endregion
@@ -578,26 +659,26 @@ namespace Milimoe.FunGame.Server.Controller
///
/// 登录
///
- ///
- ///
- private void Login(Hashtable RequestData, Hashtable ResultData)
+ ///
+ ///
+ private async Task Login(Dictionary requestData, Dictionary resultData)
{
string msg = "";
User user = Factory.GetUser();
- if (RequestData.Count >= 4)
+ if (requestData.Count >= 4)
{
- ServerHelper.WriteLine(Server.GetClientName() + " -> " + DataRequestSet.GetTypeString(_LastRequest), InvokeMessageType.DataRequest);
- string username = DataRequest.GetHashtableJsonObject(RequestData, "username") ?? "";
- string password = DataRequest.GetHashtableJsonObject(RequestData, "password") ?? "";
- string autokey = DataRequest.GetHashtableJsonObject(RequestData, "autokey") ?? "";
- Guid key = DataRequest.GetHashtableJsonObject(RequestData, "key");
+ ServerHelper.WriteLine(Server.GetClientName() + " -> " + DataRequestSet.GetTypeString(_lastRequest), InvokeMessageType.DataRequest);
+ string username = DataRequest.GetDictionaryJsonObject(requestData, "username") ?? "";
+ string password = DataRequest.GetDictionaryJsonObject(requestData, "password") ?? "";
+ string autokey = DataRequest.GetDictionaryJsonObject(requestData, "autokey") ?? "";
+ Guid key = DataRequest.GetDictionaryJsonObject(requestData, "key");
// CheckLogin的情况
if (key != Guid.Empty)
{
- if (Server.IsLoginKey(key))
+ if (IsLoginKey(key))
{
- Server.CheckLogin();
+ await CheckLogin();
user = Server.User;
}
else ServerHelper.WriteLine("客户端发送了错误的秘钥,不允许本次登录。");
@@ -607,166 +688,212 @@ namespace Milimoe.FunGame.Server.Controller
// 验证登录
if (username != null && password != null)
{
- ServerHelper.WriteLine("[" + DataRequestSet.GetTypeString(DataRequestType.Login_Login) + "] UserName: " + username);
- SQLHelper.ExecuteDataSet(UserQuery.Select_Users_LoginQuery(username, password));
- if (SQLHelper.Result == SQLResult.Success)
+ ServerHelper.WriteLine("[" + DataRequestSet.GetTypeString(DataRequestType.Login_Login) + "] Username: " + username);
+ if (SQLHelper != null)
{
- DataSet DsUser = SQLHelper.DataSet;
- if (autokey.Trim() != "")
+ SQLHelper.ExecuteDataSet(UserQuery.Select_Users_LoginQuery(username, password));
+ if (SQLHelper.Result == SQLResult.Success)
{
- SQLHelper.ExecuteDataSet(UserQuery.Select_CheckAutoKey(username, autokey));
- if (SQLHelper.Result == SQLResult.Success)
+ DataSet dsUser = SQLHelper.DataSet;
+ if (autokey.Trim() != "")
{
- ServerHelper.WriteLine("[" + DataRequestSet.GetTypeString(DataRequestType.Login_Login) + "] AutoKey: 已确认");
- }
- else
- {
- msg = "AutoKey不正确,拒绝自动登录!";
- ServerHelper.WriteLine("[" + DataRequestSet.GetTypeString(DataRequestType.Login_Login) + "] " + msg);
+ SQLHelper.ExecuteDataSet(UserQuery.Select_CheckAutoKey(username, autokey));
+ if (SQLHelper.Result == SQLResult.Success)
+ {
+ ServerHelper.WriteLine("[" + DataRequestSet.GetTypeString(DataRequestType.Login_Login) + "] AutoKey: 已确认");
+ }
+ else
+ {
+ msg = "AutoKey不正确,拒绝自动登录!";
+ ServerHelper.WriteLine("[" + DataRequestSet.GetTypeString(DataRequestType.Login_Login) + "] " + msg);
+ }
}
+ key = Guid.NewGuid();
+ PreLogin(dsUser, username, key);
+ resultData.Add("key", key);
+ }
+ else
+ {
+ msg = "用户名或密码不正确。";
+ ServerHelper.WriteLine(msg);
}
- key = Guid.NewGuid();
- Server.PreLogin(DsUser, username, key);
- ResultData.Add("key", key);
- }
- else
- {
- msg = "用户名或密码不正确。";
- ServerHelper.WriteLine(msg);
}
}
}
}
- ResultData.Add("msg", msg);
- ResultData.Add("user", user);
+ resultData.Add("msg", msg);
+ resultData.Add("user", user);
+ }
+
+ ///
+ /// 预登录
+ ///
+ ///
+ ///
+ ///
+ private void PreLogin(DataSet dsuser, string username, Guid checkloginkey)
+ {
+ _dsUser = dsuser;
+ _username = username;
+ _checkLoginKey = checkloginkey;
+ }
+
+ ///
+ /// 确认登录
+ ///
+ private async Task CheckLogin()
+ {
+ // 创建User对象
+ Server.User = Factory.GetUser(_dsUser);
+ // 检查有没有重复登录的情况
+ await Server.ForceLogOutDuplicateLogonUser();
+ // 添加至玩家列表
+ Server.AddUser();
+ Server.GetUsersCount();
+ }
+
+ ///
+ /// 检查LoginKey
+ ///
+ ///
+ ///
+ private bool IsLoginKey(Guid key)
+ {
+ return key == _checkLoginKey;
}
///
/// 接收并验证找回密码时的验证码
///
- ///
- ///
- private void ForgetPassword(Hashtable RequestData, Hashtable ResultData)
+ ///
+ ///
+ private void ForgetPassword(Dictionary requestData, Dictionary resultData)
{
string msg = "无法找回您的密码,请稍后再试。"; // 返回的验证信息
- if (RequestData.Count >= 3)
+ if (requestData.Count >= 3)
{
- ServerHelper.WriteLine(Server.GetClientName() + " -> " + DataRequestSet.GetTypeString(_LastRequest), InvokeMessageType.DataRequest);
- string username = DataRequest.GetHashtableJsonObject(RequestData, ForgetVerifyCodes.Column_Username) ?? "";
- string email = DataRequest.GetHashtableJsonObject(RequestData, ForgetVerifyCodes.Column_Email) ?? "";
- string verifycode = DataRequest.GetHashtableJsonObject(RequestData, ForgetVerifyCodes.Column_ForgetVerifyCode) ?? "";
+ ServerHelper.WriteLine(Server.GetClientName() + " -> " + DataRequestSet.GetTypeString(_lastRequest), InvokeMessageType.DataRequest);
+ string username = DataRequest.GetDictionaryJsonObject(requestData, ForgetVerifyCodes.Column_Username) ?? "";
+ string email = DataRequest.GetDictionaryJsonObject(requestData, ForgetVerifyCodes.Column_Email) ?? "";
+ string verifycode = DataRequest.GetDictionaryJsonObject(requestData, ForgetVerifyCodes.Column_ForgetVerifyCode) ?? "";
// 客户端发来了验证码就进行验证,没有发就生成
if (verifycode.Trim() != "")
{
// 先检查验证码
- SQLHelper.ExecuteDataSet(ForgetVerifyCodes.Select_ForgetVerifyCode(username, email, verifycode));
- if (SQLHelper.Result == SQLResult.Success)
+ if (SQLHelper != null)
{
- // 检查验证码是否过期
- DateTime SendTime = (DateTime)SQLHelper.DataSet.Tables[0].Rows[0][ForgetVerifyCodes.Column_SendTime];
- if ((DateTime.Now - SendTime).TotalMinutes >= 10)
+ SQLHelper.ExecuteDataSet(ForgetVerifyCodes.Select_ForgetVerifyCode(username, email, verifycode));
+ if (SQLHelper.Result == SQLResult.Success)
{
- ServerHelper.WriteLine(Server.GetClientName() + " 验证码已过期");
- msg = "此验证码已过期,请重新找回密码。";
- SQLHelper.Execute(ForgetVerifyCodes.Delete_ForgetVerifyCode(username, email));
- }
- else
- {
- // 检查验证码是否正确
- if (ForgetVerify.Equals(SQLHelper.DataSet.Tables[0].Rows[0][ForgetVerifyCodes.Column_ForgetVerifyCode]))
+ // 检查验证码是否过期
+ DateTime SendTime = (DateTime)SQLHelper.DataSet.Tables[0].Rows[0][ForgetVerifyCodes.Column_SendTime];
+ if ((DateTime.Now - SendTime).TotalMinutes >= 10)
{
- ServerHelper.WriteLine("[ForgerPassword] UserName: " + username + " Email: " + email);
+ ServerHelper.WriteLine(Server.GetClientName() + " 验证码已过期");
+ msg = "此验证码已过期,请重新找回密码。";
SQLHelper.Execute(ForgetVerifyCodes.Delete_ForgetVerifyCode(username, email));
- msg = "";
}
- else msg = "验证码不正确,请重新输入!";
+ else
+ {
+ // 检查验证码是否正确
+ if (_forgetVerify.Equals(SQLHelper.DataSet.Tables[0].Rows[0][ForgetVerifyCodes.Column_ForgetVerifyCode]))
+ {
+ ServerHelper.WriteLine("[ForgerPassword] Username: " + username + " Email: " + email);
+ SQLHelper.Execute(ForgetVerifyCodes.Delete_ForgetVerifyCode(username, email));
+ msg = "";
+ }
+ else msg = "验证码不正确,请重新输入!";
+ }
}
+ else msg = "验证码不正确,请重新输入!";
}
- else msg = "验证码不正确,请重新输入!";
}
else
{
// 检查账号和邮箱是否匹配
- SQLHelper.ExecuteDataSet(UserQuery.Select_CheckEmailWithUsername(username, email));
- if (SQLHelper.Result != SQLResult.Success)
+ if (SQLHelper != null)
{
- msg = "此邮箱未绑定此账号,请重试!";
- }
- else
- {
- // 检查验证码是否发送过和是否过期
- SQLHelper.ExecuteDataSet(ForgetVerifyCodes.Select_HasSentForgetVerifyCode(username, email));
- if (SQLHelper.Result != SQLResult.Success || (DateTime.Now - ((DateTime)SQLHelper.DataSet.Tables[0].Rows[0][ForgetVerifyCodes.Column_SendTime])).TotalMinutes >= 10)
+ SQLHelper.ExecuteDataSet(UserQuery.Select_CheckEmailWithUsername(username, email));
+ if (SQLHelper.Result != SQLResult.Success)
{
- // 发送验证码,需要先删除之前过期的验证码
- SQLHelper.Execute(ForgetVerifyCodes.Delete_ForgetVerifyCode(username, email));
- ForgetVerify = Verification.CreateVerifyCode(VerifyCodeType.NumberVerifyCode, 6);
- SQLHelper.Execute(ForgetVerifyCodes.Insert_ForgetVerifyCode(username, email, ForgetVerify));
- if (SQLHelper.Result == SQLResult.Success)
- {
- if (MailSender != null)
- {
- // 发送验证码
- string ServerName = Config.ServerName;
- string Subject = $"[{ServerName}] FunGame 找回密码验证码";
- string Body = $"亲爱的 {username},
您正在找回[{ServerName}]账号的密码,您的验证码是 {ForgetVerify} ,10分钟内有效,请及时输入!
{ServerName}
{DateTimeUtility.GetDateTimeToString(TimeType.LongDateOnly)}";
- string[] To = [email];
- if (MailSender.Send(MailSender.CreateMail(Subject, Body, System.Net.Mail.MailPriority.Normal, true, To)) == MailSendResult.Success)
- {
- ServerHelper.WriteLine(Server.GetClientName() + $" 已向{email}发送验证码:{ForgetVerify}");
- msg = "";
- }
- else
- {
- ServerHelper.WriteLine(Server.GetClientName() + " 无法发送验证码");
- ServerHelper.WriteLine(MailSender.ErrorMsg);
- }
- }
- else // 不使用MailSender的情况
- {
- ServerHelper.WriteLine(Server.GetClientName() + $" 验证码为:{ForgetVerify},请服务器管理员告知此用户");
- msg = "";
- }
- }
+ msg = "此邮箱未绑定此账号,请重试!";
}
else
{
- // 发送过验证码且验证码没有过期
- string ForgetVerifyCode = (string)SQLHelper.DataSet.Tables[0].Rows[0][ForgetVerifyCodes.Column_ForgetVerifyCode];
- ServerHelper.WriteLine(Server.GetClientName() + $" 十分钟内已向{email}发送过验证码:{ForgetVerifyCode}");
- msg = "";
+ // 检查验证码是否发送过和是否过期
+ SQLHelper.ExecuteDataSet(ForgetVerifyCodes.Select_HasSentForgetVerifyCode(username, email));
+ if (SQLHelper.Result != SQLResult.Success || (DateTime.Now - ((DateTime)SQLHelper.DataSet.Tables[0].Rows[0][ForgetVerifyCodes.Column_SendTime])).TotalMinutes >= 10)
+ {
+ // 发送验证码,需要先删除之前过期的验证码
+ SQLHelper.Execute(ForgetVerifyCodes.Delete_ForgetVerifyCode(username, email));
+ _forgetVerify = Verification.CreateVerifyCode(VerifyCodeType.NumberVerifyCode, 6);
+ SQLHelper.Execute(ForgetVerifyCodes.Insert_ForgetVerifyCode(username, email, _forgetVerify));
+ if (SQLHelper.Result == SQLResult.Success)
+ {
+ if (MailSender != null)
+ {
+ // 发送验证码
+ string ServerName = Config.ServerName;
+ string Subject = $"[{ServerName}] FunGame 找回密码验证码";
+ string Body = $"亲爱的 {username},
您正在找回[{ServerName}]账号的密码,您的验证码是 {_forgetVerify} ,10分钟内有效,请及时输入!
{ServerName}
{DateTimeUtility.GetDateTimeToString(TimeType.LongDateOnly)}";
+ string[] To = [email];
+ if (MailSender.Send(MailSender.CreateMail(Subject, Body, System.Net.Mail.MailPriority.Normal, true, To)) == MailSendResult.Success)
+ {
+ ServerHelper.WriteLine(Server.GetClientName() + $" 已向{email}发送验证码:{_forgetVerify}");
+ msg = "";
+ }
+ else
+ {
+ ServerHelper.WriteLine(Server.GetClientName() + " 无法发送验证码");
+ ServerHelper.WriteLine(MailSender.ErrorMsg);
+ }
+ }
+ else // 不使用MailSender的情况
+ {
+ ServerHelper.WriteLine(Server.GetClientName() + $" 验证码为:{_forgetVerify},请服务器管理员告知此用户");
+ msg = "";
+ }
+ }
+ }
+ else
+ {
+ // 发送过验证码且验证码没有过期
+ string ForgetVerifyCode = (string)SQLHelper.DataSet.Tables[0].Rows[0][ForgetVerifyCodes.Column_ForgetVerifyCode];
+ ServerHelper.WriteLine(Server.GetClientName() + $" 十分钟内已向{email}发送过验证码:{ForgetVerifyCode}");
+ msg = "";
+ }
}
}
}
}
- ResultData.Add("msg", msg);
+ resultData.Add("msg", msg);
}
///
/// 更新用户的密码
///
- ///
- ///
- private void UpdatePassword(Hashtable RequestData, Hashtable ResultData)
+ ///
+ ///
+ private void UpdatePassword(Dictionary requestData, Dictionary resultData)
{
string msg = "无法更新您的密码,请稍后再试。";
- if (RequestData.Count >= 2)
+ if (requestData.Count >= 2)
{
- ServerHelper.WriteLine(Server.GetClientName() + " -> " + DataRequestSet.GetTypeString(_LastRequest), InvokeMessageType.DataRequest);
- string username = DataRequest.GetHashtableJsonObject(RequestData, UserQuery.Column_Username) ?? "";
- string password = DataRequest.GetHashtableJsonObject(RequestData, UserQuery.Column_Password) ?? "";
+ ServerHelper.WriteLine(Server.GetClientName() + " -> " + DataRequestSet.GetTypeString(_lastRequest), InvokeMessageType.DataRequest);
+ string username = DataRequest.GetDictionaryJsonObject(requestData, UserQuery.Column_Username) ?? "";
+ string password = DataRequest.GetDictionaryJsonObject(requestData, UserQuery.Column_Password) ?? "";
if (username.Trim() != "" && password.Trim() != "")
{
Server.SQLHelper?.Execute(UserQuery.Update_Password(username, password));
- if (SQLHelper.Success)
+ if (SQLHelper?.Success ?? false)
{
// 更新成功返回空值
msg = "";
}
}
}
- ResultData.Add("msg", msg);
+ resultData.Add("msg", msg);
}
#endregion
@@ -776,17 +903,125 @@ namespace Milimoe.FunGame.Server.Controller
///
/// 获取房间内玩家数量
///
- ///
- ///
- private void GetRoomPlayerCount(Hashtable RequestData, Hashtable ResultData)
+ ///
+ ///
+ private void GetRoomPlayerCount(Dictionary requestData, Dictionary resultData)
{
string roomid = "-1";
- if (RequestData.Count >= 1)
+ if (requestData.Count >= 1)
{
- ServerHelper.WriteLine(Server.GetClientName() + " -> " + DataRequestSet.GetTypeString(_LastRequest), InvokeMessageType.DataRequest);
- roomid = DataRequest.GetHashtableJsonObject(RequestData, "roomid") ?? "-1";
+ ServerHelper.WriteLine(Server.GetClientName() + " -> " + DataRequestSet.GetTypeString(_lastRequest), InvokeMessageType.DataRequest);
+ roomid = DataRequest.GetDictionaryJsonObject(requestData, "roomid") ?? "-1";
}
- ResultData.Add("count", Config.RoomList.GetPlayerCount(roomid));
+ resultData.Add("count", Config.RoomList.GetUserCount(roomid));
+ }
+
+ ///
+ /// 开始匹配
+ ///
+ ///
+ ///
+ private void StartMatching(RoomType type, User user)
+ {
+ _isMatching = true;
+ ServerHelper.WriteLine(Server.GetClientName() + " 开始匹配。类型:" + RoomSet.GetTypeString(type));
+ TaskUtility.NewTask(async () =>
+ {
+ if (_isMatching)
+ {
+ Room room = await MatchingRoom(type, user);
+ if (_isMatching && Server.Socket != null)
+ {
+ await Server.Send(SocketMessageType.MatchRoom, room);
+ }
+ _isMatching = false;
+ }
+ }).OnError(e =>
+ {
+ ServerHelper.Error(e);
+ _isMatching = false;
+ });
+ }
+
+ ///
+ /// 终止匹配
+ ///
+ private void StopMatching()
+ {
+ if (_isMatching)
+ {
+ ServerHelper.WriteLine(Server.GetClientName() + " 取消了匹配。");
+ _isMatching = false;
+ }
+ }
+
+ ///
+ /// 匹配线程
+ ///
+ ///
+ ///
+ ///
+ private async Task MatchingRoom(RoomType roomtype, User user)
+ {
+ int i = 1; // Elo扩大系数
+ double time = 0; // 已经匹配的时间
+ double expandInterval = 10; // 扩大匹配范围的间隔时间
+ double maxTime = 50; // 最大匹配时间
+
+ while (_isMatching)
+ {
+ // 匹配房间类型(如果是All,则匹配所有房间)
+ List targets;
+ if (roomtype == RoomType.All)
+ {
+ targets = [.. Config.RoomList.ListRoom.Where(r => r.RoomState == RoomState.Created || r.RoomState == RoomState.Matching)];
+ }
+ else
+ {
+ targets = [.. Config.RoomList.ListRoom.Where(r => (r.RoomState == RoomState.Created || r.RoomState == RoomState.Matching) && r.RoomType == roomtype)];
+ }
+
+ // 如果匹配停止,则退出
+ if (!_isMatching) break;
+
+ foreach (Room room in targets)
+ {
+ // 获取当前房间的玩家列表
+ List players = Config.RoomList.GetUsers(room.Roomid);
+ if (players.Count > 0)
+ {
+ // 计算房间平均Elo
+ double avgElo = players.Sum(u => u.Statistics.EloStats.TryGetValue(0, out double value) ? value : 0) / players.Count;
+ double userElo = user.Statistics.EloStats.TryGetValue(0, out double userValue) ? userValue : 0;
+
+ // 匹配Elo范围,随着时间增加,范围逐渐扩大
+ if (userElo >= avgElo - (300 * i) && userElo <= avgElo + (300 * i))
+ {
+ // 找到匹配的房间,立即返回
+ return room;
+ }
+ }
+ }
+
+ // 如果匹配停止,则退出
+ if (!_isMatching) break;
+
+ // 检查是否已经过了10秒,扩大匹配范围
+ if (time >= expandInterval * i)
+ {
+ i++;
+ }
+ // 达到最大匹配时间后不再匹配Elo,直接返回第一个房间
+ if (time >= maxTime)
+ {
+ return targets.FirstOrDefault() ?? General.HallInstance;
+ }
+
+ await Task.Delay(100);
+ time += 0.1;
+ }
+
+ return General.HallInstance;
}
#endregion
diff --git a/FunGame.Server/FunGame.Server.csproj b/FunGame.Server/FunGame.Server.csproj
index c37dfb7..0fa6df9 100644
--- a/FunGame.Server/FunGame.Server.csproj
+++ b/FunGame.Server/FunGame.Server.csproj
@@ -16,20 +16,34 @@
1.0
FunGameServer
Milimoe.$(MSBuildProjectName.Replace(" ", "_"))
+ app.manifest
embedded
+ 1701;1702;IDE0130
embedded
+ 1701;1702;IDE0130
+
+
+
+
+
+
+
+
+
+
+
@@ -38,15 +52,6 @@
..\..\FunGame.Core\bin\Debug\net8.0\FunGame.Core.dll
-
- ..\bin\Debug\net7.0\MySql.Data.dll
-
-
- ..\bin\Debug\net7.0\System.Configuration.ConfigurationManager.dll
-
-
- ..\bin\Debug\net7.0\System.Security.Permissions.dll
-
diff --git a/FunGame.Server/Main.cs b/FunGame.Server/Main.cs
index c1c79de..45147f5 100644
--- a/FunGame.Server/Main.cs
+++ b/FunGame.Server/Main.cs
@@ -1,10 +1,8 @@
-using System.Collections;
-using System.Collections.Generic;
-using Milimoe.FunGame;
+using Milimoe.FunGame;
using Milimoe.FunGame.Core.Api.Utility;
-using Milimoe.FunGame.Core.Library.Common.Addon;
using Milimoe.FunGame.Core.Library.Common.Network;
using Milimoe.FunGame.Core.Library.Constant;
+using Milimoe.FunGame.Server.Controller;
using Milimoe.FunGame.Server.Model;
using Milimoe.FunGame.Server.Others;
using Milimoe.FunGame.Server.Utility;
@@ -13,7 +11,8 @@ Console.Title = Config.ServerName;
Console.WriteLine(FunGameInfo.GetInfo(Config.FunGameType));
bool Running = true;
-ServerSocket? ListeningSocket = null;
+SocketListener? SocketListener = null;
+HTTPListener? WebSocketListener = null;
StartServer();
@@ -32,7 +31,7 @@ while (Running)
Running = false;
break;
case OrderDictionary.Restart:
- if (ListeningSocket == null)
+ if (SocketListener is null || WebSocketListener is null)
{
ServerHelper.WriteLine("重启服务器");
StartServer();
@@ -40,7 +39,14 @@ while (Running)
else ServerHelper.WriteLine("服务器正在运行,拒绝重启!");
break;
default:
- ConsoleModel.Order(ListeningSocket, order);
+ if (SocketListener != null)
+ {
+ await ConsoleModel.Order(SocketListener, order);
+ }
+ else
+ {
+ await ConsoleModel.Order(WebSocketListener, order);
+ }
break;
}
}
@@ -51,7 +57,7 @@ Console.ReadKey();
void StartServer()
{
- Task t = Task.Factory.StartNew(() =>
+ TaskUtility.NewTask(async () =>
{
try
{
@@ -60,7 +66,7 @@ void StartServer()
ServerHelper.InitOrderList();
// 读取游戏模组
- if (!GetGameModuleList())
+ if (!Config.GetGameModuleList())
{
ServerHelper.WriteLine("服务器似乎未安装任何游戏模组,请检查是否正确安装它们。");
}
@@ -83,51 +89,135 @@ void StartServer()
// 创建全局SQLHelper
Config.InitSQLHelper();
- // 创建监听
- ListeningSocket = ServerSocket.StartListening();
+ // 使用Socket还是WebSocket
+ bool useWebSocket = Config.UseWebSocket;
- // 开始监听连接
- AddBannedList(ListeningSocket);
- ServerHelper.WriteLine("Listen -> " + Config.ServerPort);
- ServerHelper.WriteLine("服务器启动成功,开始监听 . . .");
-
- if (Config.ServerNotice != "")
- ServerHelper.WriteLine("\n\n********** 服务器公告 **********\n\n" + Config.ServerNotice + "\n");
- else
- ServerHelper.WriteLine("无法读取服务器公告");
-
- while (Running)
+ if (!useWebSocket)
{
- ClientSocket socket;
- string clientip = "";
- try
+ // 创建监听
+ SocketListener listener = SocketListener.StartListening(Config.ServerPort, Config.MaxPlayers);
+ SocketListener = listener;
+
+ // 开始监听连接
+ listener.BannedList.AddRange(Config.ServerBannedList);
+ ServerHelper.WriteLine("Listen -> " + Config.ServerPort);
+ ServerHelper.WriteLine("服务器启动成功,开始监听 . . .");
+
+ if (Config.ServerNotice != "")
+ ServerHelper.WriteLine("\n\n********** 服务器公告 **********\n\n" + Config.ServerNotice + "\n");
+ else
+ ServerHelper.WriteLine("无法读取服务器公告");
+
+ while (Running)
{
- Guid token = Guid.NewGuid();
- socket = ListeningSocket.Accept(token);
- clientip = socket.ClientIP;
- Config.ConnectingPlayerCount++;
- // 开始处理客户端连接请求
- bool isDebugMode = false;
- if (Connect(socket, token, clientip, ref isDebugMode))
+ ServerSocket socket;
+ string clientip = "";
+ try
{
- ServerModel ClientModel = new(ListeningSocket, socket, Running, isDebugMode);
- Task t = Task.Factory.StartNew(() =>
+ Guid token = Guid.NewGuid();
+ socket = listener.Accept(token);
+
+ TaskUtility.NewTask(async () =>
{
- ClientModel.Start();
+ clientip = socket.ClientIP;
+ Config.ConnectingPlayerCount++;
+ bool isConnected = false;
+ bool isDebugMode = false;
+
+ // 开始处理客户端连接请求
+ SocketObject[] objs = socket.Receive();
+ (isConnected, isDebugMode) = await ConnectController.Connect(listener, socket, token, clientip, objs);
+ if (isConnected)
+ {
+ ServerModel ClientModel = new(listener, socket, isDebugMode);
+ ClientModel.SetClientName(clientip);
+ Task t = Task.Run(ClientModel.Start);
+ }
+ else
+ {
+ ServerHelper.WriteLine(ServerHelper.MakeClientName(clientip) + " 连接失败。", InvokeMessageType.Core);
+ }
+ Config.ConnectingPlayerCount--;
+ }).OnError(e =>
+ {
+ if (--Config.ConnectingPlayerCount < 0) Config.ConnectingPlayerCount = 0;
+ ServerHelper.WriteLine(ServerHelper.MakeClientName(clientip) + " 中断连接!", InvokeMessageType.Core);
+ ServerHelper.Error(e);
});
- ClientModel.SetClientName(clientip);
}
- else
+ catch (Exception e)
{
- ServerHelper.WriteLine(ServerHelper.MakeClientName(clientip) + " 连接失败。", InvokeMessageType.Core);
+ ServerHelper.Error(e);
}
- Config.ConnectingPlayerCount--;
}
- catch (Exception e)
+ }
+ else
+ {
+ if (Config.WebSocketAddress == "*")
{
- if (--Config.ConnectingPlayerCount < 0) Config.ConnectingPlayerCount = 0;
- ServerHelper.WriteLine(ServerHelper.MakeClientName(clientip) + " 中断连接!", InvokeMessageType.Core);
- ServerHelper.Error(e);
+ ServerHelper.WriteLine("WebSocket 监听 * 地址要求权限提升,如果提示拒绝访问请以管理员身份运行服务器。", InvokeMessageType.Warning);
+ }
+
+ // 创建监听
+ HTTPListener listener = HTTPListener.StartListening(Config.WebSocketAddress, Config.WebSocketPort, Config.WebSocketSubUrl, Config.WebSocketSSL);
+ WebSocketListener = listener;
+
+ // 开始监听连接
+ listener.BannedList.AddRange(Config.ServerBannedList);
+ ServerHelper.WriteLine("Listen -> " + listener.Instance.Prefixes.First());
+ ServerHelper.WriteLine("服务器启动成功,开始监听 . . .");
+
+ if (Config.ServerNotice != "")
+ ServerHelper.WriteLine("\n\n********** 服务器公告 **********\n\n" + Config.ServerNotice + "\n");
+ else
+ ServerHelper.WriteLine("无法读取服务器公告");
+
+ while (Running)
+ {
+ ServerWebSocket socket;
+ string clientip = "";
+ try
+ {
+ Guid token = Guid.NewGuid();
+ socket = await listener.Accept(token);
+
+ TaskUtility.NewTask(async () =>
+ {
+ clientip = socket.ClientIP;
+ Config.ConnectingPlayerCount++;
+ bool isConnected = false;
+ bool isDebugMode = false;
+
+ // 开始处理客户端连接请求
+ IEnumerable objs = [];
+ while (!objs.Any(o => o.SocketType == SocketMessageType.Connect))
+ {
+ objs = objs.Union(await socket.ReceiveAsync());
+ }
+ (isConnected, isDebugMode) = await ConnectController.Connect(listener, socket, token, clientip, objs.Where(o => o.SocketType == SocketMessageType.Connect));
+ if (isConnected)
+ {
+ ServerModel ClientModel = new(listener, socket, isDebugMode);
+ ClientModel.SetClientName(clientip);
+ Task t = Task.Run(ClientModel.Start);
+ }
+ else
+ {
+ ServerHelper.WriteLine(ServerHelper.MakeClientName(clientip) + " 连接失败。", InvokeMessageType.Core);
+ await socket.CloseAsync();
+ }
+ Config.ConnectingPlayerCount--;
+ }).OnError(e =>
+ {
+ if (--Config.ConnectingPlayerCount < 0) Config.ConnectingPlayerCount = 0;
+ ServerHelper.WriteLine(ServerHelper.MakeClientName(clientip) + " 中断连接!", InvokeMessageType.Core);
+ ServerHelper.Error(e);
+ });
+ }
+ catch (Exception e)
+ {
+ ServerHelper.Error(e);
+ }
}
}
}
@@ -135,158 +225,31 @@ void StartServer()
{
if (e.Message.Equals(new ServerErrorException().Message))
{
- if (ListeningSocket != null)
+ if (SocketListener != null)
{
- ListeningSocket.Close();
- ListeningSocket = null;
+ SocketListener.Close();
+ SocketListener = null;
+ }
+ if (WebSocketListener != null)
+ {
+ WebSocketListener.Close();
+ WebSocketListener = null;
}
}
ServerHelper.Error(e);
}
finally
{
- if (ListeningSocket != null)
+ if (SocketListener != null)
{
- ListeningSocket.Close();
- ListeningSocket = null;
+ SocketListener.Close();
+ SocketListener = null;
+ }
+ if (WebSocketListener != null)
+ {
+ WebSocketListener.Close();
+ WebSocketListener = null;
}
}
});
}
-
-bool GetGameModuleList()
-{
- List supported = [];
- // 构建AddonController
- Hashtable delegates = [];
- delegates.Add("WriteLine", new Action(msg => ServerHelper.WriteLine(msg, InvokeMessageType.GameModule)));
- delegates.Add("Error", new Action(ServerHelper.Error));
- // 读取modules目录下的模组
- Config.GameModuleLoader = GameModuleLoader.LoadGameModules(Config.FunGameType, delegates);
- foreach (GameModule module in Config.GameModuleLoader.AssociatedServers.Keys)
- {
- bool check = true;
- // 检查模组是否存在对应的模组服务器
- if (Config.GameModuleLoader.AssociatedServers[module] is null)
- {
- ServerHelper.WriteLine("[GameModule] Load Failed: " + module.Name + " 缺少模组服务器");
- check = false;
- }
- // 检查模组是否有相对应的地图
- if (!Config.GameModuleLoader.Maps.ContainsKey(module.DefaultMap))
- {
- ServerHelper.WriteLine("[GameModule] Load Failed: " + module + " 没有找到相对应的地图,加载失败");
- check = false;
- }
- if (check)
- {
- supported.Add(module.Name);
- }
- }
- // 设置全局
- Config.GameModuleSupported = supported.Distinct().ToArray();
- foreach (string modename in Config.GameModuleSupported)
- {
- ServerHelper.WriteLine("[GameModule] Loaded: " + modename);
- }
-
- return Config.GameModuleSupported.Length > 0;
-}
-
-bool Connect(ClientSocket socket, Guid token, string clientip, ref bool isDebugMode)
-{
- // 接收客户端消息
- foreach (SocketObject read in socket.Receive())
- {
- if (read.SocketType == SocketMessageType.Connect)
- {
- if (Config.ConnectingPlayerCount + Config.OnlinePlayerCount > Config.MaxPlayers)
- {
- SendRefuseConnect(socket, "服务器可接受的连接数量已上限!");
- ServerHelper.WriteLine("服务器可接受的连接数量已上限!", InvokeMessageType.Core);
- return false;
- }
- ServerHelper.WriteLine(ServerHelper.MakeClientName(clientip) + " 正在连接服务器 . . .", InvokeMessageType.Core);
- if (IsIPBanned(ListeningSocket, clientip))
- {
- SendRefuseConnect(socket, "服务器已拒绝黑名单用户连接。");
- ServerHelper.WriteLine("检测到 " + ServerHelper.MakeClientName(clientip) + " 为黑名单用户,已禁止其连接!", InvokeMessageType.Core);
- return false;
- }
-
- ServerHelper.WriteLine("[" + SocketSet.GetTypeString(read.SocketType) + "] " + ServerHelper.MakeClientName(socket.ClientIP), InvokeMessageType.Core);
-
- // 读取参数
- // 参数1:客户端的游戏模组列表,没有服务器的需要拒绝
- string[] modes = read.GetParam(0) ?? [];
- // 参数2:客户端是否开启了开发者模式,开启开发者模式部分功能不可用
- isDebugMode = read.GetParam(1);
- if (isDebugMode) ServerHelper.WriteLine("客户端已开启开发者模式");
-
- string msg = "";
- List ClientDontHave = [];
- string strDontHave = string.Join("\r\n", Config.GameModuleSupported.Where(mode => !modes.Contains(mode)));
- if (strDontHave != "")
- {
- strDontHave = "客户端缺少服务器所需的模组:" + strDontHave;
- ServerHelper.WriteLine(strDontHave, InvokeMessageType.Core);
- msg += strDontHave;
- }
-
- if (msg == "" && socket.Send(SocketMessageType.Connect, true, msg, token, Config.ServerName, Config.ServerNotice) == SocketResult.Success)
- {
- ServerHelper.WriteLine(ServerHelper.MakeClientName(socket.ClientIP) + " <- " + "已确认连接", InvokeMessageType.Core);
- return true;
- }
- else if (msg != "" && socket.Send(SocketMessageType.Connect, false, msg) == SocketResult.Success)
- {
- ServerHelper.WriteLine(ServerHelper.MakeClientName(socket.ClientIP) + " <- " + "拒绝连接", InvokeMessageType.Core);
- return false;
- }
- else
- {
- ServerHelper.WriteLine("无法传输数据,与客户端的连接可能丢失。", InvokeMessageType.Core);
- return false;
- }
- }
- }
-
- SendRefuseConnect(socket, "服务器已拒绝连接。");
- ServerHelper.WriteLine("客户端发送了不符合FunGame规定的字符,拒绝连接。", InvokeMessageType.Core);
- return false;
-}
-
-bool SendRefuseConnect(ClientSocket socket, string msg)
-{
- // 发送消息给客户端
- msg = "连接被拒绝,如有疑问请联系服务器管理员:" + msg;
- if (socket.Send(SocketMessageType.Connect, false, msg) == SocketResult.Success)
- {
- ServerHelper.WriteLine(ServerHelper.MakeClientName(socket.ClientIP) + " <- " + "已拒绝连接", InvokeMessageType.Core);
- return true;
- }
- else
- {
- ServerHelper.WriteLine("无法传输数据,与客户端的连接可能丢失。", InvokeMessageType.Core);
- return false;
- }
-}
-
-void AddBannedList(ServerSocket server)
-{
- string[] bans = Config.ServerBannedList.Split(',');
- foreach (string banned in bans)
- {
- server.BannedList.Add(banned.Trim());
- }
-}
-
-bool IsIPBanned(ServerSocket server, string ip)
-{
- string[] strs = ip.Split(":");
- if (strs.Length == 2 && server.BannedList.Contains(strs[0]))
- {
- return true;
- }
- return false;
-}
\ No newline at end of file
diff --git a/FunGame.Server/Models/ConsoleModel.cs b/FunGame.Server/Models/ConsoleModel.cs
index ada59b8..344f11c 100644
--- a/FunGame.Server/Models/ConsoleModel.cs
+++ b/FunGame.Server/Models/ConsoleModel.cs
@@ -1,5 +1,4 @@
using Milimoe.FunGame.Core.Interface.Base;
-using Milimoe.FunGame.Core.Library.Common.Network;
using Milimoe.FunGame.Server.Others;
using Milimoe.FunGame.Server.Utility;
@@ -7,7 +6,7 @@ namespace Milimoe.FunGame.Server.Model
{
public class ConsoleModel
{
- public static void Order(ServerSocket? server, string order)
+ public static async Task Order(ISocketListener? server, string order) where T : ISocketMessageProcessor
{
try
{
@@ -19,7 +18,7 @@ namespace Milimoe.FunGame.Server.Model
string client = Console.ReadLine() ?? "";
if (client != "" && server != null)
{
- ((ServerModel)server.GetClient(client))?.Kick("您已被服务器管理员踢出此服务器。");
+ await Kick((ServerModel)server.ClientList[client]);
}
break;
}
@@ -29,7 +28,7 @@ namespace Milimoe.FunGame.Server.Model
string user = Console.ReadLine() ?? "";
if (user != "" && server != null)
{
- ((ServerModel)server.GetUser(user))?.ForceLogOut("您已被服务器管理员强制下线。");
+ await ForceLogOut((ServerModel)server.UserList[user]);
}
break;
}
@@ -46,7 +45,7 @@ namespace Milimoe.FunGame.Server.Model
ShowUsers(server);
break;
case OrderDictionary.Help:
- ServerHelper.WriteLine("Milimoe -> 帮助");
+ ShowHelp();
break;
}
}
@@ -56,7 +55,17 @@ namespace Milimoe.FunGame.Server.Model
}
}
- private static void ShowClients(ServerSocket? server)
+ public static async Task Kick(ServerModel clientModel) where T : ISocketMessageProcessor
+ {
+ await clientModel.Kick("您已被服务器管理员踢出此服务器。");
+ }
+
+ public static async Task ForceLogOut(ServerModel clientModel) where T : ISocketMessageProcessor
+ {
+ await clientModel.ForceLogOut("您已被服务器管理员强制下线。");
+ }
+
+ public static void ShowClients(ISocketListener? server) where T : ISocketMessageProcessor
{
if (server != null)
{
@@ -69,7 +78,7 @@ namespace Milimoe.FunGame.Server.Model
}
}
- private static void ShowUsers(ServerSocket? server)
+ public static void ShowUsers(ISocketListener? server) where T : ISocketMessageProcessor
{
if (server != null)
{
@@ -81,5 +90,10 @@ namespace Milimoe.FunGame.Server.Model
}
}
}
+
+ public static void ShowHelp()
+ {
+ ServerHelper.WriteLine("Milimoe -> 帮助");
+ }
}
}
diff --git a/FunGame.Server/Models/ServerModel.cs b/FunGame.Server/Models/ServerModel.cs
index 6c96c04..7567de2 100644
--- a/FunGame.Server/Models/ServerModel.cs
+++ b/FunGame.Server/Models/ServerModel.cs
@@ -1,5 +1,4 @@
-using System.Collections;
-using System.Data;
+using System.Data;
using Milimoe.FunGame.Core.Api.Transmittal;
using Milimoe.FunGame.Core.Api.Utility;
using Milimoe.FunGame.Core.Entity;
@@ -14,191 +13,225 @@ using Milimoe.FunGame.Server.Utility;
namespace Milimoe.FunGame.Server.Model
{
- public class ServerModel : IServerModel
+ public class ServerModel : IServerModel where T : ISocketMessageProcessor
{
/**
* Public
*/
- public bool Running => _Running;
- public ClientSocket? Socket => _Socket;
- public string ClientName => _ClientName;
- public User User => _User;
- public Room Room
- {
- get => _Room;
- set => _Room = value;
- }
- public MySQLHelper? SQLHelper => _SQLHelper;
- public MailSender? MailSender => _MailSender;
+ public bool Running => _running;
+ public ISocketMessageProcessor Socket { get; }
+ public ISocketListener Listener { get; }
+ public DataRequestController DataRequestController { get; }
+ public Guid Token => Socket?.Token ?? Guid.Empty;
+ public string ClientName => _clientName;
+ public User User { get; set; } = General.UnknownUserInstance;
+ public Room InRoom { get; set; } = General.HallInstance;
+ public SQLHelper? SQLHelper => _sqlHelper;
+ public MailSender? MailSender => _mailer;
public bool IsDebugMode { get; }
+ public GameModuleServer? NowGamingServer { get; set; } = null;
/**
- * Private
+ * protected
*/
- private GameModuleServer? NowGamingServer = null;
+ protected bool _running = true;
+ protected int _failedTimes = 0; // 超过一定次数断开连接
+ protected string _clientName = "";
+ protected SQLHelper? _sqlHelper = null;
+ protected MailSender? _mailer = null;
+ protected string _username = "";
+ protected long _loginTime = 0;
+ protected long _logoutTime = 0;
- private ClientSocket? _Socket = null;
- private bool _Running = false;
- private User _User = General.UnknownUserInstance;
- private Room _Room = General.HallInstance;
- private string _ClientName = "";
- public MySQLHelper? _SQLHelper = null;
- public MailSender? _MailSender = null;
-
- private Guid CheckLoginKey = Guid.Empty;
- private int FailedTimes = 0; // 超过一定次数断开连接
- private string UserName = "";
- private DataSet DsUser = new();
- private readonly Guid Token;
- private readonly ServerSocket Server;
- private readonly DataRequestController DataRequestController;
- private long LoginTime;
- private long LogoutTime;
- private bool IsMatching;
-
- public ServerModel(ServerSocket server, ClientSocket socket, bool running, bool isDebugMode)
+ public ServerModel(ISocketListener server, ISocketMessageProcessor socket, bool isDebugMode)
{
- Server = server;
- _Socket = socket;
- _Running = running;
- Token = socket.Token;
- this.IsDebugMode = isDebugMode;
- if (Config.SQLMode) _SQLHelper = new(this);
- _MailSender = SmtpHelper.GetMailSender();
+ Listener = server;
+ Socket = socket;
DataRequestController = new(this);
+ IsDebugMode = isDebugMode;
+ if (Config.SQLMode == SQLMode.MySQL) _sqlHelper = new MySQLHelper(this);
+ else if (Config.SQLMode == SQLMode.SQLite) _sqlHelper = Config.SQLHelper;
+ else ServerHelper.WriteLine("SQL 服务处于关闭状态", InvokeMessageType.Warning);
+ _mailer = SmtpHelper.GetMailSender();
}
- public bool Read(ClientSocket socket)
+ public virtual async Task SocketMessageHandler(ISocketMessageProcessor socket, SocketObject obj)
{
- // 接收客户端消息
- try
+ // 读取收到的消息
+ SocketMessageType type = obj.SocketType;
+ Guid token = obj.Token;
+ string msg = "";
+
+ // 验证Token
+ if (type != SocketMessageType.HeartBeat && token != socket.Token)
{
- // 禁止GameModuleServer调用
- if ((IServerModel)this is GameModuleServer) throw new NotSupportedException("请勿在GameModuleServer类中调用此方法");
-
- SocketObject[] SocketObjects = socket.Receive();
- if (SocketObjects.Length == 0)
- {
- ServerHelper.WriteLine(GetClientName() + " 发送了空信息。");
- return false;
- }
- SocketObject SocketObject = SocketObjects[0];
-
- SocketMessageType type = SocketObject.SocketType;
- Guid token = SocketObject.Token;
- object[] args = SocketObject.Parameters;
- string msg = "";
-
- // 验证Token
- if (type != SocketMessageType.HeartBeat && token != Token)
- {
- ServerHelper.WriteLine(GetClientName() + " 使用了非法方式传输消息,服务器拒绝回应 -> [" + SocketSet.GetTypeString(type) + "]");
- return false;
- }
-
- if (type == SocketMessageType.EndGame)
- {
- NowGamingServer = null;
- return true;
- }
-
- if (type == SocketMessageType.DataRequest)
- {
- return DataRequestHandler(socket, SocketObject);
- }
-
- if (type == SocketMessageType.Gaming)
- {
- return GamingMessageHandler(socket, SocketObject);
- }
-
- if (type == SocketMessageType.HeartBeat)
- {
- return HeartBeat(socket);
- }
-
- switch (type)
- {
- case SocketMessageType.Disconnect:
- ServerHelper.WriteLine("[" + SocketSet.GetTypeString(SocketMessageType.DataRequest) + "] " + GetClientName() + " -> Disconnect", InvokeMessageType.Core);
- msg = "你已成功断开与服务器的连接: " + Config.ServerName + "。 ";
- break;
- }
- return Send(socket, type, msg);
- }
- catch (Exception e)
- {
- ServerHelper.WriteLine(GetClientName() + " 没有回应。");
- ServerHelper.Error(e);
+ ServerHelper.WriteLine(GetClientName() + " 使用了非法方式传输消息,服务器拒绝回应 -> [" + SocketSet.GetTypeString(type) + "]");
return false;
}
+
+ if (type == SocketMessageType.HeartBeat)
+ {
+ return await HeartBeat();
+ }
+
+ if (type == SocketMessageType.EndGame)
+ {
+ NowGamingServer = null;
+ return true;
+ }
+
+ if (type == SocketMessageType.DataRequest)
+ {
+ return await DataRequestHandler(obj);
+ }
+
+ if (type == SocketMessageType.GamingRequest)
+ {
+ return await GamingRequestHandler(obj);
+ }
+
+ if (type == SocketMessageType.Gaming)
+ {
+ return await GamingMessageHandler(obj);
+ }
+
+ switch (type)
+ {
+ case SocketMessageType.Disconnect:
+ ServerHelper.WriteLine("[" + SocketSet.GetTypeString(SocketMessageType.DataRequest) + "] " + GetClientName() + " -> Disconnect", InvokeMessageType.Core);
+ msg = "你已成功断开与服务器的连接: " + Config.ServerName + "。 ";
+ break;
+ }
+
+ return await Send(type, msg);
}
- public bool DataRequestHandler(ClientSocket socket, SocketObject SocketObject)
+ public async Task HeartBeat()
+ {
+ bool result = await Send(SocketMessageType.HeartBeat);
+ if (!result)
+ {
+ ServerHelper.WriteLine("[ " + _username + " ] " + nameof(HeartBeat) + ": " + result, InvokeMessageType.Error);
+ }
+ return result;
+ }
+
+ protected async Task DataRequestHandler(SocketObject obj)
{
if (SQLHelper != null)
{
- Hashtable result = [];
+ Dictionary result = [];
+ Guid requestID = Guid.Empty;
DataRequestType type = DataRequestType.UnKnown;
- if (SocketObject.Parameters.Length > 0)
+ if (obj.Parameters.Length > 0)
{
try
{
- type = SocketObject.GetParam(0);
- Hashtable data = SocketObject.GetParam(1) ?? [];
+ type = obj.GetParam(0);
+ requestID = obj.GetParam(1);
+ Dictionary data = obj.GetParam>(2) ?? [];
- result = DataRequestController.GetResultData(type, data);
+ result = await DataRequestController.GetResultData(type, data);
}
catch (Exception e)
{
ServerHelper.Error(e);
SQLHelper.Rollback();
- return Send(socket, SocketMessageType.DataRequest, type, result);
+ return await Send(SocketMessageType.DataRequest, type, requestID, result);
}
}
- return Send(socket, SocketMessageType.DataRequest, type, result);
+ bool sendResult = await Send(SocketMessageType.DataRequest, type, requestID, result);
+ if (!sendResult)
+ {
+ ServerHelper.WriteLine("[ " + _username + " ] " + nameof(DataRequestHandler) + ": " + sendResult, InvokeMessageType.Error);
+ }
+ return sendResult;
}
+ ServerHelper.WriteLine("[ " + _username + " ] " + nameof(DataRequestHandler) + ": " + false, InvokeMessageType.Error);
return false;
}
- public bool GamingMessageHandler(ClientSocket socket, SocketObject SocketObject)
+ protected async Task GamingRequestHandler(SocketObject obj)
{
if (NowGamingServer != null)
{
- Hashtable result = [];
+ Dictionary result = [];
+ Guid requestID = Guid.Empty;
GamingType type = GamingType.None;
- if (SocketObject.Parameters.Length > 0)
+ if (obj.Parameters.Length > 0)
{
try
{
- type = SocketObject.GetParam(0);
- Hashtable data = SocketObject.GetParam(1) ?? [];
+ type = obj.GetParam(0);
+ requestID = obj.GetParam(1);
+ Dictionary data = obj.GetParam>(2) ?? [];
- result = NowGamingServer.GamingMessageHandler(UserName, type, data);
+ result = await NowGamingServer.GamingMessageHandler(_username, type, data);
}
catch (Exception e)
{
ServerHelper.Error(e);
- return Send(socket, SocketMessageType.Gaming, type, result);
+ return await Send(SocketMessageType.GamingRequest, type, requestID, result);
}
}
- return Send(socket, SocketMessageType.Gaming, type, result);
+ bool sendResult = await Send(SocketMessageType.GamingRequest, type, requestID, result);
+ if (!sendResult)
+ {
+ ServerHelper.WriteLine("[ " + _username + " ] " + nameof(GamingRequestHandler) + ": " + sendResult, InvokeMessageType.Error);
+ }
+ return sendResult;
}
+ ServerHelper.WriteLine("[ " + _username + " ] " + nameof(GamingRequestHandler) + ": " + false, InvokeMessageType.Error);
return false;
}
- public bool Send(ClientSocket socket, SocketMessageType type, params object[] objs)
+ protected async Task GamingMessageHandler(SocketObject obj)
+ {
+ if (NowGamingServer != null)
+ {
+ Dictionary result = [];
+ GamingType type = GamingType.None;
+
+ if (obj.Parameters.Length > 0)
+ {
+ try
+ {
+ type = obj.GetParam(0);
+ Dictionary data = obj.GetParam>(1) ?? [];
+
+ result = await NowGamingServer.GamingMessageHandler(_username, type, data);
+ }
+ catch (Exception e)
+ {
+ ServerHelper.Error(e);
+ return await Send(SocketMessageType.Gaming, type, result);
+ }
+ }
+
+ bool sendResult = await Send(SocketMessageType.Gaming, type, result);
+ if (!sendResult)
+ {
+ ServerHelper.WriteLine("[ " + _username + " ] " + nameof(GamingMessageHandler) + ": " + sendResult, InvokeMessageType.Error);
+ }
+ return sendResult;
+ }
+
+ ServerHelper.WriteLine("[ " + _username + " ] " + nameof(GamingMessageHandler) + ": " + false, InvokeMessageType.Error);
+ return false;
+ }
+
+ public virtual async Task Send(SocketMessageType type, params object[] objs)
{
// 发送消息给客户端
try
{
- if (socket.Send(type, objs) == SocketResult.Success)
+ if (await Socket.SendAsync(type, objs) == SocketResult.Success)
{
switch (type)
{
@@ -207,14 +240,15 @@ namespace Milimoe.FunGame.Server.Model
break;
case SocketMessageType.Disconnect:
RemoveUser();
- Close();
+ await Close();
break;
case SocketMessageType.Chat:
return true;
}
- object obj = objs[0];
- if (obj.GetType() == typeof(string) && (string)obj != "")
- ServerHelper.WriteLine("[" + SocketSet.GetTypeString(type) + "] " + GetClientName() + " <- " + obj, InvokeMessageType.Core);
+ if (objs.Length > 0 && objs[0] is string str && str != "")
+ {
+ ServerHelper.WriteLine("[" + SocketSet.GetTypeString(type) + "] " + GetClientName() + " <- " + str, InvokeMessageType.Core);
+ }
return true;
}
throw new CanNotSendToClientException();
@@ -227,18 +261,36 @@ namespace Milimoe.FunGame.Server.Model
}
}
- public void Start()
- {
- if ((IServerModel)this is GameModuleServer) throw new NotSupportedException("请勿在GameModuleServer类中调用此方法"); // 禁止GameModuleServer调用
- Task StreamReader = Task.Factory.StartNew(CreateStreamReader);
- Task PeriodicalQuerier = Task.Factory.StartNew(CreatePeriodicalQuerier);
+ public async Task SendClients(IEnumerable clients, SocketMessageType type, params object[] objs)
+ {
+ // 发送消息给多个客户端
+ try
+ {
+ foreach (IServerModel client in clients)
+ {
+ if (client.Socket != null)
+ {
+ await client.Socket.SendAsync(type, objs);
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ ServerHelper.Error(e);
+ }
+ }
+
+ public async Task Start()
+ {
+ TaskUtility.NewTask(CreatePeriodicalQuerier);
+ await CreateStreamReader();
}
public void SetClientName(string ClientName)
{
- _ClientName = ClientName;
+ _clientName = ClientName;
// 添加客户端到列表中
- Server.AddClient(_ClientName, this);
+ Listener.ClientList.Add(_clientName, this);
Config.OnlinePlayerCount++;
GetUsersCount();
}
@@ -248,55 +300,18 @@ namespace Milimoe.FunGame.Server.Model
return ServerHelper.MakeClientName(ClientName, User);
}
- public void PreLogin(DataSet dsuser, string username, Guid checkloginkey)
+ public void SendSystemMessage(ShowMessageType showtype, string msg, string title, int autoclose, params string[] usernames)
{
- DsUser = dsuser;
- UserName = username;
- CheckLoginKey = checkloginkey;
- }
-
- public void CheckLogin()
- {
- // 创建User对象
- _User = Factory.GetUser(DsUser);
- // 检查有没有重复登录的情况
- KickUser();
- // 添加至玩家列表
- AddUser();
- GetUsersCount();
- // CheckLogin
- LoginTime = DateTime.Now.Ticks;
- SQLHelper?.Execute(UserQuery.Update_CheckLogin(UserName, _Socket?.ClientIP.Split(':')[0] ?? "127.0.0.1"));
- }
-
- public bool IsLoginKey(Guid key)
- {
- return key == CheckLoginKey;
- }
-
- public void LogOut()
- {
- // 从玩家列表移除
- RemoveUser();
- GetUsersCount();
- CheckLoginKey = Guid.Empty;
- }
-
- public void ForceLogOut(string msg, string username = "")
- {
- ServerModel serverTask = (ServerModel)Server.GetUser(username == "" ? UserName : username);
- if (serverTask.Socket != null)
+ foreach (IServerModel serverTask in Listener.UserList.Where(model => usernames.Length > 0 && usernames.Contains(model.User.Username)))
{
- serverTask.Room = General.HallInstance;
- foreach (Room room in Config.RoomList.Cast())
+ if (serverTask != null && serverTask.Socket != null)
{
- QuitRoom(room.Roomid, room.RoomMaster.Id == User.Id);
+ serverTask.Send(SocketMessageType.System, showtype, msg, title, autoclose);
}
- serverTask.Send(serverTask.Socket, SocketMessageType.ForceLogout, msg);
}
}
- public bool QuitRoom(string roomid, bool isMaster)
+ public async Task QuitRoom(string roomid, bool isMaster)
{
bool result;
@@ -306,21 +321,21 @@ namespace Milimoe.FunGame.Server.Model
// 是否是房主
if (isMaster)
{
- List users = Config.RoomList.GetPlayerList(roomid);
+ List users = [.. Config.RoomList[roomid].UserAndIsReady.Keys];
if (users.Count > 0) // 如果此时房间还有人,更新房主
{
User NewMaster = users[0];
Room.RoomMaster = NewMaster;
SQLHelper?.Execute(RoomQuery.Update_QuitRoom(roomid, User.Id, NewMaster.Id));
- this.Room = General.HallInstance;
- UpdateRoomMaster(Room, true);
+ this.InRoom = General.HallInstance;
+ await UpdateRoomMaster(Room, true);
result = true;
}
else // 没人了就解散房间
{
Config.RoomList.RemoveRoom(roomid);
SQLHelper?.Execute(RoomQuery.Delete_QuitRoom(roomid, User.Id));
- this.Room = General.HallInstance;
+ this.InRoom = General.HallInstance;
ServerHelper.WriteLine("[ " + GetClientName() + " ] 解散了房间 " + roomid);
result = true;
}
@@ -328,236 +343,86 @@ namespace Milimoe.FunGame.Server.Model
// 不是房主直接退出房间
else
{
- this.Room = General.HallInstance;
- UpdateRoomMaster(Room);
+ this.InRoom = General.HallInstance;
+ await UpdateRoomMaster(Room);
result = true;
}
return result;
}
- public void Kick(string msg, string clientname = "")
+ public async Task UpdateRoomMaster(Room room, bool isUpdateRoomMaster = false)
{
- // 将客户端踢出服务器
- ServerModel serverTask = (ServerModel)Server.GetClient(clientname == "" ? ClientName : clientname);
- if (serverTask.Socket != null)
+ foreach (IServerModel Client in Listener.ClientList.Where(c => c != null && c.User.Id != 0 && room.Roomid == c.InRoom?.Roomid))
{
- serverTask.Room = General.HallInstance;
- foreach (Room room in Config.RoomList.Cast())
+ await Client.Send(SocketMessageType.Chat, User.Username, DateTimeUtility.GetNowShortTime() + " [ " + User.Username + " ] 离开了房间。");
+ if (isUpdateRoomMaster && room.RoomMaster?.Id != 0 && room.Roomid != "-1")
{
- QuitRoom(room.Roomid, room.RoomMaster.Id == User.Id);
- }
- RemoveUser();
- serverTask.Send(serverTask.Socket, SocketMessageType.Disconnect, msg);
- }
- Close();
- }
-
- public void Chat(string msg)
- {
- ServerHelper.WriteLine(msg);
- foreach (ServerModel Client in Server.ClientList.Cast())
- {
- if (Room.Roomid == Client.Room.Roomid)
- {
- if (Client != null && User.Id != 0)
- {
- Client.Send(Client.Socket!, SocketMessageType.Chat, User.Username, DateTimeUtility.GetNowShortTime() + msg);
- }
+ await Client.Send(SocketMessageType.UpdateRoomMaster, room);
}
}
}
- public void SendSystemMessage(ShowMessageType showtype, string msg, string title, int autoclose, params string[] usernames)
+ public async Task Kick(string msg)
{
- foreach (ServerModel serverTask in Server.UserList.Cast().Where(model => usernames.Length > 0 && usernames.Contains(model.UserName)))
- {
- if (serverTask != null && serverTask.Socket != null)
- {
- serverTask.Send(serverTask.Socket, SocketMessageType.System, showtype, msg, title, autoclose);
- }
- }
+ await QuitRoom(InRoom.Roomid, InRoom.RoomMaster.Id == User.Id);
+ RemoveUser();
+ InRoom = General.HallInstance;
+ await Send(SocketMessageType.Disconnect, msg);
+ await Close();
}
- public void StartGame(string roomid, List users, params string[] usernames)
+ public async Task ForceLogOut(string msg)
{
- Room room = General.HallInstance;
- if (roomid != "-1")
- {
- room = Config.RoomList[roomid];
- }
- if (room.Roomid == "-1") return;
- // 启动服务器
- TaskUtility.NewTask(() =>
- {
- if (Config.GameModuleLoader != null && Config.GameModuleLoader.ServerModules.ContainsKey(room.GameModule))
- {
- NowGamingServer = Config.GameModuleLoader.GetServerMode(room.GameModule);
- Dictionary others = Server.UserList.Cast().Where(model => usernames.Contains(model.User.Username) && model.User.Username != UserName).ToDictionary(k => k.User.Username, v => v);
- if (NowGamingServer.StartServer(room.GameModule, room, users, this, others))
- {
- foreach (ServerModel serverTask in Server.UserList.Cast().Where(model => usernames.Contains(model.User.Username)))
- {
- if (serverTask != null && serverTask.Socket != null)
- {
- Config.RoomList.CancelReady(roomid, serverTask.User);
- serverTask.Send(serverTask.Socket, SocketMessageType.StartGame, room, users);
- }
- }
- }
- }
- });
+ await QuitRoom(InRoom.Roomid, InRoom.RoomMaster.Id == User.Id);
+ InRoom = General.HallInstance;
+ await Send(SocketMessageType.ForceLogout, msg);
}
- public void IntoRoom(string roomid)
- {
- Room = Config.RoomList[roomid];
- foreach (ServerModel Client in Server.ClientList.Cast().Where(c => c != null && c.Socket != null && roomid == c.Room.Roomid))
- {
- if (User.Id != 0)
- {
- Client.Send(Client.Socket!, SocketMessageType.Chat, User.Username, DateTimeUtility.GetNowShortTime() + " [ " + User.Username + " ] 进入了房间。");
- }
- }
- }
-
- public void UpdateRoomMaster(Room Room, bool bolIsUpdateRoomMaster = false)
- {
- foreach (ServerModel Client in Server.ClientList.Cast().Where(c => c != null && c.Socket != null && Room.Roomid == c.Room.Roomid))
- {
- if (User.Id != 0)
- {
- Client.Send(Client.Socket!, SocketMessageType.Chat, User.Username, DateTimeUtility.GetNowShortTime() + " [ " + User.Username + " ] 离开了房间。");
- if (bolIsUpdateRoomMaster && Room.RoomMaster?.Id != 0 && Room.Roomid != "-1")
- {
- Client.Send(Client.Socket!, SocketMessageType.UpdateRoomMaster, Room);
- }
- }
- }
- }
-
- public bool HeartBeat(ClientSocket socket)
- {
- return Send(socket, SocketMessageType.HeartBeat, "");
- }
-
- public void StartMatching(RoomType type, User user)
- {
- IsMatching = true;
- ServerHelper.WriteLine(GetClientName() + " 开始匹配。类型:" + RoomSet.GetTypeString(type));
- TaskUtility.NewTask(async () =>
- {
- if (IsMatching)
- {
- Room room = await MatchingRoom(type, user);
- if (IsMatching && Socket != null)
- {
- Send(Socket, SocketMessageType.MatchRoom, room);
- }
- IsMatching = false;
- }
- }).OnError(e =>
- {
- ServerHelper.Error(e);
- IsMatching = false;
- });
- }
-
- public void StopMatching()
- {
- if (IsMatching)
- {
- ServerHelper.WriteLine(GetClientName() + " 取消了匹配。");
- IsMatching = false;
- }
- }
-
- private async Task MatchingRoom(RoomType roomtype, User user)
- {
- int i = 1;
- int time = 0;
- while (IsMatching)
- {
- // 先列出符合条件的房间
- List targets = Config.RoomList.ListRoom.Where(r => r.RoomType == roomtype).ToList();
-
- // 匹配Elo
- foreach (Room room in targets)
- {
- // 计算房间平均Elo
- List players = Config.RoomList.GetPlayerList(room.Roomid);
- if (players.Count > 0)
- {
- decimal avgelo = players.Sum(u => u.Statistics.EloStats.ContainsKey(0) ? u.Statistics.EloStats[0] : 0M) / players.Count;
- decimal userelo = user.Statistics.EloStats.ContainsKey(0) ? user.Statistics.EloStats[0] : 0M;
- if (userelo >= avgelo - (300 * i) && userelo <= avgelo + (300 * i))
- {
- return room;
- }
- }
- }
-
- if (!IsMatching) break;
-
- // 等待10秒
- await Task.Delay(10 * 1000);
- time += 10 * 1000;
- if (time >= 50 * 1000)
- {
- // 50秒后不再匹配Elo,直接返回第一个房间
- if (targets.Count > 0)
- {
- return targets[0];
- }
- break;
- }
- i++;
- }
-
- return General.HallInstance;
- }
-
- private void KickUser()
+ public async Task ForceLogOutDuplicateLogonUser()
{
if (User.Id != 0)
{
string user = User.Username;
- if (Server.ContainsUser(user))
+ if (Listener.UserList.ContainsKey(user))
{
ServerHelper.WriteLine("OnlinePlayers: 玩家 " + user + " 重复登录!");
- ForceLogOut("您的账号在别处登录,已强制下线。");
+ await ForceLogOut("您的账号在别处登录,已强制下线。");
}
}
}
- private bool AddUser()
+ public bool AddUser()
{
if (User.Id != 0 && this != null)
{
- Server.AddUser(User.Username, this);
- UserName = User.Username;
+ Listener.UserList.Add(User.Username, this);
+ _username = User.Username;
ServerHelper.WriteLine("OnlinePlayers: 玩家 " + User.Username + " 已添加");
+ // 更新最后登录时间、IP地址
+ _loginTime = DateTime.Now.Ticks;
+ SQLHelper?.Execute(UserQuery.Update_CheckLogin(_username, Socket?.ClientIP.Split(':')[0] ?? "127.0.0.1"));
return true;
}
return false;
}
- private bool RemoveUser()
+ public bool RemoveUser()
{
if (User.Id != 0 && this != null)
{
- LogoutTime = DateTime.Now.Ticks;
- int TotalMinutes = Convert.ToInt32((new DateTime(LogoutTime) - new DateTime(LoginTime)).TotalMinutes);
+ _logoutTime = DateTime.Now.Ticks;
+ int TotalMinutes = Convert.ToInt32((new DateTime(_logoutTime) - new DateTime(_loginTime)).TotalMinutes);
SQLHelper?.Execute(UserQuery.Update_GameTime(User.Username, TotalMinutes));
- if (SQLHelper?.Result == SQLResult.Success)
+ if (SQLHelper != null && SQLHelper.Result == SQLResult.Success)
{
ServerHelper.WriteLine("OnlinePlayers: 玩家 " + User.Username + " 本次已游玩" + TotalMinutes + "分钟");
}
else ServerHelper.WriteLine("OnlinePlayers: 无法更新玩家 " + User.Username + " 的游戏时长");
- if (Server.RemoveUser(User.Username))
+ if (Listener.UserList.Remove(User.Username))
{
ServerHelper.WriteLine("OnlinePlayers: 玩家 " + User.Username + " 已移除");
- _User = General.UnknownUserInstance;
+ User = General.UnknownUserInstance;
return true;
}
else ServerHelper.WriteLine("OnlinePlayers: 移除玩家 " + User.Username + " 失败");
@@ -565,37 +430,65 @@ namespace Milimoe.FunGame.Server.Model
return false;
}
- private void GetUsersCount()
+ public void GetUsersCount()
{
- ServerHelper.WriteLine($"目前在线客户端数量: {Server.ClientCount}(已登录的玩家数量:{Server.UserCount})");
+ ServerHelper.WriteLine($"{Listener.Name} 的目前在线客户端数量: {Listener.ClientList.Count}(已登录的玩家数量:{Listener.UserList.Count})");
}
- private void CreateStreamReader()
+ protected virtual async Task Read(ISocketMessageProcessor socket)
{
- Thread.Sleep(20);
+ // 接收客户端消息
+ try
+ {
+ SocketObject[] objs = await socket.ReceiveAsync();
+
+ if (objs.Length == 0)
+ {
+ ServerHelper.WriteLine(GetClientName() + " 发送了空信息。");
+ return false;
+ }
+
+ foreach (SocketObject obj in objs)
+ {
+ await SocketMessageHandler(socket, obj);
+ }
+
+ return true;
+ }
+ catch (Exception e)
+ {
+ ServerHelper.WriteLine(GetClientName() + " 没有回应。");
+ ServerHelper.Error(e);
+ return false;
+ }
+ }
+
+ protected async Task CreateStreamReader()
+ {
+ await Task.Delay(20);
ServerHelper.WriteLine("Creating: StreamReader -> " + GetClientName() + " ...OK");
while (Running)
{
if (Socket != null)
{
- if (!Read(Socket))
+ if (!await Read(Socket))
{
- FailedTimes++;
- if (FailedTimes >= Config.MaxConnectionFaileds)
+ _failedTimes++;
+ if (_failedTimes >= Config.MaxConnectionFaileds)
{
RemoveUser();
- Close();
+ await Close();
ServerHelper.WriteLine(GetClientName() + " Error -> Too Many Faileds.");
ServerHelper.WriteLine(GetClientName() + " Close -> StreamReader is Closed.");
break;
}
}
- else if (FailedTimes - 1 >= 0) FailedTimes--;
+ else if (_failedTimes - 1 >= 0) _failedTimes--;
}
else
{
RemoveUser();
- Close();
+ await Close();
ServerHelper.WriteLine(GetClientName() + " Error -> Socket is Closed.");
ServerHelper.WriteLine(GetClientName() + " Close -> StringStream is Closed.");
break;
@@ -603,41 +496,40 @@ namespace Milimoe.FunGame.Server.Model
}
}
- private void CreatePeriodicalQuerier()
+ protected async Task CreatePeriodicalQuerier()
{
- Thread.Sleep(20);
+ await Task.Delay(20);
ServerHelper.WriteLine("Creating: PeriodicalQuerier -> " + GetClientName() + " ...OK");
while (Running)
{
// 每两小时触发一次SQL服务器的心跳查询,防止SQL服务器掉线
try
{
- Thread.Sleep(2 * 1000 * 3600);
- SQLHelper?.ExecuteDataSet(UserQuery.Select_IsExistUsername(UserName));
+ await Task.Delay(2 * 1000 * 3600);
+ SQLHelper?.ExecuteDataSet(UserQuery.Select_IsExistUsername(_username));
}
catch (Exception e)
{
ServerHelper.Error(e);
RemoveUser();
- Close();
+ await Close();
ServerHelper.WriteLine(GetClientName() + " Error -> Socket is Closed.");
ServerHelper.WriteLine(GetClientName() + " Close -> StringStream is Closed.");
}
}
}
- private void Close()
+ protected async Task Close()
{
try
{
SQLHelper?.Close();
- _SQLHelper = null;
+ _sqlHelper = null;
MailSender?.Dispose();
- _MailSender = null;
- Socket?.Close();
- _Socket = null;
- _Running = false;
- Server.RemoveClient(ClientName);
+ _mailer = null;
+ await Socket.CloseAsync();
+ _running = false;
+ Listener.ClientList.Remove(ClientName);
Config.OnlinePlayerCount--;
GetUsersCount();
}
diff --git a/FunGame.Server/Others/Config.cs b/FunGame.Server/Others/Config.cs
index c2f2de0..8ca94e5 100644
--- a/FunGame.Server/Others/Config.cs
+++ b/FunGame.Server/Others/Config.cs
@@ -2,11 +2,13 @@
using System.Text;
using Milimoe.FunGame.Core.Api.Transmittal;
using Milimoe.FunGame.Core.Api.Utility;
+using Milimoe.FunGame.Core.Library.Common.Addon;
using Milimoe.FunGame.Core.Library.Constant;
using Milimoe.FunGame.Core.Library.SQLScript.Common;
using Milimoe.FunGame.Core.Library.SQLScript.Entity;
using Milimoe.FunGame.Core.Model;
using Milimoe.FunGame.Server.Utility;
+using Milimoe.FunGame.Server.Utility.DataUtility;
namespace Milimoe.FunGame.Server.Others
{
@@ -18,10 +20,35 @@ namespace Milimoe.FunGame.Server.Others
public static string ServerName { get; set; } = "FunGame Server";
///
- /// 默认端口
+ /// Socket 端口
///
public static int ServerPort { get; set; } = 22222;
+ ///
+ /// 使用 WebSocket
+ ///
+ public static bool UseWebSocket { get; set; } = false;
+
+ ///
+ /// WebSocket 监听地址
+ ///
+ public static string WebSocketAddress { get; set; } = "localhost";
+
+ ///
+ /// WebSocket 端口
+ ///
+ public static int WebSocketPort { get; set; } = 22222;
+
+ ///
+ /// WebSocket 监听子路径
+ ///
+ public static string WebSocketSubUrl { get; set; } = "ws";
+
+ ///
+ /// WebSocket 开启 SSL
+ ///
+ public static bool WebSocketSSL { get; set; } = false;
+
///
/// 默认状态:1可连接 0不可连接 -1不可用
///
@@ -50,7 +77,7 @@ namespace Milimoe.FunGame.Server.Others
///
/// 禁止连接的黑名单
///
- public static string ServerBannedList { get; set; } = "";
+ public static List ServerBannedList { get; set; } = [];
///
/// 最多接受连接的玩家数量
@@ -95,7 +122,7 @@ namespace Milimoe.FunGame.Server.Others
///
/// 是否运行数据库模式
///
- public static bool SQLMode { get; set; } = false;
+ public static SQLMode SQLMode { get; set; } = SQLMode.None;
///
/// Server实际安装的模组
@@ -114,7 +141,7 @@ namespace Milimoe.FunGame.Server.Others
{
get
{
- if (_SQLHelper is null) throw new MySQLConfigException();
+ if (_SQLHelper is null) throw new SQLServiceException();
return _SQLHelper;
}
}
@@ -128,12 +155,30 @@ namespace Milimoe.FunGame.Server.Others
{
try
{
- _SQLHelper = new MySQLHelper("", false);
- if (((MySQLHelper)_SQLHelper).Connection != null)
+ if (INIHelper.ExistINIFile())
{
- SQLMode = true;
- ServerLogin();
- ClearRoomList();
+ if (INIHelper.ReadINI("MySQL", "UseMySQL").Trim() == "true")
+ {
+ _SQLHelper = new MySQLHelper("", false);
+ if (((MySQLHelper)_SQLHelper).Connection != null)
+ {
+ SQLMode = _SQLHelper.Mode;
+ ServerLogin();
+ ClearRoomList();
+ }
+ }
+ else if (INIHelper.ReadINI("SQLite", "UseSQLite").Trim() == "true")
+ {
+ _SQLHelper = new SQLiteHelper();
+ SQLMode = _SQLHelper.Mode;
+ ServerLogin();
+ ClearRoomList();
+ }
+ else
+ {
+ SQLMode = SQLMode.None;
+ ServerHelper.WriteLine("未开启 SQL 服务,某些请求将无法处理。", InvokeMessageType.Warning);
+ }
}
}
catch (Exception e)
@@ -142,12 +187,45 @@ namespace Milimoe.FunGame.Server.Others
}
}
+ public static bool GetGameModuleList()
+ {
+ List supported = [];
+ // 构建AddonController
+ Hashtable delegates = [];
+ delegates.Add("WriteLine", new Action(msg => ServerHelper.WriteLine(msg, InvokeMessageType.GameModule)));
+ delegates.Add("Error", new Action(ServerHelper.Error));
+ // 读取modules目录下的模组
+ GameModuleLoader = GameModuleLoader.LoadGameModules(FunGameType, delegates);
+ foreach (GameModuleServer module in GameModuleLoader.ModuleServers.Values)
+ {
+ bool check = true;
+ // 检查模组是否有相对应的地图
+ if (!GameModuleLoader.Maps.ContainsKey(module.DefaultMap))
+ {
+ ServerHelper.WriteLine("GameModule Load Failed: " + module + " 没有找到相对应的地图,加载失败", InvokeMessageType.Error);
+ check = false;
+ }
+ if (check)
+ {
+ supported.Add(module.Name);
+ }
+ }
+ // 设置全局
+ GameModuleSupported = supported.Distinct().ToArray();
+ foreach (string modename in GameModuleSupported)
+ {
+ ServerHelper.WriteLine("Loaded: " + modename, InvokeMessageType.GameModule);
+ }
+
+ return GameModuleSupported.Length > 0;
+ }
+
///
/// 服务器启动登记
///
public static void ServerLogin()
{
- if (SQLMode)
+ if (SQLMode != SQLMode.None)
{
SQLHelper.Execute(ServerLoginLogs.Insert_ServerLoginLogs(ServerName, ServerKey));
}
@@ -158,7 +236,7 @@ namespace Milimoe.FunGame.Server.Others
///
public static void ClearRoomList()
{
- if (SQLMode)
+ if (SQLMode != SQLMode.None)
{
SQLHelper.Execute(RoomQuery.Delete_Rooms());
}
diff --git a/FunGame.Server/Utilities/ConnectProperties.cs b/FunGame.Server/Utilities/ConnectProperties.cs
new file mode 100644
index 0000000..0cd08ee
--- /dev/null
+++ b/FunGame.Server/Utilities/ConnectProperties.cs
@@ -0,0 +1,52 @@
+using Milimoe.FunGame.Core.Api.Utility;
+
+namespace Milimoe.FunGame.Server.Utility
+{
+ public class ConnectProperties
+ {
+ public static string Name { get; set; } = "";
+ public static string DataSource { get; set; } = "";
+ public static string Port { get; set; } = "";
+ public static string DataBase { get; set; } = "";
+ public static string User { get; set; } = "";
+ public static string Password { get; set; } = "";
+
+ ///
+ /// 读取MySQL服务器配置文件
+ ///
+ ///
+ public static string GetConnectPropertiesForMySQL()
+ {
+ if (Name == "" && DataSource == "" && Port == "" && DataBase == "" && User == "" && Password == "")
+ {
+ if (INIHelper.ExistINIFile())
+ {
+ DataSource = INIHelper.ReadINI("MySQL", "DBServer");
+ Port = INIHelper.ReadINI("MySQL", "DBPort");
+ DataBase = INIHelper.ReadINI("MySQL", "DBName");
+ User = INIHelper.ReadINI("MySQL", "DBUser");
+ Password = INIHelper.ReadINI("MySQL", "DBPassword");
+ }
+ else ServerHelper.Error(new MySQLConfigException());
+ }
+ return "data source = " + DataSource + "; port = " + Port + "; database = " + DataBase + "; user = " + User + "; password = " + Password + "; charset = utf8mb4;";
+ }
+
+ ///
+ /// 读取SQLite服务器配置文件
+ ///
+ ///
+ public static string GetConnectPropertiesForSQLite()
+ {
+ if (DataSource == "")
+ {
+ if (INIHelper.ExistINIFile())
+ {
+ DataSource = INIHelper.ReadINI("SQLite", "DataSource");
+ }
+ else ServerHelper.Error(new SQLServiceException());
+ }
+ return "data source=" + DataSource;
+ }
+ }
+}
diff --git a/FunGame.Server/Utilities/General.cs b/FunGame.Server/Utilities/General.cs
index 4d79b0e..cad0202 100644
--- a/FunGame.Server/Utilities/General.cs
+++ b/FunGame.Server/Utilities/General.cs
@@ -26,6 +26,10 @@ namespace Milimoe.FunGame.Server.Utility
Console.ForegroundColor = ConsoleColor.Yellow;
prefix = "[Api] ";
break;
+ case InvokeMessageType.Warning:
+ Console.ForegroundColor = ConsoleColor.Yellow;
+ prefix = "[Warning] ";
+ break;
case InvokeMessageType.Interface:
Console.ForegroundColor = ConsoleColor.Magenta;
prefix = "[Interface] ";
@@ -62,15 +66,18 @@ namespace Milimoe.FunGame.Server.Utility
public static void Write(string msg, InvokeMessageType type = InvokeMessageType.System)
{
if (msg.Trim() != "") Console.Write("\r" + GetPrefix(type) + msg + "> ");
+ Console.ResetColor();
}
public static void WriteLine(string msg, InvokeMessageType type = InvokeMessageType.System)
{
if (msg.Trim() != "") Console.Write("\r" + GetPrefix(type) + msg + "\n\r> ");
+ Console.ResetColor();
}
public static void Type()
{
+ Console.ResetColor();
Console.Write("\r> ");
}
@@ -86,7 +93,7 @@ namespace Milimoe.FunGame.Server.Utility
private static Hashtable GetServerSettingHashtable()
{
- Hashtable settings = new();
+ Hashtable settings = [];
if (INIHelper.ExistINIFile())
{
settings.Add("Name", INIHelper.ReadINI("Server", "Name"));
@@ -99,6 +106,11 @@ namespace Milimoe.FunGame.Server.Utility
settings.Add("OfficialMail", INIHelper.ReadINI("ServerMail", "OfficialMail"));
settings.Add("SupportMail", INIHelper.ReadINI("ServerMail", "SupportMail"));
settings.Add("Port", Convert.ToInt32(INIHelper.ReadINI("Socket", "Port")));
+ settings.Add("UseWebSocket", Convert.ToBoolean(INIHelper.ReadINI("Socket", "UseWebSocket")));
+ settings.Add("WebSocketAddress", Convert.ToString(INIHelper.ReadINI("Socket", "WebSocketAddress")));
+ settings.Add("WebSocketPort", Convert.ToInt32(INIHelper.ReadINI("Socket", "WebSocketPort")));
+ settings.Add("WebSocketSubUrl", Convert.ToString(INIHelper.ReadINI("Socket", "WebSocketSubUrl")));
+ settings.Add("WebSocketSSL", Convert.ToBoolean(INIHelper.ReadINI("Socket", "WebSocketSSL")));
settings.Add("MaxPlayer", Convert.ToInt32(INIHelper.ReadINI("Socket", "MaxPlayer")));
settings.Add("MaxConnectFailed", Convert.ToInt32(INIHelper.ReadINI("Socket", "MaxConnectFailed")));
}
@@ -124,7 +136,7 @@ namespace Milimoe.FunGame.Server.Utility
if (Describe != null) Config.ServerDescription = Describe;
if (Notice != null) Config.ServerNotice = Notice;
if (Key != null) Config.ServerKey = Key;
- if (BannedList != null) Config.ServerBannedList = BannedList;
+ if (BannedList != null) Config.ServerBannedList = BannedList.Split(',').Select(s => s.Trim()).ToList();
string? OfficialMail = (string?)settings["OfficialMail"];
string? SupportMail = (string?)settings["SupportMail"];
@@ -134,18 +146,28 @@ namespace Milimoe.FunGame.Server.Utility
int? Status = (int?)settings["Status"];
int? Port = (int?)settings["Port"];
+ bool? UseWebSocket = (bool?)settings["UseWebSocket"];
+ string? WebSocketAddress = (string?)settings["WebSocketAddress"];
+ int? WebSocketPort = (int?)settings["WebSocketPort"];
+ string? WebSocketSubUrl = (string?)settings["WebSocketSubUrl"];
+ bool? WebSocketSSL = (bool?)settings["WebSocketSSL"];
int? MaxPlayer = (int?)settings["MaxPlayer"];
int? MaxConnectFailed = (int?)settings["MaxConnectFailed"];
if (Status != null) Config.ServerStatus = (int)Status;
if (Port != null) Config.ServerPort = (int)Port;
+ if (UseWebSocket != null) Config.UseWebSocket = (bool)UseWebSocket;
+ if (WebSocketAddress != null) Config.WebSocketAddress = WebSocketAddress;
+ if (WebSocketPort != null) Config.WebSocketPort = (int)WebSocketPort;
+ if (WebSocketSubUrl != null) Config.WebSocketSubUrl = WebSocketSubUrl;
+ if (WebSocketSSL != null) Config.WebSocketSSL = (bool)WebSocketSSL;
if (MaxPlayer != null) Config.MaxPlayers = (int)MaxPlayer;
if (MaxConnectFailed != null) Config.MaxConnectionFaileds = (int)MaxConnectFailed;
}
}
catch (Exception e)
{
- ServerHelper.WriteLine(e.StackTrace ?? "");
+ Error(e);
}
}
@@ -192,7 +214,7 @@ namespace Milimoe.FunGame.Server.Utility
if (SmtpPort > 0) return new MailSender(SenderMailAddress, SenderName, SenderPassword, SmtpHost, SmtpPort, OpenSSL);
}
}
- ServerHelper.WriteLine("Smtp服务处于关闭状态");
+ ServerHelper.WriteLine("SMTP 服务处于关闭状态", InvokeMessageType.Warning);
return null;
}
throw new SmtpHelperException();
diff --git a/FunGame.Server/Utilities/MySQLConnection.cs b/FunGame.Server/Utilities/MySQL/MySQLConnection.cs
similarity index 53%
rename from FunGame.Server/Utilities/MySQLConnection.cs
rename to FunGame.Server/Utilities/MySQL/MySQLConnection.cs
index 6ca0cec..79fe54c 100644
--- a/FunGame.Server/Utilities/MySQLConnection.cs
+++ b/FunGame.Server/Utilities/MySQL/MySQLConnection.cs
@@ -1,41 +1,8 @@
-using Milimoe.FunGame.Core.Api.Utility;
-using Milimoe.FunGame.Core.Model;
+using Milimoe.FunGame.Core.Model;
using MySql.Data.MySqlClient;
namespace Milimoe.FunGame.Server.Utility.DataUtility
{
- public class ConnectProperties
- {
- public static string Name { get; set; } = "";
- public static string DataSource { get; set; } = "";
- public static string Port { get; set; } = "";
- public static string DataBase { get; set; } = "";
- public static string User { get; set; } = "";
- public static string Password { get; set; } = "";
-
- ///
- /// 读取MySQL服务器配置文件
- ///
- ///
- public static string GetConnectProperties()
- {
- if (Name == "" && DataSource == "" && Port == "" && DataBase == "" && User == "" && Password == "")
- {
- if (INIHelper.ExistINIFile())
- {
- DataSource = INIHelper.ReadINI("MySQL", "DBServer");
- Port = INIHelper.ReadINI("MySQL", "DBPort");
- DataBase = INIHelper.ReadINI("MySQL", "DBName");
- User = INIHelper.ReadINI("MySQL", "DBUser");
- Password = INIHelper.ReadINI("MySQL", "DBPassword");
- return "data source = " + DataSource + "; port = " + Port + "; database = " + DataBase + "; user = " + User + "; password = " + Password + "; charset = utf8mb4;";
- }
- else ServerHelper.Error(new MySQLConfigException());
- }
- return "data source = " + DataSource + "; port = " + Port + "; database = " + DataBase + "; user = " + User + "; password = " + Password + "; charset = utf8mb4;";
- }
- }
-
public class MySQLConnection
{
public MySqlConnection? Connection
@@ -87,15 +54,15 @@ namespace Milimoe.FunGame.Server.Utility.DataUtility
{
try
{
- string _GetConnection = ConnectProperties.GetConnectProperties();
- if (_GetConnection != null)
+ string connectionString = ConnectProperties.GetConnectPropertiesForMySQL();
+ if (connectionString != null)
{
- string[] DataSetting = _GetConnection.Split(";");
- if (DataSetting.Length > 1 && DataSetting[0].Length > 14 && DataSetting[1].Length > 8)
+ string[] strings = connectionString.Split(";");
+ if (strings.Length > 1 && strings[0].Length > 14 && strings[1].Length > 8)
{
- ServerHelper.WriteLine("Connect -> MySQL://" + DataSetting[0][14..] + ":" + DataSetting[1][8..]);
+ ServerHelper.WriteLine("Connect -> MySQL://" + strings[0][14..] + ":" + strings[1][8..]);
}
- _Connection = new MySqlConnection(_GetConnection);
+ _Connection = new MySqlConnection(connectionString);
_Connection.Open();
if (_Connection.State == System.Data.ConnectionState.Open)
{
diff --git a/FunGame.Server/Utilities/MySQLHelper.cs b/FunGame.Server/Utilities/MySQL/MySQLHelper.cs
similarity index 96%
rename from FunGame.Server/Utilities/MySQLHelper.cs
rename to FunGame.Server/Utilities/MySQL/MySQLHelper.cs
index ee1f6a2..7db2d5f 100644
--- a/FunGame.Server/Utilities/MySQLHelper.cs
+++ b/FunGame.Server/Utilities/MySQL/MySQLHelper.cs
@@ -1,8 +1,8 @@
using System.Data;
using Milimoe.FunGame.Core.Api.Transmittal;
+using Milimoe.FunGame.Core.Interface.Base;
using Milimoe.FunGame.Core.Library.Constant;
using Milimoe.FunGame.Core.Model;
-using Milimoe.FunGame.Server.Model;
using Milimoe.FunGame.Server.Others;
using Milimoe.FunGame.Server.Utility.DataUtility;
using MySql.Data.MySqlClient;
@@ -12,6 +12,7 @@ namespace Milimoe.FunGame.Server.Utility
public class MySQLHelper : SQLHelper
{
public override FunGameInfo.FunGame FunGameType => Config.FunGameType;
+ public override SQLMode Mode => SQLMode.MySQL;
public override string Script { get; set; } = "";
public override CommandType CommandType { get; set; } = CommandType.Text;
public override SQLResult Result => _Result;
@@ -27,7 +28,7 @@ namespace Milimoe.FunGame.Server.Utility
private DataSet _DataSet = new();
private MySQLConnection? _Connection;
private MySqlTransaction? _Transaction;
- private readonly ServerModel? ServerModel;
+ private readonly IServerModel? ServerModel;
private readonly bool _IsOneTime = false;
///
@@ -123,7 +124,7 @@ namespace Milimoe.FunGame.Server.Utility
/// 创建为SocketModel服务的SQLHelper
///
/// SocketModel
- public MySQLHelper(ServerModel ServerModel)
+ public MySQLHelper(IServerModel ServerModel)
{
this.ServerModel = ServerModel;
Script = "";
diff --git a/FunGame.Server/Utilities/MySQLManager.cs b/FunGame.Server/Utilities/MySQL/MySQLManager.cs
similarity index 100%
rename from FunGame.Server/Utilities/MySQLManager.cs
rename to FunGame.Server/Utilities/MySQL/MySQLManager.cs
diff --git a/FunGame.Server/Utilities/SQLite/SQLiteHelper.cs b/FunGame.Server/Utilities/SQLite/SQLiteHelper.cs
new file mode 100644
index 0000000..9b0ca92
--- /dev/null
+++ b/FunGame.Server/Utilities/SQLite/SQLiteHelper.cs
@@ -0,0 +1,229 @@
+using System.Data;
+using Microsoft.Data.Sqlite;
+using Milimoe.FunGame.Core.Api.Transmittal;
+using Milimoe.FunGame.Core.Library.Constant;
+using Milimoe.FunGame.Core.Model;
+
+namespace Milimoe.FunGame.Server.Utility.DataUtility
+{
+ public class SQLiteHelper : SQLHelper
+ {
+ public override FunGameInfo.FunGame FunGameType { get; } = FunGameInfo.FunGame.FunGame_Server;
+ public override SQLMode Mode { get; } = SQLMode.SQLite;
+ public override string Script { get; set; } = "";
+ public override CommandType CommandType { get; set; } = CommandType.Text;
+ public override SQLResult Result => _result;
+ public override SQLServerInfo ServerInfo => _serverInfo ?? SQLServerInfo.Create();
+ public override int UpdateRows => _updateRows;
+ public override DataSet DataSet => _dataSet;
+
+ private readonly SqliteConnection _connection;
+ private SqliteTransaction? _transaction;
+ private DataSet _dataSet = new();
+ private SQLResult _result = SQLResult.NotFound;
+ private readonly SQLServerInfo? _serverInfo;
+ private int _updateRows = 0;
+ private readonly string _connectionString = "";
+
+ public SQLiteHelper(string script = "", CommandType type = CommandType.Text)
+ {
+ Script = script;
+ CommandType = type;
+ _connectionString = ConnectProperties.GetConnectPropertiesForSQLite();
+ string[] strings = _connectionString.Split("=");
+ if (strings.Length > 1)
+ {
+ ServerHelper.WriteLine("Connect -> SQLite://" + strings[1]);
+ _serverInfo = SQLServerInfo.Create(database: strings[1]);
+ }
+ _connection = new SqliteConnection(_connectionString);
+ }
+
+ ///
+ /// 打开数据库连接
+ ///
+ private void OpenConnection()
+ {
+ if (_connection.State != ConnectionState.Open)
+ {
+ _connection.Open();
+ }
+ }
+
+ ///
+ /// 关闭数据库连接
+ ///
+ public override void Close()
+ {
+ _transaction?.Dispose();
+ if (_connection.State != ConnectionState.Closed)
+ {
+ _connection.Close();
+ }
+ }
+
+ ///
+ /// 执行一个命令
+ ///
+ ///
+ public override int Execute()
+ {
+ return Execute(Script);
+ }
+
+ ///
+ /// 执行一个指定的命令
+ ///
+ ///
+ ///
+ ///
+ public override int Execute(string script)
+ {
+ try
+ {
+ OpenConnection();
+ ServerHelper.WriteLine("SQLQuery -> " + script, InvokeMessageType.Api);
+ using SqliteCommand command = new(script, _connection);
+ command.CommandType = CommandType;
+ if (_transaction != null)
+ {
+ command.Transaction = _transaction;
+ }
+
+ _updateRows = command.ExecuteNonQuery();
+ _result = SQLResult.Success;
+ Close();
+ return UpdateRows;
+ }
+ catch (Exception ex)
+ {
+ _result = SQLResult.Fail;
+ throw new Exception($"SQL execution failed: {ex.Message}", ex);
+ }
+ }
+
+ ///
+ /// 查询DataSet
+ ///
+ ///
+ public override DataSet ExecuteDataSet()
+ {
+ return ExecuteDataSet(Script);
+ }
+
+ ///
+ /// 执行指定的命令查询DataSet
+ ///
+ ///
+ ///
+ ///
+ public override DataSet ExecuteDataSet(string script)
+ {
+ try
+ {
+ OpenConnection();
+ ServerHelper.WriteLine("SQLQuery -> " + script, InvokeMessageType.Api);
+ using SqliteCommand command = new(script, _connection)
+ {
+ CommandType = CommandType
+ };
+ using SqliteDataReader reader = command.ExecuteReader();
+ _dataSet = new();
+ DataTable table = new();
+ table.Load(reader);
+ _dataSet.Tables.Add(table);
+ Close();
+ return _dataSet;
+ }
+ catch (Exception ex)
+ {
+ _result = SQLResult.Fail;
+ throw new Exception($"SQL execution failed: {ex.Message}", ex);
+ }
+ }
+
+ ///
+ /// 执行指定的命令查询DataRow
+ ///
+ ///
+ public override DataRow? ExecuteDataRow()
+ {
+ return ExecuteDataRow(Script);
+ }
+
+ ///
+ /// 执行指定的命令查询DataRow
+ ///
+ ///
+ ///
+ public override DataRow? ExecuteDataRow(string script)
+ {
+ OpenConnection();
+ ServerHelper.WriteLine("SQLQuery -> " + script, InvokeMessageType.Api);
+ DataSet dataSet = ExecuteDataSet(script);
+ if (dataSet.Tables.Count > 0 && dataSet.Tables[0].Rows.Count > 0)
+ {
+ Close();
+ return dataSet.Tables[0].Rows[0];
+ }
+ Close();
+ return null;
+ }
+
+ ///
+ /// 创建一个SQL事务
+ ///
+ public override void NewTransaction()
+ {
+ OpenConnection();
+ _transaction = _connection.BeginTransaction();
+ }
+
+ ///
+ /// 提交事务
+ ///
+ ///
+ public override void Commit()
+ {
+ try
+ {
+ _transaction?.Commit();
+ Close();
+ _result = SQLResult.Success;
+ }
+ catch (Exception ex)
+ {
+ _result = SQLResult.Fail;
+ throw new Exception($"Transaction commit failed: {ex.Message}", ex);
+ }
+ }
+
+ ///
+ /// 回滚事务
+ ///
+ ///
+ public override void Rollback()
+ {
+ try
+ {
+ _transaction?.Rollback();
+ Close();
+ _result = SQLResult.Success;
+ }
+ catch (Exception ex)
+ {
+ _result = SQLResult.Fail;
+ throw new Exception($"Transaction rollback failed: {ex.Message}", ex);
+ }
+ }
+
+ ///
+ /// 资源清理
+ ///
+ public void Dispose()
+ {
+ _transaction?.Dispose();
+ _connection.Dispose();
+ }
+ }
+}
diff --git a/FunGame.Server/app.manifest b/FunGame.Server/app.manifest
new file mode 100644
index 0000000..04ee0ee
--- /dev/null
+++ b/FunGame.Server/app.manifest
@@ -0,0 +1,79 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/FunGame.WebAPI/Architecture/RESTfulAPI.cs b/FunGame.WebAPI/Architecture/RESTfulAPI.cs
new file mode 100644
index 0000000..1a919e5
--- /dev/null
+++ b/FunGame.WebAPI/Architecture/RESTfulAPI.cs
@@ -0,0 +1,49 @@
+using Milimoe.FunGame.Core.Interface.Base;
+using Milimoe.FunGame.Core.Library.Common.Network;
+using Milimoe.FunGame.Core.Library.Constant;
+
+namespace Milimoe.FunGame.WebAPI.Architecture
+{
+ public class RESTfulAPI(Guid token, string clientip, string clientname) : ISocketMessageProcessor
+ {
+ public Type InstanceType => typeof(RESTfulAPI);
+
+ public Guid Token { get; init; } = token;
+
+ public string ClientIP { get; init; } = clientip;
+
+ public string ClientName { get; init; } = clientname;
+
+ public void Close()
+ {
+
+ }
+
+ public async Task CloseAsync()
+ {
+ await Task.Delay(100);
+ }
+
+ public SocketObject[] Receive()
+ {
+ return [];
+ }
+
+ public async Task ReceiveAsync()
+ {
+ await Task.Delay(100);
+ return [];
+ }
+
+ public SocketResult Send(SocketMessageType type, params object[] objs)
+ {
+ return SocketResult.Success;
+ }
+
+ public async Task SendAsync(SocketMessageType type, params object[] objs)
+ {
+ await Task.Delay(100);
+ return SocketResult.Success;
+ }
+ }
+}
diff --git a/FunGame.WebAPI/Architecture/RESTfulAPIListener.cs b/FunGame.WebAPI/Architecture/RESTfulAPIListener.cs
new file mode 100644
index 0000000..5b16b99
--- /dev/null
+++ b/FunGame.WebAPI/Architecture/RESTfulAPIListener.cs
@@ -0,0 +1,21 @@
+using Milimoe.FunGame.Core.Api.Utility;
+using Milimoe.FunGame.Core.Interface.Base;
+
+namespace Milimoe.FunGame.WebAPI.Architecture
+{
+ public class RESTfulAPIListener : ISocketListener
+ {
+ public string Name => "RESTfulAPIListener";
+
+ public ConcurrentModelList ClientList { get; } = [];
+
+ public ConcurrentModelList UserList { get; } = [];
+
+ public List BannedList { get; } = [];
+
+ public void Close()
+ {
+
+ }
+ }
+}
diff --git a/FunGame.WebAPI/Architecture/WebAPIListener.cs b/FunGame.WebAPI/Architecture/WebAPIListener.cs
new file mode 100644
index 0000000..de01a78
--- /dev/null
+++ b/FunGame.WebAPI/Architecture/WebAPIListener.cs
@@ -0,0 +1,22 @@
+using Milimoe.FunGame.Core.Api.Utility;
+using Milimoe.FunGame.Core.Interface.Base;
+using Milimoe.FunGame.Core.Library.Common.Network;
+
+namespace Milimoe.FunGame.WebAPI.Architecture
+{
+ public class WebAPIListener : ISocketListener
+ {
+ public string Name => "WebAPIListener";
+
+ public ConcurrentModelList ClientList { get; } = [];
+
+ public ConcurrentModelList UserList { get; } = [];
+
+ public List BannedList { get; } = [];
+
+ public void Close()
+ {
+
+ }
+ }
+}
diff --git a/FunGame.WebAPI/Controllers/PostDataController.cs b/FunGame.WebAPI/Controllers/PostDataController.cs
new file mode 100644
index 0000000..2821c57
--- /dev/null
+++ b/FunGame.WebAPI/Controllers/PostDataController.cs
@@ -0,0 +1,58 @@
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Mvc;
+using Milimoe.FunGame.Core.Api.Utility;
+using Milimoe.FunGame.Core.Library.Common.Network;
+using Milimoe.FunGame.Core.Library.Constant;
+using Milimoe.FunGame.WebAPI.Architecture;
+using Milimoe.FunGame.WebAPI.Models;
+
+namespace Milimoe.FunGame.WebAPI.Controllers
+{
+ [ApiController]
+ [Route("[controller]")]
+ [Authorize]
+ public class PostDataController(ILogger logger) : ControllerBase
+ {
+ public static Dictionary ResultDatas { get; } = [];
+
+ private readonly ILogger _logger = logger;
+
+ [HttpPost("{username}", Name = "username")]
+ public async Task Post(string username, [FromBody] SocketObject obj)
+ {
+ try
+ {
+ RESTfulAPIListener? apiListener = Singleton.Get();
+ if (apiListener != null && apiListener.UserList.ContainsKey(username))
+ {
+ RESTfulAPIModel model = (RESTfulAPIModel)apiListener.UserList[username];
+ if (model.LastRequestID == Guid.Empty)
+ {
+ Guid uid = Guid.NewGuid();
+ model.LastRequestID = uid;
+ await model.SocketMessageHandler(model.Socket, obj);
+ model.LastRequestID = Guid.Empty;
+ if (ResultDatas.TryGetValue(uid, out SocketObject list))
+ {
+ return Ok(list);
+ }
+ else
+ {
+ return NotFound();
+ }
+ }
+ else
+ {
+ Ok(new SocketObject(SocketMessageType.System, model.Token, "δִϣȴ"));
+ }
+ }
+ return NotFound();
+ }
+ catch (Exception e)
+ {
+ _logger.LogError(e, "Error during post data");
+ return StatusCode(500, "ڲ");
+ }
+ }
+ }
+}
diff --git a/FunGame.WebAPI/Controllers/UserController.cs b/FunGame.WebAPI/Controllers/UserController.cs
new file mode 100644
index 0000000..7f5b63f
--- /dev/null
+++ b/FunGame.WebAPI/Controllers/UserController.cs
@@ -0,0 +1,74 @@
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Mvc;
+using Milimoe.FunGame.Core.Api.Utility;
+using Milimoe.FunGame.Core.Library.SQLScript.Entity;
+using Milimoe.FunGame.Server.Others;
+using Milimoe.FunGame.Server.Utility;
+using Milimoe.FunGame.WebAPI.Architecture;
+using Milimoe.FunGame.WebAPI.Models;
+using Milimoe.FunGame.WebAPI.Services;
+
+namespace Milimoe.FunGame.WebAPI.Controllers
+{
+ [ApiController]
+ [Route("[controller]")]
+ public class UserController(JWTService jwtTokenService) : ControllerBase
+ {
+ [HttpPost("login")]
+ public async Task Login([FromBody] LoginModel loginModel)
+ {
+ string msg = "用户名或密码不正确。";
+ string clientip = HttpContext.Connection.RemoteIpAddress?.ToString() + ":" + HttpContext.Connection.RemotePort;
+ ServerHelper.WriteLine(ServerHelper.MakeClientName(clientip) + " 通过 RESTful API 连接至服务器,正在登录 . . .", Core.Library.Constant.InvokeMessageType.Core);
+ string username = loginModel.Username;
+ string password = loginModel.Password;
+ RESTfulAPIListener? apiListener = Singleton.Get();
+ if (apiListener != null)
+ {
+ // 移除旧模型
+ if (apiListener.UserList.ContainsKey(username))
+ {
+ await apiListener.UserList[username].Send(Core.Library.Constant.SocketMessageType.Disconnect);
+ }
+ // 创建新模型
+ if (!apiListener.UserList.ContainsKey(username))
+ {
+ Config.ConnectingPlayerCount++;
+ RESTfulAPIModel model = new(apiListener, clientip);
+ model.SetClientName(clientip);
+ // 创建User对象
+ if (model.SQLHelper != null)
+ {
+ model.SQLHelper.ExecuteDataSet(UserQuery.Select_Users_LoginQuery(username, password));
+ Core.Entity.User user = Factory.GetUser(model.SQLHelper?.DataSet ?? new());
+ if (user.Id != 0)
+ {
+ model.User = user;
+ // 检查有没有重复登录的情况
+ await model.ForceLogOutDuplicateLogonUser();
+ // 添加至玩家列表
+ model.AddUser();
+ model.GetUsersCount();
+ string token = jwtTokenService.GenerateToken(username);
+ Config.ConnectingPlayerCount--;
+ return Ok(new { BearerToken = token, InternalToken = model.Token });
+ }
+ }
+ else msg = "服务器暂时无法处理登录请求。";
+ await model.Send(Core.Library.Constant.SocketMessageType.Disconnect);
+ }
+ }
+
+ Config.ConnectingPlayerCount--;
+ ServerHelper.WriteLine(msg, Core.Library.Constant.InvokeMessageType.Core);
+ return Unauthorized(msg);
+ }
+
+ [HttpPost("refresh")]
+ [Authorize]
+ public IActionResult Refresh([FromBody] LoginModel request)
+ {
+ return Ok(jwtTokenService.GenerateToken(request.Username));
+ }
+ }
+}
diff --git a/FunGame.WebAPI/FunGame.WebAPI.csproj b/FunGame.WebAPI/FunGame.WebAPI.csproj
new file mode 100644
index 0000000..545abd7
--- /dev/null
+++ b/FunGame.WebAPI/FunGame.WebAPI.csproj
@@ -0,0 +1,48 @@
+
+
+
+ net8.0
+ enable
+ enable
+ Milimoe.$(MSBuildProjectName.Replace(" ", "_"))
+ ..\bin\
+ FunGameWebAPI
+ Images\logo.ico
+ Milimoe
+
+
+
+ embedded
+
+
+
+ embedded
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ..\..\FunGame.Core\bin\Debug\net8.0\FunGame.Core.dll
+
+
+
+
+
+ \
+ True
+
+
+
+
diff --git a/FunGame.WebAPI/FunGame.WebAPI.http b/FunGame.WebAPI/FunGame.WebAPI.http
new file mode 100644
index 0000000..adae99e
--- /dev/null
+++ b/FunGame.WebAPI/FunGame.WebAPI.http
@@ -0,0 +1,6 @@
+@FunGame.WebAPI_HostAddress = http://localhost:5117
+
+GET {{FunGame.WebAPI_HostAddress}}/weatherforecast/
+Accept: application/json
+
+###
diff --git a/FunGame.WebAPI/Images/logo.ico b/FunGame.WebAPI/Images/logo.ico
new file mode 100644
index 0000000..4082874
Binary files /dev/null and b/FunGame.WebAPI/Images/logo.ico differ
diff --git a/FunGame.WebAPI/Models/LoginModel.cs b/FunGame.WebAPI/Models/LoginModel.cs
new file mode 100644
index 0000000..0c7db3f
--- /dev/null
+++ b/FunGame.WebAPI/Models/LoginModel.cs
@@ -0,0 +1,8 @@
+namespace Milimoe.FunGame.WebAPI.Models
+{
+ public class LoginModel(string username, string password)
+ {
+ public string Username { get; set; } = username;
+ public string Password { get; set; } = password;
+ }
+}
diff --git a/FunGame.WebAPI/Models/RESTfulAPIModel.cs b/FunGame.WebAPI/Models/RESTfulAPIModel.cs
new file mode 100644
index 0000000..6e098ca
--- /dev/null
+++ b/FunGame.WebAPI/Models/RESTfulAPIModel.cs
@@ -0,0 +1,72 @@
+using Milimoe.FunGame.Core.Interface.Base;
+using Milimoe.FunGame.Core.Library.Common.Network;
+using Milimoe.FunGame.Core.Library.Constant;
+using Milimoe.FunGame.Server.Model;
+using Milimoe.FunGame.Server.Utility;
+using Milimoe.FunGame.WebAPI.Architecture;
+using Milimoe.FunGame.WebAPI.Controllers;
+
+namespace Milimoe.FunGame.WebAPI.Models
+{
+ public class RESTfulAPIModel(ISocketListener server, string clientip) : ServerModel(server, new RESTfulAPI(Guid.NewGuid(), clientip, clientip), false)
+ {
+ public Guid LastRequestID { get; set; } = Guid.Empty;
+ public List ToBeSent { get; set; } = [];
+
+ public override async Task Send(SocketMessageType type, params object[] objs)
+ {
+ if (type == SocketMessageType.Disconnect || type == SocketMessageType.ForceLogout)
+ {
+ RemoveUser();
+ await Close();
+ return true;
+ }
+ if (type != SocketMessageType.HeartBeat)
+ {
+ SocketObject obj = new(type, Token, objs);
+ if (LastRequestID != Guid.Empty)
+ {
+ return PostDataController.ResultDatas.TryAdd(LastRequestID, obj);
+ }
+ else
+ {
+ ToBeSent.Add(obj);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public override async Task SocketMessageHandler(ISocketMessageProcessor socket, SocketObject obj)
+ {
+ // 读取收到的消息
+ SocketMessageType type = obj.SocketType;
+ Guid token = obj.Token;
+ string msg = "";
+
+ // 验证Token
+ if (type != SocketMessageType.HeartBeat && token != socket.Token)
+ {
+ ServerHelper.WriteLine(GetClientName() + " 使用了非法方式传输消息,服务器拒绝回应 -> [" + SocketSet.GetTypeString(type) + "]");
+ return false;
+ }
+
+ if (type == SocketMessageType.DataRequest)
+ {
+ return await DataRequestHandler(obj);
+ }
+
+ if (type == SocketMessageType.GamingRequest)
+ {
+ return await GamingRequestHandler(obj);
+ }
+
+ if (type == SocketMessageType.Gaming)
+ {
+ return await GamingMessageHandler(obj);
+ }
+
+ return await Send(type, msg);
+ }
+ }
+}
diff --git a/FunGame.WebAPI/Program.cs b/FunGame.WebAPI/Program.cs
new file mode 100644
index 0000000..1b743ca
--- /dev/null
+++ b/FunGame.WebAPI/Program.cs
@@ -0,0 +1,267 @@
+using System.Net.WebSockets;
+using System.Text;
+using System.Text.Encodings.Web;
+using System.Text.Json.Serialization;
+using System.Text.Unicode;
+using Microsoft.AspNetCore.Authentication.JwtBearer;
+using Microsoft.AspNetCore.Diagnostics;
+using Microsoft.IdentityModel.Tokens;
+using Microsoft.OpenApi.Models;
+using Milimoe.FunGame.Core.Api.Utility;
+using Milimoe.FunGame.Core.Library.Common.JsonConverter;
+using Milimoe.FunGame.Core.Library.Common.Network;
+using Milimoe.FunGame.Core.Library.Constant;
+using Milimoe.FunGame.Server.Controller;
+using Milimoe.FunGame.Server.Model;
+using Milimoe.FunGame.Server.Others;
+using Milimoe.FunGame.Server.Utility;
+using Milimoe.FunGame.WebAPI.Architecture;
+using Milimoe.FunGame.WebAPI.Services;
+
+WebAPIListener listener = new();
+
+try
+{
+ Console.Title = Config.ServerName;
+ Console.WriteLine(FunGameInfo.GetInfo(Config.FunGameType));
+
+ ServerHelper.WriteLine("ڶȡļʼ . . .");
+ // ʼ˵
+ ServerHelper.InitOrderList();
+
+ // ȡϷģ
+ if (!Config.GetGameModuleList())
+ {
+ ServerHelper.WriteLine("ƺδװκϷģ飬Ƿȷװǡ");
+ }
+
+ // Ƿļ
+ if (!INIHelper.ExistINIFile())
+ {
+ ServerHelper.WriteLine("δļԶļ . . .");
+ INIHelper.Init(Config.FunGameType);
+ ServerHelper.WriteLine("ļFunGame.iniɹĸļȻ");
+ Console.ReadKey();
+ return;
+ }
+ else
+ {
+ ServerHelper.GetServerSettings();
+ }
+
+ //
+ RESTfulAPIListener apiListener = new();
+ Singleton.Add(apiListener);
+
+ ServerHelper.WriteLine(" help ȡ quit رշ");
+
+ // ȫSQLHelper
+ Config.InitSQLHelper();
+
+ ServerHelper.WriteLine(" Web API . . .");
+
+ WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
+
+ // Add services to the container.
+ builder.Services.AddControllers().AddJsonOptions(options =>
+ {
+ options.JsonSerializerOptions.WriteIndented = true;
+ options.JsonSerializerOptions.Encoder = JavaScriptEncoder.Create(UnicodeRanges.All);
+ options.JsonSerializerOptions.ReferenceHandler = ReferenceHandler.IgnoreCycles;
+ options.JsonSerializerOptions.Converters.Add(new DateTimeConverter());
+ options.JsonSerializerOptions.Converters.Add(new DataTableConverter());
+ options.JsonSerializerOptions.Converters.Add(new DataSetConverter());
+ options.JsonSerializerOptions.Converters.Add(new UserConverter());
+ options.JsonSerializerOptions.Converters.Add(new RoomConverter());
+ options.JsonSerializerOptions.Converters.Add(new CharacterConverter());
+ options.JsonSerializerOptions.Converters.Add(new MagicResistanceConverter());
+ options.JsonSerializerOptions.Converters.Add(new EquipSlotConverter());
+ options.JsonSerializerOptions.Converters.Add(new SkillConverter());
+ options.JsonSerializerOptions.Converters.Add(new EffectConverter());
+ options.JsonSerializerOptions.Converters.Add(new ItemConverter());
+ });
+ // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
+ builder.Services.AddEndpointsApiExplorer();
+ builder.Services.AddSwaggerGen(options =>
+ {
+ options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
+ {
+ Name = "Authorization",
+ Type = SecuritySchemeType.Http,
+ Scheme = "Bearer",
+ BearerFormat = "JWT",
+ In = ParameterLocation.Header,
+ Description = " Auth ص BearerToken",
+ });
+ options.AddSecurityRequirement(new OpenApiSecurityRequirement
+ {
+ {
+ new OpenApiSecurityScheme
+ {
+ Reference = new OpenApiReference
+ {
+ Type = ReferenceType.SecurityScheme,
+ Id = "Bearer"
+ }
+ },
+ Array.Empty()
+ }
+ });
+ });
+ // CORS
+ builder.Services.AddCors(options =>
+ {
+ options.AddPolicy("AllowSpecificOrigin", policy =>
+ {
+ policy.AllowAnyOrigin()
+ .AllowAnyHeader()
+ .AllowAnyMethod();
+ });
+ });
+ // JWT ֤
+ builder.Services.AddScoped();
+ builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(options =>
+ {
+ options.TokenValidationParameters = new TokenValidationParameters
+ {
+ ValidateIssuer = true,
+ ValidateAudience = true,
+ ValidateLifetime = true,
+ ValidateIssuerSigningKey = true,
+ ValidIssuer = builder.Configuration["Jwt:Issuer"],
+ ValidAudience = builder.Configuration["Jwt:Audience"],
+ IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Key"] ?? "undefined"))
+ };
+ });
+
+ WebApplication app = builder.Build();
+
+ // CORS
+ app.UseCors("AllowSpecificOrigin");
+
+ // Configure the HTTP request pipeline.
+ if (app.Environment.IsDevelopment())
+ {
+ app.UseSwagger();
+ app.UseSwaggerUI();
+ }
+
+ app.UseHttpsRedirection();
+
+ app.UseAuthorization();
+
+ app.MapControllers();
+
+ app.UseExceptionHandler(errorApp =>
+ {
+ errorApp.Run(async context =>
+ {
+ context.Response.StatusCode = 500;
+ context.Response.ContentType = "application/json";
+ IExceptionHandlerFeature? contextFeature = context.Features.Get();
+ if (contextFeature != null)
+ {
+ await context.Response.WriteAsync(new
+ {
+ context.Response.StatusCode,
+ Message = "Internal Server Error.",
+ Detailed = contextFeature.Error.Message
+ }.ToString() ?? "");
+ }
+ });
+ });
+
+ // WebSockets м
+ WebSocketOptions webSocketOptions = new()
+ {
+ KeepAliveInterval = TimeSpan.FromMinutes(2) // WebSocket ı
+ };
+ app.UseWebSockets(webSocketOptions);
+
+ // ·ɵ WebSocket
+ app.Map("/ws", WebSocketConnectionHandler);
+
+ // ʼ
+ listener.BannedList.AddRange(Config.ServerBannedList);
+
+ if (Config.ServerNotice != "")
+ Console.WriteLine("\n\n********** **********\n\n" + Config.ServerNotice + "\n");
+ else
+ Console.WriteLine("ȡ");
+
+ Task order = Task.Factory.StartNew(GetConsoleOrder);
+
+ app.Run();
+}
+catch (Exception e)
+{
+ ServerHelper.Error(e);
+}
+
+async Task GetConsoleOrder()
+{
+ while (true)
+ {
+ string order = Console.ReadLine() ?? "";
+ ServerHelper.Type();
+ if (order != "")
+ {
+ order = order.ToLower();
+ switch (order)
+ {
+ default:
+ await ConsoleModel.Order(listener, order);
+ break;
+ }
+ }
+ }
+}
+
+async Task WebSocketConnectionHandler(HttpContext context)
+{
+ string clientip = "";
+ try
+ {
+ if (context.WebSockets.IsWebSocketRequest)
+ {
+ WebSocket instance = await context.WebSockets.AcceptWebSocketAsync();
+ clientip = context.Connection.RemoteIpAddress?.ToString() + ":" + context.Connection.RemotePort;
+
+ Guid token = Guid.NewGuid();
+ ServerWebSocket socket = new(listener, instance, clientip, clientip, token);
+ Config.ConnectingPlayerCount++;
+ bool isConnected = false;
+ bool isDebugMode = false;
+
+ // ʼͻ
+ IEnumerable objs = [];
+ while (!objs.Any(o => o.SocketType == SocketMessageType.Connect))
+ {
+ objs = objs.Union(await socket.ReceiveAsync());
+ }
+ (isConnected, isDebugMode) = await ConnectController.Connect(listener, socket, token, clientip, objs.Where(o => o.SocketType == SocketMessageType.Connect));
+ if (isConnected)
+ {
+ ServerModel ClientModel = new(listener, socket, isDebugMode);
+ ClientModel.SetClientName(clientip);
+ await ClientModel.Start();
+ }
+ else
+ {
+ ServerHelper.WriteLine(ServerHelper.MakeClientName(clientip) + " ʧܡ", InvokeMessageType.Core);
+ await socket.CloseAsync();
+ }
+ Config.ConnectingPlayerCount--;
+ }
+ else
+ {
+ context.Response.StatusCode = 400;
+ }
+ }
+ catch (Exception e)
+ {
+ if (--Config.ConnectingPlayerCount < 0) Config.ConnectingPlayerCount = 0;
+ ServerHelper.WriteLine(ServerHelper.MakeClientName(clientip) + " жӣ", InvokeMessageType.Core);
+ ServerHelper.Error(e);
+ }
+}
diff --git a/FunGame.WebAPI/Properties/launchSettings.json b/FunGame.WebAPI/Properties/launchSettings.json
new file mode 100644
index 0000000..5c47465
--- /dev/null
+++ b/FunGame.WebAPI/Properties/launchSettings.json
@@ -0,0 +1,41 @@
+{
+ "$schema": "http://json.schemastore.org/launchsettings.json",
+ "iisSettings": {
+ "windowsAuthentication": false,
+ "anonymousAuthentication": true,
+ "iisExpress": {
+ "applicationUrl": "http://localhost:45590",
+ "sslPort": 44356
+ }
+ },
+ "profiles": {
+ "http": {
+ "commandName": "Project",
+ "dotnetRunMessages": true,
+ "launchBrowser": true,
+ "launchUrl": "swagger",
+ "applicationUrl": "http://localhost:5117",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ },
+ "https": {
+ "commandName": "Project",
+ "dotnetRunMessages": true,
+ "launchBrowser": true,
+ "launchUrl": "swagger",
+ "applicationUrl": "https://localhost:7162;http://localhost:5117",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ },
+ "IIS Express": {
+ "commandName": "IISExpress",
+ "launchBrowser": true,
+ "launchUrl": "swagger",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ }
+ }
+}
diff --git a/FunGame.WebAPI/Services/JWTService.cs b/FunGame.WebAPI/Services/JWTService.cs
new file mode 100644
index 0000000..0068985
--- /dev/null
+++ b/FunGame.WebAPI/Services/JWTService.cs
@@ -0,0 +1,33 @@
+using System.IdentityModel.Tokens.Jwt;
+using System.Security.Claims;
+using Microsoft.IdentityModel.Tokens;
+using Milimoe.FunGame.Core.Library.Constant;
+
+namespace Milimoe.FunGame.WebAPI.Services
+{
+ public class JWTService(IConfiguration configuration)
+ {
+ public string GenerateToken(string username)
+ {
+ // 创建一个包含用户信息的声明
+ Claim[] claims = [
+ new Claim(JwtRegisteredClaimNames.Sub, username),
+ new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString())
+ ];
+
+ // 获取密钥和发行者
+ SymmetricSecurityKey key = new(General.DefaultEncoding.GetBytes(configuration["Jwt:Key"] ?? "undefined"));
+ SigningCredentials creds = new(key, SecurityAlgorithms.HmacSha256);
+
+ JwtSecurityToken token = new(
+ issuer: configuration["Jwt:Issuer"],
+ audience: configuration["Jwt:Audience"],
+ claims: claims,
+ expires: DateTime.Now.AddMinutes(30), // 设置过期时间
+ signingCredentials: creds
+ );
+
+ return new JwtSecurityTokenHandler().WriteToken(token);
+ }
+ }
+}
diff --git a/FunGame.WebAPI/appsettings.Development.json b/FunGame.WebAPI/appsettings.Development.json
new file mode 100644
index 0000000..0c208ae
--- /dev/null
+++ b/FunGame.WebAPI/appsettings.Development.json
@@ -0,0 +1,8 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.AspNetCore": "Warning"
+ }
+ }
+}
diff --git a/FunGame.WebAPI/appsettings.json b/FunGame.WebAPI/appsettings.json
new file mode 100644
index 0000000..3701d01
--- /dev/null
+++ b/FunGame.WebAPI/appsettings.json
@@ -0,0 +1,19 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.AspNetCore": "Warning"
+ }
+ },
+ "AllowedHosts": "*",
+ "Kestrel": {
+ "EndpointDefaults": {
+ "Protocols": "Http1AndHttp2AndHttp3"
+ }
+ },
+ "Jwt": {
+ "Key": "166afec8ff6e0c3a647c7230294ea10be39d5d217f37aa5195f795017403da730ce6313790335b4975d7387c14aaa06c52d1cd90b5ef47d1831b6d7d524a12bf",
+ "Issuer": "FunGame",
+ "Audience": "FunGame Web API"
+ }
+}
diff --git a/FunGameServer.sln b/FunGameServer.sln
index 7015657..9d1875c 100644
--- a/FunGameServer.sln
+++ b/FunGameServer.sln
@@ -7,6 +7,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FunGame.Server", "FunGame.S
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FunGame.Implement", "FunGame.Implement\FunGame.Implement.csproj", "{F5BACA36-3DE2-450A-8518-E5DC29991875}"
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FunGame.WebAPI", "FunGame.WebAPI\FunGame.WebAPI.csproj", "{F4C6F3E8-84EA-49B4-99B7-A886C56C44F2}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -21,6 +23,10 @@ Global
{F5BACA36-3DE2-450A-8518-E5DC29991875}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F5BACA36-3DE2-450A-8518-E5DC29991875}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F5BACA36-3DE2-450A-8518-E5DC29991875}.Release|Any CPU.Build.0 = Release|Any CPU
+ {F4C6F3E8-84EA-49B4-99B7-A886C56C44F2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {F4C6F3E8-84EA-49B4-99B7-A886C56C44F2}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {F4C6F3E8-84EA-49B4-99B7-A886C56C44F2}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {F4C6F3E8-84EA-49B4-99B7-A886C56C44F2}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE