This commit is contained in:
2025-08-25 14:05:46 +08:00
parent ca8b713d4b
commit ad660f5831
4 changed files with 90 additions and 50 deletions

View File

@@ -0,0 +1,51 @@
using HarmonyLib;
using RimWorld;
using Verse;
using System.Reflection;
using System.Collections.Generic;
using System.Reflection.Emit;
namespace WulaFallenEmpire
{
[HarmonyPatch(typeof(Dialog_EnterPortal), "CalculateAndRecacheTransferables")]
public static class DialogEnterPortal_CalculateAndRecacheTransferables_Patch
{
// Transpiler 负责修改方法的 IL 代码
public static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
{
var codes = new List<CodeInstruction>(instructions);
// 找到 MapPortal.Map 属性的 getter 方法
var mapPropertyGetter = AccessTools.PropertyGetter(typeof(MapPortal), "Map");
// 找到我们自定义的静态方法,它将返回正确的 Map
var getShuttleMapMethod = AccessTools.Method(typeof(DialogEnterPortal_CalculateAndRecacheTransferables_Patch), nameof(GetShuttleMap));
for (int i = 0; i < codes.Count; i++)
{
// 查找对 MapPortal.Map 的 get 访问
if (codes[i].opcode == OpCodes.Callvirt && codes[i].operand is MethodInfo method && method == mapPropertyGetter)
{
// 替换为调用我们的静态方法
yield return new CodeInstruction(OpCodes.Call, getShuttleMapMethod);
}
else
{
yield return codes[i];
}
}
}
// 这个静态方法将由 Transpiler 注入,用于返回正确的 Map
// 参数 portalInstance 是原始方法中对 MapPortal 实例的引用
public static Map GetShuttleMap(MapPortal portalInstance)
{
if (portalInstance is ShuttlePortalAdapter adapter && adapter.shuttle != null)
{
return adapter.shuttle.Map;
}
// 如果不是我们的适配器或者 shuttle 为空,则返回原始 MapPortal 的 Map
// 我们需要直接访问 Thing 类的 Map 属性,这是 MapPortal 继承的
var originalMapGetter = AccessTools.PropertyGetter(typeof(Thing), "Map");
return (Map)originalMapGetter.Invoke(portalInstance, null);
}
}
}

View File

@@ -33,27 +33,12 @@ namespace WulaFallenEmpire
{
// 创建MapPortal适配器并设置其地图和位置信息
portalAdapter = new ShuttlePortalAdapter(ParentShuttle);
// 使用反射设置适配器的地图和位置让Dialog_EnterPortal能正确访问
if (portalAdapter != null && ParentShuttle.Spawned)
// 确保 portalAdapter 的 shuttle 引用被正确设置
// 并在 PostSpawnSetup 中设置 MapPortal 基类的地图和位置信息
// 确保 portalAdapter 的 shuttle 引用被正确设置
if (portalAdapter != null)
{
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)
{
mapField.SetValue(portalAdapter, mapField.GetValue(ParentShuttle));
positionField.SetValue(portalAdapter, positionField.GetValue(ParentShuttle));
}
}
catch (System.Exception ex)
{
Log.Warning($"[WULA] Could not set adapter map/position via reflection: {ex.Message}");
}
portalAdapter.shuttle = ParentShuttle;
}
}
}
@@ -147,25 +132,39 @@ namespace WulaFallenEmpire
enterCommand.action = delegate
{
// 使用和Building_PocketMapExit一模一样的Dialog_EnterPortal方法
if (portalAdapter != null && portalAdapter.shuttle != null)
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)
{
var dialog = new Dialog_EnterPortal(portalAdapter);
Find.WindowStack.Add(dialog);
}
else
{
Log.Error("[WULA] Portal adapter or shuttle is null, recreating adapter");
// 重新创建适配器
if (ParentShuttle != null)
{
portalAdapter = new ShuttlePortalAdapter(ParentShuttle);
var dialog = new Dialog_EnterPortal(portalAdapter);
Find.WindowStack.Add(dialog);
}
else
{
Messages.Message("内部错误:穿梭机引用丢失", ParentShuttle, MessageTypeDefOf.RejectInput);
}
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);
@@ -271,7 +270,7 @@ namespace WulaFallenEmpire
/// </summary>
public ShuttlePortalAdapter()
{
// 为空,在PostSpawnSetup中初始化
// 在这里不初始化 shuttle因为它将在 PostSpawnSetup 中设置
}
public ShuttlePortalAdapter(Building_ArmedShuttleWithPocket shuttle)
@@ -286,7 +285,7 @@ namespace WulaFallenEmpire
{
if (shuttle?.PocketMap == null)
{
// 如口袋空间还没创建,先创建它
// 如口袋空间还没创建,先创建它
shuttle?.SwitchToPocketSpace();
}
return shuttle?.PocketMap;
@@ -318,7 +317,7 @@ namespace WulaFallenEmpire
}
// 检查穿梭机的传送状态
var transportDisabledField = typeof(Building_ArmedShuttleWithPocket).GetField("transportDisabled",
var transportDisabledField = typeof(Building_ArmedShuttleWithPocket).GetField("transportDisabled",
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
if (transportDisabledField != null)
@@ -361,19 +360,8 @@ namespace WulaFallenEmpire
/// </summary>
protected override Texture2D EnterTex => ContentFinder<Texture2D>.Get("UI/Commands/LoadTransporter");
/// <summary>
/// 获取地图引用用于Dialog_EnterPortal
/// </summary>
public new Map Map => shuttle?.Map;
/// <summary>
/// 获取位置引用用于Dialog_EnterPortal
/// </summary>
public new IntVec3 Position => shuttle?.Position ?? IntVec3.Invalid;
/// <summary>
/// 获取定义引用用于Dialog_EnterPortal
/// </summary>
public new ThingDef def => shuttle?.def;
// 移除了 new 关键字的 Map, Position, def 属性,因为它们在 MapPortal 基类中可能不是 virtual 的
// 并且我们依赖 PostSpawnSetup 中的反射来设置 MapPortal 基类的私有字段
// 这确保了 Dialog_EnterPortal 能够直接访问到正确的地图和位置信息。
}
}

View File

@@ -96,6 +96,7 @@
<Compile Include="EventSystem\EventUIConfigDef.cs" />
<Compile Include="EventSystem\Letter_EventChoice.cs" />
<Compile Include="EventSystem\QuestNode_Root_EventLetter.cs" />
<Compile Include="HarmonyPatches\DialogEnterPortal_MapPatch.cs" />
<Compile Include="HarmonyPatches\Caravan_NeedsTracker_TrySatisfyPawnNeeds_Patch.cs" />
<Compile Include="HarmonyPatches\DamageInfo_Constructor_Patch.cs" />
<Compile Include="HarmonyPatches\FloatMenuOptionProvider_Ingest_Patch.cs" />