mirror of
http://47.107.252.169:3000/Roguelite-Game-Developing-Team/Gen_Hack-and-Slash-Roguelite.git
synced 2025-11-20 05:27:13 +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
205 lines
8.4 KiB
C#
205 lines
8.4 KiB
C#
using System;
|
||
using Data;
|
||
using Entity;
|
||
using Managers;
|
||
using Newtonsoft.Json;
|
||
using Parsing;
|
||
|
||
namespace HediffComps
|
||
{
|
||
/// <summary>
|
||
/// 健康状态组件:在冷却时间结束后或满足特定条件时触发一个预定义的事件。
|
||
/// </summary>
|
||
public class HediffComp_ExecuteEvent : HediffComp
|
||
{
|
||
// 从 JSON 反序列化得到的配置
|
||
private PropertiesConfig config;
|
||
// 评估条件是否满足的委托 (如果定义了)
|
||
private Func<Entity.Entity, bool> condition;
|
||
// 距离下次事件触发或条件评估还剩多少秒
|
||
private float remainingCooldown;
|
||
// 如果配置为 TriggerOnce,记录是否已触发过一次
|
||
private bool hasTriggered;
|
||
|
||
/// <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">当配置对象、事件名称为空时抛出。</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_ExecuteEvent ({def.defName}) requires configuration in HediffCompDef.properties.");
|
||
|
||
// 反序列化配置 JSON 字符串到 PropertiesConfig 对象
|
||
try
|
||
{
|
||
config = JsonConvert.DeserializeObject<PropertiesConfig>(def.properties);
|
||
}
|
||
catch (JsonException ex)
|
||
{
|
||
throw new JsonException($"Failed to deserialize HediffComp_ExecuteEvent ({def.defName}) properties " +
|
||
$"JSON: '{def.properties}'. Error: {ex.Message}", ex);
|
||
}
|
||
|
||
// 检查反序列化后的配置对象是否为 null
|
||
if (config == null)
|
||
throw new InvalidOperationException(
|
||
$"HediffComp_ExecuteEvent ({def.defName}) PropertiesConfig deserialization resulted in null. " +
|
||
$"Input JSON: '{def.properties}'.");
|
||
|
||
// 检查事件名称是否为空或 null
|
||
if (string.IsNullOrEmpty(config.EventName))
|
||
throw new InvalidOperationException(
|
||
$"HediffComp_ExecuteEvent ({def.defName}) requires an 'eventName' in its properties.");
|
||
|
||
// 如果定义了条件表达式,则创建条件委托
|
||
if (!string.IsNullOrEmpty(config.ConditionExpression))
|
||
{
|
||
try
|
||
{
|
||
condition = ConditionDelegateFactory.CreateConditionDelegate(
|
||
config.ConditionExpression,
|
||
typeof(Entity.Entity),
|
||
typeof(ConditionFunctions)
|
||
);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
throw new Exception($"Failed to create condition delegate for HediffComp_ExecuteEvent ({def.defName}) " +
|
||
$"expression: '{config.ConditionExpression}'. Error: {ex.Message}", ex);
|
||
}
|
||
}
|
||
|
||
// 初始化冷却时间。如果 CooldownSeconds 小于0,则视为0。
|
||
remainingCooldown = Math.Max(0f, config.CooldownSeconds);
|
||
hasTriggered = false; // 初始状态为未触发
|
||
}
|
||
|
||
/// <summary>
|
||
/// 当其父 <see cref="Hediff" /> 被添加到实体时调用。
|
||
/// 重置冷却时间和触发状态。
|
||
/// </summary>
|
||
public override void OnAdded()
|
||
{
|
||
base.OnAdded();
|
||
// 每次添加到实体时,重置冷却时间和触发状态,确保组件可以重新开始工作
|
||
remainingCooldown = Math.Max(0f, config.CooldownSeconds);
|
||
hasTriggered = false;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 当其父 <see cref="Hediff" /> 从实体移除时调用。
|
||
/// 清空引用以辅助垃圾回收。
|
||
/// </summary>
|
||
public override void OnRemoved()
|
||
{
|
||
base.OnRemoved();
|
||
// 释放对配置和委托的引用,以辅助垃圾回收
|
||
config = null;
|
||
condition = null;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 每帧更新时调用。
|
||
/// 在此周期性地检查冷却时间和条件,以触发事件。
|
||
/// </summary>
|
||
/// <param name="deltaTime">自上次更新以来的时间(秒)。</param>
|
||
public override void Tick(float deltaTime)
|
||
{
|
||
base.Tick(deltaTime);
|
||
|
||
// 如果组件设置为只触发一次且已触发,则不再进行任何操作。
|
||
if (config.TriggerOnce && hasTriggered)
|
||
{
|
||
return;
|
||
}
|
||
|
||
// 如果实体不存在,则无法触发事件或评估条件
|
||
if (parentHediff?.entity == null)
|
||
{
|
||
return;
|
||
}
|
||
|
||
// 递减冷却时间
|
||
remainingCooldown -= deltaTime;
|
||
|
||
// 冷却时间结束后,检查是否可以触发事件
|
||
if (remainingCooldown <= 0)
|
||
{
|
||
// 默认条件满足,除非有条件委托且评估失败
|
||
bool conditionMet = true;
|
||
|
||
// 如果存在条件委托,则评估条件
|
||
if (condition != null)
|
||
{
|
||
conditionMet = condition(parentHediff.entity);
|
||
}
|
||
|
||
if (conditionMet)
|
||
{
|
||
// 触发事件
|
||
EventManager.Instance.Action(config.EventName, parentHediff.entity);
|
||
hasTriggered = true; // 标记已触发
|
||
|
||
// 如果不是只触发一次,则重置冷却时间以便下次触发
|
||
if (!config.TriggerOnce)
|
||
{
|
||
remainingCooldown = Math.Max(0f, config.CooldownSeconds);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// 如果冷却结束但条件不满足,并且是非一次性触发,重置冷却时间以便下次尝试
|
||
// 仅当 CooldownSeconds > 0 时才重置,避免0冷却无限Tick评估条件导致性能问题
|
||
if (!config.TriggerOnce && config.CooldownSeconds > 0)
|
||
{
|
||
remainingCooldown = Math.Max(0f, config.CooldownSeconds);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 用于反序列化 <see cref="HediffCompDef.properties" /> JSON 字符串的配置类。
|
||
/// </summary>
|
||
private class PropertiesConfig
|
||
{
|
||
/// <summary>
|
||
/// 要触发的事件名称。
|
||
/// </summary>
|
||
[JsonProperty("eventName")]
|
||
public string EventName { get; set; }
|
||
|
||
/// <summary>
|
||
/// 可选的条件表达式字符串。如果存在,只在条件满足时触发。
|
||
/// </summary>
|
||
[JsonProperty("condition")]
|
||
public string ConditionExpression { get; set; }
|
||
|
||
/// <summary>
|
||
/// 可选的冷却时间(秒)。事件触发后需要等待此时间才能再次触发。默认为0。
|
||
/// JSON 中未定义时默认为0。
|
||
/// </summary>
|
||
[JsonProperty("cooldownSeconds")]
|
||
public float CooldownSeconds { get; set; } = 0f;
|
||
|
||
/// <summary>
|
||
/// 可选的布尔值。如果为 true,事件只触发一次。默认为 false。
|
||
/// JSON 中未定义时默认为false。
|
||
/// </summary>
|
||
[JsonProperty("triggerOnce")]
|
||
public bool TriggerOnce { get; set; } = false;
|
||
}
|
||
}
|
||
}
|