Files
ArachnaeSwarm/Source/ArachnaeSwarm/Hediffs/ARA_GestaltNode/HediffComp_GestaltNode.cs
Tourswen cda002ea9e 1
2026-02-16 14:04:52 +08:00

741 lines
25 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using ArachnaeSwarm;
using RimWorld;
using System.Collections.Generic;
using Verse;
using UnityEngine;
namespace ArachnaeSwarm
{
public enum GestaltNodeType
{
HiveNode,
OverlordNode
}
public class HediffComp_GestaltNode : HediffComp
{
private GestaltNodeType? cachedNodeType;
private Pawn_GestaltTracker tracker;
private bool wasConnected = false; // 缓存连接状态,避免每帧都调整严重性
// === 延迟初始化字段 ===
/// <summary>
/// 生成时间戳ticks用于延迟计算
/// </summary>
private int spawnTimestamp = -1;
/// <summary>
/// 是否已经初始化完成(延迟后)
/// </summary>
private bool isInitialized = false;
/// <summary>
/// 延迟时间ticks默认1秒
/// </summary>
private const int DELAY_TICKS = 60;
// === 动态过渡系统字段 ===
/// <summary>
/// 过渡开始时间ticks
/// </summary>
private int transitionStartTick = -1;
/// <summary>
/// 过渡期持续时间ticks5秒
/// </summary>
private const int TRANSITION_DURATION = 300; // 5秒
/// <summary>
/// 过渡开始时的严重性
/// </summary>
private float transitionStartSeverity = 0.5f;
/// <summary>
/// 过渡结束时的目标严重性
/// </summary>
private float targetSeverityAfterTransition = 1.0f;
/// <summary>
/// 是否正在过渡中
/// </summary>
private bool isTransitioning = false;
/// <summary>
/// 上一次更新严重性的时间ticks
/// </summary>
private int lastSeverityUpdateTick = -1;
// === 属性 ===
/// <summary>
/// 获取节点类型
/// </summary>
public GestaltNodeType NodeType
{
get
{
if (!cachedNodeType.HasValue)
{
HediffCompProperties_GestaltNode props = this.props as HediffCompProperties_GestaltNode;
cachedNodeType = props?.nodeType ?? GestaltNodeType.HiveNode;
}
return cachedNodeType.Value;
}
}
/// <summary>
/// 是否已经过了生成延迟期
/// </summary>
public bool IsPastSpawnDelay
{
get
{
// OverlordNode 不需要延迟
if (NodeType == GestaltNodeType.OverlordNode)
return true;
// 如果已经初始化完成直接返回true
if (isInitialized)
return true;
// 如果还没有记录生成时间,记录当前时间
if (spawnTimestamp < 0)
return false;
// 检查是否已经过了延迟期
return Find.TickManager.TicksGame >= spawnTimestamp + DELAY_TICKS;
}
}
/// <summary>
/// 是否在过渡期中
/// </summary>
public bool IsInTransition
{
get
{
if (transitionStartTick < 0)
return false;
return Find.TickManager.TicksGame - transitionStartTick < TRANSITION_DURATION;
}
}
/// <summary>
/// 获取当前过渡进度0-1
/// </summary>
public float TransitionProgress
{
get
{
if (!IsInTransition || transitionStartTick < 0)
return 1.0f;
int elapsed = Find.TickManager.TicksGame - transitionStartTick;
return Mathf.Clamp01((float)elapsed / TRANSITION_DURATION);
}
}
/// <summary>
/// 获取每秒变化速率
/// </summary>
public float SeverityChangePerSecond
{
get
{
// 根据过渡类型计算不同的变化速率
if (targetSeverityAfterTransition > transitionStartSeverity)
{
// 连接状态从0.5到1.5总共1.0的变化量5秒内完成
return 0.2f; // 1.0 / 5.0 = 0.2
}
else
{
// 断开状态从1.5到0.5,总共-1.0的变化量5秒内完成
return -0.2f; // -1.0 / 5.0 = -0.2
}
}
}
/// <summary>
/// 获取 GestaltTracker
/// </summary>
public Pawn_GestaltTracker GestaltTracker
{
get
{
var pawn = Pawn;
if (pawn == null)
{
return tracker;
}
CompGestalt comp = pawn.TryGetComp<CompGestalt>();
if (comp != null)
{
return comp.GestaltTracker;
}
if (tracker == null && NodeType == GestaltNodeType.OverlordNode && pawn != null)
{
tracker = new Pawn_GestaltTracker(pawn);
}
return tracker;
}
}
// === 生命周期方法 ===
public override void CompPostMake()
{
base.CompPostMake();
// 记录生成时间戳
spawnTimestamp = Find.TickManager.TicksGame;
if (NodeType == GestaltNodeType.HiveNode)
{
if (parent != null)
{
parent.Severity = 1.5f;
}
}
else
{
// OverlordNode 立即初始化
isInitialized = true;
}
}
public override void CompPostTick(ref float severityAdjustment)
{
base.CompPostTick(ref severityAdjustment);
var pawn = Pawn;
if (pawn == null)
{
return;
}
// 检查是否已经过了生成延迟期
if (!IsPastSpawnDelay)
{
// 还在延迟期内,不执行任何计算
return;
}
// 延迟期过后,执行初始化
if (!isInitialized)
{
InitializeAfterDelay();
}
// 检查过渡状态,并更新严重性变化
UpdateTransitionStateWithRate();
// 正常的Tick逻辑
if (NodeType == GestaltNodeType.HiveNode)
{
// 定期检查连接状态(如果不在过渡中)
if (!IsInTransition && Find.TickManager.TicksGame % 60 == 0) // 每60tick检查一次
{
UpdateSeverityBasedOnConnection();
}
// 定期寻找 OverlordNode
if (pawn.Spawned &&
!pawn.Dead &&
Find.TickManager.TicksGame % 250 == 0)
{
TryFindOverlord();
}
}
}
/// <summary>
/// 延迟期过后初始化
/// </summary>
private void InitializeAfterDelay()
{
var pawn = Pawn;
if (pawn == null)
return;
// 标记为已初始化
isInitialized = true;
// 如果是HiveNode检查当前连接状态
if (NodeType == GestaltNodeType.HiveNode)
{
// 延迟后第一次更新严重性
UpdateSeverityBasedOnConnection();
// 延迟后第一次尝试寻找Overlord
if (pawn.IsColonist && pawn.Spawned && !pawn.Dead)
{
TryFindOverlord();
}
ArachnaeLog.Debug($"[GestaltNode] {pawn.LabelShort} (HiveNode) 延迟初始化完成,当前连接状态: {IsConnectedToOverlord()}");
}
}
/// <summary>
/// 带速率变化的过渡状态更新
/// </summary>
private void UpdateTransitionStateWithRate()
{
// 检查Pawn是否死亡或无效
var pawn = Pawn;
if (pawn == null || pawn.Dead)
{
isTransitioning = false;
transitionStartTick = -1;
lastSeverityUpdateTick = -1;
return;
}
// 如果不在过渡中,重置并返回
if (!isTransitioning || transitionStartTick < 0)
{
lastSeverityUpdateTick = -1;
return;
}
// 检查过渡是否已经完成
if (!IsInTransition)
{
// 过渡完成,确保设置到目标严重性
CompleteTransition();
return;
}
// 检查是否应该更新严重性(每秒更新一次)
int currentTick = Find.TickManager.TicksGame;
if (lastSeverityUpdateTick < 0 || currentTick - lastSeverityUpdateTick >= 60) // 60ticks = 1秒
{
UpdateSeverityWithRate(currentTick);
lastSeverityUpdateTick = currentTick;
}
}
/// <summary>
/// 使用速率更新严重性
/// </summary>
private void UpdateSeverityWithRate(int currentTick)
{
var pawn = Pawn;
if (pawn == null || parent == null)
return;
// 计算经过的时间(秒)
float elapsedSeconds = (currentTick - transitionStartTick) / 60f;
// 计算新的严重性
float newSeverity;
// 方法1线性插值
// newSeverity = Mathf.Lerp(transitionStartSeverity, targetSeverityAfterTransition,
// Mathf.Clamp01(elapsedSeconds / (TRANSITION_DURATION / 60f)));
// 方法2使用速率计算更符合要求
float changeAmount = SeverityChangePerSecond * (currentTick - transitionStartTick) / 60f;
newSeverity = transitionStartSeverity + changeAmount;
// 确保严重性在合理范围内
if (targetSeverityAfterTransition > transitionStartSeverity)
{
// 连接过程,严重性增加
newSeverity = Mathf.Clamp(newSeverity, transitionStartSeverity, targetSeverityAfterTransition);
}
else
{
// 断开过程,严重性减少
newSeverity = Mathf.Clamp(newSeverity, targetSeverityAfterTransition, transitionStartSeverity);
}
// 应用新的严重性
if (Mathf.Abs(parent.Severity - newSeverity) > 0.001f)
{
parent.Severity = newSeverity;
// 通知Pawn状态改变
if (pawn?.health != null)
{
pawn.health.Notify_HediffChanged(parent);
}
// 调试信息
if (Find.TickManager.TicksGame % 120 == 0) // 每2秒记录一次
{
ArachnaeLog.Debug($"[GestaltNode] {pawn.LabelShort} 过渡中: {parent.Severity:F2} -> {targetSeverityAfterTransition:F2} " +
$"(进度: {TransitionProgress:P0}, 速率: {SeverityChangePerSecond:F2}/秒)");
}
}
}
/// <summary>
/// 完成过渡
/// </summary>
private void CompleteTransition()
{
var pawn = Pawn;
if (pawn == null || parent == null)
{
ResetTransition();
return;
}
// 确保最终严重性准确
if (Mathf.Abs(parent.Severity - targetSeverityAfterTransition) > 0.01f)
{
parent.Severity = targetSeverityAfterTransition;
if (pawn?.health != null)
{
pawn.health.Notify_HediffChanged(parent);
}
}
ArachnaeLog.Debug($"[GestaltNode] {pawn.LabelShort} 过渡完成: {targetSeverityAfterTransition:F2}");
// 重置过渡状态
ResetTransition();
}
/// <summary>
/// 重置过渡状态
/// </summary>
private void ResetTransition()
{
transitionStartTick = -1;
isTransitioning = false;
lastSeverityUpdateTick = -1;
transitionStartSeverity = 0.5f;
targetSeverityAfterTransition = 1.0f;
}
/// <summary>
/// 开始带速率变化的过渡
/// </summary>
private void StartRateBasedTransition(bool isConnecting)
{
var pawn = Pawn;
if (pawn == null || parent == null)
return;
// 设置目标严重性
targetSeverityAfterTransition = isConnecting ? 1.5f : 0.5f;
// 记录过渡开始时的严重性
transitionStartSeverity = parent.Severity;
// 记录过渡开始时间
transitionStartTick = Find.TickManager.TicksGame;
isTransitioning = true;
lastSeverityUpdateTick = transitionStartTick;
ArachnaeLog.Debug($"[GestaltNode] {pawn.LabelShort} 开始速率过渡: {transitionStartSeverity:F2} -> {targetSeverityAfterTransition:F2} " +
$"({(isConnecting ? "" : "")}, 速率: {SeverityChangePerSecond:F2}/秒)");
}
/// <summary>
/// 根据连接状态更新 Hediff 严重性
/// </summary>
public void UpdateSeverityBasedOnConnection()
{
if (NodeType != GestaltNodeType.HiveNode || parent == null)
return;
var pawn = Pawn;
if (pawn?.health == null)
{
return;
}
bool isConnected = IsConnectedToOverlord();
// 检查连接状态是否改变
if (isConnected != wasConnected)
{
// 连接状态改变,开始带速率变化的过渡
StartRateBasedTransition(isConnected);
wasConnected = isConnected;
}
else
{
// 连接状态没有改变,但可能不在过渡中,需要确保严重性正确
// 如果不在过渡中,直接设置到目标严重性
if (!IsInTransition)
{
float currentTargetSeverity = isConnected ? 1.5f : 0.5f;
if (Mathf.Abs(parent.Severity - currentTargetSeverity) > 0.01f)
{
parent.Severity = currentTargetSeverity;
// 如果严重性改变需要重新计算Pawn的能力
pawn.health.Notify_HediffChanged(parent);
}
}
}
}
/// <summary>
/// 检查是否连接到 Overlord
/// </summary>
public bool IsConnectedToOverlord()
{
return Pawn.GetOverlord() != null;
}
/// <summary>
/// 尝试寻找 Overlord
/// </summary>
public void TryFindOverlord()
{
// 如果还没有过延迟期,不执行
if (!IsPastSpawnDelay)
return;
// 如果已经有Overlord更新连接状态并返回
var pawn = Pawn;
if (pawn == null || pawn.Dead || pawn.Destroyed)
{
return;
}
if (IsConnectedToOverlord())
{
UpdateSeverityBasedOnConnection();
return;
}
// 如果Pawn当前不在地图上无法寻找Overlord
if (pawn.Map == null)
{
return;
}
// 在殖民地寻找可用的OverlordNode
Pawn bestOverlord = null;
float bestScore = -1f;
foreach (Pawn candidate in pawn.Map.mapPawns.FreeColonists)
{
HediffComp_GestaltNode nodeComp = candidate.GetGestaltNodeComp();
if (nodeComp?.NodeType == GestaltNodeType.OverlordNode &&
candidate != pawn &&
!candidate.Dead &&
!candidate.Downed &&
!candidate.Destroyed)
{
Pawn_GestaltTracker tracker = candidate.GestaltTracker();
if (tracker != null && tracker.CanControlPawn(pawn))
{
float score = CalculateOverlordScore(candidate, tracker);
if (score > bestScore)
{
bestScore = score;
bestOverlord = candidate;
}
}
}
}
// 找到合适的Overlord建立关系并更新严重性
if (bestOverlord != null)
{
// Pawns being destroyed/vanished can temporarily have no relations tracker.
if (pawn.relations != null && ARA_PawnRelationDefOf.ARA_GestaltOverseer != null)
{
pawn.relations.AddDirectRelation(ARA_PawnRelationDefOf.ARA_GestaltOverseer, bestOverlord);
}
UpdateSeverityBasedOnConnection();
ArachnaeLog.Debug($"[GestaltNode] {pawn.LabelShort} 连接到 Overlord: {bestOverlord.LabelShort}");
}
}
/// <summary>
/// 计算 Overlord 得分
/// </summary>
private float CalculateOverlordScore(Pawn overlord, Pawn_GestaltTracker tracker)
{
float score = 0f;
if (overlord.Spawned && Pawn.Spawned && overlord.Map == Pawn.Map)
{
float distance = overlord.Position.DistanceTo(Pawn.Position);
score += 100f / (distance + 1f);
}
float availableBandwidth = tracker.TotalBandwidth - tracker.UsedBandwidth;
score += availableBandwidth * 10f;
score += (10 - tracker.ControlGroups.Count) * 5f;
return score;
}
/// <summary>
/// Hediff 被移除时的清理
/// </summary>
public override void CompPostPostRemoved()
{
base.CompPostPostRemoved();
// 清理过渡状态
ResetTransition();
// 当Hediff被移除时如果连接到Overlord需要断开连接
if (NodeType == GestaltNodeType.HiveNode && IsConnectedToOverlord())
{
var pawn = Pawn;
if (pawn?.relations == null || ARA_PawnRelationDefOf.ARA_GestaltOverseer == null)
{
return;
}
Pawn overlord = pawn.GetOverlord();
if (overlord != null)
{
pawn.relations.RemoveDirectRelation(ARA_PawnRelationDefOf.ARA_GestaltOverseer, overlord);
}
}
}
/// <summary>
/// Pawn 死亡时的处理
/// </summary>
public override void Notify_PawnDied(DamageInfo? dinfo, Hediff culprit = null)
{
base.Notify_PawnDied(dinfo, culprit);
// 清理过渡状态
ResetTransition();
ArachnaeLog.Debug($"[GestaltNode] {Pawn?.LabelShort} 死亡,清理过渡状态");
}
/// <summary>
/// 序列化
/// </summary>
public override void CompExposeData()
{
base.CompExposeData();
Scribe_Values.Look(ref wasConnected, "wasConnected", false);
Scribe_Values.Look(ref spawnTimestamp, "spawnTimestamp", -1);
Scribe_Values.Look(ref isInitialized, "isInitialized", false);
Scribe_Values.Look(ref transitionStartTick, "transitionStartTick", -1);
Scribe_Values.Look(ref transitionStartSeverity, "transitionStartSeverity", 0.5f);
Scribe_Values.Look(ref targetSeverityAfterTransition, "targetSeverityAfterTransition", 1.0f);
Scribe_Values.Look(ref isTransitioning, "isTransitioning", false);
Scribe_Values.Look(ref lastSeverityUpdateTick, "lastSeverityUpdateTick", -1);
// 加载后,如果已经过了延迟期,标记为已初始化
if (Scribe.mode == LoadSaveMode.PostLoadInit && spawnTimestamp >= 0)
{
// 检查当前时间是否已经过了延迟期
if (Find.TickManager.TicksGame >= spawnTimestamp + DELAY_TICKS)
{
isInitialized = true;
}
// 如果正在过渡中,恢复过渡状态
if (transitionStartTick >= 0 && isTransitioning)
{
// 检查过渡是否已经完成
if (!IsInTransition)
{
// 过渡已完成,设置最终严重性
if (parent != null)
{
parent.Severity = targetSeverityAfterTransition;
}
ResetTransition();
}
else
{
// 过渡未完成,恢复过渡
ArachnaeLog.Debug($"[GestaltNode] 恢复未完成的过渡: {transitionStartSeverity:F2} -> {targetSeverityAfterTransition:F2}");
}
}
}
}
/// <summary>
/// 调试信息
/// </summary>
public string GetDebugInfo()
{
var pawn = Pawn;
if (pawn == null)
return "Pawn is null";
string transitionInfo = "无";
if (IsInTransition)
{
float rate = SeverityChangePerSecond;
string direction = rate > 0 ? "增加" : "减少";
transitionInfo = $"过渡中,进度: {TransitionProgress:P0}\n" +
$"从: {transitionStartSeverity:F2} 到: {targetSeverityAfterTransition:F2}\n" +
$"速率: {Mathf.Abs(rate):F2}/秒 ({direction})\n" +
$"当前: {parent?.Severity:F2}";
}
else if (isTransitioning)
{
transitionInfo = $"过渡完成,目标: {targetSeverityAfterTransition:F2}";
}
return $"NodeType: {NodeType}\n" +
$"SpawnTimestamp: {spawnTimestamp}\n" +
$"IsPastSpawnDelay: {IsPastSpawnDelay}\n" +
$"IsInitialized: {isInitialized}\n" +
$"WasConnected: {wasConnected}\n" +
$"IsConnected: {IsConnectedToOverlord()}\n" +
$"Transition: {transitionInfo}\n" +
$"CurrentSeverity: {parent?.Severity ?? 0f:F2}";
}
}
/// <summary>
/// Pawn 扩展方法
/// </summary>
public static class HediffExtensions
{
public static HediffComp_GestaltNode GetGestaltNodeComp(this Pawn pawn)
{
if (pawn?.health?.hediffSet?.hediffs == null)
return null;
foreach (Hediff hediff in pawn.health.hediffSet.hediffs)
{
HediffComp_GestaltNode comp = hediff.TryGetComp<HediffComp_GestaltNode>();
if (comp != null)
return comp;
}
return null;
}
public static bool IsGestaltNode(this Pawn pawn, GestaltNodeType nodeType)
{
HediffComp_GestaltNode comp = pawn.GetGestaltNodeComp();
return comp?.NodeType == nodeType;
}
/// <summary>
/// 获取延迟信息(调试用)
/// </summary>
public static string GetGestaltNodeDelayInfo(this Pawn pawn)
{
HediffComp_GestaltNode comp = pawn.GetGestaltNodeComp();
if (comp == null)
return "No GestaltNode";
return comp.GetDebugInfo();
}
}
}