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
@@ -15,12 +15,6 @@ namespace GeometryTD.Core
return Utility.Text.Format("Assets/GameMain/DataTables/{0}.{1}", assetName, fromBytes ? "bytes" : "txt");
}
public static string GetDictionaryAsset(string assetName, bool fromBytes)
{
return Utility.Text.Format("Assets/GameMain/Localization/{0}/Dictionaries/{1}.{2}",
GameEntry.Localization.Language, assetName, fromBytes ? "bytes" : "xml");
}
public static string GetFontAsset(string assetName)
{
return Utility.Text.Format("Assets/GameMain/Fonts/{0}.ttf", assetName);
@@ -121,7 +121,7 @@ namespace GeometryTD.Core
private static void TryRefreshRangesFromDataTables()
{
if (GameEntry.DataTable == null)
if (CoreServiceHub.StaticData == null)
{
return;
}
@@ -154,13 +154,7 @@ namespace GeometryTD.Core
attackDamageRange = _attackDamageRange;
damageRandomRateRange = _damageRandomRateRange;
IDataTable<DRMuzzleComp> dataTable = GameEntry.DataTable.GetDataTable<DRMuzzleComp>();
if (dataTable == null || dataTable.Count <= 0)
{
return false;
}
DRMuzzleComp[] rows = dataTable.GetAllDataRows();
DRMuzzleComp[] rows = CoreServiceHub.StaticData.GetAllMuzzleComps();
if (rows == null || rows.Length <= 0)
{
return false;
@@ -201,13 +195,7 @@ namespace GeometryTD.Core
rotateSpeedRange = _rotateSpeedRange;
attackRangeRange = _attackRangeRange;
IDataTable<DRBearingComp> dataTable = GameEntry.DataTable.GetDataTable<DRBearingComp>();
if (dataTable == null || dataTable.Count <= 0)
{
return false;
}
DRBearingComp[] rows = dataTable.GetAllDataRows();
DRBearingComp[] rows = CoreServiceHub.StaticData.GetAllBearingComps();
if (rows == null || rows.Length <= 0)
{
return false;
@@ -246,13 +234,7 @@ namespace GeometryTD.Core
{
attackSpeedRange = _attackSpeedRange;
IDataTable<DRBaseComp> dataTable = GameEntry.DataTable.GetDataTable<DRBaseComp>();
if (dataTable == null || dataTable.Count <= 0)
{
return false;
}
DRBaseComp[] rows = dataTable.GetAllDataRows();
DRBaseComp[] rows = CoreServiceHub.StaticData.GetAllBaseComps();
if (rows == null || rows.Length <= 0)
{
return false;
@@ -0,0 +1,109 @@
using System.Collections.Generic;
using UnityEngine;
namespace GeometryTD.Core
{
public static class InventoryTowerEnduranceUtility
{
public static int ReduceTowerEndurance(
BackpackInventoryData inventory,
IReadOnlyList<long> towerInstanceIds,
float enduranceLoss)
{
float resolvedLoss = Mathf.Max(0f, enduranceLoss);
if (inventory?.Towers == null ||
inventory.Towers.Count <= 0 ||
resolvedLoss <= 0f ||
towerInstanceIds == null ||
towerInstanceIds.Count <= 0)
{
return 0;
}
Dictionary<long, MuzzleCompItemData> muzzleMap = BuildComponentMap(inventory.MuzzleComponents);
Dictionary<long, BearingCompItemData> bearingMap = BuildComponentMap(inventory.BearingComponents);
Dictionary<long, BaseCompItemData> baseMap = BuildComponentMap(inventory.BaseComponents);
HashSet<long> processedTowerIds = new HashSet<long>();
int affectedCount = 0;
for (int i = 0; i < towerInstanceIds.Count; i++)
{
long towerInstanceId = towerInstanceIds[i];
if (towerInstanceId <= 0 || !processedTowerIds.Add(towerInstanceId))
{
continue;
}
if (!InventoryParticipantUtility.TryGetTowerById(inventory, towerInstanceId, out TowerItemData tower) ||
tower == null)
{
continue;
}
bool towerAffected = false;
if (muzzleMap.TryGetValue(tower.MuzzleComponentInstanceId, out MuzzleCompItemData muzzleComp))
{
towerAffected |= TryReduceComponentEndurance(muzzleComp, resolvedLoss);
}
if (bearingMap.TryGetValue(tower.BearingComponentInstanceId, out BearingCompItemData bearingComp))
{
towerAffected |= TryReduceComponentEndurance(bearingComp, resolvedLoss);
}
if (baseMap.TryGetValue(tower.BaseComponentInstanceId, out BaseCompItemData baseComp))
{
towerAffected |= TryReduceComponentEndurance(baseComp, resolvedLoss);
}
if (towerAffected)
{
affectedCount++;
}
}
return affectedCount;
}
private static bool TryReduceComponentEndurance(TowerCompItemData component, float enduranceLoss)
{
if (component == null)
{
return false;
}
float originalEndurance = component.Endurance;
float nextEndurance = Mathf.Clamp(originalEndurance - Mathf.Max(0f, enduranceLoss), 0f, 100f);
if (nextEndurance >= originalEndurance)
{
return false;
}
component.Endurance = nextEndurance;
return true;
}
private static Dictionary<long, TComp> BuildComponentMap<TComp>(List<TComp> components)
where TComp : TowerCompItemData
{
Dictionary<long, TComp> map = new Dictionary<long, TComp>();
if (components == null || components.Count <= 0)
{
return map;
}
for (int i = 0; i < components.Count; i++)
{
TComp component = components[i];
if (component == null || component.InstanceId <= 0)
{
continue;
}
map[component.InstanceId] = component;
}
return map;
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: abb0c22f9d11c6b4aae1d76fede68320
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -1,7 +1,5 @@
using System;
using System.Collections.Generic;
using GameFramework.DataTable;
using GeometryTD.Core;
using UnityEngine;
using Random = System.Random;
@@ -9,9 +7,11 @@ namespace GeometryTD.Core
{
public static class ShopPriceRuleService
{
public static int ResolveRandomBuyPrice(IReadOnlyList<DRShopPrice> shopPriceRows, RarityType rarity, Random random)
private static Dictionary<RarityType, DRShopPrice> _shopPriceByRarity;
public static int ResolveRandomBuyPrice(RarityType rarity, Random random)
{
if (!TryFindPriceRow(shopPriceRows, rarity, out DRShopPrice row) || row == null)
if (!TryFindPriceRow(rarity, out DRShopPrice row) || row == null)
{
return 0;
}
@@ -21,21 +21,20 @@ namespace GeometryTD.Core
return random != null ? random.Next(min, max + 1) : min;
}
public static int ResolveComponentSalePrice(TowerCompItemData component, IDataTable<DRShopPrice> shopPriceTable = null)
public static int ResolveComponentSalePrice(TowerCompItemData component)
{
if (component == null)
{
return 0;
}
return ResolveBasePrice(component.Rarity, shopPriceTable);
return ResolveBasePrice(component.Rarity);
}
public static bool TryResolveTowerSalePrice(
TowerItemData tower,
BackpackInventoryData inventory,
out int price,
IDataTable<DRShopPrice> shopPriceTable = null)
out int price)
{
price = 0;
if (tower == null || inventory == null)
@@ -50,22 +49,15 @@ namespace GeometryTD.Core
return false;
}
price = ResolveComponentSalePrice(muzzleComp, shopPriceTable) +
ResolveComponentSalePrice(bearingComp, shopPriceTable) +
ResolveComponentSalePrice(baseComp, shopPriceTable);
price = ResolveComponentSalePrice(muzzleComp) +
ResolveComponentSalePrice(bearingComp) +
ResolveComponentSalePrice(baseComp);
return price > 0;
}
public static int ResolveBasePrice(RarityType rarity, IDataTable<DRShopPrice> shopPriceTable = null)
public static int ResolveBasePrice(RarityType rarity)
{
IDataTable<DRShopPrice> resolvedTable = shopPriceTable ?? GameEntry.DataTable.GetDataTable<DRShopPrice>();
if (resolvedTable == null)
{
return 0;
}
DRShopPrice[] rows = resolvedTable.GetAllDataRows();
if (!TryFindPriceRow(rows, rarity, out DRShopPrice row) || row == null)
if (!TryFindPriceRow(rarity, out DRShopPrice row) || row == null)
{
return 0;
}
@@ -75,25 +67,49 @@ namespace GeometryTD.Core
return Mathf.RoundToInt((min + max) * 0.5f);
}
private static bool TryFindPriceRow(IReadOnlyList<DRShopPrice> rows, RarityType rarity, out DRShopPrice result)
public static void ClearCache()
{
result = null;
if (rows == null)
_shopPriceByRarity = null;
}
private static bool TryFindPriceRow(RarityType rarity, out DRShopPrice result)
{
EnsureShopPriceCache();
if (_shopPriceByRarity == null)
{
result = null;
return false;
}
for (int i = 0; i < rows.Count; i++)
return _shopPriceByRarity.TryGetValue(rarity, out result);
}
private static void EnsureShopPriceCache()
{
if (_shopPriceByRarity != null)
{
DRShopPrice row = rows[i];
if (row != null && row.Rarity == rarity)
{
result = row;
return true;
}
return;
}
return false;
DRShopPrice[] rows = CoreServiceHub.StaticData?.GetAllShopPrices();
if (rows == null)
{
return;
}
Dictionary<RarityType, DRShopPrice> shopPriceByRarity = new Dictionary<RarityType, DRShopPrice>();
for (int i = 0; i < rows.Length; i++)
{
DRShopPrice row = rows[i];
if (row == null)
{
continue;
}
shopPriceByRarity[row.Rarity] = row;
}
_shopPriceByRarity = shopPriceByRarity;
}
private static bool TryGetComponentById<TComp>(IReadOnlyList<TComp> components, long instanceId, out TComp result)
@@ -13,9 +13,9 @@ namespace GeometryTD.Core
private static Sprite _muzzleSprite;
private static Sprite _bearingSprite;
private static Sprite _baseSprite;
private static bool s_RequestedMuzzle;
private static bool s_RequestedBearing;
private static bool s_RequestedBase;
private static bool _requestedMuzzle;
private static bool _requestedBearing;
private static bool _requestedBase;
public static Sprite ResolveTowerIconSprite(
TowerItemData tower,
@@ -103,28 +103,23 @@ namespace GeometryTD.Core
private static void EnsureBaseSpritesRequested()
{
if (GameEntry.SpriteCache == null)
if (!_requestedMuzzle)
{
return;
_requestedMuzzle = true;
CoreServiceHub.SpriteCache.Get(MuzzleAssetName, sprite => { _muzzleSprite = sprite; });
}
if (!s_RequestedMuzzle)
if (!_requestedBearing)
{
s_RequestedMuzzle = true;
GameEntry.SpriteCache.GetSprite(MuzzleAssetName, sprite => { _muzzleSprite = sprite; });
_requestedBearing = true;
CoreServiceHub.SpriteCache.Get(BearingAssetName, sprite => { _bearingSprite = sprite; });
}
if (!s_RequestedBearing)
if (!_requestedBase)
{
s_RequestedBearing = true;
GameEntry.SpriteCache.GetSprite(BearingAssetName, sprite => { _bearingSprite = sprite; });
}
if (!s_RequestedBase)
{
s_RequestedBase = true;
GameEntry.SpriteCache.GetSprite(BaseAssetName, sprite => { _baseSprite = sprite; });
_requestedBase = true;
CoreServiceHub.SpriteCache.Get(BaseAssetName, sprite => { _baseSprite = sprite; });
}
}
}
}
}