using System; using Data; using Entity; using Newtonsoft.Json; using Parsing; namespace HediffComps { /// /// 健康状态组件:在特定条件下为实体提供属性偏移量。 /// 当条件满足时,该组件会提供预设的 ;否则提供一个所有值为零的空偏移量。 /// public class HediffComp_ApplyAttributesOffset : HediffComp, IAttributesOffsetProvider { // 不活跃时返回的空属性偏移量 (所有字段为0)。这是一个只读字段,在构造时已初始化,因此永远不需要空检查。 private readonly AttributesOffsetDef emptyOffset = new(); private AttributesOffsetDef cachedActiveOffset; // 当活跃时返回的实际属性偏移量 private Func condition; // 评估条件的委托 private PropertiesConfig config; // 从 JSON 反序列化得到的配置 private bool isActive; // 当前属性偏移是否活跃(即条件是否满足) /// /// 获取此提供者当前的属性偏移量定义。 /// 实现 接口。 /// /// 此提供者所带来的属性偏移量。 public AttributesOffsetDef GetAttributesOffset() { // 如果组件活跃,则返回实际的属性偏移量;否则返回一个空的(所有值为零)的偏移量。 // cachedActiveOffset 在 Initialize 时已保证非 null,emptyOffset 是 readonly 字段并已初始化,因此不需空检查。 return isActive ? cachedActiveOffset : emptyOffset; } /// /// 组件初始化时调用,在构造函数之后。 /// 负责解析 中的 JSON 配置,并创建条件委托。 /// /// 父级 Hediff 实例。 /// 组件定义。 /// 为空或 null 时抛出。 /// 当 JSON 反序列化失败时抛出。 /// 当配置对象、条件表达式或偏移定义为 null 时抛出。 /// 当条件委托创建失败时抛出(包装原始异常)。 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(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; } /// /// 当其父 被添加到实体时调用。 /// 在此进行初始条件评估,并通知实体属性可能已更改。 /// public override void OnAdded() { base.OnAdded(); // 在被添加到实体时进行首次条件评估,设置初始 isActive 状态 EvaluateConditionAndSetState(); // 通知实体属性可能已更改,以便其重新计算属性 parentHediff?.entity?.SetAttribsDirty(); } /// /// 当其父 从实体移除时调用。 /// 确保状态被重置为不活跃,并通知实体属性可能已更改。 /// public override void OnRemoved() { base.OnRemoved(); // 确保移除时,如果组件当前活跃,则将状态设置为不活跃,并通知实体属性更新。 // 这样可以消除此 HediffComp 组件移除时带来的属性影响。 if (isActive) { isActive = false; parentHediff?.entity?.SetAttribsDirty(); } // 重置 cachedActiveOffset 和 condition 等引用,有助于 GC 并在理论上防止组件被缓存后引用旧数据。 cachedActiveOffset = null; condition = null; config = null; // 释放对配置的引用 } /// /// 每帧更新时调用。 /// 在此周期性地评估条件以更新 状态。 /// /// 自上次更新以来的时间(秒)。 public override void Tick(float deltaTime) { base.Tick(deltaTime); EvaluateConditionAndSetState(); } /// /// 评估当前条件并更新 状态。 /// 如果 状态发生变化,则通知实体属性更新。 /// 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(); } } /// /// 用于反序列化 JSON 字符串的配置类。 /// private class PropertiesConfig { /// /// 条件表达式字符串,用于通过 创建条件委托。 /// 例如:"Entity.IsHuman && Entity.HealthRatio < 0.5" /// [JsonProperty("condition")] public string ConditionExpression { get; set; } /// /// 当条件满足时应用的属性偏移定义。 /// [JsonProperty("offsetDef")] public AttributesOffsetDef OffsetDef { get; set; } } } }