Skip to content

Commit 76e5abd

Browse files
authored
add readme (#3)
1 parent 59070f8 commit 76e5abd

3 files changed

Lines changed: 310 additions & 48 deletions

File tree

‎AGENTS.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,7 @@ Harmony → yancy.rimchat → RimMind-Core → RimMind 子模组 → RimMind-Bri
259259

260260
所有 UI 文本通过 `Languages/ChineseSimplified/Keyed/RimMind_BridgeRimChat.xml` 和 `Languages/English/Keyed/RimMind_BridgeRimChat.xml` 的 Keyed 翻译,禁止硬编码中文。
261261

262-
翻译键共 22 个,覆盖 3 个设置分区(DialogueGate / ActionGate / ContextPull)+ Mod 入口。
262+
翻译键共 31 个,覆盖 3 个设置分区(DialogueGate / ActionGate / ContextPull)+ Mod 入口。
263263

264264
### 设置 UI
265265

‎CLAUDE.md‎

Lines changed: 309 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,309 @@
1+
# AGENTS.md — RimMind-Bridge-RimChat
2+
3+
本文件供 AI 编码助手阅读,描述 RimMind-Bridge-RimChat 的架构、代码约定和扩展模式。
4+
5+
## 项目定位
6+
7+
RimMind-Bridge-RimChat 是 RimMind 套件与 RimChat 模组之间的协调层。当两个模组同时激活时,本模组负责:
8+
9+
1. **对话门控**:避免 RimMind-Dialogue 和 RimChat 重复触发玩家对话
10+
2. **动作门控**:避免 RimMind-Actions 和 RimChat 重复执行外交、社交、招募等动作;避免 RimMind-Storyteller 和 RimChat 重复触发事件
11+
3. **上下文拉取**:从 RimChat 拉取外交/RPG对话历史,注册为 RimMind Provider,使 RimMind 能感知 RimChat 的对话内容
12+
13+
本模组通过 `RimMindAPI` 注册 SkipCheck 和 Provider,不依赖 RimChat 的编译期引用,因此 RimChat 未安装时不会报错。
14+
15+
## 源码结构
16+
17+
```
18+
Source/
19+
├── RimMindBridgeRimChatMod.cs Mod 入口,注册 Harmony、Settings Tab,按条件注册桥接模块
20+
├── Bridge/
21+
│ ├── DialogueGate.cs 对话门控,注册 SkipCheck 防止重复触发
22+
│ ├── ActionGate.cs 动作门控,注册 ActionSkipCheck + IncidentSkipCheck + IncidentCallback
23+
│ └── ContextPullBridge.cs 上下文拉取,从 RimChat 读取对话历史注册为 RimMind Provider
24+
├── Cooldown/
25+
│ └── SharedIncidentCooldown.cs 事件触发共享冷却,防止 RimMind-Storyteller 与 RimChat 短时间内重复触发事件
26+
├── Detection/
27+
│ └── RimChatDetector.cs 检测 RimChat 是否激活(带缓存)
28+
└── Settings/
29+
└── BridgeRimChatSettings.cs 模组设置(对话门控 + 动作门控 + 上下文拉取)
30+
```
31+
32+
## 关键类与 API
33+
34+
### RimChatDetector
35+
36+
检测 RimChat 模组状态,带缓存:
37+
38+
```csharp
39+
static class RimChatDetector {
40+
const string RimChatPackageId = "yancy.rimchat";
41+
42+
bool IsRimChatActive // RimChat 模组是否激活(6000 tick 缓存)
43+
void InvalidateCache() // 手动刷新缓存
44+
}
45+
```
46+
47+
### DialogueGate
48+
49+
对话门控,防止 RimMind-Dialogue 和 RimChat 同时触发玩家对话:
50+
51+
```csharp
52+
static class DialogueGate {
53+
bool ShouldSkipDialogue(Pawn pawn, string triggerType)
54+
// triggerType: "PlayerInput" 时检查 skipPlayerDialogue
55+
56+
bool ShouldSkipFloatMenuOption()
57+
// 判断是否跳过 RimMind 的"与X对话"浮动菜单
58+
59+
void RegisterSkipChecks()
60+
// 注册到 RimMindAPI.RegisterDialogueSkipCheck / RegisterFloatMenuSkipCheck
61+
62+
void UnregisterSkipChecks()
63+
// 清理注册
64+
}
65+
```
66+
67+
门控逻辑:
68+
69+
| 条件 | 跳过条件 |
70+
|------|---------|
71+
| `"PlayerInput"` 对话 | `enableDialogueGate && skipPlayerDialogue && !forceRimMindPlayerDialogue` |
72+
| 浮动菜单 | `enableDialogueGate && skipPlayerDialogue && !forceRimMindPlayerDialogue` |
73+
74+
### ActionGate
75+
76+
动作门控,防止 RimMind-Actions/Storyteller 和 RimChat 重复执行动作:
77+
78+
```csharp
79+
static class ActionGate {
80+
bool ShouldSkipAction(string intentId)
81+
// 检查动作是否应被跳过
82+
83+
bool ShouldSkipStorytellerIncident()
84+
// 检查 Storyteller 事件是否应被跳过(含冷却检查)
85+
86+
void Register()
87+
// 注册到 RimMindAPI.RegisterActionSkipCheck / RegisterIncidentExecutedCallback / RegisterStorytellerIncidentSkipCheck
88+
89+
void Unregister()
90+
// 清理注册
91+
}
92+
```
93+
94+
动作分类:
95+
96+
| 分类 | 动作 ID | 设置开关 |
97+
|------|---------|---------|
98+
| 外交 | `adjust_faction`, `trigger_incident` | skipDiplomacyActions |
99+
| 社交 | `romance_accept`, `romance_breakup` | skipSocialActions |
100+
| 招募 | `recruit_agree` | skipRecruitAgree |
101+
| 叙事者事件 | Storyteller incident | skipTriggerIncident + SharedIncidentCooldown |
102+
103+
> **注意**:`trigger_incident` 同时出现在 DiplomacyActions(RimMind-Actions 的动作ID)和 Storyteller 事件跳过(skipTriggerIncident)中。前者由 `skipDiplomacyActions` 控制,后者由 `skipTriggerIncident` 控制,两者互不干扰。
104+
105+
门控逻辑:
106+
107+
```
108+
ShouldSkipAction:
109+
RimChat 未激活 → false
110+
enableActionGate 关闭 → false
111+
forceRimMindActions 开启 → false(强制 RimMind-Actions 执行所有动作,不影响 Storyteller)
112+
skipDiplomacyActions && intentId ∈ DiplomacyActions → true
113+
skipSocialActions && intentId ∈ SocialActions → true
114+
skipRecruitAgree && intentId == "recruit_agree" → true
115+
否则 → false
116+
117+
ShouldSkipStorytellerIncident:
118+
RimChat 未激活 → false
119+
enableActionGate 关闭 → false
120+
skipTriggerIncident 关闭 → false
121+
SharedIncidentCooldown.IsOnCooldown(incidentCooldownTicks) → true/false
122+
```
123+
124+
### SharedIncidentCooldown
125+
126+
事件触发共享冷却,防止 RimMind-Storyteller 和 RimChat 短时间内重复触发事件:
127+
128+
```csharp
129+
static class SharedIncidentCooldown {
130+
void RecordIncident() // 记录事件触发时间
131+
bool IsOnCooldown(int cooldownTicks) // 检查是否在冷却中
132+
int LastIncidentTick { get; } // 上次事件触发 tick
133+
void Reset() // 重置冷却
134+
}
135+
```
136+
137+
### ContextPullBridge
138+
139+
从 RimChat 拉取对话历史,注册为 RimMind Provider:
140+
141+
```csharp
142+
static class ContextPullBridge {
143+
void Register() // 根据设置注册各 Provider
144+
void Unregister() // 清理所有注册(RimMindAPI.UnregisterModProviders)
145+
}
146+
```
147+
148+
注册的 Provider:
149+
150+
| Category | 数据来源 | 类型 | 优先级 | 设置开关 |
151+
|----------|---------|------|--------|---------|
152+
| `rimchat_diplomacy` | GameComponent_DiplomacyManager.dialogueSessions(反射) | StaticProvider | PriorityAuxiliary | pullDiplomacyHistory |
153+
| `rimchat_rpg_history` | RpgNpcDialogueArchiveManager._archiveCache(反射) | PawnContextProvider | PriorityMemory | pullRpgHistory |
154+
155+
所有 Provider 注册时使用 ModId `"RimMind.BridgeRimChat"`,卸载时通过 `UnregisterModProviders` 一次性清理。
156+
157+
### BridgeRimChatSettings
158+
159+
```csharp
160+
class BridgeRimChatSettings : ModSettings {
161+
// 对话门控
162+
bool enableDialogueGate; // 默认 true
163+
bool skipPlayerDialogue; // 默认 true
164+
bool forceRimMindPlayerDialogue; // 默认 false
165+
166+
// 动作门控
167+
bool enableActionGate; // 默认 true
168+
bool skipDiplomacyActions; // 默认 true(跳过 adjust_faction, trigger_incident)
169+
bool skipTriggerIncident; // 默认 true(跳过 Storyteller 事件触发)
170+
bool skipSocialActions; // 默认 false(跳过 romance_accept, romance_breakup)
171+
bool skipRecruitAgree; // 默认 false(跳过 recruit_agree)
172+
int incidentCooldownTicks; // 默认 60000(1 游戏天),Slider 6000~180000,步进 1500
173+
bool forceRimMindActions; // 默认 false(仅影响 RimMind-Actions,不影响 Storyteller)
174+
175+
// 上下文拉取
176+
bool enableContextPull; // 默认 true
177+
bool pullDiplomacyHistory; // 默认 true
178+
bool pullRpgHistory; // 默认 false
179+
180+
static BridgeRimChatSettings Get();
181+
static void DrawSettingsContent(Rect inRect);
182+
}
183+
```
184+
185+
## 数据流
186+
187+
```
188+
RimChat 对话数据 RimMind 上下文系统
189+
┌──────────────────┐ ┌──────────────────┐
190+
│ 外交对话历史 │──反射读取──→ │ rimchat_diplomacy (Static)
191+
│ RPG对话历史 │──反射读取──→ │ rimchat_rpg_history (Pawn)
192+
└──────────────────┘ └──────────────────┘
193+
194+
RimMind-Dialogue 触发 ──DialogueGate──→ 跳过/放行
195+
RimMind-Actions 执行 ──ActionGate────→ 跳过/放行
196+
RimMind-Storyteller ──ActionGate────→ 跳过/放行(含冷却)
197+
```
198+
199+
## 初始化流程
200+
201+
```
202+
RimMindBridgeRimChatMod 构造函数
203+
│
204+
├── GetSettings<BridgeRimChatSettings>()
205+
├── Harmony("mcocdaa.RimMindBridgeRimChat").PatchAll()
206+
├── RimMindAPI.RegisterSettingsTab("bridge_rimchat", ...)
207+
│
208+
├── RimChatDetector.IsRimChatActive?
209+
│ │
210+
│ ├── No → Log + 跳过所有桥接模块
211+
│ │
212+
│ └── Yes → DialogueGate.RegisterSkipChecks()
213+
│ ActionGate.Register()
214+
│ ContextPullBridge.Register()
215+
```
216+
217+
## 代码约定
218+
219+
### 命名空间
220+
221+
| 命名空间 | 目录 | 职责 |
222+
|---------|------|------|
223+
| `RimMind.Bridge.RimChat` | Source/ 根目录 | Mod 入口 |
224+
| `RimMind.Bridge.RimChat.Bridge` | Bridge/ | 桥接模块 |
225+
| `RimMind.Bridge.RimChat.Cooldown` | Cooldown/ | 冷却管理 |
226+
| `RimMind.Bridge.RimChat.Detection` | Detection/ | RimChat 检测 |
227+
| `RimMind.Bridge.RimChat.Settings` | Settings/ | 设置 |
228+
229+
### ModId
230+
231+
所有 RimMindAPI 注册使用统一 ModId:`"RimMind.BridgeRimChat"`
232+
233+
### Harmony
234+
235+
- Harmony ID:`mcocdaa.RimMindBridgeRimChat`
236+
- 当前无 Harmony Patch(预留)
237+
238+
### 构建
239+
240+
| 配置项 | 值 |
241+
|--------|-----|
242+
| 目标框架 | `net48` |
243+
| C# 语言版本 | 9.0 |
244+
| Nullable | enable |
245+
| RimWorld 版本 | 1.6 |
246+
| 输出路径 | `../1.6/Assemblies/` |
247+
| 部署 | 设置 `RIMWORLD_DIR` 环境变量后自动部署 |
248+
| NuGet 依赖 | `Krafs.Rimworld.Ref 1.6.*-*`, `Lib.Harmony.Ref 2.*`, `Newtonsoft.Json 13.0.*` |
249+
| 编译期引用 | RimMindCore, RimMindDialogue, RimMindPersonality, RimMindMemory, RimMindStoryteller, RimMindAdvisor, RimMindActions(均为 Private=false) |
250+
| 无编译期引用 | RimChat(纯反射读取,不调用 RimChat API) |
251+
252+
### 加载顺序
253+
254+
```
255+
Harmony → yancy.rimchat → RimMind-Core → RimMind 子模组 → RimMind-Bridge-RimChat
256+
```
257+
258+
### UI 本地化
259+
260+
所有 UI 文本通过 `Languages/ChineseSimplified/Keyed/RimMind_BridgeRimChat.xml` 和 `Languages/English/Keyed/RimMind_BridgeRimChat.xml` 的 Keyed 翻译,禁止硬编码中文。
261+
262+
翻译键共 22 个,覆盖 3 个设置分区(DialogueGate / ActionGate / ContextPull)+ Mod 入口。
263+
264+
### 设置 UI
265+
266+
通过 `RimMindAPI.RegisterSettingsTab` 注册到 Core 的多分页设置界面,Tab 标签为 "Bridge (RimChat)"。使用 `SettingsUIHelper` 辅助工具类绘制。
267+
268+
设置项条件嵌套:
269+
- `skipPlayerDialogue` 仅在 `enableDialogueGate` 为 true 时显示
270+
- `forceRimMindPlayerDialogue` 仅在 `enableDialogueGate && skipPlayerDialogue` 为 true 时显示
271+
- 4 个 skip 选项 + `forceRimMindActions` 仅在 `enableActionGate` 为 true 时显示
272+
- `incidentCooldownTicks` 滑块仅在 `enableActionGate && skipTriggerIncident` 为 true 时显示
273+
- `pullDiplomacyHistory` / `pullRpgHistory` 仅在 `enableContextPull` 为 true 时显示
274+
275+
## 与 RimTalk Bridge 的区别
276+
277+
| 特性 | RimChat Bridge | RimTalk Bridge |
278+
|------|---------------|----------------|
279+
| 目标模组 | RimChat (`yancy.rimchat`) | RimTalk (`cj.rimtalk`) |
280+
| 对话门控 | 仅 PlayerInput | Chitchat + Auto + PlayerInput |
281+
| 动作门控 | 有(外交/社交/招募/叙事者事件) | 无 |
282+
| 事件冷却 | 有(SharedIncidentCooldown) | 无 |
283+
| 上下文推送 | 无(RimChat 无公开API) | 有(变量/PromptEntry/Hook) |
284+
| 上下文拉取 | 有(反射读取外交/RPG对话历史) | 有(反射读取对话历史) |
285+
| RimChat API 调用 | 无(仅检测激活状态+反射读取数据) | 有(反射调用 RimTalkPromptAPI) |
286+
| 人格推送 | 无 | 有(PersonaPushBridge + Hook) |
287+
288+
## 扩展指南
289+
290+
### 新增动作门控
291+
292+
1. 在 `ActionGate` 中添加动作 ID 到对应 HashSet,或新增 HashSet
293+
2. 在 `BridgeRimChatSettings` 中添加对应开关
294+
3. 在语言文件中添加翻译键
295+
4. 更新 `EstimateHeight` 中的高度计算
296+
297+
### 新增上下文拉取
298+
299+
1. 在 `ContextPullBridge` 中添加反射读取方法
300+
2. 使用 `RimMindAPI.RegisterPawnContextProvider` 或 `RegisterStaticProvider` 注册
301+
3. 在 `BridgeRimChatSettings` 中添加对应开关
302+
4. 在语言文件中添加翻译键
303+
304+
### 新增对话门控类型
305+
306+
1. 在 `DialogueGate.ShouldSkipDialogue` 中添加 triggerType 分支
307+
2. 在 `BridgeRimChatSettings` 中添加对应开关
308+
3. 在语言文件中添加翻译键
309+
4. 更新 `EstimateHeight` 中的高度计算

‎INTRODUCTION.md‎

Lines changed: 0 additions & 47 deletions
This file was deleted.

0 commit comments

Comments
 (0)