diff --git a/Assets/MyGame/Scenes/UIScene.unity b/Assets/MyGame/Scenes/UIScene.unity
index 39543a147..60720ca70 100644
--- a/Assets/MyGame/Scenes/UIScene.unity
+++ b/Assets/MyGame/Scenes/UIScene.unity
@@ -3690,7 +3690,7 @@ GameObject:
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
- m_IsActive: 0
+ m_IsActive: 1
--- !u!114 &1096182886
MonoBehaviour:
m_ObjectHideFlags: 0
@@ -6398,7 +6398,7 @@ MonoBehaviour:
spawnList: []
isCreateFish: 0
isFrozen: 0
- debugSpawnFishNumber: 12032
+ debugSpawnFishNumber: 12029
fishList_All: []
fishList_Small: []
fishList_Boss: []
@@ -6845,6 +6845,11 @@ PrefabInstance:
propertyPath: m_Name
value: PW_Prop_IronFist
objectReference: {fileID: 0}
+ - target: {fileID: 6379684486006968571, guid: 9b8be0fc8702c6546bdb3fce2d1f479f,
+ type: 3}
+ propertyPath: m_IsActive
+ value: 0
+ objectReference: {fileID: 0}
- target: {fileID: 6385227750942468653, guid: 9b8be0fc8702c6546bdb3fce2d1f479f,
type: 3}
propertyPath: m_LocalPosition.x
@@ -7119,6 +7124,79 @@ MonoBehaviour:
m_FillOrigin: 0
m_UseSpriteMesh: 0
m_PixelsPerUnitMultiplier: 1
+--- !u!1001 &4272855452577043047
+PrefabInstance:
+ m_ObjectHideFlags: 0
+ serializedVersion: 2
+ m_Modification:
+ serializedVersion: 3
+ m_TransformParent: {fileID: 0}
+ m_Modifications:
+ - target: {fileID: 3187087628806128005, guid: 97aa30e2785dc6b4a8857b2718fedf53,
+ type: 3}
+ propertyPath: m_LocalPosition.x
+ value: 3.2313976
+ objectReference: {fileID: 0}
+ - target: {fileID: 3187087628806128005, guid: 97aa30e2785dc6b4a8857b2718fedf53,
+ type: 3}
+ propertyPath: m_LocalPosition.y
+ value: 1.60395
+ objectReference: {fileID: 0}
+ - target: {fileID: 3187087628806128005, guid: 97aa30e2785dc6b4a8857b2718fedf53,
+ type: 3}
+ propertyPath: m_LocalPosition.z
+ value: -1.430045
+ objectReference: {fileID: 0}
+ - target: {fileID: 3187087628806128005, guid: 97aa30e2785dc6b4a8857b2718fedf53,
+ type: 3}
+ propertyPath: m_LocalRotation.w
+ value: 1
+ objectReference: {fileID: 0}
+ - target: {fileID: 3187087628806128005, guid: 97aa30e2785dc6b4a8857b2718fedf53,
+ type: 3}
+ propertyPath: m_LocalRotation.x
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 3187087628806128005, guid: 97aa30e2785dc6b4a8857b2718fedf53,
+ type: 3}
+ propertyPath: m_LocalRotation.y
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 3187087628806128005, guid: 97aa30e2785dc6b4a8857b2718fedf53,
+ type: 3}
+ propertyPath: m_LocalRotation.z
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 3187087628806128005, guid: 97aa30e2785dc6b4a8857b2718fedf53,
+ type: 3}
+ propertyPath: m_LocalEulerAnglesHint.x
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 3187087628806128005, guid: 97aa30e2785dc6b4a8857b2718fedf53,
+ type: 3}
+ propertyPath: m_LocalEulerAnglesHint.y
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 3187087628806128005, guid: 97aa30e2785dc6b4a8857b2718fedf53,
+ type: 3}
+ propertyPath: m_LocalEulerAnglesHint.z
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 3363739725897090535, guid: 97aa30e2785dc6b4a8857b2718fedf53,
+ type: 3}
+ propertyPath: m_Name
+ value: GameObject
+ objectReference: {fileID: 0}
+ - target: {fileID: 3363739725897090535, guid: 97aa30e2785dc6b4a8857b2718fedf53,
+ type: 3}
+ propertyPath: m_IsActive
+ value: 0
+ objectReference: {fileID: 0}
+ m_RemovedComponents: []
+ m_RemovedGameObjects: []
+ m_AddedGameObjects: []
+ m_AddedComponents: []
+ m_SourcePrefab: {fileID: 100100000, guid: 97aa30e2785dc6b4a8857b2718fedf53, type: 3}
--- !u!224 &4559688231163668212
RectTransform:
m_ObjectHideFlags: 0
@@ -7918,3 +7996,4 @@ SceneRoots:
- {fileID: 841547336076769388}
- {fileID: 1328183416056466136}
- {fileID: 2518911503280687070}
+ - {fileID: 4272855452577043047}
diff --git a/Assets/MyGame/Scripts/Characters/Monster/MonsterContral.cs b/Assets/MyGame/Scripts/Characters/Monster/MonsterContral.cs
index 24ff11b91..c1371c9c1 100644
--- a/Assets/MyGame/Scripts/Characters/Monster/MonsterContral.cs
+++ b/Assets/MyGame/Scripts/Characters/Monster/MonsterContral.cs
@@ -289,7 +289,12 @@ public class MonsterContral : MonoBehaviour
LoadHitEffect();
baseMmove = isMove;
}
- public async void LoadHitEffect()
+ ///
+ /// 查找受击特效子物体并强制隐藏。
+ /// 原为 async void(无 await 实际同步执行),现改为普通方法;
+ /// Awake 和每次 OnEnable 都会调用,保证池回收后不残留激活状态。
+ ///
+ public void LoadHitEffect()
{
// 查找受击特效子物体并默认隐藏
var hitTra = FindDeepChild(transform, "HitEffect");
@@ -301,6 +306,14 @@ public class MonsterContral : MonoBehaviour
}
public virtual void OnEnable()
{
+ // ⭐ 每次 OnEnable 重新查找并强制隐藏受击特效。
+ // 根因:HurtCoroutine 激活 hurt 后等 0.2s 再关闭,若鱼在这期间被
+ // 击杀回收(GO 停用 → 协程中断),hurt 会残留激活状态;
+ // 而 LoadHitEffect 原来只在 Awake 调用一次(池化对象不重跑 Awake),
+ // 重新生成时不会恢复 → 鱼带着受击特效出场。
+ // 另外池回收的鱼 transform 可能更换子层级,重新查找更稳妥。
+ LoadHitEffect();
+
// ⭐ 用 baseMmove 恢复 isMove:Awake 时记录预制体原始 isMove 状态。
// - 普通鱼预制体 isMove=true → 池回收后恢复 true,正常游动
// (之前被注释导致:冰冻时 FreezeAllFish 设 isMove=false → 鱼回收 →
diff --git a/Assets/MyGame/Scripts/Net/APIResponses/GameConfig_SubClass/BossConfig.cs b/Assets/MyGame/Scripts/Net/APIResponses/GameConfig_SubClass/BossConfig.cs
deleted file mode 100644
index 0e06d275f..000000000
--- a/Assets/MyGame/Scripts/Net/APIResponses/GameConfig_SubClass/BossConfig.cs
+++ /dev/null
@@ -1,588 +0,0 @@
-using System.Collections.Generic;
-using System.Linq;
-
-// ============================================================
-// 文件:BossConfig.cs
-// 职责:Boss 各种死亡爆奖配置(幸运轮盘/小丑扑克/幸运飞碟/破坏球/烈焰风暴/星际巡航/神龙转盘 等)
-// - 服务端下发配置,客户端解析后用 GetResponse() 取随机结果
-// - 已将服务端依赖(GlobalRandom/RandomBossOption/BsonIgnoreExtraElements)
-// 替换为 Unity 客户端兼容实现
-// ============================================================
-
-namespace Assets.MyGame.Scripts.Net.APIResponses.GameConfig_SubClass
-{
- ///
- /// Boss设定配置信息
- ///
- public class BossConfig
- {
- /// 幸运轮盘配置信息
- public List LuckWheel { get; set; } = new List();
-
- /// 小丑扑克
- public LuckPokerConfig LuckPoker { get; set; } = new LuckPokerConfig();
-
- /// 幸运飞碟
- public List LuckFlyDisk { get; set; } = new List();
-
- /// 全屏秒怪
- public BaseBossConfig FullScreen { get; set; } = new BaseBossConfig();
-
- /// 范围秒怪
- public BaseBossConfig Range { get; set; } = new BaseBossConfig();
-
- /// 弹药箱配置
- public AmmunitionBoxConfig AmmunitionBox { get; set; } = new AmmunitionBoxConfig();
-
- /// 星际巡航配置
- public InterstellarCruiseConfig InterstellarCruise { get; set; } = new InterstellarCruiseConfig();
-
- /// 烈焰风暴-死亡配置
- public BossFlameStormConfig FlameStorm { get; set; } = new BossFlameStormConfig();
-
- /// 破坏球-死亡配置
- public BossBombConfig Bomb { get; set; } = new BossBombConfig();
-
- /// 概率击杀
- public List Probability { get; set; } = new List();
-
- /// 神龙转盘
- public List LuckDragon { get; set; } = new List();
-
- ///
- /// 根据权重随机获取一个 Boss 选项
- ///
- public static int GetBossProbabilityConfigResponse(List configParams)
- {
- if (configParams == null || configParams.Count == 0) return 0;
-
- int totalWeight = configParams.Sum(p => p.TriggerRate);
- if (totalWeight <= 0) return 0;
-
- int randomValue = GlobalRandom.Next(0, totalWeight);
- int currentWeightSum = 0;
- foreach (var param in configParams)
- {
- currentWeightSum += param.TriggerRate;
- if (randomValue < currentWeightSum)
- {
- return GlobalRandom.NextInclusive(param.Min, param.Max);
- }
- }
- return 0;
- }
-
- ///
- /// 根据权重随机获取一个死亡次数配置
- ///
- public static CruiseConfigCount GetRandomCountConfigOption(List options)
- {
- if (options == null || !options.Any()) return null;
-
- long totalWeight = options.Sum(o => (long)o.TriggerRate);
- if (totalWeight <= 0) return null;
-
- long randomValue = GlobalRandom.NextInt64(0, totalWeight);
- long currentWeightSum = 0;
- foreach (var option in options)
- {
- currentWeightSum += option.TriggerRate;
- if (randomValue < currentWeightSum)
- {
- return option;
- }
- }
- return options.FirstOrDefault(o => o.TriggerRate > 0);
- }
-
- /// 死亡次数配置参数
- public class CruiseConfigCount
- {
- /// 死亡次数
- public int Count { get; set; }
-
- /// 触发权重
- public int TriggerRate { get; set; } = 0;
-
- /// 击杀权重
- public int KillRate { get; set; } = 0;
- }
-
- /// 神龙转盘
- public class LuckDragonConfig : BaseBossConfig
- {
- /// 外圈配置 下一个配置为-1
- public List OuterConfig { get; set; } = new List();
-
- /// 中圈配置 下一个配置为-1
- public List MiddleConfig { get; set; } = new List();
-
- /// 内圈配置 下一个配置为-1
- public List InnerConfig { get; set; } = new List();
-
- /// 获取结果
- public (List option, int beizhu) GetResponse()
- {
- int beishu = 1;
- var result = new List();
- int outerResult = GetBossProbabilityConfigResponse(OuterConfig);
- result.Add(outerResult);
- if (outerResult == -1)
- {
- int middleResult = GetBossProbabilityConfigResponse(MiddleConfig);
- result.Add(middleResult);
- if (outerResult == -1)
- {
- int innerResult = GetBossProbabilityConfigResponse(InnerConfig);
- result.Add(innerResult);
- beishu = innerResult;
- }
- else
- {
- beishu = middleResult;
- }
- }
- else
- {
- beishu = outerResult;
- }
- UnityEngine.Debug.Log($"[BossConfig] LuckDragon.GetResponse 选项=[{string.Join(",", result)}] 倍数={beishu}");
- return (result, beishu);
- }
- }
-
- /// 破坏球配置参数
- public class BossBombConfig : BaseBossConfig
- {
- /// 死亡次数配置
- public List CountConfig { get; set; } = new List();
-
- /// 第一次死亡配置
- public List OneDeathConfig { get; set; } = new List();
-
- /// 第二次死亡配置
- public List TwoDeathConfig { get; set; } = new List();
-
- /// 获取破坏球配置响应信息
- public (int beishu, int type) GetResponse(string fishId)
- {
- int beishu = 0;
- var countConfig = GetRandomCountConfigOption(CountConfig);
- if (countConfig == null)
- {
- UnityEngine.Debug.Log("[BossConfig] Bomb.GetResponse countConfig为null 返回 (1,1)");
- return (1, 1);
- }
- if (countConfig.Count == 1)
- {
- beishu = GetBossProbabilityConfigResponse(OneDeathConfig);
- UnityEngine.Debug.Log($"[BossConfig] Bomb.GetResponse 死亡次数={countConfig.Count} 倍数={beishu} type=1 fishId={fishId}");
- return (beishu, 1);
- }
- else
- {
- beishu = GetBossProbabilityConfigResponse(TwoDeathConfig);
- UnityEngine.Debug.Log($"[BossConfig] Bomb.GetResponse 死亡次数={countConfig.Count} 倍数={beishu} type=2 fishId={fishId}");
- return (beishu, 2);
- }
- }
- }
-
- /// 烈焰风暴配置
- public class BossFlameStormConfig : BaseBossConfig
- {
- /// 死亡次数配置
- public List CountConfig { get; set; } = new List();
-
- /// 第一次死亡配置
- public List OneDeathConfig { get; set; } = new List();
-
- /// 第二次死亡配置
- public List TwoDeathConfig { get; set; } = new List();
-
- /// 获取烈焰风暴配置响应信息
- public (bool isKill, int beishu, string fishId) GetResponse(string fishId)
- {
- bool isKill = false;
- int beishu = 0;
- int count = 1;
- int sumcount = 1;
-
- if (!fishId.Contains("-")) // 首次击杀
- {
- var countConfig = GetRandomCountConfigOption(CountConfig);
- if (countConfig == null)
- {
- UnityEngine.Debug.Log($"[BossConfig] FlameStorm.GetResponse 首击 countConfig为null 返回 (true,1,{fishId})");
- return (true, 1, fishId);
- }
- count = countConfig.Count;
- beishu = GetBossProbabilityConfigResponse(OneDeathConfig);
- if (count == 1)
- {
- isKill = true;
- UnityEngine.Debug.Log($"[BossConfig] FlameStorm.GetResponse 首击一次死 isKill=true 倍数={beishu} fishId={fishId}-{count}-{sumcount}");
- return (isKill, beishu, $"{fishId}-{count}-{sumcount}");
- }
- else
- {
- sumcount = countConfig.Count;
- }
- }
- else
- {
- var parts = fishId.Split('-');
- count = int.Parse(parts[1]);
- sumcount = int.Parse(parts[2]);
- }
- if (count == 1)
- {
- beishu = GetBossProbabilityConfigResponse(TwoDeathConfig);
- if (sumcount == 2 && count == 1)
- {
- UnityEngine.Debug.Log($"[BossConfig] FlameStorm.GetResponse 二击致死 isKill=true 倍数={beishu} fishId={fishId}-{count + 1}-{sumcount}");
- return (true, beishu, $"{fishId}-{count + 1}-{sumcount}");
- }
- else
- {
- UnityEngine.Debug.Log($"[BossConfig] FlameStorm.GetResponse 二击未死 isKill=false 倍数={beishu} fishId={fishId}-{count + 1}-{sumcount}");
- return (false, beishu, $"{fishId}-{count + 1}-{sumcount}");
- }
- }
- UnityEngine.Debug.Log($"[BossConfig] FlameStorm.GetResponse 三击致死 isKill=true 倍数={beishu} fishId={fishId}-{count + 1}-{sumcount}");
- return (true, beishu, $"{fishId}-{count + 1}-{sumcount}");
- }
- }
-
- /// 星际巡航配置
- public class InterstellarCruiseConfig : BaseBossConfig
- {
- /// 死亡次数配置
- public List CountConfig { get; set; } = new List();
-
- /// 第一次死亡配置
- public List OneDeathConfig { get; set; } = new List();
-
- /// 第二次死亡配置
- public List TwoDeathConfig { get; set; } = new List();
-
- /// 第三次死亡配置
- public List ThreeDeathConfig { get; set; } = new List();
-
- /// 获取星际巡航配置响应信息
- public (bool isKill, int beishu, string fishId) GetResponse(string fishId)
- {
- bool isKill = false;
- int beishu = 0;
- int count = 1;
- int sumcount = 1;
-
- if (!fishId.Contains("-")) // 首次击杀
- {
- var countConfig = GetRandomCountConfigOption(CountConfig);
- if (countConfig == null)
- {
- UnityEngine.Debug.Log($"[BossConfig] Cruise.GetResponse 首击 countConfig为null 返回 (true,1,{fishId})");
- return (true, 1, fishId);
- }
- count = countConfig.Count;
- beishu = GetBossProbabilityConfigResponse(OneDeathConfig);
- if (count == 1)
- {
- isKill = true;
- UnityEngine.Debug.Log($"[BossConfig] Cruise.GetResponse 首击一次死 isKill=true 倍数={beishu} fishId={fishId}-{count}-{sumcount}");
- return (isKill, beishu, $"{fishId}-{count}-{sumcount}");
- }
- else
- {
- sumcount = countConfig.Count;
- }
- }
- else
- {
- var parts = fishId.Split('-');
- count = int.Parse(parts[1]);
- sumcount = int.Parse(parts[2]);
- }
- if (count == 1)
- {
- beishu = GetBossProbabilityConfigResponse(TwoDeathConfig);
- if (sumcount == 2 && count == 1)
- {
- UnityEngine.Debug.Log($"[BossConfig] Cruise.GetResponse 二击致死 isKill=true 倍数={beishu} fishId={fishId}-{count + 1}-{sumcount}");
- return (true, beishu, $"{fishId}-{count + 1}-{sumcount}");
- }
- else
- {
- UnityEngine.Debug.Log($"[BossConfig] Cruise.GetResponse 二击未死 isKill=false 倍数={beishu} fishId={fishId}-{count + 1}-{sumcount}");
- return (false, beishu, $"{fishId}-{count + 1}-{sumcount}");
- }
- }
- beishu = GetBossProbabilityConfigResponse(ThreeDeathConfig);
- UnityEngine.Debug.Log($"[BossConfig] Cruise.GetResponse 三击致死 isKill=true 倍数={beishu} fishId={fishId}-{count + 1}-{sumcount}");
- return (true, beishu, $"{fishId}-{count + 1}-{sumcount}");
- }
- }
-
- /// 概率击杀
- public class BossProbabilityConfig : BaseBossConfig
- {
- public List configParams { get; set; } = new List();
-
- public int GetResponse()
- {
- int beishu = GetBossProbabilityConfigResponse(configParams);
- UnityEngine.Debug.Log($"[BossConfig] Probability.GetResponse 倍数={beishu}");
- return beishu;
- }
- }
-
- /// 弹药箱配置
- public class AmmunitionBoxConfig : BaseBossConfig
- {
- /// 3个一样的
- public List OptionList { get; set; } = new List();
-
- /// 获取随机结果
- public List GetResponse()
- {
- var opt = RandomBossOption.GetRandomBossOption(OptionList);
- if (opt == null)
- {
- UnityEngine.Debug.LogWarning("[BossConfig] AmmunitionBox.GetResponse 选中为null");
- return null;
- }
- UnityEngine.Debug.Log($"[BossConfig] AmmunitionBox.GetResponse 选项Id={opt.OptionId} 倍数/分值={opt.Score}");
- return new List() { opt };
- }
- }
-
- /// 幸运飞碟配置信息
- public class LuckFlyDiskConfig : BaseBossConfig
- {
- /// 内层配置选项列表
- public List InnerOptionList { get; set; } = new List();
-
- /// 外层配置选项列表
- public List OuterOptionList { get; set; } = new List();
-
- /// 获取随机结果
- public List GetResponse()
- {
- List result = new List();
- var opt = RandomBossOption.GetRandomBossOption(InnerOptionList);
- result.Add(opt);
- var opt1 = RandomBossOption.GetRandomBossOption(OuterOptionList);
- result.Add(opt1);
- UnityEngine.Debug.Log($"[BossConfig] FlyDisk.GetResponse 内层={(opt?.OptionId.ToString() ?? "null")} 外层={(opt1?.OptionId.ToString() ?? "null")}");
- return result;
- }
- }
-
- /// 小丑扑克
- public class LuckPokerConfig : BaseBossConfig
- {
- /// 配置选项列表
- public List OptionList { get; set; } = new List();
-
- /// 获取随机结果
- public List GetResponse()
- {
- var opt = RandomBossOption.GetRandomBossOption(OptionList);
- if (opt == null)
- {
- UnityEngine.Debug.LogWarning("[BossConfig] Poker.GetResponse 选中为null");
- return null;
- }
- UnityEngine.Debug.Log($"[BossConfig] Poker.GetResponse 选项Id={opt.OptionId} 倍数/分值={opt.Score}");
- return new List() { opt };
- }
- }
-
- /// 幸运轮盘配置信息
- public class LuckWheelConfig : BaseBossConfig
- {
- /// 配置选项列表
- public List OptionList { get; set; } = new List();
-
- /// 配置项数量配置列表
- public List CountList { get; set; } = new List();
-
- /// 获取随机结果
- public List GetResponse()
- {
- List count = new List();
- List option = new List();
-
- foreach (var item in CountList)
- {
- if (item.TriggerRate >= 100)
- {
- count.Add(item.OptionId);
- continue;
- }
- if (GlobalRandom.Next(100) < item.TriggerRate)
- {
- count.Add(item.OptionId);
- continue;
- }
- break;
- }
- foreach (var item in count)
- {
- var opt = RandomBossOption.GetRandomBossOption(OptionList);
- if (opt == null) continue;
- option.Add(opt);
- }
- UnityEngine.Debug.Log($"[BossConfig] Wheel.GetResponse 触发次数={count.Count} 选项Ids=[{string.Join(",", option.Select(o => o.OptionId))}]");
- return option;
- }
- }
-
- /// Boss配置基类
- public class BaseBossConfig
- {
- /// 鱼编号
- public List FishNumber { get; set; } = new List();
- }
-
- /// boss 概率配置参数
- public class BossProbabilityConfigParam
- {
- public BossProbabilityConfigParam() { }
-
- public BossProbabilityConfigParam(int min, int max, int triggerRate)
- {
- Min = min;
- Max = max;
- TriggerRate = triggerRate;
- }
-
- /// 最小值
- public int Min { get; set; }
-
- /// 最大值
- public int Max { get; set; }
-
- /// 触发权重
- public int TriggerRate { get; set; } = 0;
- }
- }
-
- /// Boss道具掉落配置项
- public class BossDropItemConfig
- {
- /// 道具编号
- public string PropNumber { get; set; } = string.Empty;
-
- /// 道具名称
- public string PropName { get; set; } = string.Empty;
-
- /// 掉落数量
- public int Count { get; set; } = 1;
-
- /// 掉落权重(概率 = Weight / 10000)
- public int Weight { get; set; } = 0;
- }
-
- /// Boss道具掉落配置
- public class BossDropConfig
- {
- /// 不掉落权重(概率 = NoDropWeight / 总权重和)
- public int NoDropWeight { get; set; } = 5000;
-
- /// 掉落道具列表
- public List DropItems { get; set; } = new List();
- }
-
- /// 公共选项配置
- public class BossOptionBaseParam
- {
- public BossOptionBaseParam() { }
-
- public BossOptionBaseParam(double optionId, int triggerRate, double score = 0)
- {
- OptionId = optionId;
- TriggerRate = triggerRate;
- Score = score;
- }
-
- /// 选项编号
- public double OptionId { get; set; }
-
- /// 触发权重
- public int TriggerRate { get; set; } = 0;
-
- /// 分值
- public double Score { get; set; } = 0;
- }
-
- // ============================================================
- // 服务端依赖的 Unity 客户端兼容实现
- // ============================================================
-
- ///
- /// 线程安全的随机数工具(替代服务端的 GlobalRandom)。
- /// 全部走 UnityEngine.Random,保证客户端单线程主逻辑使用。
- ///
- public static class GlobalRandom
- {
- /// [min, max) 的随机整数
- public static int Next(int min, int max)
- {
- return UnityEngine.Random.Range(min, max);
- }
-
- /// [0, max) 的随机整数
- public static int Next(int max)
- {
- return UnityEngine.Random.Range(0, max);
- }
-
- /// [min, max] 闭区间的随机整数(含两端)
- public static int NextInclusive(int min, int max)
- {
- // Range 的整数重载是 [min, max) 上界开,这里补 1 实现闭区间
- if (min > max) return min;
- return UnityEngine.Random.Range(min, max + 1);
- }
-
- /// [min, max) 的随机 long
- public static long NextInt64(long min, long max)
- {
- if (min >= max) return min;
- // UnityEngine.Random 无 long 重载,用 double 映射
- double t = UnityEngine.Random.value;
- return (long)(min + (max - min) * t);
- }
- }
-
- ///
- /// Boss 选项权重随机工具(替代服务端的 RandomBossOption)。
- ///
- public static class RandomBossOption
- {
- ///
- /// 按权重随机选中一个 Boss 选项。
- ///
- public static BossOptionBaseParam GetRandomBossOption(List options)
- {
- if (options == null || options.Count == 0) return null;
-
- long totalWeight = options.Sum(o => (long)o.TriggerRate);
- if (totalWeight <= 0) return null;
-
- long randomValue = GlobalRandom.NextInt64(0, totalWeight);
- long currentWeightSum = 0;
- foreach (var option in options)
- {
- currentWeightSum += option.TriggerRate;
- if (randomValue < currentWeightSum)
- {
- return option;
- }
- }
- return options.FirstOrDefault(o => o.TriggerRate > 0);
- }
- }
-}
diff --git a/Assets/MyGame/Scripts/Net/WebResponses/BossKillParam.cs b/Assets/MyGame/Scripts/Net/WebResponses/BossKillParam.cs
new file mode 100644
index 000000000..b535849cc
--- /dev/null
+++ b/Assets/MyGame/Scripts/Net/WebResponses/BossKillParam.cs
@@ -0,0 +1,288 @@
+using Newtonsoft.Json.Linq;
+using System;
+using System.Collections.Generic;
+
+// ============================================================
+// 文件:BossKillParam.cs
+// 职责:Boss 爆奖(击杀奖励)param 的客户端专用解析模型。
+// 对应《Boss爆浆数据前端对接文档》第三节各 Boss 的 param 结构。
+// 所有数据由服务端 RoomKillNotice.param 直接下发,客户端只负责
+// 解析和渲染,不做任何随机计算(旧 BossConfig 的 GetResponse 已全部删除)。
+//
+// param 结构速查(按 Boss 类型):
+// 1. 幸运轮盘/小丑扑克/弹药箱 → { res:[{optionId,triggerRate,score}], count } 总倍数=score之和
+// 2. 幸运飞碟 → { res:[内层,外层], count:2 } 总倍数=内层×外层
+// 3. 星际巡航/烈焰风暴 → { isKill, beishu, fishId } 多次死亡
+// 4. 破坏球 → { beishu, type } type=2 为最终死亡
+// 5. 神龙转盘 → { res:{ option:[...], beizhu } } beizhu=最终倍数
+// 6. 概率击杀 → param 直接是整数(倍数)
+// 7. 全屏/范围秒怪 → param = null
+// ============================================================
+
+namespace Assets.MyGame.Scripts.Net.WebResponses
+{
+ /// Boss 爆奖 param 类型(由 BossKillParamParser.DetectType 判定)
+ public enum BossKillParamType
+ {
+ /// 无 param(普通鱼 / 全屏秒怪 / 范围秒怪)
+ None = 0,
+
+ /// 选项数组类:幸运轮盘 / 小丑扑克 / 幸运飞碟 / 弹药箱(res 是数组)
+ Options = 1,
+
+ /// 多次死亡:星际巡航 / 烈焰风暴(含 isKill + fishId)
+ MultiDeath = 2,
+
+ /// 破坏球(含 type,无 isKill)
+ Bomb = 3,
+
+ /// 神龙转盘(res 是对象,含 option 数组)
+ Dragon = 4,
+
+ /// 概率击杀(param 直接是整数倍数)
+ Probability = 5,
+ }
+
+ ///
+ /// 选项数组项:幸运轮盘/小丑扑克/幸运飞碟/弹药箱的 res 数组元素。
+ /// JSON: { "optionId": 2, "triggerRate": 30, "score": 3 }
+ ///
+ [Serializable]
+ public class BossKillOption
+ {
+ /// 选项编号(转盘位置/扑克牌编号/飞碟内外层索引)
+ public double optionId;
+
+ /// 触发权重(客户端一般用不到,仅透传)
+ public int triggerRate;
+
+ /// 该项倍数/分值
+ public double score;
+
+ public BossKillOption() { }
+
+ public BossKillOption(double optionId, int triggerRate, double score = 0)
+ {
+ this.optionId = optionId;
+ this.triggerRate = triggerRate;
+ this.score = score;
+ }
+ }
+
+ ///
+ /// 选项数组类 param:幸运轮盘/小丑扑克/幸运飞碟/弹药箱。
+ /// JSON: { "res": [...], "count": N }
+ ///
+ [Serializable]
+ public class BossOptionsParam
+ {
+ /// 选中的选项数组(长度=转动/抽取次数;飞碟固定2:res[0]=内层 res[1]=外层)
+ public List res = new List();
+
+ /// 选项个数(= res.Length)
+ public int count;
+ }
+
+ ///
+ /// 多次死亡 param:星际巡航(最多3次)/ 烈焰风暴(最多2次)。
+ /// JSON: { "isKill": true, "beishu": 155, "fishId": "13009-3-3" }
+ ///
+ [Serializable]
+ public class BossMultiDeathParam
+ {
+ /// true=最终击杀(鱼死亡爆炸);false=未死(鱼复活继续打)
+ public bool isKill;
+
+ /// 本次奖励倍数
+ public int beishu;
+
+ /// 鱼ID,格式:原ID-总次数-当前次数(如 13009-3-2)
+ public string fishId = "";
+
+ /// 从 fishId 解析总死亡次数(解析失败返回 0)
+ public int TotalCount
+ {
+ get
+ {
+ var parts = fishId?.Split('-');
+ return parts != null && parts.Length >= 3 && int.TryParse(parts[1], out int v) ? v : 0;
+ }
+ }
+
+ /// 从 fishId 解析当前第几次死亡(解析失败返回 0)
+ public int CurrentCount
+ {
+ get
+ {
+ var parts = fishId?.Split('-');
+ return parts != null && parts.Length >= 3 && int.TryParse(parts[2], out int v) ? v : 0;
+ }
+ }
+ }
+
+ ///
+ /// 破坏球 param。
+ /// JSON: { "beishu": 420, "type": 1 }
+ ///
+ [Serializable]
+ public class BossBombParam
+ {
+ /// 本次奖励倍数
+ public int beishu;
+
+ /// 死亡类型:1=第一次死亡(鱼继续存活),2=第二次死亡(最终死亡,鱼爆炸)
+ public int type;
+
+ /// 是否最终死亡(type==2)
+ public bool IsFinalKill => type >= 2;
+ }
+
+ ///
+ /// 神龙转盘 param。
+ /// JSON: { "res": { "option": [80, 160], "beizhu": 160 } }
+ /// option 数组长度=停靠圈数(1~3):外圈先判定,-1 则继续中圈,再 -1 判定内圈。
+ ///
+ [Serializable]
+ public class BossDragonParam
+ {
+ /// 转盘结果(内层结构)
+ public DragonRes res = new DragonRes();
+
+ [Serializable]
+ public class DragonRes
+ {
+ /// 各圈数值结果(外→中→内,-1 表示未停靠该圈)
+ public List option = new List();
+
+ /// 最终倍数(取最内层已停靠圈的数值)
+ public int beizhu;
+ }
+ }
+
+ // ============================================================
+ // 解析器
+ // ============================================================
+
+ ///
+ /// BossKillNotice.param 解析器(客户端专用,只解析不随机)。
+ /// 用法:
+ /// var type = BossKillParamParser.DetectType(notice.param);
+ /// switch (type) {
+ /// case BossKillParamType.MultiDeath: var p = BossKillParamParser.ParseMultiDeath(notice.param); ...
+ /// }
+ ///
+ public static class BossKillParamParser
+ {
+ ///
+ /// 判定 param 类型(对齐文档第四节 JS 判定逻辑)。
+ ///
+ public static BossKillParamType DetectType(JToken param)
+ {
+ if (param == null || param.Type == JTokenType.Null)
+ return BossKillParamType.None;
+
+ // 整数 = 概率击杀
+ if (param.Type == JTokenType.Integer || param.Type == JTokenType.Float)
+ return BossKillParamType.Probability;
+
+ if (param is JObject obj)
+ {
+ // 多次死亡:isKill + fishId
+ if (obj["isKill"] != null && obj["fishId"] != null)
+ return BossKillParamType.MultiDeath;
+
+ // 破坏球:type
+ if (obj["type"] != null)
+ return BossKillParamType.Bomb;
+
+ // 神龙转盘:res 是对象且含 option
+ if (obj["res"] is JObject resObj && resObj["option"] != null)
+ return BossKillParamType.Dragon;
+
+ // 选项数组类:res 是数组
+ if (obj["res"] is JArray)
+ return BossKillParamType.Options;
+ }
+
+ return BossKillParamType.None;
+ }
+
+ /// 解析选项数组类(幸运轮盘/小丑扑克/幸运飞碟/弹药箱),失败返回空对象
+ public static BossOptionsParam ParseOptions(JToken param)
+ {
+ try
+ {
+ if (param is JObject obj)
+ {
+ var result = obj.ToObject();
+ if (result != null) return result;
+ }
+ }
+ catch (Exception e)
+ {
+ UnityEngine.Debug.LogWarning($"[BossKillParam] ParseOptions 失败: {e.Message}");
+ }
+ return new BossOptionsParam();
+ }
+
+ /// 解析多次死亡(星际巡航/烈焰风暴),失败返回 null
+ public static BossMultiDeathParam ParseMultiDeath(JToken param)
+ {
+ try
+ {
+ if (param is JObject obj)
+ return obj.ToObject();
+ }
+ catch (Exception e)
+ {
+ UnityEngine.Debug.LogWarning($"[BossKillParam] ParseMultiDeath 失败: {e.Message}");
+ }
+ return null;
+ }
+
+ /// 解析破坏球,失败返回 null
+ public static BossBombParam ParseBomb(JToken param)
+ {
+ try
+ {
+ if (param is JObject obj)
+ return obj.ToObject();
+ }
+ catch (Exception e)
+ {
+ UnityEngine.Debug.LogWarning($"[BossKillParam] ParseBomb 失败: {e.Message}");
+ }
+ return null;
+ }
+
+ /// 解析神龙转盘,失败返回 null
+ public static BossDragonParam ParseDragon(JToken param)
+ {
+ try
+ {
+ if (param is JObject obj)
+ return obj.ToObject();
+ }
+ catch (Exception e)
+ {
+ UnityEngine.Debug.LogWarning($"[BossKillParam] ParseDragon 失败: {e.Message}");
+ }
+ return null;
+ }
+
+ /// 解析概率击杀(param 直接是整数倍数),失败返回 0
+ public static int ParseProbability(JToken param)
+ {
+ try
+ {
+ if (param != null && (param.Type == JTokenType.Integer || param.Type == JTokenType.Float))
+ return (int)param.Value();
+ }
+ catch (Exception e)
+ {
+ UnityEngine.Debug.LogWarning($"[BossKillParam] ParseProbability 失败: {e.Message}");
+ }
+ return 0;
+ }
+ }
+}
diff --git a/Assets/MyGame/Scripts/Net/APIResponses/GameConfig_SubClass/BossConfig.cs.meta b/Assets/MyGame/Scripts/Net/WebResponses/BossKillParam.cs.meta
similarity index 83%
rename from Assets/MyGame/Scripts/Net/APIResponses/GameConfig_SubClass/BossConfig.cs.meta
rename to Assets/MyGame/Scripts/Net/WebResponses/BossKillParam.cs.meta
index 37b1ee58c..da7329379 100644
--- a/Assets/MyGame/Scripts/Net/APIResponses/GameConfig_SubClass/BossConfig.cs.meta
+++ b/Assets/MyGame/Scripts/Net/WebResponses/BossKillParam.cs.meta
@@ -1,5 +1,5 @@
fileFormatVersion: 2
-guid: 69ace07c67208384189ccb057cbecba5
+guid: 46b52b22a0770114bbc78dada374f6fe
MonoImporter:
externalObjects: {}
serializedVersion: 2
diff --git a/Assets/MyGame/Scripts/Net/WebResponses/RoomKillNotice.cs b/Assets/MyGame/Scripts/Net/WebResponses/RoomKillNotice.cs
index d167b6913..dd40ed85e 100644
--- a/Assets/MyGame/Scripts/Net/WebResponses/RoomKillNotice.cs
+++ b/Assets/MyGame/Scripts/Net/WebResponses/RoomKillNotice.cs
@@ -38,12 +38,14 @@ namespace Assets.MyGame.Scripts.Net.WebResponses
public long fishScore;
///
- /// Boss 爆奖结果(服务端按 Boss 类型下发不同结构)。
- /// 调用方按鱼类型用 ToObject<T>() 解析为具体结构:
- /// - LuckDragon: 取 option(int 数组)、beishu
- /// - Bomb: 取 beishu、type
- /// - FlameStorm/Cruise: 取 isKill、beishu、fishId
- /// - 选项类(Wheel/Poker/FlyDisk/AmmunitionBox): List<BossOptionBaseParam>
+ /// Boss 爆奖结果(服务端按 Boss 类型下发不同结构,客户端只解析不随机)。
+ /// 用 BossKillParamParser.DetectType(param) 判定类型后按结构解析:
+ /// - Options : ParseOptions → BossOptionsParam(幸运轮盘/小丑扑克/幸运飞碟/弹药箱)
+ /// - MultiDeath : ParseMultiDeath → BossMultiDeathParam(星际巡航/烈焰风暴 isKill/beishu/fishId)
+ /// - Bomb : ParseBomb → BossBombParam(破坏球 beishu/type)
+ /// - Dragon : ParseDragon → BossDragonParam(神龙转盘 res.option/res.beizhu)
+ /// - Probability : ParseProbability → int(概率击杀,param 直接是倍数)
+ /// - None : 普通鱼 / 全屏秒怪 / 范围秒怪
///
public JToken param;
diff --git a/Assets/MyGame/aa/Game/XJMH/Boss/ChaoNengMoHe/ChaoNengMoHeEvent.cs b/Assets/MyGame/aa/Game/XJMH/Boss/ChaoNengMoHe/ChaoNengMoHeEvent.cs
index f44849e83..57421b8bf 100644
--- a/Assets/MyGame/aa/Game/XJMH/Boss/ChaoNengMoHe/ChaoNengMoHeEvent.cs
+++ b/Assets/MyGame/aa/Game/XJMH/Boss/ChaoNengMoHe/ChaoNengMoHeEvent.cs
@@ -1,4 +1,4 @@
-using Assets.MyGame.Scripts.Net.APIResponses.GameConfig_SubClass;
+using Assets.MyGame.Scripts.Net.WebResponses;
using DG.Tweening;
using Newtonsoft.Json.Linq;
using System;
@@ -11,7 +11,7 @@ using UnityEngine.UI;
public class ChaoNengMoHeEvent : BJEventBase
{
/// Boss 死亡时传来的特殊值(服务端 res 数组),与幸运轮一致
- private List _cardParams = new List();
+ private List _cardParams = new List();
/// 倍数列表(Inspector 拖入,8 个)
public List obj_BeiShu = new List();
@@ -73,19 +73,19 @@ public class ChaoNengMoHeEvent : BJEventBase
JToken resToken = rootToken["res"] ?? rootToken;
if (resToken is JArray jarr)
- _cardParams = jarr.ToObject>() ?? new List();
+ _cardParams = jarr.ToObject>() ?? new List();
else if (resToken is JObject jobj)
- _cardParams = new List { jobj.ToObject() };
+ _cardParams = new List { jobj.ToObject() };
else
- _cardParams = new List();
+ _cardParams = new List();
}
catch (Exception e)
{
Debug.LogError($"[ChaoNengMoHe] 解析参数失败:{e.Message}; 原始={obj}");
- _cardParams = new List();
+ _cardParams = new List();
}
- Debug.Log($"[ChaoNengMoHe] 解析到 {_cardParams.Count} 个选项: [{string.Join(", ", _cardParams.Select(p => p.Score))}]");
+ Debug.Log($"[ChaoNengMoHe] 解析到 {_cardParams.Count} 个选项: [{string.Join(", ", _cardParams.Select(p => p.score))}]");
}
/// Timeline 结束触发:无爆奖,直接播放 bjEndUI 并退出
public void TimeLineEnd()
@@ -132,7 +132,7 @@ public class ChaoNengMoHeEvent : BJEventBase
obj_BeiShu[0].transform.parent.gameObject.SetActive(true);
// 如果没有服务端数据,用默认倍数兜底
var sourceScores = _cardParams != null && _cardParams.Count > 0
- ? _cardParams.Select(p => (int)p.Score).ToList()
+ ? _cardParams.Select(p => (int)p.score).ToList()
: defaultBeishu.ToList();
// 随机打乱源数据
diff --git a/Assets/MyGame/aa/Game/XJMH/Boss/XiaoChouPuKe/XiaoChouPuKeEvent.cs b/Assets/MyGame/aa/Game/XJMH/Boss/XiaoChouPuKe/XiaoChouPuKeEvent.cs
index d1d5f80fe..c5e077744 100644
--- a/Assets/MyGame/aa/Game/XJMH/Boss/XiaoChouPuKe/XiaoChouPuKeEvent.cs
+++ b/Assets/MyGame/aa/Game/XJMH/Boss/XiaoChouPuKe/XiaoChouPuKeEvent.cs
@@ -1,4 +1,4 @@
-using Assets.MyGame.Scripts.Net.APIResponses.GameConfig_SubClass;
+using Assets.MyGame.Scripts.Net.WebResponses;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
@@ -57,7 +57,7 @@ public class XiaoChouPuKeEvent : BJEventBase
private const int AWARD_SANPAI = 6; // 散排
/// 服务端下发的奖项数据(通常只有 1 个元素)
- private List _cardParams = new List();
+ private List _cardParams = new List();
/// 本次奖项类型(1-6)
private int _awardType = AWARD_SANPAI;
@@ -105,7 +105,7 @@ public class XiaoChouPuKeEvent : BJEventBase
// ============================================================
///
- /// 把 obj(RoomKillNotice.param)解析为 List<BossOptionBaseParam>。
+ /// 把 obj(RoomKillNotice.param)解析为 List<BossKillOption>。
/// 服务端格式:{ "res": [{optionId, triggerRate, score}], "count": 1 }
///
private void ParseCardParams()
@@ -113,7 +113,7 @@ public class XiaoChouPuKeEvent : BJEventBase
if (obj == null)
{
Debug.LogWarning("[XiaoChouPuKe] param 为 null,使用默认散排");
- _cardParams = new List();
+ _cardParams = new List();
return;
}
@@ -123,23 +123,23 @@ public class XiaoChouPuKeEvent : BJEventBase
JToken resToken = rootToken["res"] ?? rootToken;
if (resToken is JArray)
- _cardParams = resToken.ToObject>() ?? new List();
+ _cardParams = resToken.ToObject>() ?? new List();
else if (resToken is JObject jobj)
- _cardParams = new List { jobj.ToObject() };
+ _cardParams = new List { jobj.ToObject() };
else
- _cardParams = new List();
+ _cardParams = new List();
}
catch (Exception e)
{
Debug.LogError($"[XiaoChouPuKe] 解析卡牌数据失败:{e.Message};原始={obj}");
- _cardParams = new List();
+ _cardParams = new List();
}
// 读取奖项类型和倍数
if (_cardParams.Count > 0 && _cardParams[0] != null)
{
- _awardType = Mathf.Clamp((int)_cardParams[0].OptionId, 1, 6);
- _awardScore = (int)_cardParams[0].Score;
+ _awardType = Mathf.Clamp((int)_cardParams[0].optionId, 1, 6);
+ _awardScore = (int)_cardParams[0].score;
}
else
{
diff --git a/Assets/MyGame/aa/Game/XJMH/Boss/XingJiXunHang/XingJiXunHang_BOSS.cs b/Assets/MyGame/aa/Game/XJMH/Boss/XingJiXunHang/XingJiXunHang_BOSS.cs
index f2a3b30ab..0128b5574 100644
--- a/Assets/MyGame/aa/Game/XJMH/Boss/XingJiXunHang/XingJiXunHang_BOSS.cs
+++ b/Assets/MyGame/aa/Game/XJMH/Boss/XingJiXunHang/XingJiXunHang_BOSS.cs
@@ -1,4 +1,3 @@
-using Assets.MyGame.Scripts.Net.APIResponses.GameConfig_SubClass;
using Assets.MyGame.Scripts.Net.WebResponses;
using Newtonsoft.Json.Linq;
using System;
@@ -8,19 +7,16 @@ using UnityEngine;
///
/// 星际巡航 Boss(继承 MonsterControl_BossBase)。
///
-/// 支持多次死亡(1~3次,服务端配置决定):
+/// 支持多次死亡(1~3次,服务端决定):
/// 非最终死亡 → 显示 BJEndUI(倍数+分数),Boss 不消失,等待下次击杀
-/// 最终死亡 → 触发完整爆奖流程 + 道具武器掉落
+/// 最终死亡 → isKill=true 直接删除 Boss + 触发完整爆奖流程 + 道具武器掉落
///
/// 死亡判定来源:
-/// 方式1(优先):从 RoomKillNotice.param 解析 isKill/beishu/fishId(服务端下发)
-/// 方式2(兜底):调用 InterstellarCruiseConfig.GetResponse(fishId) 客户端计算
+/// 方式1(优先):BossKillParamParser.ParseMultiDeath 解析 RoomKillNotice.param
+/// { "isKill": bool, "beishu": int, "fishId": "原ID-总次数-当前次数" }
+/// 方式2(兜底):param 缺失时按 maxDeathCount 简单判定死亡次数
///
-/// fishId 格式:原ID-总次数-当前次数(由 InterstellarCruiseConfig.GetResponse 管理)
-/// 例:4000-3-2 表示总共3次,当前第2次
-///
-/// ⭐ 非最终死亡时不从鱼列表删除 Boss,等最终死亡爆奖流程结束后,
-/// 由 XingJiXunHangEvent.die() 通知 Boss 回收。
+/// ⭐ 非最终死亡时不从鱼列表删除 Boss;最终死亡时下一帧直接 Id_DieFish_NotFX 删除。
///
public class XingJiXunHang_BOSS : MonsterControl_BossBase
{
@@ -34,15 +30,12 @@ public class XingJiXunHang_BOSS : MonsterControl_BossBase
public float resumeMoveDelay = 2f;
[Header("星际巡航 - 服务端参数解析")]
- [Tooltip("是否从 param 解析 isKill(关闭则用客户端配置计算)")]
+ [Tooltip("是否从 param 解析 isKill(关闭则用 maxDeathCount 客户端兜底判定)")]
public bool useServerParam = true;
[Header("星际巡航 - 客户端兜底配置")]
- [Tooltip("星际巡航死亡配置(兜底用,服务端未下发 param 时使用)。留空则按 maxDeathCount 简单判定。")]
- public BossConfig.InterstellarCruiseConfig cruiseConfig;
-
- [Tooltip("最大死亡次数(cruiseConfig 为空时生效,默认2次)")]
- public int maxDeathCount = 2;
+ [Tooltip("最大死亡次数(param 缺失时生效,默认3次)")]
+ public int maxDeathCount = 3;
// ==================== 运行时状态 ====================
@@ -101,16 +94,28 @@ public class XingJiXunHang_BOSS : MonsterControl_BossBase
if (useServerParam && obj?.param != null)
{
- // 方式1:从服务端 param 解析
+ // 方式1:BossKillParamParser 解析服务端 param
Debug.Log($"[XingJiXunHang] DieFish 第{_deathCount}次 param原文: {obj.param.ToString(Newtonsoft.Json.Formatting.None)}");
- (isKill, beishu) = ParseServerParam(obj.param);
- Debug.Log($"[XingJiXunHang] DieFish 第{_deathCount}次(服务端) isKill={isKill} beishu={beishu} guid={guid}");
+ var p = BossKillParamParser.ParseMultiDeath(obj.param);
+ if (p != null)
+ {
+ isKill = p.isKill;
+ beishu = p.beishu;
+ if (!string.IsNullOrEmpty(p.fishId))
+ _cruiseFishId = p.fishId;
+ }
+ else
+ {
+ Debug.LogWarning("[XingJiXunHang] param 解析失败,走客户端兜底");
+ (isKill, beishu) = GetClientFallback(obj);
+ }
+ Debug.Log($"[XingJiXunHang] DieFish 第{_deathCount}次(服务端) isKill={isKill} beishu={beishu} fishId={_cruiseFishId} guid={guid}");
}
else
{
- // 方式2:调用客户端配置计算
- (isKill, beishu, _cruiseFishId) = GetClientConfigResponse(obj);
- Debug.Log($"[XingJiXunHang] DieFish 第{_deathCount}次(客户端) isKill={isKill} beishu={beishu} fishId={_cruiseFishId}");
+ // 方式2:客户端兜底(param 缺失时按 maxDeathCount 判定)
+ (isKill, beishu) = GetClientFallback(obj);
+ Debug.Log($"[XingJiXunHang] DieFish 第{_deathCount}次(客户端兜底) isKill={isKill} beishu={beishu}");
}
if (!isKill)
@@ -329,58 +334,15 @@ public class XingJiXunHang_BOSS : MonsterControl_BossBase
// ==================== 参数解析 ====================
///
- /// 从服务端 param 解析 isKill 和 beishu。
- /// param 结构(JToken):
- /// { "isKill": true/false, "beishu": 100, "fishId": "4000-3-2", "weaponID": 6 }
+ /// 客户端兜底判定(param 缺失或解析失败时使用):
+ /// 按 maxDeathCount 简单判定死亡次数(类似 LieYanFengBao 模式)。
///
- private (bool isKill, int beishu) ParseServerParam(JToken param)
+ private (bool isKill, int beishu) GetClientFallback(RoomKillNotice obj)
{
- bool isKill = true;
- int beishu = 1;
-
- try
- {
- JToken root = param is JObject jo ? jo : JObject.Parse(param.ToString());
-
- isKill = root["isKill"]?.Value() ?? true;
- beishu = root["beishu"]?.Value() ?? 1;
-
- // 同步更新 _cruiseFishId(如果服务端返回了)
- var fishIdToken = root["fishId"];
- if (fishIdToken != null)
- _cruiseFishId = fishIdToken.Value();
- }
- catch (Exception e)
- {
- Debug.LogWarning($"[XingJiXunHang] 解析 param 失败: {e.Message},使用默认值 isKill=true beishu=1");
- }
-
- return (isKill, beishu);
- }
-
- ///
- /// 调用客户端 InterstellarCruiseConfig.GetResponse 计算死亡结果。
- /// 用于服务端未下发 param 时的兜底方案。
- ///
- private (bool isKill, int beishu, string fishId) GetClientConfigResponse(RoomKillNotice obj)
- {
- // 方式A:使用 Inspector 配置的 InterstellarCruiseConfig
- if (cruiseConfig != null)
- {
- string currentFishId = string.IsNullOrEmpty(_cruiseFishId)
- ? fishTypeID.ToString()
- : _cruiseFishId;
-
- var result = cruiseConfig.GetResponse(currentFishId);
- _cruiseFishId = result.fishId;
- return result;
- }
-
- // 方式B:cruiseConfig 为空,用简单死亡次数判定(类似 LieYanFengBao 模式)
bool kill = _deathCount >= maxDeathCount;
int bs = obj?.beishu > 0 ? (int)obj.beishu : 1;
- Debug.Log($"[XingJiXunHang] 客户端兜底(无配置): 第{_deathCount}次/{maxDeathCount}次 isKill={kill} beishu={bs}");
- return (kill, bs, _cruiseFishId);
+ Debug.Log($"[XingJiXunHang] 客户端兜底: 第{_deathCount}次/{maxDeathCount}次 isKill={kill} beishu={bs}");
+ return (kill, bs);
}
// ==================== 清理 ====================
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 2a8622be5..6ef70a7c5 100644
--- a/Assets/MyGame/aa/Game/XJMH/Boss/XingYunFeiDie/RotatePan_XJMH.cs
+++ b/Assets/MyGame/aa/Game/XJMH/Boss/XingYunFeiDie/RotatePan_XJMH.cs
@@ -1,4 +1,4 @@
-using Assets.MyGame.Scripts.Net.APIResponses.GameConfig_SubClass;
+using Assets.MyGame.Scripts.Net.WebResponses;
using DG.Tweening;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
@@ -55,9 +55,9 @@ public class RotatePan_XJMH : BJEventBase
private Tween _neiTween;
/// 内层选项(服务端下发,OptionId=索引)
- private BossOptionBaseParam _innerOpt;
+ private BossKillOption _innerOpt;
/// 外层选项(服务端下发,OptionId=索引)
- private BossOptionBaseParam _outerOpt;
+ private BossKillOption _outerOpt;
/// 内圈实际倍数(从数组取)
private float _innerBeishu = 10f;
@@ -85,7 +85,7 @@ public class RotatePan_XJMH : BJEventBase
///
private void ParseOptions()
{
- List opts = null;
+ List opts = null;
if (obj != null)
{
@@ -95,9 +95,9 @@ public class RotatePan_XJMH : BJEventBase
JToken resToken = rootToken["res"] ?? rootToken;
if (resToken is JArray)
- opts = resToken.ToObject>();
+ opts = resToken.ToObject>();
else if (resToken is JObject jobj)
- opts = new List { jobj.ToObject() };
+ opts = new List { jobj.ToObject() };
}
catch (Exception e)
{
@@ -108,22 +108,22 @@ public class RotatePan_XJMH : BJEventBase
if (opts == null || opts.Count == 0)
{
Debug.LogWarning("[XingYunFeiDie] 选项数据为空,使用默认索引 0");
- _innerOpt = new BossOptionBaseParam(0, 0, 1);
- _outerOpt = new BossOptionBaseParam(0, 0, 1);
+ _innerOpt = new BossKillOption(0, 0, 1);
+ _outerOpt = new BossKillOption(0, 0, 1);
}
else
{
- _innerOpt = opts.Count > 0 ? opts[0] : new BossOptionBaseParam(0, 0, 1);
- _outerOpt = opts.Count > 1 ? opts[1] : new BossOptionBaseParam(0, 0, 1);
+ _innerOpt = opts.Count > 0 ? opts[0] : new BossKillOption(0, 0, 1);
+ _outerOpt = opts.Count > 1 ? opts[1] : new BossKillOption(0, 0, 1);
}
// 从数组按 OptionId 索引取实际倍数
- _innerBeishu = GetBeishuFromArray(innerBeishus, (int)_innerOpt.OptionId, 10f);
- _outerBeishu = GetBeishuFromArray(outerBeishus, (int)_outerOpt.OptionId, 1f);
+ _innerBeishu = GetBeishuFromArray(innerBeishus, (int)_innerOpt.optionId, 10f);
+ _outerBeishu = GetBeishuFromArray(outerBeishus, (int)_outerOpt.optionId, 1f);
_totalBeishu = _innerBeishu * _outerBeishu;
- Debug.Log($"[XingYunFeiDie] 内层 OptionId={_innerOpt.OptionId} 倍数={_innerBeishu}");
- Debug.Log($"[XingYunFeiDie] 外层 OptionId={_outerOpt.OptionId} 倍数={_outerBeishu}");
+ Debug.Log($"[XingYunFeiDie] 内层 OptionId={_innerOpt.optionId} 倍数={_innerBeishu}");
+ Debug.Log($"[XingYunFeiDie] 外层 OptionId={_outerOpt.optionId} 倍数={_outerBeishu}");
Debug.Log($"[XingYunFeiDie] 总倍数={_totalBeishu}");
}
@@ -159,17 +159,17 @@ public class RotatePan_XJMH : BJEventBase
int innerCount = innerBeishus != null ? innerBeishus.Length : 1;
Debug.Log($"[XingYunFeiDie] 数组长度: outerBeishus(外圈7项)={outerCount} innerBeishus(内圈10项)={innerCount}");
- Debug.Log($"[XingYunFeiDie] 服务端OptionId: 外圈={_outerOpt.OptionId} 内圈={_innerOpt.OptionId}");
+ Debug.Log($"[XingYunFeiDie] 服务端OptionId: 外圈={_outerOpt.optionId} 内圈={_innerOpt.optionId}");
// 外圈:必须精确停在顶点(中心角度),不随机
- float waiTargetAngle = OptionIdToAngle((int)_outerOpt.OptionId, outerCount);
- Debug.Log($"[XingYunFeiDie] 外圈目标角度: OptionId={_outerOpt.OptionId} count={outerCount} → {waiTargetAngle}°");
+ float waiTargetAngle = OptionIdToAngle((int)_outerOpt.optionId, outerCount);
+ Debug.Log($"[XingYunFeiDie] 外圈目标角度: OptionId={_outerOpt.optionId} count={outerCount} → {waiTargetAngle}°");
// 内圈:可在选项范围内随机偏移(中心角度 ± 半角)
- float neiCenterAngle = OptionIdToAngle((int)_innerOpt.OptionId, innerCount);
+ float neiCenterAngle = OptionIdToAngle((int)_innerOpt.optionId, innerCount);
float neiHalfAngle = (360f / innerCount) / 2f;
float neiTargetAngle = neiCenterAngle + Random.Range(-neiHalfAngle, neiHalfAngle);
- Debug.Log($"[XingYunFeiDie] 内圈目标角度: OptionId={_innerOpt.OptionId} count={innerCount} 中心={neiCenterAngle}° 随机后={neiTargetAngle}°");
+ Debug.Log($"[XingYunFeiDie] 内圈目标角度: OptionId={_innerOpt.optionId} count={innerCount} 中心={neiCenterAngle}° 随机后={neiTargetAngle}°");
// 先转内圈
bool neiDone = false;
diff --git a/Assets/MyGame/aa/Game/XJMH/Boss/XingYunLun/XingYunLunEvent.cs b/Assets/MyGame/aa/Game/XJMH/Boss/XingYunLun/XingYunLunEvent.cs
index a09548f59..38920c7e9 100644
--- a/Assets/MyGame/aa/Game/XJMH/Boss/XingYunLun/XingYunLunEvent.cs
+++ b/Assets/MyGame/aa/Game/XJMH/Boss/XingYunLun/XingYunLunEvent.cs
@@ -1,4 +1,4 @@
-using Assets.MyGame.Scripts.Net.APIResponses.GameConfig_SubClass;
+using Assets.MyGame.Scripts.Net.WebResponses;
using DG.Tweening;
using Newtonsoft.Json.Linq;
using System;
@@ -50,7 +50,7 @@ public class XingYunLunEvent : BJEventBase
private List _items = new List();
/// 服务端下发的选项列表(用于映射格子)
- private List _cardParams = new List();
+ private List _cardParams = new List();
/// 每个 item 的目标格子索引
private List _targetSlots = new List();
@@ -111,20 +111,20 @@ public class XingYunLunEvent : BJEventBase
JToken resToken = rootToken["res"] ?? rootToken;
if (resToken is JArray jarr)
- _cardParams = jarr.ToObject>() ?? new List();
+ _cardParams = jarr.ToObject>() ?? new List();
else if (resToken is JObject jobj)
- _cardParams = new List { jobj.ToObject() };
+ _cardParams = new List { jobj.ToObject() };
else
- _cardParams = new List();
+ _cardParams = new List();
}
catch (Exception e)
{
Debug.LogError($"[XingYunLun] 解析参数失败:{e.Message};原始={obj}");
- _cardParams = new List();
+ _cardParams = new List();
}
Debug.Log($"[XingYunLun] 解析到 {_cardParams.Count} 个选项: " +
- $"[{string.Join(", ", _cardParams.Select(p => p.Score))}]");
+ $"[{string.Join(", ", _cardParams.Select(p => p.score))}]");
}
///
@@ -139,7 +139,7 @@ public class XingYunLunEvent : BJEventBase
{
if (_cardParams[i] != null)
{
- int score = (int)_cardParams[i].Score;
+ int score = (int)_cardParams[i].score;
int slotIdx = FindSlotByScore(score);
_targetSlots.Add(slotIdx);
Debug.Log($"[XingYunLun] item[{i}] score={score} → slot={slotIdx}");