Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions Commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@

## Summary

`Commands` in `Scanline` are parser-level action specifications that describe **custom gameplay commands** without hardcoding one-off logic into `Parser.ts`.
`Commands` in `Scanline` are authored action specifications that describe **custom gameplay commands** without hardcoding one-off logic into `Parser.ts`.

The goal is to let us add commands such as:
- `TELEPORT WITH ID CARD`
- `UNLOCK DOOR WITH KEY`
- `REPAIR BOOMBOX WITH SOLDERING IRON`
- `USE ITEM ON TARGET`

while reusing the same generic parser systems for:
while reusing the same generic parser and runtime systems for:
- target resolution
- ambiguity clarification
- missing-argument clarification
Expand All @@ -36,15 +36,15 @@ Instead:
- each custom command is described by data
- `Parser Core` executes a generic plan

This is also the shared execution foundation for the LLM cascade:
- lower layers, custom commands, mocked scenarios, and LLM outputs can emit the same plan format
- `Core` stays the only place where parser plans are executed against gameplay rules
This is also the shared execution foundation for the LLM cascade and other actor-aware clients:
- lower layers, custom commands, mocked scenarios, NPC Puppet Master plans, and LLM outputs can emit the same plan format
- parser-produced plans still execute through `Parser Core`, while non-parser actor plans use the shared actor-aware executor instead of going through text parsing again

---

## Position In The Architecture

Custom command assets belong to the **parser layer**, not to `Game`.
Custom command assets are authored content, not hardcoded `Game` logic. Their execution is shared runtime behavior, even when the initiating client is the parser.

They are:
- language-aware
Expand All @@ -63,8 +63,8 @@ The flow is:
2. Stage 1 tries built-in parser logic
3. Stage 1 also checks custom command assets
4. A matching command asset produces a parser envelope / plan
5. `Parser Core` resolves arguments and executes the plan
6. `Game API` performs the actual world operations
5. `Parser Core` resolves arguments and executes the plan for parser-originated input
6. `Game API` / shared actor-aware runtime performs the actual world operations

---

Expand Down
8 changes: 4 additions & 4 deletions GDD.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@

## Парсер - посредник

Парсер в нашей игре -- это "мозг", который, общаясь с игроком на естественном языке, играет роль **посредника** между игровым движком и игроком, своеобразного гейм-мастера. Он принимает пользовательский ввод, наряду с контекстом (информацией о сцене, находящихся в ней предметах и NPC, доступныx действиях и состояниях). Затем парсер обрабатывает это и даёт команды игровому движку через API, опционально получает возвращаемые API значения и составляет сообщения для пользователя.
Парсер в нашей игре -- это "мозг", который, общаясь с игроком на естественном языке, играет роль **посредника** между игровым движком и игроком, своеобразного гейм-мастера. Он принимает пользовательский ввод, наряду с контекстом (информацией о сцене, находящихся в ней предметах и NPC, доступныx действиях и состояниях). Затем парсер обрабатывает это и даёт команды игровому движку через API, опционально получает возвращаемые API значения и составляет сообщения для пользователя. При этом сама семантическая часть исполнения действий постепенно выведена в общий actor-aware runtime слой: player parser, Puppet Master и другие клиенты могут использовать одни и те же разрешённые world actions и authored commands, не проходя через текстовый парсер заново.

<Context> ---json---> | | | |
| | ---text--> | <Parser> | ---json--> | <API> |
Expand Down Expand Up @@ -625,7 +625,7 @@ Parser-команды `OPEN` и `CLOSE` используют тот же runtime

Скриптовое API позволяет получать и устанавливать любые State любого объекта, но не позволяет создавать новые. Пользователь должен явно создать их в реакторе.

Parser command DSL тоже может менять уже созданные State через data-driven action. Такие команды не создают State автоматически: если State отсутствует или тип значения не совпадает, действие считается неуспешным. State текущих объектов сцены и inventory-предметов включаются в parser context и worldFacts, чтобы runtime-изменения были видны LLM без попадания в stale static cache.
Parser command DSL и общий actor-aware command runtime тоже могут менять уже созданные State через data-driven action. Такие команды не создают State автоматически: если State отсутствует или тип значения не совпадает, действие считается неуспешным. State текущих объектов сцены и inventory-предметов включаются в parser context и worldFacts, чтобы runtime-изменения были видны LLM без попадания в stale static cache.

Runtime-изменения State должны идти через общий State event path (Script API и parser actions используют его автоматически). Если значение реально изменилось, движок проверяет `interactions` объекта и запускает скрипты по ключам `state:<stateId>` и `state:<stateId>=<value>`. В контекст скрипта передаются `entity` и `args`: `stateId`, `previousValue`, `value`, `valueType`, `source`. Низкоуровневый `ComponentSystem.setStateValue` остаётся helper-ом без script side effects для нормализации, редактора и тестов.

Expand Down Expand Up @@ -660,7 +660,7 @@ Static и Actor могут содержать скриптовые событи

> Примечание: События _Always_ и _OnCollide_ зарезервированы в дизайне, но на текущий момент технически не реализованы в движке.

Parser command DSL поддерживает переиспользуемые runtime actions для authored-команд: проверку наличия точного объекта в scope (`requireEntityAvailable`), проверку одного из нескольких допустимых объектов (`requireAnyEntityAvailable`), изменение State (`setEntityState`), включение/выключение группы объектов (`setGroupDisabled`) и запуск/остановку скриптов (`runScript`/`stopScript`). Текущий пример: `TURN ON TV` / `TURN TV ON` требует видимый `tv` и пульт `tv_rc` у игрока или рядом; `TURN OFF TV` / `TURN TV OFF` требует пульт или reachable+visible `tv`. При успехе команды меняют только `tv.power` и выводят текст, а визуальные блики включаются/выключаются обычным State script event `state:power -> tv_power_changed`.
Parser command DSL и shared actor-aware command runtime поддерживают переиспользуемые runtime actions для authored-команд: проверку наличия точного объекта в scope (`requireEntityAvailable`), проверку одного из нескольких допустимых объектов (`requireAnyEntityAvailable`), изменение State (`setEntityState`), включение/выключение группы объектов (`setGroupDisabled`) и запуск/остановку скриптов (`runScript`/`stopScript`). Текущий пример: `TURN ON TV` / `TURN TV ON` требует видимый `tv` и пульт `tv_rc` у игрока или рядом; `TURN OFF TV` / `TURN TV OFF` требует пульт или reachable+visible `tv`. При успехе команды меняют только `tv.power` и выводят текст, а визуальные блики включаются/выключаются обычным State script event `state:power -> tv_power_changed`. Эти же authored commands могут быть выполнены и другими Actor, например через Puppet Master, если команда присутствует в их runtime context.

## Текстовые ассеты (TA)

Expand All @@ -670,7 +670,7 @@ Parser command DSL поддерживает переиспользуемые run

LLM-каскад поддерживает Parser Notes (PN): runtime-only приватные заметки ведущего-парсера для текущей сцены или отдельных объектов. PN нужны для мелких фактов, придуманных при обработке неподдержанных, но правдоподобных действий игрока, чтобы следующие ответы оставались консистентными. Например, если при попытке послушать радио парсер решил, что в эфире сейчас только статика, он может записать это как PN объекта и учитывать при следующей команде. PN не являются текстовыми ассетами, не сохраняются в scene JSON и не показываются игроку напрямую; при `#PEEK-ON` debug-лог показывает создание, обновление, очистку и stale-пометку PN, а `#PEEKPN-ON` выводит только PN context и PN mutations с operation, targetType, id, полным текстом note и `needsCheck`, если заметка требует перепроверки.

Если обычная runtime-операция реально затрагивает объект с PN или его содержимое (`TAKE`, `PUT`, `OPEN`, `CLOSE` и т.п.), движок не редактирует текст PN сам, а помечает её `parserNoteNeedsCheck: true`. LLM должна сверить такую заметку с текущей моделью мира и заменить или очистить её, если она устарела.
Если обычная runtime-операция реально затрагивает объект с PN или его содержимое (`TAKE`, `PUT`, `OPEN`, `CLOSE` и т.п.), движок не редактирует текст PN сам, а помечает её `parserNoteNeedsCheck: true`. LLM должна сверить такую заметку с текущей моделью мира и заменить или очистить её, если она устарела. Этот механизм относится ко всем Actor-инициированным действиям, а не только к командам игрока.

LLM-контекст сцены также содержит короткую runtime-only мини-историю текущего визита: до 8 последних команд игрока и player-facing ответов парсера (`context.scene.recentTurns`). Ответы урезаются до 85 символов. Эта история нужна для локальной conversational continuity, не сохраняется в файлы сцен и очищается при новом входе в сцену после ухода.

Expand Down
Loading
Loading