refactor 6:
- CombatInfoFormUseCase.cs 改成回调驱动:
- 不再直接读 GameEntry.CombatNode
- 由 CombatLoadSession.cs 在打开 CombatInfoForm 前注入 modelProvider 和 TryEndCombat 回调
- CombatSelectFormUseCase.cs 的默认 coin provider 改成返回 0,不再偷偷 fallback 到 GameEntry.CombatNode
- CombatFinishFormUseCase.cs 去掉了未准备 summary 时对 GameEntry.CombatNode 的兜底读取
- MapData.cs 进一步补充了战斗初始快照:
- InventorySnapshot
- ParticipantTowerSnapshot
- CombatLoadingState.cs 现在会把这些背包/参战塔快照也一起打进 MapData
- MapEntity.cs 配置建塔面板时不再直接读 PlayerInventory,改为用 MapData 里的快照
This commit is contained in:
parent
ca7b2f2dca
commit
ab7c7172b8
|
|
@ -45,7 +45,7 @@ namespace GeometryTD.CustomComponent
|
||||||
_currentMap = null;
|
_currentMap = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool StartLoading(DRLevel level, MapData mapData, out string errorMessage)
|
public bool StartLoading(DRLevel level, MapData mapData, CombatScheduler scheduler, out string errorMessage)
|
||||||
{
|
{
|
||||||
errorMessage = null;
|
errorMessage = null;
|
||||||
if (_entity == null)
|
if (_entity == null)
|
||||||
|
|
@ -59,7 +59,7 @@ namespace GeometryTD.CustomComponent
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!TryOpenCombatInfoForm(out errorMessage))
|
if (!TryOpenCombatInfoForm(scheduler, out errorMessage))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -249,7 +249,7 @@ namespace GeometryTD.CustomComponent
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool TryOpenCombatInfoForm(out string errorMessage)
|
private bool TryOpenCombatInfoForm(CombatScheduler scheduler, out string errorMessage)
|
||||||
{
|
{
|
||||||
errorMessage = null;
|
errorMessage = null;
|
||||||
if (_combatInfoFormUseCase == null)
|
if (_combatInfoFormUseCase == null)
|
||||||
|
|
@ -258,6 +258,10 @@ namespace GeometryTD.CustomComponent
|
||||||
GameEntry.UIRouter.BindUIUseCase(UIFormType.CombatInfoForm, _combatInfoFormUseCase);
|
GameEntry.UIRouter.BindUIUseCase(UIFormType.CombatInfoForm, _combatInfoFormUseCase);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_combatInfoFormUseCase.Configure(
|
||||||
|
() => BuildCombatInfoFormRawData(scheduler),
|
||||||
|
() => scheduler != null && scheduler.CanEndCombat && scheduler.TryEndCombatByPlayer());
|
||||||
|
|
||||||
int? serialId = GameEntry.UIRouter.OpenUI(UIFormType.CombatInfoForm);
|
int? serialId = GameEntry.UIRouter.OpenUI(UIFormType.CombatInfoForm);
|
||||||
if (!serialId.HasValue)
|
if (!serialId.HasValue)
|
||||||
{
|
{
|
||||||
|
|
@ -270,6 +274,28 @@ namespace GeometryTD.CustomComponent
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static CombatInfoFormRawData BuildCombatInfoFormRawData(CombatScheduler scheduler)
|
||||||
|
{
|
||||||
|
if (scheduler == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
DRLevel level = scheduler.CurrentLevel;
|
||||||
|
LevelThemeType themeType = level != null ? level.LevelThemeType : LevelThemeType.None;
|
||||||
|
int levelId = level != null ? level.Id : 0;
|
||||||
|
int baseHpMax = level != null ? Mathf.Max(0, level.BaseHp) : 0;
|
||||||
|
return CombatInfoFormUseCase.BuildRawData(
|
||||||
|
themeType,
|
||||||
|
levelId,
|
||||||
|
scheduler.DisplayPhaseIndex,
|
||||||
|
scheduler.PhaseCount,
|
||||||
|
scheduler.CurrentCoin,
|
||||||
|
scheduler.CurrentBaseHp,
|
||||||
|
baseHpMax,
|
||||||
|
scheduler.CanEndCombat);
|
||||||
|
}
|
||||||
|
|
||||||
private void CloseCombatInfoForm()
|
private void CloseCombatInfoForm()
|
||||||
{
|
{
|
||||||
GameEntry.UIRouter.CloseUI(UIFormType.CombatInfoForm);
|
GameEntry.UIRouter.CloseUI(UIFormType.CombatInfoForm);
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using GeometryTD.Definition;
|
using GeometryTD.Definition;
|
||||||
using GeometryTD.Entity.EntityData;
|
using GeometryTD.Entity.EntityData;
|
||||||
|
using GeometryTD.UI;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
namespace GeometryTD.CustomComponent
|
namespace GeometryTD.CustomComponent
|
||||||
|
|
@ -22,7 +23,7 @@ namespace GeometryTD.CustomComponent
|
||||||
}
|
}
|
||||||
|
|
||||||
MapData mapData = BuildMapData();
|
MapData mapData = BuildMapData();
|
||||||
if (!Scheduler._loadSession.StartLoading(Scheduler._currentLevel, mapData, out string errorMessage))
|
if (!Scheduler._loadSession.StartLoading(Scheduler._currentLevel, mapData, Scheduler, out string errorMessage))
|
||||||
{
|
{
|
||||||
Scheduler.EnterFailureFallback($"Combat loading failed. {errorMessage}");
|
Scheduler.EnterFailureFallback($"Combat loading failed. {errorMessage}");
|
||||||
}
|
}
|
||||||
|
|
@ -60,6 +61,12 @@ namespace GeometryTD.CustomComponent
|
||||||
position: Vector3.zero,
|
position: Vector3.zero,
|
||||||
initialCoin: Scheduler._combatInRunResourceManager.CurrentCoin,
|
initialCoin: Scheduler._combatInRunResourceManager.CurrentCoin,
|
||||||
buildTowerStatsSnapshot: buildTowerStatsSnapshot,
|
buildTowerStatsSnapshot: buildTowerStatsSnapshot,
|
||||||
|
inventorySnapshot: GameEntry.PlayerInventory != null
|
||||||
|
? GameEntry.PlayerInventory.GetInventorySnapshot()
|
||||||
|
: null,
|
||||||
|
participantTowerSnapshot: GameEntry.PlayerInventory != null
|
||||||
|
? GameEntry.PlayerInventory.GetParticipantTowerSnapshot()
|
||||||
|
: null,
|
||||||
tryConsumeCoin: Scheduler.TryConsumeCoin,
|
tryConsumeCoin: Scheduler.TryConsumeCoin,
|
||||||
addCoin: Scheduler.AddCoin);
|
addCoin: Scheduler.AddCoin);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,8 @@ namespace GeometryTD.Entity.EntityData
|
||||||
[SerializeField] private int _levelId = 0;
|
[SerializeField] private int _levelId = 0;
|
||||||
[SerializeField] private int _initialCoin = 0;
|
[SerializeField] private int _initialCoin = 0;
|
||||||
[SerializeField] private TowerStatsData[] _buildTowerStatsSnapshot = Array.Empty<TowerStatsData>();
|
[SerializeField] private TowerStatsData[] _buildTowerStatsSnapshot = Array.Empty<TowerStatsData>();
|
||||||
|
[SerializeField] private BackpackInventoryData _inventorySnapshot;
|
||||||
|
[SerializeField] private TowerItemData[] _participantTowerSnapshot = Array.Empty<TowerItemData>();
|
||||||
|
|
||||||
[NonSerialized] private Func<int, bool> _tryConsumeCoin;
|
[NonSerialized] private Func<int, bool> _tryConsumeCoin;
|
||||||
[NonSerialized] private Action<int> _addCoin;
|
[NonSerialized] private Action<int> _addCoin;
|
||||||
|
|
@ -33,6 +35,8 @@ namespace GeometryTD.Entity.EntityData
|
||||||
Vector3 position,
|
Vector3 position,
|
||||||
int initialCoin,
|
int initialCoin,
|
||||||
IReadOnlyList<TowerStatsData> buildTowerStatsSnapshot,
|
IReadOnlyList<TowerStatsData> buildTowerStatsSnapshot,
|
||||||
|
BackpackInventoryData inventorySnapshot,
|
||||||
|
IReadOnlyList<TowerItemData> participantTowerSnapshot,
|
||||||
Func<int, bool> tryConsumeCoin,
|
Func<int, bool> tryConsumeCoin,
|
||||||
Action<int> addCoin) : base(entityId, typeId)
|
Action<int> addCoin) : base(entityId, typeId)
|
||||||
{
|
{
|
||||||
|
|
@ -40,6 +44,10 @@ namespace GeometryTD.Entity.EntityData
|
||||||
Position = position;
|
Position = position;
|
||||||
_initialCoin = Mathf.Max(0, initialCoin);
|
_initialCoin = Mathf.Max(0, initialCoin);
|
||||||
SetBuildTowerStatsSnapshot(buildTowerStatsSnapshot);
|
SetBuildTowerStatsSnapshot(buildTowerStatsSnapshot);
|
||||||
|
_inventorySnapshot = inventorySnapshot != null
|
||||||
|
? InventoryCloneUtility.CloneInventory(inventorySnapshot)
|
||||||
|
: null;
|
||||||
|
SetParticipantTowerSnapshot(participantTowerSnapshot);
|
||||||
_tryConsumeCoin = tryConsumeCoin;
|
_tryConsumeCoin = tryConsumeCoin;
|
||||||
_addCoin = addCoin;
|
_addCoin = addCoin;
|
||||||
}
|
}
|
||||||
|
|
@ -57,6 +65,10 @@ namespace GeometryTD.Entity.EntityData
|
||||||
}
|
}
|
||||||
|
|
||||||
public int CurrentBuildTowerCount => _buildTowerStatsSnapshot != null ? _buildTowerStatsSnapshot.Length : 0;
|
public int CurrentBuildTowerCount => _buildTowerStatsSnapshot != null ? _buildTowerStatsSnapshot.Length : 0;
|
||||||
|
public BackpackInventoryData InventorySnapshot => _inventorySnapshot != null
|
||||||
|
? InventoryCloneUtility.CloneInventory(_inventorySnapshot)
|
||||||
|
: null;
|
||||||
|
public IReadOnlyList<TowerItemData> ParticipantTowerSnapshot => _participantTowerSnapshot;
|
||||||
|
|
||||||
public void BindCombatCallbacks(Func<int, bool> tryConsumeCoin, Action<int> addCoin)
|
public void BindCombatCallbacks(Func<int, bool> tryConsumeCoin, Action<int> addCoin)
|
||||||
{
|
{
|
||||||
|
|
@ -128,8 +140,25 @@ namespace GeometryTD.Entity.EntityData
|
||||||
position,
|
position,
|
||||||
_initialCoin,
|
_initialCoin,
|
||||||
_buildTowerStatsSnapshot,
|
_buildTowerStatsSnapshot,
|
||||||
|
_inventorySnapshot,
|
||||||
|
_participantTowerSnapshot,
|
||||||
_tryConsumeCoin,
|
_tryConsumeCoin,
|
||||||
_addCoin);
|
_addCoin);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SetParticipantTowerSnapshot(IReadOnlyList<TowerItemData> participantTowerSnapshot)
|
||||||
|
{
|
||||||
|
if (participantTowerSnapshot == null || participantTowerSnapshot.Count <= 0)
|
||||||
|
{
|
||||||
|
_participantTowerSnapshot = Array.Empty<TowerItemData>();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_participantTowerSnapshot = new TowerItemData[participantTowerSnapshot.Count];
|
||||||
|
for (int i = 0; i < participantTowerSnapshot.Count; i++)
|
||||||
|
{
|
||||||
|
_participantTowerSnapshot[i] = InventoryCloneUtility.CloneTower(participantTowerSnapshot[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -243,12 +243,6 @@ namespace GeometryTD.Entity
|
||||||
private void ConfigureCombatSelectUseCase()
|
private void ConfigureCombatSelectUseCase()
|
||||||
{
|
{
|
||||||
_combatSelectFormUseCase.SetCoinProvider(GetCurrentCoin);
|
_combatSelectFormUseCase.SetCoinProvider(GetCurrentCoin);
|
||||||
BackpackInventoryData inventorySnapshot = GameEntry.PlayerInventory != null
|
|
||||||
? GameEntry.PlayerInventory.GetInventorySnapshot()
|
|
||||||
: null;
|
|
||||||
IReadOnlyList<TowerItemData> participantTowers = GameEntry.PlayerInventory != null
|
|
||||||
? GameEntry.PlayerInventory.GetParticipantTowerSnapshot()
|
|
||||||
: null;
|
|
||||||
_combatSelectUseCaseConfigurator?.Configure(
|
_combatSelectUseCaseConfigurator?.Configure(
|
||||||
_combatSelectFormUseCase,
|
_combatSelectFormUseCase,
|
||||||
GetCurrentCoin,
|
GetCurrentCoin,
|
||||||
|
|
@ -259,8 +253,8 @@ namespace GeometryTD.Entity
|
||||||
_destroyGain,
|
_destroyGain,
|
||||||
_buildTowerCosts,
|
_buildTowerCosts,
|
||||||
GetCurrentBuildTowerCount(),
|
GetCurrentBuildTowerCount(),
|
||||||
inventorySnapshot,
|
_mapData != null ? _mapData.InventorySnapshot : null,
|
||||||
participantTowers);
|
_mapData != null ? _mapData.ParticipantTowerSnapshot : null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleCombatSelectInput()
|
private void HandleCombatSelectInput()
|
||||||
|
|
|
||||||
|
|
@ -45,12 +45,8 @@ namespace GeometryTD.UI
|
||||||
{
|
{
|
||||||
if (!_isSummaryPrepared)
|
if (!_isSummaryPrepared)
|
||||||
{
|
{
|
||||||
_defeatedEnemyCount = GameEntry.CombatNode != null
|
_defeatedEnemyCount = 0;
|
||||||
? Mathf.Max(0, GameEntry.CombatNode.LastDefeatedEnemyCount)
|
_gainedGold = 0;
|
||||||
: 0;
|
|
||||||
_gainedGold = GameEntry.CombatNode != null
|
|
||||||
? Mathf.Max(0, GameEntry.CombatNode.LastGainedGold)
|
|
||||||
: 0;
|
|
||||||
_rewardInventory = null;
|
_rewardInventory = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,14 @@
|
||||||
|
using System;
|
||||||
using GeometryTD.Definition;
|
using GeometryTD.Definition;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
namespace GeometryTD.UI
|
namespace GeometryTD.UI
|
||||||
{
|
{
|
||||||
public class CombatInfoFormUseCase : IUIUseCase
|
public class CombatInfoFormUseCase : IUIUseCase
|
||||||
{
|
{
|
||||||
|
private Func<CombatInfoFormRawData> _modelProvider;
|
||||||
|
private Func<bool> _tryEndCombat;
|
||||||
|
|
||||||
public CombatInfoFormRawData CreateInitialModel()
|
public CombatInfoFormRawData CreateInitialModel()
|
||||||
{
|
{
|
||||||
return BuildModel();
|
return BuildModel();
|
||||||
|
|
@ -14,43 +19,49 @@ namespace GeometryTD.UI
|
||||||
return BuildModel();
|
return BuildModel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Configure(Func<CombatInfoFormRawData> modelProvider, Func<bool> tryEndCombat)
|
||||||
|
{
|
||||||
|
_modelProvider = modelProvider;
|
||||||
|
_tryEndCombat = tryEndCombat;
|
||||||
|
}
|
||||||
|
|
||||||
public bool TryEndCombat()
|
public bool TryEndCombat()
|
||||||
{
|
{
|
||||||
if (GameEntry.CombatNode == null || !GameEntry.CombatNode.CanEndCombat)
|
if (_tryEndCombat == null)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return GameEntry.CombatNode.TryEndCombatByPlayer();
|
return _tryEndCombat.Invoke();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static CombatInfoFormRawData BuildModel()
|
private CombatInfoFormRawData BuildModel()
|
||||||
{
|
{
|
||||||
if (GameEntry.CombatNode == null)
|
return _modelProvider != null ? _modelProvider.Invoke() : null;
|
||||||
{
|
}
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
var level = GameEntry.CombatNode.CurrentLevel;
|
|
||||||
LevelThemeType themeType = level != null ? level.LevelThemeType : GameEntry.CombatNode.CurrentThemeType;
|
|
||||||
int levelId = level != null ? level.Id : 0;
|
|
||||||
int baseHpMax = level != null ? level.BaseHp : 0;
|
|
||||||
int enemyHpRateMultiplier = ResolveEnemyHpRateMultiplier(
|
|
||||||
GameEntry.CombatNode.CurrentPhaseIndex,
|
|
||||||
GameEntry.CombatNode.CurrentLevelPhaseCount);
|
|
||||||
|
|
||||||
|
public static CombatInfoFormRawData BuildRawData(
|
||||||
|
LevelThemeType themeType,
|
||||||
|
int levelId,
|
||||||
|
int currentPhaseIndex,
|
||||||
|
int totalPhaseCount,
|
||||||
|
int coin,
|
||||||
|
int baseHp,
|
||||||
|
int baseHpMax,
|
||||||
|
bool canEnd)
|
||||||
|
{
|
||||||
return new CombatInfoFormRawData
|
return new CombatInfoFormRawData
|
||||||
{
|
{
|
||||||
LevelThemeType = themeType,
|
LevelThemeType = themeType,
|
||||||
LevelId = levelId,
|
LevelId = levelId,
|
||||||
CurrentPhaseIndex = GameEntry.CombatNode.CurrentPhaseIndex,
|
CurrentPhaseIndex = Mathf.Max(0, currentPhaseIndex),
|
||||||
TotalPhaseCount = GameEntry.CombatNode.CurrentLevelPhaseCount,
|
TotalPhaseCount = Mathf.Max(0, totalPhaseCount),
|
||||||
Coin = GameEntry.CombatNode.CurrentCoin,
|
Coin = Mathf.Max(0, coin),
|
||||||
BaseHp = GameEntry.CombatNode.CurrentBaseHp,
|
BaseHp = Mathf.Max(0, baseHp),
|
||||||
BaseHpMax = baseHpMax,
|
BaseHpMax = Mathf.Max(0, baseHpMax),
|
||||||
EnemyHpRateMultiplier = enemyHpRateMultiplier,
|
EnemyHpRateMultiplier = ResolveEnemyHpRateMultiplier(currentPhaseIndex, totalPhaseCount),
|
||||||
CanPause = true,
|
CanPause = true,
|
||||||
CanEnd = GameEntry.CombatNode.CanEndCombat
|
CanEnd = canEnd
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -61,7 +72,7 @@ namespace GeometryTD.UI
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int completedLoopCount = UnityEngine.Mathf.Max(0, (currentPhaseIndex - 1) / totalPhaseCount);
|
int completedLoopCount = Mathf.Max(0, (currentPhaseIndex - 1) / totalPhaseCount);
|
||||||
if (completedLoopCount >= 30)
|
if (completedLoopCount >= 30)
|
||||||
{
|
{
|
||||||
return int.MaxValue;
|
return int.MaxValue;
|
||||||
|
|
|
||||||
|
|
@ -269,12 +269,7 @@ namespace GeometryTD.UI
|
||||||
|
|
||||||
private static int DefaultCoinProvider()
|
private static int DefaultCoinProvider()
|
||||||
{
|
{
|
||||||
if (GameEntry.CombatNode == null)
|
return 0;
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Mathf.Max(0, GameEntry.CombatNode.CurrentCoin);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool CanExecute(Option option, int currentCoin)
|
private static bool CanExecute(Option option, int currentCoin)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue