feat: Introduce new services and refactor existing code for better structure

- Added ISpriteCacheService, IStaticDataService, and ITextService interfaces for improved service management.
- Implemented RunContracts for managing run states and node execution contexts.
- Created EnemyTagStatusRuntime to handle enemy status effects and their application.
- Refactored ShopPriceRuleService to utilize static data service for shop prices.
- Enhanced InventoryTowerEnduranceUtility to manage tower endurance reduction.
- Updated EventFormUseCase to work with new EventOptionExecutionContext.
- Removed unused dictionary loading code from ProcedurePreload.
- Cleaned up various utility classes and ensured consistent naming conventions.
- Updated tests to reflect changes in context and service usage.
This commit is contained in:
2026-05-13 22:18:47 +08:00
parent 9fc0ef2216
commit 7106e0adbe
45 changed files with 590 additions and 426 deletions
@@ -50,8 +50,6 @@ namespace GeometryTD.Procedure
GameEntry.Event.Subscribe(LoadConfigFailureEventArgs.EventId, OnLoadConfigFailure);
GameEntry.Event.Subscribe(LoadDataTableSuccessEventArgs.EventId, OnLoadDataTableSuccess);
GameEntry.Event.Subscribe(LoadDataTableFailureEventArgs.EventId, OnLoadDataTableFailure);
GameEntry.Event.Subscribe(LoadDictionarySuccessEventArgs.EventId, OnLoadDictionarySuccess);
GameEntry.Event.Subscribe(LoadDictionaryFailureEventArgs.EventId, OnLoadDictionaryFailure);
_loadedFlag.Clear();
@@ -64,8 +62,6 @@ namespace GeometryTD.Procedure
GameEntry.Event.Unsubscribe(LoadConfigFailureEventArgs.EventId, OnLoadConfigFailure);
GameEntry.Event.Unsubscribe(LoadDataTableSuccessEventArgs.EventId, OnLoadDataTableSuccess);
GameEntry.Event.Unsubscribe(LoadDataTableFailureEventArgs.EventId, OnLoadDataTableFailure);
GameEntry.Event.Unsubscribe(LoadDictionarySuccessEventArgs.EventId, OnLoadDictionarySuccess);
GameEntry.Event.Unsubscribe(LoadDictionaryFailureEventArgs.EventId, OnLoadDictionaryFailure);
base.OnLeave(procedureOwner, isShutdown);
}
@@ -97,9 +93,6 @@ namespace GeometryTD.Procedure
LoadDataTable(dataTableName);
}
// Preload dictionaries
//LoadDictionary("Default");
// Preload fonts
LoadFont("MainFont");
LoadTMPFont("MainTMPFont");
@@ -119,13 +112,6 @@ namespace GeometryTD.Procedure
GameEntry.DataTable.LoadDataTable(dataTableName, dataTableAssetName, this);
}
private void LoadDictionary(string dictionaryName)
{
string dictionaryAssetName = AssetUtility.GetDictionaryAsset(dictionaryName, false);
_loadedFlag.Add(dictionaryAssetName, false);
GameEntry.Localization.ReadData(dictionaryAssetName, this);
}
private void LoadFont(string fontName)
{
_loadedFlag.Add(Utility.Text.Format("Font.{0}", fontName), false);
@@ -209,29 +195,5 @@ namespace GeometryTD.Procedure
Log.Error("Can not load data table '{0}' from '{1}' with error message '{2}'.", ne.DataTableAssetName,
ne.DataTableAssetName, ne.ErrorMessage);
}
private void OnLoadDictionarySuccess(object sender, GameEventArgs e)
{
LoadDictionarySuccessEventArgs ne = (LoadDictionarySuccessEventArgs)e;
if (ne.UserData != this)
{
return;
}
_loadedFlag[ne.DictionaryAssetName] = true;
Log.Info("Load dictionary '{0}' OK.", ne.DictionaryAssetName);
}
private void OnLoadDictionaryFailure(object sender, GameEventArgs e)
{
LoadDictionaryFailureEventArgs ne = (LoadDictionaryFailureEventArgs)e;
if (ne.UserData != this)
{
return;
}
Log.Error("Can not load dictionary '{0}' from '{1}' with error message '{2}'.", ne.DictionaryAssetName,
ne.DictionaryAssetName, ne.ErrorMessage);
}
}
}
@@ -1,20 +1,10 @@
using System;
using System.Collections.Generic;
using GeometryTD.CustomUtility;
using GeometryTD.Definition;
using GeometryTD.Core;
using GeometryTD.Factory;
namespace GeometryTD.Procedure
{
public enum RunNodeType
{
None = 0,
Combat = 1,
Event = 2,
Shop = 3,
BossCombat = 4
}
public enum RunNodeStatus
{
Locked = 0,
@@ -24,13 +14,6 @@ namespace GeometryTD.Procedure
Skipped = 4
}
public enum RunNodeCompletionStatus
{
None = 0,
Completed = 1,
Exception = 2
}
[Serializable]
public sealed class RunNodeSeed
{
@@ -65,96 +48,6 @@ namespace GeometryTD.Procedure
}
}
[Serializable]
public sealed class RunItemState
{
public int ItemId { get; set; }
public int StackCount { get; set; }
internal RunItemState Clone()
{
return new RunItemState
{
ItemId = ItemId,
StackCount = StackCount
};
}
}
[Serializable]
public sealed class RunNodeExecutionContext
{
public string RunId { get; set; }
public int RunSeed { get; set; }
public int NodeId { get; set; }
public RunNodeType NodeType { get; set; }
public int SequenceIndex { get; set; }
public LevelThemeType ThemeType { get; set; }
public int ThemeStageIndex { get; set; }
public List<LevelThemeType> CurrentThemePool { get; set; } = new List<LevelThemeType>();
public List<LevelThemeType> ThemeHistory { get; set; } = new List<LevelThemeType>();
public int CurrentNodeContinueChallengeLayer { get; set; }
public List<RunItemState> RunItems { get; set; } = new List<RunItemState>();
internal RunNodeExecutionContext Clone()
{
return new RunNodeExecutionContext
{
RunId = RunId,
RunSeed = RunSeed,
NodeId = NodeId,
NodeType = NodeType,
SequenceIndex = SequenceIndex,
ThemeType = ThemeType,
ThemeStageIndex = ThemeStageIndex,
CurrentThemePool = RunStateCloneUtility.CloneThemeList(CurrentThemePool),
ThemeHistory = RunStateCloneUtility.CloneThemeList(ThemeHistory),
CurrentNodeContinueChallengeLayer = CurrentNodeContinueChallengeLayer,
RunItems = RunStateCloneUtility.CloneRunItems(RunItems)
};
}
public RunNodeCompletionSnapshot CreateCompletionSnapshot(BackpackInventoryData inventorySnapshot)
{
return new RunNodeCompletionSnapshot
{
InventorySnapshot = InventoryCloneUtility.CloneInventory(inventorySnapshot),
ThemeType = ThemeType,
ThemeStageIndex = ThemeStageIndex,
CurrentThemePool = RunStateCloneUtility.CloneThemeList(CurrentThemePool),
ThemeHistory = RunStateCloneUtility.CloneThemeList(ThemeHistory),
CurrentNodeContinueChallengeLayer = CurrentNodeContinueChallengeLayer,
RunItems = RunStateCloneUtility.CloneRunItems(RunItems)
};
}
}
[Serializable]
public sealed class RunNodeCompletionSnapshot
{
public BackpackInventoryData InventorySnapshot { get; set; }
public LevelThemeType ThemeType { get; set; }
public int ThemeStageIndex { get; set; }
public List<LevelThemeType> CurrentThemePool { get; set; } = new List<LevelThemeType>();
public List<LevelThemeType> ThemeHistory { get; set; } = new List<LevelThemeType>();
public int CurrentNodeContinueChallengeLayer { get; set; }
public List<RunItemState> RunItems { get; set; } = new List<RunItemState>();
internal RunNodeCompletionSnapshot Clone()
{
return new RunNodeCompletionSnapshot
{
InventorySnapshot = InventoryCloneUtility.CloneInventory(InventorySnapshot),
ThemeType = ThemeType,
ThemeStageIndex = ThemeStageIndex,
CurrentThemePool = RunStateCloneUtility.CloneThemeList(CurrentThemePool),
ThemeHistory = RunStateCloneUtility.CloneThemeList(ThemeHistory),
CurrentNodeContinueChallengeLayer = CurrentNodeContinueChallengeLayer,
RunItems = RunStateCloneUtility.CloneRunItems(RunItems)
};
}
}
[Serializable]
public sealed class RunState
{
@@ -314,42 +207,4 @@ namespace GeometryTD.Procedure
}
}
internal static class RunStateCloneUtility
{
internal static List<LevelThemeType> CloneThemeList(IReadOnlyList<LevelThemeType> source)
{
List<LevelThemeType> cloned = new List<LevelThemeType>();
if (source == null)
{
return cloned;
}
for (int i = 0; i < source.Count; i++)
{
cloned.Add(source[i]);
}
return cloned;
}
internal static List<RunItemState> CloneRunItems(IReadOnlyList<RunItemState> source)
{
List<RunItemState> cloned = new List<RunItemState>();
if (source == null)
{
return cloned;
}
for (int i = 0; i < source.Count; i++)
{
RunItemState item = source[i];
if (item != null)
{
cloned.Add(item.Clone());
}
}
return cloned;
}
}
}