mirror of
https://github.com/Alex-Rachel/TEngine.git
synced 2025-08-14 16:51:28 +00:00
Compare commits
71 Commits
demo
...
TEngine3.0
Author | SHA1 | Date | |
---|---|---|---|
![]() |
6a6d33c536 | ||
![]() |
57a014a83a | ||
![]() |
9d1a8e8c9d | ||
![]() |
86c26cd21b | ||
![]() |
b60b9fff42 | ||
![]() |
990e17a6cc | ||
![]() |
be531bfad0 | ||
![]() |
6c46f3e5fd | ||
![]() |
e4b48e3c58 | ||
![]() |
68e5b1d482 | ||
![]() |
abd152b072 | ||
![]() |
470e62d9c4 | ||
![]() |
481b5911ab | ||
![]() |
05d3aff05e | ||
![]() |
86bb6353dc | ||
![]() |
334698b6e6 | ||
![]() |
2684bd29f5 | ||
![]() |
c568c62404 | ||
![]() |
699ccb3b09 | ||
![]() |
f92bf5c602 | ||
![]() |
cd87c71281 | ||
![]() |
94c137b3c6 | ||
![]() |
120a86b396 | ||
![]() |
383dc50fe3 | ||
![]() |
2369e8723c | ||
![]() |
344f3293ad | ||
![]() |
5d361dd188 | ||
![]() |
a2f7fe907a | ||
![]() |
5b3f64689f | ||
![]() |
2258c13892 | ||
![]() |
a70d2e7d17 | ||
![]() |
b15f51631a | ||
![]() |
da12bd7cab | ||
![]() |
98bcaef6b7 | ||
![]() |
71d1286144 | ||
![]() |
9359a81a96 | ||
![]() |
a9542646c1 | ||
![]() |
0890ca9bdb | ||
![]() |
ec409c7e15 | ||
![]() |
4bc63fafc8 | ||
![]() |
fe0f9afd6d | ||
![]() |
4632a0c099 | ||
![]() |
60e57bb80b | ||
![]() |
b7c79d0438 | ||
![]() |
62b7c9e4d6 | ||
![]() |
75a6977afb | ||
![]() |
659da836ac | ||
![]() |
07c459051f | ||
![]() |
4253a81e78 | ||
![]() |
e498abacd1 | ||
![]() |
f16759483f | ||
![]() |
899472a5db | ||
![]() |
e65245371a | ||
![]() |
b04fff4ec9 | ||
![]() |
d8f8fd01d9 | ||
![]() |
9b1c5e6f0a | ||
![]() |
b2b5c9274c | ||
![]() |
b814d689d8 | ||
![]() |
ca6de42d67 | ||
![]() |
c3e9b76fd6 | ||
![]() |
dca7b71457 | ||
![]() |
7106454dfb | ||
![]() |
b97e24aa6d | ||
![]() |
bec4cba501 | ||
![]() |
0568d5f8b2 | ||
![]() |
49db48e7fc | ||
![]() |
92fc5e0bcd | ||
![]() |
11391e597e | ||
![]() |
6b64f3b261 | ||
![]() |
dff6ba4e6d | ||
![]() |
036c89a6d1 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -116,3 +116,4 @@ UserSettings/Layouts/default-2021.dwlt
|
|||||||
Assets/UnityOnlineServiceData.meta
|
Assets/UnityOnlineServiceData.meta
|
||||||
Assets/UnityOnlineServiceData
|
Assets/UnityOnlineServiceData
|
||||||
|
|
||||||
|
.DS_Store
|
||||||
|
8
Assets/GameScripts/Editor/Inspector.meta
Normal file
8
Assets/GameScripts/Editor/Inspector.meta
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 22d1bcdd317c6f64daeb9bf9742495f2
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
8
Assets/GameScripts/Editor/Postprocessor.meta
Normal file
8
Assets/GameScripts/Editor/Postprocessor.meta
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 4944189ec9c939b45a65d93c704a22ec
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
33
Assets/GameScripts/HotFix/GameBase/Attribute.cs
Normal file
33
Assets/GameScripts/HotFix/GameBase/Attribute.cs
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace TEngine
|
||||||
|
{
|
||||||
|
#region Attribute
|
||||||
|
|
||||||
|
[AttributeUsage(AttributeTargets.Class)]
|
||||||
|
public class UpdateAttribute : Attribute
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
[AttributeUsage(AttributeTargets.Class)]
|
||||||
|
public class FixedUpdateAttribute : Attribute
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
[AttributeUsage(AttributeTargets.Class)]
|
||||||
|
public class LateUpdateAttribute : Attribute
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
[AttributeUsage(AttributeTargets.Class)]
|
||||||
|
public class RoleLoginAttribute : Attribute
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
[AttributeUsage(AttributeTargets.Class)]
|
||||||
|
public class RoleLogoutAttribute : Attribute
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
3
Assets/GameScripts/HotFix/GameBase/Attribute.cs.meta
Normal file
3
Assets/GameScripts/HotFix/GameBase/Attribute.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 80791cccf63d44faa348884ea0c506a2
|
||||||
|
timeCreated: 1684553027
|
@@ -51,6 +51,10 @@
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public virtual void OnRoleLogin()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
public virtual void OnRoleLogout()
|
public virtual void OnRoleLogout()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@@ -1,9 +1,10 @@
|
|||||||
using System.Collections.Generic;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace TEngine
|
namespace TEngine
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 通过LogicSys来驱动且具备Unity完整生命周期的单例(不继承MonoBehaviour)
|
/// 通过LogicSys来驱动且具备Unity完整生命周期的单例(不继承MonoBehaviour)。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T"></typeparam>
|
/// <typeparam name="T"></typeparam>
|
||||||
public abstract class BehaviourSingleton<T> : BaseBehaviourSingleton where T : BaseBehaviourSingleton, new()
|
public abstract class BehaviourSingleton<T> : BaseBehaviourSingleton where T : BaseBehaviourSingleton, new()
|
||||||
@@ -53,14 +54,30 @@ namespace TEngine
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 帧更新。
|
||||||
|
/// <remarks>需要UpdateAttribute。</remarks>
|
||||||
|
/// </summary>
|
||||||
public virtual void Update()
|
public virtual void Update()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 后帧更新。
|
||||||
|
/// <remarks>需要LateUpdateAttribute。</remarks>
|
||||||
|
/// </summary>
|
||||||
public virtual void LateUpdate()
|
public virtual void LateUpdate()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 物理帧更新。
|
||||||
|
/// <remarks>需要FixedUpdateAttribute。</remarks>
|
||||||
|
/// </summary>
|
||||||
|
public virtual void FixedUpdate()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
public virtual void Destroy()
|
public virtual void Destroy()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -84,12 +101,25 @@ namespace TEngine
|
|||||||
private readonly List<BaseBehaviourSingleton> _listStart = new List<BaseBehaviourSingleton>();
|
private readonly List<BaseBehaviourSingleton> _listStart = new List<BaseBehaviourSingleton>();
|
||||||
private readonly List<BaseBehaviourSingleton> _listUpdate = new List<BaseBehaviourSingleton>();
|
private readonly List<BaseBehaviourSingleton> _listUpdate = new List<BaseBehaviourSingleton>();
|
||||||
private readonly List<BaseBehaviourSingleton> _listLateUpdate = new List<BaseBehaviourSingleton>();
|
private readonly List<BaseBehaviourSingleton> _listLateUpdate = new List<BaseBehaviourSingleton>();
|
||||||
|
private readonly List<BaseBehaviourSingleton> _listFixedUpdate = new List<BaseBehaviourSingleton>();
|
||||||
|
|
||||||
public void RegSingleton(BaseBehaviourSingleton inst)
|
public void RegSingleton(BaseBehaviourSingleton inst)
|
||||||
{
|
{
|
||||||
Log.Assert(!_listInst.Contains(inst));
|
Log.Assert(!_listInst.Contains(inst));
|
||||||
_listInst.Add(inst);
|
_listInst.Add(inst);
|
||||||
_listStart.Add(inst);
|
_listStart.Add(inst);
|
||||||
|
if (HadAttribute<UpdateAttribute>(inst.GetType()))
|
||||||
|
{
|
||||||
|
_listUpdate.Add(inst);
|
||||||
|
}
|
||||||
|
if (HadAttribute<LateUpdateAttribute>(inst.GetType()))
|
||||||
|
{
|
||||||
|
_listLateUpdate.Add(inst);
|
||||||
|
}
|
||||||
|
if (HadAttribute<FixedUpdateAttribute>(inst.GetType()))
|
||||||
|
{
|
||||||
|
_listFixedUpdate.Add(inst);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UnRegSingleton(BaseBehaviourSingleton inst)
|
public void UnRegSingleton(BaseBehaviourSingleton inst)
|
||||||
@@ -175,6 +205,20 @@ namespace TEngine
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void OnFixedUpdate()
|
||||||
|
{
|
||||||
|
var listFixedUpdate = _listFixedUpdate;
|
||||||
|
var listFixedUpdateCnt = listFixedUpdate.Count;
|
||||||
|
for (int i = 0; i < listFixedUpdateCnt; i++)
|
||||||
|
{
|
||||||
|
var inst = listFixedUpdate[i];
|
||||||
|
|
||||||
|
TProfiler.BeginFirstSample(inst.GetType().FullName);
|
||||||
|
inst.FixedUpdate();
|
||||||
|
TProfiler.EndFirstSample();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public override void OnDestroy()
|
public override void OnDestroy()
|
||||||
{
|
{
|
||||||
for (int i = 0; i < _listInst.Count; i++)
|
for (int i = 0; i < _listInst.Count; i++)
|
||||||
@@ -208,5 +252,12 @@ namespace TEngine
|
|||||||
inst.OnDrawGizmos();
|
inst.OnDrawGizmos();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool HadAttribute<T>(Type type) where T:Attribute
|
||||||
|
{
|
||||||
|
T attribute = Attribute.GetCustomAttribute(type, typeof(T)) as T;
|
||||||
|
|
||||||
|
return attribute != null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -35,15 +35,21 @@ public interface ILogicSys
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
void OnFixedUpdate();
|
void OnFixedUpdate();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 登录账号/角色时调用
|
||||||
|
/// </summary>
|
||||||
|
void OnRoleLogin();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 清理数据接口,切换账号/角色时调用
|
/// 清理数据接口,切换账号/角色时调用
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void OnRoleLogout();
|
void OnRoleLogout();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// OnDrawGizmos
|
/// 绘制调试接口
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void OnDrawGizmos();
|
void OnDrawGizmos();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 暂停游戏
|
/// 暂停游戏
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
1118
Assets/GameScripts/HotFix/GameBase/Redux.cs
Normal file
1118
Assets/GameScripts/HotFix/GameBase/Redux.cs
Normal file
File diff suppressed because it is too large
Load Diff
3
Assets/GameScripts/HotFix/GameBase/Redux.cs.meta
Normal file
3
Assets/GameScripts/HotFix/GameBase/Redux.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 464445719fff48a78021df4a4a6b05a5
|
||||||
|
timeCreated: 1684552621
|
@@ -30,11 +30,11 @@ namespace GameBase
|
|||||||
{
|
{
|
||||||
if (_root == null)
|
if (_root == null)
|
||||||
{
|
{
|
||||||
_root = GameObject.Find("[SingletonMgr]");
|
_root = GameObject.Find("[GameModule]");
|
||||||
|
|
||||||
if (_root == null)
|
if (_root == null)
|
||||||
{
|
{
|
||||||
_root = new GameObject("[SingletonMgr]")
|
_root = new GameObject("[GameModule]")
|
||||||
{
|
{
|
||||||
transform =
|
transform =
|
||||||
{
|
{
|
||||||
@@ -42,7 +42,7 @@ namespace GameBase
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
UnityEngine.Object.DontDestroyOnLoad(_root);
|
Object.DontDestroyOnLoad(_root);
|
||||||
}
|
}
|
||||||
return _root;
|
return _root;
|
||||||
}
|
}
|
||||||
@@ -70,7 +70,7 @@ namespace GameBase
|
|||||||
_gameObjects.Add(go.name, go);
|
_gameObjects.Add(go.name, go);
|
||||||
if (Application.isPlaying)
|
if (Application.isPlaying)
|
||||||
{
|
{
|
||||||
UnityEngine.Object.DontDestroyOnLoad(go);
|
Object.DontDestroyOnLoad(go);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -80,7 +80,7 @@ namespace GameBase
|
|||||||
if (_gameObjects != null && _gameObjects.ContainsKey(go.name))
|
if (_gameObjects != null && _gameObjects.ContainsKey(go.name))
|
||||||
{
|
{
|
||||||
_gameObjects.Remove(go.name);
|
_gameObjects.Remove(go.name);
|
||||||
UnityEngine.Object.Destroy(go);
|
Object.Destroy(go);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -17,7 +17,7 @@ namespace GameBase
|
|||||||
{
|
{
|
||||||
if (_instance == null)
|
if (_instance == null)
|
||||||
{
|
{
|
||||||
var ins = UnityEngine.Object.FindObjectOfType<T>();
|
var ins = FindObjectOfType<T>();
|
||||||
if (ins != null)
|
if (ins != null)
|
||||||
{
|
{
|
||||||
var obj = ins.gameObject;
|
var obj = ins.gameObject;
|
||||||
@@ -32,11 +32,16 @@ namespace GameBase
|
|||||||
GameObject go = SingletonMgr.GetGameObject(instName);
|
GameObject go = SingletonMgr.GetGameObject(instName);
|
||||||
if (go == null)
|
if (go == null)
|
||||||
{
|
{
|
||||||
go = GameObject.Find($"{instName}");
|
go = GameObject.Find($"[{instName}]");
|
||||||
if (go == null)
|
if (go == null)
|
||||||
{
|
{
|
||||||
go = new GameObject(instName);
|
go = new GameObject($"[{instName}]")
|
||||||
go.transform.position = Vector3.zero;
|
{
|
||||||
|
transform =
|
||||||
|
{
|
||||||
|
position = Vector3.zero
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,11 +106,9 @@ namespace GameBase
|
|||||||
|
|
||||||
public static void Release()
|
public static void Release()
|
||||||
{
|
{
|
||||||
if (_instance != null)
|
if (_instance == null) return;
|
||||||
{
|
SingletonMgr.Release(_instance.gameObject);
|
||||||
SingletonMgr.Release(_instance.gameObject);
|
_instance = null;
|
||||||
_instance = null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -25,7 +25,8 @@ public partial class GameApp
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private void RegisterAllSystem()
|
private void RegisterAllSystem()
|
||||||
{
|
{
|
||||||
|
//带生命周期的单例系统。
|
||||||
|
AddLogicSys(BehaviourSingleSystem.Instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@@ -11,7 +11,7 @@
|
|||||||
],
|
],
|
||||||
"includePlatforms": [],
|
"includePlatforms": [],
|
||||||
"excludePlatforms": [],
|
"excludePlatforms": [],
|
||||||
"allowUnsafeCode": false,
|
"allowUnsafeCode": true,
|
||||||
"overrideReferences": false,
|
"overrideReferences": false,
|
||||||
"precompiledReferences": [],
|
"precompiledReferences": [],
|
||||||
"autoReferenced": true,
|
"autoReferenced": true,
|
||||||
|
@@ -0,0 +1,166 @@
|
|||||||
|
using TEngine;
|
||||||
|
|
||||||
|
namespace GameLogic
|
||||||
|
{
|
||||||
|
public enum ClientConnectWatcherStatus
|
||||||
|
{
|
||||||
|
StatusInit,
|
||||||
|
StatusReconnectAuto,
|
||||||
|
StatusReconnectConfirm,
|
||||||
|
StatusWaitExit
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ClientConnectWatcher
|
||||||
|
{
|
||||||
|
private readonly GameClient _client;
|
||||||
|
private ClientConnectWatcherStatus _status;
|
||||||
|
private float _statusTime;
|
||||||
|
private int _reconnectCnt = 0;
|
||||||
|
private int _disconnectReason = 0;
|
||||||
|
|
||||||
|
private bool _enable = false;
|
||||||
|
|
||||||
|
public bool Enable
|
||||||
|
{
|
||||||
|
get => _enable;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (_enable != value)
|
||||||
|
{
|
||||||
|
_enable = value;
|
||||||
|
if (_enable)
|
||||||
|
{
|
||||||
|
OnEnable();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
OnDisable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ClientConnectWatcherStatus Status
|
||||||
|
{
|
||||||
|
get => _status;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (_status == value) return;
|
||||||
|
_status = value;
|
||||||
|
_statusTime = NowTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private float NowTime => GameTime.unscaledTime;
|
||||||
|
|
||||||
|
public ClientConnectWatcher(GameClient client)
|
||||||
|
{
|
||||||
|
_client = client;
|
||||||
|
_statusTime = NowTime;
|
||||||
|
_status = ClientConnectWatcherStatus.StatusInit;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Update()
|
||||||
|
{
|
||||||
|
if (!_enable)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_client.IsEntered)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (_status)
|
||||||
|
{
|
||||||
|
case ClientConnectWatcherStatus.StatusInit:
|
||||||
|
UpdateOnInitStatus();
|
||||||
|
break;
|
||||||
|
case ClientConnectWatcherStatus.StatusReconnectAuto:
|
||||||
|
UpdateOnReconnectAuto();
|
||||||
|
break;
|
||||||
|
case ClientConnectWatcherStatus.StatusReconnectConfirm:
|
||||||
|
UpdateOnReconnectConfirm();
|
||||||
|
break;
|
||||||
|
case ClientConnectWatcherStatus.StatusWaitExit:
|
||||||
|
UpdateOnWaitExit();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnReConnect()
|
||||||
|
{
|
||||||
|
if (_status == ClientConnectWatcherStatus.StatusReconnectConfirm)
|
||||||
|
{
|
||||||
|
Status = ClientConnectWatcherStatus.StatusReconnectAuto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateOnInitStatus()
|
||||||
|
{
|
||||||
|
int autoReconnectMaxCount = 4;
|
||||||
|
if (_reconnectCnt <= autoReconnectMaxCount)
|
||||||
|
{
|
||||||
|
if (_reconnectCnt == 0)
|
||||||
|
{
|
||||||
|
_disconnectReason = _client.LastNetErrCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
Status = ClientConnectWatcherStatus.StatusReconnectAuto;
|
||||||
|
_reconnectCnt++;
|
||||||
|
|
||||||
|
//重连
|
||||||
|
_client.Reconnect();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Status = ClientConnectWatcherStatus.StatusReconnectConfirm;
|
||||||
|
_reconnectCnt++;
|
||||||
|
// UISys.Mgr.ShowUI(GAME_UI_TYPE.Tip_NetDisconn, UISys.Mgr.GetUIWindowParam().SetParam("errCode", m_disconnectReason));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateOnReconnectAuto()
|
||||||
|
{
|
||||||
|
if (_client.IsEntered)
|
||||||
|
{
|
||||||
|
Status = ClientConnectWatcherStatus.StatusInit;
|
||||||
|
_reconnectCnt = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
float nowTime = NowTime;
|
||||||
|
var timeoutTime = 10f;
|
||||||
|
|
||||||
|
if (_statusTime + timeoutTime < nowTime)
|
||||||
|
{
|
||||||
|
Log.Error("UpdateOnReconnectAuto timeout: {0}", timeoutTime);
|
||||||
|
|
||||||
|
//切换到默认的,下一帧继续判断是否需要自动还是手动
|
||||||
|
Status = ClientConnectWatcherStatus.StatusInit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateOnReconnectConfirm()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateOnWaitExit()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnDisable()
|
||||||
|
{
|
||||||
|
Status = ClientConnectWatcherStatus.StatusInit;
|
||||||
|
_reconnectCnt = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnEnable()
|
||||||
|
{
|
||||||
|
Status = ClientConnectWatcherStatus.StatusInit;
|
||||||
|
_reconnectCnt = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 3e4e637f3da340dd9512150c3e2ff087
|
||||||
|
timeCreated: 1684334948
|
428
Assets/GameScripts/HotFix/GameLogic/Network/GameClient.cs
Normal file
428
Assets/GameScripts/HotFix/GameLogic/Network/GameClient.cs
Normal file
@@ -0,0 +1,428 @@
|
|||||||
|
using System.Net.Sockets;
|
||||||
|
using GameBase;
|
||||||
|
using GameProto;
|
||||||
|
using TEngine;
|
||||||
|
using CSPkg = GameProto.CSPkg;
|
||||||
|
|
||||||
|
namespace GameLogic
|
||||||
|
{
|
||||||
|
public enum GameClientStatus
|
||||||
|
{
|
||||||
|
StatusInit, //初始化
|
||||||
|
StatusReconnect, //重新连接
|
||||||
|
StatusClose, //断开连接
|
||||||
|
StatusLogin, //登录中
|
||||||
|
StatusEnter, //AccountLogin成功,进入服务器了
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum CsMsgResult
|
||||||
|
{
|
||||||
|
NoError = 0,
|
||||||
|
NetworkError = 1,
|
||||||
|
InternalError = 2,
|
||||||
|
MsgTimeOut = 3,
|
||||||
|
PingTimeOut = 4,
|
||||||
|
}
|
||||||
|
|
||||||
|
//定义消息回报的回调接口
|
||||||
|
public delegate void CsMsgDelegate(CsMsgResult result, CSPkg msg);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 统计网络协议的接口
|
||||||
|
/// </summary>
|
||||||
|
public delegate void CsMsgStatDelegate(int cmdID, int pkgSize);
|
||||||
|
|
||||||
|
public class GameClient : Singleton<GameClient>
|
||||||
|
{
|
||||||
|
private readonly INetworkChannel _channel;
|
||||||
|
|
||||||
|
private GameClientStatus _status = GameClientStatus.StatusInit;
|
||||||
|
|
||||||
|
private readonly MsgDispatcher _dispatcher;
|
||||||
|
|
||||||
|
private readonly ClientConnectWatcher _connectWatcher;
|
||||||
|
|
||||||
|
private float _lastLogDisconnectErrTime = 0f;
|
||||||
|
|
||||||
|
private int _lastNetErrCode = 0;
|
||||||
|
|
||||||
|
public int LastNetErrCode => _lastNetErrCode;
|
||||||
|
|
||||||
|
public GameClientStatus Status
|
||||||
|
{
|
||||||
|
get => _status;
|
||||||
|
set => _status = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsEntered => _status == GameClientStatus.StatusEnter;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 连续心跳超时
|
||||||
|
/// </summary>
|
||||||
|
private int _heatBeatTimeoutNum = 0;
|
||||||
|
|
||||||
|
private int _ping = -1;
|
||||||
|
|
||||||
|
private float NowTime => GameTime.unscaledTime;
|
||||||
|
|
||||||
|
private string _lastHost = null;
|
||||||
|
private int _lastPort = 0;
|
||||||
|
|
||||||
|
public GameClient()
|
||||||
|
{
|
||||||
|
_connectWatcher = new ClientConnectWatcher(this);
|
||||||
|
_dispatcher = new MsgDispatcher();
|
||||||
|
_dispatcher.SetTimeout(5f);
|
||||||
|
GameEvent.AddEventListener<INetworkChannel,object>(NetworkEvent.NetworkConnectedEvent,OnNetworkConnected);
|
||||||
|
GameEvent.AddEventListener<INetworkChannel>(NetworkEvent.NetworkClosedEvent,OnNetworkClosed);
|
||||||
|
GameEvent.AddEventListener<INetworkChannel,NetworkErrorCode,SocketError,string>(NetworkEvent.NetworkErrorEvent,OnNetworkError);
|
||||||
|
GameEvent.AddEventListener<INetworkChannel,object>(NetworkEvent.NetworkCustomErrorEvent,OnNetworkCustomError);
|
||||||
|
_channel = Network.Instance.CreateNetworkChannel("GameClient", ServiceType.Tcp, new NetworkChannelHelper());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnNetworkConnected(INetworkChannel channel, object userdata)
|
||||||
|
{
|
||||||
|
bool isReconnect = (_status == GameClientStatus.StatusReconnect);
|
||||||
|
//准备登录
|
||||||
|
Status = GameClientStatus.StatusLogin;
|
||||||
|
|
||||||
|
OnServerConnected(isReconnect);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnNetworkClosed(INetworkChannel channel)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnNetworkError(INetworkChannel channel, NetworkErrorCode networkErrorCode, SocketError socketError, string errorMessage)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnNetworkCustomError(INetworkChannel channel, object userData)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Connect(string host, int port, bool reconnect = false)
|
||||||
|
{
|
||||||
|
ResetParam();
|
||||||
|
if (!reconnect)
|
||||||
|
{
|
||||||
|
SetWatchReconnect(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reconnect)
|
||||||
|
{
|
||||||
|
// GameEvent.Get<ICommUI>().ShowWaitUITip(WaitUISeq.LOGINWORLD_SEQID, G.R(TextDefine.ID_TIPS_RECONNECTING));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// GameEvent.Get<ICommUI>().ShowWaitUI(WaitUISeq.LOGINWORLD_SEQID);
|
||||||
|
}
|
||||||
|
|
||||||
|
_lastHost = host;
|
||||||
|
_lastPort = port;
|
||||||
|
|
||||||
|
Status = reconnect ? GameClientStatus.StatusReconnect : GameClientStatus.StatusInit;
|
||||||
|
|
||||||
|
_channel.Connect(host, port);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Reconnect()
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(_lastHost) || _lastPort <= 0)
|
||||||
|
{
|
||||||
|
// GameModule.UI.ShowTipMsg("Invalid reconnect param");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_connectWatcher.OnReConnect();
|
||||||
|
Connect(_lastHost, _lastPort, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void Shutdown()
|
||||||
|
{
|
||||||
|
_channel.Close();
|
||||||
|
_status = GameClientStatus.StatusInit;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnServerConnected(bool isReconnect)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool SendCsMsg(CSPkg reqPkg)
|
||||||
|
{
|
||||||
|
if (!IsStatusCanSendMsg(reqPkg.Head.MsgId))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return DoSendData(reqPkg);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsStatusCanSendMsg(uint msgId)
|
||||||
|
{
|
||||||
|
bool canSend = false;
|
||||||
|
if (_status == GameClientStatus.StatusLogin)
|
||||||
|
{
|
||||||
|
canSend = (msgId == (uint)CSMsgID.CsCmdActLoginReq);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_status == GameClientStatus.StatusEnter)
|
||||||
|
{
|
||||||
|
canSend = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!canSend)
|
||||||
|
{
|
||||||
|
float nowTime = NowTime;
|
||||||
|
if (_lastLogDisconnectErrTime + 5 < nowTime)
|
||||||
|
{
|
||||||
|
Log.Error("GameClient not connected, send msg failed, msgId[{0}]", msgId);
|
||||||
|
_lastLogDisconnectErrTime = nowTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
//UISys.Mgr.ShowTipMsg(TextDefine.ID_ERR_NETWORKD_DISCONNECT);
|
||||||
|
}
|
||||||
|
|
||||||
|
return canSend;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool SendCsMsg(CSPkg reqPkg, uint resCmd, CsMsgDelegate resHandler = null, bool needShowWaitUI = true)
|
||||||
|
{
|
||||||
|
if (!IsStatusCanSendMsg(reqPkg.Head.MsgId))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var ret = DoSendData(reqPkg);
|
||||||
|
if (!ret)
|
||||||
|
{
|
||||||
|
if (resHandler != null)
|
||||||
|
{
|
||||||
|
resHandler(CsMsgResult.InternalError, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
_dispatcher.NotifyCmdError(resCmd, CsMsgResult.InternalError);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//注册消息
|
||||||
|
if (resHandler != null)
|
||||||
|
{
|
||||||
|
_dispatcher.RegSeqHandle(reqPkg.Head.Echo, resCmd, resHandler);
|
||||||
|
if (reqPkg.Head.Echo > 0 && IsWaitingCmd(resCmd) && needShowWaitUI)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
// GameEvent.Get<ICommUI>().ShowWaitUI(reqPkg.Head.Echo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool DoSendData(CSPkg reqPkg)
|
||||||
|
{
|
||||||
|
if (!IsIgnoreLog(reqPkg.Head.MsgId))
|
||||||
|
{
|
||||||
|
Log.Debug("[c-s] CmdId[{0}]\n{1}", reqPkg.Head.MsgId, reqPkg.Body.ToString());
|
||||||
|
}
|
||||||
|
var sendRet = _channel.Send(reqPkg);
|
||||||
|
return sendRet;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool IsIgnoreLog(uint msgId)
|
||||||
|
{
|
||||||
|
bool ignoreLog = false;
|
||||||
|
switch (msgId)
|
||||||
|
{
|
||||||
|
case (uint)CSMsgID.CsCmdHeatbeatReq:
|
||||||
|
case (uint)CSMsgID.CsCmdHeatbeatRes:
|
||||||
|
ignoreLog = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return ignoreLog;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsWaitingCmd(uint msgId)
|
||||||
|
{
|
||||||
|
//心跳包不需要读条等待
|
||||||
|
if (msgId == (uint)CSMsgID.CsCmdHeatbeatRes)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ResetParam()
|
||||||
|
{
|
||||||
|
_lastLogDisconnectErrTime = 0f;
|
||||||
|
_heatBeatTimeoutNum = 0;
|
||||||
|
_lastHbTime = 0f;
|
||||||
|
_ping = -1;
|
||||||
|
_lastNetErrCode = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnUpdate()
|
||||||
|
{
|
||||||
|
_dispatcher.Update();
|
||||||
|
TickHeartBeat();
|
||||||
|
CheckHeatBeatTimeout();
|
||||||
|
_connectWatcher.Update();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 注册静态消息
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="iCmdID"></param>
|
||||||
|
/// <param name="msgDelegate"></param>
|
||||||
|
public void RegCmdHandle(int iCmdID, CsMsgDelegate msgDelegate)
|
||||||
|
{
|
||||||
|
_dispatcher.RegCmdHandle((uint)iCmdID, msgDelegate);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 移除消息处理函数
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="cmdId"></param>
|
||||||
|
/// <param name="msgDelegate"></param>
|
||||||
|
public void RmvCmdHandle(int cmdId, CsMsgDelegate msgDelegate)
|
||||||
|
{
|
||||||
|
_dispatcher.RmvCmdHandle((uint)cmdId, msgDelegate);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 设置加密密钥
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="key"></param>
|
||||||
|
public void SetEncryptKey(string key)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 设置是否需要监控网络重连。
|
||||||
|
/// 登录成功后,开启监控,可以自动重连或者提示玩家重连。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="needWatch"></param>
|
||||||
|
public void SetWatchReconnect(bool needWatch)
|
||||||
|
{
|
||||||
|
_connectWatcher.Enable = needWatch;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsNetworkOkAndLogin()
|
||||||
|
{
|
||||||
|
return _status == GameClientStatus.StatusEnter;
|
||||||
|
}
|
||||||
|
|
||||||
|
#region 心跳处理
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 最近一次心跳的时间
|
||||||
|
/// </summary>
|
||||||
|
private float _lastHbTime = 0f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 心跳间隔
|
||||||
|
/// </summary>
|
||||||
|
private readonly float _heartBeatDurTime = 5;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 心跳超时的最大次数
|
||||||
|
/// </summary>
|
||||||
|
private const int HeatBeatTimeoutMaxCount = 2;
|
||||||
|
|
||||||
|
private bool CheckHeatBeatTimeout()
|
||||||
|
{
|
||||||
|
if (_heatBeatTimeoutNum >= HeatBeatTimeoutMaxCount)
|
||||||
|
{
|
||||||
|
//断开连接
|
||||||
|
Shutdown();
|
||||||
|
|
||||||
|
//准备重连
|
||||||
|
_heatBeatTimeoutNum = 0;
|
||||||
|
Status = GameClientStatus.StatusClose;
|
||||||
|
Log.Error("heat beat detect timeout");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TickHeartBeat()
|
||||||
|
{
|
||||||
|
if (Status != GameClientStatus.StatusEnter)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var nowTime = NowTime;
|
||||||
|
if (_lastHbTime + _heartBeatDurTime < nowTime)
|
||||||
|
{
|
||||||
|
_lastHbTime = nowTime;
|
||||||
|
|
||||||
|
CSPkg heatPkg = ProtobufUtility.BuildCsMsg((int)CSMsgID.CsCmdHeatbeatReq);
|
||||||
|
heatPkg.Body.HeatBeatReq = new CSHeatBeatReq { HeatEchoTime = _lastHbTime };
|
||||||
|
SendCsMsg(heatPkg, (int)CSMsgID.CsCmdHeatbeatRes, HandleHeatBeatRes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandleHeatBeatRes(CsMsgResult result, CSPkg msg)
|
||||||
|
{
|
||||||
|
if (result != CsMsgResult.NoError)
|
||||||
|
{
|
||||||
|
//如果是超时了,则标记最近收到包的次数
|
||||||
|
if (result == CsMsgResult.MsgTimeOut)
|
||||||
|
{
|
||||||
|
_heatBeatTimeoutNum++;
|
||||||
|
Log.Warning("heat beat timeout: {0}", _heatBeatTimeoutNum);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var resBody = msg.Body.HeatBeatRes;
|
||||||
|
float diffTime = NowTime - resBody.HeatEchoTime;
|
||||||
|
_ping = (int)(diffTime * 1000);
|
||||||
|
_heatBeatTimeoutNum = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Ping值
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// ping值
|
||||||
|
/// </summary>
|
||||||
|
public int Ping
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (IsPingValid())
|
||||||
|
{
|
||||||
|
return _ping / 4;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsPingValid()
|
||||||
|
{
|
||||||
|
if (IsNetworkOkAndLogin())
|
||||||
|
{
|
||||||
|
return _ping >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 8c5441725c9f4d98a7790dc76a6a0c48
|
||||||
|
timeCreated: 1684331687
|
@@ -1,19 +0,0 @@
|
|||||||
using System;
|
|
||||||
using ProtoBuf;
|
|
||||||
|
|
||||||
namespace GameLogic
|
|
||||||
{
|
|
||||||
[Serializable, ProtoContract(Name = @"HeartBeat")]
|
|
||||||
public class HeartBeat : PacketBase
|
|
||||||
{
|
|
||||||
public HeartBeat()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public override int Id => 1;
|
|
||||||
|
|
||||||
public override void Clear()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,3 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: d8b9b60d2abf409ca9dd2ce00506ac79
|
|
||||||
timeCreated: 1682046644
|
|
265
Assets/GameScripts/HotFix/GameLogic/Network/MsgDispatcher.cs
Normal file
265
Assets/GameScripts/HotFix/GameLogic/Network/MsgDispatcher.cs
Normal file
@@ -0,0 +1,265 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using GameProto;
|
||||||
|
using TEngine;
|
||||||
|
using CSPkg = GameProto.CSPkg;
|
||||||
|
|
||||||
|
namespace GameLogic
|
||||||
|
{
|
||||||
|
internal class MsgHandleDataToRmv
|
||||||
|
{
|
||||||
|
public uint MsgId;
|
||||||
|
public CsMsgDelegate Handle;
|
||||||
|
};
|
||||||
|
|
||||||
|
class MsgDispatcher
|
||||||
|
{
|
||||||
|
const int CheckTimeoutPerframe = 10;
|
||||||
|
const int MaxMsgHandle = 256;
|
||||||
|
|
||||||
|
private readonly CsMsgDelegate[] _aMsgHandles = new CsMsgDelegate[MaxMsgHandle];
|
||||||
|
private readonly float[] _fMsgRegTime = new float[MaxMsgHandle];
|
||||||
|
private readonly UInt32[] _adwMsgRegSeq = new UInt32[MaxMsgHandle]; //因为_aiMsgRegResCmdID存储的是hash,不能保证一定seqid一样,所以这儿存储下,用来校验
|
||||||
|
private readonly uint[] _aiMsgRegResCmdID = new uint[MaxMsgHandle];
|
||||||
|
|
||||||
|
UInt32 _dwLastCheckIndex = 0;
|
||||||
|
|
||||||
|
private readonly Dictionary<uint, List<CsMsgDelegate>> _mapCmdHandle = new Dictionary<uint, List<CsMsgDelegate>>();
|
||||||
|
private readonly List<CsMsgStatDelegate> _listStatHandle = new List<CsMsgStatDelegate>();
|
||||||
|
|
||||||
|
//防止在处理消息的时候又删除了消息映射,所以这儿加了个队列来做个保护
|
||||||
|
private readonly List<MsgHandleDataToRmv> _rmvList = new List<MsgHandleDataToRmv>();
|
||||||
|
private bool _isInHandleLoop = false;
|
||||||
|
private float _timeout = 5;
|
||||||
|
|
||||||
|
// 清理所有的网络消息
|
||||||
|
public void CleanAllNetMsg()
|
||||||
|
{
|
||||||
|
_mapCmdHandle.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetTimeout(float timeout)
|
||||||
|
{
|
||||||
|
_timeout = timeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RegSeqHandle(UInt32 dwMsgSeqID, uint iResCmdID, CsMsgDelegate msgDelegate)
|
||||||
|
{
|
||||||
|
UInt32 hashIndex = dwMsgSeqID % MaxMsgHandle;
|
||||||
|
if (_aMsgHandles[hashIndex] != null)
|
||||||
|
{
|
||||||
|
OnCallSeqHandle(_adwMsgRegSeq[hashIndex], _aiMsgRegResCmdID[hashIndex]);
|
||||||
|
NotifyTimeout(_aMsgHandles[hashIndex]);
|
||||||
|
RmvReg((int)hashIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
_aMsgHandles[hashIndex] = msgDelegate;
|
||||||
|
_fMsgRegTime[hashIndex] = NowTime;
|
||||||
|
_adwMsgRegSeq[hashIndex] = dwMsgSeqID;
|
||||||
|
_aiMsgRegResCmdID[hashIndex] = iResCmdID;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RegCmdHandle(uint iCmdID, CsMsgDelegate msgDelegate)
|
||||||
|
{
|
||||||
|
if (!_mapCmdHandle.TryGetValue(iCmdID, out var listHandle))
|
||||||
|
{
|
||||||
|
listHandle = new List<CsMsgDelegate>();
|
||||||
|
_mapCmdHandle[iCmdID] = listHandle;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (listHandle != null)
|
||||||
|
{
|
||||||
|
if (listHandle.Contains(msgDelegate))
|
||||||
|
{
|
||||||
|
Log.Error("-------------repeat RegCmdHandle:{0}-----------", iCmdID);
|
||||||
|
}
|
||||||
|
|
||||||
|
listHandle.Add(msgDelegate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 注册统计处理接口
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="handler"></param>
|
||||||
|
public void RegCmdStatHandle(CsMsgStatDelegate handler)
|
||||||
|
{
|
||||||
|
_listStatHandle.Add(handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DispatchCmdStat(int cmdID, int pkgSize)
|
||||||
|
{
|
||||||
|
foreach (CsMsgStatDelegate handle in _listStatHandle)
|
||||||
|
{
|
||||||
|
handle(cmdID, pkgSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RmvCmdHandle(uint iCmdID, CsMsgDelegate msgDelegate)
|
||||||
|
{
|
||||||
|
if (_isInHandleLoop)
|
||||||
|
{
|
||||||
|
MsgHandleDataToRmv toRmvData = new MsgHandleDataToRmv();
|
||||||
|
toRmvData.MsgId = iCmdID;
|
||||||
|
toRmvData.Handle = msgDelegate;
|
||||||
|
|
||||||
|
_rmvList.Add(toRmvData);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_mapCmdHandle.TryGetValue(iCmdID, out var listHandle))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (listHandle != null)
|
||||||
|
{
|
||||||
|
listHandle.Remove(msgDelegate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void NotifyCmdError(uint iCmdID, CsMsgResult result)
|
||||||
|
{
|
||||||
|
NotifyCmdHandle(iCmdID, result, default(CSPkg));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected bool NotifyCmdHandle(uint cmdID, CsMsgResult result, CSPkg pkg)
|
||||||
|
{
|
||||||
|
bool ret = false;
|
||||||
|
if (_mapCmdHandle.TryGetValue(cmdID, out var listHandle))
|
||||||
|
{
|
||||||
|
_isInHandleLoop = true;
|
||||||
|
|
||||||
|
var rmvList = _rmvList;
|
||||||
|
rmvList.Clear();
|
||||||
|
foreach (CsMsgDelegate handle in listHandle)
|
||||||
|
{
|
||||||
|
ret = true;
|
||||||
|
|
||||||
|
TProfiler.BeginSample("handle");
|
||||||
|
handle(result, pkg);
|
||||||
|
TProfiler.EndSample();
|
||||||
|
}
|
||||||
|
|
||||||
|
_isInHandleLoop = false;
|
||||||
|
|
||||||
|
//再统一删除掉
|
||||||
|
int rmvCnt = rmvList.Count;
|
||||||
|
for (int i = 0; i < rmvCnt; i++)
|
||||||
|
{
|
||||||
|
var rmvItem = rmvList[i];
|
||||||
|
Log.Error("-------------remove cmd handle on loop:{0}-----------", rmvItem.MsgId);
|
||||||
|
RmvCmdHandle(rmvItem.MsgId, rmvItem.Handle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void OnCallSeqHandle(UInt32 echoSeq, uint resCmdID)
|
||||||
|
{
|
||||||
|
if (echoSeq > 0)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
// GameEvent.Get<ICommUI>().FinWaitUI(echoSeq);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void NotifyTimeout(CsMsgDelegate msgHandler)
|
||||||
|
{
|
||||||
|
msgHandler(CsMsgResult.MsgTimeOut, default(CSPkg));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void NotifySeqError(UInt32 dwSeqID, CsMsgResult result)
|
||||||
|
{
|
||||||
|
UInt32 hashIndex = dwSeqID % MaxMsgHandle;
|
||||||
|
|
||||||
|
//先判断是否有注册的指定消息
|
||||||
|
if (_aMsgHandles[hashIndex] != null &&
|
||||||
|
_adwMsgRegSeq[hashIndex] == dwSeqID)
|
||||||
|
{
|
||||||
|
OnCallSeqHandle(dwSeqID, _aiMsgRegResCmdID[hashIndex]);
|
||||||
|
_aMsgHandles[hashIndex](result, null);
|
||||||
|
|
||||||
|
RmvReg((int)hashIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsCmdFilterNoLog(int cmdID)
|
||||||
|
{
|
||||||
|
switch (cmdID)
|
||||||
|
{
|
||||||
|
case (int)CSMsgID.CsCmdHeatbeatRes:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void NotifyMsg(CSPkg msg)
|
||||||
|
{
|
||||||
|
UInt32 dwSeq = msg.Head.Echo;
|
||||||
|
UInt32 hashIndex = dwSeq % MaxMsgHandle;
|
||||||
|
//判断是否有固定的消息处理流程
|
||||||
|
bool bHaveHandle = NotifyCmdHandle(msg.Head.MsgId, CsMsgResult.NoError, msg);
|
||||||
|
|
||||||
|
//再判断是否有注册的指定消息
|
||||||
|
if (_aMsgHandles[hashIndex] != null &&
|
||||||
|
_adwMsgRegSeq[hashIndex] == dwSeq &&
|
||||||
|
_aiMsgRegResCmdID[hashIndex] == (int)msg.Head.MsgId)
|
||||||
|
{
|
||||||
|
OnCallSeqHandle(_adwMsgRegSeq[hashIndex], _aiMsgRegResCmdID[hashIndex]);
|
||||||
|
_aMsgHandles[hashIndex](CsMsgResult.NoError, msg);
|
||||||
|
RmvReg((int)hashIndex);
|
||||||
|
bHaveHandle = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!bHaveHandle)
|
||||||
|
{
|
||||||
|
Log.Debug("there is no handle for Msg[{0}]", msg.Head.MsgId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private float NowTime => GameTime.unscaledTime;
|
||||||
|
|
||||||
|
public void Update()
|
||||||
|
{
|
||||||
|
CheckTimeOut();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 定时检查是否请求超时。
|
||||||
|
/// </summary>
|
||||||
|
private void CheckTimeOut()
|
||||||
|
{
|
||||||
|
float timeout = _timeout;
|
||||||
|
float nowTime = NowTime;
|
||||||
|
for (int i = 0; i < CheckTimeoutPerframe; i++)
|
||||||
|
{
|
||||||
|
_dwLastCheckIndex = (_dwLastCheckIndex + 1) % MaxMsgHandle;
|
||||||
|
if (_aMsgHandles[_dwLastCheckIndex] != null)
|
||||||
|
{
|
||||||
|
if (_fMsgRegTime[_dwLastCheckIndex] + timeout < nowTime)
|
||||||
|
{
|
||||||
|
Log.Error("msg timeout, resCmdID[{0}], reqSeq[{1}]", _aiMsgRegResCmdID[_dwLastCheckIndex],
|
||||||
|
_adwMsgRegSeq[_dwLastCheckIndex]);
|
||||||
|
|
||||||
|
OnCallSeqHandle(_adwMsgRegSeq[_dwLastCheckIndex], _aiMsgRegResCmdID[_dwLastCheckIndex]);
|
||||||
|
NotifyTimeout(_aMsgHandles[_dwLastCheckIndex]);
|
||||||
|
|
||||||
|
RmvReg((int)_dwLastCheckIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RmvReg(int index)
|
||||||
|
{
|
||||||
|
_aMsgHandles[index] = null;
|
||||||
|
_adwMsgRegSeq[index] = 0;
|
||||||
|
_aiMsgRegResCmdID[index] = 0;
|
||||||
|
_fMsgRegTime[index] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 7d667fb84fed4c5f93a06c464585512f
|
||||||
|
timeCreated: 1684333223
|
@@ -1,10 +1,10 @@
|
|||||||
using ProtoBuf;
|
using System;
|
||||||
using ProtoBuf.Meta;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
using System.Reflection;
|
using GameProto;
|
||||||
|
using Google.Protobuf;
|
||||||
using TEngine;
|
using TEngine;
|
||||||
|
|
||||||
namespace GameLogic
|
namespace GameLogic
|
||||||
@@ -29,31 +29,6 @@ namespace GameLogic
|
|||||||
{
|
{
|
||||||
_networkChannel = networkChannel;
|
_networkChannel = networkChannel;
|
||||||
|
|
||||||
// 反射注册包和包处理函数。
|
|
||||||
Type packetBaseType = typeof(ProtoPacket);
|
|
||||||
Assembly assembly = Assembly.GetExecutingAssembly();
|
|
||||||
Type[] types = assembly.GetTypes();
|
|
||||||
for (int i = 0; i < types.Length; i++)
|
|
||||||
{
|
|
||||||
if (!types[i].IsClass || types[i].IsAbstract)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (types[i].BaseType == packetBaseType)
|
|
||||||
{
|
|
||||||
PacketBase packetBase = (PacketBase)Activator.CreateInstance(types[i]);
|
|
||||||
Type packetType = GetServerToClientPacketType(packetBase.Id);
|
|
||||||
if (packetType != null)
|
|
||||||
{
|
|
||||||
Log.Warning("Already exist packet type '{0}', check '{1}' or '{2}'?.", packetBase.Id.ToString(), packetType.Name, packetBase.GetType().Name);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
_serverToClientPacketTypes.Add(packetBase.Id, types[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
GameEvent.AddEventListener<INetworkChannel, object>(NetworkEvent.NetworkConnectedEvent, OnNetworkConnected);
|
GameEvent.AddEventListener<INetworkChannel, object>(NetworkEvent.NetworkConnectedEvent, OnNetworkConnected);
|
||||||
GameEvent.AddEventListener<INetworkChannel>(NetworkEvent.NetworkClosedEvent, OnNetworkClosed);
|
GameEvent.AddEventListener<INetworkChannel>(NetworkEvent.NetworkClosedEvent, OnNetworkClosed);
|
||||||
GameEvent.AddEventListener<INetworkChannel, int>(NetworkEvent.NetworkMissHeartBeatEvent, OnNetworkMissHeartBeat);
|
GameEvent.AddEventListener<INetworkChannel, int>(NetworkEvent.NetworkMissHeartBeatEvent, OnNetworkMissHeartBeat);
|
||||||
@@ -84,13 +59,16 @@ namespace GameLogic
|
|||||||
_networkChannel.Socket.SendBufferSize = 1024 * 64;
|
_networkChannel.Socket.SendBufferSize = 1024 * 64;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public CSPkg HeartBeatPack = new CSPkg { Head = new CSPkgHead(), Body = new CSPkgBody() };
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 发送心跳消息包。
|
/// 发送心跳消息包。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>是否发送心跳消息包成功。</returns>
|
/// <returns>是否发送心跳消息包成功。</returns>
|
||||||
public bool SendHeartBeat()
|
public bool SendHeartBeat()
|
||||||
{
|
{
|
||||||
_networkChannel.Send(MemoryPool.Acquire<HeartBeat>());
|
HeartBeatPack.Head.MsgId = (uint)CSMsgID.CsCmdHeatbeatReq;
|
||||||
|
_networkChannel.Send(HeartBeatPack);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,10 +79,9 @@ namespace GameLogic
|
|||||||
/// <param name="packet">要序列化的消息包。</param>
|
/// <param name="packet">要序列化的消息包。</param>
|
||||||
/// <param name="destination">要序列化的目标流。</param>
|
/// <param name="destination">要序列化的目标流。</param>
|
||||||
/// <returns>是否序列化成功。</returns>
|
/// <returns>是否序列化成功。</returns>
|
||||||
public bool Serialize<T>(T packet, Stream destination) where T : Packet
|
public bool Serialize(CSPkg packet, Stream destination)
|
||||||
{
|
{
|
||||||
PacketBase packetImpl = packet as PacketBase;
|
if (packet == null)
|
||||||
if (packetImpl == null)
|
|
||||||
{
|
{
|
||||||
Log.Warning("Packet is invalid.");
|
Log.Warning("Packet is invalid.");
|
||||||
return false;
|
return false;
|
||||||
@@ -112,14 +89,7 @@ namespace GameLogic
|
|||||||
|
|
||||||
_cachedStream.SetLength(_cachedStream.Capacity); // 此行防止 Array.Copy 的数据无法写入
|
_cachedStream.SetLength(_cachedStream.Capacity); // 此行防止 Array.Copy 的数据无法写入
|
||||||
_cachedStream.Position = 0L;
|
_cachedStream.Position = 0L;
|
||||||
|
global::ProtobufUtility.ToStreamWithHead(packet,_cachedStream);
|
||||||
PacketHeader packetHeader = MemoryPool.Acquire<PacketHeader>();
|
|
||||||
Serializer.Serialize(_cachedStream, packetHeader);
|
|
||||||
MemoryPool.Release(packetHeader);
|
|
||||||
|
|
||||||
Serializer.SerializeWithLengthPrefix(_cachedStream, packet, PrefixStyle.Fixed32);
|
|
||||||
MemoryPool.Release((IMemory)packet);
|
|
||||||
|
|
||||||
_cachedStream.WriteTo(destination);
|
_cachedStream.WriteTo(destination);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -134,7 +104,9 @@ namespace GameLogic
|
|||||||
{
|
{
|
||||||
// 注意:此函数并不在主线程调用!
|
// 注意:此函数并不在主线程调用!
|
||||||
customErrorData = null;
|
customErrorData = null;
|
||||||
return (IPacketHeader)RuntimeTypeModel.Default.Deserialize(source, MemoryPool.Acquire<PacketHeader>(), typeof(PacketHeader));
|
PacketHeader packetHeader = MemoryPool.Acquire<PacketHeader>();
|
||||||
|
packetHeader.PacketLength = ((MemoryStream)source).GetBuffer()[0];
|
||||||
|
return packetHeader;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -144,7 +116,7 @@ namespace GameLogic
|
|||||||
/// <param name="source">要反序列化的来源流。</param>
|
/// <param name="source">要反序列化的来源流。</param>
|
||||||
/// <param name="customErrorData">用户自定义错误数据。</param>
|
/// <param name="customErrorData">用户自定义错误数据。</param>
|
||||||
/// <returns>反序列化后的消息包。</returns>
|
/// <returns>反序列化后的消息包。</returns>
|
||||||
public Packet DeserializePacket(IPacketHeader packetHeader, Stream source, out object customErrorData)
|
public CSPkg DeserializePacket(IPacketHeader packetHeader, Stream source, out object customErrorData)
|
||||||
{
|
{
|
||||||
// 注意:此函数并不在主线程调用!
|
// 注意:此函数并不在主线程调用!
|
||||||
customErrorData = null;
|
customErrorData = null;
|
||||||
@@ -156,17 +128,17 @@ namespace GameLogic
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
Packet packet = null;
|
CSPkg csPkg = null;
|
||||||
if (scPacketHeader.IsValid)
|
if (scPacketHeader.IsValid)
|
||||||
{
|
{
|
||||||
Type packetType = GetServerToClientPacketType(scPacketHeader.Id);
|
try
|
||||||
if (packetType != null)
|
|
||||||
{
|
{
|
||||||
packet = (Packet)RuntimeTypeModel.Default.DeserializeWithLengthPrefix(source, MemoryPool.Acquire(packetType), packetType, PrefixStyle.Fixed32, 0);
|
csPkg = global::ProtobufUtility.Deserialize(((MemoryStream)source).GetBuffer(),0,scPacketHeader.PacketLength);
|
||||||
|
Log.Debug("[s-c] CmdId[{0}]\n{1}", csPkg.Head.MsgId, csPkg.ToString());
|
||||||
}
|
}
|
||||||
else
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
Log.Warning("Can not deserialize packet for packet id '{0}'.", scPacketHeader.Id.ToString());
|
Log.Warning(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -175,7 +147,7 @@ namespace GameLogic
|
|||||||
}
|
}
|
||||||
|
|
||||||
MemoryPool.Release(scPacketHeader);
|
MemoryPool.Release(scPacketHeader);
|
||||||
return packet;
|
return csPkg;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Type GetServerToClientPacketType(int id)
|
private Type GetServerToClientPacketType(int id)
|
||||||
|
@@ -1,6 +1,8 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
|
using GameProto;
|
||||||
|
using Google.Protobuf;
|
||||||
|
|
||||||
namespace TEngine
|
namespace TEngine
|
||||||
{
|
{
|
||||||
@@ -163,7 +165,7 @@ namespace TEngine
|
|||||||
/// <typeparam name="T">消息包类型。</typeparam>
|
/// <typeparam name="T">消息包类型。</typeparam>
|
||||||
/// <param name="packet">要发送的消息包。</param>
|
/// <param name="packet">要发送的消息包。</param>
|
||||||
/// <returns>消息包是否发送成功。</returns>
|
/// <returns>消息包是否发送成功。</returns>
|
||||||
bool Send<T>(T packet) where T : Packet;
|
bool Send(CSPkg packet);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 向远程主机发送消息包并注册消息回调。
|
/// 向远程主机发送消息包并注册消息回调。
|
||||||
@@ -173,6 +175,6 @@ namespace TEngine
|
|||||||
/// <param name="resHandler">要注册的回调。</param>
|
/// <param name="resHandler">要注册的回调。</param>
|
||||||
/// <param name="needShowWaitUI">是否需要等待UI。</param>
|
/// <param name="needShowWaitUI">是否需要等待UI。</param>
|
||||||
/// <returns>消息包是否发送成功。</returns>
|
/// <returns>消息包是否发送成功。</returns>
|
||||||
bool Send<T>(T packet, CsMsgDelegate resHandler, bool needShowWaitUI = false) where T : Packet;
|
bool Send(CSPkg packet, CsMsgDelegate resHandler, bool needShowWaitUI = false);
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -1,4 +1,5 @@
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
|
using GameProto;
|
||||||
|
|
||||||
namespace TEngine
|
namespace TEngine
|
||||||
{
|
{
|
||||||
@@ -44,7 +45,7 @@ namespace TEngine
|
|||||||
/// <param name="packet">要序列化的消息包。</param>
|
/// <param name="packet">要序列化的消息包。</param>
|
||||||
/// <param name="destination">要序列化的目标流。</param>
|
/// <param name="destination">要序列化的目标流。</param>
|
||||||
/// <returns>是否序列化成功。</returns>
|
/// <returns>是否序列化成功。</returns>
|
||||||
bool Serialize<T>(T packet, Stream destination) where T : Packet;
|
bool Serialize(CSPkg packet, Stream destination);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 反序列化消息包头。
|
/// 反序列化消息包头。
|
||||||
@@ -61,6 +62,6 @@ namespace TEngine
|
|||||||
/// <param name="source">要反序列化的来源流。</param>
|
/// <param name="source">要反序列化的来源流。</param>
|
||||||
/// <param name="customErrorData">用户自定义错误数据。</param>
|
/// <param name="customErrorData">用户自定义错误数据。</param>
|
||||||
/// <returns>反序列化后的消息包。</returns>
|
/// <returns>反序列化后的消息包。</returns>
|
||||||
Packet DeserializePacket(IPacketHeader packetHeader, Stream source, out object customErrorData);
|
CSPkg DeserializePacket(IPacketHeader packetHeader, Stream source, out object customErrorData);
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -1,5 +1,6 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
|
using GameBase;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
namespace TEngine
|
namespace TEngine
|
||||||
@@ -8,9 +9,9 @@ namespace TEngine
|
|||||||
/// 网络组件。
|
/// 网络组件。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DisallowMultipleComponent]
|
[DisallowMultipleComponent]
|
||||||
public sealed class Network : GameFrameworkModuleBase
|
public sealed class Network : UnitySingleton<Network>
|
||||||
{
|
{
|
||||||
private static INetworkManager m_NetworkManager = null;
|
private NetworkManager m_NetworkManager = null;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取网络频道数量。
|
/// 获取网络频道数量。
|
||||||
@@ -20,11 +21,12 @@ namespace TEngine
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 游戏框架组件初始化。
|
/// 游戏框架组件初始化。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected override void Awake()
|
public override void Awake()
|
||||||
{
|
{
|
||||||
base.Awake();
|
base.Awake();
|
||||||
|
|
||||||
m_NetworkManager = GameFrameworkEntry.GetModule<INetworkManager>();
|
// m_NetworkManager = GameFrameworkEntry.GetModule<INetworkManager>();
|
||||||
|
m_NetworkManager = new NetworkManager();
|
||||||
if (m_NetworkManager == null)
|
if (m_NetworkManager == null)
|
||||||
{
|
{
|
||||||
Log.Fatal("Network manager is invalid.");
|
Log.Fatal("Network manager is invalid.");
|
||||||
@@ -38,12 +40,17 @@ namespace TEngine
|
|||||||
m_NetworkManager.NetworkCustomError += OnNetworkCustomError;
|
m_NetworkManager.NetworkCustomError += OnNetworkCustomError;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void Update()
|
||||||
|
{
|
||||||
|
m_NetworkManager.Update(GameTime.deltaTime, GameTime.unscaledDeltaTime);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 检查是否存在网络频道。
|
/// 检查是否存在网络频道。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="name">网络频道名称。</param>
|
/// <param name="name">网络频道名称。</param>
|
||||||
/// <returns>是否存在网络频道。</returns>
|
/// <returns>是否存在网络频道。</returns>
|
||||||
public static bool HasNetworkChannel(string name)
|
public bool HasNetworkChannel(string name)
|
||||||
{
|
{
|
||||||
return m_NetworkManager.HasNetworkChannel(name);
|
return m_NetworkManager.HasNetworkChannel(name);
|
||||||
}
|
}
|
||||||
@@ -53,7 +60,7 @@ namespace TEngine
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="name">网络频道名称。</param>
|
/// <param name="name">网络频道名称。</param>
|
||||||
/// <returns>要获取的网络频道。</returns>
|
/// <returns>要获取的网络频道。</returns>
|
||||||
public static INetworkChannel GetNetworkChannel(string name)
|
public INetworkChannel GetNetworkChannel(string name)
|
||||||
{
|
{
|
||||||
return m_NetworkManager.GetNetworkChannel(name);
|
return m_NetworkManager.GetNetworkChannel(name);
|
||||||
}
|
}
|
||||||
@@ -62,7 +69,7 @@ namespace TEngine
|
|||||||
/// 获取所有网络频道。
|
/// 获取所有网络频道。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>所有网络频道。</returns>
|
/// <returns>所有网络频道。</returns>
|
||||||
public static INetworkChannel[] StaticGetAllNetworkChannels()
|
public INetworkChannel[] StaticGetAllNetworkChannels()
|
||||||
{
|
{
|
||||||
return m_NetworkManager.GetAllNetworkChannels();
|
return m_NetworkManager.GetAllNetworkChannels();
|
||||||
}
|
}
|
||||||
@@ -80,7 +87,7 @@ namespace TEngine
|
|||||||
/// 获取所有网络频道。
|
/// 获取所有网络频道。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="results">所有网络频道。</param>
|
/// <param name="results">所有网络频道。</param>
|
||||||
public static void GetAllNetworkChannels(List<INetworkChannel> results)
|
public void GetAllNetworkChannels(List<INetworkChannel> results)
|
||||||
{
|
{
|
||||||
m_NetworkManager.GetAllNetworkChannels(results);
|
m_NetworkManager.GetAllNetworkChannels(results);
|
||||||
}
|
}
|
||||||
@@ -92,7 +99,8 @@ namespace TEngine
|
|||||||
/// <param name="serviceType">网络服务类型。</param>
|
/// <param name="serviceType">网络服务类型。</param>
|
||||||
/// <param name="networkChannelHelper">网络频道辅助器。</param>
|
/// <param name="networkChannelHelper">网络频道辅助器。</param>
|
||||||
/// <returns>要创建的网络频道。</returns>
|
/// <returns>要创建的网络频道。</returns>
|
||||||
public static INetworkChannel CreateNetworkChannel(string name, ServiceType serviceType, INetworkChannelHelper networkChannelHelper)
|
public INetworkChannel CreateNetworkChannel(string name, ServiceType serviceType,
|
||||||
|
INetworkChannelHelper networkChannelHelper)
|
||||||
{
|
{
|
||||||
return m_NetworkManager.CreateNetworkChannel(name, serviceType, networkChannelHelper);
|
return m_NetworkManager.CreateNetworkChannel(name, serviceType, networkChannelHelper);
|
||||||
}
|
}
|
||||||
@@ -102,7 +110,7 @@ namespace TEngine
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="channelName">网络频道名称。</param>
|
/// <param name="channelName">网络频道名称。</param>
|
||||||
/// <returns>是否销毁网络频道成功。</returns>
|
/// <returns>是否销毁网络频道成功。</returns>
|
||||||
public static bool DestroyNetworkChannel(string channelName)
|
public bool DestroyNetworkChannel(string channelName)
|
||||||
{
|
{
|
||||||
return m_NetworkManager.DestroyNetworkChannel(channelName);
|
return m_NetworkManager.DestroyNetworkChannel(channelName);
|
||||||
}
|
}
|
||||||
@@ -122,7 +130,8 @@ namespace TEngine
|
|||||||
GameEvent.Send(NetworkEvent.NetworkMissHeartBeatEvent, channel, missCount);
|
GameEvent.Send(NetworkEvent.NetworkMissHeartBeatEvent, channel, missCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnNetworkError(INetworkChannel channel, NetworkErrorCode networkErrorCode, SocketError socketError, string errorMessage)
|
private void OnNetworkError(INetworkChannel channel, NetworkErrorCode networkErrorCode, SocketError socketError,
|
||||||
|
string errorMessage)
|
||||||
{
|
{
|
||||||
GameEvent.Send(NetworkEvent.NetworkErrorEvent, channel, networkErrorCode, socketError, errorMessage);
|
GameEvent.Send(NetworkEvent.NetworkErrorEvent, channel, networkErrorCode, socketError, errorMessage);
|
||||||
}
|
}
|
@@ -2,6 +2,8 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
|
using GameProto;
|
||||||
|
using Google.Protobuf;
|
||||||
|
|
||||||
namespace TEngine
|
namespace TEngine
|
||||||
{
|
{
|
||||||
@@ -15,7 +17,7 @@ namespace TEngine
|
|||||||
private const float DefaultHeartBeatInterval = 30f;
|
private const float DefaultHeartBeatInterval = 30f;
|
||||||
|
|
||||||
private readonly string _name;
|
private readonly string _name;
|
||||||
protected readonly Queue<Packet> SendPacketPool;
|
protected readonly Queue<CSPkg> SendPacketPool;
|
||||||
protected readonly INetworkChannelHelper NetworkChannelHelper;
|
protected readonly INetworkChannelHelper NetworkChannelHelper;
|
||||||
protected AddressFamily MAddressFamily;
|
protected AddressFamily MAddressFamily;
|
||||||
protected bool MResetHeartBeatElapseSecondsWhenReceivePacket;
|
protected bool MResetHeartBeatElapseSecondsWhenReceivePacket;
|
||||||
@@ -48,7 +50,7 @@ namespace TEngine
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 消息包缓存堆栈。
|
/// 消息包缓存堆栈。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private readonly Queue<Packet> _packsQueue = new Queue<Packet>();
|
private readonly Queue<CSPkg> _packsQueue = new Queue<CSPkg>();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 初始化网络频道基类的新实例。
|
/// 初始化网络频道基类的新实例。
|
||||||
@@ -58,7 +60,7 @@ namespace TEngine
|
|||||||
public NetworkChannelBase(string name, INetworkChannelHelper networkChannelHelper)
|
public NetworkChannelBase(string name, INetworkChannelHelper networkChannelHelper)
|
||||||
{
|
{
|
||||||
_name = name ?? string.Empty;
|
_name = name ?? string.Empty;
|
||||||
SendPacketPool = new Queue<Packet>();
|
SendPacketPool = new Queue<CSPkg>();
|
||||||
NetworkChannelHelper = networkChannelHelper;
|
NetworkChannelHelper = networkChannelHelper;
|
||||||
MAddressFamily = AddressFamily.Unknown;
|
MAddressFamily = AddressFamily.Unknown;
|
||||||
MResetHeartBeatElapseSecondsWhenReceivePacket = false;
|
MResetHeartBeatElapseSecondsWhenReceivePacket = false;
|
||||||
@@ -411,9 +413,8 @@ namespace TEngine
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 向远程主机发送消息包。
|
/// 向远程主机发送消息包。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T">消息包类型。</typeparam>
|
|
||||||
/// <param name="packet">要发送的消息包。</param>
|
/// <param name="packet">要发送的消息包。</param>
|
||||||
public bool Send<T>(T packet) where T : Packet
|
public bool Send(CSPkg packet)
|
||||||
{
|
{
|
||||||
if (MSocket == null)
|
if (MSocket == null)
|
||||||
{
|
{
|
||||||
@@ -461,14 +462,13 @@ namespace TEngine
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 向远程主机发送消息包并注册消息回调。
|
/// 向远程主机发送消息包并注册消息回调。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T">消息包类型。</typeparam>
|
|
||||||
/// <param name="packet">要发送的消息包。</param>
|
/// <param name="packet">要发送的消息包。</param>
|
||||||
/// <param name="resHandler">要注册的回调。</param>
|
/// <param name="resHandler">要注册的回调。</param>
|
||||||
/// <param name="needShowWaitUI">是否需要等待UI。</param>
|
/// <param name="needShowWaitUI">是否需要等待UI。</param>
|
||||||
/// <returns>消息包是否发送成功。</returns>
|
/// <returns>消息包是否发送成功。</returns>
|
||||||
public bool Send<T>(T packet, CsMsgDelegate resHandler, bool needShowWaitUI = false) where T : Packet
|
public bool Send(CSPkg packet, CsMsgDelegate resHandler, bool needShowWaitUI = false)
|
||||||
{
|
{
|
||||||
RegisterMsgHandler(packet.Id,resHandler,false);
|
RegisterMsgHandler((int)packet.Head.MsgId,resHandler,false);
|
||||||
return Send(packet);
|
return Send(packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -511,16 +511,16 @@ namespace TEngine
|
|||||||
|
|
||||||
while (SendPacketPool.Count > 0)
|
while (SendPacketPool.Count > 0)
|
||||||
{
|
{
|
||||||
Packet packet = null;
|
CSPkg csPkg = null;
|
||||||
lock (SendPacketPool)
|
lock (SendPacketPool)
|
||||||
{
|
{
|
||||||
packet = SendPacketPool.Dequeue();
|
csPkg = SendPacketPool.Dequeue();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool serializeResult = false;
|
bool serializeResult = false;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
serializeResult = NetworkChannelHelper.Serialize(packet, MSendState.Stream);
|
serializeResult = NetworkChannelHelper.Serialize(csPkg, MSendState.Stream);
|
||||||
}
|
}
|
||||||
catch (Exception exception)
|
catch (Exception exception)
|
||||||
{
|
{
|
||||||
@@ -614,22 +614,22 @@ namespace TEngine
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Packet packet = NetworkChannelHelper.DeserializePacket(MReceiveState.PacketHeader, MReceiveState.Stream, out var customErrorData);
|
CSPkg csPkg = NetworkChannelHelper.DeserializePacket(MReceiveState.PacketHeader, MReceiveState.Stream, out var customErrorData);
|
||||||
|
|
||||||
if (customErrorData != null && NetworkChannelCustomError != null)
|
if (customErrorData != null && NetworkChannelCustomError != null)
|
||||||
{
|
{
|
||||||
NetworkChannelCustomError(this, customErrorData);
|
NetworkChannelCustomError(this, customErrorData);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (packet != null)
|
if (csPkg != null)
|
||||||
{
|
{
|
||||||
lock (_cacheHandlerQueue)
|
lock (_cacheHandlerQueue)
|
||||||
{
|
{
|
||||||
if (_msgHandlerMap.TryGetValue((int)packet.Id, out var listHandle))
|
if (_msgHandlerMap.TryGetValue((int)csPkg.Head.MsgId, out var listHandle))
|
||||||
{
|
{
|
||||||
_cacheHandlerQueue.Enqueue(listHandle);
|
_cacheHandlerQueue.Enqueue(listHandle);
|
||||||
|
|
||||||
_packsQueue.Enqueue(packet);
|
_packsQueue.Enqueue(csPkg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -1,18 +1,20 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
|
using GameBase;
|
||||||
|
using GameProto;
|
||||||
|
|
||||||
namespace TEngine
|
namespace TEngine
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 网络消息委托。
|
/// 网络消息委托。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public delegate void CsMsgDelegate(Packet packet);
|
public delegate void CsMsgDelegate(CSPkg csPkg);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 网络管理器。
|
/// 网络管理器。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal sealed partial class NetworkManager : GameFrameworkModule, INetworkManager
|
internal sealed partial class NetworkManager : Singleton<NetworkManager>, INetworkManager
|
||||||
{
|
{
|
||||||
private readonly Dictionary<string, NetworkChannelBase> _networkChannels;
|
private readonly Dictionary<string, NetworkChannelBase> _networkChannels;
|
||||||
|
|
||||||
@@ -90,7 +92,7 @@ namespace TEngine
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="elapseSeconds">逻辑流逝时间,以秒为单位。</param>
|
/// <param name="elapseSeconds">逻辑流逝时间,以秒为单位。</param>
|
||||||
/// <param name="realElapseSeconds">真实流逝时间,以秒为单位。</param>
|
/// <param name="realElapseSeconds">真实流逝时间,以秒为单位。</param>
|
||||||
internal override void Update(float elapseSeconds, float realElapseSeconds)
|
public void Update(float elapseSeconds, float realElapseSeconds)
|
||||||
{
|
{
|
||||||
foreach (KeyValuePair<string, NetworkChannelBase> networkChannel in _networkChannels)
|
foreach (KeyValuePair<string, NetworkChannelBase> networkChannel in _networkChannels)
|
||||||
{
|
{
|
||||||
@@ -101,7 +103,7 @@ namespace TEngine
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 关闭并清理网络管理器。
|
/// 关闭并清理网络管理器。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal override void Shutdown()
|
public void Shutdown()
|
||||||
{
|
{
|
||||||
foreach (KeyValuePair<string, NetworkChannelBase> networkChannel in _networkChannels)
|
foreach (KeyValuePair<string, NetworkChannelBase> networkChannel in _networkChannels)
|
||||||
{
|
{
|
||||||
@@ -183,7 +185,8 @@ namespace TEngine
|
|||||||
/// <param name="serviceType">网络服务类型。</param>
|
/// <param name="serviceType">网络服务类型。</param>
|
||||||
/// <param name="networkChannelHelper">网络频道辅助器。</param>
|
/// <param name="networkChannelHelper">网络频道辅助器。</param>
|
||||||
/// <returns>要创建的网络频道。</returns>
|
/// <returns>要创建的网络频道。</returns>
|
||||||
public INetworkChannel CreateNetworkChannel(string name, ServiceType serviceType, INetworkChannelHelper networkChannelHelper)
|
public INetworkChannel CreateNetworkChannel(string name, ServiceType serviceType,
|
||||||
|
INetworkChannelHelper networkChannelHelper)
|
||||||
{
|
{
|
||||||
if (networkChannelHelper == null)
|
if (networkChannelHelper == null)
|
||||||
{
|
{
|
||||||
@@ -197,7 +200,8 @@ namespace TEngine
|
|||||||
|
|
||||||
if (HasNetworkChannel(name))
|
if (HasNetworkChannel(name))
|
||||||
{
|
{
|
||||||
throw new GameFrameworkException(Utility.Text.Format("Already exist network channel '{0}'.", name ?? string.Empty));
|
throw new GameFrameworkException(Utility.Text.Format("Already exist network channel '{0}'.",
|
||||||
|
name ?? string.Empty));
|
||||||
}
|
}
|
||||||
|
|
||||||
NetworkChannelBase networkChannel = null;
|
NetworkChannelBase networkChannel = null;
|
||||||
@@ -220,7 +224,8 @@ namespace TEngine
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new GameFrameworkException(Utility.Text.Format("Not supported service type '{0}'.", serviceType));
|
throw new GameFrameworkException(Utility.Text.Format("Not supported service type '{0}'.",
|
||||||
|
serviceType));
|
||||||
}
|
}
|
||||||
|
|
||||||
networkChannel.NetworkChannelConnected += OnNetworkChannelConnected;
|
networkChannel.NetworkChannelConnected += OnNetworkChannelConnected;
|
||||||
@@ -249,6 +254,7 @@ namespace TEngine
|
|||||||
networkChannel.Shutdown();
|
networkChannel.Shutdown();
|
||||||
return name != null && _networkChannels.Remove(name);
|
return name != null && _networkChannels.Remove(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -285,7 +291,8 @@ namespace TEngine
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnNetworkChannelError(NetworkChannelBase networkChannel, NetworkErrorCode errorCode, SocketError socketErrorCode, string errorMessage)
|
private void OnNetworkChannelError(NetworkChannelBase networkChannel, NetworkErrorCode errorCode,
|
||||||
|
SocketError socketErrorCode, string errorMessage)
|
||||||
{
|
{
|
||||||
if (_networkErrorEventHandler != null)
|
if (_networkErrorEventHandler != null)
|
||||||
{
|
{
|
@@ -1,24 +0,0 @@
|
|||||||
using TEngine;
|
|
||||||
|
|
||||||
namespace GameLogic
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 网络消息包基类。
|
|
||||||
/// </summary>
|
|
||||||
public abstract class PacketBase : Packet
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 网络消息包Id。
|
|
||||||
/// </summary>
|
|
||||||
public int ProtoId;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 网络消息包包体。
|
|
||||||
/// </summary>
|
|
||||||
public byte[] ProtoBody;
|
|
||||||
|
|
||||||
public void Close()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,3 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: acea4283f57644b6b4452354d23f2803
|
|
||||||
timeCreated: 1682045887
|
|
@@ -1,15 +0,0 @@
|
|||||||
namespace GameLogic
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 网络消息包。
|
|
||||||
/// </summary>
|
|
||||||
public partial class ProtoPacket : PacketBase
|
|
||||||
{
|
|
||||||
public override int Id => 1;
|
|
||||||
|
|
||||||
public override void Clear()
|
|
||||||
{
|
|
||||||
Close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user