using System.Collections; using Milimoe.FunGame.Core.Api.Transmittal; using Milimoe.FunGame.Core.Api.Utility; using Milimoe.FunGame.Core.Library.Common.Network; using Milimoe.FunGame.Core.Library.Constant; using Milimoe.FunGame.Core.Library.Exception; namespace Milimoe.FunGame.Core.Controller { /// /// 此类实现服务器连接、断开连接、心跳检测、创建数据请求等功能 /// -- 需要继承并实现部分方法 -- /// public abstract class RunTimeController { /// /// 与服务器的连接套接字实例 /// public Socket? Socket => _Socket; /// /// 与服务器的连接套接字实例(WebSocket) /// public HTTPClient? HTTPClient => _HTTPClient; /// /// 套接字是否已经连接 /// public bool Connected => _Socket != null && _Socket.Connected; /// /// 接收服务器信息的线程 /// protected Task? _ReceivingTask; /// /// 用于类内赋值 /// protected Socket? _Socket; /// /// 用于类内赋值 /// protected HTTPClient? _HTTPClient; /// /// 是否正在接收服务器信息 /// protected bool _IsReceiving; /// /// 断开服务器连接 /// /// public bool Disconnect() { bool result = false; try { result = _Socket?.Send(SocketMessageType.Disconnect, "") == SocketResult.Success; } catch (Exception e) { WritelnSystemInfo(e.GetErrorInfo()); } return result; } /// /// 发送结束游戏反馈 /// /// public bool EndGame() { bool result = false; try { result = _Socket?.Send(SocketMessageType.EndGame, "") == SocketResult.Success; } catch (Exception e) { WritelnSystemInfo(e.GetErrorInfo()); } return result; } /// /// 连接服务器 [ 可选参数需要根据连接方式提供 ] /// 建议使用异步版,此方法为兼容性处理 /// /// /// /// /// /// /// public ConnectResult Connect(TransmittalType type, string address, int port, bool ssl = false, string subUrl = "") { return Task.Run(() => ConnectAsync(type, address, port, ssl, subUrl)).Result; } /// /// 连接服务器 [ 异步版,可选参数需要根据连接方式提供 ] /// /// /// /// /// /// /// public async Task ConnectAsync(TransmittalType type, string address, int port = 0, bool ssl = false, string subUrl = "") { ArrayList connectArgs = []; if (!BeforeConnect(ref address, ref port, connectArgs)) { return ConnectResult.ConnectFailed; } ConnectResult result = ConnectResult.Success; string msg; string serverName = ""; string notice = ""; // 检查服务器地址和端口是否正确 if (address == "" || (type == TransmittalType.Socket && port <= 0) || (type == TransmittalType.WebSocket && port < 0)) { result = ConnectResult.FindServerFailed; } if (result == ConnectResult.Success) { // 与服务器建立连接 if (type == TransmittalType.Socket) { connectArgs = await Connect_Socket(connectArgs, address, port); } else if (type == TransmittalType.WebSocket) { connectArgs = await Connect_WebSocket(connectArgs, address, ssl, port, subUrl); } else { result = ConnectResult.FindServerFailed; msg = "连接服务器失败,未指定连接方式。"; connectArgs = [result, msg, serverName, notice]; } } AfterConnect(connectArgs); // 允许修改数组中的result,强行改变连接的结果 if (connectArgs.Count > 0) { result = (ConnectResult?)connectArgs[0] ?? result; } return result; } /// /// 使用 Socket 方式连接服务器 /// /// /// /// /// private async Task Connect_Socket(ArrayList connectArgs, string address, int port) { ConnectResult result = ConnectResult.Success; string msg = ""; string serverName = ""; string notice = ""; _Socket?.Close(); _Socket = Socket.Connect(address, port); if (_Socket != null && _Socket.Connected) { if (_Socket.Send(SocketMessageType.Connect, connectArgs.Cast().ToArray()) == SocketResult.Success) { SocketObject[] objs = _Socket.Receive(); foreach (SocketObject obj in objs) { if (obj.SocketType == SocketMessageType.Connect) { bool success = obj.GetParam(0); msg = obj.GetParam(1) ?? ""; result = success ? ConnectResult.Success : ConnectResult.ConnectFailed; if (success) { _Socket.Token = obj.GetParam(2); serverName = obj.GetParam(3) ?? ""; notice = obj.GetParam(4) ?? ""; StartReceiving(); await Task.Run(() => { while (true) { if (_IsReceiving) { break; } } }); _Socket.ConnectionLost += Error; } } } } else result = ConnectResult.ConnectFailed; } else _Socket?.Close(); return [result, msg, serverName, notice]; } /// /// 使用 WebSocket 方式连接服务器 /// /// /// /// /// /// /// private async Task Connect_WebSocket(ArrayList connectArgs, string address, bool ssl, int port, string subUrl) { ConnectResult result = ConnectResult.Success; string msg = ""; string serverName = ""; string notice = ""; _HTTPClient?.Close(); _HTTPClient = await HTTPClient.Connect(address, ssl, port, subUrl, connectArgs.Cast().ToArray()); if (_HTTPClient.Connected) { bool webSocketConnected = false; _HTTPClient.AddSocketObjectHandler(obj => { try { if (obj.SocketType == SocketMessageType.Connect) { bool success = obj.GetParam(0); msg = obj.GetParam(1) ?? ""; result = success ? ConnectResult.Success : ConnectResult.ConnectFailed; if (success) { _HTTPClient.Token = obj.GetParam(2); serverName = obj.GetParam(3) ?? ""; notice = obj.GetParam(4) ?? ""; } webSocketConnected = true; return; } HandleSocketMessage(TransmittalType.WebSocket, obj); } catch (Exception e) { Error(e); } }); while (!webSocketConnected) { await Task.Delay(100); } _HTTPClient.ConnectionLost += Error; } else { _HTTPClient?.Close(); result = ConnectResult.ConnectFailed; } return [result, msg, serverName, notice]; } /// /// 获取服务器地址 /// /// string:服务器地址;int:端口号 /// public (string, int) GetServerAddress() { try { string? ipaddress = (string?)Implement.GetFunGameImplValue(InterfaceType.IClient, InterfaceMethod.RemoteServerIP); if (ipaddress != null) { string[] s = ipaddress.Split(':'); if (s != null && s.Length > 1) { return (s[0], Convert.ToInt32(s[1])); } } throw new FindServerFailedException(); } catch (FindServerFailedException e) { WritelnSystemInfo(e.GetErrorInfo()); return ("", 0); } } /// /// 此方法将在连接服务器前触发 /// 客户端可以重写此方法 /// /// 服务器地址 /// 服务器端口 /// 重写时可以提供额外的连接参数 /// false:中止连接 public virtual bool BeforeConnect(ref string address, ref int port, ArrayList args) { return true; } /// /// 此方法将在连接服务器后触发(Connect结果返回前) /// 客户端可以重写此方法 /// /// 连接服务器后返回的一些数据,可以使用也可以修改它们 /// public virtual void AfterConnect(ArrayList ConnectArgs) { } /// /// 客户端需要自行实现自动登录的事务 /// public virtual void AutoLogin(string Username, string Password, string AutoKey) { } /// /// 关闭 Socket 连接 /// /// public bool Close_Socket() { try { if (_Socket != null) { _Socket.Close(); _Socket = null; } if (_ReceivingTask != null && !_ReceivingTask.IsCompleted) { _ReceivingTask.Wait(1); _ReceivingTask = null; _IsReceiving = false; } } catch (Exception e) { WritelnSystemInfo(e.GetErrorInfo()); return false; } return true; } /// /// 关闭 WebSocket 连接 /// /// public bool Close_WebSocket() { try { if (_HTTPClient != null) { _HTTPClient.Close(); _HTTPClient = null; } } catch (Exception e) { WritelnSystemInfo(e.GetErrorInfo()); return false; } return true; } /// /// 输出消息 /// /// /// /// public abstract void WritelnSystemInfo(string msg, LogLevel level = LogLevel.Info, bool useLevel = true); /// /// 自定处理异常的方法 /// -- 一般放在catch中 -- /// /// public abstract void Error(Exception e); /// /// 基于本地已连接的Socket创建新的数据请求 /// /// /// /// public DataRequest NewDataRequest(DataRequestType RequestType) { if (_Socket != null) { DataRequest request = new(_Socket, RequestType); return request; } else if (_HTTPClient != null) { DataRequest request = new(_HTTPClient, RequestType); return request; } throw new ConnectFailedException(); } /// /// 基于本地已连接的Socket创建长时间运行的数据请求 /// /// /// /// public DataRequest NewLongRunningDataRequest(DataRequestType RequestType) { if (_Socket != null) { DataRequest request = new(_Socket, RequestType, true); return request; } else if (_HTTPClient != null) { DataRequest request = new(_HTTPClient, RequestType, true); return request; } throw new ConnectFailedException(); } /// /// 基于本地已连接的Socket创建新的数据请求 /// 加载项专用( / ) /// /// /// /// public DataRequest NewDataRequestForAddon(DataRequestType RequestType) { if (_Socket != null) { DataRequest request = new(_Socket, RequestType, false, SocketRuntimeType.Addon); return request; } else if (_HTTPClient != null) { DataRequest request = new(_HTTPClient, RequestType, false, SocketRuntimeType.Addon); return request; } throw new ConnectFailedException(); } /// /// 基于本地已连接的Socket创建长时间运行的数据请求 /// 加载项专用( / ) /// /// /// /// public DataRequest NewLongRunningDataRequestForAddon(DataRequestType RequestType) { if (_Socket != null) { DataRequest request = new(_Socket, RequestType, true, SocketRuntimeType.Addon); return request; } else if (_HTTPClient != null) { DataRequest request = new(_HTTPClient, RequestType, true, SocketRuntimeType.Addon); return request; } throw new ConnectFailedException(); } /// /// 基于本地已连接的Socket创建新的局内()数据请求 /// 加载项专用:此方法是给 提供的 /// /// /// /// public DataRequest NewDataRequestForAddon(GamingType GamingType) { if (_Socket != null) { DataRequest request = new(_Socket, GamingType, false, SocketRuntimeType.Addon); return request; } else if (_HTTPClient != null) { DataRequest request = new(_HTTPClient, GamingType, false, SocketRuntimeType.Addon); return request; } throw new ConnectFailedException(); } /// /// 基于本地已连接的Socket创建长时间运行的局内()数据请求 /// 加载项专用:此方法是给 提供的 /// /// /// /// public DataRequest NewLongRunningDataRequestForAddon(GamingType GamingType) { if (_Socket != null) { DataRequest request = new(_Socket, GamingType, true, SocketRuntimeType.Addon); return request; } else if (_HTTPClient != null) { DataRequest request = new(_HTTPClient, GamingType, true, SocketRuntimeType.Addon); return request; } throw new ConnectFailedException(); } /// /// 开始接收服务器信息 [ Socket Only ] /// protected void StartReceiving() { _ReceivingTask = Task.Factory.StartNew(() => { Thread.Sleep(100); _IsReceiving = true; while (Connected) { Receiving(); } }); _Socket?.StartReceiving(_ReceivingTask); } /// /// 获取服务器已发送的信息为SocketObject数组 [ Socket Only ] /// /// protected SocketObject[] GetServerMessage() { if (_Socket != null && _Socket.Connected) { return _Socket.Receive(); } return []; } /// /// 具体接收服务器信息以及处理信息的方法 [ Socket Only ] /// /// protected SocketMessageType Receiving() { if (_Socket is null) return SocketMessageType.Unknown; SocketMessageType result = SocketMessageType.Unknown; try { SocketObject[] messages = GetServerMessage(); foreach (SocketObject obj in messages) { result = HandleSocketMessage(TransmittalType.Socket, obj); } } catch (Exception e) { _Socket?.OnConnectionLost(e); Close_Socket(); } return result; } /// /// 处理接收到的信息 /// /// /// /// protected SocketMessageType HandleSocketMessage(TransmittalType transmittalType, SocketObject obj) { SocketMessageType type = obj.SocketType; SocketMessageType result = type; switch (type) { case SocketMessageType.Disconnect: if (transmittalType == TransmittalType.Socket) { Close_Socket(); } else if (transmittalType == TransmittalType.WebSocket) { Close_WebSocket(); } SocketHandler_Disconnect(obj); break; case SocketMessageType.System: SocketHandler_System(obj); break; case SocketMessageType.HeartBeat: SocketHandler_HeartBeat(obj); break; case SocketMessageType.ForceLogout: SocketHandler_ForceLogout(obj); break; case SocketMessageType.Chat: SocketHandler_Chat(obj); break; case SocketMessageType.UpdateRoomMaster: SocketHandler_UpdateRoomMaster(obj); break; case SocketMessageType.MatchRoom: SocketHandler_MatchRoom(obj); break; case SocketMessageType.StartGame: SocketHandler_StartGame(obj); break; case SocketMessageType.EndGame: SocketHandler_EndGame(obj); break; case SocketMessageType.Gaming: SocketHandler_Gaming(obj); break; case SocketMessageType.AnonymousGameServer: SocketHandler_AnonymousGameServer(obj); break; case SocketMessageType.Unknown: default: break; } return result; } /// /// 客户端接收服务器断开连接的通知 /// /// protected abstract void SocketHandler_Disconnect(SocketObject ServerMessage); /// /// 客户端接收并处理服务器系统消息 /// /// protected virtual void SocketHandler_System(SocketObject ServerMessage) { } /// /// 客户端接收并处理服务器心跳 /// /// protected virtual void SocketHandler_HeartBeat(SocketObject ServerMessage) { } /// /// 客户端接收强制退出登录的通知 /// /// protected virtual void SocketHandler_ForceLogout(SocketObject ServerMessage) { } /// /// 客户端接收并处理聊天信息 /// /// protected virtual void SocketHandler_Chat(SocketObject ServerMessage) { } /// /// 客户端接收并处理更换房主信息 /// /// protected virtual void SocketHandler_UpdateRoomMaster(SocketObject ServerMessage) { } /// /// 客户端接收并处理匹配房间成功信息 /// /// protected virtual void SocketHandler_MatchRoom(SocketObject ServerMessage) { } /// /// 客户端接收并处理开始游戏信息 /// /// protected virtual void SocketHandler_StartGame(SocketObject ServerMessage) { } /// /// 客户端接收并处理游戏结束信息 /// /// protected virtual void SocketHandler_EndGame(SocketObject ServerMessage) { } /// /// 客户端接收并处理局内消息 /// /// protected virtual void SocketHandler_Gaming(SocketObject ServerMessage) { } /// /// 客户端接收并处理匿名服务器的消息 /// /// protected virtual void SocketHandler_AnonymousGameServer(SocketObject ServerMessage) { } } }