diff --git a/Assets/AddressableAssetsData/Windows/addressables_content_state.bin b/Assets/AddressableAssetsData/Windows/addressables_content_state.bin index 2a329f40b..25fb8cb89 100644 Binary files a/Assets/AddressableAssetsData/Windows/addressables_content_state.bin and b/Assets/AddressableAssetsData/Windows/addressables_content_state.bin differ diff --git a/Assets/MyGame/Scenes/UIScene.unity b/Assets/MyGame/Scenes/UIScene.unity index b81767b04..39c441ed2 100644 --- a/Assets/MyGame/Scenes/UIScene.unity +++ b/Assets/MyGame/Scenes/UIScene.unity @@ -583,7 +583,7 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 22400762, guid: 67117722a812a2e46ab8cb8eafbf5f5e, type: 3} propertyPath: m_AnchoredPosition.y - value: -0.0000076293945 + value: -0.000015258789 objectReference: {fileID: 0} - target: {fileID: 22426080, guid: 67117722a812a2e46ab8cb8eafbf5f5e, type: 3} propertyPath: m_AnchorMax.x diff --git a/Assets/MyGame/Scripts/Net/APIRequestList_Hall.cs b/Assets/MyGame/Scripts/Net/APIRequestList_Hall.cs index d7b0728b0..9920f1a99 100644 --- a/Assets/MyGame/Scripts/Net/APIRequestList_Hall.cs +++ b/Assets/MyGame/Scripts/Net/APIRequestList_Hall.cs @@ -322,6 +322,17 @@ namespace Assets.MyGame.Scripts.Net APIManager.Response(APIType.Hall_GetChessRoomPartitionCount, callback); } + /// + /// 大喇叭消息标识字符(预留位):发送大喇叭时拼在正文最前面。 + /// 接收端(WebSocketReponseList.LoginBroadcast)凭首字符识别为大喇叭,再补上 + /// "喇叭图标+打码昵称"前缀渲染;普通公告不带此字符,原样显示。 + /// 如需更换标识只改这里(前后端需一致)。 + /// + public const char BroadcastMarker = '§'; + + /// 大喇叭正文最大字数:后端整条广播限制20字,标识占1字,故正文最多19字 + public const int BroadcastMaxContentLength = 19; + /// /// 发送全服广播(GET /api/Hall/SendBroadcast?message=xxx) /// 返回:string diff --git a/Assets/MyGame/Scripts/Net/WebSocketReponseList.cs b/Assets/MyGame/Scripts/Net/WebSocketReponseList.cs index 8c37b3148..be7ed2597 100644 --- a/Assets/MyGame/Scripts/Net/WebSocketReponseList.cs +++ b/Assets/MyGame/Scripts/Net/WebSocketReponseList.cs @@ -726,11 +726,39 @@ namespace Assets.MyGame.Scripts.Net /// /// LoginHub Broadcast — 大厅公告广播 + /// 首字符命中大喇叭标识(APIRequestList.BroadcastMarker)时按大喇叭格式渲染: + /// 去掉标识,补"喇叭图标+打码昵称"前缀;否则原样显示为普通公告。 /// public static void LoginBroadcast(string msg) { var data = JsonConvert.DeserializeObject>(msg).arguments[0]; - UIManager.Instance.ShowBoardGongGao(data.message); + string message = data?.message; + + if (!string.IsNullOrEmpty(message) && message[0] == APIRequestList.BroadcastMarker) + { + // 大喇叭:服务端只存了"标识+正文",昵称从广播数据取,展示时再拼接前缀 + string content = message.Substring(1); + string userName = data.userName; + if (string.IsNullOrEmpty(userName)) userName = "玩家"; + UIManager.Instance.ShowBoardGongGao($"【{MaskBroadcastName(userName)}】:{content}"); + } + else + { + // 普通公告:原样显示 + UIManager.Instance.ShowBoardGongGao(message); + } + } + + /// + /// 玩家名打码(大喇叭展示格式):保留首尾字符、中间一个 *("小金鱼"→"小*鱼")。 + /// 与 GameMainPanel_FishBase / UIHome_BY_BackPackPanel 同格式。 + /// + private static string MaskBroadcastName(string name) + { + if (string.IsNullOrEmpty(name)) return name; + name = name.Trim(); + if (name.Length <= 1) return name; + return name[0] + "*" + name[name.Length - 1]; } /// diff --git a/Assets/MyGame/aa/UI/DefaultPanel/LoadPanel/LoadingPanel.cs b/Assets/MyGame/aa/UI/DefaultPanel/LoadPanel/LoadingPanel.cs index 9cf86f3a3..53128770b 100644 --- a/Assets/MyGame/aa/UI/DefaultPanel/LoadPanel/LoadingPanel.cs +++ b/Assets/MyGame/aa/UI/DefaultPanel/LoadPanel/LoadingPanel.cs @@ -12,6 +12,24 @@ public class LoadingPanel : MonoBehaviour public Image image_Bg; public Action actionEnd; public float fadeTime = 1.3f; + + private void Start() + { + // ⭐ 视频播放期间预载大厅主面板:把 HomeUIRes 的加载提前到这段视频等待时间里, + // 登录成功 UILoginPanel.Succeed() 的 ShowAsync(HomeMainPanel) 命中缓存秒开, + // 不再出现"登录成功后进大厅白等"。 + StartCoroutine(PreloadHomeMainRoutine()); + } + + /// 预载大厅主面板:等 UIManager 就绪后发起(视频这段时间足够 HomeUIRes 加载完) + private IEnumerator PreloadHomeMainRoutine() + { + while (UIManager.Instance == null) + yield return null; + yield return null; // 等 UIManager 初始化完成(地址表装载) + UIManager.Instance.PreloadPanel(UIPanel.HomeMainPanel); + } + /// /// 进入条进度值 /// @@ -20,6 +38,9 @@ public class LoadingPanel : MonoBehaviour { if (count == 100) { + // ⭐ 兜底再预载一次:若启动时 UIManager 尚未就绪导致首次发起无效,这里补上 + if (UIManager.Instance != null) + UIManager.Instance.PreloadPanel(UIPanel.HomeMainPanel); GameManager.Instance.btn_Skip.gameObject.SetActive(false); Destroy(gameObject, fadeTime); if (player.gameObject.activeSelf) diff --git a/Assets/MyGame/aa/UI/Game/GameMainPanel_FishBase.cs b/Assets/MyGame/aa/UI/Game/GameMainPanel_FishBase.cs index 77048e020..ddc994cc3 100644 --- a/Assets/MyGame/aa/UI/Game/GameMainPanel_FishBase.cs +++ b/Assets/MyGame/aa/UI/Game/GameMainPanel_FishBase.cs @@ -722,6 +722,9 @@ public class GameMainPanel_FishBase : GameMainPanel_Base obj_DaLaBaPanel.SetActive(!obj_DaLaBaPanel.activeSelf); }); } + // 大喇叭正文限长:后端整条广播≤20字,标识占1字,输入框直接限制19字 + if (tmp_DaLaBaInput != null) + tmp_DaLaBaInput.characterLimit = APIRequestList.BroadcastMaxContentLength; if (btn_DaLaBaSend != null) { btn_DaLaBaSend.onClick.RemoveAllListeners(); @@ -1296,30 +1299,35 @@ public class GameMainPanel_FishBase : GameMainPanel_Base UIManager.Instance.ReleaseHomeUI(); SetLoadProgress(0.02f); - // 路线:2~30(路线文本可能和鱼资源同一个大包,解压耗时由回调实时反映) + // 路线:2~30(大包同步解压期间回调不刷新 → 预估进度保证条持续推进) + StartCreepProgress(0.02f, 0.30f); await MonsterMoveLine.LoadBezier(p => { - if (flow == _resourceFlowToken) SetLoadProgress(Mathf.Lerp(0.02f, 0.30f, p)); + if (flow == _resourceFlowToken) SetLoadProgress(Mathf.Max(_loadProgress, Mathf.Lerp(0.02f, 0.30f, p))); }); if (flow != _resourceFlowToken) return; // ⭐ 期间已退出/切换,本轮作废 - // 鱼包:30~60,内部子进度实时上报(残留流程不再写面板) + // 鱼包:30~60,内部子进度实时上报(预估进度兜底 LZMA 解压阻塞段,不再卡在 30) + StartCreepProgress(0.30f, 0.60f); await FishResourcesData.LoadFishAssetsData(p => { - if (flow == _resourceFlowToken) SetLoadProgress(Mathf.Lerp(0.30f, 0.60f, p)); + if (flow == _resourceFlowToken) SetLoadProgress(Mathf.Max(_loadProgress, Mathf.Lerp(0.30f, 0.60f, p))); }); if (flow != _resourceFlowToken) return; // 玩法音频:60~78 + StartCreepProgress(0.60f, 0.78f); await AudioResourcesData.LoadAudioGame(p => { - if (flow == _resourceFlowToken) SetLoadProgress(Mathf.Lerp(0.60f, 0.78f, p)); + if (flow == _resourceFlowToken) SetLoadProgress(Mathf.Max(_loadProgress, Mathf.Lerp(0.60f, 0.78f, p))); }); if (flow != _resourceFlowToken) return; // ⭐ 开火音效 PW_Shoot 在 Default Local Group(Audio+PTCBZS 双标签交集检索): // 只命中 Default 小包,不把其它玩法的巨型音频包拉进内存;句柄由 LoadBulletClip 静态保存,离房释放 + StartCreepProgress(0.78f, 0.84f); await LoadBulletClip(); + StopCreepProgress(); if (flow != _resourceFlowToken) return; SetLoadProgress(0.84f); if (_bulletClipHandle.IsValid() && _bulletClipHandle.Result != null) @@ -1725,12 +1733,48 @@ public class GameMainPanel_FishBase : GameMainPanel_Base /// 加载段进度写入:切换房间时映射到合并进度条后半段(55~100%),平时直接写面板进度条 private void SetLoadProgress(float p) { + p = Mathf.Clamp01(p); + _loadProgress = p; if (_changeRoomBar != null) _changeRoomBar.SetProgress(0.55f + p * 0.45f); else if (JinDuTiao != null) JinDuTiao.SetProgress(p); } + // ---- 预估进度(大包 LZMA 同步解压期间主线程阻塞、回调不刷新 → 条卡死像没响应)---- + /// 加载进度当前值(真实或预估),预估推进时判断不回退 + private float _loadProgress = 0f; + private Coroutine _creepRoutine; + + /// + /// 预估进度:等待段内按时间指数逼近"段末-2%",真实进度回调以更大值覆盖。 + /// 加载完成时直接跳到真实位置,全程条和数字都在动,不会出现"卡住不动"的假死感。 + /// + private void StartCreepProgress(float from, float to) + { + StopCreepProgress(); + if (isActiveAndEnabled) _creepRoutine = StartCoroutine(CreepProgressRoutine(from, to)); + } + + private void StopCreepProgress() + { + if (_creepRoutine != null) { StopCoroutine(_creepRoutine); _creepRoutine = null; } + } + + private IEnumerator CreepProgressRoutine(float from, float to) + { + float cap = Mathf.Max(from, to - 0.02f); + float elapsed = 0f; + while (true) + { + yield return new WaitForSeconds(0.1f); + elapsed += 0.1f; + // 指数逼近:前 2.5 秒走完区间约 63%,越接近段末越慢,不会超过 cap + float creep = Mathf.Lerp(from, cap, 1f - Mathf.Exp(-elapsed / 2.5f)); + if (creep > _loadProgress) SetLoadProgress(creep); + } + } + /// 写切换房间合并进度条(网络段:QuickJoin返回/JoinRoom已发送) private static void SetChangeRoomBarProgress(float p) { @@ -2045,16 +2089,20 @@ public class GameMainPanel_FishBase : GameMainPanel_Base UIManager.Instance.ShowBoardError("请输入广播内容"); return; } + // ⭐ 后端整条广播限制20字,标识字符占1字,正文最多19字 + if (msg.Length > APIRequestList.BroadcastMaxContentLength) + { + UIManager.Instance.ShowBoardError($"广播内容不能超过{APIRequestList.BroadcastMaxContentLength}个字"); + return; + } _isSendingDaLaBa = true; // ⭐ 超时兜底:后端拒绝(字数超限等)时没有回调,靠超时复位防重入标志 if (_daLaBaTimeoutRoutine != null) StopCoroutine(_daLaBaTimeoutRoutine); _daLaBaTimeoutRoutine = StartCoroutine(ResetDaLaBaFlagAfterTimeout()); - // ⭐ 显示格式:"【小*鱼】:内容"(前面加喇叭图标 TMP 标签;名字打码:首尾保留、中间一个 *) - var userName = GameManager.Instance.user?.BaseInfo?.userName; - if (string.IsNullOrEmpty(userName)) userName = "玩家"; - APIRequestList.SendBroadcast($"【{MaskBroadcastName(userName)}】:{msg}", (result) => + // ⭐ 只发"标识字符+正文":喇叭图标与打码昵称由接收端(LoginBroadcast)统一补上 + APIRequestList.SendBroadcast(APIRequestList.BroadcastMarker + msg, (result) => { // 成功:停掉超时协程并复位标志 if (_daLaBaTimeoutRoutine != null) @@ -2085,18 +2133,6 @@ public class GameMainPanel_FishBase : GameMainPanel_Base _daLaBaTimeoutRoutine = null; } - /// - /// 玩家名打码(广播格式):保留首尾字符、中间一个 *("小金鱼"→"小*鱼"、"我是大帅哥"→"我*哥")。 - /// 与召唤卡提示的 MaskUserName(三个星)区分,广播用单星。 - /// - private static string MaskBroadcastName(string name) - { - if (string.IsNullOrEmpty(name)) return name; - name = name.Trim(); - if (name.Length <= 1) return name; - return name[0] + "*" + name[name.Length - 1]; - } - /// /// 使用召唤卡:从背包找到召唤卡道具(type=11)拿道具编号 /// → /api/SummonCard/use 召唤Boss(Boss鱼由服务端 OnFishSpawn 下发给房间所有人) diff --git a/Assets/MyGame/aa/UI/Home/Sub/UIHome_BY_BackPackPanel.cs b/Assets/MyGame/aa/UI/Home/Sub/UIHome_BY_BackPackPanel.cs index 64d27b1f7..0033405ca 100644 --- a/Assets/MyGame/aa/UI/Home/Sub/UIHome_BY_BackPackPanel.cs +++ b/Assets/MyGame/aa/UI/Home/Sub/UIHome_BY_BackPackPanel.cs @@ -71,6 +71,9 @@ public class UIHome_BY_BackPackPanel : SubUIBase // 大喇叭 if (DaLaBaPanel != null) DaLaBaPanel.SetActive(false); + // 大喇叭正文限长:后端整条广播≤20字,标识占1字,输入框直接限制19字 + if (tMPText_DaLaBaLabel != null) + tMPText_DaLaBaLabel.characterLimit = APIRequestList.BroadcastMaxContentLength; if (btn_FaSong != null) { // ⭐ 先清再绑:防止面板重复 Show 叠加监听器(点一次发 N 次 = 多扣 N 个大喇叭) @@ -170,16 +173,20 @@ public class UIHome_BY_BackPackPanel : SubUIBase UIManager.Instance.ShowBoardError("请输入广播内容"); return; } + // ⭐ 后端整条广播限制20字,标识字符占1字,正文最多19字 + if (content.Length > APIRequestList.BroadcastMaxContentLength) + { + UIManager.Instance.ShowBoardError($"广播内容不能超过{APIRequestList.BroadcastMaxContentLength}个字"); + return; + } _isSendingFaSong = true; // ⭐ 超时兜底:后端拒绝(字数超限等)时没有回调,靠超时复位防重入标志 if (_faSongTimeoutRoutine != null) StopCoroutine(_faSongTimeoutRoutine); _faSongTimeoutRoutine = StartCoroutine(ResetFaSongFlagAfterTimeout()); - // ⭐ 显示格式:"【小*鱼】:内容"(前面加喇叭图标 TMP 标签;名字打码与游戏内大喇叭同格式) - var userName = GameManager.Instance.user?.BaseInfo?.userName; - if (string.IsNullOrEmpty(userName)) userName = "玩家"; - APIRequestList.SendBroadcast($"【{MaskBroadcastName(userName)}】:{content}", (result) => + // ⭐ 只发"标识字符+正文":喇叭图标与打码昵称由接收端(LoginBroadcast)统一补上 + APIRequestList.SendBroadcast(APIRequestList.BroadcastMarker + content, (result) => { // 成功:停掉超时协程并复位标志 if (_faSongTimeoutRoutine != null) @@ -207,18 +214,6 @@ public class UIHome_BY_BackPackPanel : SubUIBase _faSongTimeoutRoutine = null; } - /// - /// 玩家名打码(广播格式):保留首尾字符、中间一个 *("小金鱼"→"小*鱼")。 - /// 与 GameMainPanel_FishBase.MaskBroadcastName 同格式(背包面板独立副本)。 - /// - private static string MaskBroadcastName(string name) - { - if (string.IsNullOrEmpty(name)) return name; - name = name.Trim(); - if (name.Length <= 1) return name; - return name[0] + "*" + name[name.Length - 1]; - } - private void OnClickConfirmChangeName() { string newName = tMPText_NewName?.text?.Trim();