InventoryGenerationComponent + TagRegistryComponent 收口

This commit is contained in:
SepComet
2026-03-13 11:06:14 +08:00
parent 0c92fd9886
commit aa44170d56
23 changed files with 967 additions and 251 deletions
@@ -26,6 +26,8 @@ public partial class GameEntry
public static InventoryGenerationComponent InventoryGeneration { get; private set; }
public static TagRegistryComponent TagRegistry { get; private set; }
private static void InitCustomComponents()
{
BuiltinData = UnityGameFramework.Runtime.GameEntry.GetComponent<BuiltinDataComponent>();
@@ -38,5 +40,6 @@ public partial class GameEntry
ResolutionAdapter = UnityGameFramework.Runtime.GameEntry.GetComponent<ResolutionAdapterComponent>();
SpriteCache = UnityGameFramework.Runtime.GameEntry.GetComponent<SpriteCacheComponent>();
InventoryGeneration = UnityGameFramework.Runtime.GameEntry.GetComponent<InventoryGenerationComponent>();
TagRegistry = UnityGameFramework.Runtime.GameEntry.GetComponent<TagRegistryComponent>();
}
}
@@ -3,6 +3,7 @@ using GameFramework.DataTable;
using GeometryTD.DataTable;
using GeometryTD.Definition;
using UnityEngine;
using Random = System.Random;
namespace GeometryTD.CustomComponent
{
@@ -22,6 +23,7 @@ namespace GeometryTD.CustomComponent
public bool TryRollRow(
int displayPhaseIndex,
LevelThemeType themeType,
Random random,
out DROutGameDropPool selectedRow,
out RarityType selectedRarity)
{
@@ -40,7 +42,7 @@ namespace GeometryTD.CustomComponent
return false;
}
selectedRarity = RollRarity(displayPhaseIndex);
selectedRarity = RollRarity(displayPhaseIndex, random);
if (selectedRarity == RarityType.None)
{
return false;
@@ -71,7 +73,7 @@ namespace GeometryTD.CustomComponent
return false;
}
int randomWeight = Random.Range(1, totalWeight + 1);
int randomWeight = random.Next(1, totalWeight + 1);
int cumulativeWeight = 0;
foreach (var row in _eligibleRowBuffer)
{
@@ -127,7 +129,7 @@ namespace GeometryTD.CustomComponent
}
}
private RarityType RollRarity(int displayPhaseIndex)
private RarityType RollRarity(int displayPhaseIndex, Random random)
{
_rarityWeightBuffer.Clear();
float phaseT = Mathf.Clamp01((displayPhaseIndex - 1) / RarityCurveScalePhase);
@@ -178,7 +180,7 @@ namespace GeometryTD.CustomComponent
return RarityType.None;
}
float randomWeight = Random.value * totalWeight;
float randomWeight = (float)(random.NextDouble() * totalWeight);
float cumulativeWeight = 0f;
foreach (var pair in _rarityWeightBuffer)
{
@@ -1,4 +1,3 @@
using System;
using System.Collections.Generic;
using GameFramework.DataTable;
using GeometryTD.DataTable;
@@ -7,21 +6,16 @@ using GeometryTD.Factory;
using GeometryTD.UI;
using UnityEngine;
using UnityGameFramework.Runtime;
using Random = UnityEngine.Random;
using Random = System.Random;
namespace GeometryTD.CustomComponent
{
public sealed class InventoryGenerationComponent : GameFrameworkComponent
{
private const float DropChanceBase = 0.05f;
private const float DropChancePerPhase = 0.2f;
private const float DropChanceCap = 0.2f;
private long _nextTempInstanceId = 1000000;
private int _runSeed;
private int _nodeSequenceIndex = -1;
private int _nextDropTagOrdinal;
private int _nextRewardTagOrdinal;
private int _nextDropOrdinal;
private int _nextRewardOrdinal;
private readonly List<DRShopPrice> _shopPriceRows = new();
private IDataTable<DRShopPrice> _shopPriceTable;
@@ -32,19 +26,20 @@ namespace GeometryTD.CustomComponent
private ShopGoodsBuilder _shopGoodsBuilder;
private DropPoolRoller _dropPoolRoller;
private RewardCandidateBuilder _rewardCandidateBuilder;
private OutGameDropItemBuilder _outGameDropItemBuilder;
public void ConfigureRunContext(int runSeed, int sequenceIndex)
{
_runSeed = runSeed;
_nodeSequenceIndex = sequenceIndex;
_nextDropTagOrdinal = 0;
_nextRewardTagOrdinal = 0;
_nextDropOrdinal = 0;
_nextRewardOrdinal = 0;
}
public List<GoodsItemRawData> BuildShopGoods(int goodsCount, int runSeed = 0, int sequenceIndex = -1)
{
EnsureShopBuilder();
return _shopGoodsBuilder.BuildGoods(goodsCount, runSeed, sequenceIndex, AllocateTempInstanceId);
return _shopGoodsBuilder.BuildGoods(goodsCount, runSeed, sequenceIndex);
}
public EnemyDropResult ResolveEnemyDrop(in EnemyDropContext context)
@@ -61,14 +56,24 @@ namespace GeometryTD.CustomComponent
? Mathf.Clamp01(enemy.DropPercent * 0.01f)
: Mathf.Clamp01(enemy.DropPercent);
if (enemy.DropGold > 0 && dropRate > 0f && Random.value <= dropRate)
int dropOrdinal = AllocateDropOrdinal();
InventoryGenerationRandomContext randomContext =
new(_runSeed, _nodeSequenceIndex, InventoryTagSourceType.Drop, dropOrdinal);
Random random = randomContext.CreateRandom();
if (enemy.DropGold > 0 && dropRate > 0f && random.NextDouble() <= dropRate)
{
gold = Mathf.Max(0, enemy.DropGold);
}
TowerCompItemData lootItem = null;
if (ShouldRollOutGameItem(context.DisplayPhaseIndex) &&
TryRollOutGameItem(context.DisplayPhaseIndex, context.ThemeType, out TowerCompItemData droppedItem))
if (OutGameDropRuleService.ShouldRollOutGameItem(context.DisplayPhaseIndex, random) &&
TryRollOutGameItem(
context.DisplayPhaseIndex,
context.ThemeType,
randomContext,
random,
out TowerCompItemData droppedItem))
{
lootItem = droppedItem;
}
@@ -86,6 +91,7 @@ namespace GeometryTD.CustomComponent
displayPhaseIndex,
themeType,
candidateCount,
CreateNextRewardRandomContext,
BuildRewardCandidateItem);
}
@@ -99,7 +105,7 @@ namespace GeometryTD.CustomComponent
if (_shopPriceTable == null || _muzzleCompTable == null || _bearingCompTable == null ||
_baseCompTable == null)
{
throw new InvalidOperationException(
throw new System.InvalidOperationException(
"InventoryGenerationComponent requires ShopPrice, MuzzleComp, BearingComp, and BaseComp data tables.");
}
@@ -111,7 +117,7 @@ namespace GeometryTD.CustomComponent
DRShopPrice[] rows = _shopPriceTable.GetAllDataRows();
if (rows == null || rows.Length <= 0)
{
throw new InvalidOperationException(
throw new System.InvalidOperationException(
"InventoryGenerationComponent requires at least one shop price row.");
}
@@ -125,7 +131,7 @@ namespace GeometryTD.CustomComponent
if (_shopPriceRows.Count <= 0)
{
throw new InvalidOperationException("InventoryGenerationComponent requires non-null shop price rows.");
throw new System.InvalidOperationException("InventoryGenerationComponent requires non-null shop price rows.");
}
}
@@ -139,11 +145,6 @@ namespace GeometryTD.CustomComponent
_baseCompTable);
}
private long AllocateTempInstanceId()
{
return _nextTempInstanceId++;
}
private void EnsureDropTables()
{
_dropPoolTable ??= GameEntry.DataTable.GetDataTable<DROutGameDropPool>();
@@ -153,7 +154,7 @@ namespace GeometryTD.CustomComponent
if (_dropPoolTable == null || _muzzleCompTable == null || _bearingCompTable == null || _baseCompTable == null)
{
throw new InvalidOperationException(
throw new System.InvalidOperationException(
"InventoryGenerationComponent requires OutGameDropPool, MuzzleComp, BearingComp, and BaseComp data tables.");
}
}
@@ -171,14 +172,22 @@ namespace GeometryTD.CustomComponent
return _rewardCandidateBuilder;
}
private static bool ShouldRollOutGameItem(int displayPhaseIndex)
private OutGameDropItemBuilder EnsureOutGameDropItemBuilder()
{
int phaseIndex = Mathf.Max(1, displayPhaseIndex);
float dropChance = Mathf.Clamp(DropChanceBase + (phaseIndex - 1) * DropChancePerPhase, 0f, DropChanceCap);
return Random.value <= dropChance;
EnsureDropTables();
_outGameDropItemBuilder ??= new OutGameDropItemBuilder(
_muzzleCompTable,
_bearingCompTable,
_baseCompTable);
return _outGameDropItemBuilder;
}
private bool TryRollOutGameItem(int displayPhaseIndex, LevelThemeType themeType, out TowerCompItemData droppedItem)
private bool TryRollOutGameItem(
int displayPhaseIndex,
LevelThemeType themeType,
InventoryGenerationRandomContext randomContext,
Random random,
out TowerCompItemData droppedItem)
{
droppedItem = null;
DropPoolRoller dropPoolRoller = EnsureDropPoolRoller();
@@ -186,120 +195,46 @@ namespace GeometryTD.CustomComponent
if (!dropPoolRoller.TryRollRow(
phaseIndex,
themeType,
random,
out DROutGameDropPool selectedRow,
out RarityType selectedRarity) || selectedRow == null)
{
return false;
}
return TryBuildDropItem(
selectedRow,
selectedRarity,
InventoryTagSourceType.Drop,
AllocateDropTagOrdinal(),
out droppedItem);
return EnsureOutGameDropItemBuilder().TryBuildItem(selectedRow, selectedRarity, randomContext, out droppedItem);
}
private bool TryBuildDropItem(
private int AllocateDropOrdinal()
{
return _nextDropOrdinal++;
}
private int AllocateRewardOrdinal()
{
return _nextRewardOrdinal++;
}
private InventoryGenerationRandomContext CreateNextRewardRandomContext()
{
return new InventoryGenerationRandomContext(
_runSeed,
_nodeSequenceIndex,
InventoryTagSourceType.Reward,
AllocateRewardOrdinal());
}
private TowerCompItemData BuildRewardCandidateItem(
DROutGameDropPool row,
RarityType rarity,
InventoryTagSourceType sourceType,
int localOrdinal,
out TowerCompItemData droppedItem)
InventoryGenerationRandomContext randomContext)
{
droppedItem = null;
if (row.ItemId <= 0 || string.IsNullOrWhiteSpace(row.ItemType))
{
return false;
}
string itemType = row.ItemType.Trim();
if (itemType.Equals("MuzzleComp", StringComparison.OrdinalIgnoreCase))
{
DRMuzzleComp config = _muzzleCompTable.GetDataRow(row.ItemId);
if (config == null)
{
return false;
}
droppedItem = ComponentItemFactory.CreateMuzzle(
config,
AllocateTempInstanceId(),
rarity,
CreateRandomContext(sourceType, localOrdinal, config.Id));
return true;
}
if (itemType.Equals("BearingComp", StringComparison.OrdinalIgnoreCase))
{
DRBearingComp config = _bearingCompTable.GetDataRow(row.ItemId);
if (config == null)
{
return false;
}
droppedItem = ComponentItemFactory.CreateBearing(
config,
AllocateTempInstanceId(),
rarity,
CreateRandomContext(sourceType, localOrdinal, config.Id));
return true;
}
if (itemType.Equals("BaseComp", StringComparison.OrdinalIgnoreCase))
{
DRBaseComp config = _baseCompTable.GetDataRow(row.ItemId);
if (config == null)
{
return false;
}
droppedItem = ComponentItemFactory.CreateBase(
config,
AllocateTempInstanceId(),
rarity,
CreateRandomContext(sourceType, localOrdinal, config.Id));
return true;
}
return false;
}
private int AllocateDropTagOrdinal()
{
return _nextDropTagOrdinal++;
}
private int AllocateRewardTagOrdinal()
{
return _nextRewardTagOrdinal++;
}
private TowerCompItemData BuildRewardCandidateItem(DROutGameDropPool row, RarityType rarity)
{
if (!TryBuildDropItem(
row,
rarity,
InventoryTagSourceType.Reward,
AllocateRewardTagOrdinal(),
out TowerCompItemData droppedItem))
if (!EnsureOutGameDropItemBuilder().TryBuildItem(row, rarity, randomContext, out TowerCompItemData droppedItem))
{
return null;
}
return droppedItem;
}
private InventoryTagRandomContext CreateRandomContext(
InventoryTagSourceType sourceType,
int localOrdinal,
int configId)
{
return sourceType switch
{
InventoryTagSourceType.Reward => InventoryTagRandomContext.CreateReward(_runSeed, _nodeSequenceIndex, localOrdinal, configId),
_ => InventoryTagRandomContext.CreateDrop(_runSeed, _nodeSequenceIndex, localOrdinal, configId)
};
}
}
}
@@ -0,0 +1,64 @@
using System;
using Random = System.Random;
namespace GeometryTD.Definition
{
public readonly struct InventoryGenerationRandomContext
{
public InventoryGenerationRandomContext(
int runSeed,
int nodeSequenceIndex,
InventoryTagSourceType sourceType,
int localOrdinal)
{
RunSeed = runSeed;
NodeSequenceIndex = nodeSequenceIndex;
SourceType = sourceType;
LocalOrdinal = localOrdinal;
}
public int RunSeed { get; }
public int NodeSequenceIndex { get; }
public InventoryTagSourceType SourceType { get; }
public int LocalOrdinal { get; }
public Random CreateRandom()
{
return new Random(BuildSeed());
}
public long CreateStableItemInstanceId()
{
long normalizedSource = ((long)Math.Max(0, (int)SourceType) + 1L) << 48;
long normalizedSequence = ((long)Math.Max(0, NodeSequenceIndex) + 1L) << 24;
long normalizedOrdinal = (uint)(Math.Max(0, LocalOrdinal) + 1);
return normalizedSource | normalizedSequence | normalizedOrdinal;
}
public InventoryTagRandomContext CreateTagRandomContext(int configId)
{
return SourceType switch
{
InventoryTagSourceType.Shop => InventoryTagRandomContext.CreateShop(RunSeed, NodeSequenceIndex, LocalOrdinal, configId),
InventoryTagSourceType.Reward => InventoryTagRandomContext.CreateReward(RunSeed, NodeSequenceIndex, LocalOrdinal, configId),
_ => InventoryTagRandomContext.CreateDrop(RunSeed, NodeSequenceIndex, LocalOrdinal, configId)
};
}
private int BuildSeed()
{
unchecked
{
int seed = 17;
seed = seed * 31 + RunSeed;
seed = seed * 31 + NodeSequenceIndex;
seed = seed * 31 + (int)SourceType;
seed = seed * 31 + LocalOrdinal;
return seed;
}
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 95b2ab672a7049ef9356a90d87baca50
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,19 @@
using UnityEngine;
using Random = System.Random;
namespace GeometryTD.CustomComponent
{
public static class OutGameDropRuleService
{
private const float DropChanceBase = 0.05f;
private const float DropChancePerPhase = 0.2f;
private const float DropChanceCap = 0.2f;
public static bool ShouldRollOutGameItem(int displayPhaseIndex, Random random)
{
int phaseIndex = Mathf.Max(1, displayPhaseIndex);
float dropChance = Mathf.Clamp(DropChanceBase + (phaseIndex - 1) * DropChancePerPhase, 0f, DropChanceCap);
return random.NextDouble() <= dropChance;
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 519549c7542f40efabf83a2b1b2dff44
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using GeometryTD.DataTable;
using GeometryTD.Definition;
using UnityEngine;
using Random = System.Random;
namespace GeometryTD.CustomComponent
{
@@ -19,7 +20,8 @@ namespace GeometryTD.CustomComponent
int displayPhaseIndex,
LevelThemeType themeType,
int candidateCount,
Func<DROutGameDropPool, RarityType, TowerCompItemData> buildRewardItem)
Func<InventoryGenerationRandomContext> createRandomContext,
Func<DROutGameDropPool, RarityType, InventoryGenerationRandomContext, TowerCompItemData> buildRewardItem)
{
int resolvedCount = Mathf.Max(0, candidateCount);
if (resolvedCount <= 0)
@@ -36,9 +38,12 @@ namespace GeometryTD.CustomComponent
while (candidates.Count < resolvedCount && attempts < maxAttempts)
{
attempts++;
InventoryGenerationRandomContext randomContext = createRandomContext();
Random random = randomContext.CreateRandom();
if (!_dropPoolRoller.TryRollRow(
phaseIndex,
themeType,
random,
out DROutGameDropPool selectedRow,
out RarityType selectedRarity) || selectedRow == null)
{
@@ -50,7 +55,7 @@ namespace GeometryTD.CustomComponent
continue;
}
TowerCompItemData candidate = buildRewardItem(selectedRow, selectedRarity);
TowerCompItemData candidate = buildRewardItem(selectedRow, selectedRarity, randomContext);
if (candidate == null)
{
continue;
@@ -63,16 +68,19 @@ namespace GeometryTD.CustomComponent
while (candidates.Count < resolvedCount && attempts < maxAttempts)
{
attempts++;
InventoryGenerationRandomContext randomContext = createRandomContext();
Random random = randomContext.CreateRandom();
if (!_dropPoolRoller.TryRollRow(
phaseIndex,
themeType,
random,
out DROutGameDropPool selectedRow,
out RarityType selectedRarity) || selectedRow == null)
{
break;
}
TowerCompItemData candidate = buildRewardItem(selectedRow, selectedRarity);
TowerCompItemData candidate = buildRewardItem(selectedRow, selectedRarity, randomContext);
if (candidate == null)
{
continue;
@@ -7,6 +7,7 @@ using GeometryTD.Definition;
using GeometryTD.Factory;
using GeometryTD.UI;
using UnityEngine;
using Random = System.Random;
namespace GeometryTD.CustomComponent
{
@@ -32,8 +33,7 @@ namespace GeometryTD.CustomComponent
public List<GoodsItemRawData> BuildGoods(
int goodsCount,
int runSeed,
int sequenceIndex,
Func<long> allocateInstanceId)
int sequenceIndex)
{
if (goodsCount <= 0)
{
@@ -43,7 +43,9 @@ namespace GeometryTD.CustomComponent
List<GoodsItemRawData> goodsItems = new(goodsCount);
for (int i = 0; i < goodsCount; i++)
{
goodsItems.Add(BuildGoodsItem(i, runSeed, sequenceIndex, allocateInstanceId));
InventoryGenerationRandomContext randomContext =
new(runSeed, sequenceIndex, InventoryTagSourceType.Shop, i);
goodsItems.Add(BuildGoodsItem(i, randomContext));
}
return goodsItems;
@@ -51,18 +53,17 @@ namespace GeometryTD.CustomComponent
private GoodsItemRawData BuildGoodsItem(
int goodsIndex,
int runSeed,
int sequenceIndex,
Func<long> allocateInstanceId)
InventoryGenerationRandomContext randomContext)
{
TowerCompItemData sourceItem = BuildRandomComponentItem(goodsIndex, runSeed, sequenceIndex, allocateInstanceId);
Random random = randomContext.CreateRandom();
TowerCompItemData sourceItem = BuildRandomComponentItem(randomContext, random);
return new GoodsItemRawData
{
GoodsIndex = goodsIndex,
Title = sourceItem.Name,
TypeText = BuildTypeText(sourceItem.SlotType),
Description = BuildDescription(sourceItem),
Price = ResolveRandomPrice(sourceItem.Rarity),
Price = ResolveRandomPrice(sourceItem.Rarity, random),
Tags = sourceItem.Tags != null ? (TagType[])sourceItem.Tags.Clone() : Array.Empty<TagType>(),
IconAreaContext = BuildIconAreaContext(sourceItem),
SourceItem = sourceItem,
@@ -71,70 +72,56 @@ namespace GeometryTD.CustomComponent
}
private TowerCompItemData BuildRandomComponentItem(
int goodsIndex,
int runSeed,
int sequenceIndex,
Func<long> allocateInstanceId)
InventoryGenerationRandomContext randomContext,
Random random)
{
int slotRoll = UnityEngine.Random.Range(0, 3);
DRShopPrice priceRow = _shopPriceRows[UnityEngine.Random.Range(0, _shopPriceRows.Count)];
int slotRoll = random.Next(0, 3);
DRShopPrice priceRow = _shopPriceRows[random.Next(0, _shopPriceRows.Count)];
RarityType rarity = InventoryRarityRuleService.NormalizeComponentRarity(
priceRow != null ? priceRow.Rarity : RarityType.White);
return slotRoll switch
{
0 => BuildRandomMuzzleItem(rarity, goodsIndex, runSeed, sequenceIndex, allocateInstanceId),
1 => BuildRandomBearingItem(rarity, goodsIndex, runSeed, sequenceIndex, allocateInstanceId),
_ => BuildRandomBaseItem(rarity, goodsIndex, runSeed, sequenceIndex, allocateInstanceId)
0 => BuildRandomMuzzleItem(rarity, randomContext, random),
1 => BuildRandomBearingItem(rarity, randomContext, random),
_ => BuildRandomBaseItem(rarity, randomContext, random)
};
}
private MuzzleCompItemData BuildRandomMuzzleItem(
RarityType rarity,
int goodsIndex,
int runSeed,
int sequenceIndex,
Func<long> allocateInstanceId)
InventoryGenerationRandomContext randomContext,
Random random)
{
DRMuzzleComp[] rows = _muzzleCompTable.GetAllDataRows();
DRMuzzleComp config = rows[UnityEngine.Random.Range(0, rows.Length)];
long instanceId = allocateInstanceId();
InventoryTagRandomContext randomContext =
InventoryTagRandomContext.CreateShop(runSeed, sequenceIndex, goodsIndex, config.Id);
return ComponentItemFactory.CreateMuzzle(config, instanceId, rarity, randomContext);
DRMuzzleComp config = rows[random.Next(0, rows.Length)];
long instanceId = randomContext.CreateStableItemInstanceId();
return ComponentItemFactory.CreateMuzzle(config, instanceId, rarity, randomContext.CreateTagRandomContext(config.Id));
}
private BearingCompItemData BuildRandomBearingItem(
RarityType rarity,
int goodsIndex,
int runSeed,
int sequenceIndex,
Func<long> allocateInstanceId)
InventoryGenerationRandomContext randomContext,
Random random)
{
DRBearingComp[] rows = _bearingCompTable.GetAllDataRows();
DRBearingComp config = rows[UnityEngine.Random.Range(0, rows.Length)];
long instanceId = allocateInstanceId();
InventoryTagRandomContext randomContext =
InventoryTagRandomContext.CreateShop(runSeed, sequenceIndex, goodsIndex, config.Id);
return ComponentItemFactory.CreateBearing(config, instanceId, rarity, randomContext);
DRBearingComp config = rows[random.Next(0, rows.Length)];
long instanceId = randomContext.CreateStableItemInstanceId();
return ComponentItemFactory.CreateBearing(config, instanceId, rarity, randomContext.CreateTagRandomContext(config.Id));
}
private BaseCompItemData BuildRandomBaseItem(
RarityType rarity,
int goodsIndex,
int runSeed,
int sequenceIndex,
Func<long> allocateInstanceId)
InventoryGenerationRandomContext randomContext,
Random random)
{
DRBaseComp[] rows = _baseCompTable.GetAllDataRows();
DRBaseComp config = rows[UnityEngine.Random.Range(0, rows.Length)];
long instanceId = allocateInstanceId();
InventoryTagRandomContext randomContext =
InventoryTagRandomContext.CreateShop(runSeed, sequenceIndex, goodsIndex, config.Id);
return ComponentItemFactory.CreateBase(config, instanceId, rarity, randomContext);
DRBaseComp config = rows[random.Next(0, rows.Length)];
long instanceId = randomContext.CreateStableItemInstanceId();
return ComponentItemFactory.CreateBase(config, instanceId, rarity, randomContext.CreateTagRandomContext(config.Id));
}
private int ResolveRandomPrice(RarityType rarity)
private int ResolveRandomPrice(RarityType rarity, Random random)
{
for (int i = 0; i < _shopPriceRows.Count; i++)
{
@@ -143,7 +130,7 @@ namespace GeometryTD.CustomComponent
{
int min = Mathf.Max(0, row.MinPrice);
int max = Mathf.Max(min, row.MaxPrice);
return UnityEngine.Random.Range(min, max + 1);
return random.Next(min, max + 1);
}
}
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 523d63397a9c41fdaaf238bfb0e95357
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,64 @@
using System;
using GameFramework.DataTable;
using GeometryTD.DataTable;
using GeometryTD.Definition;
using UnityGameFramework.Runtime;
namespace GeometryTD.CustomComponent
{
public sealed class TagRegistryComponent : GameFrameworkComponent
{
private IDataTable<DRTagConfig> _tagConfigTable;
private IDataTable<DRTag> _tagTable;
private IDataTable<DRRarityTagBudget> _rarityTagBudgetTable;
public void OnInit()
{
ReloadAllFromLoadedTables();
}
public void ReloadAllFromLoadedTables()
{
ReloadTagDefinitionsAndGenerationFromLoadedTables();
ReloadRarityTagBudgetFromLoadedTable();
}
public void ReloadTagDefinitionsAndGenerationFromLoadedTables()
{
EnsureTagDefinitionTables();
DRTagConfig[] tagConfigRows = _tagConfigTable.GetAllDataRows();
DRTag[] tagRows = _tagTable.GetAllDataRows();
TagGenerationRuleRegistry.LoadFromRows(tagRows);
TagDefinitionRegistry.ReloadFromRows(tagConfigRows, tagRows);
}
public void ReloadRarityTagBudgetFromLoadedTable()
{
EnsureRarityTagBudgetTable();
RarityTagBudgetRuleRegistry.LoadFromRows(_rarityTagBudgetTable.GetAllDataRows());
}
private void EnsureTagDefinitionTables()
{
_tagConfigTable ??= GameEntry.DataTable.GetDataTable<DRTagConfig>();
_tagTable ??= GameEntry.DataTable.GetDataTable<DRTag>();
if (_tagConfigTable == null || _tagTable == null)
{
throw new InvalidOperationException(
"TagRegistryComponent requires TagConfig and Tag data tables to be loaded before initialization.");
}
}
private void EnsureRarityTagBudgetTable()
{
_rarityTagBudgetTable ??= GameEntry.DataTable.GetDataTable<DRRarityTagBudget>();
if (_rarityTagBudgetTable == null)
{
throw new InvalidOperationException(
"TagRegistryComponent requires RarityTagBudget data table to be loaded before initialization.");
}
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a268c57d4373494ab9b4d7167099f170
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,88 @@
using System;
using GameFramework.DataTable;
using GeometryTD.DataTable;
using GeometryTD.Definition;
namespace GeometryTD.Factory
{
public sealed class OutGameDropItemBuilder
{
private readonly IDataTable<DRMuzzleComp> _muzzleCompTable;
private readonly IDataTable<DRBearingComp> _bearingCompTable;
private readonly IDataTable<DRBaseComp> _baseCompTable;
public OutGameDropItemBuilder(
IDataTable<DRMuzzleComp> muzzleCompTable,
IDataTable<DRBearingComp> bearingCompTable,
IDataTable<DRBaseComp> baseCompTable)
{
_muzzleCompTable = muzzleCompTable;
_bearingCompTable = bearingCompTable;
_baseCompTable = baseCompTable;
}
public bool TryBuildItem(
DROutGameDropPool row,
RarityType rarity,
InventoryGenerationRandomContext randomContext,
out TowerCompItemData droppedItem)
{
droppedItem = null;
if (row.ItemId <= 0 || string.IsNullOrWhiteSpace(row.ItemType))
{
return false;
}
string itemType = row.ItemType.Trim();
if (itemType.Equals("MuzzleComp", StringComparison.OrdinalIgnoreCase))
{
DRMuzzleComp config = _muzzleCompTable.GetDataRow(row.ItemId);
if (config == null)
{
return false;
}
droppedItem = ComponentItemFactory.CreateMuzzle(
config,
randomContext.CreateStableItemInstanceId(),
rarity,
randomContext.CreateTagRandomContext(config.Id));
return true;
}
if (itemType.Equals("BearingComp", StringComparison.OrdinalIgnoreCase))
{
DRBearingComp config = _bearingCompTable.GetDataRow(row.ItemId);
if (config == null)
{
return false;
}
droppedItem = ComponentItemFactory.CreateBearing(
config,
randomContext.CreateStableItemInstanceId(),
rarity,
randomContext.CreateTagRandomContext(config.Id));
return true;
}
if (itemType.Equals("BaseComp", StringComparison.OrdinalIgnoreCase))
{
DRBaseComp config = _baseCompTable.GetDataRow(row.ItemId);
if (config == null)
{
return false;
}
droppedItem = ComponentItemFactory.CreateBase(
config,
randomContext.CreateStableItemInstanceId(),
rarity,
randomContext.CreateTagRandomContext(config.Id));
return true;
}
return false;
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c5915901f51c430db50725908113ae1a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -196,45 +196,6 @@ namespace GeometryTD.Procedure
_loadedFlag[ne.DataTableAssetName] = true;
Log.Info("Load data table '{0}' OK.", ne.DataTableAssetName);
if (ne.DataTableAssetName == AssetUtility.GetDataTableAsset("TagConfig", false))
{
ReloadTagRegistriesFromLoadedTables();
}
if (ne.DataTableAssetName == AssetUtility.GetDataTableAsset("Tag", false))
{
ReloadTagRegistriesFromLoadedTables();
}
if (ne.DataTableAssetName == AssetUtility.GetDataTableAsset("RarityTagBudget", false))
{
var tagBudgetTable = GameEntry.DataTable.GetDataTable<DRRarityTagBudget>();
if (tagBudgetTable != null)
{
RarityTagBudgetRuleRegistry.LoadFromRows(tagBudgetTable.GetAllDataRows());
}
}
}
private static void ReloadTagRegistriesFromLoadedTables()
{
DRTagConfig[] tagConfigRows = null;
var tagConfigTable = GameEntry.DataTable.GetDataTable<DRTagConfig>();
if (tagConfigTable != null)
{
tagConfigRows = tagConfigTable.GetAllDataRows();
}
DRTag[] tagRows = null;
var tagTable = GameEntry.DataTable.GetDataTable<DRTag>();
if (tagTable != null)
{
tagRows = tagTable.GetAllDataRows();
TagGenerationRuleRegistry.LoadFromRows(tagRows);
}
TagDefinitionRegistry.ReloadFromRows(tagConfigRows, tagRows);
}
private void OnLoadDataTableFailure(object sender, GameEventArgs e)
@@ -34,6 +34,7 @@ namespace GeometryTD.Procedure
GameEntry.Event.Subscribe(NodeEnterEventArgs.EventId, OnNodeEnter);
GameEntry.Event.Subscribe(NodeMapNodeEnterRequestedEventArgs.EventId, OnNodeMapNodeEnterRequested);
GameEntry.TagRegistry.OnInit();
GameEntry.EventNode.OnInit();
GameEntry.CombatNode.OnInit(LevelThemeType.Plain);
GameEntry.ShopNode.OnInit();
@@ -2,7 +2,6 @@ using System;
using System.Collections.Generic;
using GeometryTD.Definition;
using UnityEngine;
using Random = UnityEngine.Random;
namespace GeometryTD.UI
{
@@ -19,6 +18,7 @@ namespace GeometryTD.UI
private bool _allowRefreshOnce = true;
private bool _allowGiveUp = true;
private bool _hasRefreshed;
private int _selectionOffset;
private string _tipText = "Select one reward";
public void ConfigureRewardPool(
@@ -49,6 +49,7 @@ namespace GeometryTD.UI
_allowGiveUp = allowGiveUp;
_tipText = string.IsNullOrWhiteSpace(tipText) ? "Select one reward" : tipText;
_hasRefreshed = false;
_selectionOffset = 0;
_currentModel = null;
}
@@ -80,6 +81,7 @@ namespace GeometryTD.UI
_allowGiveUp = allowGiveUp;
_tipText = string.IsNullOrWhiteSpace(tipText) ? "Select one reward" : tipText;
_hasRefreshed = false;
_selectionOffset = 0;
_currentModel = null;
}
@@ -115,6 +117,11 @@ namespace GeometryTD.UI
}
_hasRefreshed = true;
if (_rewardPool.Count > 0)
{
_selectionOffset = (_selectionOffset + _displayCount) % _rewardPool.Count;
}
_currentModel = BuildModel();
return _currentModel;
}
@@ -172,22 +179,11 @@ namespace GeometryTD.UI
}
int finalCount = Mathf.Clamp(_displayCount, 1, _rewardPool.Count);
int[] indexes = new int[_rewardPool.Count];
for (int i = 0; i < indexes.Length; i++)
{
indexes[i] = i;
}
for (int i = 0; i < finalCount; i++)
{
int randomIndex = Random.Range(i, indexes.Length);
(indexes[i], indexes[randomIndex]) = (indexes[randomIndex], indexes[i]);
}
RewardSelectItemRawData[] results = new RewardSelectItemRawData[finalCount];
for (int i = 0; i < finalCount; i++)
{
RewardSelectItemRawData source = _rewardPool[indexes[i]];
int sourceIndex = (_selectionOffset + i) % _rewardPool.Count;
RewardSelectItemRawData source = _rewardPool[sourceIndex];
results[i] = source;
}