Files
Cielonos/Assets/Scripts/MainGame/Characters/Base/Submodules/AttributeSubmodule.cs
SoulliesOfficial 649b7a5ddc 更新
2026-05-23 08:27:50 -04:00

152 lines
5.6 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System;
using System.Collections.Generic;
using UnityEngine;
namespace Cielonos.MainGame.Characters
{
public partial class AttributeSubmodule : SubmoduleBase<CharacterBase>
{
public AttributeGroup attributeGroup;
/// <summary>
/// 属性值变更回调表。Key 为属性名Value 为回调委托 (oldValue, newValue)。
/// 当属性值通过 indexer 或 RefreshAttribute 发生实际变化时自动触发。
/// </summary>
private readonly Dictionary<string, Action<float, float>> _onValueChanged = new();
/// <summary>
/// 当为 true 时,暂时不触发属性变更回调。
/// 用于批量修改属性时避免中间状态触发回调。
/// </summary>
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);
}
}
}
/// <summary>
/// 属性变更回调注册与触发
/// </summary>
public partial class AttributeSubmodule
{
/// <summary>
/// 为指定属性注册一个值变更回调。多次注册同一属性会追加委托。
/// </summary>
/// <param name="attributeName">属性名(使用 CharacterAttribute 常量)</param>
/// <param name="callback">回调委托,参数为 (oldValue, newValue)</param>
public void RegisterValueChangedCallback(string attributeName, Action<float, float> callback)
{
if (_onValueChanged.TryGetValue(attributeName, out var existing))
{
_onValueChanged[attributeName] = existing + callback;
}
else
{
_onValueChanged[attributeName] = callback;
}
}
/// <summary>
/// 为指定属性注销一个值变更回调。
/// </summary>
public void UnregisterValueChangedCallback(string attributeName, Action<float, float> callback)
{
if (_onValueChanged.TryGetValue(attributeName, out var existing))
{
var updated = existing - callback;
if (updated == null)
{
_onValueChanged.Remove(attributeName);
}
else
{
_onValueChanged[attributeName] = updated;
}
}
}
/// <summary>
/// 暂时挂起所有属性变更回调。调用 ResumeCallbacks 恢复。
/// 适用于批量初始化等不需要触发 UI 更新的场景。
/// </summary>
public void SuppressCallbacks() => _suppressCallbacks = true;
/// <summary>
/// 恢复属性变更回调触发。
/// </summary>
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);
}
}
}
}