435 lines
14 KiB
C#
435 lines
14 KiB
C#
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();
|
||
}
|
||
}
|
||
}
|