diff --git a/Assets/AddressableAssetsData/AddressableAssetSettings.asset b/Assets/AddressableAssetsData/AddressableAssetSettings.asset
index bfecbaea5..bbd70078d 100644
--- a/Assets/AddressableAssetsData/AddressableAssetSettings.asset
+++ b/Assets/AddressableAssetsData/AddressableAssetSettings.asset
@@ -15,7 +15,7 @@ MonoBehaviour:
m_DefaultGroup: a263e71fce79f2f4cb5b5f1fa6b7291a
m_currentHash:
serializedVersion: 2
- Hash: e88239bd385df7eeb8432db63ac72d7d
+ Hash: 3b2ddf0423273ab9d68b887ff1cc1809
m_OptimizeCatalogSize: 0
m_BuildRemoteCatalog: 0
m_BundleLocalCatalog: 0
diff --git a/Assets/AddressableAssetsData/AssetGroups/Default Local Group.asset b/Assets/AddressableAssetsData/AssetGroups/Default Local Group.asset
index d46ee1e08..7c6935f7e 100644
--- a/Assets/AddressableAssetsData/AssetGroups/Default Local Group.asset
+++ b/Assets/AddressableAssetsData/AssetGroups/Default Local Group.asset
@@ -51,6 +51,13 @@ MonoBehaviour:
- PTCBZS
- ZSYX
FlaggedDuringContentUpdateRestriction: 0
+ - m_GUID: 4ccd2be5159a8434689185dad378dd01
+ m_Address: Assets/Art/FengLei/Audio/FLZY_bgm_default.ogg
+ m_ReadOnly: 0
+ m_SerializedLabels:
+ - Audio
+ - Default
+ FlaggedDuringContentUpdateRestriction: 0
- m_GUID: 55692611ed57c594fa0d7ecba7dcf704
m_Address: Assets/MyGame/aa/Game/ZhanShen/Game/display_wargod_14901_0_dev.prefab
m_ReadOnly: 0
@@ -70,6 +77,41 @@ MonoBehaviour:
m_ReadOnly: 0
m_SerializedLabels: []
FlaggedDuringContentUpdateRestriction: 0
+ - m_GUID: 8e07162e07c25974cae59b29d808aaf2
+ m_Address: Assets/MyGame/aa/Game/XJMH/Sound/PW_BgFree.ogg
+ m_ReadOnly: 0
+ m_SerializedLabels:
+ - Audio
+ - Default
+ FlaggedDuringContentUpdateRestriction: 0
+ - m_GUID: 964dfa5d6b6f9b947983721026622299
+ m_Address: Assets/MyGame/aa/Game/XJMH/Sound/PW_Shoot.ogg
+ m_ReadOnly: 0
+ m_SerializedLabels:
+ - Audio
+ - PTCBZS
+ FlaggedDuringContentUpdateRestriction: 0
+ - m_GUID: 98b1baf987b5c8942baa65ac95c04a15
+ m_Address: Assets/Audios/HHWK/HHWK_ziyouxiBGM.ogg
+ m_ReadOnly: 0
+ m_SerializedLabels:
+ - Audio
+ - Default
+ FlaggedDuringContentUpdateRestriction: 0
+ - m_GUID: a5531410c3acf2a45990658c82c7db06
+ m_Address: Assets/Art/FengLei/Audio/FLZY_bgm_20.ogg
+ m_ReadOnly: 0
+ m_SerializedLabels:
+ - Audio
+ - Default
+ FlaggedDuringContentUpdateRestriction: 0
+ - m_GUID: b9f66d4b543101b4a8f6529f7e1c3fc8
+ m_Address: Assets/Audios/HHWK/HHWK_youxiBGM2.ogg
+ m_ReadOnly: 0
+ m_SerializedLabels:
+ - Audio
+ - Default
+ FlaggedDuringContentUpdateRestriction: 0
- m_GUID: c0665105ad467074a9d951a074b6c71b
m_Address: Assets/MyGame/aa/Game/XJMH/Boss/XingJiXunHang/PW_Enemy_4000.prefab
m_ReadOnly: 0
@@ -77,6 +119,20 @@ MonoBehaviour:
- FishPrefab
- XJMH
FlaggedDuringContentUpdateRestriction: 0
+ - m_GUID: c37a24b1b9382e04c86ecae674a7e071
+ m_Address: Assets/MyGame/aa/Game/XJMH/Sound/PW_Bg.ogg
+ m_ReadOnly: 0
+ m_SerializedLabels:
+ - Audio
+ - Default
+ FlaggedDuringContentUpdateRestriction: 0
+ - m_GUID: ec58d755545af58489ae35ed82c1e07d
+ m_Address: Assets/Audios/HHWK/HHWK_youxiBGM.ogg
+ m_ReadOnly: 0
+ m_SerializedLabels:
+ - Audio
+ - Default
+ FlaggedDuringContentUpdateRestriction: 0
- m_GUID: fd77a1da22db21441ab0b116128a5e3a
m_Address: Assets/MyGame/aa/Game/ZhanShen/Game/display_wargod_in_14053_0_dev.prefab
m_ReadOnly: 0
diff --git a/Assets/AddressableAssetsData/AssetGroups/Fish_FLZY.asset b/Assets/AddressableAssetsData/AssetGroups/Fish_FLZY.asset
index 2c72de5b6..37b881152 100644
--- a/Assets/AddressableAssetsData/AssetGroups/Fish_FLZY.asset
+++ b/Assets/AddressableAssetsData/AssetGroups/Fish_FLZY.asset
@@ -206,13 +206,6 @@ MonoBehaviour:
- FLZY
- FishPrefab
FlaggedDuringContentUpdateRestriction: 0
- - m_GUID: 4ccd2be5159a8434689185dad378dd01
- m_Address: Assets/Art/FengLei/Audio/FLZY_bgm_default.ogg
- m_ReadOnly: 0
- m_SerializedLabels:
- - Audio
- - Default
- FlaggedDuringContentUpdateRestriction: 0
- m_GUID: 4f07750ceee651741ba0228ffd45e954
m_Address: Assets/Art/FengLei/bundles/by_fish_base/bundles/prefab/fishbase@/12.prefab
m_ReadOnly: 0
@@ -528,13 +521,6 @@ MonoBehaviour:
- FLZY
- FishPrefab
FlaggedDuringContentUpdateRestriction: 0
- - m_GUID: a5531410c3acf2a45990658c82c7db06
- m_Address: Assets/Art/FengLei/Audio/FLZY_bgm_20.ogg
- m_ReadOnly: 0
- m_SerializedLabels:
- - Audio
- - Default
- FlaggedDuringContentUpdateRestriction: 0
- m_GUID: a718714f431d35247b001c93ad1683b9
m_Address: Assets/Art/TuJianFishTexture/1595.png
m_ReadOnly: 0
diff --git a/Assets/AddressableAssetsData/AssetGroups/Fish_HHWK.asset b/Assets/AddressableAssetsData/AssetGroups/Fish_HHWK.asset
index 0eb69dd09..7f0265d5d 100644
--- a/Assets/AddressableAssetsData/AssetGroups/Fish_HHWK.asset
+++ b/Assets/AddressableAssetsData/AssetGroups/Fish_HHWK.asset
@@ -1200,13 +1200,6 @@ MonoBehaviour:
- FishPrefab
- HHWK
FlaggedDuringContentUpdateRestriction: 0
- - m_GUID: 98b1baf987b5c8942baa65ac95c04a15
- m_Address: Assets/Audios/HHWK/HHWK_ziyouxiBGM.ogg
- m_ReadOnly: 0
- m_SerializedLabels:
- - Audio
- - Default
- FlaggedDuringContentUpdateRestriction: 0
- m_GUID: 9a71ec700d97e9442be4e7ca1ec88b88
m_Address: Assets/Art/HHWK/TuJianTexture/fish_1022 Variant.png
m_ReadOnly: 0
@@ -1501,13 +1494,6 @@ MonoBehaviour:
- FishPrefab
- HHWK
FlaggedDuringContentUpdateRestriction: 0
- - m_GUID: b9f66d4b543101b4a8f6529f7e1c3fc8
- m_Address: Assets/Audios/HHWK/HHWK_youxiBGM2.ogg
- m_ReadOnly: 0
- m_SerializedLabels:
- - Audio
- - Default
- FlaggedDuringContentUpdateRestriction: 0
- m_GUID: bbddd2883bdfd1644ba49d4261a73d27
m_Address: Assets/game_download/games/game177/prefab/fish/Game177_yilong_sj_2.prefab
m_ReadOnly: 0
@@ -1963,13 +1949,6 @@ MonoBehaviour:
- FishPrefab
- HHWK
FlaggedDuringContentUpdateRestriction: 0
- - m_GUID: ec58d755545af58489ae35ed82c1e07d
- m_Address: Assets/Audios/HHWK/HHWK_youxiBGM.ogg
- m_ReadOnly: 0
- m_SerializedLabels:
- - Audio
- - Default
- FlaggedDuringContentUpdateRestriction: 0
- m_GUID: ec8b574c01d5d354db2c62b9737d7c49
m_Address: Assets/Art/HHWK/TuJianTexture/Fish_2009 Variant.png
m_ReadOnly: 0
diff --git a/Assets/AddressableAssetsData/AssetGroups/Fish_XJMH.asset b/Assets/AddressableAssetsData/AssetGroups/Fish_XJMH.asset
index 47b9c2b6c..c16dcc58a 100644
--- a/Assets/AddressableAssetsData/AssetGroups/Fish_XJMH.asset
+++ b/Assets/AddressableAssetsData/AssetGroups/Fish_XJMH.asset
@@ -178,6 +178,12 @@ MonoBehaviour:
- FishPrefab
- XJMH
FlaggedDuringContentUpdateRestriction: 0
+ - m_GUID: 1abfe2b699a5f764c896951d8bc859ad
+ m_Address: Assets/Art/XJMH/pw/pw_sprite/freemodel/PW_FreeItem_1.png
+ m_ReadOnly: 0
+ m_SerializedLabels:
+ - XJMH
+ FlaggedDuringContentUpdateRestriction: 0
- m_GUID: 1c991808cacc37a4884f95a3bd88a29c
m_Address: Assets/MyGame/aa/Game/XJMH/Sound/PW_FlyCoin.ogg
m_ReadOnly: 0
@@ -423,6 +429,12 @@ MonoBehaviour:
- TuJian
- XJMH
FlaggedDuringContentUpdateRestriction: 0
+ - m_GUID: 3b6ce020d078b524ab9f8ea29d7fe431
+ m_Address: Assets/Art/XJMH/pw/pw_sprite/common/zd_jn_zd.png
+ m_ReadOnly: 0
+ m_SerializedLabels:
+ - XJMH
+ FlaggedDuringContentUpdateRestriction: 0
- m_GUID: 3c361fb6838b59a40b183bc1dbf9ae2a
m_Address: Assets/Art/XJMH/pw/pw_prefab/game/enemy/XJMHEnemy/PW_Enemy_2.prefab
m_ReadOnly: 0
@@ -801,6 +813,12 @@ MonoBehaviour:
- Audio
- XJMH
FlaggedDuringContentUpdateRestriction: 0
+ - m_GUID: 689bc9268484c3c4fab1743b9c99ee9e
+ m_Address: Assets/Art/XJMH/pw/pw_sprite/freemodel/PW_FreeItem_2.png
+ m_ReadOnly: 0
+ m_SerializedLabels:
+ - XJMH
+ FlaggedDuringContentUpdateRestriction: 0
- m_GUID: 68e9db06ce8a52043bce8e20dd84fb7e
m_Address: Assets/Art/XJMH/pw/pw_prefab/game/enemy/XJMHEnemy/PW_Enemy_9.prefab
m_ReadOnly: 0
@@ -983,13 +1001,6 @@ MonoBehaviour:
- Audio
- XJMH
FlaggedDuringContentUpdateRestriction: 0
- - m_GUID: 8e07162e07c25974cae59b29d808aaf2
- m_Address: Assets/MyGame/aa/Game/XJMH/Sound/PW_BgFree.ogg
- m_ReadOnly: 0
- m_SerializedLabels:
- - Audio
- - Default
- FlaggedDuringContentUpdateRestriction: 0
- m_GUID: 8e9f22d048bac0a41a86b7a8f89efb0f
m_Address: Assets/MyGame/aa/Game/XJMH/Boss/XiaoChouPuKe/PW_Enemy_113.prefab
m_ReadOnly: 0
@@ -1032,11 +1043,10 @@ MonoBehaviour:
- TuJian
- XJMH
FlaggedDuringContentUpdateRestriction: 0
- - m_GUID: 964dfa5d6b6f9b947983721026622299
- m_Address: Assets/MyGame/aa/Game/XJMH/Sound/PW_Shoot.ogg
+ - m_GUID: 9bf752fc3d63b374998b79d5b9e169a0
+ m_Address: Assets/Art/XJMH/pw/pw_sprite/freemodel/PW_FreeItem_3.png
m_ReadOnly: 0
m_SerializedLabels:
- - Audio
- XJMH
FlaggedDuringContentUpdateRestriction: 0
- m_GUID: 9cd48272e3e176b4b86b3ce703cfa03b
@@ -1128,6 +1138,12 @@ MonoBehaviour:
- TuJian
- XJMH
FlaggedDuringContentUpdateRestriction: 0
+ - m_GUID: adf779a3413c62744b56021a0ad5c93d
+ m_Address: Assets/Art/XJMH/pw/pw_sprite/common/zd_jn_ss.png
+ m_ReadOnly: 0
+ m_SerializedLabels:
+ - XJMH
+ FlaggedDuringContentUpdateRestriction: 0
- m_GUID: aea38e560a41ff44ba0a68d3b3194052
m_Address: Assets/MyGame/aa/Game/XJMH/Sound/PW_TextDragon.ogg
m_ReadOnly: 0
@@ -1156,6 +1172,12 @@ MonoBehaviour:
- Audio
- XJMH
FlaggedDuringContentUpdateRestriction: 0
+ - m_GUID: b40ddb35d439d4546ab220424de7e930
+ m_Address: Assets/Art/XJMH/pw/pw_sprite/common/zd_jn_sd.png
+ m_ReadOnly: 0
+ m_SerializedLabels:
+ - XJMH
+ FlaggedDuringContentUpdateRestriction: 0
- m_GUID: b494aa76324a7c84ba8d1b26c9b3d231
m_Address: Assets/Art/XJMH/pw/pw_sprite/handbook/PW_Enemy_32.png
m_ReadOnly: 0
@@ -1247,13 +1269,6 @@ MonoBehaviour:
- FishPrefab
- XJMH
FlaggedDuringContentUpdateRestriction: 0
- - m_GUID: c37a24b1b9382e04c86ecae674a7e071
- m_Address: Assets/MyGame/aa/Game/XJMH/Sound/PW_Bg.ogg
- m_ReadOnly: 0
- m_SerializedLabels:
- - Audio
- - Default
- FlaggedDuringContentUpdateRestriction: 0
- m_GUID: c37fb4f7c76b1154a9d20ad974a14010
m_Address: Assets/Art/XJMH/pw/pw_sprite/handbook/PW_Enemy_104.png
m_ReadOnly: 0
@@ -1525,6 +1540,12 @@ MonoBehaviour:
- FishPrefab
- XJMH
FlaggedDuringContentUpdateRestriction: 0
+ - m_GUID: e54c60eb5da5278478389292015f8e8a
+ m_Address: Assets/Art/XJMH/pw/pw_sprite/freemodel/PW_FreeItem_4.png
+ m_ReadOnly: 0
+ m_SerializedLabels:
+ - XJMH
+ FlaggedDuringContentUpdateRestriction: 0
- m_GUID: e590af03990a88a4c842c66df7dde040
m_Address: Assets/MyGame/aa/Game/XJMH/Sound/PW_Prop_GammaStorm_Attack.ogg
m_ReadOnly: 0
@@ -1733,48 +1754,6 @@ MonoBehaviour:
- Audio
- XJMH
FlaggedDuringContentUpdateRestriction: 0
- - m_GUID: b40ddb35d439d4546ab220424de7e930
- m_Address: Assets/Art/XJMH/pw/pw_sprite/common/zd_jn_sd.png
- m_ReadOnly: 0
- m_SerializedLabels:
- - XJMH
- FlaggedDuringContentUpdateRestriction: 0
- - m_GUID: 3b6ce020d078b524ab9f8ea29d7fe431
- m_Address: Assets/Art/XJMH/pw/pw_sprite/common/zd_jn_zd.png
- m_ReadOnly: 0
- m_SerializedLabels:
- - XJMH
- FlaggedDuringContentUpdateRestriction: 0
- - m_GUID: adf779a3413c62744b56021a0ad5c93d
- m_Address: Assets/Art/XJMH/pw/pw_sprite/common/zd_jn_ss.png
- m_ReadOnly: 0
- m_SerializedLabels:
- - XJMH
- FlaggedDuringContentUpdateRestriction: 0
- - m_GUID: 1abfe2b699a5f764c896951d8bc859ad
- m_Address: Assets/Art/XJMH/pw/pw_sprite/freemodel/PW_FreeItem_1.png
- m_ReadOnly: 0
- m_SerializedLabels:
- - XJMH
- FlaggedDuringContentUpdateRestriction: 0
- - m_GUID: 689bc9268484c3c4fab1743b9c99ee9e
- m_Address: Assets/Art/XJMH/pw/pw_sprite/freemodel/PW_FreeItem_2.png
- m_ReadOnly: 0
- m_SerializedLabels:
- - XJMH
- FlaggedDuringContentUpdateRestriction: 0
- - m_GUID: 9bf752fc3d63b374998b79d5b9e169a0
- m_Address: Assets/Art/XJMH/pw/pw_sprite/freemodel/PW_FreeItem_3.png
- m_ReadOnly: 0
- m_SerializedLabels:
- - XJMH
- FlaggedDuringContentUpdateRestriction: 0
- - m_GUID: e54c60eb5da5278478389292015f8e8a
- m_Address: Assets/Art/XJMH/pw/pw_sprite/freemodel/PW_FreeItem_4.png
- m_ReadOnly: 0
- m_SerializedLabels:
- - XJMH
- FlaggedDuringContentUpdateRestriction: 0
m_ReadOnly: 0
m_Settings: {fileID: 11400000, guid: 3d7ea06370502a34e82011fabf822b45, type: 2}
m_SchemaSet:
diff --git a/Assets/AddressableAssetsData/Windows/addressables_content_state.bin b/Assets/AddressableAssetsData/Windows/addressables_content_state.bin
index ec818b67b..c8bb5aba9 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 743b22a59..48752abfe 100644
--- a/Assets/MyGame/Scenes/UIScene.unity
+++ b/Assets/MyGame/Scenes/UIScene.unity
@@ -3855,6 +3855,7 @@ GameObject:
- component: {fileID: 2075409202}
- component: {fileID: 2075409203}
- component: {fileID: 2075409204}
+ - component: {fileID: 2075409205}
m_Layer: 0
m_Name: Manager
m_TagString: Untagged
@@ -3917,7 +3918,7 @@ MonoBehaviour:
m_Name:
m_EditorClassIdentifier:
cam: {fileID: 1985717029}
- enableBot: 0
+ enableBot: 1
botConfig:
enabled: 1
aiState: active
@@ -4342,6 +4343,18 @@ MonoBehaviour:
m_Name:
m_EditorClassIdentifier:
audioMixer: {fileID: 24100000, guid: ca43f9a7549657a49a2978e97c7a621a, type: 2}
+--- !u!114 &2075409205
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 2075409194}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: bd70cad3c45605a4f824c9eaf1eb081d, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
--- !u!1001 &3569938244496052059
PrefabInstance:
m_ObjectHideFlags: 0
diff --git a/Assets/MyGame/Scripts/Debug.meta b/Assets/MyGame/Scripts/Debug.meta
new file mode 100644
index 000000000..8ff3fb5ea
--- /dev/null
+++ b/Assets/MyGame/Scripts/Debug.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 7f650bd50b29116409d46a87a7828a35
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/MyGame/Scripts/Debug/AABundleMonitor.cs b/Assets/MyGame/Scripts/Debug/AABundleMonitor.cs
new file mode 100644
index 000000000..f29e4c759
--- /dev/null
+++ b/Assets/MyGame/Scripts/Debug/AABundleMonitor.cs
@@ -0,0 +1,513 @@
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+using System.Text;
+using UnityEngine;
+using UnityEngine.InputSystem;
+using UnityEngine.Profiling;
+
+///
+/// Addressables / AssetBundle 已加载包实时监控悬浮窗(调试插件)。
+///
+/// 【用途】
+/// 实时查看当前进程里加载了哪些 AA 包(bundle)、数量与内存概况,
+/// 用于定位"进房加载资源时内存暴涨 / 被 iOS jetsam 杀掉"这类问题。
+/// 注意:本项目所有 Addressables 组都是 LZMA 压缩,包一旦被打开就会整体解压进内存
+/// (实测 fish_hhwk 解压 487MB、fish_flzy 436MB、fish_xjmh 219MB),
+/// 所以看到哪个大包出现时,概览里的内存数字会立刻抬升,可直接对上。
+///
+/// 【使用方式】
+/// 1. 编辑器 Play / Development Build:自动出现在左上角,无需任何操作;
+/// 2. 其他构建(如 Release 真机包):加 AA_MONITOR 宏,或把本组件手动挂到任意常驻物体上。
+///
+/// 【操作】
+/// - 左上角小标签:可拖动;轻点 = 展开 / 收起面板(编辑器下 F9 也可切换)
+/// - 面板:上一页 / 下一页翻页;"导出日志"把完整列表 + 内存打入 Player Log(真机看 Xcode / idevice 日志)
+/// - 每次有新包加载 / 卸载时自动打日志(logOnChange,默认开)
+///
+/// 【注意】
+/// 项目 Active Input Handling = Input System(New),IMGUI 收不到点击事件,
+/// 所以本窗口的交互(拖动 / 轻点 / 翻页)全部用新输入系统自行采样实现,不依赖 GUILayout 按钮;
+/// 也因此悬浮层上的点击无法从游戏输入里"吃掉",测试时的小误触属正常现象。
+///
+public class AABundleMonitor : MonoBehaviour
+{
+ #region 配置
+
+ /// 新包加载 / 卸载时自动输出日志(真机排查用,建议保持开启)
+ public static bool logOnChange = true;
+
+ /// 刷新间隔(秒):0.5 秒扫一次已加载包列表,避免每帧开销
+ private const float RefreshInterval = 0.5f;
+
+ /// 新增包高亮保持时长(秒)
+ private const float HighlightDuration = 5f;
+
+ #endregion
+
+ #region 自动安装
+
+#if UNITY_EDITOR || DEVELOPMENT_BUILD || AA_MONITOR
+ [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterSceneLoad)]
+ private static void AutoInstall()
+ {
+ if (FindFirstObjectByType() != null) return;
+ var go = new GameObject("[AABundleMonitor]");
+ DontDestroyOnLoad(go);
+ go.AddComponent();
+ }
+#endif
+
+ #endregion
+
+ #region 数据
+
+ /// 单个已加载包的记录
+ private sealed class BundleRecord
+ {
+ public string name; // 完整 bundle 名(导出日志用)
+ public string shortName; // 截断后的显示名
+ public float firstSeen; // 首次出现时间(realtimeSinceStartup)
+ public bool streamedScene; // 是否是场景包
+ public string tag; // 内容标识(扫描包内资源路径得出,如 XJMH/HHWK/FLZY/LOGIN)
+ public int assetCount; // 包内资源数量(GetAllAssetNames 只读目录,不会加载资源)
+ public List samplePaths; // 样例资源路径(导出日志用,帮助辨认包内容)
+ }
+
+ private readonly Dictionary _records = new Dictionary();
+ private readonly List _sorted = new List(); // 按加载时间倒序(最新在前)
+ private readonly HashSet _loadedNow = new HashSet(); // 本次扫描到的包名
+ private readonly List _removed = new List(); // 本次扫描发现已卸载的包名
+
+ private float _appStartTime;
+ private float _nextRefreshTime;
+
+ // 悬浮标签(可拖动)
+ private Vector2 _ballPos = new Vector2(16f, 16f);
+ private Rect _ballRect;
+ private bool _ballDragging;
+ private Vector2 _ballDragOffset;
+ private bool _ballMoved;
+
+ // 面板
+ private bool _panelOpen = true;
+ private int _page;
+ private int _rowsPerPage = 12;
+
+ // 上一帧 OnGUI 画出的按钮区域(供自采样点击命中,IMGUI 事件在本项目不可用)
+ private Rect _prevPageRect, _nextPageRect, _exportRect;
+
+ // 样式缓存
+ private GUIStyle _styleTitle, _styleLine, _styleOld, _styleNew, _styleButton, _styleWrap;
+
+ // 编辑器 PlayMode Script 名称(仅编辑器下有效,反射读取,失败为空)
+ private string _editorPlayModeName;
+
+ #endregion
+
+ #region 生命周期
+
+ private void Awake()
+ {
+ _appStartTime = Time.realtimeSinceStartup;
+ if (Application.isEditor) _editorPlayModeName = ReadEditorPlayModeName();
+ Refresh();
+ }
+
+ private void Update()
+ {
+ PollPointer();
+ if (Time.unscaledTime >= _nextRefreshTime)
+ Refresh();
+ }
+
+ #endregion
+
+ #region 扫描已加载包
+
+ private void Refresh()
+ {
+ _nextRefreshTime = Time.unscaledTime + RefreshInterval;
+
+ int addedCount = 0;
+ _loadedNow.Clear();
+ var bundles = AssetBundle.GetAllLoadedAssetBundles();
+ if (bundles != null)
+ {
+ foreach (var b in bundles)
+ {
+ if (b == null) continue;
+ string n = b.name;
+ _loadedNow.Add(n);
+
+ if (!_records.ContainsKey(n))
+ {
+ string baseName = n.EndsWith(".bundle") ? n.Substring(0, n.Length - 7) : n;
+ var rec = new BundleRecord
+ {
+ name = n,
+ shortName = baseName.Length > 16 ? baseName.Substring(0, 16) + "…" : baseName,
+ firstSeen = Time.realtimeSinceStartup,
+ streamedScene = b.isStreamedSceneAssetBundle
+ };
+
+ // ⭐ 扫描包内资源清单辨认内容(GetAllAssetNames 只读包目录、不会把资源加载进内存)
+ try
+ {
+ var assets = b.GetAllAssetNames();
+ if (assets != null && assets.Length > 0)
+ {
+ rec.assetCount = assets.Length;
+ rec.tag = GuessTag(assets);
+ rec.samplePaths = new List();
+ for (int i = 0; i < assets.Length && rec.samplePaths.Count < 4; i++)
+ rec.samplePaths.Add(assets[i]);
+ }
+ }
+ catch { }
+
+ _records[n] = rec;
+ addedCount++;
+ if (logOnChange)
+ Debug.Log(string.IsNullOrEmpty(rec.tag)
+ ? $"[AA包监控] + {n}({rec.assetCount} 项)"
+ : $"[AA包监控] + {n}【{rec.tag}】({rec.assetCount} 项)");
+ }
+ }
+ }
+
+ // 已卸载的包:从记录中移除
+ _removed.Clear();
+ foreach (var kv in _records)
+ if (!_loadedNow.Contains(kv.Key)) _removed.Add(kv.Key);
+ foreach (var n in _removed)
+ {
+ _records.Remove(n);
+ if (logOnChange)
+ Debug.Log($"[AA包监控] - {n}");
+ }
+
+ // 排序:最新加载的排最前(进房时新增的包会直接顶到列表上方)
+ _sorted.Clear();
+ _sorted.AddRange(_records.Values);
+ _sorted.Sort((a, b) => b.firstSeen.CompareTo(a.firstSeen));
+
+ if (logOnChange && (addedCount > 0 || _removed.Count > 0))
+ Debug.Log($"[AA包监控] 变动:+{addedCount} / -{_removed.Count},当前共 {_records.Count} 个包 | {MemSummary()}");
+ }
+
+ private static string MemSummary()
+ {
+ long allocated = Profiler.GetTotalAllocatedMemoryLong();
+ long reserved = Profiler.GetTotalReservedMemoryLong();
+ long mono = Profiler.GetMonoUsedSizeLong();
+ return $"内存: 已分配 {allocated / 1048576f:F1}MB / 预留 {reserved / 1048576f:F1}MB / Mono {mono / 1048576f:F1}MB";
+ }
+
+ ///
+ /// 根据包内资源路径猜内容标识:优先识别玩法关键词(XJMH/HHWK/FLZY),
+ /// 否则取出现最多的路径段(如 login/home/zhanshen 等),识别不出返回空。
+ ///
+ private static string GuessTag(string[] assets)
+ {
+ int sample = Mathf.Min(assets.Length, 400);
+ int xjmh = 0, hhwk = 0, flzy = 0;
+ var freq = new Dictionary(StringComparer.OrdinalIgnoreCase);
+
+ for (int i = 0; i < sample; i++)
+ {
+ string a = assets[i].ToLowerInvariant();
+ if (a.Contains("xjmh")) xjmh++;
+ else if (a.Contains("hhwk")) hhwk++;
+ else if (a.Contains("flzy") || a.Contains("fenglei")) flzy++;
+
+ var parts = a.Split('/');
+ for (int k = 1; k < parts.Length && k <= 3; k++)
+ {
+ string seg = parts[k];
+ if (seg.Length == 0 || seg.Length > 12) continue;
+ if (seg == "assets" || seg == "mygame" || seg == "art" || seg == "game" || seg == "aa" || seg == "ui") continue;
+ freq.TryGetValue(seg, out int c);
+ freq[seg] = c + 1;
+ }
+ }
+
+ int minHits = Mathf.Max(3, sample / 5);
+ if (xjmh >= minHits && xjmh >= hhwk && xjmh >= flzy) return "XJMH";
+ if (hhwk >= minHits && hhwk >= xjmh && hhwk >= flzy) return "HHWK";
+ if (flzy >= minHits && flzy >= xjmh && flzy >= hhwk) return "FLZY";
+
+ string best = null;
+ int bestCount = 0;
+ foreach (var kv in freq)
+ if (kv.Value > bestCount) { bestCount = kv.Value; best = kv.Key; }
+ return bestCount >= minHits ? best.ToUpperInvariant() : null;
+ }
+
+ ///
+ /// 编辑器里显示当前 Addressables Play Mode Script 状态:
+ /// Use Asset Database / Simulate Groups 模式下资源直接走工程读取、不产生 bundle,
+ /// 本窗口看不到包属正常;0 个包时附带"去哪看真实包"的操作指引。
+ ///
+ private string EditorStatusLine()
+ {
+ if (!Application.isEditor) return null;
+ string mode = string.IsNullOrEmpty(_editorPlayModeName) ? "未知" : _editorPlayModeName;
+ if (_records.Count == 0 && mode != "Use Existing Build")
+ return $"编辑器 PlayMode:{mode} —— 此模式资源不走 bundle,0 个包属正常。" +
+ "要看真实包:构建 Windows 内容后切 Use Existing Build,或用真机 Dev Build";
+ return $"编辑器 PlayMode:{mode}";
+ }
+
+ ///
+ /// 反射读取 Addressables 编辑器设置里的 PlayMode Script 索引
+ /// (0=Use Asset Database 1=Simulate Groups 2=Use Existing Build 3=Default Build Script)。
+ /// 用反射是为了不依赖 Unity.Addressables.Editor 程序集,运行时/真机编译不受影响。
+ ///
+ private static string ReadEditorPlayModeName()
+ {
+ try
+ {
+ var t = Type.GetType("UnityEditor.AddressableAssets.Settings.ProjectConfigData, Unity.Addressables.Editor");
+ var prop = t?.GetProperty("ActivePlayModeIndex", BindingFlags.Public | BindingFlags.Static);
+ if (prop != null)
+ {
+ int idx = (int)prop.GetValue(null);
+ switch (idx)
+ {
+ case 0: return "Use Asset Database";
+ case 1: return "Simulate Groups";
+ case 2: return "Use Existing Build";
+ case 3: return "Default Build Script";
+ }
+ return $"index={idx}";
+ }
+ }
+ catch { }
+ return "未知";
+ }
+
+ #endregion
+
+ #region 输入(新输入系统自采样:拖动标签 / 轻点切换 / 翻页 / 导出)
+
+ private void PollPointer()
+ {
+ // 键盘便捷开关(编辑器 / 带键盘设备;真机为 null 自动跳过)
+ var kb = Keyboard.current;
+ if (kb != null && kb.f9Key.wasPressedThisFrame)
+ _panelOpen = !_panelOpen;
+
+ Vector2 screenPos;
+ bool isPressed, wasPressed, wasReleased;
+
+ var ts = Touchscreen.current;
+ var m = Mouse.current;
+
+ bool touchActive = ts != null &&
+ (ts.primaryTouch.press.isPressed || ts.primaryTouch.press.wasPressedThisFrame || ts.primaryTouch.press.wasReleasedThisFrame);
+
+ if (touchActive)
+ {
+ screenPos = ts.primaryTouch.position.ReadValue();
+ isPressed = ts.primaryTouch.press.isPressed;
+ wasPressed = ts.primaryTouch.press.wasPressedThisFrame;
+ wasReleased = ts.primaryTouch.press.wasReleasedThisFrame;
+ }
+ else if (m != null)
+ {
+ screenPos = m.position.ReadValue();
+ isPressed = m.leftButton.isPressed;
+ wasPressed = m.leftButton.wasPressedThisFrame;
+ wasReleased = m.leftButton.wasReleasedThisFrame;
+ }
+ else
+ {
+ return;
+ }
+
+ // 输入系统的坐标原点在左下,OnGUI 在左上
+ var guiPos = new Vector2(screenPos.x, Screen.height - screenPos.y);
+
+ if (wasPressed)
+ OnPointerPressed(guiPos);
+
+ if (_ballDragging)
+ {
+ if (isPressed)
+ {
+ Vector2 target = guiPos - _ballDragOffset;
+ if (Vector2.Distance(target, _ballPos) > 6f) _ballMoved = true;
+ _ballPos = ClampToScreen(target);
+ }
+ else if (wasReleased)
+ {
+ _ballDragging = false;
+ if (!_ballMoved) _panelOpen = !_panelOpen; // 轻点 = 切换面板
+ }
+ }
+ }
+
+ private void OnPointerPressed(Vector2 guiPos)
+ {
+ _ballDragging = false;
+ _ballMoved = false;
+
+ if (_ballRect.Contains(guiPos))
+ {
+ _ballDragging = true;
+ _ballDragOffset = guiPos - _ballPos;
+ return;
+ }
+
+ if (!_panelOpen) return;
+
+ if (_prevPageRect.Contains(guiPos)) { _page--; return; }
+ if (_nextPageRect.Contains(guiPos)) { _page++; return; }
+ if (_exportRect.Contains(guiPos)) { ExportLog(); return; }
+ }
+
+ private static Vector2 ClampToScreen(Vector2 pos)
+ {
+ return new Vector2(
+ Mathf.Clamp(pos.x, 0f, Mathf.Max(0f, Screen.width - 160f)),
+ Mathf.Clamp(pos.y, 0f, Mathf.Max(0f, Screen.height - 64f)));
+ }
+
+ #endregion
+
+ #region 绘制
+
+ private void OnGUI()
+ {
+ EnsureStyles();
+ DrawBall();
+ if (_panelOpen)
+ DrawPanel();
+ }
+
+ private void DrawBall()
+ {
+ _ballRect = new Rect(_ballPos.x, _ballPos.y, 152f, 56f);
+
+ GUI.color = new Color(0f, 0f, 0f, 0.72f);
+ GUI.DrawTexture(_ballRect, Texture2D.whiteTexture);
+ GUI.color = Color.white;
+
+ GUI.Label(new Rect(_ballRect.x + 12f, _ballRect.y + 3f, 140f, 26f), $"AA包 {_records.Count}", _styleTitle);
+ GUI.Label(new Rect(_ballRect.x + 12f, _ballRect.y + 28f, 140f, 24f), _panelOpen ? "点我收起" : "点我展开", _styleLine);
+ }
+
+ private void DrawPanel()
+ {
+ float w = Mathf.Min(Screen.width - 32f, 980f);
+ float h = Mathf.Min(Screen.height - 140f, 1500f);
+ float x = Mathf.Clamp(_ballPos.x, 8f, Mathf.Max(8f, Screen.width - w - 8f));
+ float y = Mathf.Clamp(_ballPos.y + 64f, 8f, Mathf.Max(8f, Screen.height - h - 8f));
+ var panel = new Rect(x, y, w, h);
+
+ GUI.color = new Color(0f, 0f, 0f, 0.84f);
+ GUI.DrawTexture(panel, Texture2D.whiteTexture);
+ GUI.color = Color.white;
+
+ string status = EditorStatusLine();
+ float statusH = status == null ? 0f : 58f;
+ float headerH = 108f + statusH;
+ const float footerH = 64f;
+ const float rowH = 30f;
+
+ // ---- 概要 ----
+ GUI.Label(new Rect(panel.x + 16f, panel.y + 8f, w - 32f, 30f), $"AA 已加载包监控 共 {_records.Count} 个", _styleTitle);
+ GUI.Label(new Rect(panel.x + 16f, panel.y + 42f, w - 32f, 26f), MemSummary(), _styleLine);
+ GUI.Label(new Rect(panel.x + 16f, panel.y + 70f, w - 32f, 26f),
+ $"运行 {(Time.realtimeSinceStartup - _appStartTime):F0}s 黄色 = 近 {HighlightDuration:F0} 秒新增(新加载的包在列表最上方)", _styleLine);
+ if (status != null)
+ GUI.Label(new Rect(panel.x + 16f, panel.y + 96f, w - 32f, statusH), status, _styleWrap);
+
+ // ---- 列表分页 ----
+ _rowsPerPage = Mathf.Max(4, (int)((panel.height - headerH - footerH - 12f) / rowH));
+ int totalPages = Mathf.Max(1, Mathf.CeilToInt(_sorted.Count / (float)_rowsPerPage));
+ _page = Mathf.Clamp(_page, 0, totalPages - 1);
+ int start = _page * _rowsPerPage;
+
+ float rowY = panel.y + headerH;
+ for (int i = 0; i < _rowsPerPage; i++)
+ {
+ int idx = start + i;
+ if (idx >= _sorted.Count) break;
+
+ var r = _sorted[idx];
+ bool isNew = Time.realtimeSinceStartup - r.firstSeen < HighlightDuration;
+ var style = isNew ? _styleNew : _styleOld;
+ string sceneTag = r.streamedScene ? "[场景] " : "";
+ string info = string.IsNullOrEmpty(r.tag)
+ ? (r.assetCount > 0 ? $"{r.assetCount}项" : "")
+ : $"【{r.tag}】{r.assetCount}项";
+ string text = $"{sceneTag}{r.shortName} {info} (+{r.firstSeen - _appStartTime:F0}s)";
+ GUI.Label(new Rect(panel.x + 18f, rowY, w - 36f, rowH), text, style);
+ rowY += rowH;
+ }
+
+ // ---- 底部按钮(自采样点击,IMGUI 按钮不可用)----
+ float btnY = panel.yMax - 52f;
+ float btnW = 150f;
+ _prevPageRect = new Rect(panel.x + 16f, btnY, btnW, 44f);
+ _nextPageRect = new Rect(panel.x + 16f + btnW + 12f, btnY, btnW, 44f);
+ _exportRect = new Rect(panel.xMax - btnW - 16f, btnY, btnW, 44f);
+
+ DrawFakeButton(_prevPageRect, "上一页");
+ DrawFakeButton(_nextPageRect, "下一页");
+ DrawFakeButton(_exportRect, "导出日志");
+
+ GUI.Label(new Rect(panel.x + 16f + (btnW + 12f) * 2f, btnY + 10f, 160f, 26f), $"{_page + 1} / {totalPages}", _styleLine);
+ }
+
+ private void DrawFakeButton(Rect r, string text)
+ {
+ GUI.color = new Color(1f, 1f, 1f, 0.22f);
+ GUI.DrawTexture(r, Texture2D.whiteTexture);
+ GUI.color = Color.white;
+ GUI.Label(new Rect(r.x, r.y + 8f, r.width, 28f), text, _styleButton);
+ }
+
+ private void EnsureStyles()
+ {
+ if (_styleTitle != null) return;
+
+ _styleTitle = new GUIStyle(GUI.skin.label) { fontSize = 26, fontStyle = FontStyle.Bold };
+ _styleTitle.normal.textColor = Color.white;
+
+ _styleLine = new GUIStyle(GUI.skin.label) { fontSize = 22 };
+ _styleLine.normal.textColor = new Color(0.82f, 0.9f, 1f);
+
+ _styleOld = new GUIStyle(GUI.skin.label) { fontSize = 23 };
+ _styleOld.normal.textColor = Color.white;
+
+ _styleNew = new GUIStyle(GUI.skin.label) { fontSize = 23, fontStyle = FontStyle.Bold };
+ _styleNew.normal.textColor = new Color(1f, 0.82f, 0.2f);
+
+ _styleButton = new GUIStyle(GUI.skin.label) { fontSize = 24, alignment = TextAnchor.UpperCenter };
+ _styleButton.normal.textColor = Color.white;
+
+ _styleWrap = new GUIStyle(GUI.skin.label) { fontSize = 20, wordWrap = true };
+ _styleWrap.normal.textColor = new Color(0.95f, 0.9f, 0.62f);
+ }
+
+ #endregion
+
+ #region 导出
+
+ private void ExportLog()
+ {
+ var sb = new StringBuilder();
+ sb.AppendLine($"[AA包监控] 导出时间 {DateTime.Now:yyyy-MM-dd HH:mm:ss},共 {_records.Count} 个包 | {MemSummary()}");
+ foreach (var r in _sorted)
+ sb.AppendLine($" {(r.streamedScene ? "[场景] " : "")}{r.name} (+{r.firstSeen - _appStartTime:F1}s)");
+
+ string text = sb.ToString();
+ Debug.Log(text);
+ try { GUIUtility.systemCopyBuffer = text; } catch { }
+ }
+
+ #endregion
+}
\ No newline at end of file
diff --git a/Assets/MyGame/Scripts/Debug/AABundleMonitor.cs.meta b/Assets/MyGame/Scripts/Debug/AABundleMonitor.cs.meta
new file mode 100644
index 000000000..9c7291ae6
--- /dev/null
+++ b/Assets/MyGame/Scripts/Debug/AABundleMonitor.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: bd70cad3c45605a4f824c9eaf1eb081d
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/MyGame/Scripts/Turret/SitPosData.cs b/Assets/MyGame/Scripts/Turret/SitPosData.cs
index 9fb85a2d4..5d2715469 100644
--- a/Assets/MyGame/Scripts/Turret/SitPosData.cs
+++ b/Assets/MyGame/Scripts/Turret/SitPosData.cs
@@ -261,12 +261,15 @@ public class SitPosData : MonoBehaviour, IPointerDownHandler, IPointerUpHandler
if (btn_TurretMinus != null)
btn_TurretMinus.onClick.AddListener(() => ChangeTurretMinusConsumeNum());
- // ⭐ 自动攻击开关:先检测自身 GameObject 激活状态,没激活就激活(预制体/外部可能把它藏了,
- // 隐藏状态下点不到,自动攻击无法开关);再挂监听:关闭时本地座位炮台切回 Idle(原 GameMainPanel 的 toggle_SkillAuto 逻辑)
+ // ⭐ 自动攻击开关:默认隐藏,等玩家入座时由 ShowPlayer 按"是否本地座位"决定显隐。
+ // ⚠️ 以前这里是"没激活就无条件激活"(为修预制体把按钮藏了、点不到的问题),
+ // 但第二个人加入时他的座位才第一次激活、Awake 此刻才执行 → 会把他的"自动"按钮也打开,
+ // 屏幕上出现两个"自动"按钮。改为默认隐藏 + 入座时按本地/他座显隐(本地按钮不会再被藏)。
+ // 监听照旧:关闭时本地座位炮台切回 Idle(原 GameMainPanel 的 toggle_SkillAuto 逻辑)
if (toggle_AutoAttack != null)
{
- if (!toggle_AutoAttack.gameObject.activeSelf)
- toggle_AutoAttack.gameObject.SetActive(true);
+ if (toggle_AutoAttack.gameObject.activeSelf)
+ toggle_AutoAttack.gameObject.SetActive(false);
toggle_AutoAttack.onValueChanged.AddListener(OnAutoAttackToggleChanged);
}
@@ -1101,6 +1104,11 @@ public class SitPosData : MonoBehaviour, IPointerDownHandler, IPointerUpHandler
transform.GetChild(1).gameObject.SetActive(false);
}
+ // ⭐ "自动"按钮只属于本地玩家:本地座位显示、其他座位隐藏
+ // (第二个人加入时他的座位才第一次激活,Awake 已改为默认隐藏,这里按座位归属再定一次)
+ if (toggle_AutoAttack != null)
+ toggle_AutoAttack.gameObject.SetActive(user == GameManager.Instance?.user?.id);
+
// 如果是本地玩家的座位,自动注册并加载装备
if (user == GameManager.Instance?.user?.id)
{
@@ -1134,6 +1142,10 @@ public class SitPosData : MonoBehaviour, IPointerDownHandler, IPointerUpHandler
///
public void ShowWaiting()
{
+ // ⭐ 离座:自动按钮一并隐藏(XJMH 也要处理——空座位不该留"自动"按钮)
+ if (toggle_AutoAttack != null)
+ toggle_AutoAttack.gameObject.SetActive(false);
+
if (turretControlMode == TurretControlMode.XJMH) return;
if (transform.childCount > 0)
diff --git a/Assets/MyGame/Scripts/fishResources/AudioResourcesData.cs b/Assets/MyGame/Scripts/fishResources/AudioResourcesData.cs
index 6a0fa3d2a..4c2de34a7 100644
--- a/Assets/MyGame/Scripts/fishResources/AudioResourcesData.cs
+++ b/Assets/MyGame/Scripts/fishResources/AudioResourcesData.cs
@@ -1,4 +1,4 @@
-using Newtonsoft.Json;
+using Newtonsoft.Json;
using Spine.Unity;
using System;
using System.Collections;
@@ -20,10 +20,20 @@ public class AudioResourcesData
static Dictionary audioClipDefaultDic=new Dictionary();
static Dictionary audioClipGameDic=new Dictionary();
const string Audio_AALabel="Audio";
+
+ // ⭐ 句柄显式管理(修复"包只增不减"的根源):
+ // 之前 Load 的句柄直接丢弃(泄漏,包永不卸载),UnLoad 再重新 Load 一遍拿句柄释放
+ // (净引用数 0,等于什么都没卸载)。现在:加载时保存句柄,卸载时真正 Release。
+ // 注意:游戏音频物理上打在鱼包里(Audio+玩法 交集 = 鱼包),释放本句柄是鱼包能卸载的前提之一。
+ /// 默认音频句柄(Audio+Default,进程常驻,不卸载)
+ static AsyncOperationHandle> _defaultAudioHandle;
+ /// 当前玩法游戏音频句柄(Audio+玩法,进房加载/离房释放)
+ static AsyncOperationHandle> _gameAudioHandle;
+
static AudioResourcesData()
{
-
-
+
+
//这里要添加默认的音效 背景 按钮点击
LoadDefaultAudioGame();
}
@@ -39,7 +49,7 @@ public class AudioResourcesData
name_IDDic[item.audioResourcesPath]=item.audioID;
}
var keys = new List { Audio_AALabel, "Default" };
- await Addressables.LoadAssetsAsync(keys, audio =>
+ _defaultAudioHandle = Addressables.LoadAssetsAsync(keys, audio =>
{
Debug.Log("加载音频: " + audio.name);
if (name_IDDic.ContainsKey(audio.name))
@@ -47,7 +57,8 @@ public class AudioResourcesData
Debug.Log("加载音频ID: " + name_IDDic[audio.name]);
audioClipDefaultDic.Add(name_IDDic[audio.name],audio);
}
- }, MergeMode.Intersection).Task;
+ }, MergeMode.Intersection);
+ await _defaultAudioHandle.Task;
foreach (var item in audioClipDefaultDic)
{
audioClipDic.Add(item.Key, item.Value);
@@ -82,13 +93,22 @@ public class AudioResourcesData
try
{
- await Addressables.LoadAssetsAsync(keys, audio =>
+ // ⭐ 防御:上一轮句柄未释放(如离房被跳过)时先释放,避免引用计数累加
+ if (_gameAudioHandle.IsValid())
+ Addressables.Release(_gameAudioHandle);
+
+ // ⭐ 双标签交集(Audio + 当前玩法):只加载当前玩法标记的音频。
+ // Union 会按 "Audio" 标签把其它玩法的音频包一并打开,
+ // 而这些音频物理上和鱼的 Prefab 打在同一个 LZMA 包里 → 整包解压进内存导致 iOS 被杀
+ // 句柄保存到 _gameAudioHandle,离房时 UnLoadAudioGame 真正释放 → 鱼包才能卸载
+ _gameAudioHandle = Addressables.LoadAssetsAsync(keys, audio =>
{
if (name_IDDic != null && name_IDDic.ContainsKey(audio.name))
{
audioClipGameDic[name_IDDic[audio.name]] = audio;
}
- }, MergeMode.Union).Task;
+ }, MergeMode.Intersection);
+ await _gameAudioHandle.Task;
audioClipDic = new Dictionary();
if (audioClipDefaultDic != null)
@@ -107,40 +127,21 @@ public class AudioResourcesData
Debug.LogError($"加载游戏音频失败: {e.Message}");
}
}
- public static async Task UnLoadAudioGame()
+ public static Task UnLoadAudioGame()
{
- GameType gameType = GameManager.Instance.gameData.currGameType;
- var keys = new List { Audio_AALabel, gameType.ToString() };
+ // ⭐ 真正的卸载:释放加载时保存的句柄(引用归零后 Audio+玩法 命中的 bundle 才会真正卸载)。
+ // 旧实现"重新 Load 一遍拿句柄再 Release"是净 0 操作,什么都卸不掉。
+ if (_gameAudioHandle.IsValid())
+ Addressables.Release(_gameAudioHandle);
- // 加载对应的句柄(只是为了拿到引用,之后释放)
- AsyncOperationHandle> handle = Addressables.LoadAssetsAsync(keys, null, MergeMode.Intersection);
- await handle.Task;
+ // 清空游戏音频字典(包卸载后 AudioClip 对象已失效,残留引用会导致播放 null)
+ audioClipGameDic.Clear();
- // 遍历卸载对应的音频
- foreach (var audio in handle.Result)
- {
- if (name_IDDic.ContainsKey(audio.name))
- {
- int id = name_IDDic[audio.name];
- if (audioClipGameDic.ContainsKey(id))
- {
- audioClipGameDic.Remove(id);
- Debug.Log($"卸载音频: {audio.name} (ID={id})");
- }
- }
- }
-
- // 释放 Addressables 资源句柄
- Addressables.Release(handle);
-
- // 重建总字典:保留默认音频 + 剩余游戏音频
+ // 重建总字典:只保留默认音频
audioClipDic = new Dictionary(audioClipDefaultDic);
- foreach (var item in audioClipGameDic)
- {
- audioClipDic[item.Key] = item.Value;
- }
Debug.Log("卸载完成,当前音频数量:" + audioClipDic.Count);
+ return Task.CompletedTask;
}
diff --git a/Assets/MyGame/Scripts/fishResources/FishResourcesData.cs b/Assets/MyGame/Scripts/fishResources/FishResourcesData.cs
index 2bcc69aea..83d59f31e 100644
--- a/Assets/MyGame/Scripts/fishResources/FishResourcesData.cs
+++ b/Assets/MyGame/Scripts/fishResources/FishResourcesData.cs
@@ -6,6 +6,7 @@ using System.Collections.Generic;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.AddressableAssets;
+using UnityEngine.ResourceManagement.AsyncOperations;
using static UnityEngine.AddressableAssets.Addressables;
[Serializable]
@@ -77,6 +78,14 @@ public class FishResourcesData
public static Dictionary fishResourcesDatasDic;//id--FishResourcesData
public static Dictionary fishResourcesSpritesDic;//id--Sprite
private static Dictionary diePrefabDic;//id--SkeletonDataAsset
+
+ // ⭐ 句柄显式管理(修复"包只增不减"的根源):
+ // 旧实现加载完立即 Release 句柄,但 fishPrefabDic 还持有 prefab 引用 ——
+ // 包没被卸载全靠 AudioResourcesData 泄漏的音频句柄"误打误撞"撑着(音频物理上就在鱼包里)。
+ // 现在:加载时保存句柄(prefab/dieSpine/sprite 三类),离房时 UnLoadFishAssetsData 统一 Release,
+ // 引用归零后鱼包真正从内存卸载 —— 依次进所有玩法不再累加内存。
+ private static readonly List _fishHandles = new List();
+
public static async Task LoadFishAssetsData()
{
// 清空对象池
@@ -86,6 +95,13 @@ public class FishResourcesData
diePrefabDic = new Dictionary();
fishResourcesSpritesDic = new Dictionary();
+ // ⭐ 防御:上一轮句柄未释放(如离房流程被跳过)时先释放,避免引用计数累加
+ foreach (var h in _fishHandles)
+ {
+ if (h.IsValid()) Addressables.Release(h);
+ }
+ _fishHandles.Clear();
+
// ---------------- 1. 预下载所有依赖资源(关键) ----------------
var labels = new List
{
@@ -120,7 +136,8 @@ public class FishResourcesData
}, MergeMode.Intersection);
await prefabHandle.Task;
- Addressables.Release(prefabHandle);
+ // ⭐ 不再立即 Release:保存句柄保持包存活,离房时统一卸载
+ _fishHandles.Add(prefabHandle);
Debug.Log($"Prefab 加载完成,共 {fishPrefabDic.Count} 个");
// ---------------- 3. 加载死亡 Spine 动效 ----------------
@@ -138,7 +155,7 @@ public class FishResourcesData
}, MergeMode.Intersection);
await dieHandle.Task;
- Addressables.Release(dieHandle);
+ _fishHandles.Add(dieHandle);
Debug.Log($"死亡 Spine 加载完成,共 {diePrefabDic.Count} 个");
}
catch (Exception e)
@@ -159,7 +176,7 @@ public class FishResourcesData
}, MergeMode.Intersection);
await spriteHandle.Task;
- Addressables.Release(spriteHandle);
+ _fishHandles.Add(spriteHandle);
Debug.Log($"Sprite 加载完成,共 {fishResourcesSpritesDic.Count} 个");
}
catch (Exception e)
@@ -171,81 +188,26 @@ public class FishResourcesData
}
- public static async Task UnLoadFishAssetsData()
+ public static Task UnLoadFishAssetsData()
{
+ // ⭐ 真正的卸载:释放加载时保存的全部句柄(引用归零后鱼包才会真正卸载)。
+ // 旧实现"重新 Load 一遍拿句柄再 Release"是净 0 操作,什么都卸不掉。
Pool.Instance.Clear();
- // 卸载 Prefab
- var keys = new List { prefabFish_AALabel, GameManager.Instance.gameData.currGameType.ToString() };
- var prefabHandle = Addressables.LoadAssetsAsync(keys, null, MergeMode.Intersection);
- await prefabHandle.Task;
-
- if (prefabHandle.Result != null)
+ foreach (var h in _fishHandles)
{
- foreach (var prefab in prefabHandle.Result)
- {
- if (FishResourcesPrefabsDic.TryGetValue(prefab.name, out int id))
- {
- if (fishPrefabDic.Remove(id))
- {
- Debug.Log($"卸载鱼Prefab: {prefab.name} (ID={id})");
- }
- }
- }
+ if (h.IsValid())
+ Addressables.Release(h);
}
- Addressables.Release(prefabHandle);
+ _fishHandles.Clear();
- // 卸载死亡 Spine 动效
- keys = new List { dieSpine_AALabel, GameManager.Instance.gameData.currGameType.ToString() };
- var dieHandle = Addressables.LoadAssetsAsync(keys, null, MergeMode.Intersection);
- await dieHandle.Task;
+ // ⭐ 清空字典(包卸载后对象已失效,残留引用会指向已销毁资源)
+ fishPrefabDic?.Clear();
+ diePrefabDic?.Clear();
+ fishResourcesSpritesDic?.Clear();
- if (dieHandle.Result != null)
- {
- foreach (var data in dieHandle.Result)
- {
- if (FishResourcesSpineDieDic.TryGetValue(data.name, out int id))
- {
- if (diePrefabDic.Remove(id))
- {
- Debug.Log($"卸载鱼死亡动效: {data.name} (ID={id})");
- }
- }
- }
- }
- Addressables.Release(dieHandle);
-
- // 卸载鱼 Sprite
- // ⭐ try-catch 防护:Addressables 可能找不到 TuJian+游戏类型 交集的 Sprite,
- // 抛 InvalidKeyException 导致整个 UnLoadFishAssetsData 中断,后续清理无法执行。
- // Sprite 加载时已有 try-catch,卸载时也应对称处理
- try
- {
- keys = new List { Sprite_AALabel, GameManager.Instance.gameData.currGameType.ToString() };
- var spriteHandle = Addressables.LoadAssetsAsync(keys, null, MergeMode.Intersection);
- await spriteHandle.Task;
-
- if (spriteHandle.Result != null)
- {
- foreach (var sprite in spriteHandle.Result)
- {
- if (FishResourcesSpriteDic.TryGetValue(sprite.name, out int id))
- {
- if (fishResourcesSpritesDic.Remove(id))
- {
- Debug.Log($"卸载鱼Sprite: {sprite.name} (ID={id})");
- }
- }
- }
- }
- Addressables.Release(spriteHandle);
- }
- catch (Exception e)
- {
- Debug.LogWarning($"[FishResourcesData] Sprite 卸载失败(游戏类型={GameManager.Instance.gameData.currGameType}),跳过此项: {e.Message}");
- }
-
- Debug.Log($"卸载完成,剩余Prefab数量: {fishPrefabDic.Count}, 死亡动效数量: {diePrefabDic.Count}, Sprite数量: {fishResourcesSpritesDic.Count}");
+ Debug.Log($"[FishResourcesData] 鱼资源卸载完成");
+ return Task.CompletedTask;
}
diff --git a/Assets/MyGame/aa/Game/FLZY/BOSS/LTZZ/4052.prefab b/Assets/MyGame/aa/Game/FLZY/BOSS/LTZZ/4052.prefab
index fbbf8db11..26baf846d 100644
--- a/Assets/MyGame/aa/Game/FLZY/BOSS/LTZZ/4052.prefab
+++ b/Assets/MyGame/aa/Game/FLZY/BOSS/LTZZ/4052.prefab
@@ -11994,7 +11994,7 @@ MonoBehaviour:
drawLineSegments: 60
drawLineColor: {r: 1, g: 0.92156863, b: 0.015686275, a: 1}
bossName:
- isToUI: 1
+ isToUI: 0
tMP_CurrBossScore: {fileID: 0}
currBossScoreValue: 0
bossScoreValue: 0
diff --git a/Assets/MyGame/aa/Game/FLZY/BOSS/SLZP/1507.prefab b/Assets/MyGame/aa/Game/FLZY/BOSS/SLZP/1507.prefab
index 776145fd1..7337d88ab 100644
--- a/Assets/MyGame/aa/Game/FLZY/BOSS/SLZP/1507.prefab
+++ b/Assets/MyGame/aa/Game/FLZY/BOSS/SLZP/1507.prefab
@@ -1035,6 +1035,11 @@ PrefabInstance:
propertyPath: m_Layer
value: 6
objectReference: {fileID: 0}
+ - target: {fileID: 1758318735507541674, guid: f11065bf68488f64e9d9b8acc8c4caff,
+ type: 3}
+ propertyPath: m_TagString
+ value: Fish
+ objectReference: {fileID: 0}
- target: {fileID: 1848564584791591582, guid: f11065bf68488f64e9d9b8acc8c4caff,
type: 3}
propertyPath: m_Layer
diff --git a/Assets/MyGame/aa/Game/FLZY/BOSS/SSQL/7005.prefab b/Assets/MyGame/aa/Game/FLZY/BOSS/SSQL/7005.prefab
index 12dd9ae79..a0dc8bf9a 100644
--- a/Assets/MyGame/aa/Game/FLZY/BOSS/SSQL/7005.prefab
+++ b/Assets/MyGame/aa/Game/FLZY/BOSS/SSQL/7005.prefab
@@ -14838,7 +14838,7 @@ MonoBehaviour:
drawLineSegments: 60
drawLineColor: {r: 1, g: 0.92156863, b: 0.015686275, a: 1}
bossName:
- isToUI: 1
+ isToUI: 0
tMP_CurrBossScore: {fileID: 0}
currBossScoreValue: 0
bossScoreValue: 0
diff --git a/Assets/MyGame/aa/Game/XJMH/Boss/XingYunFeiDie/RotatePan_XJMH.cs b/Assets/MyGame/aa/Game/XJMH/Boss/XingYunFeiDie/RotatePan_XJMH.cs
index 5ea6aa603..1e99942f8 100644
--- a/Assets/MyGame/aa/Game/XJMH/Boss/XingYunFeiDie/RotatePan_XJMH.cs
+++ b/Assets/MyGame/aa/Game/XJMH/Boss/XingYunFeiDie/RotatePan_XJMH.cs
@@ -192,7 +192,8 @@ public class RotatePan_XJMH : BJRedPacketEvent
// 内圈:可在选项范围内随机偏移(中心角度 ± 半角)
float neiCenterAngle = OptionIdToAngle((int)_innerOpt.optionId, innerCount);
float neiHalfAngle = (360f / innerCount) / 2f;
- float neiTargetAngle = neiCenterAngle + Random.Range(-neiHalfAngle, neiHalfAngle);
+ //float neiTargetAngle = neiCenterAngle + Random.Range(-neiHalfAngle, neiHalfAngle);
+ float neiTargetAngle = neiCenterAngle;
Debug.Log($"[XingYunFeiDie] 内圈目标角度: OptionId={_innerOpt.optionId} count={innerCount} 中心={neiCenterAngle}° 随机后={neiTargetAngle}°");
// 先转内圈
diff --git a/Assets/MyGame/aa/UI/DefaultPanel/592228afbce16145.asset b/Assets/MyGame/aa/UI/DefaultPanel/592228afbce16145.asset
new file mode 100644
index 000000000..172b7f621
--- /dev/null
+++ b/Assets/MyGame/aa/UI/DefaultPanel/592228afbce16145.asset
@@ -0,0 +1,108 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!114 &11400000
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 0}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: 84a92b25f83d49b9bc132d206b370281, type: 3}
+ m_Name: 592228afbce16145
+ m_EditorClassIdentifier:
+ hashCode: -1919871374
+ material: {fileID: 8548082164682178837}
+ materialHashCode: 0
+ m_Version: 1.1.0
+ m_FaceInfo:
+ m_FaceIndex: 0
+ m_FamilyName:
+ m_StyleName:
+ m_PointSize: 0
+ m_Scale: 0
+ m_UnitsPerEM: 0
+ m_LineHeight: 0
+ m_AscentLine: 0
+ m_CapLine: 0
+ m_MeanLine: 0
+ m_Baseline: 0
+ m_DescentLine: 0
+ m_SuperscriptOffset: 0
+ m_SuperscriptSize: 0
+ m_SubscriptOffset: 0
+ m_SubscriptSize: 0
+ m_UnderlineOffset: 0
+ m_UnderlineThickness: 0
+ m_StrikethroughOffset: 0
+ m_StrikethroughThickness: 0
+ m_TabWidth: 0
+ spriteSheet: {fileID: 2800000, guid: 1b70eadb887fad44abd4ece91ee38a6d, type: 3}
+ m_SpriteCharacterTable:
+ - m_ElementType: 2
+ m_Unicode: 65534
+ m_GlyphIndex: 0
+ m_Scale: 1
+ m_Name: 592228afbce16145
+ m_HashCode: -1919871374
+ m_SpriteGlyphTable:
+ - m_Index: 0
+ m_Metrics:
+ m_Width: 127
+ m_Height: 136
+ m_HorizontalBearingX: -63.5
+ m_HorizontalBearingY: 117.5
+ m_HorizontalAdvance: 127
+ m_GlyphRect:
+ m_X: 0
+ m_Y: 0
+ m_Width: 127
+ m_Height: 136
+ m_Scale: 1
+ m_AtlasIndex: 0
+ m_ClassDefinitionType: 0
+ sprite: {fileID: 21300000, guid: 1b70eadb887fad44abd4ece91ee38a6d, type: 3}
+ spriteInfoList: []
+ fallbackSpriteAssets: []
+--- !u!21 &8548082164682178837
+Material:
+ serializedVersion: 8
+ m_ObjectHideFlags: 1
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_Name: TextMeshPro/Sprite
+ m_Shader: {fileID: 4800000, guid: cf81c85f95fe47e1a27f6ae460cf182c, type: 3}
+ m_Parent: {fileID: 0}
+ m_ModifiedSerializedProperties: 0
+ m_ValidKeywords: []
+ m_InvalidKeywords: []
+ m_LightmapFlags: 4
+ m_EnableInstancingVariants: 0
+ m_DoubleSidedGI: 0
+ m_CustomRenderQueue: -1
+ stringTagMap: {}
+ disabledShaderPasses: []
+ m_LockedProperties:
+ m_SavedProperties:
+ serializedVersion: 3
+ m_TexEnvs:
+ - _MainTex:
+ m_Texture: {fileID: 2800000, guid: 1b70eadb887fad44abd4ece91ee38a6d, type: 3}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ m_Ints: []
+ m_Floats:
+ - _ColorMask: 15
+ - _CullMode: 0
+ - _Stencil: 0
+ - _StencilComp: 8
+ - _StencilOp: 0
+ - _StencilReadMask: 255
+ - _StencilWriteMask: 255
+ - _UseUIAlphaClip: 0
+ m_Colors:
+ - _ClipRect: {r: -32767, g: -32767, b: 32767, a: 32767}
+ - _Color: {r: 1, g: 1, b: 1, a: 1}
+ m_BuildTextureStacks: []
diff --git a/Assets/MyGame/aa/UI/DefaultPanel/592228afbce16145.asset.meta b/Assets/MyGame/aa/UI/DefaultPanel/592228afbce16145.asset.meta
new file mode 100644
index 000000000..6dd10bb6a
--- /dev/null
+++ b/Assets/MyGame/aa/UI/DefaultPanel/592228afbce16145.asset.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: ca36565f9fa2172499feaedffabf3ee8
+NativeFormatImporter:
+ externalObjects: {}
+ mainObjectFileID: 11400000
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/MyGame/aa/UI/DefaultPanel/592228afbce16145.png b/Assets/MyGame/aa/UI/DefaultPanel/592228afbce16145.png
new file mode 100644
index 000000000..4527873c1
Binary files /dev/null and b/Assets/MyGame/aa/UI/DefaultPanel/592228afbce16145.png differ
diff --git a/Assets/MyGame/aa/UI/DefaultPanel/592228afbce16145.png.meta b/Assets/MyGame/aa/UI/DefaultPanel/592228afbce16145.png.meta
new file mode 100644
index 000000000..804b00726
--- /dev/null
+++ b/Assets/MyGame/aa/UI/DefaultPanel/592228afbce16145.png.meta
@@ -0,0 +1,153 @@
+fileFormatVersion: 2
+guid: 1b70eadb887fad44abd4ece91ee38a6d
+TextureImporter:
+ internalIDToNameTable: []
+ externalObjects: {}
+ serializedVersion: 13
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 0
+ sRGBTexture: 1
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapsPreserveCoverage: 0
+ alphaTestReferenceValue: 0.5
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ flipGreenChannel: 0
+ isReadable: 0
+ streamingMipmaps: 0
+ streamingMipmapsPriority: 0
+ vTOnly: 0
+ ignoreMipmapLimit: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ serializedVersion: 2
+ filterMode: 1
+ aniso: 1
+ mipBias: 0
+ wrapU: 1
+ wrapV: 1
+ wrapW: 0
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 1
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spritePixelsToUnits: 100
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 8
+ textureShape: 1
+ singleChannelComponent: 0
+ flipbookRows: 1
+ flipbookColumns: 1
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ ignorePngGamma: 0
+ applyGammaDecoding: 0
+ swizzle: 50462976
+ cookieLightType: 0
+ platformSettings:
+ - serializedVersion: 3
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 3
+ buildTarget: Standalone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 3
+ buildTarget: iPhone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 3
+ buildTarget: WebGL
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 3
+ buildTarget: Android
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ physicsShape: []
+ bones: []
+ spriteID: 5e97eb03825dee720800000000000000
+ internalID: 0
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ secondaryTextures: []
+ nameFileIdTable: {}
+ mipmapLimitGroupName:
+ pSDRemoveMatte: 0
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/MyGame/aa/UI/DefaultPanel/BossBoardCarstGongGao.prefab b/Assets/MyGame/aa/UI/DefaultPanel/BossBoardCarstGongGao.prefab
index 59c238f35..72a28c7b4 100644
--- a/Assets/MyGame/aa/UI/DefaultPanel/BossBoardCarstGongGao.prefab
+++ b/Assets/MyGame/aa/UI/DefaultPanel/BossBoardCarstGongGao.prefab
@@ -161,7 +161,7 @@ MonoBehaviour:
bottomLeft: {r: 1, g: 1, b: 1, a: 1}
bottomRight: {r: 1, g: 1, b: 1, a: 1}
m_fontColorGradientPreset: {fileID: 0}
- m_spriteAsset: {fileID: 0}
+ m_spriteAsset: {fileID: 11400000, guid: ca36565f9fa2172499feaedffabf3ee8, type: 2}
m_tintAllSprites: 0
m_StyleSheet: {fileID: 0}
m_TextStyleHashCode: -1183493901
diff --git a/Assets/MyGame/aa/UI/Game/GameMainPanel_FishBase.cs b/Assets/MyGame/aa/UI/Game/GameMainPanel_FishBase.cs
index a39f63d65..b27c80cfe 100644
--- a/Assets/MyGame/aa/UI/Game/GameMainPanel_FishBase.cs
+++ b/Assets/MyGame/aa/UI/Game/GameMainPanel_FishBase.cs
@@ -103,6 +103,7 @@ using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.EventSystems;
using UnityEngine.InputSystem;
+using UnityEngine.ResourceManagement.AsyncOperations;
using UnityEngine.Playables;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
@@ -699,23 +700,38 @@ public class GameMainPanel_FishBase : GameMainPanel_Base
});
// ⭐ 大喇叭:开/关弹幕输入面板
+ // ⭐ 绑定在 OnShow 里:先 RemoveAllListeners 再 Add,防止面板重复 OnShow 叠加监听器
+ // (叠加后点一次发送 = 发 N 次 API = 多扣 N 个道具)
if (dalaba != null)
+ {
+ dalaba.onClick.RemoveAllListeners();
dalaba.onClick.AddListener(() =>
{
if (obj_DaLaBaPanel != null)
obj_DaLaBaPanel.SetActive(!obj_DaLaBaPanel.activeSelf);
});
+ }
if (btn_DaLaBaSend != null)
+ {
+ btn_DaLaBaSend.onClick.RemoveAllListeners();
btn_DaLaBaSend.onClick.AddListener(OnClickDaLaBaSend);
+ }
if (btn_DaLaBaClose != null)
+ {
+ btn_DaLaBaClose.onClick.RemoveAllListeners();
btn_DaLaBaClose.onClick.AddListener(() =>
{
- if (obj_DaLaBaPanel != null) obj_DaLaBaPanel.SetActive(false);
+ if (obj_DaLaBaPanel != null)
+ obj_DaLaBaPanel.SetActive(false);
});
+ }
- // ⭐ 召唤卡:使用召唤卡召唤Boss
+ // ⭐ 召唤卡:使用召唤卡召唤Boss(同样防重复绑定)
if (zhanhuanka != null)
+ {
+ zhanhuanka.onClick.RemoveAllListeners();
zhanhuanka.onClick.AddListener(OnClickZhanHuanKa);
+ }
// 服务器广播监听
EventCenter.Instance.AddEventListener(ConstEventString.SyncGameData_Rotate, SyncGameData_Rotate);
@@ -1253,13 +1269,21 @@ public class GameMainPanel_FishBase : GameMainPanel_Base
await AudioResourcesData.LoadAudioGame();
if (flow != _resourceFlowToken) return;
- await Addressables.LoadAssetsAsync("Audio", clip =>
- {
- if (flow != _resourceFlowToken) return; // 残留流程不再写面板字段
- if (clip.name == "PW_Shoot")
- bulletClip = clip;
- }).Task;
+ // ⭐ 开火音效 PW_Shoot 在 Default Local Group(Audio+PTCBZS 双标签交集检索):
+ // 只命中 Default 小包,不把其它玩法的巨型音频包拉进内存;句柄由 LoadBulletClip 静态保存,离房释放
+ await LoadBulletClip();
if (flow != _resourceFlowToken) return;
+ if (_bulletClipHandle.IsValid() && _bulletClipHandle.Result != null)
+ {
+ foreach (var clip in _bulletClipHandle.Result)
+ {
+ if (clip.name == "PW_Shoot")
+ {
+ bulletClip = clip;
+ break;
+ }
+ }
+ }
SetLoadProgress(0.8f);
await Task.Delay(100);
@@ -1321,6 +1345,7 @@ public class GameMainPanel_FishBase : GameMainPanel_Base
if (flow != _resourceFlowToken) return; // ⭐ 期间已有新流程(新面板加载),剩余卸载作废
await AudioResourcesData.UnLoadAudioGame();
if (flow != _resourceFlowToken) return;
+ UnLoadBulletClip(); // ⭐ 释放开火音效句柄(引用计数归零)
await MonsterMoveLine.UnLoadBezier();
if (flow != _resourceFlowToken) return;
// ⭐ 清空子弹池 + 特效池(鱼池已在 UnLoadFishAssetsData 内清理)
@@ -1332,6 +1357,32 @@ public class GameMainPanel_FishBase : GameMainPanel_Base
/// 资源是否已卸载(避免 OnHide 重复卸载)
private bool _resourcesUnloaded = false;
+ ///
+ /// ⭐ 开火音效 PW_Shoot 的加载句柄(static:新老面板实例共享)。
+ /// PW_Shoot 在 Default Local Group(Audio+PTCBZS),该包因默认音频常驻本就不会卸载,
+ /// 但句柄仍要显式保存/释放,避免每次进房引用计数 +1 无限累加。
+ ///
+ private static AsyncOperationHandle> _bulletClipHandle;
+
+ /// 加载开火音效(Audio+PTCBZS 交集,只命中 Default Local Group 里的 PW_Shoot)
+ private static async Task LoadBulletClip()
+ {
+ // 防御:上一轮句柄未释放时先释放
+ if (_bulletClipHandle.IsValid())
+ Addressables.Release(_bulletClipHandle);
+
+ _bulletClipHandle = Addressables.LoadAssetsAsync(new List { "Audio", "PTCBZS" }, null,
+ Addressables.MergeMode.Intersection);
+ await _bulletClipHandle.Task;
+ }
+
+ /// 释放开火音效句柄(离房卸载流程调用)
+ private static void UnLoadBulletClip()
+ {
+ if (_bulletClipHandle.IsValid())
+ Addressables.Release(_bulletClipHandle);
+ }
+
/// 离房 socket 响应等待信号
private TaskCompletionSource _leaveRoomResponseTcs;
/// 正在离开的游戏面板类型(完成后关闭它切到 home)
@@ -1383,11 +1434,20 @@ public class GameMainPanel_FishBase : GameMainPanel_Base
{
if (JinDuTiao != null) JinDuTiao.Show();
+ // ⭐ 先退房销毁场上活鱼,再卸载资源(与 UnLoadResources 顺序一致):
+ // 现在句柄真正会释放、包内资源(贴图/Spine)会被销毁,
+ // 若先卸载后销毁鱼,残留活鱼会在淡出期间丢失材质花屏
+ CreateFishManager.Instance.ExitRoom();
+ CreateFishManager.Instance.isResources = false;
+ BulletPool.Instance.ClearAll();
+ EffectPool.Instance.ClearAll();
+
SetUnloadProgress(0.2f);
await FishResourcesData.UnLoadFishAssetsData();
SetUnloadProgress(0.4f);
await AudioResourcesData.UnLoadAudioGame();
+ UnLoadBulletClip(); // ⭐ 释放开火音效句柄(引用计数归零)
SetUnloadProgress(0.6f);
await MonsterMoveLine.UnLoadBezier();
@@ -1395,11 +1455,6 @@ public class GameMainPanel_FishBase : GameMainPanel_Base
SetUnloadProgress(0.8f);
await Task.Delay(100);
- CreateFishManager.Instance.ExitRoom();
- CreateFishManager.Instance.isResources = false;
- // ⭐ 清空子弹池 + 特效池(鱼池已在 UnLoadFishAssetsData 内清理)
- BulletPool.Instance.ClearAll();
- EffectPool.Instance.ClearAll();
SetUnloadProgress(0.9f);
// ⭐ 卡在 0.9 等待 socket 返回 LeaveRoomResult
@@ -1862,8 +1917,13 @@ public class GameMainPanel_FishBase : GameMainPanel_Base
/// 大喇叭发送:输入弹幕 → /api/Hall/SendBroadcast 全服广播
/// (与背包大喇叭 OnClickFaSong 流程一致),发送成功后清空输入框并关闭面板。
///
+ /// 大喇叭发送中标志:防止回调返回前连点发送按钮导致多发多扣道具
+ private bool _isSendingDaLaBa;
+
private void OnClickDaLaBaSend()
{
+ // ⭐ 防重入:上次请求回调还没回来时连点直接忽略(多发一次 = 多扣一个大喇叭)
+ if (_isSendingDaLaBa) return;
string msg = tmp_DaLaBaInput?.text?.Trim();
if (string.IsNullOrEmpty(msg))
{
@@ -1871,8 +1931,13 @@ public class GameMainPanel_FishBase : GameMainPanel_Base
return;
}
- APIRequestList.SendBroadcast("广播:" + msg, (result) =>
+ _isSendingDaLaBa = true;
+ // ⭐ 显示格式:"【小*鱼】:内容"(前面加喇叭图标 TMP 标签;名字打码:首尾保留、中间一个 *)
+ var userName = GameManager.Instance.user?.BaseInfo?.userName;
+ if (string.IsNullOrEmpty(userName)) userName = "玩家";
+ APIRequestList.SendBroadcast($"【{MaskBroadcastName(userName)}】:{msg}", (result) =>
{
+ _isSendingDaLaBa = false;
// 发送成功:清空输入框并关闭面板(广播内容会通过 LoginBroadcast 全服弹幕显示)
if (tmp_DaLaBaInput != null) tmp_DaLaBaInput.text = "";
if (obj_DaLaBaPanel != null) obj_DaLaBaPanel.SetActive(false);
@@ -1887,6 +1952,18 @@ public class GameMainPanel_FishBase : GameMainPanel_Base
});
}
+ ///
+ /// 玩家名打码(广播格式):保留首尾字符、中间一个 *("小金鱼"→"小*鱼"、"我是大帅哥"→"我*哥")。
+ /// 与召唤卡提示的 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 949a01173..80daf5afa 100644
--- a/Assets/MyGame/aa/UI/Home/Sub/UIHome_BY_BackPackPanel.cs
+++ b/Assets/MyGame/aa/UI/Home/Sub/UIHome_BY_BackPackPanel.cs
@@ -72,7 +72,11 @@ public class UIHome_BY_BackPackPanel : SubUIBase
if (DaLaBaPanel != null)
DaLaBaPanel.SetActive(false);
if (btn_FaSong != null)
+ {
+ // ⭐ 先清再绑:防止面板重复 Show 叠加监听器(点一次发 N 次 = 多扣 N 个大喇叭)
+ btn_FaSong.onClick.RemoveAllListeners();
btn_FaSong.onClick.AddListener(OnClickFaSong);
+ }
// 数量选择面板(默认隐藏)
if (useObj != null) useObj.SetActive(false);
@@ -147,23 +151,51 @@ public class UIHome_BY_BackPackPanel : SubUIBase
_curUseCountAction = null;
}
+ /// 大喇叭发送中标志:防止回调返回前连点发送按钮导致多发多扣道具
+ private bool _isSendingFaSong;
+
private void OnClickFaSong()
{
- string msg = "广播:"+ tMPText_DaLaBaLabel?.text?.Trim();
- if (string.IsNullOrEmpty(msg))
+ // ⭐ 防重入:上次请求回调还没回来时连点直接忽略
+ if (_isSendingFaSong) return;
+ // ⭐ 先取文本判空再拼前缀(原"广播:"+text 判空永远不成立,空内容也会发送扣道具)
+ string content = tMPText_DaLaBaLabel?.text?.Trim();
+ if (string.IsNullOrEmpty(content))
{
UIManager.Instance.ShowBoardError("请输入广播内容");
return;
}
- APIRequestList.SendBroadcast(msg, (result) =>
+ _isSendingFaSong = true;
+ // ⭐ 显示格式:"【小*鱼】:内容"(前面加喇叭图标 TMP 标签;名字打码与游戏内大喇叭同格式)
+ var userName = GameManager.Instance.user?.BaseInfo?.userName;
+ if (string.IsNullOrEmpty(userName)) userName = "玩家";
+ APIRequestList.SendBroadcast($"【{MaskBroadcastName(userName)}】:{content}", (result) =>
{
- //UIManager.Instance.ShowBoardGongGao($"广播: {msg}");
+ _isSendingFaSong = false;
tMPText_DaLaBaLabel.text = "";
DaLaBaPanel.SetActive(false);
+ // ⭐ 发送成功=服务端已扣大喇叭:拉最新用户数据刷新背包数量
+ APIRequestList.GetUser((user) =>
+ {
+ if (user != null)
+ GameManager.Instance.UpdataUserData(user);
+ });
});
}
+ ///
+ /// 玩家名打码(广播格式):保留首尾字符、中间一个 *("小金鱼"→"小*鱼")。
+ /// 与 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();