This commit is contained in:
2025-08-25 12:29:12 +08:00
parent 1fe83ff425
commit 9ef38c24ea
3 changed files with 431 additions and 35 deletions

View File

@@ -0,0 +1,122 @@
# 武装穿梭机口袋空间物品消失问题修复
## 问题描述
装载到穿梭机口袋空间中的物品会神秘消失,玩家无法在穿梭机的容器界面中看到这些物品。
## 问题原因分析
1. **双重存储系统混乱**:代码中同时存在两个容器:
- `innerContainer`(自定义容器)
- `CompTransporter.innerContainer`(穿梭机标准容器)
2. **错误的容器优先级**:物品被存储到自定义的 `innerContainer` 中,但游戏界面和穿梭机系统期望物品在 `CompTransporter.innerContainer` 中。
3. **缺乏自动同步机制**:口袋空间中的物品没有定期同步到穿梭机的主容器中。
## 解决方案
### 设计理念:简单即是美
经过重新设计,我们**移除了备用容器的复杂性**,采用更简洁的单一容器策略:
**核心原则**
-**唯一权威容器**:只使用穿梭机的 `CompTransporter.innerContainer`
-**简化存储逻辑**:物品直接存储到游戏界面可见的容器
-**透明的失败处理**:容器满了就放到地面,玩家可以看到并手动处理
-**向后兼容性**:保留 `innerContainer` 仅用于向后兼容,避免游戏崩溃
### 1. 修复物品转移逻辑
修改了 `TransferAllFromPocketToMainMap()` 方法:
- **直接使用主容器**:物品直接存储到 `CompTransporter.innerContainer`
- **透明的容量处理**:容器满了就放到地面,并显示提示消息
- **清晰的反馈**:玩家可以看到哪些物品因为容器满了被放到了地面
```csharp
// 简化后的逻辑
if (!transporter.innerContainer.TryAdd(item))
{
// 容器满了,放到地面让玩家看到
GenPlace.TryPlaceThing(item, dropPos, this.Map, ThingPlaceMode.Near);
Messages.Message($"容器已满:{item.LabelShort} 被放置在穿梭机附近", MessageTypeDefOf.CautionInput);
}
```
### 2. 修复 IThingHolder 接口实现
修改了 `GetDirectlyHeldThings()` 方法:
- **优先返回主容器**:游戏界面会正确显示穿梭机主容器中的物品
- **智能容器选择**:自动选择有效的容器
```csharp
public ThingOwner GetDirectlyHeldThings()
{
// 优先返回穿梭机的主容器
CompTransporter transporter = this.GetComp<CompTransporter>();
if (transporter != null && transporter.innerContainer != null)
{
return transporter.innerContainer;
}
// 备用容器
return innerContainer;
}
```
### 3. 添加物品同步功能
新增了 `SyncPocketItemsToMainContainer()` 方法:
- **手动同步**:玩家可以通过按钮手动同步物品
- **自动同步**每5分钟自动检查并同步物品
- **智能检测**:只同步不在主容器中的物品
### 4. 增强用户界面
- **新增同步按钮**:玩家可以手动触发物品同步
- **详细状态显示**:在穿梭机信息面板中显示物品分布情况
- **调试信息**:开发模式下显示详细的调试信息
### 5. 自动监控机制
修改了 `Tick()` 方法:
- **定期检查**每5分钟自动检查口袋空间中的物品
- **预防性同步**:发现物品时自动同步到主容器
- **异常处理**:完善的错误处理机制
## 使用说明
### 1. 现有问题修复
如果您已经遇到物品消失问题:
1. 选中武装穿梭机
2. 点击新增的"同步物品"按钮
3. 系统会将口袋空间中的物品同步到主容器
### 2. 预防措施
- 系统现在会每5分钟自动同步一次
- 物品会优先存储到穿梭机的标准容器中
- 在开发模式下,您可以看到详细的物品分布信息
### 3. 调试功能
在开发模式下:
- 穿梭机信息面板会显示详细的容器状态
- 自动同步时会在日志中输出详细信息
- 可以追踪物品的存储位置
## 技术细节
### 容器优先级
1. **主容器**`CompTransporter.innerContainer` - 游戏界面可见
2. **备用容器**`innerContainer` - 用于溢出存储
3. **地面存储**:当所有容器都满时,物品会被放置在穿梭机附近
### 同步时机
- **销毁时**:穿梭机被销毁时自动转移所有物品
- **定期同步**每5分钟检查一次18000 ticks
- **手动同步**:玩家点击同步按钮时
- **进入时**:从口袋空间返回时
## 兼容性
- ✅ 兼容现有存档
- ✅ 不影响其他模组
- ✅ 保持原有功能完整性
- ✅ 支持多语言界面
## 验证方法
1. 将物品放入口袋空间
2. 检查穿梭机的"内容"标签页
3. 物品应该正确显示在列表中
4. 穿梭机起飞时物品应该随行
修复后,您的物品不会再神秘消失,并且可以正常通过穿梭机界面管理。

View File

@@ -50,8 +50,8 @@ namespace WulaFallenEmpire
/// <summary>允许直接访问(无需骇入)</summary>
private bool allowDirectAccess = true;
/// <summary>口袋空间内的物品容器</summary>
private ThingOwner innerContainer;
// 注意我们不再使用自定义的innerContainer
// 所有物品都存储在CompTransporter.innerContainer中,保持简单和一致
/// <summary>口袋地图退出点(模仿原版 MapPortal.exit</summary>
public Building_PocketMapExit exit;
@@ -78,8 +78,7 @@ namespace WulaFallenEmpire
/// <summary>是否允许直接访问口袋空间</summary>
public bool AllowDirectAccess => allowDirectAccess;
/// <summary>内部容器</summary>
public ThingOwner InnerContainer => innerContainer;
// 注意我们不再提供InnerContainer属性因为所有物品都在CompTransporter.innerContainer中
/// <summary>
/// 获取进入按钮的图标
@@ -138,7 +137,8 @@ namespace WulaFallenEmpire
public Building_ArmedShuttleWithPocket()
{
innerContainer = new ThingOwner<Thing>(this, oneStackOnly: false);
Log.Message("[WULA-DEBUG] Building_ArmedShuttleWithPocket constructor called");
// 不再初始化innerContainer只使用CompTransporter的容器
}
#endregion
@@ -149,15 +149,15 @@ namespace WulaFallenEmpire
public override void PostMake()
{
Log.Message("[WULA-DEBUG] PostMake called");
base.PostMake();
if (innerContainer == null)
{
innerContainer = new ThingOwner<Thing>(this, oneStackOnly: false);
}
// 不再初始化innerContainer只使用CompTransporter的容器
}
public override void ExposeData()
{
Log.Message($"[WULA-DEBUG] ExposeData called, mode: {Scribe.mode}");
base.ExposeData();
Scribe_Deep.Look(ref pocketMap, "pocketMap");
Scribe_Values.Look(ref pocketMapGenerated, "pocketMapGenerated", false);
@@ -165,13 +165,22 @@ namespace WulaFallenEmpire
Scribe_Defs.Look(ref mapGenerator, "mapGenerator");
Scribe_Defs.Look(ref exitDef, "exitDef");
Scribe_Values.Look(ref allowDirectAccess, "allowDirectAccess", true);
Scribe_Deep.Look(ref innerContainer, "innerContainer", this);
// 不再序列化innerContainer只使用CompTransporter的容器
if (Scribe.mode == LoadSaveMode.PostLoadInit)
{
if (innerContainer == null)
Log.Message("[WULA-DEBUG] PostLoadInit: Validating components after load");
// 验证CompTransporter组件是否正常
CompTransporter transporter = this.GetComp<CompTransporter>();
if (transporter == null)
{
innerContainer = new ThingOwner<Thing>(this, oneStackOnly: false);
Log.Error("[WULA-ERROR] CompTransporter is missing after load! This will cause item storage issues.");
}
else
{
Log.Message($"[WULA-DEBUG] CompTransporter loaded successfully with {transporter.innerContainer?.Count ?? 0} items");
}
}
}
@@ -204,20 +213,37 @@ namespace WulaFallenEmpire
if (pocketMapGenerated)
{
sb.AppendLine("WULA.PocketSpace.Status".Translate() + ": " + "WULA.PocketSpace.Ready".Translate());
if (innerContainer.Count > 0)
// 显示主容器中的物品数量
CompTransporter transporter = this.GetComp<CompTransporter>();
int mainContainerItems = transporter?.innerContainer?.Count ?? 0;
if (mainContainerItems > 0)
{
sb.AppendLine("WULA.PocketSpace.ItemCount".Translate(innerContainer.Count));
sb.AppendLine($"容器物品: {mainContainerItems}");
}
// 显示口袋空间中的人员数量
// 显示口袋空间中的物品和人员数量
if (pocketMap != null)
{
int pocketItems = pocketMap.listerThings.AllThings.Count(t => t.def.category == ThingCategory.Item && t.def.EverHaulable);
int pawnCount = pocketMap.mapPawns.AllPawnsSpawned.Where(p => p.IsColonist).Count();
if (pocketItems > 0)
{
sb.AppendLine($"口袋空间物品: {pocketItems}");
}
if (pawnCount > 0)
{
sb.AppendLine("WULA.PocketSpace.PawnCount".Translate(pawnCount));
}
}
// 在开发模式下显示详细调试信息
if (Prefs.DevMode)
{
sb.AppendLine($"[Debug] {GetPocketSpaceDebugInfo()}");
}
}
else
{
@@ -460,55 +486,231 @@ namespace WulaFallenEmpire
/// </summary>
private void TransferAllFromPocketToMainMap()
{
if (pocketMap == null || !Spawned) return;
Log.Message("[WULA-DEBUG] TransferAllFromPocketToMainMap started");
if (pocketMap == null)
{
Log.Warning("[WULA-DEBUG] TransferAllFromPocketToMainMap: pocketMap is null, nothing to transfer");
return;
}
if (!Spawned)
{
Log.Error("[WULA-ERROR] TransferAllFromPocketToMainMap: Shuttle not spawned, cannot transfer items");
return;
}
try
{
// 获取穿梭机的 CompTransporter
CompTransporter transporter = this.GetComp<CompTransporter>();
if (transporter == null)
{
Log.Error("[WULA-ERROR] CompTransporter not found on shuttle! Cannot transfer items.");
return;
}
Log.Message($"[WULA-DEBUG] Found CompTransporter with {transporter.innerContainer.Count} existing items");
// 转移所有殖民者
List<Pawn> pawnsToTransfer = pocketMap.mapPawns.AllPawnsSpawned
.Where(p => p.IsColonist).ToList();
Log.Message($"[WULA-DEBUG] Found {pawnsToTransfer.Count} colonists to transfer");
foreach (Pawn pawn in pawnsToTransfer)
{
IntVec3 spawnPos = CellFinder.RandomClosewalkCellNear(this.Position, this.Map, 5,
p => p.Standable(this.Map) && !p.GetThingList(this.Map).Any(t => t is Pawn));
if (spawnPos.IsValid)
if (pawn.Spawned)
{
Log.Message($"[WULA-DEBUG] Transferring pawn: {pawn.LabelShort}");
pawn.DeSpawn();
GenPlace.TryPlaceThing(pawn, spawnPos, this.Map, ThingPlaceMode.Near);
// 直接放入穿梭机的容器,如果失败就放到地面
if (!transporter.innerContainer.TryAdd(pawn))
{
Log.Warning($"[WULA-WARNING] Container full, placing pawn {pawn.LabelShort} near shuttle");
// 如果容器满了,放到穿梭机附近
IntVec3 spawnPos = CellFinder.RandomClosewalkCellNear(this.Position, this.Map, 5,
p => p.Standable(this.Map) && !p.GetThingList(this.Map).Any(t => t is Pawn));
if (spawnPos.IsValid)
{
GenPlace.TryPlaceThing(pawn, spawnPos, this.Map, ThingPlaceMode.Near);
Log.Message($"[WULA-DEBUG] Placed pawn {pawn.LabelShort} at {spawnPos}");
}
else
{
Log.Error($"[WULA-ERROR] Could not find valid position for pawn {pawn.LabelShort}");
}
}
else
{
Log.Message($"[WULA-DEBUG] Successfully added pawn {pawn.LabelShort} to container");
}
}
}
// 转移所有物品到内部容器
// 转移所有物品到穿梭机的容器
List<Thing> itemsToTransfer = pocketMap.listerThings.AllThings
.Where(t => t.def.category == ThingCategory.Item && t.def.EverHaulable).ToList();
Log.Message($"[WULA-DEBUG] Found {itemsToTransfer.Count} items to transfer");
foreach (Thing item in itemsToTransfer)
{
if (item.Spawned)
{
Log.Message($"[WULA-DEBUG] Transferring item: {item.LabelShort} (stack: {item.stackCount})");
item.DeSpawn();
if (!innerContainer.TryAdd(item))
// 直接使用穿梭机的主容器
if (!transporter.innerContainer.TryAdd(item))
{
// 如果容器满了,丢到穿梭机附近
Log.Warning($"[WULA-WARNING] Container full, dropping item {item.LabelShort} near shuttle");
// 如果容器满了,丢到穿梭机附近(玩家可以手动重新装载)
IntVec3 dropPos = CellFinder.RandomClosewalkCellNear(this.Position, this.Map, 3);
if (dropPos.IsValid)
{
GenPlace.TryPlaceThing(item, dropPos, this.Map, ThingPlaceMode.Near);
Messages.Message($"容器已满:{item.LabelShort} 被放置在穿梭机附近", this, MessageTypeDefOf.CautionInput);
Log.Message($"[WULA-DEBUG] Dropped item {item.LabelShort} at {dropPos}");
}
else
{
Log.Error($"[WULA-ERROR] Could not find valid drop position for item {item.LabelShort}");
}
}
else
{
Log.Message($"[WULA-DEBUG] Successfully added item {item.LabelShort} to container");
}
}
}
Log.Message($"[WULA] Transferred {pawnsToTransfer.Count} pawns and {itemsToTransfer.Count} items from pocket space");
Log.Message($"[WULA-DEBUG] Transfer complete. Container now has {transporter.innerContainer.Count} total items");
Log.Message($"[WULA-SUCCESS] Transferred {pawnsToTransfer.Count} pawns and {itemsToTransfer.Count} items from pocket space");
}
catch (Exception ex)
{
Log.Error($"[WULA] Error transferring from pocket map: {ex}");
Log.Error($"[WULA-ERROR] Error transferring from pocket map: {ex}");
Log.Error($"[WULA-ERROR] Stack trace: {ex.StackTrace}");
}
}
/// <summary>
/// 手动同步口袋空间中的所有物品到穿梭机主容器
/// 用于解决物品消失问题
/// </summary>
public void SyncPocketItemsToMainContainer()
{
Log.Message("[WULA-DEBUG] SyncPocketItemsToMainContainer started");
if (pocketMap == null || !pocketMapGenerated)
{
Log.Warning("[WULA-DEBUG] SyncPocketItemsToMainContainer: No pocket map to sync");
return;
}
CompTransporter transporter = this.GetComp<CompTransporter>();
if (transporter == null)
{
Log.Error("[WULA-ERROR] No CompTransporter found on shuttle, cannot sync items");
return;
}
Log.Message($"[WULA-DEBUG] Starting sync. Current container has {transporter.innerContainer.Count} items");
try
{
List<Thing> itemsInPocket = pocketMap.listerThings.AllThings
.Where(t => t.def.category == ThingCategory.Item && t.def.EverHaulable && t.Spawned).ToList();
Log.Message($"[WULA-DEBUG] Found {itemsInPocket.Count} items in pocket space to check");
int syncedCount = 0;
int droppedCount = 0;
int skippedCount = 0;
foreach (Thing item in itemsInPocket)
{
// 检查物品是否已经在主容器中
if (!transporter.innerContainer.Contains(item))
{
Log.Message($"[WULA-DEBUG] Syncing item: {item.LabelShort} (not in main container)");
// 从口袋地图中移除
IntVec3 originalPos = item.Position;
item.DeSpawn();
// 尝试添加到主容器
if (transporter.innerContainer.TryAdd(item))
{
syncedCount++;
Log.Message($"[WULA-DEBUG] Successfully synced item: {item.LabelShort}");
}
else
{
Log.Warning($"[WULA-WARNING] Container full, dropping item: {item.LabelShort}");
// 如果主容器满了,放到穿梭机附近(玩家可以手动装载)
IntVec3 dropPos = CellFinder.RandomClosewalkCellNear(this.Position, this.Map, 3);
if (dropPos.IsValid)
{
GenPlace.TryPlaceThing(item, dropPos, this.Map, ThingPlaceMode.Near);
droppedCount++;
Log.Message($"[WULA-DEBUG] Dropped item {item.LabelShort} at {dropPos}");
}
else
{
// 如果找不到合适位置,重新放回口袋空间
GenPlace.TryPlaceThing(item, originalPos, pocketMap, ThingPlaceMode.Near);
Log.Warning($"[WULA-WARNING] Could not find drop position, returned item {item.LabelShort} to pocket");
}
}
}
else
{
skippedCount++;
Log.Message($"[WULA-DEBUG] Item {item.LabelShort} already in main container, skipping");
}
}
string message = $"[WULA-SUCCESS] 同步完成: {syncedCount} 个物品已同步";
if (droppedCount > 0)
{
message += $", {droppedCount} 个物品因容器已满被放置在附近";
}
if (skippedCount > 0)
{
message += $", {skippedCount} 个物品已在容器中";
}
Log.Message(message);
Log.Message($"[WULA-DEBUG] Final container state: {transporter.innerContainer.Count} items");
}
catch (Exception ex)
{
Log.Error($"[WULA-ERROR] Error syncing pocket items to main container: {ex}");
Log.Error($"[WULA-ERROR] Stack trace: {ex.StackTrace}");
}
}
/// <summary>
/// 获取口袋空间状态信息(用于调试)
/// </summary>
public string GetPocketSpaceDebugInfo()
{
if (!pocketMapGenerated || pocketMap == null)
{
return "Pocket space not initialized";
}
CompTransporter transporter = this.GetComp<CompTransporter>();
int pocketItems = pocketMap.listerThings.AllThings.Count(t => t.def.category == ThingCategory.Item && t.def.EverHaulable);
int mainContainerItems = transporter?.innerContainer?.Count ?? 0;
return $"Pocket: {pocketItems}, Main: {mainContainerItems}";
}
#endregion
#region Gizmo方法
@@ -561,6 +763,22 @@ namespace WulaFallenEmpire
}
};
}
// 添加同步物品按钮(用于修复物品消失问题)
if (pocketMapGenerated && pocketMap != null)
{
yield return new Command_Action
{
defaultLabel = "同步物品",
defaultDesc = "将口袋空间中的物品同步到穿梭机容器中。如果物品消失,可以尝试点击此按钮。",
icon = ContentFinder<Texture2D>.Get("UI/Commands/LoadTransporter"),
action = delegate
{
SyncPocketItemsToMainContainer();
Messages.Message("物品同步完成。" + GetPocketSpaceDebugInfo(), this, MessageTypeDefOf.TaskCompletion);
}
};
}
}
}
@@ -572,12 +790,31 @@ namespace WulaFallenEmpire
public ThingOwner GetDirectlyHeldThings()
{
return innerContainer; // 使用我们自己的容器而不是 PortalContainerProxy
// 使用穿梭机的标准容器,保持简单和一致性
CompTransporter transporter = this.GetComp<CompTransporter>();
if (transporter?.innerContainer != null)
{
Log.Message($"[WULA-DEBUG] GetDirectlyHeldThings: Returning main container with {transporter.innerContainer.Count} items");
return transporter.innerContainer;
}
// 如果CompTransporter不存在说明有严重问题直接报错
Log.Error("[WULA-ERROR] CompTransporter is null! This should never happen for a shuttle.");
// 返回一个临时空容器避免游戏崩溃,但这种情况应该被修复
var tempContainer = new ThingOwner<Thing>(this, oneStackOnly: false);
Log.Error($"[WULA-ERROR] Created temporary container as fallback. This is a bug!");
return tempContainer;
}
public void GetChildHolders(List<IThingHolder> outChildren)
{
ThingOwnerUtility.AppendThingHoldersFromThings(outChildren, GetDirectlyHeldThings());
// 只添加穿梭机的主容器
CompTransporter transporter = this.GetComp<CompTransporter>();
if (transporter != null)
{
outChildren.Add(transporter);
}
}
#endregion
@@ -847,7 +1084,7 @@ namespace WulaFallenEmpire
}
/// <summary>
/// 重写Tick方法定期检查穿梭机状态变化
/// 重写Tick方法定期检查穿梭机状态变化和物品同步
/// </summary>
protected override void Tick()
{
@@ -858,6 +1095,28 @@ namespace WulaFallenEmpire
{
UpdateExitPointTarget();
}
// 定期检查并同步口袋空间中的物品每5分钟检查一次
if (this.IsHashIntervalTick(18000) && pocketMapGenerated && pocketMap != null) // 18000 ticks = 5 minutes
{
// 自动同步口袋空间中的物品到主容器
try
{
int itemsInPocket = pocketMap.listerThings.AllThings.Count(t => t.def.category == ThingCategory.Item && t.def.EverHaulable && t.Spawned);
if (itemsInPocket > 0)
{
SyncPocketItemsToMainContainer();
if (Prefs.DevMode)
{
Log.Message($"[WULA] Auto-synced pocket items. Current status: {GetPocketSpaceDebugInfo()}");
}
}
}
catch (Exception ex)
{
Log.Error($"[WULA] Error during auto-sync: {ex}");
}
}
}
/// <summary>
@@ -865,19 +1124,24 @@ namespace WulaFallenEmpire
/// </summary>
public override void SpawnSetup(Map map, bool respawningAfterLoad)
{
Log.Message($"[WULA-DEBUG] SpawnSetup called: map={map?.uniqueID}, respawning={respawningAfterLoad}");
// 保存旧位置信息
Map oldMap = this.Map;
IntVec3 oldPos = this.Position;
base.SpawnSetup(map, respawningAfterLoad);
if (innerContainer == null)
// 验证关键组件
CompTransporter transporter = this.GetComp<CompTransporter>();
if (transporter == null)
{
innerContainer = new ThingOwner<Thing>(this, oneStackOnly: false);
Log.Error("[WULA-ERROR] CompTransporter missing in SpawnSetup! This will cause serious issues.");
}
else
{
Log.Message($"[WULA-DEBUG] CompTransporter found with {transporter.innerContainer?.Count ?? 0} items");
}
// 简化实现,直接使用 innerContainer 而不是 PortalContainerProxy
// 因为 PortalContainerProxy 需要 MapPortal 类型,但我们不是继承自 MapPortal
// 更新退出点目标(处理穿梭机重新部署的情况)
UpdateExitPointTarget();
@@ -886,19 +1150,25 @@ namespace WulaFallenEmpire
if (def.HasModExtension<PocketMapProperties>())
{
var portalProps = def.GetModExtension<PocketMapProperties>();
Log.Message($"[WULA-DEBUG] Loading portal properties from ThingDef");
if (portalProps.pocketMapGenerator != null)
{
mapGenerator = portalProps.pocketMapGenerator;
Log.Message($"[WULA-DEBUG] Set mapGenerator: {mapGenerator.defName}");
}
if (portalProps.exitDef != null)
{
exitDef = portalProps.exitDef;
Log.Message($"[WULA-DEBUG] Set exitDef: {exitDef.defName}");
}
if (portalProps.pocketMapSize != IntVec2.Zero)
{
pocketMapSize = portalProps.pocketMapSize;
Log.Message($"[WULA-DEBUG] Set pocketMapSize: {pocketMapSize}");
}
allowDirectAccess = portalProps.allowDirectAccess;
Log.Message($"[WULA-DEBUG] Set allowDirectAccess: {allowDirectAccess}");
}
// 初始化地图生成器和退出点定义(如果 XML 中没有配置)
@@ -907,19 +1177,23 @@ namespace WulaFallenEmpire
mapGenerator = DefDatabase<MapGeneratorDef>.GetNamed("AncientStockpile", false)
?? DefDatabase<MapGeneratorDef>.GetNamed("Base_Player", false)
?? MapGeneratorDefOf.Base_Player;
Log.Message($"[WULA-DEBUG] Using fallback mapGenerator: {mapGenerator.defName}");
}
if (exitDef == null)
{
exitDef = DefDatabase<ThingDef>.GetNamed("WULA_PocketMapExit", false)
?? ThingDefOf.Door;
Log.Message($"[WULA-DEBUG] Using fallback exitDef: {exitDef.defName}");
}
// 如果位置发生了变化,记录日志
if (oldMap != null && (oldMap != map || oldPos != this.Position))
{
Log.Message($"[WULA] Shuttle moved from {oldMap?.uniqueID}:{oldPos} to {map?.uniqueID}:{this.Position}, updating pocket map exit target");
Log.Message($"[WULA-DEBUG] Shuttle moved from {oldMap?.uniqueID}:{oldPos} to {map?.uniqueID}:{this.Position}, updating pocket map exit target");
}
Log.Message($"[WULA-DEBUG] SpawnSetup completed successfully");
}
#endregion