暂存3
This commit is contained in:
Binary file not shown.
122
Source/Documentation/PocketSpace_ItemFix_README.md
Normal file
122
Source/Documentation/PocketSpace_ItemFix_README.md
Normal 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. 穿梭机起飞时物品应该随行
|
||||||
|
|
||||||
|
修复后,您的物品不会再神秘消失,并且可以正常通过穿梭机界面管理。
|
||||||
@@ -50,8 +50,8 @@ namespace WulaFallenEmpire
|
|||||||
/// <summary>允许直接访问(无需骇入)</summary>
|
/// <summary>允许直接访问(无需骇入)</summary>
|
||||||
private bool allowDirectAccess = true;
|
private bool allowDirectAccess = true;
|
||||||
|
|
||||||
/// <summary>口袋空间内的物品容器</summary>
|
// 注意:我们不再使用自定义的innerContainer,
|
||||||
private ThingOwner innerContainer;
|
// 所有物品都存储在CompTransporter.innerContainer中,保持简单和一致
|
||||||
|
|
||||||
/// <summary>口袋地图退出点(模仿原版 MapPortal.exit)</summary>
|
/// <summary>口袋地图退出点(模仿原版 MapPortal.exit)</summary>
|
||||||
public Building_PocketMapExit exit;
|
public Building_PocketMapExit exit;
|
||||||
@@ -78,8 +78,7 @@ namespace WulaFallenEmpire
|
|||||||
/// <summary>是否允许直接访问口袋空间</summary>
|
/// <summary>是否允许直接访问口袋空间</summary>
|
||||||
public bool AllowDirectAccess => allowDirectAccess;
|
public bool AllowDirectAccess => allowDirectAccess;
|
||||||
|
|
||||||
/// <summary>内部容器</summary>
|
// 注意:我们不再提供InnerContainer属性,因为所有物品都在CompTransporter.innerContainer中
|
||||||
public ThingOwner InnerContainer => innerContainer;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取进入按钮的图标
|
/// 获取进入按钮的图标
|
||||||
@@ -138,7 +137,8 @@ namespace WulaFallenEmpire
|
|||||||
|
|
||||||
public Building_ArmedShuttleWithPocket()
|
public Building_ArmedShuttleWithPocket()
|
||||||
{
|
{
|
||||||
innerContainer = new ThingOwner<Thing>(this, oneStackOnly: false);
|
Log.Message("[WULA-DEBUG] Building_ArmedShuttleWithPocket constructor called");
|
||||||
|
// 不再初始化innerContainer,只使用CompTransporter的容器
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
@@ -149,15 +149,15 @@ namespace WulaFallenEmpire
|
|||||||
|
|
||||||
public override void PostMake()
|
public override void PostMake()
|
||||||
{
|
{
|
||||||
|
Log.Message("[WULA-DEBUG] PostMake called");
|
||||||
base.PostMake();
|
base.PostMake();
|
||||||
if (innerContainer == null)
|
// 不再初始化innerContainer,只使用CompTransporter的容器
|
||||||
{
|
|
||||||
innerContainer = new ThingOwner<Thing>(this, oneStackOnly: false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void ExposeData()
|
public override void ExposeData()
|
||||||
{
|
{
|
||||||
|
Log.Message($"[WULA-DEBUG] ExposeData called, mode: {Scribe.mode}");
|
||||||
|
|
||||||
base.ExposeData();
|
base.ExposeData();
|
||||||
Scribe_Deep.Look(ref pocketMap, "pocketMap");
|
Scribe_Deep.Look(ref pocketMap, "pocketMap");
|
||||||
Scribe_Values.Look(ref pocketMapGenerated, "pocketMapGenerated", false);
|
Scribe_Values.Look(ref pocketMapGenerated, "pocketMapGenerated", false);
|
||||||
@@ -165,13 +165,22 @@ namespace WulaFallenEmpire
|
|||||||
Scribe_Defs.Look(ref mapGenerator, "mapGenerator");
|
Scribe_Defs.Look(ref mapGenerator, "mapGenerator");
|
||||||
Scribe_Defs.Look(ref exitDef, "exitDef");
|
Scribe_Defs.Look(ref exitDef, "exitDef");
|
||||||
Scribe_Values.Look(ref allowDirectAccess, "allowDirectAccess", true);
|
Scribe_Values.Look(ref allowDirectAccess, "allowDirectAccess", true);
|
||||||
Scribe_Deep.Look(ref innerContainer, "innerContainer", this);
|
|
||||||
|
// 不再序列化innerContainer,只使用CompTransporter的容器
|
||||||
|
|
||||||
if (Scribe.mode == LoadSaveMode.PostLoadInit)
|
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)
|
if (pocketMapGenerated)
|
||||||
{
|
{
|
||||||
sb.AppendLine("WULA.PocketSpace.Status".Translate() + ": " + "WULA.PocketSpace.Ready".Translate());
|
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)
|
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();
|
int pawnCount = pocketMap.mapPawns.AllPawnsSpawned.Where(p => p.IsColonist).Count();
|
||||||
|
|
||||||
|
if (pocketItems > 0)
|
||||||
|
{
|
||||||
|
sb.AppendLine($"口袋空间物品: {pocketItems}");
|
||||||
|
}
|
||||||
if (pawnCount > 0)
|
if (pawnCount > 0)
|
||||||
{
|
{
|
||||||
sb.AppendLine("WULA.PocketSpace.PawnCount".Translate(pawnCount));
|
sb.AppendLine("WULA.PocketSpace.PawnCount".Translate(pawnCount));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 在开发模式下显示详细调试信息
|
||||||
|
if (Prefs.DevMode)
|
||||||
|
{
|
||||||
|
sb.AppendLine($"[Debug] {GetPocketSpaceDebugInfo()}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -460,55 +486,231 @@ namespace WulaFallenEmpire
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private void TransferAllFromPocketToMainMap()
|
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
|
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
|
List<Pawn> pawnsToTransfer = pocketMap.mapPawns.AllPawnsSpawned
|
||||||
.Where(p => p.IsColonist).ToList();
|
.Where(p => p.IsColonist).ToList();
|
||||||
|
|
||||||
|
Log.Message($"[WULA-DEBUG] Found {pawnsToTransfer.Count} colonists to transfer");
|
||||||
|
|
||||||
foreach (Pawn pawn in pawnsToTransfer)
|
foreach (Pawn pawn in pawnsToTransfer)
|
||||||
{
|
{
|
||||||
IntVec3 spawnPos = CellFinder.RandomClosewalkCellNear(this.Position, this.Map, 5,
|
if (pawn.Spawned)
|
||||||
p => p.Standable(this.Map) && !p.GetThingList(this.Map).Any(t => t is Pawn));
|
|
||||||
|
|
||||||
if (spawnPos.IsValid)
|
|
||||||
{
|
{
|
||||||
|
Log.Message($"[WULA-DEBUG] Transferring pawn: {pawn.LabelShort}");
|
||||||
pawn.DeSpawn();
|
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
|
List<Thing> itemsToTransfer = pocketMap.listerThings.AllThings
|
||||||
.Where(t => t.def.category == ThingCategory.Item && t.def.EverHaulable).ToList();
|
.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)
|
foreach (Thing item in itemsToTransfer)
|
||||||
{
|
{
|
||||||
if (item.Spawned)
|
if (item.Spawned)
|
||||||
{
|
{
|
||||||
|
Log.Message($"[WULA-DEBUG] Transferring item: {item.LabelShort} (stack: {item.stackCount})");
|
||||||
item.DeSpawn();
|
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);
|
IntVec3 dropPos = CellFinder.RandomClosewalkCellNear(this.Position, this.Map, 3);
|
||||||
if (dropPos.IsValid)
|
if (dropPos.IsValid)
|
||||||
{
|
{
|
||||||
GenPlace.TryPlaceThing(item, dropPos, this.Map, ThingPlaceMode.Near);
|
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)
|
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
|
#endregion
|
||||||
|
|
||||||
#region Gizmo方法
|
#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()
|
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)
|
public void GetChildHolders(List<IThingHolder> outChildren)
|
||||||
{
|
{
|
||||||
ThingOwnerUtility.AppendThingHoldersFromThings(outChildren, GetDirectlyHeldThings());
|
// 只添加穿梭机的主容器
|
||||||
|
CompTransporter transporter = this.GetComp<CompTransporter>();
|
||||||
|
if (transporter != null)
|
||||||
|
{
|
||||||
|
outChildren.Add(transporter);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
@@ -847,7 +1084,7 @@ namespace WulaFallenEmpire
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 重写Tick方法,定期检查穿梭机状态变化
|
/// 重写Tick方法,定期检查穿梭机状态变化和物品同步
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected override void Tick()
|
protected override void Tick()
|
||||||
{
|
{
|
||||||
@@ -858,6 +1095,28 @@ namespace WulaFallenEmpire
|
|||||||
{
|
{
|
||||||
UpdateExitPointTarget();
|
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>
|
/// <summary>
|
||||||
@@ -865,19 +1124,24 @@ namespace WulaFallenEmpire
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public override void SpawnSetup(Map map, bool respawningAfterLoad)
|
public override void SpawnSetup(Map map, bool respawningAfterLoad)
|
||||||
{
|
{
|
||||||
|
Log.Message($"[WULA-DEBUG] SpawnSetup called: map={map?.uniqueID}, respawning={respawningAfterLoad}");
|
||||||
|
|
||||||
// 保存旧位置信息
|
// 保存旧位置信息
|
||||||
Map oldMap = this.Map;
|
Map oldMap = this.Map;
|
||||||
IntVec3 oldPos = this.Position;
|
IntVec3 oldPos = this.Position;
|
||||||
|
|
||||||
base.SpawnSetup(map, respawningAfterLoad);
|
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();
|
UpdateExitPointTarget();
|
||||||
@@ -886,19 +1150,25 @@ namespace WulaFallenEmpire
|
|||||||
if (def.HasModExtension<PocketMapProperties>())
|
if (def.HasModExtension<PocketMapProperties>())
|
||||||
{
|
{
|
||||||
var portalProps = def.GetModExtension<PocketMapProperties>();
|
var portalProps = def.GetModExtension<PocketMapProperties>();
|
||||||
|
Log.Message($"[WULA-DEBUG] Loading portal properties from ThingDef");
|
||||||
|
|
||||||
if (portalProps.pocketMapGenerator != null)
|
if (portalProps.pocketMapGenerator != null)
|
||||||
{
|
{
|
||||||
mapGenerator = portalProps.pocketMapGenerator;
|
mapGenerator = portalProps.pocketMapGenerator;
|
||||||
|
Log.Message($"[WULA-DEBUG] Set mapGenerator: {mapGenerator.defName}");
|
||||||
}
|
}
|
||||||
if (portalProps.exitDef != null)
|
if (portalProps.exitDef != null)
|
||||||
{
|
{
|
||||||
exitDef = portalProps.exitDef;
|
exitDef = portalProps.exitDef;
|
||||||
|
Log.Message($"[WULA-DEBUG] Set exitDef: {exitDef.defName}");
|
||||||
}
|
}
|
||||||
if (portalProps.pocketMapSize != IntVec2.Zero)
|
if (portalProps.pocketMapSize != IntVec2.Zero)
|
||||||
{
|
{
|
||||||
pocketMapSize = portalProps.pocketMapSize;
|
pocketMapSize = portalProps.pocketMapSize;
|
||||||
|
Log.Message($"[WULA-DEBUG] Set pocketMapSize: {pocketMapSize}");
|
||||||
}
|
}
|
||||||
allowDirectAccess = portalProps.allowDirectAccess;
|
allowDirectAccess = portalProps.allowDirectAccess;
|
||||||
|
Log.Message($"[WULA-DEBUG] Set allowDirectAccess: {allowDirectAccess}");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 初始化地图生成器和退出点定义(如果 XML 中没有配置)
|
// 初始化地图生成器和退出点定义(如果 XML 中没有配置)
|
||||||
@@ -907,19 +1177,23 @@ namespace WulaFallenEmpire
|
|||||||
mapGenerator = DefDatabase<MapGeneratorDef>.GetNamed("AncientStockpile", false)
|
mapGenerator = DefDatabase<MapGeneratorDef>.GetNamed("AncientStockpile", false)
|
||||||
?? DefDatabase<MapGeneratorDef>.GetNamed("Base_Player", false)
|
?? DefDatabase<MapGeneratorDef>.GetNamed("Base_Player", false)
|
||||||
?? MapGeneratorDefOf.Base_Player;
|
?? MapGeneratorDefOf.Base_Player;
|
||||||
|
Log.Message($"[WULA-DEBUG] Using fallback mapGenerator: {mapGenerator.defName}");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (exitDef == null)
|
if (exitDef == null)
|
||||||
{
|
{
|
||||||
exitDef = DefDatabase<ThingDef>.GetNamed("WULA_PocketMapExit", false)
|
exitDef = DefDatabase<ThingDef>.GetNamed("WULA_PocketMapExit", false)
|
||||||
?? ThingDefOf.Door;
|
?? ThingDefOf.Door;
|
||||||
|
Log.Message($"[WULA-DEBUG] Using fallback exitDef: {exitDef.defName}");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果位置发生了变化,记录日志
|
// 如果位置发生了变化,记录日志
|
||||||
if (oldMap != null && (oldMap != map || oldPos != this.Position))
|
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
|
#endregion
|
||||||
|
|||||||
Reference in New Issue
Block a user