文件迁移

This commit is contained in:
2026-03-07 18:26:28 +08:00
parent ab7c7172b8
commit 3badbe9212
31 changed files with 54 additions and 29 deletions
@@ -387,7 +387,7 @@ namespace GeometryTD.CustomComponent
GameEntry.UIRouter.CloseUI(UIFormType.RewardSelectForm);
}
private void CompleteCombatAndNotify(bool succeeded)
private void CompleteCombat(bool succeeded)
{
_isCompleted = true;
_currentState = null;
@@ -395,6 +395,12 @@ namespace GeometryTD.CustomComponent
GameEntry.CombatNode?.OnCombatEndedByScheduler(succeeded);
}
private void CompleteNormalCombatAndNotify(bool succeeded)
{
CompleteCombat(succeeded);
GameEntry.Event.Fire(this, NodeCompleteEventArgs.Create());
}
private bool HandleStartFailure(string errorMessage)
{
Log.Warning("{0}", errorMessage);
@@ -497,7 +503,7 @@ namespace GeometryTD.CustomComponent
private void GameOverByFailure()
{
CompleteCombatAndNotify(false);
CompleteCombat(false);
}
}
@@ -4,10 +4,18 @@ namespace GeometryTD.CustomComponent
{
internal sealed class CombatSettlementContext
{
public bool IsVictory;
public int FinalCoin;
public int FinalBaseHp;
public int MaxBaseHp;
public int DefeatedEnemyCount;
public int GainedGold;
public BackpackInventoryData RewardInventory;
public bool ShouldOpenRewardSelection;
public bool DidEnterRewardSelection;
public bool ShouldApplyLowBaseHpPenalty;
public float LowBaseHpEndurancePenaltyValue;
public int AffectedTowerCount;
public bool IsCommitted;
public string Reason;
}
@@ -39,12 +39,20 @@ namespace GeometryTD.CustomComponent
CombatSettlementContext settlementContext = new CombatSettlementContext
{
IsVictory = isVictory,
FinalCoin = Mathf.Max(0, resourceManager != null ? resourceManager.CurrentCoin : 0),
FinalBaseHp = currentBaseHp,
MaxBaseHp = maxBaseHp,
DefeatedEnemyCount = Mathf.Max(0, defeatedEnemyCount),
GainedGold = Mathf.Max(0, resourceManager != null ? resourceManager.GainedGold : 0),
RewardInventory = resourceManager != null
? resourceManager.GetRewardInventorySnapshot()
: new BackpackInventoryData(),
ShouldOpenRewardSelection = shouldOpenFullBaseHpRewardSelect,
DidEnterRewardSelection = false,
ShouldApplyLowBaseHpPenalty = appliedLowBaseHpPenalty,
LowBaseHpEndurancePenaltyValue = appliedLowBaseHpPenalty ? LowBaseHpTowerEndurancePenalty : 0f,
AffectedTowerCount = 0,
Reason = reason
};
@@ -72,6 +80,7 @@ namespace GeometryTD.CustomComponent
BackpackInventoryData rewardInventory = settlementContext.RewardInventory ?? new BackpackInventoryData();
GameEntry.PlayerInventory?.MergeInventory(rewardInventory);
settlementContext.RewardInventory = rewardInventory;
settlementContext.AffectedTowerCount = ApplyDeferredSettlementPenalty(settlementContext);
settlementContext.IsCommitted = true;
}
@@ -133,6 +142,7 @@ namespace GeometryTD.CustomComponent
return false;
}
settlementContext.DidEnterRewardSelection = true;
GameEntry.UIRouter.OpenUI(UIFormType.RewardSelectForm, rawData);
return true;
}
@@ -149,7 +159,6 @@ namespace GeometryTD.CustomComponent
public void OpenCombatFinishForm(
CombatSettlementContext settlementContext,
CombatInRunResourceManager resourceManager,
CombatFinishFormUseCase combatFinishFormUseCase)
{
if (settlementContext == null || combatFinishFormUseCase == null)
@@ -157,11 +166,7 @@ namespace GeometryTD.CustomComponent
return;
}
settlementContext.GainedGold = Mathf.Max(0, resourceManager != null ? resourceManager.GainedGold : settlementContext.GainedGold);
combatFinishFormUseCase.SetSummary(
settlementContext.DefeatedEnemyCount,
settlementContext.GainedGold,
settlementContext.RewardInventory);
combatFinishFormUseCase.SetSummary(settlementContext);
GameEntry.UIRouter.OpenUI(UIFormType.CombatFinishForm);
}
@@ -209,7 +214,7 @@ namespace GeometryTD.CustomComponent
}
else if (hpRate < MidBaseHpThreshold)
{
appliedLowBaseHpPenalty = ApplyLowBaseHpPenalty();
appliedLowBaseHpPenalty = true;
}
}
@@ -219,16 +224,22 @@ namespace GeometryTD.CustomComponent
resourceManager.AddSettlementGold(settlementGold);
}
private static bool ApplyLowBaseHpPenalty()
private static int ApplyDeferredSettlementPenalty(CombatSettlementContext settlementContext)
{
if (settlementContext == null ||
!settlementContext.ShouldApplyLowBaseHpPenalty ||
settlementContext.LowBaseHpEndurancePenaltyValue <= 0f)
{
return 0;
}
PlayerInventoryComponent inventory = GameEntry.PlayerInventory;
if (inventory == null)
{
return false;
return 0;
}
int affectedTowerCount = inventory.ReduceAllTowerEndurance(LowBaseHpTowerEndurancePenalty);
return affectedTowerCount > 0;
return inventory.ReduceAllTowerEndurance(settlementContext.LowBaseHpEndurancePenaltyValue);
}
private static bool TryAppendRewardComponent(BackpackInventoryData rewardInventory, TowerCompItemData selectedItem)
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 76973ced080a4a839543fc9361b6b96b
timeCreated: 1772847309
@@ -0,0 +1,35 @@
using UnityGameFramework.Runtime;
namespace GeometryTD.CustomComponent
{
public partial class CombatScheduler
{
private sealed class CombatFailedState : CombatStateBase
{
private readonly string _errorMessage;
private readonly bool _notifyCombatNode;
public CombatFailedState(CombatScheduler scheduler, string errorMessage, bool notifyCombatNode) : base(scheduler)
{
_errorMessage = errorMessage;
_notifyCombatNode = notifyCombatNode;
}
public override void OnEnter()
{
Log.Error(
"CombatScheduler failed. LevelId={0}, {1}",
Scheduler._currentLevel != null ? Scheduler._currentLevel.Id : 0,
_errorMessage);
Scheduler._enemyManager.EndPhase();
Scheduler.CleanupAllCombatEntities();
Scheduler.CloseCombatFinishForm();
Scheduler.CloseRewardSelectForm();
if (_notifyCombatNode)
{
Scheduler.GameOverByFailure();
}
}
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 39d988ff69b018a49857384e3a3b6f20
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,28 @@
namespace GeometryTD.CustomComponent
{
public partial class CombatScheduler
{
private sealed class CombatFinishFormState : CombatStateBase
{
public CombatFinishFormState(CombatScheduler scheduler) : base(scheduler)
{
}
public override void OnEnter()
{
if (Scheduler._settlementContext == null)
{
Scheduler.EnterFailureFallback("Combat finish form failed. Settlement context is missing.");
return;
}
Scheduler._settlementFlowService.CommitSettlementInventory(Scheduler._settlementContext);
Scheduler.EnsureCombatFinishFormUseCaseBound();
Scheduler._settlementFlowService.OpenCombatFinishForm(
Scheduler._settlementContext,
Scheduler._combatFinishFormUseCase);
Scheduler.ChangeState(new CombatWaitingForReturnState(Scheduler));
}
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0d78014e1fa53434aa14628f83ed3669
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,75 @@
using System.Collections.Generic;
using GeometryTD.Definition;
using GeometryTD.Entity.EntityData;
using GeometryTD.UI;
using UnityEngine;
namespace GeometryTD.CustomComponent
{
public partial class CombatScheduler
{
private sealed class CombatLoadingState : CombatStateBase
{
public CombatLoadingState(CombatScheduler scheduler) : base(scheduler)
{
}
public override void OnEnter()
{
if (Scheduler._currentLevel == null)
{
Scheduler.EnterFailureFallback("Combat loading failed. Current level is null.");
return;
}
MapData mapData = BuildMapData();
if (!Scheduler._loadSession.StartLoading(Scheduler._currentLevel, mapData, Scheduler, out string errorMessage))
{
Scheduler.EnterFailureFallback($"Combat loading failed. {errorMessage}");
}
}
public override void OnUpdate(float elapseSeconds, float realElapseSeconds)
{
_ = elapseSeconds;
_ = realElapseSeconds;
if (!Scheduler._loadSession.IsReady)
{
return;
}
Scheduler.TryBeginNextPhase();
}
private MapData BuildMapData()
{
List<TowerStatsData> buildTowerStatsSnapshot = new();
for (int i = 0; i < Scheduler._combatInRunResourceManager.CurrentBuildTowerCount; i++)
{
if (Scheduler._combatInRunResourceManager.TryGetBuildTowerStats(i, out TowerStatsData stats) &&
stats != null)
{
buildTowerStatsSnapshot.Add(stats);
}
}
return new MapData(
entityId: 0,
typeId: 0,
levelId: Scheduler._currentLevel.Id,
position: Vector3.zero,
initialCoin: Scheduler._combatInRunResourceManager.CurrentCoin,
buildTowerStatsSnapshot: buildTowerStatsSnapshot,
inventorySnapshot: GameEntry.PlayerInventory != null
? GameEntry.PlayerInventory.GetInventorySnapshot()
: null,
participantTowerSnapshot: GameEntry.PlayerInventory != null
? GameEntry.PlayerInventory.GetParticipantTowerSnapshot()
: null,
tryConsumeCoin: Scheduler.TryConsumeCoin,
addCoin: Scheduler.AddCoin);
}
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8f604bf4c97e462abf153804c1b0b55d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,39 @@
namespace GeometryTD.CustomComponent
{
public partial class CombatScheduler
{
private sealed class CombatRewardSelectionState : CombatStateBase
{
public CombatRewardSelectionState(CombatScheduler scheduler) : base(scheduler)
{
}
public override void OnEnter()
{
if (Scheduler._settlementContext == null)
{
Scheduler.EnterFailureFallback("Combat reward selection failed. Settlement context is missing.");
return;
}
Scheduler.EnsureRewardSelectFormUseCaseBound();
if (!Scheduler._settlementFlowService.TryPrepareRewardSelection(
Scheduler._settlementContext,
Scheduler._combatInRunResourceManager,
Scheduler._phaseLoopRuntime.DisplayPhaseIndex,
Scheduler.ResolveCurrentThemeType(),
Scheduler._rewardSelectFormUseCase,
Scheduler.OnFullBaseHpRewardSelected,
Scheduler.OnFullBaseHpRewardGiveUp))
{
Scheduler.ChangeState(new CombatFinishFormState(Scheduler));
}
}
public override void OnExit()
{
Scheduler.CloseRewardSelectForm();
}
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e087635834ae66943a6fc76e813ab1f5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,77 @@
using System.Collections.Generic;
using GeometryTD.CustomEvent;
using GeometryTD.DataTable;
using UnityGameFramework.Runtime;
namespace GeometryTD.CustomComponent
{
public partial class CombatScheduler
{
private sealed class CombatRunningPhaseState : CombatStateBase
{
private readonly DRLevelPhase _phase;
private readonly IReadOnlyList<DRLevelSpawnEntry> _spawnEntries;
public CombatRunningPhaseState(
CombatScheduler scheduler,
DRLevelPhase phase,
IReadOnlyList<DRLevelSpawnEntry> spawnEntries) : base(scheduler)
{
_phase = phase;
_spawnEntries = spawnEntries;
}
public override void OnEnter()
{
Scheduler._enemyManager.BeginPhase(_phase, _spawnEntries);
GameEntry.Event.Fire(
Scheduler,
CombatProcessEventArgs.Create(
Scheduler._phaseLoopRuntime.DisplayPhaseIndex,
Scheduler._phaseLoopRuntime.PhaseCount));
GameEntry.Event.Fire(
Scheduler,
CombatEnemyHpRateChangedEventArgs.Create(
ResolveEnemyHpRateMultiplier(
Scheduler._phaseLoopRuntime.DisplayPhaseIndex,
Scheduler._phaseLoopRuntime.PhaseCount)));
if (!Scheduler._nodeEnterFired)
{
Scheduler._nodeEnterFired = true;
GameEntry.Event.Fire(Scheduler, NodeEnterEventArgs.Create());
}
Log.Info(
"CombatScheduler phase started. Level={0}, Phase={1}, EndType={2}, Entries={3}.",
Scheduler._currentLevel != null ? Scheduler._currentLevel.Id : 0,
Scheduler._phaseLoopRuntime.DisplayPhaseIndex,
_phase.EndType,
_spawnEntries != null ? _spawnEntries.Count : 0);
}
public override void OnUpdate(float elapseSeconds, float realElapseSeconds)
{
if (Scheduler._phaseLoopRuntime.CurrentPhase == null)
{
Scheduler.EnterFailureFallback("CombatScheduler update failed. Current phase is null.");
return;
}
Scheduler._phaseLoopRuntime.AdvancePhaseElapsed(elapseSeconds);
Scheduler._enemyManager.OnUpdate(elapseSeconds, realElapseSeconds);
if (Scheduler.ShouldEnterSettlementFromActiveState(out string reason, out bool isVictory))
{
Scheduler.ChangeState(new CombatSettlementState(Scheduler, reason, isVictory));
return;
}
if (Scheduler._enemyManager.IsPhaseSpawnCompleted)
{
Scheduler.EnterWaitingForPhaseEnd();
}
}
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4ea3f65c4dc4478ab57c6b8d7a5382b3
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,37 @@
namespace GeometryTD.CustomComponent
{
public partial class CombatScheduler
{
private sealed class CombatSettlementState : CombatStateBase
{
private readonly string _reason;
private readonly bool _isVictory;
public CombatSettlementState(CombatScheduler scheduler, string reason, bool isVictory) : base(scheduler)
{
_reason = reason;
_isVictory = isVictory;
}
public override void OnEnter()
{
Scheduler._enemyManager.EndPhase();
Scheduler._enemyManager.CleanupTrackedEnemies();
Scheduler._isFinishAsVictory = _isVictory;
Scheduler._settlementContext = Scheduler._settlementFlowService.BuildSettlementContext(
_reason,
_isVictory,
Scheduler._currentLevel,
Scheduler._enemyManager.DefeatedEnemyCount,
Scheduler._combatInRunResourceManager);
if (Scheduler._settlementContext.ShouldOpenRewardSelection)
{
Scheduler.ChangeState(new CombatRewardSelectionState(Scheduler));
return;
}
Scheduler.ChangeState(new CombatFinishFormState(Scheduler));
}
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 61773c700734bfb4db073594ef2f97a8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,35 @@
namespace GeometryTD.CustomComponent
{
public partial class CombatScheduler
{
private abstract class CombatStateBase
{
protected CombatScheduler Scheduler { get; }
protected CombatStateBase(CombatScheduler scheduler)
{
Scheduler = scheduler;
}
public virtual void OnInit()
{
}
public virtual void OnEnter()
{
}
public virtual void OnExit()
{
}
public virtual void OnUpdate(float elapseSeconds, float realElapseSeconds)
{
}
public virtual void OnDestroy()
{
}
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 9346a56a6d174c3fbc6889003134ddc6
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,46 @@
namespace GeometryTD.CustomComponent
{
public partial class CombatScheduler
{
private sealed class CombatWaitingForPhaseEndState : CombatStateBase
{
public CombatWaitingForPhaseEndState(CombatScheduler scheduler) : base(scheduler)
{
}
public override void OnUpdate(float elapseSeconds, float realElapseSeconds)
{
_ = realElapseSeconds;
var currentPhase = Scheduler._phaseLoopRuntime.CurrentPhase;
if (currentPhase == null)
{
Scheduler.EnterFailureFallback("CombatScheduler waiting phase failed. Current phase is null.");
return;
}
Scheduler._phaseLoopRuntime.AdvancePhaseElapsed(elapseSeconds);
if (Scheduler.ShouldEnterSettlementFromActiveState(out string reason, out bool isVictory))
{
Scheduler.ChangeState(new CombatSettlementState(Scheduler, reason, isVictory));
return;
}
PhaseEndConditionContext context = new(
currentPhase,
Scheduler._phaseLoopRuntime.CurrentPhaseElapsed,
Scheduler._enemyManager.IsPhaseSpawnCompleted,
Scheduler._enemyManager.AliveEnemyCount,
Scheduler._enemyManager.HasAliveBoss);
IPhaseEndCondition endCondition = PhaseEndConditionFactory.Create(currentPhase.EndType);
if (!endCondition.ShouldExit(context))
{
return;
}
Scheduler.CompleteCurrentPhase();
}
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 190af076775ad1b4c97a2baf09588bbf
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,35 @@
namespace GeometryTD.CustomComponent
{
public partial class CombatScheduler
{
private sealed class CombatWaitingForReturnState : CombatStateBase
{
private bool _returnRequested;
public CombatWaitingForReturnState(CombatScheduler scheduler) : base(scheduler)
{
}
public void RequestReturn()
{
_returnRequested = true;
}
public override void OnUpdate(float elapseSeconds, float realElapseSeconds)
{
_ = elapseSeconds;
_ = realElapseSeconds;
if (!_returnRequested)
{
return;
}
Scheduler._loadSession.Cleanup();
Scheduler.CloseCombatFinishForm();
Scheduler.CloseRewardSelectForm();
Scheduler.CompleteNormalCombatAndNotify(Scheduler._isFinishAsVictory);
}
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6c86116fef176a840a38bd7c154a5deb
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 5f2ff98d705436042b48a4c56d982411
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant: