using System; using System.Collections.Generic; using System.Linq; using Data; using UnityEngine; namespace Entity { /// /// 定义一个接口,用于提供属性偏移量。 /// 任何实现此接口的组件都可以贡献实体的属性修正。 /// public interface IAttributesOffsetProvider { /// /// 获取此提供者当前的属性偏移量定义。 /// /// 此提供者所带来的属性偏移量。 AttributesOffsetDef GetAttributesOffset(); } /// /// 表示一个实体上运行时存在的健康状态(Hediff)。 /// Hediff 可以是疾病、增益、减益、伤口等,它们会影响实体的属性、行为或状态。 /// public class Hediff { /// /// 此 Hediff 的定义数据。 /// public HediffDef def { get; private set; } /// /// 此 Hediff 附加到的活体实体。 /// public LivingEntity parent { get; internal set; } /// /// 此 Hediff 存在的当前年龄(以秒为单位)。 /// public float Age { get; private set; } = 0f; /// /// 当前激活的 Hediff 阶段的索引。 /// private int _currentStageIndex = -1; /// /// 附加到此 Hediff 上的所有组件列表。 /// public List Comps { get; private set; } = new List(); /// /// 标志,指示此 Hediff 是否应该被父实体移除。 /// public bool ShouldRemove { get; private set; } = false; /// /// 内部缓存,用于存储计算出的总属性偏移量。 /// private AttributesOffsetDef _cachedTotalAttributesOffset; /// /// 标志,指示 Hediff 的属性偏移量是否需要重新计算。 /// private bool _attribsDirty = true; /// /// 构造函数,创建一个新的运行时 Hediff 实例。 /// /// 此 Hediff 的定义。 /// 如果传入的定义为空。 public Hediff(HediffDef definition) { if (definition == null) { throw new ArgumentNullException(nameof(definition), "Hediff 定义不能为空。"); } this.def = definition; this._attribsDirty = true; // 构造时标记需要计算属性 // 确保阶段列表按开始时间排序,以便正确判断当前阶段。 if (this.def.stages == null) this.def.stages = new List(); this.def.stages = this.def.stages.OrderBy(s => s.start).ToList(); // 实例化所有定义的组件。 if (def.comps != null) { foreach (var compDef in def.comps) { if (compDef.compClass != null && typeof(HediffComp).IsAssignableFrom(compDef.compClass)) { try { // 使用 Activator.CreateInstance 动态创建组件实例,并传入构造函数参数。 // HediffComp 的构造函数需要接受 Hediff parentHediff 和 HediffCompDef def。 var comp = (HediffComp)Activator.CreateInstance(compDef.compClass, this, compDef); Comps.Add(comp); comp.Initialize(); // 初始化组件 } catch (Exception ex) { Debug.LogError( $"实例化健康状态组件 '{compDef.compClass?.Name ?? "空"}' 失败,所属健康状态 '{def.defName ?? def.GetType().Name}':{ex.Message}"); } } else { Debug.LogWarning( $"警告:健康状态组件定义 '{compDef.compClass?.Name ?? "空"}' 无效或未继承自 HediffComp,所属健康状态 '{def.defName ?? def.GetType().Name}'。"); } } } // 初始化时确定第一个阶段,这会触发 SetDirty()。 UpdateStageIndex(); } /// /// 获取此 Hediff 当前激活的阶段定义。 /// 如果没有激活的阶段或阶段列表为空,则返回 null。 /// public HediffStageDef CurrentStage { get { if (_currentStageIndex >= 0 && _currentStageIndex < def.stages.Count) { return def.stages[_currentStageIndex]; } return null; } } /// /// 获取此 Hediff 当前累计的总属性偏移量。 /// 只有当属性被标记为“脏”时才重新计算,否则返回缓存值。 /// public AttributesOffsetDef CurrentTotalAttributesOffset { get { // 只有当属性需要更新时才重新计算。 if (_attribsDirty || _cachedTotalAttributesOffset == null) { _cachedTotalAttributesOffset = CalculateTotalAttributesOffset(); _attribsDirty = false; // 计算完成后重置标志。 } return _cachedTotalAttributesOffset; } } /// /// 内部方法,用于实际计算 Hediff 的所有总属性偏移量。 /// 这包括当前阶段的偏移量和所有组件提供的偏移量。 /// /// 此 Hediff 当前的总属性偏移量。 private AttributesOffsetDef CalculateTotalAttributesOffset() { var totalOffset = new AttributesOffsetDef(); if (CurrentStage != null) { totalOffset += CurrentStage.attributesOffset; } // 累加来自组件的属性偏移。 foreach (var comp in Comps) { if (comp is IAttributesOffsetProvider attributesOffsetProvider) { totalOffset += attributesOffsetProvider.GetAttributesOffset(); } } return totalOffset; } /// /// 标记 Hediff 的属性偏移量需要重新计算。 /// 当 Hediff 的内部状态改变并可能影响属性时调用。 /// 同时会通知其父 LivingEntity,使其也更新属性缓存。 /// internal void SetDirty() { _attribsDirty = true; // 如果此 Hediff 附加到了一个 LivingEntity 上,也通知 LivingEntity 属性可能改变。 if (parent) { parent.SetAttribsDirty(); } } /// /// 更新 Hediff 的年龄,检查阶段变化并更新所有组件。 /// /// 自上次更新以来的时间(秒)。 public void Tick(float deltaTime) { if (ShouldRemove) return; // 已经标记为移除,无需继续更新。 Age += deltaTime; // 增加 Hediff 的年龄。 UpdateStageIndex(); // 检查是否有阶段变化(此方法内部会调用 SetDirty)。 // 更新所有组件。 foreach (var comp in Comps) { comp.Tick(deltaTime); } // 检查 Hediff 是否到期(如果 def.time > 0 表示有时限,否则为永久)。 if (def.time > 0 && Age >= def.time) { ShouldRemove = true; SetDirty(); // Hediff 将被移除,其贡献的属性将不再有效,标记为脏。 } } /// /// 根据当前年龄更新阶段索引。 /// 如果阶段发生变化,会调用 SetDirty()。 /// private void UpdateStageIndex() { var originalStageIndex = _currentStageIndex; // 获取当前阶段索引。 var newStageIndex = _currentStageIndex; // 从后往前遍历阶段,找到当前年龄所属的最高阶段。 for (var i = def.stages.Count - 1; i >= 0; i--) { if (def.stages[i].start <= Age) { newStageIndex = i; break; } } // 如果阶段发生变化,则标记为脏。 if (newStageIndex != originalStageIndex) { _currentStageIndex = newStageIndex; // 阶段发生变化,属性偏移可能改变,标记为脏。 SetDirty(); } } /// /// 当此 Hediff 被添加到实体时调用。 /// 进行初始化设置,如存储父实体引用,并标记属性为脏以强制重新计算。 /// /// 此 Hediff 附加到的 LivingEntity 实例。 internal void OnAdded(LivingEntity entity) { this.parent = entity; // 存储父实体引用。 SetDirty(); // 刚添加也需要标记为脏以确保属性在下次计算时被纳入。 foreach (var comp in Comps) { comp.OnAdded(); } } /// /// 当此 Hediff 从实体移除时调用。 /// 进行清理操作,如清除父实体引用,并标记属性为脏以强制重新计算。 /// /// 此 Hediff 从中移除的 LivingEntity 实例。 internal void OnRemoved(LivingEntity entity) { foreach (var comp in Comps) { comp.OnRemoved(); } this.parent = null; // 清除对父实体的引用。 SetDirty(); // 移除后也需要标记为脏,确保属性计算考虑去除此Hediff。 } } }