This commit is contained in:
2026-10-10 08:59:44 +08:00
parent 2bbabb70b4
commit b5881a6cc4
7 changed files with 130 additions and 39 deletions
+1 -1
View File
@@ -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
@@ -322,6 +322,17 @@ namespace Assets.MyGame.Scripts.Net
APIManager.Response<int>(APIType.Hall_GetChessRoomPartitionCount, callback);
}
/// <summary>
/// 大喇叭消息标识字符(预留位):发送大喇叭时拼在正文最前面。
/// 接收端(WebSocketReponseList.LoginBroadcast)凭首字符识别为大喇叭,再补上
/// "喇叭图标+打码昵称"前缀渲染;普通公告不带此字符,原样显示。
/// 如需更换标识只改这里(前后端需一致)。
/// </summary>
public const char BroadcastMarker = '§';
/// <summary>大喇叭正文最大字数:后端整条广播限制20字,标识占1字,故正文最多19字</summary>
public const int BroadcastMaxContentLength = 19;
/// <summary>
/// 发送全服广播(GET /api/Hall/SendBroadcast?message=xxx)
/// 返回:string
@@ -726,11 +726,39 @@ namespace Assets.MyGame.Scripts.Net
/// <summary>
/// LoginHub Broadcast — 大厅公告广播
/// 首字符命中大喇叭标识(APIRequestList.BroadcastMarker)时按大喇叭格式渲染:
/// 去掉标识,补"喇叭图标+打码昵称"前缀;否则原样显示为普通公告。
/// </summary>
public static void LoginBroadcast(string msg)
{
var data = JsonConvert.DeserializeObject<WebSocketResponseBase<LoginBroadcastData>>(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($"<sprite index=0>【{MaskBroadcastName(userName)}】:{content}");
}
else
{
// 普通公告:原样显示
UIManager.Instance.ShowBoardGongGao(message);
}
}
/// <summary>
/// 玩家名打码(大喇叭展示格式):保留首尾字符、中间一个 *("小金鱼"→"小*鱼")。
/// 与 GameMainPanel_FishBase / UIHome_BY_BackPackPanel 同格式。
/// </summary>
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];
}
/// <summary>
@@ -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());
}
/// <summary>预载大厅主面板:等 UIManager 就绪后发起(视频这段时间足够 HomeUIRes 加载完)</summary>
private IEnumerator PreloadHomeMainRoutine()
{
while (UIManager.Instance == null)
yield return null;
yield return null; // 等 UIManager 初始化完成(地址表装载)
UIManager.Instance.PreloadPanel(UIPanel.HomeMainPanel);
}
/// <summary>
/// 进入条进度值
/// </summary>
@@ -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)
@@ -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
/// <summary>加载段进度写入:切换房间时映射到合并进度条后半段(55~100%),平时直接写面板进度条</summary>
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 同步解压期间主线程阻塞、回调不刷新 → 条卡死像没响应)----
/// <summary>加载进度当前值(真实或预估),预估推进时判断不回退</summary>
private float _loadProgress = 0f;
private Coroutine _creepRoutine;
/// <summary>
/// 预估进度:等待段内按时间指数逼近"段末-2%",真实进度回调以更大值覆盖。
/// 加载完成时直接跳到真实位置,全程条和数字都在动,不会出现"卡住不动"的假死感。
/// </summary>
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);
}
}
/// <summary>写切换房间合并进度条(网络段:QuickJoin返回/JoinRoom已发送)</summary>
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());
// ⭐ 显示格式:"<sprite index=0>【小*鱼】:内容"(前面加喇叭图标 TMP 标签;名字打码:首尾保留、中间一个 *)
var userName = GameManager.Instance.user?.BaseInfo?.userName;
if (string.IsNullOrEmpty(userName)) userName = "玩家";
APIRequestList.SendBroadcast($"<sprite index=0>【{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;
}
/// <summary>
/// 玩家名打码(广播格式):保留首尾字符、中间一个 *("小金鱼"→"小*鱼"、"我是大帅哥"→"我*哥")。
/// 与召唤卡提示的 MaskUserName(三个星)区分,广播用单星。
/// </summary>
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];
}
/// <summary>
/// 使用召唤卡:从背包找到召唤卡道具(type=11)拿道具编号
/// → /api/SummonCard/use 召唤Boss(Boss鱼由服务端 OnFishSpawn 下发给房间所有人)
@@ -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());
// ⭐ 显示格式:"<sprite index=0>【小*鱼】:内容"(前面加喇叭图标 TMP 标签;名字打码与游戏内大喇叭同格式)
var userName = GameManager.Instance.user?.BaseInfo?.userName;
if (string.IsNullOrEmpty(userName)) userName = "玩家";
APIRequestList.SendBroadcast($"<sprite index=0>【{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;
}
/// <summary>
/// 玩家名打码(广播格式):保留首尾字符、中间一个 *("小金鱼"→"小*鱼")。
/// 与 GameMainPanel_FishBase.MaskBroadcastName 同格式(背包面板独立副本)。
/// </summary>
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();