[Refactor] Replace enum-driven modifier system with data-driven SO composition
Replace the entire static, enum-based modifier pipeline with a composition-based, data-driven architecture using ScriptableObject polymorphism. New modifiers can now be created by assembling SO building blocks (Conditions + Effects + Behaviors) — no core code edits needed. New architecture: - Core/: TriggerType, ModifierPhase, ModifierContext, ICondition, IEffect - Definition/: ModifierDefinitionSO, ModifierBehaviorSO, ConditionSO, EffectSO, ModifierCatalogSO - Conditions/: DieValueCondition, CategoryCondition, MinScoreCondition, DiceCountCondition - Effects/: AddFlat, AddPerDie, Multiply, MultiplyPerDie, PostMultiply, AddCurrency, ConsumeCharge - Runtime/: ModifierInstance, ModifierRegistry (non-static service) - Pipeline/: async ModifierPipeline with phase ordering, tracing, anti-recursion - Editor/: ModifierDefinitionValidator with menu items - Events/: GameEventBus (non-static typed dispatcher) - DI/: GameLifetimeScope (VContainer composition root) Deleted old system: ModifierData, ModifierEffect, ModifierEnums, ModifierPipeline (static), ModifierRuntime, ModifierTarget, ShopCatalog, ModifierAssetCreator. Updated: ScoringSystem (VContainer + async), InventoryModel (delegates to ModifierRegistry), ShopModel (uses ModifierDefinitionSO), GameController (VContainer injection), SaveData (uses Runtime.ModifierSaveEntry), all views/controllers, and all test files. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,13 +1,15 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using VContainer;
|
||||
using YachtDice.Game;
|
||||
using YachtDice.Scoring;
|
||||
using YachtDice.Economy;
|
||||
using YachtDice.Shop;
|
||||
using YachtDice.Inventory;
|
||||
using YachtDice.Persistence;
|
||||
using YachtDice.Modifiers;
|
||||
using YachtDice.Modifiers.Definition;
|
||||
using YachtDice.Modifiers.Runtime;
|
||||
|
||||
namespace YachtDice.UI
|
||||
{
|
||||
@@ -43,9 +45,16 @@ namespace YachtDice.UI
|
||||
|
||||
private int totalCategoryCount;
|
||||
|
||||
private ModifierRegistry modifierRegistry;
|
||||
private InventoryModel inventoryModel;
|
||||
private ShopModel shopModel;
|
||||
|
||||
[Inject]
|
||||
public void Construct(ModifierRegistry modifierRegistry)
|
||||
{
|
||||
this.modifierRegistry = modifierRegistry;
|
||||
}
|
||||
|
||||
// ── Lifecycle ──────────────────────────────────────────────
|
||||
|
||||
private void Awake()
|
||||
@@ -70,7 +79,10 @@ namespace YachtDice.UI
|
||||
// Currency
|
||||
if (currencyBank != null)
|
||||
currencyBank.OnBalanceChanged += HandleCurrencyChanged;
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
InitializeModifierSystems();
|
||||
}
|
||||
|
||||
@@ -92,21 +104,26 @@ namespace YachtDice.UI
|
||||
if (currencyBank != null)
|
||||
currencyBank.OnBalanceChanged -= HandleCurrencyChanged;
|
||||
|
||||
if (inventoryModel != null)
|
||||
inventoryModel.OnInventoryChanged -= HandleInventoryChangedForSave;
|
||||
if (modifierRegistry != null)
|
||||
modifierRegistry.OnChanged -= HandleInventoryChangedForSave;
|
||||
}
|
||||
|
||||
// ── Modifier System Init ─────────────────────────────────
|
||||
|
||||
private void InitializeModifierSystems()
|
||||
{
|
||||
inventoryModel = new InventoryModel(maxActiveModifierSlots);
|
||||
inventoryModel.OnInventoryChanged += HandleInventoryChangedForSave;
|
||||
if (modifierRegistry == null)
|
||||
modifierRegistry = new ModifierRegistry(maxActiveModifierSlots);
|
||||
else
|
||||
modifierRegistry.SetMaxActiveSlots(maxActiveModifierSlots);
|
||||
|
||||
ShopCatalog catalog = shopController != null ? shopController.Catalog : null;
|
||||
modifierRegistry.OnChanged += HandleInventoryChangedForSave;
|
||||
|
||||
inventoryModel = new InventoryModel(modifierRegistry);
|
||||
|
||||
shopModel = new ShopModel(currencyBank, inventoryModel);
|
||||
|
||||
ModifierCatalogSO catalog = shopController != null ? shopController.Catalog : null;
|
||||
LoadSaveData(catalog);
|
||||
|
||||
if (inventoryController != null)
|
||||
@@ -119,7 +136,7 @@ namespace YachtDice.UI
|
||||
gameInfoView.SetCurrencyText(currencyBank.Balance);
|
||||
}
|
||||
|
||||
private void LoadSaveData(ShopCatalog catalog)
|
||||
private void LoadSaveData(ModifierCatalogSO catalog)
|
||||
{
|
||||
SaveData save = SaveSystem.Load();
|
||||
|
||||
@@ -128,35 +145,34 @@ namespace YachtDice.UI
|
||||
|
||||
if (catalog != null && save.OwnedModifiers.Count > 0)
|
||||
{
|
||||
var runtimeList = new List<ModifierRuntime>();
|
||||
var entries = new List<ModifierSaveEntry>();
|
||||
var permanentIds = new HashSet<string>();
|
||||
|
||||
for (int i = 0; i < save.OwnedModifiers.Count; i++)
|
||||
{
|
||||
var entry = save.OwnedModifiers[i];
|
||||
ModifierData data = catalog.FindById(entry.ModifierId);
|
||||
var oldEntry = save.OwnedModifiers[i];
|
||||
var def = catalog.FindById(oldEntry.ModifierId);
|
||||
|
||||
if (data == null)
|
||||
if (def == null)
|
||||
{
|
||||
Debug.LogWarning($"Modifier '{entry.ModifierId}' not found in catalog, skipping.");
|
||||
Debug.LogWarning($"Modifier '{oldEntry.ModifierId}' not found in catalog, skipping.");
|
||||
continue;
|
||||
}
|
||||
|
||||
var runtime = new ModifierRuntime
|
||||
entries.Add(new ModifierSaveEntry
|
||||
{
|
||||
ModifierId = entry.ModifierId,
|
||||
IsActive = entry.IsActive,
|
||||
RemainingUses = entry.RemainingUses,
|
||||
Data = data
|
||||
};
|
||||
ModifierId = oldEntry.ModifierId,
|
||||
IsActive = oldEntry.IsActive,
|
||||
RemainingUses = oldEntry.RemainingUses,
|
||||
Stacks = oldEntry.Stacks,
|
||||
CustomState = oldEntry.CustomState,
|
||||
});
|
||||
|
||||
runtimeList.Add(runtime);
|
||||
|
||||
if (data.Durability == ModifierDurability.Permanent)
|
||||
permanentIds.Add(data.Id);
|
||||
if (!def.HasLimitedUses)
|
||||
permanentIds.Add(def.Id);
|
||||
}
|
||||
|
||||
inventoryModel.LoadState(runtimeList);
|
||||
modifierRegistry.LoadSaveData(entries, catalog);
|
||||
shopModel.LoadPurchasedPermanentIds(permanentIds);
|
||||
}
|
||||
}
|
||||
@@ -168,15 +184,10 @@ namespace YachtDice.UI
|
||||
Currency = currencyBank != null ? currencyBank.Balance : 0
|
||||
};
|
||||
|
||||
var owned = inventoryModel.GetAllForSave();
|
||||
for (int i = 0; i < owned.Count; i++)
|
||||
var entries = modifierRegistry.GetSaveData();
|
||||
for (int i = 0; i < entries.Count; i++)
|
||||
{
|
||||
save.OwnedModifiers.Add(new ModifierSaveEntry
|
||||
{
|
||||
ModifierId = owned[i].ModifierId,
|
||||
IsActive = owned[i].IsActive,
|
||||
RemainingUses = owned[i].RemainingUses
|
||||
});
|
||||
save.OwnedModifiers.Add(entries[i]);
|
||||
}
|
||||
|
||||
SaveSystem.Save(save);
|
||||
|
||||
Reference in New Issue
Block a user