using System; using System.Collections.Generic; using UnityEngine; namespace Cielonos.MainGame.Characters { public partial class AttributeSubmodule : SubmoduleBase { public AttributeGroup attributeGroup; /// /// 属性值变更回调表。Key 为属性名,Value 为回调委托 (oldValue, newValue)。 /// 当属性值通过 indexer 或 RefreshAttribute 发生实际变化时自动触发。 /// private readonly Dictionary> _onValueChanged = new(); /// /// 当为 true 时,暂时不触发属性变更回调。 /// 用于批量修改属性时避免中间状态触发回调。 /// private bool _suppressCallbacks; public bool Has(string attributeName) => attributeGroup.current.ContainsKey(attributeName); public float Get(string attributeName, float defaultValue) => attributeGroup.current.GetValueOrDefault(attributeName, defaultValue); public float this[string attributeName] { get => attributeGroup.current.GetValueOrDefault(attributeName, attributeName.Contains("Multiplier") ? 1 : 0); set { float oldValue = attributeGroup.current.GetValueOrDefault(attributeName, 0f); attributeGroup.current[attributeName] = value; if (!_suppressCallbacks && Math.Abs(oldValue - value) > float.Epsilon) { NotifyValueChanged(attributeName, oldValue, value); } } } public AttributeSubmodule(CharacterBase character) : base(character) { Initialize(character.attributeData); } public AttributeSubmodule(CharacterBase character, AttributeData attributeData) : base(character) { Initialize(attributeData); } private void Initialize(AttributeData attributeData) { attributeGroup = new AttributeGroup(attributeData.originalAttributes); attributeGroup.SetUpEndowments(attributeData.runtimeAttributes); } public void RefreshAttribute(string attributeName) { float oldValue = attributeGroup.current.GetValueOrDefault(attributeName, 0f); attributeGroup.ResetAttribute(attributeName); float numeric = 0; float pAccumulation = 0; float pMultiplication = 1; if (owner is Player player) { player.inventorySc.ApplyAttributeChange(attributeName, ref numeric, ref pAccumulation, ref pMultiplication); } owner.buffSm.ApplyAttributeChange(attributeName, ref numeric, ref pAccumulation, ref pMultiplication); attributeGroup.ModifyAttribute(attributeName, numeric, pAccumulation, pMultiplication); float newValue = attributeGroup.current.GetValueOrDefault(attributeName, 0f); if (!_suppressCallbacks && Math.Abs(oldValue - newValue) > float.Epsilon) { NotifyValueChanged(attributeName, oldValue, newValue); } } public void RefreshAllAttributes() { foreach (var attributeName in attributeGroup.original.Keys) { RefreshAttribute(attributeName); } } } /// /// 属性变更回调注册与触发 /// public partial class AttributeSubmodule { /// /// 为指定属性注册一个值变更回调。多次注册同一属性会追加委托。 /// /// 属性名(使用 CharacterAttribute 常量) /// 回调委托,参数为 (oldValue, newValue) public void RegisterValueChangedCallback(string attributeName, Action callback) { if (_onValueChanged.TryGetValue(attributeName, out var existing)) { _onValueChanged[attributeName] = existing + callback; } else { _onValueChanged[attributeName] = callback; } } /// /// 为指定属性注销一个值变更回调。 /// public void UnregisterValueChangedCallback(string attributeName, Action callback) { if (_onValueChanged.TryGetValue(attributeName, out var existing)) { var updated = existing - callback; if (updated == null) { _onValueChanged.Remove(attributeName); } else { _onValueChanged[attributeName] = updated; } } } /// /// 暂时挂起所有属性变更回调。调用 ResumeCallbacks 恢复。 /// 适用于批量初始化等不需要触发 UI 更新的场景。 /// public void SuppressCallbacks() => _suppressCallbacks = true; /// /// 恢复属性变更回调触发。 /// public void ResumeCallbacks() => _suppressCallbacks = false; private void NotifyValueChanged(string attributeName, float oldValue, float newValue) { if (_onValueChanged.TryGetValue(attributeName, out var callback)) { callback.Invoke(oldValue, newValue); } } } }