2025-09-02 11:08:15 +08:00
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Linq;
|
2025-08-28 15:07:36 +08:00
|
|
|
|
using Data;
|
2025-09-02 11:08:15 +08:00
|
|
|
|
using UnityEngine;
|
2025-08-28 15:07:36 +08:00
|
|
|
|
|
|
|
|
|
namespace Entity
|
|
|
|
|
{
|
2025-09-02 11:08:15 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// 定义一个接口,用于提供属性偏移量。
|
|
|
|
|
/// 任何实现此接口的组件都可以贡献实体的属性修正。
|
|
|
|
|
/// </summary>
|
|
|
|
|
public interface IAttributesOffsetProvider
|
|
|
|
|
{
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 获取此提供者当前的属性偏移量定义。
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <returns>此提供者所带来的属性偏移量。</returns>
|
|
|
|
|
AttributesOffsetDef GetAttributesOffset();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 表示一个实体上运行时存在的健康状态(Hediff)。
|
|
|
|
|
/// Hediff 可以是疾病、增益、减益、伤口等,它们会影响实体的属性、行为或状态。
|
|
|
|
|
/// </summary>
|
2025-08-28 15:07:36 +08:00
|
|
|
|
public class Hediff
|
|
|
|
|
{
|
2025-09-02 11:08:15 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// 此 Hediff 的定义数据。
|
|
|
|
|
/// </summary>
|
|
|
|
|
public HediffDef def { get; private set; }
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 此 Hediff 附加到的活体实体。
|
|
|
|
|
/// </summary>
|
|
|
|
|
public LivingEntity parent { get; internal set; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 此 Hediff 存在的当前年龄(以秒为单位)。
|
|
|
|
|
/// </summary>
|
|
|
|
|
public float Age { get; private set; } = 0f;
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 当前激活的 Hediff 阶段的索引。
|
|
|
|
|
/// </summary>
|
|
|
|
|
private int _currentStageIndex = -1;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 附加到此 Hediff 上的所有组件列表。
|
|
|
|
|
/// </summary>
|
|
|
|
|
public List<HediffComp> Comps { get; private set; } = new List<HediffComp>();
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 标志,指示此 Hediff 是否应该被父实体移除。
|
|
|
|
|
/// </summary>
|
|
|
|
|
public bool ShouldRemove { get; private set; } = false;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 内部缓存,用于存储计算出的总属性偏移量。
|
|
|
|
|
/// </summary>
|
|
|
|
|
private AttributesOffsetDef _cachedTotalAttributesOffset;
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 标志,指示 Hediff 的属性偏移量是否需要重新计算。
|
|
|
|
|
/// </summary>
|
|
|
|
|
private bool _attribsDirty = true;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 构造函数,创建一个新的运行时 Hediff 实例。
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="definition">此 Hediff 的定义。</param>
|
|
|
|
|
/// <exception cref="ArgumentNullException">如果传入的定义为空。</exception>
|
|
|
|
|
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<HediffStageDef>();
|
|
|
|
|
this.def.stages = this.def.stages.OrderBy(s => s.start).ToList();
|
2025-09-06 12:25:55 +08:00
|
|
|
|
|
2025-09-02 11:08:15 +08:00
|
|
|
|
|
|
|
|
|
// 初始化时确定第一个阶段,这会触发 SetDirty()。
|
|
|
|
|
UpdateStageIndex();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 获取此 Hediff 当前激活的阶段定义。
|
|
|
|
|
/// 如果没有激活的阶段或阶段列表为空,则返回 null。
|
|
|
|
|
/// </summary>
|
|
|
|
|
public HediffStageDef CurrentStage
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
if (_currentStageIndex >= 0 && _currentStageIndex < def.stages.Count)
|
|
|
|
|
{
|
|
|
|
|
return def.stages[_currentStageIndex];
|
|
|
|
|
}
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 获取此 Hediff 当前累计的总属性偏移量。
|
|
|
|
|
/// 只有当属性被标记为“脏”时才重新计算,否则返回缓存值。
|
|
|
|
|
/// </summary>
|
|
|
|
|
public AttributesOffsetDef CurrentTotalAttributesOffset
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
// 只有当属性需要更新时才重新计算。
|
|
|
|
|
if (_attribsDirty || _cachedTotalAttributesOffset == null)
|
|
|
|
|
{
|
|
|
|
|
_cachedTotalAttributesOffset = CalculateTotalAttributesOffset();
|
|
|
|
|
_attribsDirty = false; // 计算完成后重置标志。
|
|
|
|
|
}
|
|
|
|
|
return _cachedTotalAttributesOffset;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 内部方法,用于实际计算 Hediff 的所有总属性偏移量。
|
|
|
|
|
/// 这包括当前阶段的偏移量和所有组件提供的偏移量。
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <returns>此 Hediff 当前的总属性偏移量。</returns>
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 标记 Hediff 的属性偏移量需要重新计算。
|
|
|
|
|
/// 当 Hediff 的内部状态改变并可能影响属性时调用。
|
|
|
|
|
/// 同时会通知其父 LivingEntity,使其也更新属性缓存。
|
|
|
|
|
/// </summary>
|
|
|
|
|
internal void SetDirty()
|
|
|
|
|
{
|
|
|
|
|
_attribsDirty = true;
|
|
|
|
|
// 如果此 Hediff 附加到了一个 LivingEntity 上,也通知 LivingEntity 属性可能改变。
|
|
|
|
|
if (parent)
|
|
|
|
|
{
|
|
|
|
|
parent.SetAttribsDirty();
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-08-28 15:07:36 +08:00
|
|
|
|
|
2025-09-02 11:08:15 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// 更新 Hediff 的年龄,检查阶段变化并更新所有组件。
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="deltaTime">自上次更新以来的时间(秒)。</param>
|
|
|
|
|
public void Tick(float deltaTime)
|
2025-08-28 15:07:36 +08:00
|
|
|
|
{
|
2025-09-02 11:08:15 +08:00
|
|
|
|
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 将被移除,其贡献的属性将不再有效,标记为脏。
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 根据当前年龄更新阶段索引。
|
|
|
|
|
/// 如果阶段发生变化,会调用 SetDirty()。
|
|
|
|
|
/// </summary>
|
|
|
|
|
private void UpdateStageIndex()
|
|
|
|
|
{
|
|
|
|
|
var originalStageIndex = _currentStageIndex; // 获取当前阶段索引。
|
|
|
|
|
var newStageIndex = _currentStageIndex;
|
2025-08-28 15:07:36 +08:00
|
|
|
|
|
2025-09-02 11:08:15 +08:00
|
|
|
|
// 从后往前遍历阶段,找到当前年龄所属的最高阶段。
|
|
|
|
|
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();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 当此 Hediff 被添加到实体时调用。
|
|
|
|
|
/// 进行初始化设置,如存储父实体引用,并标记属性为脏以强制重新计算。
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="entity">此 Hediff 附加到的 LivingEntity 实例。</param>
|
|
|
|
|
internal void OnAdded(LivingEntity entity)
|
|
|
|
|
{
|
|
|
|
|
this.parent = entity; // 存储父实体引用。
|
|
|
|
|
SetDirty(); // 刚添加也需要标记为脏以确保属性在下次计算时被纳入。
|
|
|
|
|
|
|
|
|
|
foreach (var comp in Comps)
|
|
|
|
|
{
|
|
|
|
|
comp.OnAdded();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 当此 Hediff 从实体移除时调用。
|
|
|
|
|
/// 进行清理操作,如清除父实体引用,并标记属性为脏以强制重新计算。
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="entity">此 Hediff 从中移除的 LivingEntity 实例。</param>
|
|
|
|
|
internal void OnRemoved(LivingEntity entity)
|
|
|
|
|
{
|
|
|
|
|
foreach (var comp in Comps)
|
|
|
|
|
{
|
|
|
|
|
comp.OnRemoved();
|
|
|
|
|
}
|
|
|
|
|
this.parent = null; // 清除对父实体的引用。
|
|
|
|
|
SetDirty(); // 移除后也需要标记为脏,确保属性计算考虑去除此Hediff。
|
2025-08-28 15:07:36 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
2025-09-02 11:08:15 +08:00
|
|
|
|
}
|