Files
ArachnaeSwarm/Source/ArachnaeSwarm/Hediffs/ARA_GestaltNode/HediffComp_GestaltNode.cs
2026-02-14 10:44:32 +08:00

435 lines
14 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>
/// 获取节点类型
/// </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>
/// 获取 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)
{
tracker = new Pawn_GestaltTracker(pawn);
}
return tracker;
}
}
// === 生命周期方法 ===
public override void CompPostMake()
{
base.CompPostMake();
// 记录生成时间戳
spawnTimestamp = Find.TickManager.TicksGame;
// 如果是HiveNode初始化时设置较低的严重性延迟后再计算
if (NodeType == GestaltNodeType.HiveNode)
{
// 设置初始严重性为0.5(未连接状态)
if (parent != null)
{
parent.Severity = 0.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();
}
// 正常的Tick逻辑
if (NodeType == GestaltNodeType.HiveNode)
{
// 定期更新严重性
if (Find.TickManager.TicksGame % 60 == 0) // 每60tick检查一次
{
UpdateSeverityBasedOnConnection();
}
// 定期寻找 OverlordNode
if (pawn.IsColonist &&
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();
}
Log.Message($"[GestaltNode] {pawn.LabelShort} (HiveNode) 延迟初始化完成,当前连接状态: {IsConnectedToOverlord()}");
}
}
/// <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)
{
float targetSeverity = isConnected ? 1.5f : 0.5f;
// 平滑过渡到目标严重性
if (Mathf.Abs(parent.Severity - targetSeverity) > 0.01f)
{
parent.Severity = targetSeverity;
}
wasConnected = isConnected;
// 如果严重性改变需要重新计算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();
Log.Message($"[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();
// 当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>
/// 序列化
/// </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);
// 加载后,如果已经过了延迟期,标记为已初始化
if (Scribe.mode == LoadSaveMode.PostLoadInit && spawnTimestamp >= 0)
{
// 检查当前时间是否已经过了延迟期
if (Find.TickManager.TicksGame >= spawnTimestamp + DELAY_TICKS)
{
isInitialized = true;
}
}
}
/// <summary>
/// 调试信息
/// </summary>
public string GetDebugInfo()
{
var pawn = Pawn;
if (pawn == null)
return "Pawn is null";
return $"NodeType: {NodeType}\n" +
$"SpawnTimestamp: {spawnTimestamp}\n" +
$"IsPastSpawnDelay: {IsPastSpawnDelay}\n" +
$"IsInitialized: {isInitialized}\n" +
$"WasConnected: {wasConnected}\n" +
$"IsConnected: {IsConnectedToOverlord()}\n" +
$"CurrentSeverity: {parent?.Severity ?? 0f}";
}
}
/// <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();
}
}
}