Files
WulaFallenEmpireRW/Source/WulaFallenEmpire/WULA_Shuttle/CompPocketMapPortal.cs
2025-08-25 14:17:37 +08:00

366 lines
15 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 RimWorld;
using Verse;
using System.Collections.Generic;
using UnityEngine;
using System.Reflection;
namespace WulaFallenEmpire
{
/// <summary>
/// 口袋空间传送门组件 - 只作为入口功能,附加在穿梭机上处理进入内部空间的逻辑
/// </summary>
public class CompPocketMapPortal : ThingComp
{
/// <summary>组件属性</summary>
public CompProperties_PocketMapPortal Props => (CompProperties_PocketMapPortal)props;
/// <summary>父建筑(必须是穿梭机)</summary>
public Building_ArmedShuttleWithPocket ParentShuttle => parent as Building_ArmedShuttleWithPocket;
/// <summary>MapPortal适配器用于使用原版Dialog_EnterPortal</summary>
private ShuttlePortalAdapter portalAdapter;
public override void PostSpawnSetup(bool respawningAfterLoad)
{
base.PostSpawnSetup(respawningAfterLoad);
Log.Message($"[WULA-DEBUG] CompPocketMapPortal.PostSpawnSetup called. Parent: {parent?.def?.defName ?? "null"}");
// 检查父对象是否是穿梭机
if (ParentShuttle == null)
{
Log.Error($"[WULA] CompPocketMapPortal attached to non-shuttle building: {parent?.def?.defName}");
return; // Early exit if parent is not a shuttle
}
// 创建MapPortal适配器并设置其地图和位置信息
portalAdapter = new ShuttlePortalAdapter(ParentShuttle);
// 确保 portalAdapter 的 shuttle 引用被正确设置
if (portalAdapter != null)
{
portalAdapter.shuttle = ParentShuttle;
Log.Message($"[WULA-DEBUG] portalAdapter.shuttle set in PostSpawnSetup: {portalAdapter.shuttle?.def.defName ?? "null"}");
}
}
/// <summary>
/// 检查穿梭机是否可以进入(仅作为入口功能)
/// </summary>
public bool IsEnterable(out string reason)
{
if (ParentShuttle == null)
{
reason = "WULA.PocketSpace.NotSpawned".Translate();
return false;
}
if (!ParentShuttle.AllowDirectAccess)
{
reason = "WULA.PocketSpace.AccessDenied".Translate();
return false;
}
if (!ParentShuttle.Spawned)
{
reason = "WULA.PocketSpace.NotSpawned".Translate();
return false;
}
// 检查穿梭机的传送状态
var transportDisabledField = typeof(Building_ArmedShuttleWithPocket).GetField("transportDisabled",
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
if (transportDisabledField != null)
{
bool transportDisabled = (bool)transportDisabledField.GetValue(ParentShuttle);
if (transportDisabled)
{
reason = "WULA.PocketSpace.TransportDisabled".Translate();
return false;
}
}
// 检查口袋地图是否存在
if (ParentShuttle.PocketMap == null)
{
reason = "WULA.PocketSpace.NoTargetMap".Translate();
return false;
}
reason = "";
return true;
}
/// <summary>
/// 获取组件额外的Gizmo按钮根据口袋空间初始化状态显示不同按钮
/// 重写CompGetGizmosExtra方法这样RimWorld会自动调用并显示按钮
/// </summary>
public override IEnumerable<Gizmo> CompGetGizmosExtra()
{
if (ParentShuttle == null) yield break;
// 检查口袋空间是否已初始化
bool pocketMapExists = ParentShuttle.PocketMap != null;
if (!pocketMapExists)
{
// 口袋空间未创建,显示初始化按钮
Command_Action initializeCommand = new Command_Action();
initializeCommand.action = delegate
{
// 创建口袋空间
InitializePocketSpace();
};
initializeCommand.icon = ContentFinder<Texture2D>.Get("UI/Commands/LoadTransporter");
initializeCommand.defaultLabel = "WULA.PocketSpace.Initialize".Translate();
initializeCommand.defaultDesc = "WULA.PocketSpace.InitializeDesc".Translate();
// 检查是否可以初始化
if (!ParentShuttle.Spawned)
{
initializeCommand.Disabled = true;
initializeCommand.disabledReason = "WULA.PocketSpace.NotSpawned".Translate();
}
yield return initializeCommand;
}
else
{
// 穿梭机已创建显示装载按钮使用原版Dialog_EnterPortal
Command_Action enterCommand = new Command_Action();
enterCommand.action = delegate
{
// 使用和Building_PocketMapExit一模一样的Dialog_EnterPortal方法
if (portalAdapter == null || portalAdapter.shuttle != ParentShuttle)
{
// 重新创建并设置适配器,确保其指向正确的穿梭机
portalAdapter = new ShuttlePortalAdapter(ParentShuttle);
// 再次尝试设置 MapPortal 基类的地图和位置信息
try
{
var mapField = typeof(Thing).GetField("mapIndexOrState",
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
var positionField = typeof(Thing).GetField("positionInt",
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
if (mapField != null && positionField != null && ParentShuttle.Spawned)
{
mapField.SetValue(portalAdapter, (sbyte)ParentShuttle.Map.Index); // 显式转换为 sbyte
positionField.SetValue(portalAdapter, ParentShuttle.Position);
}
}
catch (System.Exception ex)
{
Log.Error($"[WULA] Error setting MapPortal base fields during Gizmo click: {ex.Message}");
}
}
if (portalAdapter != null)
{
Log.Message($"[WULA-DEBUG] Opening Dialog_EnterPortal with portalAdapter. Type: {portalAdapter.GetType().Name}. Shuttle: {portalAdapter.shuttle?.def.defName ?? "null"}");
var dialog = new Dialog_EnterPortal(portalAdapter);
Find.WindowStack.Add(dialog);
}
else
{
Messages.Message("WULA.PocketSpace.AdapterError".Translate(), ParentShuttle, MessageTypeDefOf.RejectInput);
Log.Error("[WULA] Portal adapter is null after recreation attempt.");
}
};
enterCommand.icon = ContentFinder<Texture2D>.Get(Props.buttonIconPath);
enterCommand.defaultLabel = Props.enterButtonTextKey.Translate() + "...";
enterCommand.defaultDesc = Props.enterButtonDescKey.Translate();
// 检查是否可以进入
string reason;
enterCommand.Disabled = !IsEnterable(out reason);
enterCommand.disabledReason = reason;
yield return enterCommand;
// 查看口袋地图按钮
yield return new Command_Action
{
defaultLabel = "WULA.PocketSpace.SwitchTo".Translate(),
defaultDesc = "WULA.PocketSpace.SwitchToDesc".Translate(),
icon = ContentFinder<Texture2D>.Get("UI/Commands/ViewCave"),
action = delegate
{
Current.Game.CurrentMap = ParentShuttle.PocketMap;
Find.CameraDriver.JumpToCurrentMapLoc(ParentShuttle.PocketMap.Center);
}
};
}
}
/// <summary>
/// 初始化口袋空间
/// </summary>
private void InitializePocketSpace()
{
if (ParentShuttle == null || !ParentShuttle.Spawned)
{
Messages.Message("WULA.PocketSpace.CannotInitialize".Translate(), ParentShuttle, MessageTypeDefOf.RejectInput);
return;
}
if (ParentShuttle.PocketMap != null)
{
Messages.Message("WULA.PocketSpace.AlreadyInitialized".Translate(), ParentShuttle, MessageTypeDefOf.RejectInput);
return;
}
try
{
Log.Message("[WULA] Starting pocket space initialization via component");
// 使用穿梭机的SwitchToPocketSpace方法它会自动创建口袋空间
ParentShuttle.SwitchToPocketSpace();
if (ParentShuttle.PocketMap != null)
{
Messages.Message("WULA.PocketSpace.InitializeSuccess".Translate(), ParentShuttle, MessageTypeDefOf.PositiveEvent);
Log.Message("[WULA] Pocket space initialization completed successfully");
}
else
{
Messages.Message("WULA.PocketSpace.InitializeFailed".Translate(), ParentShuttle, MessageTypeDefOf.RejectInput);
Log.Error("[WULA] Pocket space initialization failed");
}
}
catch (System.Exception ex)
{
Log.Error($"[WULA] Error during pocket space initialization: {ex}");
Messages.Message("WULA.PocketSpace.InitializeFailed".Translate(), ParentShuttle, MessageTypeDefOf.RejectInput);
}
}
}
/// <summary>
/// 口袋空间传送门组件属性
/// </summary>
public class CompProperties_PocketMapPortal : CompProperties
{
/// <summary>进入按钮文本键</summary>
public string enterButtonTextKey = "WULA.PocketSpace.Enter";
/// <summary>进入按钮描述键</summary>
public string enterButtonDescKey = "WULA.PocketSpace.EnterDesc";
/// <summary>按钮图标路径</summary>
public string buttonIconPath = "UI/Commands/LoadTransporter";
public CompProperties_PocketMapPortal()
{
this.compClass = typeof(CompPocketMapPortal);
}
}
/// <summary>
/// MapPortal适配器类将Building_ArmedShuttleWithPocket适配为MapPortal接口
/// 完全模仿Building_PocketMapExit的实现方式
/// </summary>
public class ShuttlePortalAdapter : MapPortal
{
/// <summary>关联的穿梭机</summary>
public Building_ArmedShuttleWithPocket shuttle;
/// <summary>
/// 默认构造函数RimWorld组件系统要求
/// </summary>
public ShuttlePortalAdapter()
{
// 在这里不初始化 shuttle因为它将在 PostSpawnSetup 中设置
}
public ShuttlePortalAdapter(Building_ArmedShuttleWithPocket shuttle)
{
this.shuttle = shuttle;
}
/// <summary>
/// 重写获取其他地图返回口袋空间模仿Building_PocketMapExit.GetOtherMap
/// </summary>
public override Map GetOtherMap()
{
if (shuttle?.PocketMap == null)
{
// 如口袋空间还没创建,先创建它
shuttle?.SwitchToPocketSpace();
}
return shuttle?.PocketMap;
}
/// <summary>
/// 重写获取目标位置返回口袋空间中心模仿Building_PocketMapExit.GetDestinationLocation
/// </summary>
public override IntVec3 GetDestinationLocation()
{
return shuttle?.PocketMap?.Center ?? IntVec3.Invalid;
}
/// <summary>
/// 重写是否可进入检查穿梭机状态模仿Building_PocketMapExit.IsEnterable
/// </summary>
public override bool IsEnterable(out string reason)
{
if (shuttle == null || !shuttle.Spawned)
{
reason = "WULA.PocketSpace.NotSpawned".Translate();
return false;
}
if (!shuttle.AllowDirectAccess)
{
reason = "WULA.PocketSpace.AccessDenied".Translate();
return false;
}
// 检查穿梭机的传送状态
var transportDisabledField = typeof(Building_ArmedShuttleWithPocket).GetField("transportDisabled",
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
if (transportDisabledField != null)
{
bool transportDisabled = (bool)transportDisabledField.GetValue(shuttle);
if (transportDisabled)
{
reason = "WULA.PocketSpace.TransportDisabled".Translate();
return false;
}
}
reason = "";
return true;
}
/// <summary>
/// 重写进入事件处理进入口袋空间模仿Building_PocketMapExit.OnEntered
/// </summary>
public override void OnEntered(Pawn pawn)
{
// 通知穿梭机有物品被添加(用于统计和管理)
shuttle?.Notify_ThingAdded(pawn);
// 播放传送音效(如果存在)
if (Find.CurrentMap == shuttle?.Map)
{
// 可以在这里添加音效播放
// def.portal?.traverseSound?.PlayOneShot(this);
}
}
/// 重写进入按钮文本
/// </summary>
public override string EnterString => "WULA.PocketSpace.Enter".Translate();
/// <summary>
/// 重写进入按钮图标,使用装载按钮的贴图
/// </summary>
protected override Texture2D EnterTex => ContentFinder<Texture2D>.Get("UI/Commands/LoadTransporter");
// 移除了 new 关键字的 Map, Position, def 属性,因为它们在 MapPortal 基类中可能不是 virtual 的
// 并且我们依赖 PostSpawnSetup 中的反射来设置 MapPortal 基类的私有字段
// 这确保了 Dialog_EnterPortal 能够直接访问到正确的地图和位置信息。
}
}