Skip to content

Commit d93c6fd

Browse files
committed
上传两篇skills
1 parent fd13588 commit d93c6fd

2 files changed

Lines changed: 537 additions & 0 deletions

File tree

Lines changed: 324 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,324 @@
1+
---
2+
name: "openra-copilot-api-command"
3+
description: "Guides adding new OpenRA Copilot API commands. Invoke when implementing, registering, validating, or debugging Socket-based Copilot commands and related Traits."
4+
---
5+
6+
# OpenRA Copilot API Command
7+
8+
在这个工作区中,当任务涉及为 OpenRA Copilot Mod 新增、修改、排查 API 指令时,使用这个技能。
9+
10+
## 何时使用
11+
12+
在以下场景调用这个技能:
13+
14+
- 用户要求新增一个 OpenRA Copilot API 指令
15+
- 需要修改已有 Copilot 指令的参数验证、注册或执行逻辑
16+
- 需要排查 Socket API 请求能到达服务端,但命令执行失败的问题
17+
- 任务涉及 `CopilotCommandServer.cs``CopilotModels.cs``ServerCommands.cs``Traits/Copilot/`
18+
- 某个复杂命令需要拆成跨多个 Tick 执行的 Trait 状态机
19+
20+
不要在纯地图编辑、纯 YAML 地图资源修改、或与 Copilot API 无关的通用游戏逻辑任务中调用这个技能。
21+
22+
## 核心架构
23+
24+
OpenRA Copilot 的 API 系统基于 Socket 通信,核心职责通常分布在以下文件:
25+
26+
- `OpenRA.Game/CopilotCommandServer.cs`
27+
- 服务端入口
28+
- 接收 Socket 请求
29+
- 解析 JSON
30+
- 验证基础格式
31+
- 将命令路由到对应处理函数
32+
33+
- `OpenRA.Game/CopilotModels.cs`
34+
- 定义请求与响应模型
35+
- 负责命令参数验证
36+
37+
- `OpenRA.Mods.Common/ServerCommands.cs`
38+
- 放置具体指令处理逻辑
39+
- 通常负责解析参数、解析玩家、调用游戏逻辑或 Trait
40+
41+
- `OpenRA.Mods.Common/Traits/Copilot/`
42+
- 存放复杂命令对应的 Trait
43+
- 适合封装跨多个 Tick 的长流程逻辑
44+
- 常见挂载位置是 `Player``World`
45+
46+
## 标准新增流程
47+
48+
假设要新增一个名为 `my_command` 的新指令,优先按以下顺序实现。
49+
50+
### 第 1 步:在 `CopilotModels.cs` 中补齐参数验证
51+
52+
`ValidateCommandParams` 中新增分支,并为命令编写专用校验函数。
53+
54+
```csharp
55+
public static (bool isValid, MCPError error) ValidateCommandParams(string command, JObject parameters)
56+
{
57+
switch (command)
58+
{
59+
case "my_command":
60+
return ValidateMyCommandParams(parameters);
61+
}
62+
}
63+
64+
private static (bool isValid, MCPError error) ValidateMyCommandParams(JObject parameters)
65+
{
66+
if (parameters == null || !parameters.ContainsKey("targetId"))
67+
{
68+
return (false, new MCPError
69+
{
70+
Code = "MISSING_PARAM",
71+
Message = "Missing parameter: targetId"
72+
});
73+
}
74+
75+
return (true, null);
76+
}
77+
```
78+
79+
实现要点:
80+
81+
- 不要把参数校验延后到真正执行逻辑时才做
82+
- 错误信息要明确指出缺失字段或格式问题
83+
- 如果已有类似命令,优先复用现有校验风格
84+
85+
### 第 2 步:在 `ServerCommands.cs` 中实现命令逻辑
86+
87+
为新命令添加静态处理方法。
88+
89+
```csharp
90+
public static string MyCommand(JObject json, World world)
91+
{
92+
var player = ResolvePlayer(json, world);
93+
var targetId = json["targetId"]?.ToObject<int>();
94+
95+
// 执行游戏逻辑
96+
97+
return "Command executed successfully";
98+
}
99+
```
100+
101+
实现要点:
102+
103+
- 先解析玩家,再解析命令参数
104+
- 尽量沿用已有的 `ResolvePlayer`、实体解析、命名风格和错误返回模式
105+
- 简单命令直接在这里完成
106+
- 复杂命令只在这里做参数入口与调度,把流程下沉到 Trait
107+
108+
### 第 3 步:在 `CopilotCommandServer.cs` 中注册命令
109+
110+
`WorldLoaded` 中把字符串命令名映射到处理函数。
111+
112+
```csharp
113+
public void WorldLoaded(World w, WorldRenderer wr)
114+
{
115+
if (w.Type == WorldType.Regular && w.CopilotServer != null)
116+
{
117+
w.CopilotServer.CommandHandlers["my_command"] = ServerCommands.MyCommand;
118+
}
119+
}
120+
```
121+
122+
实现要点:
123+
124+
- 注册名必须和请求里的命令名完全一致
125+
- 如果命令逻辑已实现但没有注册,外部调用仍然会失败
126+
- 修改后要检查是否只在正确的世界类型下注册
127+
128+
### 第 4 步:复杂逻辑改用 Trait
129+
130+
如果命令涉及跨多个 Tick 的操作,优先创建独立 Trait,而不是把所有逻辑塞进一个方法。
131+
132+
典型场景:
133+
134+
- 造单位
135+
- 等待生产完成
136+
- 控制移动
137+
- 展开或部署
138+
- 放置建筑
139+
- 串联多个前置检查与状态切换
140+
141+
推荐做法:
142+
143+
1.`OpenRA.Mods.Common/Traits/Copilot/` 下创建新的 Trait 文件
144+
2. 实现 `ITick` 处理逐帧推进
145+
3.`ServerCommands.cs` 获取对应 Trait 并调用入口方法
146+
147+
## 长流程命令的设计原则
148+
149+
### 使用状态机管理流程
150+
151+
对于类似 `expand_base` 这样的长流程,使用状态机而不是单函数串行逻辑。
152+
153+
推荐模式:
154+
155+
- 使用 `enum` 表达流程状态
156+
-`ITick.Tick` 中根据状态推进一步
157+
- 每次只做一个小动作
158+
- 动作发出后切换到对应 Waiting 状态
159+
160+
示例状态:
161+
162+
- `WaitingForMCV`
163+
- `MovingMCV`
164+
- `WaitingForDeploy`
165+
- `WaitingForPowerPlant`
166+
167+
### 使用等待与重试节流
168+
169+
不要每个 Tick 都高频重复发命令或高频检查完整条件。
170+
171+
推荐模式:
172+
173+
- 使用 `waitTicks` 做简单节流
174+
- 把它既当作轮询间隔,也当作基础超时重试机制
175+
- 对生产、移动、部署这类动作都设置明确等待窗口
176+
177+
## 经验总结与避坑指南
178+
179+
### 1. Trait 必须在 YAML 中注册
180+
181+
常见现象:
182+
183+
- 代码已经写好
184+
- 调用命令时报错 `Player does not have X trait`
185+
186+
根本原因:
187+
188+
- 仅在 C# 中定义 Trait 还不够
189+
- 必须在规则文件中显式挂载,否则 Actor 不会拥有它
190+
191+
检查位置:
192+
193+
- `mods/ra/rules/player.yaml`
194+
- `mods/cnc/rules/player.yaml`
195+
- 必要时检查 `rules/world.yaml`
196+
197+
检查重点:
198+
199+
- 确认 Trait 名称出现在正确的 Actor 定义下
200+
- 例如 `CopilotExpansionManager` 是否真实挂在 `Player``World`
201+
202+
### 2. 生产队列优先使用批量补齐,而不是单次反复发单
203+
204+
常见现象:
205+
206+
- 目标是建造多个建筑
207+
- 实际只造了一个
208+
- 或者逻辑在 Tick 循环里不断重复下单
209+
210+
更可靠的模式是 `EnsureProduction(type, quantity)`
211+
212+
- 计算目标总数
213+
- 扣除队列中已有数量
214+
- 扣除已完成但尚未放置的数量
215+
- 一次性把剩余数量交给引擎队列系统处理
216+
217+
推荐思路:
218+
219+
- 使用 `需建造总数 - (当前队列数量 + 已完成未放置数量)`
220+
- 调用 `Order.StartProduction(actor, item, count)` 一次下发剩余数
221+
222+
这样可以避免:
223+
224+
- 每 Tick 重复发单
225+
- 造完第一个后无法自然衔接第二个
226+
- 人工维护队列状态过于复杂
227+
228+
### 3. 正确构造 Order 与 Target
229+
230+
常见现象:
231+
232+
- 发送了 `Move``Deploy`
233+
- 单位没有反应
234+
235+
优先检查以下几点:
236+
237+
1. `Target` 是否正确构造
238+
- `Target.FromCell`
239+
- `Target.FromActor`
240+
- 二者不能混用
241+
242+
2. `Order` 构造函数是否匹配具体命令
243+
- 某些命令如 `DeployTransform` 需要特殊参数
244+
- 例如视觉反馈参数或是否排队参数
245+
246+
3. 是否错误地把命令加入已有队列末尾
247+
- 紧急命令通常应设置为立即执行
248+
- 如果不覆盖当前队列,单位可能永远先执行旧命令
249+
250+
处理原则:
251+
252+
- 对移动、展开、脱离卡死状态这类强控制命令,优先考虑非排队执行
253+
254+
### 4. 错误信息必须具体
255+
256+
不要只返回:
257+
258+
- `Failed`
259+
- `Command failed`
260+
261+
推荐返回:
262+
263+
- 缺少哪个参数
264+
- 缺少哪个前置建筑或科技
265+
- 当前流程正在执行什么
266+
- 是否已有同类任务在进行中
267+
268+
优先模式:
269+
270+
- 如果缺前置,调用类似 `DescribeMissingPrerequisites`
271+
- 如果流程已在运行,返回如 `Base expansion already in progress`
272+
273+
### 5. 做好多 Mod 兼容
274+
275+
常见现象:
276+
277+
- 在 RA 下正常
278+
- 在 CNC 下报错或无反应
279+
280+
根本原因:
281+
282+
- 不同 Mod 的 Actor 名称不同
283+
284+
例如同类建筑可能存在多种名字:
285+
286+
```csharp
287+
string[] powerNames = { "POWR", "APWR", "PWR", "NUKR" };
288+
```
289+
290+
推荐做法:
291+
292+
- 对关键单位和建筑定义别名数组
293+
- 解析时按别名依次尝试
294+
- 不要把 RA 的命名硬编码成唯一来源
295+
296+
## 实施检查清单
297+
298+
完成新增命令后,至少检查以下几点:
299+
300+
- 参数验证已接入 `ValidateCommandParams`
301+
- 命令处理函数已写入 `ServerCommands.cs`
302+
- 命令已在 `CopilotCommandServer.cs` 注册
303+
- 如果使用 Trait,已在对应 YAML 中挂载
304+
- 错误返回信息足够明确
305+
- 长流程逻辑已拆成状态机,而不是单函数硬写
306+
- 对 RA 和 CNC 的命名差异做了兼容处理
307+
308+
## 回答此类任务时的建议
309+
310+
当你处理这类需求时,优先按下面的顺序工作:
311+
312+
1. 先定位命令入口、参数校验、注册表和实际处理逻辑
313+
2. 判断这是简单即时命令还是复杂长流程命令
314+
3. 简单命令直接在 `ServerCommands.cs` 实现
315+
4. 长流程命令下沉到 Trait,并配套状态机
316+
5. 最后检查 YAML 注册与跨 Mod 命名兼容
317+
318+
如果用户是在排查已有命令失败,优先检查:
319+
320+
1. 命令是否注册
321+
2. 参数是否通过校验
322+
3. Trait 是否实际挂载
323+
4. Order 与 Target 是否构造正确
324+
5. 是否被旧命令队列阻塞

0 commit comments

Comments
 (0)