This commit is contained in:
2025-12-29 13:11:33 +08:00
parent 870f1ad9c3
commit 0cea79ddff
8 changed files with 1 additions and 2734 deletions

View File

@@ -1,405 +0,0 @@
# AI Letter Auto-Response System - 开发文档
## 概述
这个功能将使 P.I.A AI 能够自动监听游戏内的 Letter信封通知并根据内容智能决定是否向玩家发送评论、吐槽、警告或提供帮助建议。
---
## 功能需求
### 核心功能
1. **Mod 设置开关**: 在设置中添加 `启用 AI 自动评论` 开关
2. **Letter 监听**: 拦截所有发送给玩家的 Letter
3. **智能判断**: AI 分析 Letter 内容,决定是否需要回应
4. **自动回复**: 通过现有的 AI 对话系统发送回复
### AI 回应类型
| 类型 | 触发场景示例 | 回应风格 |
|------|-------------|---------|
| 警告 | 袭击通知、疫病爆发 | 紧急提醒,询问是否需要启动防御 |
| 吐槽 | 殖民者精神崩溃、愚蠢死亡 | 幽默/讽刺评论 |
| 建议 | 资源短缺、贸易商到来 | 实用建议 |
| 庆祝 | 任务完成、殖民者加入 | 积极反馈 |
| 沉默 | 常规事件、无关紧要的通知 | 不发送任何回复 |
---
## 技术架构
### 1. 文件结构
```
Source/WulaFallenEmpire/
├── Settings/
│ └── WulaModSettings.cs # 添加新设置字段
├── EventSystem/
│ └── AI/
│ ├── LetterInterceptor/
│ │ ├── Patch_LetterStack.cs # Harmony Patch 拦截 Letter
│ │ ├── LetterAnalyzer.cs # Letter 分析和分类
│ │ └── LetterToPromptConverter.cs # Letter 转提示词
│ └── AIAutoCommentary.cs # AI 自动评论逻辑
```
### 2. 关键类设计
#### 2.1 WulaModSettings.cs (修改)
```csharp
public class WulaModSettings : ModSettings
{
// 现有设置...
// 新增
public bool enableAIAutoCommentary = false; // AI 自动评论开关
public float aiCommentaryChance = 0.7f; // AI 评论概率 (0-1)
public bool commentOnNegativeOnly = false; // 仅评论负面事件
public override void ExposeData()
{
base.ExposeData();
Scribe_Values.Look(ref enableAIAutoCommentary, "enableAIAutoCommentary", false);
Scribe_Values.Look(ref aiCommentaryChance, "aiCommentaryChance", 0.7f);
Scribe_Values.Look(ref commentOnNegativeOnly, "commentOnNegativeOnly", false);
}
}
```
#### 2.2 Patch_LetterStack.cs (新建)
```csharp
using HarmonyLib;
using RimWorld;
using Verse;
namespace WulaFallenEmpire.EventSystem.AI.LetterInterceptor
{
[HarmonyPatch(typeof(LetterStack), nameof(LetterStack.ReceiveLetter),
new Type[] { typeof(Letter), typeof(string) })]
public static class Patch_LetterStack_ReceiveLetter
{
public static void Postfix(Letter let, string debugInfo)
{
// 检查设置开关
if (!WulaModSettings.Instance.enableAIAutoCommentary) return;
// 异步处理,避免阻塞游戏
AIAutoCommentary.ProcessLetter(let);
}
}
}
```
#### 2.3 LetterAnalyzer.cs (新建)
```csharp
namespace WulaFallenEmpire.EventSystem.AI.LetterInterceptor
{
public enum LetterCategory
{
Raid, // 袭击
Disease, // 疾病
MentalBreak, // 精神崩溃
Trade, // 贸易
Quest, // 任务
Death, // 死亡
Recruitment, // 招募
Resource, // 资源
Weather, // 天气
Positive, // 正面事件
Negative, // 负面事件
Neutral, // 中性事件
Unknown // 未知
}
public static class LetterAnalyzer
{
public static LetterCategory Categorize(Letter letter)
{
// 根据 LetterDef 分类
var def = letter.def;
if (def == LetterDefOf.ThreatBig || def == LetterDefOf.ThreatSmall)
return LetterCategory.Raid;
if (def == LetterDefOf.Death)
return LetterCategory.Death;
if (def == LetterDefOf.PositiveEvent)
return LetterCategory.Positive;
if (def == LetterDefOf.NegativeEvent)
return LetterCategory.Negative;
if (def == LetterDefOf.NeutralEvent)
return LetterCategory.Neutral;
// 根据内容关键词进一步分类
string text = letter.text?.ToLower() ?? "";
if (text.Contains("raid") || text.Contains("袭击") || text.Contains("attack"))
return LetterCategory.Raid;
if (text.Contains("disease") || text.Contains("疫病") || text.Contains("plague"))
return LetterCategory.Disease;
if (text.Contains("mental") || text.Contains("精神") || text.Contains("break"))
return LetterCategory.MentalBreak;
if (text.Contains("trade") || text.Contains("贸易") || text.Contains("商队"))
return LetterCategory.Trade;
return LetterCategory.Unknown;
}
public static bool ShouldComment(Letter letter)
{
var category = Categorize(letter);
// 始终评论的类型
switch (category)
{
case LetterCategory.Raid:
case LetterCategory.Death:
case LetterCategory.MentalBreak:
case LetterCategory.Disease:
return true;
case LetterCategory.Trade:
case LetterCategory.Quest:
case LetterCategory.Positive:
return Rand.Chance(WulaModSettings.Instance.aiCommentaryChance);
case LetterCategory.Neutral:
case LetterCategory.Unknown:
return Rand.Chance(0.3f); // 低概率评论
default:
return false;
}
}
}
}
```
#### 2.4 LetterToPromptConverter.cs (新建)
```csharp
namespace WulaFallenEmpire.EventSystem.AI.LetterInterceptor
{
public static class LetterToPromptConverter
{
public static string Convert(Letter letter, LetterCategory category)
{
var sb = new StringBuilder();
sb.AppendLine("[SYSTEM EVENT NOTIFICATION]");
sb.AppendLine($"Event Type: {category}");
sb.AppendLine($"Severity: {GetSeverityFromDef(letter.def)}");
sb.AppendLine($"Title: {letter.label}");
sb.AppendLine($"Content: {letter.text}");
sb.AppendLine();
sb.AppendLine("[INSTRUCTION]");
sb.AppendLine("You have received a game event notification. Based on the event type and content:");
sb.AppendLine("- For RAIDS/THREATS: Offer tactical advice or ask if player needs orbital support");
sb.AppendLine("- For DEATHS: Express condolences or make a sardonic comment if death was avoidable");
sb.AppendLine("- For MENTAL BREAKS: Comment on the colonist's weakness or offer mood management tips");
sb.AppendLine("- For TRADE: Suggest useful purchases or sales");
sb.AppendLine("- For POSITIVE events: Celebrate briefly");
sb.AppendLine("- For trivial events: You may choose to say nothing (respond with [NO_COMMENT])");
sb.AppendLine();
sb.AppendLine("Keep your response brief (1-2 sentences). Match your personality as the Legion AI.");
sb.AppendLine("If you don't think this event warrants a response, reply with exactly: [NO_COMMENT]");
return sb.ToString();
}
private static string GetSeverityFromDef(LetterDef def)
{
if (def == LetterDefOf.ThreatBig) return "CRITICAL";
if (def == LetterDefOf.ThreatSmall) return "WARNING";
if (def == LetterDefOf.Death) return "SERIOUS";
if (def == LetterDefOf.NegativeEvent) return "MODERATE";
if (def == LetterDefOf.PositiveEvent) return "GOOD";
return "INFO";
}
}
}
```
#### 2.5 AIAutoCommentary.cs (新建)
```csharp
namespace WulaFallenEmpire.EventSystem.AI
{
public static class AIAutoCommentary
{
private static Queue<Letter> pendingLetters = new Queue<Letter>();
private static bool isProcessing = false;
public static void ProcessLetter(Letter letter)
{
// 检查是否应该评论
if (!LetterAnalyzer.ShouldComment(letter))
{
WulaLog.Debug($"[AI Commentary] Skipping letter: {letter.label}");
return;
}
// 加入队列
pendingLetters.Enqueue(letter);
// 开始处理(如果还没在处理中)
if (!isProcessing)
{
ProcessNextLetter();
}
}
private static async void ProcessNextLetter()
{
if (pendingLetters.Count == 0)
{
isProcessing = false;
return;
}
isProcessing = true;
var letter = pendingLetters.Dequeue();
try
{
var category = LetterAnalyzer.Categorize(letter);
var prompt = LetterToPromptConverter.Convert(letter, category);
// 获取 AI 核心
var aiCore = Find.World?.GetComponent<AIIntelligenceCore>();
if (aiCore == null)
{
WulaLog.Debug("[AI Commentary] AIIntelligenceCore not found.");
ProcessNextLetter();
return;
}
// 发送到 AI 并等待响应
string response = await aiCore.SendSystemMessageAsync(prompt);
// 检查是否选择不评论
if (string.IsNullOrEmpty(response) || response.Contains("[NO_COMMENT]"))
{
WulaLog.Debug($"[AI Commentary] AI chose not to comment on: {letter.label}");
}
else
{
// 显示 AI 的评论
DisplayAICommentary(response, letter);
}
}
catch (Exception ex)
{
WulaLog.Debug($"[AI Commentary] Error processing letter: {ex.Message}");
}
// 延迟处理下一个,避免刷屏
await Task.Delay(2000);
ProcessNextLetter();
}
private static void DisplayAICommentary(string response, Letter originalLetter)
{
// 方式1: 作为小型通知显示在 WulaLink 小 UI
var overlay = Find.WindowStack.Windows.OfType<Overlay_WulaLink>().FirstOrDefault();
if (overlay != null)
{
overlay.AddAIMessage(response);
}
// 方式2: 作为 Message 显示在屏幕左上角
Messages.Message($"[P.I.A]: {response}", MessageTypeDefOf.SilentInput);
}
}
}
```
---
## 实现步骤
### 阶段 1: 基础设施 (预计 1 小时)
1. [ ] 在 `WulaModSettings.cs` 添加新设置字段
2. [ ] 在设置 UI 中添加开关
3. [ ] 添加对应的 Keyed 翻译
### 阶段 2: Letter 拦截 (预计 30 分钟)
1. [ ] 创建 `Patch_LetterStack.cs` Harmony Patch
2. [ ] 确保 Patch 正确注册到 Harmony 实例
3. [ ] 测试 Letter 拦截是否正常工作
### 阶段 3: Letter 分析 (预计 1 小时)
1. [ ] 创建 `LetterAnalyzer.cs` 分类逻辑
2. [ ] 创建 `LetterToPromptConverter.cs` 转换逻辑
3. [ ] 测试不同类型 Letter 的分类准确性
### 阶段 4: AI 集成 (预计 1.5 小时)
1. [ ] 创建 `AIAutoCommentary.cs` 管理类
2. [ ] 集成到现有的 `AIIntelligenceCore` 系统
3. [ ] 实现队列处理避免刷屏
4. [ ] 添加 `SendSystemMessageAsync` 方法到 AIIntelligenceCore
### 阶段 5: UI 显示 (预计 30 分钟)
1. [ ] 决定评论显示方式WulaLink UI / Message / 独立通知)
2. [ ] 实现显示逻辑
3. [ ] 测试显示效果
### 阶段 6: 测试与优化 (预计 1 小时)
1. [ ] 测试各类 Letter 的评论效果
2. [ ] 调整评论概率和过滤规则
3. [ ] 优化提示词以获得更好的 AI 回应
4. [ ] 添加速率限制避免 API 过载
---
## 需要添加的翻译键
```xml
<!-- AI Auto Commentary Settings -->
<Wula_AISettings_AutoCommentary>启用 AI 自动评论</Wula_AISettings_AutoCommentary>
<Wula_AISettings_AutoCommentaryDesc>开启后P.I.A 会自动对游戏事件(袭击、死亡、贸易等)发表评论或提供建议。</Wula_AISettings_AutoCommentaryDesc>
<Wula_AISettings_CommentaryChance>评论概率</Wula_AISettings_CommentaryChance>
<Wula_AISettings_CommentaryChanceDesc>AI 对中性事件发表评论的概率。负面事件(如袭击)总是会评论。</Wula_AISettings_CommentaryChanceDesc>
<Wula_AISettings_NegativeOnly>仅评论负面事件</Wula_AISettings_NegativeOnly>
<Wula_AISettings_NegativeOnlyDesc>开启后AI 只会对负面事件(袭击、死亡、疾病等)发表评论。</Wula_AISettings_NegativeOnlyDesc>
```
---
## 注意事项
1. **API 限流**: 需要实现请求队列和速率限制,避免短时间内发送过多请求
2. **异步处理**: 所有 AI 请求必须异步处理,避免阻塞游戏主线程
3. **用户控制**: 提供足够的设置选项让用户控制评论频率和类型
4. **优雅降级**: 如果 AI 服务不可用,静默失败而不影响游戏
5. **内存管理**: 队列大小限制,避免积累过多未处理的 Letter
---
## 预期效果示例
**场景 1: 袭击通知**
```
[Letter] 海盗袭击!一群海盗正在向你的殖民地进发。
[P.I.A] 检测到敌对势力入侵。需要我启动轨道监视协议吗?
```
**场景 2: 殖民者死亡**
```
[Letter] 张三死了。他被一只疯狂的松鼠咬死了。
[P.I.A] ...被松鼠咬死?这位殖民者的战斗技能令人印象深刻。
```
**场景 3: 贸易商到来**
```
[Letter] 商队到来。一个来自外部势力的商队想要与你交易。
[P.I.A] 贸易商队抵达。我注意到你的钢铁储备较低,建议优先采购。
```
---
## 依赖项
- Harmony 2.0+ (用于 Patch)
- 现有的 AIIntelligenceCore 系统
- 现有的 WulaModSettings 系统
- 现有的 Overlay_WulaLink UI
---
*文档版本: 1.0*
*创建时间: 2025-12-28*

View File

@@ -1,56 +0,0 @@
WulaLink / AI Core Handoff (for Claude)
Context
- Mod: RimWorld WulaFallenEmpire.
- The AI conversation system was refactored to use a shared WorldComponent core.
- The small WulaLink overlay is now optional; the main event entry should open the old large dialog.
Current behavior and verification
- `Effect_OpenAIConversation` now opens the large window `Dialog_AIConversation`.
- The small overlay (`Overlay_WulaLink`) remains available via dev/debug entry.
- Non-final / streaming AI output should not create empty lines in the small window:
- SimpleAIClient is non-stream by default.
- AIIntelligenceCore only fires `OnMessageReceived` on final reply and ignores empty or XML-only output.
- Overlay filters `tool`/`toolcall` messages unless DevMode is on.
- Build verified: `dotnet build C:\Steam\steamapps\common\RimWorld\Mods\3516260226\Source\WulaFallenEmpire\WulaFallenEmpire.csproj`
Key changes
1) New shared AI core
- File: `Source/WulaFallenEmpire/EventSystem/AI/AIIntelligenceCore.cs`
- WorldComponent with static `Instance` and events:
- `OnMessageReceived`, `OnThinkingStateChanged`, `OnExpressionChanged`
- Public API:
- `InitializeConversation`, `GetHistorySnapshot`, `SetExpression`, `SetPortrait`, `SendMessage`, `SendUserMessage`
- Core responsibilities:
- History load/save via `AIHistoryManager`
- `/clear` support
- Expression tag parsing `[EXPR:n]`
- 3-phase tool pipeline (query/action/reply) from the old dialog logic
- Tool execution and ledger tracking
2) OpenAI conversation entry now opens the large dialog
- File: `Source/WulaFallenEmpire/EventSystem/Effect/Effect_OpenAIConversation.cs`
- Uses `Dialog_AIConversation` instead of `Overlay_WulaLink`.
- XML entry in `1.6/1.6/Defs/EventDefs/Wula_AI_Events.xml` stays the same.
3) Overlay and tools point to the shared core
- Files:
- `Source/WulaFallenEmpire/EventSystem/AI/UI/Overlay_WulaLink.cs`
- `Source/WulaFallenEmpire/EventSystem/AI/UI/Overlay_WulaLink_Notification.cs`
- `Source/WulaFallenEmpire/EventSystem/AI/Tools/Tool_ChangeExpression.cs`
- `Source/WulaFallenEmpire/EventSystem/AI/Tools/Tool_GetRecentNotifications.cs`
- Namespace import updated to `WulaFallenEmpire.EventSystem.AI`.
4) WulaLink styles restored for overlay build
- File: `Source/WulaFallenEmpire/EventSystem/AI/UI/WulaLinkStyles.cs`
- Added colors used by overlay:
- `InputBarColor`, `SystemAccentColor`, `SenseiTextColor`, `StudentTextColor`
Notes / gotchas
- Some UI files are not UTF-8 (likely ANSI). If you edit them with scripts, prefer `-Encoding Default` in PowerShell to avoid invalid UTF-8 errors.
- The old large dialog is still self-contained; the shared core is used by overlay + tools. Future cleanup can rewire `Dialog_AIConversation` to use the core if desired.
Open questions / TODO (if needed later)
- Memory system integration is not done in the core:
- `AIMemoryManager.cs`, `MemoryPrompts.cs`, and `Dialog_AIConversation.cs` integration still pending.
- If the overlay should become a non-debug entry, wire an explicit effect or UI button to open it.

View File

@@ -1,429 +0,0 @@
# RimWorld AI Agent 开发文档
> 本文档用于移交给 Codex 继续开发
---
## 1. 项目概述
### 目标
创建一个**完全自主的 AI Agent**,能够自动玩 RimWorld 游戏。用户只需给出开放式指令(如"帮我挖点铁"或"帮我玩10分钟"AI 即可独立决策并操作游戏。
### 技术栈
- **语言**: C# (.NET Framework 4.8)
- **框架**: RimWorld Mod (Verse/RimWorld API)
- **AI 后端**: 阿里云百炼 (DashScope) API
- **VLM 模型**: Qwen-VL / Qwen-Omni-Realtime
### 核心设计
```
用户指令 → AIIntelligenceCore → [被动模式 | 主动模式] → 工具执行 → 游戏操作
```
---
## 2. 架构
### 2.1 模式切换设计
```
┌────────────────────────────────────────────┐
│ AIIntelligenceCore │
│ ┌─────────────┐ ┌─────────────────┐ │
│ │ 被动模式 │◄──►│ 主动模式 │ │
│ │ (聊天对话) │ │ (Agent循环) │ │
│ └─────────────┘ └────────┬────────┘ │
└──────────────────────────────┼────────────┘
┌─────────────────────┐
│ AutonomousAgentLoop │
│ Observe → Think │
│ → Act │
└─────────────────────┘
```
**模式切换触发条件(待实现)**:
- 用户说"帮我玩X分钟" → 切换到主动模式
- 主动模式任务完成 → 自动切回被动模式
- 用户说"停止" → 强制切回被动模式
### 2.2 文件结构
```
Source/WulaFallenEmpire/EventSystem/AI/
├── AIIntelligenceCore.cs # 核心AI控制器已有
├── SimpleAIClient.cs # HTTP API 客户端(已有)
├── ScreenCaptureUtility.cs # 截屏工具(已有)
├── Agent/ # ★ 新增目录
│ ├── AutonomousAgentLoop.cs # 主动模式循环
│ ├── StateObserver.cs # 游戏状态收集器
│ ├── GameStateSnapshot.cs # 状态数据结构
│ ├── VisualInteractionTools.cs # 视觉交互工具(10个)
│ ├── MouseSimulator.cs # 鼠标模拟
│ └── OmniRealtimeClient.cs # WebSocket流式连接
├── Tools/ # AI工具
│ ├── AITool.cs # 工具基类(已有)
│ ├── Tool_GetGameState.cs # ★ 新增
│ ├── Tool_DesignateMine.cs # ★ 新增
│ ├── Tool_DraftPawn.cs # ★ 新增
│ ├── Tool_VisualClick.cs # ★ 新增
│ └── ... (其他原有工具)
└── UI/
├── Dialog_AIConversation.cs # 对话UI已有
└── Overlay_WulaLink.cs # 悬浮UI已有
```
---
## 3. 已完成组件
### 3.1 StateObserver (状态观察器)
**路径**: [Agent/StateObserver.cs](file:///C:/Steam/steamapps/common/RimWorld/Mods/3516260226/Source/WulaFallenEmpire/EventSystem/AI/Agent/StateObserver.cs)
**功能**: 收集当前游戏状态,生成给 VLM 的文本描述
**API**:
```csharp
public static class StateObserver
{
// 捕获当前游戏状态快照
public static GameStateSnapshot CaptureState();
}
```
**收集内容**:
- 时间(小时、季节、年份)
- 环境(生物群系、温度、天气)
- 殖民者(名字、健康、心情、当前工作、位置)
- 资源(钢铁、银、食物、医药等)
- 建筑进度(蓝图、建造框架)
- 威胁(敌对派系、距离)
- 最近消息
---
### 3.2 GameStateSnapshot (状态数据结构)
**路径**: [Agent/GameStateSnapshot.cs](file:///C:/Steam/steamapps/common/RimWorld/Mods/3516260226/Source/WulaFallenEmpire/EventSystem/AI/Agent/GameStateSnapshot.cs)
**功能**: 存储游戏状态数据
**关键方法**:
```csharp
public class GameStateSnapshot
{
public List<PawnSnapshot> Colonists;
public Dictionary<string, int> Resources;
public List<ThreatSnapshot> Threats;
// 生成给VLM的文本描述
public string ToPromptText();
}
```
---
### 3.3 VisualInteractionTools (视觉交互工具集)
**路径**: [Agent/VisualInteractionTools.cs](file:///C:/Steam/steamapps/common/RimWorld/Mods/3516260226/Source/WulaFallenEmpire/EventSystem/AI/Agent/VisualInteractionTools.cs)
**功能**: 10个纯视觉交互工具使用 Windows API 模拟输入
| 方法 | 功能 | 参数 |
|------|------|------|
| [MouseClick(x, y, button, clicks)](file:///C:/Steam/steamapps/common/RimWorld/Mods/3516260226/Source/WulaFallenEmpire/EventSystem/AI/Agent/VisualInteractionTools.cs#49-89) | 鼠标点击 | 0-1比例坐标 |
| [TypeText(x, y, text)](file:///C:/Steam/steamapps/common/RimWorld/Mods/3516260226/Source/WulaFallenEmpire/EventSystem/AI/Agent/VisualInteractionTools.cs#90-118) | 输入文本 | 通过剪贴板 |
| [ScrollWindow(x, y, direction, amount)](file:///C:/Steam/steamapps/common/RimWorld/Mods/3516260226/Source/WulaFallenEmpire/EventSystem/AI/Agent/VisualInteractionTools.cs#119-144) | 滚动 | up/down |
| [MouseDrag(sx, sy, ex, ey, duration)](file:///C:/Steam/steamapps/common/RimWorld/Mods/3516260226/Source/WulaFallenEmpire/EventSystem/AI/Agent/VisualInteractionTools.cs#145-187) | 拖拽 | 起止坐标 |
| [Wait(seconds)](file:///C:/Steam/steamapps/common/RimWorld/Mods/3516260226/Source/WulaFallenEmpire/EventSystem/AI/Agent/VisualInteractionTools.cs#188-203) | 等待 | 秒数 |
| [PressEnter()](file:///C:/Steam/steamapps/common/RimWorld/Mods/3516260226/Source/WulaFallenEmpire/EventSystem/AI/Agent/VisualInteractionTools.cs#204-220) | 按回车 | 无 |
| [PressEscape()](file:///C:/Steam/steamapps/common/RimWorld/Mods/3516260226/Source/WulaFallenEmpire/EventSystem/AI/Agent/VisualInteractionTools.cs#221-237) | 按ESC | 无 |
| [DeleteText(x, y, count)](file:///C:/Steam/steamapps/common/RimWorld/Mods/3516260226/Source/WulaFallenEmpire/EventSystem/AI/Agent/VisualInteractionTools.cs#238-262) | 删除 | 字符数 |
| [PressHotkey(x, y, hotkey)](file:///C:/Steam/steamapps/common/RimWorld/Mods/3516260226/Source/WulaFallenEmpire/EventSystem/AI/Agent/VisualInteractionTools.cs#263-306) | 快捷键 | 如"ctrl+c" |
| [CloseWindow(x, y)](file:///C:/Steam/steamapps/common/RimWorld/Mods/3516260226/Source/WulaFallenEmpire/EventSystem/AI/Agent/VisualInteractionTools.cs#307-329) | 关闭窗口 | Alt+F4 |
---
### 3.4 AutonomousAgentLoop (自主Agent循环)
**路径**: [Agent/AutonomousAgentLoop.cs](file:///C:/Steam/steamapps/common/RimWorld/Mods/3516260226/Source/WulaFallenEmpire/EventSystem/AI/Agent/AutonomousAgentLoop.cs)
**功能**: 主动模式的核心循环
**状态**:
- `IsRunning`: 是否运行中
- `CurrentObjective`: 当前目标
- `DecisionCount`: 已执行决策次数
**关键API**:
```csharp
public class AutonomousAgentLoop : GameComponent
{
public static AutonomousAgentLoop Instance;
// 开始执行目标
public void StartObjective(string objective);
// 停止Agent
public void Stop();
// 事件
public event Action<string> OnDecisionMade;
public event Action<string> OnObjectiveComplete;
}
```
**待完成**: [ExecuteDecision()](file:///C:/Steam/steamapps/common/RimWorld/Mods/3516260226/Source/WulaFallenEmpire/EventSystem/AI/Agent/AutonomousAgentLoop.cs#244-269) 方法需要整合工具执行逻辑
---
### 3.5 原生API工具
| 工具 | 路径 | 功能 | 参数格式 |
|------|------|------|----------|
| [Tool_GetGameState](file:///C:/Steam/steamapps/common/RimWorld/Mods/3516260226/Source/WulaFallenEmpire/EventSystem/AI/Tools/Tool_GetGameState.cs#8-45) | Tools/ | 获取游戏状态 | `<get_game_state/>` |
| [Tool_DesignateMine](file:///C:/Steam/steamapps/common/RimWorld/Mods/3516260226/Source/WulaFallenEmpire/EventSystem/AI/Tools/Tool_DesignateMine.cs#12-139) | Tools/ | 采矿指令 | `<designate_mine><x>数字</x><z>数字</z><radius>可选</radius></designate_mine>` |
| [Tool_DraftPawn](file:///C:/Steam/steamapps/common/RimWorld/Mods/3516260226/Source/WulaFallenEmpire/EventSystem/AI/Tools/Tool_DraftPawn.cs#10-105) | Tools/ | 征召殖民者 | `<draft_pawn><pawn_name>名字</pawn_name><draft>true/false</draft></draft_pawn>` |
---
## 4. 待完成任务
### 4.1 模式切换整合 (高优先级)
**目标**: 在 [AIIntelligenceCore](file:///C:/Steam/steamapps/common/RimWorld/Mods/3516260226/Source/WulaFallenEmpire/EventSystem/AI/AIIntelligenceCore.cs#16-1364) 中实现被动/主动模式切换
**实现思路**:
```csharp
// AIIntelligenceCore 中添加
private bool _isAgentMode = false;
public void ProcessUserMessage(string message)
{
// 检测是否触发主动模式
if (IsAgentTrigger(message, out string objective, out float duration))
{
_isAgentMode = true;
AutonomousAgentLoop.Instance.StartObjective(objective);
// 设置定时器duration后自动停止
}
else
{
// 正常对话处理
RunConversation(message);
}
}
private bool IsAgentTrigger(string msg, out string obj, out float dur)
{
// 匹配模式:
// "帮我玩10分钟" → obj="管理殖民地", dur=600
// "帮我挖点铁" → obj="采集铁矿", dur=0(无限)
// ...
}
```
---
### 4.2 工具执行整合 (高优先级)
**目标**: 让 `AutonomousAgentLoop.ExecuteDecision()` 能够执行工具
**当前状态**: 方法体是空的 TODO
**实现思路**:
```csharp
private void ExecuteDecision(string decision)
{
// 1. 检查特殊标记
if (decision.Contains("<no_action")) return;
if (decision.Contains("<objective_complete"))
{
OnObjectiveComplete?.Invoke(_currentObjective);
Stop();
return;
}
// 2. 获取工具实例
var core = AIIntelligenceCore.Instance;
var tools = core.GetAvailableTools();
// 3. 解析XML工具调用复用AIIntelligenceCore的逻辑
foreach (var tool in tools)
{
if (decision.Contains($"<{tool.Name}"))
{
string result = tool.Execute(decision);
WulaLog.Debug($"Tool {tool.Name}: {result}");
_lastToolResult = result;
break;
}
}
}
```
---
### 4.3 AI待办清单 (中优先级)
**目标**: AI 维护自己的待办清单,持久化到游戏存档
**设计**:
```csharp
public class AgentTodoList : IExposable
{
public List<TodoItem> Items = new List<TodoItem>();
public void ExposeData()
{
Scribe_Collections.Look(ref Items, "todoItems", LookMode.Deep);
}
}
public class TodoItem : IExposable
{
public string Description;
public bool IsComplete;
public int Priority;
public int CreatedTick;
}
```
---
### 4.4 Qwen-Omni-Realtime 测试 (低优先级)
**目标**: 测试 WebSocket 流式连接
**已完成**: [OmniRealtimeClient.cs](file:///C:/Steam/steamapps/common/RimWorld/Mods/3516260226/Source/WulaFallenEmpire/EventSystem/AI/Agent/OmniRealtimeClient.cs) 基础实现
**待测试**:
- WebSocket 连接建立
- 图片发送 (`input_image_buffer.append`)
- 文本接收 (`response.text.delta`)
---
## 5. 关键接口参考
### 5.1 AITool 基类
```csharp
public abstract class AITool
{
public abstract string Name { get; }
public abstract string Description { get; }
public abstract string UsageSchema { get; }
public abstract string Execute(string args);
// 解析XML参数
protected Dictionary<string, string> ParseXmlArgs(string xmlContent);
}
```
### 5.2 SimpleAIClient API
```csharp
public class SimpleAIClient
{
public SimpleAIClient(string apiKey, string baseUrl, string model);
// 文本对话
public Task<string> GetChatCompletionAsync(
string systemPrompt,
List<(string role, string message)> messages,
int maxTokens = 1024,
float temperature = 0.7f
);
// VLM 视觉分析
public Task<string> GetVisionCompletionAsync(
string systemPrompt,
string userPrompt,
string base64Image,
int maxTokens = 1024,
float temperature = 0.7f
);
}
```
### 5.3 设置 (WulaFallenEmpireSettings)
```csharp
public class WulaFallenEmpireSettings : ModSettings
{
// 主模型
public string apiKey;
public string baseUrl = "https://dashscope.aliyuncs.com/compatible-mode/v1";
public string model = "qwen-turbo";
// VLM 模型
public string vlmApiKey;
public string vlmBaseUrl;
public string vlmModel = "qwen-vl-max";
public bool enableVlmFeatures = false;
}
```
---
## 6. 开发指南
### 6.1 添加新工具
1. 在 [Tools/](file:///C:/Steam/steamapps/common/RimWorld/Mods/3516260226/Source/WulaFallenEmpire/EventSystem/AI/AIIntelligenceCore.cs#310-337) 创建新类继承 [AITool](file:///C:/Steam/steamapps/common/RimWorld/Mods/3516260226/Source/WulaFallenEmpire/EventSystem/AI/Tools/AITool.cs#8-41)
2. 实现 [Name](file:///C:/Steam/steamapps/common/RimWorld/Mods/3516260226/Source/WulaFallenEmpire/EventSystem/AI/AIIntelligenceCore.cs#636-642), [Description](file:///C:/Steam/steamapps/common/RimWorld/Mods/3516260226/Source/WulaFallenEmpire/EventSystem/AI/Agent/StateObserver.cs#156-187), `UsageSchema`, [Execute](file:///C:/Steam/steamapps/common/RimWorld/Mods/3516260226/Source/WulaFallenEmpire/EventSystem/AI/Tools/Tool_VisualClick.cs#133-165)
3. 在 `AIIntelligenceCore.InitializeTools()` 中注册
```csharp
// 示例Tool_BuildWall.cs
public class Tool_BuildWall : AITool
{
public override string Name => "build_wall";
public override string Description => "在指定位置放置墙壁蓝图";
public override string UsageSchema => "<build_wall><x>X</x><z>Z</z><stuff>材料</stuff></build_wall>";
public override string Execute(string args)
{
var dict = ParseXmlArgs(args);
// 实现建造逻辑
// GenConstruct.PlaceBlueprintForBuild(...)
return "Success: 墙壁蓝图已放置";
}
}
```
### 6.2 调试技巧
- 使用 `WulaLog.Debug()` 输出日志
- 检查 RimWorld 的 `Player.log` 文件
- 在开发者模式下 `Prefs.DevMode = true` 显示更多信息
### 6.3 常见问题
**Q: .NET Framework 4.8 兼容性问题**
- 不支持 `TakeLast()` → 使用 `Skip(list.Count - n)`
- 不支持 `string.Contains(x, StringComparison)` → 使用 `IndexOf`
**Q: Unity 主线程限制**
- 异步操作结果需要回到主线程执行
- 使用 `LongEventHandler.ExecuteWhenFinished(() => { ... })`
---
## 7. 参考资源
- [RimWorld Modding Wiki](https://rimworldwiki.com/wiki/Modding)
- [Harmony Patching](https://harmony.pardeike.net/)
- [阿里云百炼 API](https://help.aliyun.com/zh/model-studio/)
- [Qwen-Omni 文档](https://help.aliyun.com/zh/model-studio/user-guide/qwen-omni)
---
**文档版本**: v1.0
**更新时间**: 2025-12-27
**作者**: Gemini AI Agent

View File

@@ -1,3 +0,0 @@
https://api.xiaomimimo.com/v1
mimo-v2-flash
sk-cuwai2jix0zwrghj307pmvdpmtoc74j4uv9bejglxcs89tnx

View File

@@ -1,150 +0,0 @@
# WulaLink UI 修复任务 - Codex 交接文档
## 项目概述
RimWorld Mod: [WulaFallenEmpire](file:///C:/Steam/steamapps/common/RimWorld/Mods/3516260226/Source/WulaFallenEmpire)
目标: 实现 MomoTalk 风格的悬浮 AI 聊天 UI (WulaLink),同时确保原有大 UI 不被破坏。
## 关键文件路径
```
C:\Steam\steamapps\common\RimWorld\Mods\3516260226\Source\WulaFallenEmpire\
├── EventSystem\
│ ├── Dialog_CustomDisplay.cs # 基类,包含正确的按钮样式和布局逻辑
│ └── AI\
│ ├── AIIntelligenceCore.cs # AI 核心逻辑 (WorldComponent) - 已完成
│ ├── DebugActions_WulaLink.cs # Debug 入口
│ └── UI\
│ ├── Dialog_AIConversation.cs # 大 UI - 需要修复布局
│ ├── Overlay_WulaLink.cs # 小悬浮框 - 需要修复样式
│ ├── Overlay_WulaLink_Notification.cs # 通知弹窗 - 已完成
│ └── WulaLinkStyles.cs # 样式定义 - 需要调整颜色
```
---
## 问题 1: 大 UI (Dialog_AIConversation) 布局损坏
### 现状
[Dialog_AIConversation](file:///C:/Steam/steamapps/common/RimWorld/Mods/3516260226/Source/WulaFallenEmpire/EventSystem/AI/UI/Dialog_AIConversation.cs#108-133) 继承自 [Dialog_CustomDisplay](file:///C:/Steam/steamapps/common/RimWorld/Mods/3516260226/Source/WulaFallenEmpire/EventSystem/Dialog_CustomDisplay.cs#10-668),但 [DoWindowContents](file:///C:/Steam/steamapps/common/RimWorld/Mods/3516260226/Source/WulaFallenEmpire/EventSystem/AI/UI/Dialog_AIConversation.cs#1177-1328) 被完全重写,丢失了原有的沉浸式布局。
### 期望效果 (参考用户截图)
- 左侧: 大尺寸立绘 (占据约 60% 窗口)
- 右下: 半透明暗红色面板,包含:
- 标题 "「军团」,P.I.A"
- 描述文本区域
- 底部按钮 "打开通讯频道" (使用 [DrawCustomButton](file:///C:/Steam/steamapps/common/RimWorld/Mods/3516260226/Source/WulaFallenEmpire/EventSystem/Dialog_CustomDisplay.cs#388-449) 样式)
- 点击按钮后进入聊天模式 (显示对话历史)
### 修复方案
恢复 `base.DoWindowContents(inRect)` 的调用,或手动复制 `Dialog_CustomDisplay.DoWindowContents` 的布局逻辑。
关键代码参考 ([Dialog_CustomDisplay.cs](file:///C:/Steam/steamapps/common/RimWorld/Mods/3516260226/Source/WulaFallenEmpire/EventSystem/Dialog_CustomDisplay.cs) 第 144-280 行):
```csharp
// 1. 绘制背景
if (background != null) GUI.DrawTexture(inRect, background, ScaleMode.StretchToFill);
// 2. 立绘 (Config.showPortrait)
Rect portraitRect = Config.GetScaledRect(Config.portraitSize, inRect);
// 3. 标题 (Config.showLabel)
Rect labelRect = Config.GetScaledRect(Config.labelSize, inRect);
// 4. 描述 (Config.showDescriptions)
Rect descriptionRect = Config.GetScaledRect(Config.descriptionsSize, inRect);
// 5. 选项按钮 (Config.showOptions)
Rect optionsRect = Config.GetScaledRect(Config.optionsListSize, inRect);
```
---
## 问题 2: 小悬浮框 (Overlay_WulaLink) 样式问题
### 2.1 背景颜色错误
**现状**: 使用纯黑背景 `new Color(10, 10, 12, 255)`
**期望**: 半透明暗红色,与大 UI 一致
修改 [WulaLinkStyles.cs](file:///C:/Steam/steamapps/common/RimWorld/Mods/3516260226/Source/WulaFallenEmpire/EventSystem/AI/UI/WulaLinkStyles.cs):
```csharp
// 修改前
public static readonly Color BackgroundColor = new Color32(10, 10, 12, 255);
// 修改后
public static readonly Color BackgroundColor = new Color(0.2f, 0.05f, 0.05f, 0.85f); // 半透明暗红
```
### 2.2 消息间距过大
**原因**: `role == "tool"` 的消息也被渲染,占用空间但不显示内容。
修改 [Overlay_WulaLink.cs](file:///C:/Steam/steamapps/common/RimWorld/Mods/3516260226/Source/WulaFallenEmpire/EventSystem/AI/UI/Overlay_WulaLink.cs) 的 [DrawMessageList](file:///C:/Steam/steamapps/common/RimWorld/Mods/3516260226/Source/WulaFallenEmpire/EventSystem/AI/UI/Overlay_WulaLink.cs#265-344) 方法:
```csharp
// 在 foreach 循环中添加过滤
foreach (var msg in history)
{
// 跳过工具调用消息
if (msg.role == "tool") continue;
// ... 其余渲染逻辑
}
```
### 2.3 气泡无圆角
**问题**: RimWorld 原生 `Widgets.DrawBoxSolid` 不支持圆角。
**方案**:
- 方案 A: 使用 9-slice 圆角贴图 (`Textures/UI/BubbleRounded.png`)
- 方案 B: 接受直角,但添加边框使其更精致
### 2.4 头像无圆形处理
**方案**: 使用圆形遮罩贴图覆盖在头像上,或创建 `Textures/UI/AvatarMask.png`
### 2.5 按钮样式不一致
**现状**: 使用默认 `Widgets.ButtonText`
**期望**: 使用 `Dialog_CustomDisplay.DrawCustomButton` 样式
修改 [Overlay_WulaLink.cs](file:///C:/Steam/steamapps/common/RimWorld/Mods/3516260226/Source/WulaFallenEmpire/EventSystem/AI/UI/Overlay_WulaLink.cs) 的 [DrawFooter](file:///C:/Steam/steamapps/common/RimWorld/Mods/3516260226/Source/WulaFallenEmpire/EventSystem/AI/UI/Overlay_WulaLink.cs#345-385):
```csharp
// 修改前
if (Widgets.ButtonText(btnRect, ">"))
// 修改后 (需要静态化或复制 DrawCustomButton 方法)
DrawCustomButton(btnRect, ">", isEnabled: true);
```
---
## 问题 3: 样式统一 (WulaLinkStyles.cs)
需要调整以下颜色以匹配大 UI 的"军团"风格:
```csharp
// Header: 深红色,与大 UI 标题栏一致
public static readonly Color HeaderColor = new Color(0.5f, 0.15f, 0.15f, 1f);
// 背景: 半透明暗红
public static readonly Color BackgroundColor = new Color(0.2f, 0.05f, 0.05f, 0.85f);
// AI 气泡: 深灰带红色边框
public static readonly Color StudentBubbleColor = new Color(0.15f, 0.12f, 0.12f, 1f);
public static readonly Color StudentStrokeColor = new Color(0.6f, 0.2f, 0.2f, 1f);
// 玩家气泡: 暗红色
public static readonly Color SenseiBubbleColor = new Color(0.4f, 0.15f, 0.15f, 1f);
```
---
## 验证清单
- [ ] 大 UI 显示正确的立绘、标题、描述和按钮布局
- [ ] 小悬浮框背景为半透明暗红色
- [ ] 消息之间无多余空白
- [ ] 按钮使用暗红色自定义样式
- [ ] (可选) 气泡有圆角
- [ ] (可选) 头像为圆形
## 编译命令
```powershell
dotnet build C:\Steam\steamapps\common\RimWorld\Mods\3516260226\Source\WulaFallenEmpire\WulaFallenEmpire.csproj
```
## 测试入口
1. 启动 RimWorld加载存档
2. 打开 Debug Actions Menu
3. 搜索 "WulaLink" 并点击 "Open WulaLink UI"

View File

@@ -1,140 +0,0 @@
# WulaLink 任务交接文档
## 当前状态:需要创建 AIIntelligenceCore.cs
### 背景
WulaLink 是一个 RimWorld Mod 中的 AI 对话系统,包含两个 UI
1. **大 UI** (`Dialog_AIConversation`) - 全屏对话窗口
2. **小 UI** (`Overlay_WulaLink`) - 悬浮对话窗口
### 已完成的操作
1. ✅ 恢复了 `Dialog_AIConversation.cs` 为旧版自包含版本(从备份文件 `Tools/using System;.cs` 复制)
2. ✅ 删除了损坏的 `AIIntelligenceCore.cs`
3. ✅ 重写了 `WulaLinkStyles.cs`(颜色主题配置)
### 当前编译错误
```
error CS0246: 未能找到类型或命名空间名"AIIntelligenceCore"
```
以下文件引用了 `AIIntelligenceCore`
- `Overlay_WulaLink.cs` (第13行, 第94行)
- `Overlay_WulaLink_Notification.cs` (第89行)
- `Tool_ChangeExpression.cs` (第24行)
- `Tool_GetRecentNotifications.cs` (第113行)
---
## 需要完成的任务
### 任务:创建 AIIntelligenceCore.cs
**路径**: `Source/WulaFallenEmpire/EventSystem/AI/AIIntelligenceCore.cs`
**要求**
1. 必须是 `WorldComponent`,类名 `AIIntelligenceCore`
2. 提供 `static Instance` 属性供外部访问
3.`Dialog_AIConversation`(备份文件 `Tools/using System;.cs`)提取 AI 核心逻辑
4. 暴露事件/回调供 UI 使用
**必须包含的公共接口**(根据现有代码引用):
```csharp
public class AIIntelligenceCore : WorldComponent
{
// 静态实例
public static AIIntelligenceCore Instance { get; private set; }
// 事件回调
public event Action<string> OnMessageReceived;
public event Action<bool> OnThinkingStateChanged;
public event Action<int> OnExpressionChanged;
// 公共属性
public int ExpressionId { get; }
public bool IsThinking { get; }
// 公共方法
public void InitializeConversation(string eventDefName);
public List<(string role, string message)> GetHistorySnapshot();
public void SetExpression(int id); // 供 Tool_ChangeExpression 调用
public void SendMessage(string text); // 供小 UI 调用
}
```
**参考代码**
- 备份文件 `Tools/using System;.cs` 包含完整的 AI 逻辑1549行
- 核心方法包括:
- `RunPhasedRequestAsync()` - 3阶段请求处理
- `ExecuteXmlToolsForPhase()` - 工具执行
- `BuildToolContext()` / `BuildReplyHistory()` - 上下文构建
- `ParseResponse()` - 响应解析
- `GetSystemInstruction()` / `GetToolSystemInstruction()` - 提示词生成
---
## 关键文件路径
```
C:\Steam\steamapps\common\RimWorld\Mods\3516260226\
├── Tools\
│ └── using System;.cs # 旧版 Dialog_AIConversation 备份(包含完整 AI 逻辑)
└── Source\WulaFallenEmpire\EventSystem\AI\
├── AIIntelligenceCore.cs # 【需要创建】
├── AIHistoryManager.cs # 历史记录管理
├── AIMemoryManager.cs # 记忆管理
├── SimpleAIClient.cs # API 客户端
├── Tools\ # AI 工具目录
│ ├── Tool_SpawnResources.cs
│ ├── Tool_SendReinforcement.cs
│ └── ... (其他工具)
└── UI\
├── Dialog_AIConversation.cs # 大 UI已恢复
├── Overlay_WulaLink.cs # 小 UI需要修复引用
├── Overlay_WulaLink_Notification.cs
└── WulaLinkStyles.cs # 样式配置(已重写)
```
---
## 编译命令
```powershell
dotnet build C:\Steam\steamapps\common\RimWorld\Mods\3516260226\Source\WulaFallenEmpire\WulaFallenEmpire.csproj
```
---
## 架构说明
### 目标架构
```
┌─────────────────────────────────────┐
│ AIIntelligenceCore │ ← WorldComponent (核心逻辑)
│ - 历史记录管理 │
│ - AI 请求处理 (3阶段) │
│ - 工具执行 │
│ - 表情/状态管理 │
└──────────────┬──────────────────────┘
│ 事件回调
┌──────────┴──────────┐
▼ ▼
┌─────────────┐ ┌──────────────┐
│ Dialog_AI │ │ Overlay_ │
│ Conversation│ │ WulaLink │
│ (大 UI) │ │ (小 UI) │
└─────────────┘ └──────────────┘
```
### 关键点
1. `Dialog_AIConversation` 目前是**自包含**的(既有 UI 也有 AI 逻辑)
2. `Overlay_WulaLink` 需要通过 `AIIntelligenceCore` 获取数据
3. 两个 UI 可以共享同一个 `AIIntelligenceCore` 实例
---
## 注意事项
1. **不要使用 PowerShell Get-Content 读取文件** - 会显示乱码,请使用 `view_file` 工具
2. **备份文件编码正常** - `Tools/using System;.cs` 可以正常读取
3. **命名空间**`WulaFallenEmpire.EventSystem.AI`
4. **依赖项**:需要引用 `SimpleAIClient``AIHistoryManager``AITool` 等现有类

File diff suppressed because it is too large Load Diff