Skip to content

Commit 8ab323a

Browse files
authored
Merge branch 'master' into feature/placeholders
2 parents 00898b7 + f44909e commit 8ab323a

40 files changed

Lines changed: 2008 additions & 0 deletions

‎.opencode/plugin/amxb-skills.js‎

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// Bridge: exposes amxb (amxx-builder) skills to opencode from three sources:
2+
// 1. builder-bundled skills, via "amxb skills-dir"
3+
// 2. the current project's own "skills:" from amxbuild.yml
4+
// 3. deps/repos skills read from their manifests; missing ones are fetched
5+
// from the network on demand ("amxb opencode-skills")
6+
// No machine-specific paths are stored in opencode.json: amxb resolves its own
7+
// install and cache directories at every opencode start, like the MCP entry does.
8+
import { execSync } from "node:child_process";
9+
10+
export default async function amxbSkills() {
11+
return {
12+
config(cfg) {
13+
cfg.skills = cfg.skills || {};
14+
cfg.skills.paths = cfg.skills.paths || [];
15+
const exe = process.platform === "win32" ? "amxb.cmd" : "amxb";
16+
const add = (p) => {
17+
if (p && !cfg.skills.paths.includes(p)) cfg.skills.paths.push(p);
18+
};
19+
try {
20+
add(execSync(exe + " skills-dir", { encoding: "utf8" }).trim());
21+
} catch {}
22+
try {
23+
const out = execSync(exe + " opencode-skills", { encoding: "utf8", timeout: 180000 });
24+
for (const line of out.split("\n")) add(line.trim());
25+
} catch {}
26+
},
27+
};
28+
}

‎amxbuild.yml‎

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,44 @@ name: ParamsController
44

55
amxmodx:
66
version: "1.10.5428"
7+
8+
skills:
9+
- dir: skills/param-types
10+
name: ParamsController param types
11+
description: >-
12+
Встроенные типы параметров ParamsController: допустимые JSON-значения,
13+
что попадает в Trie, теги и геттер чтения для каждого типа. Только
14+
специфика типов; общие механизмы контроллера здесь не описаны. Покрывает
15+
Boolean, Integer, Float, ShortString, String, LongString, RGB, Model,
16+
PlayerModel, Sound, Resource, File, Dir, ChatMessage, Flags, Time,
17+
TimeInterval, WeekDay, Regexp.
18+
- dir: skills/param-types-authoring
19+
name: Plugin param types skill authoring
20+
description: >-
21+
Мета-скилл: как агенту описать скилл с типами параметров, которые плагин
22+
регистрирует сам через ParamsController (ParamsController_OnRegisterTypes,
23+
ParamsController_RegSimpleType, ParamsController_ParamType_Register).
24+
Процедура поиска регистраций и хелперов чтения (своих у плагина или
25+
стандартных PCGet_*/PCSingle_*), чтения колбеков, выписки контракта типа
26+
(JSON-форматы, результат в Trie, теги, условия ошибки, прекеш) и сборки
27+
составного скилла SKILL.md + references (включая групповые _<группа>.md)
28+
с записью в skills: манифеста. Только про типы.
29+
- dir: skills/param-type-registration
30+
name: Param type registration
31+
description: >-
32+
Как плагину зарегистрировать собственный тип параметра в ParamsController:
33+
ParamsController_OnRegisterTypes, ParamsController_RegSimpleType /
34+
ParamsController_ParamType_Register + SetReadCallback, контракт колбека
35+
чтения, запись значения в Trie, теги, условия ошибки, а также создание
36+
хелперов чтения PCSingle_*/PCGet_* для своего типа. Триггеры: register
37+
param type, custom param type, ParamsController_OnRegisterTypes,
38+
PCSingle, PCGet helper.
39+
- dir: skills/params-usage
40+
name: Params usage
41+
description: >-
42+
Как читать параметры ParamsController в коде плагина: PCSingle_* как обёртки
43+
над json_* для одиночных значений, регистрация параметров сущностей
44+
(Param_Construct + Param_ReadList + PCGet_*), приём наборов через нативы
45+
(ParamsController_Param_ListFromNativeParams, PCParam/PCParams). Триггеры:
46+
PCSingle, PCGet, ParamsController_Param_Construct, Param_ReadList,
47+
PCParam, consume params.

‎amxmodx/scripting/ParamsController/Objects/Param.inc‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,16 @@ Trie:Param_ReadList(
130130
continue;
131131
}
132132

133+
if (paramObject[Param_IsUnknownType]) {
134+
if (paramObject[Param_Required]) {
135+
iErrType = ParamsReadError_UnknownParamType;
136+
return p;
137+
}
138+
139+
PCJson_LogForFile(objectJson, "WARNING", "Param '%s' has unknown type '%s', skipping.", paramObject[Param_Key], paramObject[Param_Tag]);
140+
continue;
141+
}
142+
133143
if (!json_object_has_value(objectJson, paramObject[Param_Key])) {
134144
if (paramObject[Param_Required]) {
135145
errType = ParamsReadError_RequiredParamNotPresented;
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
---
2+
name: param-type-registration
3+
description: >-
4+
Как плагину зарегистрировать собственный тип параметра в ParamsController (AMXX):
5+
форвард ParamsController_OnRegisterTypes, ParamsController_RegSimpleType /
6+
ParamsController_ParamType_Register + ParamsController_ParamType_SetReadCallback,
7+
контракт колбека чтения bool:(const JSON, const Trie, const key[], const tag[]),
8+
запись значения (ParamsController_SetCell/SetString или Trie напрямую), теги,
9+
условия ошибки, а также создание хелперов чтения PCSingle_*/PCGet_* для своего
10+
типа. Использовать, когда плагин добавляет свой тип параметра.
11+
Триггеры: регистрация типа параметра, custom param type,
12+
ParamsController_OnRegisterTypes, ParamsController_RegSimpleType,
13+
ParamsController_ParamType_Register, PCSingle helper, PCGet helper,
14+
read callback, register parameter type.
15+
Use when a plugin adds its own ParamsController parameter type.
16+
---
17+
18+
# Регистрация своих типов параметров
19+
20+
Как плагину добавить **собственный тип** параметра в ParamsController: объявить
21+
имя типа, повесить на него функцию чтения и записывать результат в `Trie`.
22+
23+
Встроенные типы (`Boolean`, `Integer`, `Model`, …) уже зарегистрированы — их
24+
описывать не надо. Здесь — про свои.
25+
26+
## Когда применять
27+
28+
- плагину нужен нестандартный формат значения параметра;
29+
- нужно, чтобы конфиг плагина понимал свой тип.
30+
31+
Если нужен просто доступ к JSON без параметра — это другой скилл
32+
(`params-usage`, `PCSingle_*`), регистрировать тип не обязательно.
33+
34+
## Коротко
35+
36+
1. `ParamsController_Init()` в `plugin_init()` — инициализация контроллера.
37+
2. В `public ParamsController_OnRegisterTypes()` зарегистрировать тип:
38+
- `ParamsController_RegSimpleType("MyType", "@OnReadMyType")` — обычный путь;
39+
- либо `ParamsController_ParamType_Register("MyType")` +
40+
`ParamsController_ParamType_SetReadCallback(iType, "@OnReadMyType")`.
41+
3. Написать колбек `bool:@OnReadMyType(const JSON:jValue, const Trie:tParams,
42+
const sParamKey[], const sParamTag[])`, который разбирает `jValue`, пишет
43+
результат в `tParams` и возвращает `true`/`false`.
44+
45+
## Детали
46+
47+
- `references/registration.md` — способы регистрации, тайминг, ограничения.
48+
- `references/read-callback.md` — контракт колбека, запись значения, теги, ошибки.
49+
- `references/helpers.md` — как написать свои хелперы `PCSingle_*` / `PCGet_*`.
50+
- `references/examples.md` — полный пример плагина.
51+
52+
## Ключевые правила
53+
54+
- Регистрировать типы — строго в `ParamsController_OnRegisterTypes`.
55+
- Пока `ParamsController_Init()` не вызван, любой вызов API аварийно падает.
56+
- Колбек **обязан** записать значение в `Trie` — иначе контроллер сообщит об ошибке.
57+
- `return false` = «значение невалидно для этого типа».
58+
- Тег (`Тип:тег`) приходит в колбек четвёртым аргументом.
59+
- К типу по конвенции пишутся хелперы `PCSingle_*` / `PCGet_*` (см. `helpers.md`) —
60+
чтобы потребитель читал значение единообразно с встроенными типами.
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
# Пример: свои типы
2+
3+
Полный плагин с двумя типами: скаляр `Percent` и `Duration` с тегом `minutes`.
4+
5+
```pawn
6+
#include <amxmodx>
7+
#include <json>
8+
#include <ParamsController>
9+
10+
public plugin_init() {
11+
ParamsController_Init();
12+
}
13+
14+
public ParamsController_OnRegisterTypes() {
15+
ParamsController_RegSimpleType("Percent", "@OnReadPercent");
16+
ParamsController_RegSimpleType("Duration", "@OnReadDuration");
17+
}
18+
19+
// Число 0..100.
20+
bool:@OnReadPercent(const JSON:jValue, const Trie:tParams, const sParamKey[]) {
21+
if (!json_is_number(jValue)) {
22+
return false;
23+
}
24+
25+
new value = json_get_number(jValue);
26+
if (value < 0 || value > 100) {
27+
return false;
28+
}
29+
30+
return ParamsController_SetCell(value);
31+
}
32+
33+
// Число; тег "minutes" трактует его как минуты.
34+
bool:@OnReadDuration(const JSON:jValue, const Trie:tParams, const sParamKey[], const sParamTag[]) {
35+
if (!json_is_number(jValue)) {
36+
return false;
37+
}
38+
39+
new value = json_get_number(jValue);
40+
if (equali(sParamTag, "minutes")) {
41+
value *= 60;
42+
}
43+
44+
return ParamsController_SetCell(value);
45+
}
46+
```
47+
48+
Использование в параметрах:
49+
50+
```pawn
51+
ParamsController_Param_Construct("Chance", "Percent", true);
52+
ParamsController_Param_Construct("KickTime", "Duration:minutes", true);
53+
```
54+
55+
## Что тут важно
56+
57+
- оба типа зарегистрированы в `ParamsController_OnRegisterTypes`;
58+
- оба колбека записывают значение и возвращают `bool`;
59+
- `Percent` пишет ячейку, `Duration` учитывает тег;
60+
- `ParamsController_Init()` вызван до любого использования API.
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
# Хелперы для своего типа (`PCSingle_*` / `PCGet_*`)
2+
3+
Для работы типа контроллеру достаточно колбека чтения. Но по конвенции к типу
4+
пишут пару хелперов-обёрток, чтобы потребителю было удобно читать значение — как
5+
у встроенных типов:
6+
7+
- `PCSingle_*` — прочитать **одно** значение типа прямо из JSON, без параметра;
8+
- `PCGet_*` — прочитать готовое значение из **результата** (`Trie`).
9+
10+
## Процесс
11+
12+
1. **Определи вид значения.** Что колбек пишет в `Trie`: число/`cell` или строку.
13+
Для хендлеров (напр. `Regex`) — тоже `cell`, с приведением типа.
14+
2. **`PCSingle_*`** (сырое значение) — обёртка над `PCSingle_Cell` (число) или
15+
`PCSingle_Str` (строка).
16+
3. **`PCSingle_Obj*`** (из объекта по ключу) — обёртка над `PCSingle_ObjCell` /
17+
`PCSingle_ObjStr`; принимает `key`, `dotNot`, `orFail`.
18+
4. **`PCGet_*`** (из результата) — обёртка над `PCGet_Cell` / `PCGet_Str`; для
19+
строки добавь `i`-вариант.
20+
5. **Положи хелперы в публичный `.inc` плагина**, если API типа доступно другим
21+
плагинам.
22+
23+
## Числовое значение
24+
25+
```pawn
26+
// из сырого значения
27+
stock any:PCSingle_MyType(const JSON:valueJson, const any:def = 0, const orFailKey[] = "") {
28+
return PCSingle_Cell(valueJson, "MyType", def, orFailKey);
29+
}
30+
31+
// из поля объекта по ключу
32+
stock any:PCSingle_ObjMyType(const JSON:objectJson, const key[], const any:def = 0, const bool:dotNot = false, const bool:orFail = false) {
33+
return PCSingle_ObjCell(objectJson, key, "MyType", def, dotNot, orFail);
34+
}
35+
36+
// из результата
37+
stock any:PCGet_MyType(const Trie:p, const key[], const any:def = 0) {
38+
return PCGet_Cell(p, key, def);
39+
}
40+
```
41+
42+
## Строковое значение
43+
44+
```pawn
45+
stock PCSingle_MyStr(const JSON:valueJson, out[], const outLen, const def[] = "", const orFailKey[] = "") {
46+
return PCSingle_Str(valueJson, "MyType", out, outLen, def, orFailKey);
47+
}
48+
49+
stock PCSingle_iMyStr(const JSON:valueJson, const def[] = "", const orFailKey[] = "") {
50+
new out[PARAM_VALUE_MAX_LEN];
51+
PCSingle_Str(valueJson, "MyType", out, charsmax(out), def, orFailKey);
52+
return out;
53+
}
54+
55+
stock PCSingle_ObjMyStr(const JSON:objectJson, const key[], out[], const outLen, const def[] = "", const bool:dotNot = false, const bool:orFail = false) {
56+
return PCSingle_ObjStr(objectJson, key, "MyType", out, outLen, def, dotNot, orFail);
57+
}
58+
59+
stock PCGet_MyStr(const Trie:p, const key[], out[], const outLen, const def[] = "") {
60+
return PCGet_Str(p, key, out, outLen, def);
61+
}
62+
63+
stock PCGet_iMyStr(const Trie:p, const key[], const def[] = "") {
64+
return PCGet_iStr(p, key, def);
65+
}
66+
```
67+
68+
## Соглашение об именах
69+
70+
- `..._Obj...` — значение из **объекта** по ключу; без `Obj` — из **сырого** значения;
71+
- `i`-префикс — возвращает временную строку;
72+
- внутри указывается **имя своего типа** строкой (`"MyType"`).
73+
74+
## Замечания
75+
76+
- Хелперы **не обязательны** для работы типа — это удобство и единый стиль.
77+
- `stock` компилируется только при использовании, поэтому держать их в `.inc` дёшево.
78+
- Свои хелперы стоит задокументировать в скилле типов плагина — см. скилл
79+
`param-types-authoring`.
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
# Колбек чтения типа
2+
3+
Функция, которая разбирает JSON-значение параметра и пишет результат в `Trie`.
4+
5+
## Сигнатура
6+
7+
```pawn
8+
bool:@OnReadMyType(const JSON:jValue, const Trie:tParams, const sParamKey[], const sParamTag[])
9+
```
10+
11+
| Аргумент | Что это |
12+
|---|---|
13+
| `jValue` | JSON-значение параметра (то, что пришло из конфига) |
14+
| `tParams` | гарантированно валидный `Trie`, куда писать результат |
15+
| `sParamKey` | ключ параметра — под ним нужно записать значение |
16+
| `sParamTag` | тег после `:` в имени типа (`Тип:тег`), иначе пусто |
17+
18+
## Возврат
19+
20+
- `true` — значение прочитано и записано;
21+
- `false` — значение некорректно для этого типа (параметр считается невалидным).
22+
23+
## Запись результата
24+
25+
Три способа:
26+
27+
1. `ParamsController_SetCell(value)` — число / float / bool / хендлер;
28+
2. `ParamsController_SetString(str)` — строка (до 4096 ячеек);
29+
3. напрямую в `tParams` по `sParamKey`: `TrieSetCell`, `TrieSetString`,
30+
`TrieSetArray`.
31+
32+
`SetCell` / `SetString` работают **только внутри колбека чтения** (иначе аварийное
33+
завершение `Attempt to set param value outside the read callback.`) и не требуют
34+
ключа — контроллер знает текущий параметр.
35+
36+
> Колбек **обязан** записать значение под своим ключом. Если вернуть `true`, ничего
37+
> не записав, контроллер сообщит об ошибке вида «тип не пишет значение в trie».
38+
39+
## Разбор входа
40+
41+
- `json_get_type(jValue)` → `JSONNumber` / `JSONString` / `JSONBoolean` /
42+
`JSONArray` / `JSONObject` / `JSONNull`;
43+
- `json_is_array` / `json_is_object` / `json_is_string` / `json_is_number` / `json_is_bool`;
44+
- `json_get_number` / `json_get_real` / `json_get_bool` / `json_get_string`;
45+
- массивы/объекты: `json_array_get_count`, `json_array_get_number`,
46+
`json_object_has_value`, `json_object_get_number` и т.п.
47+
48+
## Теги
49+
50+
Тег приходит в `sParamTag`; пустой тег (`sParamTag[0] == EOS`) — обычный режим.
51+
52+
```pawn
53+
bool:@OnReadDuration(const JSON:jValue, const Trie:tParams, const sParamKey[], const sParamTag[]) {
54+
new value = json_get_number(jValue);
55+
if (equali(sParamTag, "minutes")) {
56+
value *= 60;
57+
}
58+
return ParamsController_SetCell(value);
59+
}
60+
```
61+
62+
Такой тип объявляется как `Duration` или `Duration:minutes`.
63+
64+
## Ошибки и мягкие преобразования
65+
66+
- Всё, что не должно приниматься, — `return false`.
67+
- Осторожно с `str_to_num` / `str_to_float`: нечисловая строка даёт `0` **без**
68+
ошибки. Если «мусор» должен быть ошибкой — проверяйте вручную
69+
(`json_get_type`, `is_strnum` и т.п.).
70+
- Некорректный вход можно залогировать: `PCJson_LogForFile(jValue, "WARNING", "...")`.

0 commit comments

Comments
 (0)