From dddcbbfbfa77c4a4775c39e633b7c0dc13d2437d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=A3=AE2003?= <2384017988@qq.com>
Date: Sat, 1 Aug 2026 15:27:12 +0800
Subject: [PATCH] 1
---
.../Monster/MonsterControl_BossBase.cs | 11 ++++-
Assets/MyGame/Scripts/Manager/GameManager.cs | 12 +++--
Assets/MyGame/Scripts/Net/APIManager.cs | 10 ++--
Assets/MyGame/Scripts/Net/WebSocketManager.cs | 49 ++++++++++++++++++-
Assets/MyGame/aa/UI/Home/UIHomeMain.cs | 4 +-
5 files changed, 72 insertions(+), 14 deletions(-)
diff --git a/Assets/MyGame/Scripts/Characters/Monster/MonsterControl_BossBase.cs b/Assets/MyGame/Scripts/Characters/Monster/MonsterControl_BossBase.cs
index 4a1574d60..e984d1e00 100644
--- a/Assets/MyGame/Scripts/Characters/Monster/MonsterControl_BossBase.cs
+++ b/Assets/MyGame/Scripts/Characters/Monster/MonsterControl_BossBase.cs
@@ -141,18 +141,25 @@ public class MonsterControl_BossBase : MonsterContral
CreateFishManager.Instance.currGameType.subUIManager.ShowBoardBoss(handle.Result, bossName);
}
-
+
if (isMove)
{
var bezierData = MonsterMoveLine.dic_BezierCurveDatas[bossName + pathId];
monsterData.moveLine.Init(bezierData, time);
-
+ // ⭐ isMove=true 的 Boss 初始位置设为曲线起点,
+ // 避免在 moveTime 更新前卡在生成时的 (9999,9999,0)
+ transform.position = new Vector3(bezierData.start.x, bezierData.start.y, 0);
}
else
{
transform.position = new Vector3(0, 0, 0);
}
+
+ // ⭐ Boss 重写 Init 未调用 base.Init,需手动标记已初始化并切换到 move 状态,
+ // 否则 OnMoveUpdata 不会被调用(OnUpdate 里 isInitialized=false 会 return),moveTime 不自增
+ isInitialized = true;
+ ChangeState(CharacterStateType.move);
}
///
diff --git a/Assets/MyGame/Scripts/Manager/GameManager.cs b/Assets/MyGame/Scripts/Manager/GameManager.cs
index a7454473c..a881e4f5b 100644
--- a/Assets/MyGame/Scripts/Manager/GameManager.cs
+++ b/Assets/MyGame/Scripts/Manager/GameManager.cs
@@ -585,9 +585,11 @@ public class GameManager : MonoSingleton
IEnumerator yanchi(LoadingPanel loadingPanel)
{
yield return new WaitForSeconds(5);
- btn_Skip.gameObject.SetActive(true);
+ if (btn_Skip != null) btn_Skip.gameObject.SetActive(true);
yield return new WaitForSeconds(23f);
- loadingPanel.LoadBar(100);
+ // ⭐ 防御:loadingPanel 可能已被 UIManager.CloseAll 销毁(如 Logout 时)
+ if (loadingPanel != null)
+ loadingPanel.LoadBar(100);
}
void Start()
{
@@ -646,12 +648,16 @@ public class GameManager : MonoSingleton
public void Logout(Action onDone = null)
{
- // 关闭所有 WebSocket 连接
+ // ⭐ 标记登出中:阻止 WebSocket 关闭后触发自动重连(避免访问已 null 的 user)
+ WebSocketManager.Instance.isLoggingOut = true;
+ // 关闭所有 WebSocket 连接(内部会先 StopAllReconnects 停止所有重连协程)
WebSocketManager.Instance.CloseAll();
// 清空用户数据
user = null;
// 关闭所有 UI
UIManager.Instance.CloseAll();
+ // ⭐ 登出流程完成,立即恢复重连开关(不依赖 ShowAsync 回调,避免 UI 异常导致永不重置)
+ WebSocketManager.Instance.isLoggingOut = false;
// 切换到登录界面
UIManager.Instance.ShowAsync(UIPanel.LoginPanel, null, (panel) =>
{
diff --git a/Assets/MyGame/Scripts/Net/APIManager.cs b/Assets/MyGame/Scripts/Net/APIManager.cs
index bb8965b6e..62b453386 100644
--- a/Assets/MyGame/Scripts/Net/APIManager.cs
+++ b/Assets/MyGame/Scripts/Net/APIManager.cs
@@ -249,7 +249,7 @@ namespace Assets.MyGame.Scripts.Net
var json = req.downloadHandler.text;
var res = JsonConvert.DeserializeObject>(json);
#if UNITY_EDITOR
- Debug.Log("url----" + url+"--"+ "Json-"+json+"res--"+JsonConvert.SerializeObject(res));
+ Debug.Log("url----" + url + "--" + "Json-" + json + "res--" + JsonConvert.SerializeObject(res));
#endif
Debug.Log("url----" + url + "--" + "Json-" + json + "res--" + JsonConvert.SerializeObject(res));
@@ -313,9 +313,9 @@ namespace Assets.MyGame.Scripts.Net
var res = JsonConvert.DeserializeObject>(json);
#if UNITY_EDITOR
Debug.Log("url----" + url + "--" + "Json-" + json + "res--" + JsonConvert.SerializeObject(res));
-
+#else
+Debug.Log("url----" + url + "--" + "Json-" + json + "res--" + JsonConvert.SerializeObject(res));
#endif
- Debug.Log("url----" + url + "--" + "Json-" + json + "res--" + JsonConvert.SerializeObject(res));
// 自动保存 token
if (typeof(T) == typeof(UserToken))
@@ -383,8 +383,8 @@ namespace Assets.MyGame.Scripts.Net
}
public static void Log(string json)
{
- #if UNITY_EDITOR
- Debug.Log(json);
+#if UNITY_EDITOR
+ Debug.Log(json);
#endif
}
diff --git a/Assets/MyGame/Scripts/Net/WebSocketManager.cs b/Assets/MyGame/Scripts/Net/WebSocketManager.cs
index de26b0808..c9dcdb5b1 100644
--- a/Assets/MyGame/Scripts/Net/WebSocketManager.cs
+++ b/Assets/MyGame/Scripts/Net/WebSocketManager.cs
@@ -27,6 +27,11 @@ namespace Assets.MyGame.Scripts.Net
private readonly HashSet handshakeCompleted = new();
private readonly HashSet reconnecting = new();
private readonly HashSet manualClosing = new();
+ /// 登出标志:true 时所有 socket 关闭后都不触发自动重连。
+ /// Logout 开始时设 true,切回登录界面后设 false,避免关连接时误触发重连访问已 null 的 user。
+ public bool isLoggingOut = false;
+ /// 每个 socketType 正在运行的重连协程引用,用于主动 StopCoroutine
+ private readonly Dictionary reconnectCoroutines = new();
private float nextHeartbeatTime;
private const float HeartbeatIntervalSeconds = 20f;
#if ENABLE_LOG_FILE
@@ -154,6 +159,11 @@ namespace Assets.MyGame.Scripts.Net
sockets.Remove(type);
if (manualClosing.Remove(type))
return;
+ // ⭐ 登出中或未登录:不触发自动重连。
+ // isLoggingOut 可能因 ws.Close 异步导致 OnClosed 触发时已重置,
+ // 所以同时检查 user==null 做双重保险(登出后 user 必为 null)
+ if (isLoggingOut || GameManager.Instance.user == null)
+ return;
// 自动重连
switch (type)
@@ -256,7 +266,7 @@ namespace Assets.MyGame.Scripts.Net
{
if (sockets.TryGetValue(type, out var ws))
{
- manualClosing.Add(type);
+ //manualClosing.Add(type);
handshakeCompleted.Remove(type);
ws.Close(WebSocketStatusCodes.NormalClosure, "正常关闭"); // 或者 CloseStatusCode.Normal
//ws.Close();
@@ -269,6 +279,9 @@ namespace Assets.MyGame.Scripts.Net
///
public void CloseAll()
{
+ // ⭐ 先停止所有重连协程:socket 因 ClosedAbnormally 关闭时已从 sockets 移除,
+ // CloseAll 遍历 sockets.Keys 会漏掉它,导致重连协程继续运行。这里统一停止。
+ StopAllReconnects();
foreach (var type in new List(sockets.Keys))
{
Close(type);
@@ -282,7 +295,23 @@ namespace Assets.MyGame.Scripts.Net
{
if (!reconnecting.Add(type))
return;
- StartCoroutine(Reconnect(type, action));
+ var co = StartCoroutine(Reconnect(type, action));
+ reconnectCoroutines[type] = co;
+ }
+
+ ///
+ /// 主动停止所有正在等待的重连协程并清空状态。
+ /// 用于 Logout 时彻底取消所有待重连任务,不依赖 isLoggingOut 时序。
+ ///
+ public void StopAllReconnects()
+ {
+ foreach (var kv in reconnectCoroutines)
+ {
+ if (kv.Value != null)
+ StopCoroutine(kv.Value);
+ }
+ reconnectCoroutines.Clear();
+ reconnecting.Clear();
}
private System.Collections.IEnumerator Reconnect(SocketType type, Action action = null)
@@ -296,9 +325,18 @@ namespace Assets.MyGame.Scripts.Net
if (manualClosing.Contains(type))
{
reconnecting.Remove(type);
+ reconnectCoroutines.Remove(type);
+ yield break;
+ }
+ // ⭐ 登出中或未登录:取消已排队等待的重连
+ if (isLoggingOut || GameManager.Instance.user == null)
+ {
+ reconnecting.Remove(type);
+ reconnectCoroutines.Remove(type);
yield break;
}
+ reconnectCoroutines.Remove(type);
socketUrls.TryGetValue(type, out var url);
Connect(type, url, action);
}
@@ -311,6 +349,12 @@ namespace Assets.MyGame.Scripts.Net
switch (type)
{
case SocketType.login:
+ // ⭐ 防御:登出后 user 可能为 null,避免 NRE
+ if (GameManager.Instance.user == null || string.IsNullOrEmpty(GameManager.Instance.user.id))
+ {
+ Debug.LogWarning("[WebSocket] login 握手完成但 user 为 null,跳过 Bind(可能登出中)");
+ return;
+ }
WebSocketSendList.Bind(GameManager.Instance.user.id);
break;
case SocketType.chess:
@@ -330,6 +374,7 @@ namespace Assets.MyGame.Scripts.Net
///
private void OnDestroy()
{
+ StopAllReconnects();
foreach (var type in new List(sockets.Keys))
manualClosing.Add(type);
foreach (var ws in new List(sockets.Values))
diff --git a/Assets/MyGame/aa/UI/Home/UIHomeMain.cs b/Assets/MyGame/aa/UI/Home/UIHomeMain.cs
index a5abd62a8..ff48b7dc4 100644
--- a/Assets/MyGame/aa/UI/Home/UIHomeMain.cs
+++ b/Assets/MyGame/aa/UI/Home/UIHomeMain.cs
@@ -100,8 +100,8 @@ public class UIHomeMain : UIBase
});
XJMHButton.onClick.AddListener(() =>
{
- subUIManager.ShowAsync(UIPanel.SelectRoomLeavePenel, GameType.XJMH);
- //UIManager.Instance.ShowBoardError("维护中...");
+ //subUIManager.ShowAsync(UIPanel.SelectRoomLeavePenel, GameType.XJMH);
+ UIManager.Instance.ShowBoardError("维护中...");
});
HHWKButton.onClick.AddListener(() =>