mirror of
http://47.107.252.169:3000/Roguelite-Game-Developing-Team/Gen_Hack-and-Slash-Roguelite.git
synced 2025-11-20 05:37:11 +08:00
Co-authored-by: m0_75251201 <m0_75251201@noreply.gitcode.com> Reviewed-on: http://47.107.252.169:3000/Roguelite-Game-Developing-Team/Gen_Hack-and-Slash-Roguelite/pulls/60
197 lines
9.4 KiB
C#
197 lines
9.4 KiB
C#
using System;
|
||
using Data;
|
||
using Entity;
|
||
using Newtonsoft.Json;
|
||
using Parsing;
|
||
|
||
namespace HediffComps
|
||
{
|
||
/// <summary>
|
||
/// 健康状态组件:在特定条件下为实体提供属性偏移量。
|
||
/// 当条件满足时,该组件会提供预设的 <see cref="AttributesOffsetDef" />;否则提供一个所有值为零的空偏移量。
|
||
/// </summary>
|
||
public class HediffComp_ApplyAttributesOffset : HediffComp, IAttributesOffsetProvider
|
||
{
|
||
// 不活跃时返回的空属性偏移量 (所有字段为0)。这是一个只读字段,在构造时已初始化,因此永远不需要空检查。
|
||
private readonly AttributesOffsetDef emptyOffset = new();
|
||
|
||
private AttributesOffsetDef cachedActiveOffset; // 当活跃时返回的实际属性偏移量
|
||
private Func<Entity.Entity, bool> condition; // 评估条件的委托
|
||
private PropertiesConfig config; // 从 JSON 反序列化得到的配置
|
||
private bool isActive; // 当前属性偏移是否活跃(即条件是否满足)
|
||
|
||
/// <summary>
|
||
/// 获取此提供者当前的属性偏移量定义。
|
||
/// 实现 <see cref="IAttributesOffsetProvider" /> 接口。
|
||
/// </summary>
|
||
/// <returns>此提供者所带来的属性偏移量。</returns>
|
||
public AttributesOffsetDef GetAttributesOffset()
|
||
{
|
||
// 如果组件活跃,则返回实际的属性偏移量;否则返回一个空的(所有值为零)的偏移量。
|
||
// cachedActiveOffset 在 Initialize 时已保证非 null,emptyOffset 是 readonly 字段并已初始化,因此不需空检查。
|
||
return isActive ? cachedActiveOffset : emptyOffset;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 组件初始化时调用,在构造函数之后。
|
||
/// 负责解析 <see cref="HediffCompDef.properties" /> 中的 JSON 配置,并创建条件委托。
|
||
/// </summary>
|
||
/// <param name="parentHediff">父级 Hediff 实例。</param>
|
||
/// <param name="def">组件定义。</param>
|
||
/// <exception cref="ArgumentNullException">当 <paramref name="def.properties" /> 为空或 null 时抛出。</exception>
|
||
/// <exception cref="JsonException">当 JSON 反序列化失败时抛出。</exception>
|
||
/// <exception cref="InvalidOperationException">当配置对象、条件表达式或偏移定义为 null 时抛出。</exception>
|
||
/// <exception cref="Exception">当条件委托创建失败时抛出(包装原始异常)。</exception>
|
||
public override void Initialize(Hediff parentHediff, HediffCompDef def)
|
||
{
|
||
base.Initialize(parentHediff, def);
|
||
|
||
// 检查配置 JSON 字符串是否为空或 null
|
||
if (string.IsNullOrEmpty(def.properties))
|
||
throw new ArgumentNullException(nameof(def.properties),
|
||
$"HediffComp_ApplyAttributesOffset ({def.defName}) requires configuration in HediffCompDef.properties.");
|
||
|
||
// 反序列化配置 JSON 字符串到 PropertiesConfig 对象
|
||
try
|
||
{
|
||
config = JsonConvert.DeserializeObject<PropertiesConfig>(def.properties);
|
||
}
|
||
catch (JsonException ex)
|
||
{
|
||
// JsonException 是一种特定类型的异常,直接抛出,而不是包装在泛型 Exception 中。
|
||
throw new JsonException($"Failed to deserialize HediffComp_ApplyAttributesOffset ({def.defName}) properties " +
|
||
$"JSON: '{def.properties}'. Error: {ex.Message}", ex);
|
||
}
|
||
|
||
// 检查反序列化后的配置对象是否为 null
|
||
if (config == null)
|
||
throw new InvalidOperationException(
|
||
$"HediffComp_ApplyAttributesOffset ({def.defName}) PropertiesConfig deserialization resulted in null. " +
|
||
$"Input JSON: '{def.properties}'.");
|
||
|
||
// 检查条件表达式是否为空或 null
|
||
if (string.IsNullOrEmpty(config.ConditionExpression))
|
||
throw new InvalidOperationException(
|
||
$"HediffComp_ApplyAttributesOffset ({def.defName}) requires a 'condition' expression in its properties.");
|
||
|
||
// 创建条件委托
|
||
try
|
||
{
|
||
condition = ConditionDelegateFactory.CreateConditionDelegate(
|
||
config.ConditionExpression,
|
||
typeof(Entity.Entity),
|
||
typeof(ConditionFunctions)
|
||
);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
// 包装原始异常,提供更多上下文信息。
|
||
throw new Exception($"Failed to create condition delegate for HediffComp_ApplyAttributesOffset ({def.defName}) " +
|
||
$"expression: '{config.ConditionExpression}'. Error: {ex.Message}", ex);
|
||
}
|
||
|
||
// 检查属性偏移定义是否为 null
|
||
if (config.OffsetDef == null)
|
||
throw new InvalidOperationException(
|
||
$"HediffComp_ApplyAttributesOffset ({def.defName}) requires 'offsetDef' in its properties, but it was null.");
|
||
|
||
// 缓存实际的偏移量,当组件活跃时使用。此时已保证 config.OffsetDef 非空。
|
||
cachedActiveOffset = config.OffsetDef;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 当其父 <see cref="Hediff" /> 被添加到实体时调用。
|
||
/// 在此进行初始条件评估,并通知实体属性可能已更改。
|
||
/// </summary>
|
||
public override void OnAdded()
|
||
{
|
||
base.OnAdded();
|
||
// 在被添加到实体时进行首次条件评估,设置初始 isActive 状态
|
||
EvaluateConditionAndSetState();
|
||
// 通知实体属性可能已更改,以便其重新计算属性
|
||
parentHediff?.entity?.SetAttribsDirty();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 当其父 <see cref="Hediff" /> 从实体移除时调用。
|
||
/// 确保状态被重置为不活跃,并通知实体属性可能已更改。
|
||
/// </summary>
|
||
public override void OnRemoved()
|
||
{
|
||
base.OnRemoved();
|
||
// 确保移除时,如果组件当前活跃,则将状态设置为不活跃,并通知实体属性更新。
|
||
// 这样可以消除此 HediffComp 组件移除时带来的属性影响。
|
||
if (isActive)
|
||
{
|
||
isActive = false;
|
||
parentHediff?.entity?.SetAttribsDirty();
|
||
}
|
||
// 重置 cachedActiveOffset 和 condition 等引用,有助于 GC 并在理论上防止组件被缓存后引用旧数据。
|
||
cachedActiveOffset = null;
|
||
condition = null;
|
||
config = null; // 释放对配置的引用
|
||
}
|
||
|
||
/// <summary>
|
||
/// 每帧更新时调用。
|
||
/// 在此周期性地评估条件以更新 <see cref="isActive" /> 状态。
|
||
/// </summary>
|
||
/// <param name="deltaTime">自上次更新以来的时间(秒)。</param>
|
||
public override void Tick(float deltaTime)
|
||
{
|
||
base.Tick(deltaTime);
|
||
EvaluateConditionAndSetState();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 评估当前条件并更新 <see cref="isActive" /> 状态。
|
||
/// 如果 <see cref="isActive" /> 状态发生变化,则通知实体属性更新。
|
||
/// </summary>
|
||
private void EvaluateConditionAndSetState()
|
||
{
|
||
// 如果父 Hediff 的实体为空或条件委托未初始化,则无法评估条件。
|
||
// 此时应确保偏移量处于非激活状态,并通知属性变化(如果状态有变)。
|
||
// condition 已经通过 Initialize 方法保证非 null,除非父 Hediff.entity 为 null,
|
||
// 否则这里可以简化。但为了更强的健壮性,保留 condition == null 检查。
|
||
if (parentHediff?.entity == null || condition == null)
|
||
{
|
||
if (isActive) // 如果当前是活跃状态,但现在条件不可评估或实体不存在,需要重置
|
||
{
|
||
isActive = false;
|
||
parentHediff?.entity?.SetAttribsDirty(); // 通知属性脏,以便移除此组件的影响
|
||
}
|
||
return;
|
||
}
|
||
|
||
// 评估条件委托
|
||
var newIsActive = condition(parentHediff.entity);
|
||
|
||
// 如果 isActive 状态发生变化,则更新状态并通知实体。
|
||
if (newIsActive != isActive)
|
||
{
|
||
isActive = newIsActive;
|
||
parentHediff.entity.SetAttribsDirty();
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 用于反序列化 <see cref="HediffCompDef.properties" /> JSON 字符串的配置类。
|
||
/// </summary>
|
||
private class PropertiesConfig
|
||
{
|
||
/// <summary>
|
||
/// 条件表达式字符串,用于通过 <see cref="ConditionDelegateFactory" /> 创建条件委托。
|
||
/// 例如:"Entity.IsHuman && Entity.HealthRatio < 0.5"
|
||
/// </summary>
|
||
[JsonProperty("condition")]
|
||
public string ConditionExpression { get; set; }
|
||
|
||
/// <summary>
|
||
/// 当条件满足时应用的属性偏移定义。
|
||
/// </summary>
|
||
[JsonProperty("offsetDef")]
|
||
public AttributesOffsetDef OffsetDef { get; set; }
|
||
}
|
||
}
|
||
}
|