Compare commits
4
Commits
84894b1e98
...
152096337b
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
152096337b | ||
|
|
8944ba756c | ||
|
|
5be5bed0c5 | ||
|
|
cbc9472738 |
No files matched your search
+38
@@ -0,0 +1,38 @@
|
||||
# Godot 4.x
|
||||
.godot/
|
||||
.idea/
|
||||
sdk/
|
||||
bin/
|
||||
obj/
|
||||
|
||||
#ai
|
||||
.omo/
|
||||
.opencode/
|
||||
|
||||
gen/
|
||||
obj/
|
||||
bin/
|
||||
art_sources/
|
||||
|
||||
*.tres~
|
||||
*.tscn~
|
||||
|
||||
# GDScript LSP
|
||||
.godot/
|
||||
|
||||
# Export
|
||||
*.exe
|
||||
*.dmg
|
||||
*.apk
|
||||
*.aab
|
||||
*.pck
|
||||
*.zip
|
||||
*.log
|
||||
|
||||
# OS
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
# Editor
|
||||
*.import
|
||||
*.godot.uid
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 66 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 27 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 16 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 22 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 37 KiB |
+73
@@ -0,0 +1,73 @@
|
||||
# Editor Tools — making scenes and scenarios inside the running game
|
||||
|
||||
Editor Tools are the author's windows that open over the running game: the scene editor, the scenario editor, editors for the world map, interactive objects and lights, a builder of Godot scenes and the catalog export of a mod. Everything they save is ordinary mod files, and the game picks the change up at once, so an author writes a place, walks into it and plays it without restarting.
|
||||
|
||||
The mod also holds the base of the item and character editors (they are separate mods: Items Editor, Characters Editor). A game gets these tools through the Developer Tools toolset or its own collection.
|
||||
|
||||
## Opening the tools
|
||||
|
||||
In a game, the hammer button on the toolbar opens the tool box:
|
||||
|
||||

|
||||
|
||||
- **Scene editor**, **Map Editor**, **Interactive Editor** and **Light Editor** are in the tool box. Other tool mods add their own entries there (the item, character and RPG map editors, the Data Editor).
|
||||
- The **scenario editor** opens from the scene editor: select a scene, pick one of its scenarios and press **Open**, or **+ New scenario**.
|
||||
- When the tools are loaded at the main menu (for example with `--all-mods`), every tool also has a button in the menu's tool block, including the scene builder and the catalog export.
|
||||
|
||||
The windows stay open across scene changes, can be moved and resized, and close with the cross.
|
||||
|
||||
## A whole small edit: a new place
|
||||
|
||||
The novel template has a town, a bar and a home. Here an author adds a park that can be reached from the town, using only the editors.
|
||||
|
||||
**1. A new scene.** In the scene editor press **+ New scene**, type the name, choose the mod to save it to and add a background:
|
||||
|
||||

|
||||
|
||||
Save (Ctrl+S) writes `scenes/my_novel_park.json` into `my_novel_game`; the game knows the scene at once.
|
||||
|
||||
**2. Its scenario.** **+ New scenario** opens the scenario editor with a file for the scene. The park offers one way back:
|
||||
|
||||

|
||||
|
||||
**3. A way there.** In the town's scenario one answer and one label are added:
|
||||
|
||||

|
||||
|
||||
```scenario
|
||||
option "Go to the park" -> :park
|
||||
|
||||
:park
|
||||
switch_scene my_novel_park
|
||||
end
|
||||
```
|
||||
|
||||
Saving a scenario drops the game's scenario caches, so the next entry into the town plays the new text.
|
||||
|
||||
**4. Play it.** **Go to scene** in the scene editor, or simply playing on, enters the town, and the new answer is there:
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
## The editors
|
||||
|
||||
- **Scene editor** — the places of a novel: name, the mod to save to, backgrounds (one is picked at random on entry), ambient sound with a listen button, the default scenario and the scene's scenarios. **Go to scene** ends the running dialog and enters the scene.
|
||||
- **Scenario editor** — the files of every mod, a summary and a graph of scenes and transitions; DSL highlighting; Ctrl+S saves; **Play** (F5) saves and plays the scenario inside the running game, and Stop returns to where the game was; **Open in external editor** opens the file in the system's editor.
|
||||
- **Map Editor** — the zones of the world map.
|
||||
- **Interactive Editor** — clickable objects of the current scene.
|
||||
- **Light Editor** — the lights of the current scene.
|
||||
- **Scene builder** — Godot `.tscn` scenes for mods.
|
||||
- **Catalog export** — packs a mod into a zip and writes its entry for a mod catalog with checksums.
|
||||
|
||||
Undo works while editing (Ctrl+Z in the text and in the forms of the entity editors). Checking a mod for broken references is the Validator's job; the editors do not stop you from saving a scenario with a mistake.
|
||||
|
||||
## Whose files are written
|
||||
|
||||
The tools write only into mods installed as folders. A scene is the sum of the `scenes/<name>.json` files of all mods, so the scene editor writes the file of the mod chosen in **Save to**. Changing a scene that belongs to another or a packed mod creates a file in your mod that adds to it; backgrounds that come from other files are shown locked. Scenarios are saved in the mod they belong to.
|
||||
|
||||
## If something goes wrong
|
||||
|
||||
1. **The hammer button is missing.** The game does not include the tools; add the Developer Tools toolset in its collection or run with `--with-mods=editor_tools`.
|
||||
2. **A new scenario does not play.** Its header names another scene, or another scenario of the scene is chosen first (compare their `priority`).
|
||||
3. **Save to lists no mods.** Only mods installed as folders can be written to.
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
# Editor Tools — crear escenas y escenarios dentro del juego en marcha
|
||||
|
||||
Editor Tools son las ventanas de autor que se abren sobre el juego en marcha: el editor de escenas, el de escenarios, los editores del mapa del mundo, de objetos interactivos y de luces, un constructor de escenas de Godot y la exportación al catálogo de un mod. Todo lo que guardan son archivos de mod normales, y el juego toma el cambio al instante, así que puedes escribir un lugar, entrar en él y jugarlo sin reiniciar.
|
||||
|
||||
El mod también contiene la base de los editores de objetos y de personajes (que son mods aparte: Items Editor y Characters Editor). Un juego obtiene estas herramientas mediante el conjunto Developer Tools o con su propia colección.
|
||||
|
||||
## Cómo abrir las herramientas
|
||||
|
||||
Dentro de un juego, el botón del martillo de la barra de herramientas abre la caja de herramientas:
|
||||
|
||||

|
||||
|
||||
- **Editor de escenas**, **Editor de mapas**, **Editor de interactivos** y **Editor de luces** están en la caja. Otros mods de herramientas añaden ahí sus propias entradas (los editores de objetos, de personajes y de mapas RPG, el editor de datos).
|
||||
- El **editor de escenarios** se abre desde el editor de escenas: elige una escena, selecciona uno de sus escenarios y pulsa **Abrir**, o **+ Nuevo escenario**.
|
||||
- Si las herramientas se cargan en el menú principal (por ejemplo con `--all-mods`), cada una tiene también un botón en el bloque de herramientas del menú, incluidos el constructor de escenas y la exportación al catálogo.
|
||||
|
||||
Las ventanas siguen abiertas al cambiar de escena, se pueden mover y redimensionar, y se cierran con la cruz.
|
||||
|
||||
## Una edición pequeña completa: un lugar nuevo
|
||||
|
||||
La plantilla de novela tiene un pueblo, un bar y una casa. Aquí añadiremos un parque al que se llega desde el pueblo usando solo los editores.
|
||||
|
||||
**1. Una escena nueva.** En el editor de escenas pulsa **+ Nueva escena**, escribe el nombre, elige el mod donde guardarla y añade un fondo:
|
||||
|
||||

|
||||
|
||||
Guardar (Ctrl+S) escribe `scenes/my_novel_park.json` en `my_novel_game`; el juego conoce la escena al instante.
|
||||
|
||||
**2. Su escenario.** **+ Nuevo escenario** abre el editor de escenarios con un archivo para la escena. El parque ofrece una única salida:
|
||||
|
||||

|
||||
|
||||
**3. Un camino hasta allí.** En el escenario del pueblo se añaden una respuesta y una etiqueta:
|
||||
|
||||

|
||||
|
||||
```scenario
|
||||
option "Ir al parque" -> :park
|
||||
|
||||
:park
|
||||
switch_scene my_novel_park
|
||||
end
|
||||
```
|
||||
|
||||
Guardar un escenario descarta las cachés de escenarios del juego, así que la próxima entrada al pueblo ya reproduce el texto nuevo.
|
||||
|
||||
**4. Juégalo.** **Ir a la escena** en el editor de escenas, o simplemente seguir jugando, entra en el pueblo, y la nueva respuesta ya está ahí:
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
## Los editores
|
||||
|
||||
- **Editor de escenas**: los lugares de una novela: nombre, el mod donde guardar, fondos (al entrar se elige uno al azar), sonido ambiente con botón de escucha, el escenario por defecto y los escenarios de la escena. **Ir a la escena** termina el diálogo en curso y entra en la escena.
|
||||
- **Editor de escenarios**: los archivos de todos los mods, un resumen y un grafo de escenas y transiciones; resaltado de DSL; Ctrl+S guarda; **Jugar** (F5) guarda y reproduce el escenario dentro del juego en marcha, y Detener vuelve a donde estaba el juego; **Abrir en un editor externo** abre el archivo en el editor del sistema.
|
||||
- **Editor de mapas**: las zonas del mapa del mundo.
|
||||
- **Editor de interactivos**: los objetos clicables de la escena actual.
|
||||
- **Editor de luces**: las luces de la escena actual.
|
||||
- **Constructor de escenas**: escenas `.tscn` de Godot para los mods.
|
||||
- **Exportación al catálogo**: empaqueta un mod en un zip y escribe su entrada para un catálogo de mods con sumas de comprobación.
|
||||
|
||||
Deshacer funciona mientras editas (Ctrl+Z en el texto y en los formularios de los editores de objetos y personajes). Comprobar un mod en busca de referencias rotas es tarea de Validator; los editores no te impiden guardar un escenario con un error.
|
||||
|
||||
## De quién son los archivos que se escriben
|
||||
|
||||
Las herramientas solo escriben en mods instalados como carpetas. Una escena es la suma de los archivos `scenes/<name>.json` de todos los mods, así que el editor de escenas escribe el archivo del mod elegido en **Guardar en**. Si cambias una escena que pertenece a otro mod o a un mod empaquetado, se crea un archivo en tu mod que la amplía; los fondos que vienen de otros archivos se muestran bloqueados. Los escenarios se guardan en el mod al que pertenecen.
|
||||
|
||||
## Si algo sale mal
|
||||
|
||||
1. **No aparece el botón del martillo.** El juego no incluye las herramientas; añade el conjunto Developer Tools a su colección o ejecútalo con `--with-mods=editor_tools`.
|
||||
2. **Un escenario nuevo no se reproduce.** Su cabecera nombra otra escena, o antes se elige otro escenario de la escena (compara sus `priority`).
|
||||
3. **Guardar en no muestra ningún mod.** Solo se puede escribir en mods instalados como carpetas.
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
# Editor Tools — 実行中のゲーム内でシーンとシナリオを作る
|
||||
|
||||
Editor Tools は、実行中のゲームの上に開く作者向けのウィンドウ群です。シーンエディター、シナリオエディター、ワールドマップ・インタラクティブ・ライトの各エディター、Godot シーンのビルダー、MOD カタログの書き出しが含まれます。保存されるのはどれも普通の MOD ファイルで、ゲームは変更をすぐに取り込みます。そのため、場所を書いて、その場に入って遊ぶまでを、再起動なしで行えます。
|
||||
|
||||
この MOD には、アイテムエディターとキャラクターエディターの土台も入っています(本体は別の MOD、Items Editor と Characters Editor です)。ゲームにこれらのツールを入れるには、Developer Tools ツールセットか、そのゲーム独自のコレクションを使います。
|
||||
|
||||
## ツールを開く
|
||||
|
||||
ゲーム内では、ツールバーのハンマーのボタンでツールボックスが開きます:
|
||||
|
||||

|
||||
|
||||
- ツールボックスには**シーンエディター**、**マップエディター**、**インタラクティブエディター**、**ライトエディター**が入っています。他のツール MOD もここに項目を追加します(アイテム、キャラクター、RPG マップの各エディター、データエディター)。
|
||||
- **シナリオエディター**はシーンエディターから開きます。シーンを選び、そのシナリオのひとつを選んで**開く**を押すか、**+ 新しいシナリオ**を押します。
|
||||
- メインメニューでツールを読み込んでいる場合(たとえば `--all-mods`)、メニューのツール欄にも各ツールのボタンが並びます。シーンビルダーとカタログの書き出しも含まれます。
|
||||
|
||||
ウィンドウはシーンを切り替えても開いたまま残り、移動やサイズ変更ができ、×で閉じます。
|
||||
|
||||
## 小さな編集をひと通り: 新しい場所
|
||||
|
||||
ノベルのテンプレートには、町、バー、家があります。ここではエディターだけを使って、町から行ける公園を追加します。
|
||||
|
||||
**1. 新しいシーン。** シーンエディターで **+ 新しいシーン**を押し、名前を入力し、保存先の MOD を選んで背景を追加します:
|
||||
|
||||

|
||||
|
||||
保存(Ctrl+S)すると `scenes/my_novel_park.json` が `my_novel_game` に書き込まれ、ゲームはそのシーンをすぐに認識します。
|
||||
|
||||
**2. そのシナリオ。** **+ 新しいシナリオ**を押すと、そのシーンのファイルを開いたシナリオエディターが立ち上がります。公園からは戻る道が一本だけあります:
|
||||
|
||||

|
||||
|
||||
**3. そこへ行く道。** 町のシナリオに、答えをひとつとラベルをひとつ追加します:
|
||||
|
||||

|
||||
|
||||
```scenario
|
||||
option "公園へ行く" -> :park
|
||||
|
||||
:park
|
||||
switch_scene my_novel_park
|
||||
end
|
||||
```
|
||||
|
||||
シナリオを保存するとゲームのシナリオキャッシュが破棄されるので、次に町へ入ったときには新しいテキストが再生されます。
|
||||
|
||||
**4. 遊んでみる。** シーンエディターの**シーンへ移動**を押すか、そのまま遊び続けると町に入り、新しい答えがそこにあります:
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
## 各エディター
|
||||
|
||||
- **シーンエディター** — ノベルの場所: 名前、保存先の MOD、背景(入るたびにひとつがランダムで選ばれます)、試聴ボタン付きの環境音、既定のシナリオ、そのシーンのシナリオ。**シーンへ移動**は進行中のダイアログを終わらせてシーンに入ります。
|
||||
- **シナリオエディター** — すべての MOD のファイル、概要、シーンと遷移のグラフ、DSL のハイライト、Ctrl+S で保存。**プレイ**(F5)は保存して実行中のゲーム内でシナリオを再生し、停止するとゲームが元いた場所へ戻ります。**外部エディターで開く**はシステムのエディターでファイルを開きます。
|
||||
- **マップエディター** — ワールドマップのゾーン。
|
||||
- **インタラクティブエディター** — 現在のシーンのクリックできるオブジェクト。
|
||||
- **ライトエディター** — 現在のシーンのライト。
|
||||
- **シーンビルダー** — MOD 用の Godot `.tscn` シーン。
|
||||
- **カタログの書き出し** — MOD を zip にまとめ、チェックサム付きで MOD カタログ用のエントリーを書き出します。
|
||||
|
||||
編集中は元に戻せます(テキスト内と、アイテム・キャラクターエディターのフォームで Ctrl+Z)。壊れた参照の検査は Validator の仕事で、エディターは間違いのあるシナリオの保存を止めません。
|
||||
|
||||
## どの MOD のファイルが書かれるか
|
||||
|
||||
ツールが書き込むのは、フォルダーとしてインストールされた MOD だけです。シーンは全 MOD の `scenes/<name>.json` の合計なので、シーンエディターは**保存先**で選んだ MOD のファイルを書き込みます。他の MOD やパッケージ済みの MOD に属するシーンを変更すると、それを補うファイルがあなたの MOD に作られ、他のファイル由来の背景はロックされて表示されます。シナリオは所属する MOD に保存されます。
|
||||
|
||||
## うまくいかないとき
|
||||
|
||||
1. **ハンマーのボタンがない。** そのゲームにツールが入っていません。コレクションに Developer Tools ツールセットを追加するか、`--with-mods=editor_tools` で起動してください。
|
||||
2. **新しいシナリオが再生されない。** ヘッダーが別のシーンを指しているか、そのシーンの別のシナリオが先に選ばれています(`priority` を比べてください)。
|
||||
3. **保存先に MOD が出ない。** 書き込めるのはフォルダーとしてインストールされた MOD だけです。
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
# Editor Tools — 실행 중인 게임 안에서 장면과 시나리오 만들기
|
||||
|
||||
Editor Tools는 실행 중인 게임 위에 열리는 창작용 창 모음입니다. 장면 에디터, 시나리오 에디터, 월드 맵·상호작용·조명 에디터, Godot 장면 빌더, 모드 카탈로그 내보내기가 들어 있습니다. 저장되는 것은 모두 평범한 모드 파일이고 게임은 변경을 곧바로 받아들입니다. 그래서 장소를 쓰고, 바로 들어가 플레이하는 일을 재시작 없이 할 수 있습니다.
|
||||
|
||||
이 모드에는 아이템·캐릭터 에디터의 기반도 들어 있습니다(본체는 별도 모드인 Items Editor와 Characters Editor입니다). 게임에 이 도구들을 넣으려면 Developer Tools 도구 모음이나 그 게임의 컬렉션을 사용합니다.
|
||||
|
||||
## 도구 열기
|
||||
|
||||
게임 안에서 도구 모음의 망치 버튼을 누르면 도구 상자가 열립니다:
|
||||
|
||||

|
||||
|
||||
- 도구 상자에는 **장면 에디터**, **맵 에디터**, **상호작용 에디터**, **조명 에디터**가 있습니다. 다른 도구 모드도 여기에 항목을 추가합니다(아이템, 캐릭터, RPG 맵 에디터, 데이터 에디터).
|
||||
- **시나리오 에디터**는 장면 에디터에서 엽니다. 장면을 고르고 그 시나리오 중 하나를 선택한 뒤 **열기**를 누르거나 **+ 새 시나리오**를 누릅니다.
|
||||
- 메인 메뉴에서 도구를 불러오는 경우(예: `--all-mods`), 메뉴의 도구 영역에도 각 도구 버튼이 생깁니다. 장면 빌더와 카탈로그 내보내기도 포함됩니다.
|
||||
|
||||
창은 장면을 바꿔도 열린 채로 남고, 옮기고 크기를 바꿀 수 있으며 ×로 닫습니다.
|
||||
|
||||
## 작은 편집 하나를 끝까지: 새 장소
|
||||
|
||||
소설 템플릿에는 마을, 술집, 집이 있습니다. 여기서는 에디터만 써서 마을에서 갈 수 있는 공원을 추가해 보겠습니다.
|
||||
|
||||
**1. 새 장면.** 장면 에디터에서 **+ 새 장면**을 누르고 이름을 입력하고 저장할 모드를 고른 다음 배경을 추가합니다:
|
||||
|
||||

|
||||
|
||||
저장(Ctrl+S)하면 `scenes/my_novel_park.json`이 `my_novel_game`에 기록되고, 게임은 그 장면을 곧바로 인식합니다.
|
||||
|
||||
**2. 그 장면의 시나리오.** **+ 새 시나리오**를 누르면 그 장면의 파일이 열린 시나리오 에디터가 뜹니다. 공원에서는 돌아가는 길이 하나뿐입니다:
|
||||
|
||||

|
||||
|
||||
**3. 그곳으로 가는 길.** 마을 시나리오에 답 하나와 레이블 하나를 추가합니다:
|
||||
|
||||

|
||||
|
||||
```scenario
|
||||
option "공원으로 가기" -> :park
|
||||
|
||||
:park
|
||||
switch_scene my_novel_park
|
||||
end
|
||||
```
|
||||
|
||||
시나리오를 저장하면 게임의 시나리오 캐시가 비워지므로, 다음에 마을에 들어가면 새 텍스트가 재생됩니다.
|
||||
|
||||
**4. 플레이해 보기.** 장면 에디터의 **장면으로 이동**을 누르거나 그냥 계속 플레이하면 마을로 들어가고, 새 답이 그 자리에 있습니다:
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
## 각 에디터
|
||||
|
||||
- **장면 에디터** — 소설의 장소: 이름, 저장할 모드, 배경(들어갈 때 하나가 무작위로 선택됩니다), 청취 버튼이 있는 환경음, 기본 시나리오, 장면의 시나리오. **장면으로 이동**은 진행 중인 대화를 끝내고 장면으로 들어갑니다.
|
||||
- **시나리오 에디터** — 모든 모드의 파일, 요약, 장면과 전환의 그래프, DSL 강조 표시, Ctrl+S 저장. **플레이**(F5)는 저장하고 실행 중인 게임 안에서 시나리오를 재생하며, 정지는 게임이 있던 곳으로 돌아갑니다. **외부 에디터로 열기**는 시스템 편집기로 파일을 엽니다.
|
||||
- **맵 에디터** — 월드 맵의 구역.
|
||||
- **상호작용 에디터** — 현재 장면의 클릭 가능한 객체.
|
||||
- **조명 에디터** — 현재 장면의 조명.
|
||||
- **장면 빌더** — 모드용 Godot `.tscn` 장면.
|
||||
- **카탈로그 내보내기** — 모드를 zip으로 묶고 체크섬과 함께 모드 카탈로그용 항목을 기록합니다.
|
||||
|
||||
편집 중에는 되돌리기가 됩니다(텍스트와 아이템·캐릭터 에디터의 폼에서 Ctrl+Z). 깨진 참조 검사는 Validator의 일이며, 에디터가 실수가 있는 시나리오의 저장을 막지는 않습니다.
|
||||
|
||||
## 어떤 모드의 파일이 기록되는가
|
||||
|
||||
도구는 폴더로 설치된 모드에만 씁니다. 장면은 모든 모드의 `scenes/<name>.json` 파일을 합친 것이므로, 장면 에디터는 **저장할 곳**에서 고른 모드의 파일을 씁니다. 다른 모드나 압축된 모드에 속한 장면을 바꾸면 그 장면을 보충하는 파일이 당신의 모드에 만들어지고, 다른 파일에서 온 배경은 잠긴 상태로 표시됩니다. 시나리오는 속한 모드에 저장됩니다.
|
||||
|
||||
## 문제가 생겼을 때
|
||||
|
||||
1. **망치 버튼이 없습니다.** 그 게임에 도구가 들어 있지 않습니다. 컬렉션에 Developer Tools 도구 모음을 추가하거나 `--with-mods=editor_tools`로 실행하세요.
|
||||
2. **새 시나리오가 재생되지 않습니다.** 머리말이 다른 장면을 가리키고 있거나, 그 장면의 다른 시나리오가 먼저 선택됩니다(`priority`를 비교해 보세요).
|
||||
3. **저장할 곳에 모드가 없습니다.** 폴더로 설치된 모드에만 쓸 수 있습니다.
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
# Editor Tools — сцены и сценарии прямо в запущенной игре
|
||||
|
||||
Editor Tools — это авторские окна поверх работающей игры: редактор сцен, редактор сценариев, редакторы карты мира, интерактивных объектов и света, конструктор сцен Godot и экспорт каталога мода. Всё, что они сохраняют, — обычные файлы модов, и игра подхватывает правки сразу: можно описать место, тут же войти в него и сыграть, ничего не перезапуская.
|
||||
|
||||
Здесь же лежит основа редакторов предметов и персонажей (сами они — отдельные моды: Items Editor и Characters Editor). В игру эти инструменты попадают через набор Developer Tools или через её собственную коллекцию.
|
||||
|
||||
## Как открыть инструменты
|
||||
|
||||
Молоток на панели инструментов в игре открывает набор инструментов:
|
||||
|
||||

|
||||
|
||||
- **Редактор сцен**, **Редактор карты**, **Редактор интерактивов** и **Редактор освещения** входят в набор. Другие инструментальные моды добавляют туда свои пункты (редакторы предметов, персонажей и RPG-карт, редактор данных).
|
||||
- **Редактор сценариев** открывается из редактора сцен: выберите сцену, укажите один из её сценариев и нажмите **Открыть** — или **+ Новый сценарий**.
|
||||
- Если инструменты загружены в главном меню (например, с `--all-mods`), у каждого есть кнопка и в блоке инструментов меню, включая конструктор сцен и экспорт каталога.
|
||||
|
||||
Окна остаются открытыми при смене сцен, их можно двигать и растягивать, а закрываются они крестиком.
|
||||
|
||||
## Целая небольшая правка: новое место
|
||||
|
||||
В шаблоне новеллы есть город, бар и дом. Добавим туда парк, до которого можно дойти из города, — только средствами редакторов.
|
||||
|
||||
**1. Новая сцена.** В редакторе сцен нажмите **+ Новая сцена**, введите имя, выберите мод для сохранения и добавьте фон:
|
||||
|
||||

|
||||
|
||||
Сохранение (Ctrl+S) записывает `scenes/my_novel_park.json` в `my_novel_game` — и игра знает сцену сразу.
|
||||
|
||||
**2. Её сценарий.** **+ Новый сценарий** открывает редактор сценариев с файлом для сцены. Из парка есть один путь назад:
|
||||
|
||||

|
||||
|
||||
**3. Путь туда.** В сценарии города добавляются один ответ и одна метка:
|
||||
|
||||

|
||||
|
||||
```scenario
|
||||
option "Пойти в парк" -> :park
|
||||
|
||||
:park
|
||||
switch_scene my_novel_park
|
||||
end
|
||||
```
|
||||
|
||||
Сохранение сценария сбрасывает кэш сценариев игры, так что при следующем входе в город сыграет уже новый текст.
|
||||
|
||||
**4. Сыграйте.** **Перейти в сцену** в редакторе сцен — или просто продолжайте играть — и вы попадёте в город, где новый ответ уже на месте:
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
## Редакторы
|
||||
|
||||
- **Редактор сцен** — места новеллы: имя, мод для сохранения, фоны (при входе один выбирается случайно), звук окружения с кнопкой прослушивания, сценарий по умолчанию и сценарии сцены. **Перейти в сцену** завершает текущий диалог и входит в сцену.
|
||||
- **Редактор сценариев** — файлы всех модов, сводка и граф сцен и переходов; подсветка DSL; Ctrl+S сохраняет; **Запустить** (F5) сохраняет и проигрывает сценарий прямо в запущенной игре, а «Стоп» возвращает туда, где игра была; **Открыть во внешнем редакторе** открывает файл в системном редакторе.
|
||||
- **Редактор карты** — зоны карты мира.
|
||||
- **Редактор интерактивов** — кликабельные объекты текущей сцены.
|
||||
- **Редактор освещения** — источники света текущей сцены.
|
||||
- **Конструктор сцен** — сцены Godot `.tscn` для модов.
|
||||
- **Экспорт каталога** — упаковывает мод в zip и пишет его запись для каталога модов с контрольными суммами.
|
||||
|
||||
Отмена работает во время редактирования (Ctrl+Z в тексте и в формах редакторов предметов и персонажей). Проверка мода на битые ссылки — задача Validator; редакторы не мешают сохранить сценарий с ошибкой.
|
||||
|
||||
## Чьи файлы пишутся
|
||||
|
||||
Инструменты пишут только в моды, установленные папками. Сцена — это сумма файлов `scenes/<name>.json` всех модов, поэтому редактор сцен пишет файл того мода, который выбран в **Сохранять в**. Если вы меняете сцену, принадлежащую другому моду или упакованному моду, создаётся файл в вашем моде, который её дополняет; фоны из чужих файлов показываются заблокированными. Сценарии сохраняются в том моде, которому принадлежат.
|
||||
|
||||
## Если что-то пошло не так
|
||||
|
||||
1. **Нет кнопки-молотка.** В игре нет инструментов — добавьте набор Developer Tools в её коллекцию или запустите с `--with-mods=editor_tools`.
|
||||
2. **Новый сценарий не играет.** В его заголовке указана другая сцена, или вперёд выбран другой сценарий этой сцены (сравните их `priority`).
|
||||
3. **В «Сохранять в» нет модов.** Писать можно только в моды, установленные папками.
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
# Editor Tools — dựng cảnh và kịch bản ngay trong trò chơi đang chạy
|
||||
|
||||
Editor Tools là những cửa sổ dành cho tác giả mở trên trò chơi đang chạy: trình sửa cảnh, trình sửa kịch bản, trình sửa bản đồ thế giới, trình sửa vật tương tác và ánh sáng, trình dựng cảnh Godot và phần xuất danh mục của mod. Mọi thứ chúng lưu đều là tệp mod bình thường, và trò chơi nhận thay đổi ngay lập tức, nên bạn viết ra một địa điểm, bước vào đó và chơi luôn mà không phải khởi động lại.
|
||||
|
||||
Mod này cũng chứa phần nền của trình sửa vật phẩm và nhân vật (bản thân chúng là mod riêng: Items Editor và Characters Editor). Một trò chơi nhận các công cụ này qua bộ Developer Tools hoặc qua bộ sưu tập riêng của nó.
|
||||
|
||||
## Mở các công cụ
|
||||
|
||||
Trong game, nút chiếc búa trên thanh công cụ mở hộp công cụ:
|
||||
|
||||

|
||||
|
||||
- **Trình sửa cảnh**, **trình sửa bản đồ**, **trình sửa tương tác** và **trình sửa ánh sáng** nằm trong hộp công cụ. Các mod công cụ khác thêm mục của riêng chúng vào đó (trình sửa vật phẩm, nhân vật và bản đồ RPG, trình sửa dữ liệu).
|
||||
- **Trình sửa kịch bản** mở từ trình sửa cảnh: chọn một cảnh, chọn một kịch bản của cảnh rồi nhấn **Mở**, hoặc **+ Kịch bản mới**.
|
||||
- Nếu các công cụ được tải ở menu chính (ví dụ với `--all-mods`), mỗi công cụ cũng có nút trong khối công cụ của menu, kể cả trình dựng cảnh và phần xuất danh mục.
|
||||
|
||||
Các cửa sổ vẫn mở khi chuyển cảnh, có thể di chuyển và đổi kích thước, và đóng bằng dấu ×.
|
||||
|
||||
## Một chỉnh sửa nhỏ trọn vẹn: một địa điểm mới
|
||||
|
||||
Mẫu tiểu thuyết có một thị trấn, một quán bar và một ngôi nhà. Ở đây ta thêm một công viên đi được từ thị trấn, chỉ bằng các trình sửa.
|
||||
|
||||
**1. Một cảnh mới.** Trong trình sửa cảnh nhấn **+ Cảnh mới**, gõ tên, chọn mod để lưu và thêm phông nền:
|
||||
|
||||

|
||||
|
||||
Lưu (Ctrl+S) ghi `scenes/my_novel_park.json` vào `my_novel_game`; trò chơi biết cảnh này ngay.
|
||||
|
||||
**2. Kịch bản của cảnh.** **+ Kịch bản mới** mở trình sửa kịch bản với một tệp cho cảnh. Công viên chỉ có một lối về:
|
||||
|
||||

|
||||
|
||||
**3. Một lối đến đó.** Trong kịch bản của thị trấn, thêm một câu trả lời và một nhãn:
|
||||
|
||||

|
||||
|
||||
```scenario
|
||||
option "Ra công viên" -> :park
|
||||
|
||||
:park
|
||||
switch_scene my_novel_park
|
||||
end
|
||||
```
|
||||
|
||||
Lưu kịch bản sẽ xóa bộ nhớ đệm kịch bản của game, nên lần vào thị trấn tiếp theo sẽ chơi đoạn văn bản mới.
|
||||
|
||||
**4. Chơi thử.** **Đến cảnh** trong trình sửa cảnh, hoặc cứ chơi tiếp, sẽ vào thị trấn, và câu trả lời mới đã ở đó:
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
## Các trình sửa
|
||||
|
||||
- **Trình sửa cảnh** — các địa điểm của tiểu thuyết: tên, mod để lưu, phông nền (mỗi lần vào chọn ngẫu nhiên một), âm thanh nền có nút nghe thử, kịch bản mặc định và các kịch bản của cảnh. **Đến cảnh** kết thúc đoạn hội thoại đang chạy và vào cảnh.
|
||||
- **Trình sửa kịch bản** — tệp của mọi mod, bản tóm tắt và đồ thị cảnh cùng chuyển cảnh; tô sáng DSL; Ctrl+S để lưu; **Chơi** (F5) lưu và phát kịch bản ngay trong game đang chạy, còn Dừng đưa game về chỗ cũ; **Mở bằng trình sửa ngoài** mở tệp bằng chương trình mặc định của hệ thống.
|
||||
- **Trình sửa bản đồ** — các vùng của bản đồ thế giới.
|
||||
- **Trình sửa tương tác** — những vật bấm được của cảnh hiện tại.
|
||||
- **Trình sửa ánh sáng** — đèn của cảnh hiện tại.
|
||||
- **Trình dựng cảnh** — cảnh `.tscn` của Godot cho các mod.
|
||||
- **Xuất danh mục** — đóng gói mod thành zip và ghi mục danh mục kèm tổng kiểm tra.
|
||||
|
||||
Hoàn tác hoạt động trong khi sửa (Ctrl+Z trong phần văn bản và trong biểu mẫu của trình sửa vật phẩm, nhân vật). Kiểm tra mod có tham chiếu hỏng là việc của Validator; các trình sửa không cản bạn lưu một kịch bản còn lỗi.
|
||||
|
||||
## Tệp của ai được ghi
|
||||
|
||||
Các công cụ chỉ ghi vào mod được cài dưới dạng thư mục. Một cảnh là tổng các tệp `scenes/<name>.json` của mọi mod, nên trình sửa cảnh ghi tệp của mod được chọn trong **Lưu vào**. Khi sửa một cảnh thuộc mod khác hoặc mod đã đóng gói, một tệp bổ sung cho nó sẽ được tạo trong mod của bạn; những phông nền đến từ tệp khác hiện ở trạng thái khóa. Kịch bản được lưu vào mod mà chúng thuộc về.
|
||||
|
||||
## Khi có trục trặc
|
||||
|
||||
1. **Không thấy nút chiếc búa.** Trò chơi không có công cụ; hãy thêm bộ Developer Tools vào bộ sưu tập của nó hoặc chạy với `--with-mods=editor_tools`.
|
||||
2. **Kịch bản mới không phát.** Phần đầu của nó ghi cảnh khác, hoặc một kịch bản khác của cảnh được chọn trước (so sánh `priority` của chúng).
|
||||
3. **Mục Lưu vào không có mod nào.** Chỉ ghi được vào mod cài dưới dạng thư mục.
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
# Editor Tools — 在运行中的游戏里制作场景与剧本
|
||||
|
||||
Editor Tools 是叠在运行中游戏之上的作者工具窗口:场景编辑器、剧本编辑器、世界地图编辑器、交互物编辑器和光照编辑器,还有一个 Godot 场景构建器与模组目录导出。它们保存的全是普通的模组文件,游戏会立刻读到改动,所以作者可以写下一个地点,马上走进去试玩,无需重启。
|
||||
|
||||
本模组还包含物品与角色编辑器的底层部分(它们是两个独立的模组:Items Editor 和 Characters Editor)。游戏通过 Developer Tools 工具集或自己的集合获得这些工具。
|
||||
|
||||
## 打开工具
|
||||
|
||||
在游戏中,工具栏上的锤子按钮会打开工具箱:
|
||||
|
||||

|
||||
|
||||
- 工具箱里有**场景编辑器**、**地图编辑器**、**交互编辑器**和**光照编辑器**。其他工具模组会往里面添加自己的条目(物品、角色和 RPG 地图编辑器,以及数据编辑器)。
|
||||
- **剧本编辑器**从场景编辑器打开:选中一个场景,挑一个它的剧本,按**打开**,或者按 **+ 新剧本**。
|
||||
- 如果在主菜单就加载了工具(比如用 `--all-mods`),菜单的工具区里每个工具也都有按钮,包括场景构建器和目录导出。
|
||||
|
||||
这些窗口在切换场景后依然开着,可以拖动和调整大小,点叉号关闭。
|
||||
|
||||
## 一次完整的小改动:一个新地点
|
||||
|
||||
小说模板里有小镇、酒吧和家。下面只用编辑器,给小镇加一个能走过去的公园。
|
||||
|
||||
**1. 新场景。** 在场景编辑器里按 **+ 新场景**,输入名称,选择保存到哪个模组,再添加一个背景:
|
||||
|
||||

|
||||
|
||||
保存(Ctrl+S)会把 `scenes/my_novel_park.json` 写进 `my_novel_game`,游戏马上就知道这个场景了。
|
||||
|
||||
**2. 它的剧本。** **+ 新剧本**会打开剧本编辑器,里面是该场景的一个文件。公园只有一条回去的路:
|
||||
|
||||

|
||||
|
||||
**3. 通往那里的路。** 在小镇的剧本里加一个回答和一个标签:
|
||||
|
||||

|
||||
|
||||
```scenario
|
||||
option "去公园" -> :park
|
||||
|
||||
:park
|
||||
switch_scene my_novel_park
|
||||
end
|
||||
```
|
||||
|
||||
保存剧本会清掉游戏的剧本缓存,所以下次进小镇时播放的就是新文本。
|
||||
|
||||
**4. 试玩。** 在场景编辑器里点**前往场景**,或者干脆继续玩下去,就会进入小镇,新的回答已经在那里了:
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
## 各个编辑器
|
||||
|
||||
- **场景编辑器** —— 小说的地点:名称、保存到的模组、背景(进入时随机选一个)、带试听按钮的环境音、默认剧本和场景的剧本。**前往场景**会结束当前对话并进入该场景。
|
||||
- **剧本编辑器** —— 所有模组的文件、一份概要,以及场景与转场的图;DSL 高亮;Ctrl+S 保存;**试玩**(F5)保存并在运行中的游戏里播放剧本,停止则回到游戏原来的位置;**在外部编辑器中打开**会用系统默认程序打开文件。
|
||||
- **地图编辑器** —— 世界地图上的区域。
|
||||
- **交互编辑器** —— 当前场景里可点击的对象。
|
||||
- **光照编辑器** —— 当前场景的灯光。
|
||||
- **场景构建器** —— 为模组制作 Godot `.tscn` 场景。
|
||||
- **目录导出** —— 把模组打包成 zip,并写出带校验和的模组目录条目。
|
||||
|
||||
编辑期间可以撤销(文本里和物品、角色编辑器的表单里都支持 Ctrl+Z)。检查模组有没有失效引用是 Validator 的活儿;编辑器不会拦着你保存一个有错误的剧本。
|
||||
|
||||
## 写的是谁的文件
|
||||
|
||||
这些工具只写安装成文件夹的模组。一个场景是所有模组 `scenes/<name>.json` 文件的总和,所以场景编辑器写的是**保存到**里选中的那个模组的文件。改动属于别的模组或打包模组的场景时,会在你的模组里新建一个文件来补充它;来自其他文件的背景会显示为锁定。剧本则保存在它所属的模组里。
|
||||
|
||||
## 出问题了怎么办
|
||||
|
||||
1. **找不到锤子按钮。** 这个游戏没带工具;在它的集合里加上 Developer Tools 工具集,或者用 `--with-mods=editor_tools` 启动。
|
||||
2. **新剧本不播放。** 它的头部写的是另一个场景,或者这个场景里有别的剧本先被选中了(比较它们的 `priority`)。
|
||||
3. **「保存到」里没有模组。** 只有安装成文件夹的模组才能写入。
|
||||
@@ -1,5 +1,5 @@
|
||||
mod_editor_tools_name = Editor Tools
|
||||
mod_editor_tools_desc = Developer toolbox: scenario graph editor, map editor with zones, scene builder with inspector, interactive and light editors, and the mod catalog export window.
|
||||
mod_editor_tools_desc = The author's windows over a running game: scene, scenario, map, interactive and light editors and a Godot scene builder. What they save are ordinary mod files the game applies at once.
|
||||
|
||||
tools/common/save = Save
|
||||
tools/common/save_tip = Save the file (Ctrl+S)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
mod_editor_tools_name = Herramientas de edición
|
||||
mod_editor_tools_desc = Caja de herramientas del desarrollador: editor de grafos de escenarios, editor de mapas con zonas, constructor de escenas con inspector, editores de interactivos y de luces, y la ventana de exportación al catálogo de mods.
|
||||
mod_editor_tools_desc = Ventanas de autor sobre el juego en marcha: editores de escenas, escenarios, mapa, interactivos y luces, y un constructor de escenas de Godot. Todo lo que guardan son archivos de mod normales que el juego aplica al instante.
|
||||
|
||||
tools/common/save = Guardar
|
||||
tools/common/save_tip = Guardar el archivo (Ctrl+S)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
mod_editor_tools_name = エディターツール
|
||||
mod_editor_tools_desc = 開発者向けツールボックス:シナリオのグラフエディター、ゾーン付きのマップエディター、インスペクター付きのシーンビルダー、インタラクティブとライトのエディター、MOD カタログの書き出しウィンドウ。
|
||||
mod_editor_tools_desc = 実行中のゲームの上に開くオーサリング用ウィンドウ:シーン、シナリオ、マップ、インタラクティブ、ライトの各エディターと Godot シーンビルダー。保存内容は普通の MOD ファイルで、ゲームはすぐに反映します。
|
||||
|
||||
tools/common/save = 保存
|
||||
tools/common/save_tip = ファイルを保存(Ctrl+S)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
mod_editor_tools_name = 에디터 도구
|
||||
mod_editor_tools_desc = 개발자 도구 상자: 시나리오 그래프 에디터, 구역이 있는 맵 에디터, 인스펙터가 있는 장면 빌더, 상호작용과 조명 에디터, 모드 카탈로그 내보내기 창.
|
||||
mod_editor_tools_desc = 실행 중인 게임 위에 열리는 창작용 창: 장면, 시나리오, 맵, 상호작용, 조명 에디터와 Godot 장면 빌더. 저장하는 것은 모두 일반 모드 파일이며 게임이 즉시 적용합니다.
|
||||
|
||||
tools/common/save = 저장
|
||||
tools/common/save_tip = 파일 저장 (Ctrl+S)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
mod_editor_tools_name = Редакторы
|
||||
mod_editor_tools_desc = Инструменты разработчика: редактор сценариев (граф), редактор карты с зонами, конструктор сцен с инспектором, редакторы интерактива и света, экспорт каталога модов.
|
||||
mod_editor_tools_desc = Авторские окна поверх запущенной игры: редакторы сцен, сценариев, карты, интерактива и света, а также конструктор сцен Godot. Всё, что они сохраняют, — обычные файлы модов, которые игра подхватывает сразу.
|
||||
|
||||
tools/common/save = Сохранить
|
||||
tools/common/save_tip = Сохранить файл (Ctrl+S)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
mod_editor_tools_name = Công cụ chỉnh sửa
|
||||
mod_editor_tools_desc = Hộp công cụ cho nhà phát triển: trình sửa đồ thị kịch bản, trình sửa bản đồ có vùng, trình dựng cảnh có thanh thuộc tính, trình sửa tương tác và ánh sáng, và cửa sổ xuất danh mục mod.
|
||||
mod_editor_tools_desc = Các cửa sổ tác giả mở trên trò chơi đang chạy: trình sửa cảnh, kịch bản, bản đồ, tương tác và ánh sáng, cùng trình dựng cảnh Godot. Mọi thứ chúng lưu là tệp mod bình thường và game áp dụng ngay lập tức.
|
||||
|
||||
tools/common/save = Lưu
|
||||
tools/common/save_tip = Lưu tệp (Ctrl+S)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
mod_editor_tools_name = 编辑工具
|
||||
mod_editor_tools_desc = 开发者工具箱:剧本图编辑器、带区域的地图编辑器、带检查器的场景构建器、交互物和光照编辑器,以及模组目录导出窗口。
|
||||
mod_editor_tools_desc = 运行中的游戏之上的创作窗口:场景、剧本、地图、交互物和光照编辑器,以及 Godot 场景构建器。保存的都是普通模组文件,游戏会立即生效。
|
||||
|
||||
tools/common/save = 保存
|
||||
tools/common/save_tip = 保存文件(Ctrl+S)
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
"name": "Editor Tools",
|
||||
"version": "1.0.0",
|
||||
"author": "ct",
|
||||
"description": "Developer toolbox of ToolBox windows: scenario graph editor, scene editor (create and change the places of a novel: backgrounds, ambient sound, default scenario, the scene's scenarios), map editor with zones, scene builder with inspector, interactive and light editors, the base of the data editors (items, characters: a searchable list and a form over JSON entities with texts in every language of the mod) and the mod catalog export window.",
|
||||
"description": "The author's windows over a running game: scene, scenario, map, interactive and light editors and a Godot scene builder. What they save are ordinary mod files the game applies at once.",
|
||||
"category": "tools, editor",
|
||||
"sources": [
|
||||
"src/**/*.cs"
|
||||
|
||||
@@ -119,12 +119,13 @@ namespace Cthangover.Tools.Common
|
||||
/// <summary>Monospace font for IDs, numbers and code (style guide <c>--ct-mono</c>).</summary>
|
||||
public static Font Mono() => ToolWindow.GetMonospaceFont();
|
||||
|
||||
/// <summary>Code editor preset: monospace, line numbers, current-line highlight, no wrap.</summary>
|
||||
/// <summary>Code editor preset: monospace, line numbers, JSON highlighting and no wrap; scenario/scene callers select their syntax.</summary>
|
||||
public static CodeEdit Code(bool editable = true)
|
||||
{
|
||||
var edit = new CodeEdit
|
||||
{
|
||||
Editable = editable,
|
||||
SyntaxHighlighter = SourceSyntax.CreateJsonHighlighter(),
|
||||
GuttersDrawLineNumbers = true,
|
||||
HighlightCurrentLine = true,
|
||||
WrapMode = TextEdit.LineWrappingMode.None,
|
||||
|
||||
@@ -201,7 +201,7 @@ namespace Cthangover.Tools.EntityEditor
|
||||
|
||||
private void BuildSchemaFields()
|
||||
{
|
||||
var described = SchemaCatalog.Current.FieldsOf(kind)
|
||||
var described = Cthangover.Mods.Schemas.SchemaCatalog.Current.FieldsOf(kind)
|
||||
.Where(f => !string.Equals(f.Key, "Id", StringComparison.OrdinalIgnoreCase) && !fields.Any(e => string.Equals(e.Key, f.Key, StringComparison.OrdinalIgnoreCase)))
|
||||
.ToList();
|
||||
if (described.Count == 0)
|
||||
|
||||
@@ -110,6 +110,7 @@ namespace Cthangover.Core.UI.Tool.LightEditor
|
||||
canvasPanel.AddChild(_canvas);
|
||||
|
||||
_lineEdit = ToolUi.Code(editable: false);
|
||||
_lineEdit.SyntaxHighlighter = ScenarioSyntaxService.CreateHighlighter();
|
||||
_lineEdit.CustomMinimumSize = new Vector2(0, 70);
|
||||
_lineEdit.WrapMode = TextEdit.LineWrappingMode.Boundary;
|
||||
_lineEdit.Visible = false;
|
||||
|
||||
@@ -249,6 +249,7 @@ namespace Cthangover.Core.UI.Tool.SceneBuilder
|
||||
_sideTabs.SetTabTitle(1, ToolUi.Tr("tools/scene_builder/tab_tscn"));
|
||||
|
||||
_tscnEditor = ToolUi.Code();
|
||||
_tscnEditor.SyntaxHighlighter = SourceSyntax.CreateTscnHighlighter();
|
||||
_tscnEditor.TextChanged += OnTscnTextChanged;
|
||||
tscnTab.AddChild(_tscnEditor);
|
||||
tscnTab.AddChild(ToolUi.Hint(ToolUi.Tr("tools/scene_builder/tscn_hint")));
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
namespace Cthangover.Tools.Schemas
|
||||
{
|
||||
using Cthangover.Mods.Schemas;
|
||||
using SchemaFieldDefinition = Cthangover.Mods.Schemas.FieldSchema;
|
||||
using SchemaJsonValues = Cthangover.Mods.Schemas.SchemaJson;
|
||||
using System.Text.Json.Nodes;
|
||||
|
||||
/// <summary>One field's editor in the data editor form: shows the field's JSON and gives it back edited.</summary>
|
||||
public interface ISchemaFieldEditor
|
||||
{
|
||||
/// <summary>The described field.</summary>
|
||||
FieldSchema Field { get; }
|
||||
SchemaFieldDefinition Field { get; }
|
||||
|
||||
/// <summary>Shows <paramref name="node"/> (null: the field is absent).</summary>
|
||||
void Load(JsonNode node);
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
namespace Cthangover.Tools.Schemas
|
||||
{
|
||||
using Cthangover.Mods.Schemas;
|
||||
using SchemaFieldDefinition = Cthangover.Mods.Schemas.FieldSchema;
|
||||
using SchemaJsonValues = Cthangover.Mods.Schemas.SchemaJson;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
@@ -12,7 +14,7 @@ namespace Cthangover.Tools.Schemas
|
||||
using Godot;
|
||||
|
||||
/// <summary>
|
||||
/// Edits a <c>list</c> field — an array of objects described by <see cref="FieldSchema.Of"/>
|
||||
/// Edits a <c>list</c> field — an array of objects described by <see cref="SchemaFieldDefinition.Of"/>
|
||||
/// (an item's traits, an archetype's learnings, a shop's goods) — as a stack of small
|
||||
/// cards with an add and a remove button, each card a form of the sub-fields.
|
||||
/// <para/>
|
||||
@@ -22,7 +24,7 @@ namespace Cthangover.Tools.Schemas
|
||||
/// </summary>
|
||||
public class ListFieldEditor : ISchemaFieldEditor
|
||||
{
|
||||
private readonly FieldSchema field;
|
||||
private readonly SchemaFieldDefinition field;
|
||||
private readonly Action changed;
|
||||
private readonly VBoxContainer cards;
|
||||
private readonly List<List<SchemaFieldControl>> rows = new();
|
||||
@@ -30,10 +32,10 @@ namespace Cthangover.Tools.Schemas
|
||||
private bool suppress;
|
||||
|
||||
/// <inheritdoc />
|
||||
public FieldSchema Field => field;
|
||||
public SchemaFieldDefinition Field => field;
|
||||
|
||||
/// <summary>Adds the editor for <paramref name="field"/> to <paramref name="parent"/>.</summary>
|
||||
public ListFieldEditor(Container parent, FieldSchema field, Action changed)
|
||||
public ListFieldEditor(Container parent, SchemaFieldDefinition field, Action changed)
|
||||
{
|
||||
this.field = field;
|
||||
this.changed = changed;
|
||||
@@ -87,7 +89,7 @@ namespace Cthangover.Tools.Schemas
|
||||
{
|
||||
var item = new JsonObject();
|
||||
foreach (var control in card.Where(c => c.Value.Length > 0))
|
||||
item[control.Field.Key] = SchemaJson.ToNode(control.Field, control.Value);
|
||||
item[control.Field.Key] = SchemaJsonValues.ToNode(control.Field, control.Value);
|
||||
if (item.Count > 0)
|
||||
array.Add(item);
|
||||
}
|
||||
@@ -126,10 +128,10 @@ namespace Cthangover.Tools.Schemas
|
||||
var column = new VBoxContainer();
|
||||
card.AddChild(column);
|
||||
var controls = new List<SchemaFieldControl>();
|
||||
foreach (var sub in field.Of ?? new List<FieldSchema>())
|
||||
foreach (var sub in field.Of ?? new List<SchemaFieldDefinition>())
|
||||
{
|
||||
var control = new SchemaFieldControl(column, sub, OnChanged);
|
||||
control.Value = SchemaJson.ToText(Find(item, sub.Key));
|
||||
control.Value = SchemaJsonValues.ToText(Find(item, sub.Key));
|
||||
controls.Add(control);
|
||||
}
|
||||
if (!IsValues)
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
namespace Cthangover.Tools.Schemas
|
||||
{
|
||||
using Cthangover.Mods.Schemas;
|
||||
using SchemaFieldDefinition = Cthangover.Mods.Schemas.FieldSchema;
|
||||
using SchemaJsonValues = Cthangover.Mods.Schemas.SchemaJson;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json.Nodes;
|
||||
@@ -18,7 +20,7 @@ namespace Cthangover.Tools.Schemas
|
||||
/// </summary>
|
||||
public class LocaleFieldEditor : ISchemaFieldEditor
|
||||
{
|
||||
private readonly FieldSchema field;
|
||||
private readonly SchemaFieldDefinition field;
|
||||
private readonly Action changed;
|
||||
private readonly LineEdit keyEdit;
|
||||
private readonly VBoxContainer texts;
|
||||
@@ -28,10 +30,10 @@ namespace Cthangover.Tools.Schemas
|
||||
private bool suppress;
|
||||
|
||||
/// <inheritdoc />
|
||||
public FieldSchema Field => field;
|
||||
public SchemaFieldDefinition Field => field;
|
||||
|
||||
/// <summary>Adds the editor for <paramref name="field"/> to <paramref name="parent"/>.</summary>
|
||||
public LocaleFieldEditor(Container parent, FieldSchema field, Action changed)
|
||||
public LocaleFieldEditor(Container parent, SchemaFieldDefinition field, Action changed)
|
||||
{
|
||||
this.field = field;
|
||||
this.changed = changed;
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
namespace Cthangover.Tools.Schemas
|
||||
{
|
||||
using Cthangover.Mods.Schemas;
|
||||
using SchemaFieldDefinition = Cthangover.Mods.Schemas.FieldSchema;
|
||||
using SchemaJsonValues = Cthangover.Mods.Schemas.SchemaJson;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
@@ -11,24 +13,24 @@ namespace Cthangover.Tools.Schemas
|
||||
using Godot;
|
||||
|
||||
/// <summary>
|
||||
/// Edits a <c>map</c> field — an object whose keys are ids of <see cref="FieldSchema.Kind"/>
|
||||
/// Edits a <c>map</c> field — an object whose keys are ids of <see cref="SchemaFieldDefinition.Kind"/>
|
||||
/// and whose values are numbers or formulas (a character's own <c>Stats</c>, an archetype's
|
||||
/// growth): one row per key with a key picker, a value box and a remove button. A number
|
||||
/// is written as a number, anything else as a formula text.
|
||||
/// </summary>
|
||||
public class MapFieldEditor : ISchemaFieldEditor
|
||||
{
|
||||
private readonly FieldSchema field;
|
||||
private readonly SchemaFieldDefinition field;
|
||||
private readonly Action changed;
|
||||
private readonly VBoxContainer lines;
|
||||
private readonly List<(OptionButton Key, List<string> Keys, LineEdit Value, Control Row)> rows = new();
|
||||
private bool suppress;
|
||||
|
||||
/// <inheritdoc />
|
||||
public FieldSchema Field => field;
|
||||
public SchemaFieldDefinition Field => field;
|
||||
|
||||
/// <summary>Adds the editor for <paramref name="field"/> to <paramref name="parent"/>.</summary>
|
||||
public MapFieldEditor(Container parent, FieldSchema field, Action changed)
|
||||
public MapFieldEditor(Container parent, SchemaFieldDefinition field, Action changed)
|
||||
{
|
||||
this.field = field;
|
||||
this.changed = changed;
|
||||
@@ -56,7 +58,7 @@ namespace Cthangover.Tools.Schemas
|
||||
if (node is JsonObject obj)
|
||||
{
|
||||
foreach (var pair in obj)
|
||||
AddRow(pair.Key, SchemaJson.ToText(pair.Value));
|
||||
AddRow(pair.Key, SchemaJsonValues.ToText(pair.Value));
|
||||
}
|
||||
suppress = false;
|
||||
}
|
||||
@@ -69,7 +71,7 @@ namespace Cthangover.Tools.Schemas
|
||||
{
|
||||
var key = row.Key.Selected >= 0 && row.Key.Selected < row.Keys.Count ? row.Keys[row.Key.Selected] : null;
|
||||
if (!string.IsNullOrEmpty(key) && row.Value.Text.Trim().Length > 0)
|
||||
obj[key] = SchemaJson.NumberOrText(row.Value.Text.Trim());
|
||||
obj[key] = SchemaJsonValues.NumberOrText(row.Value.Text.Trim());
|
||||
}
|
||||
return obj.Count == 0 ? null : obj;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
namespace Cthangover.Tools.Schemas
|
||||
{
|
||||
using Cthangover.Mods.Schemas;
|
||||
using SchemaFieldDefinition = Cthangover.Mods.Schemas.FieldSchema;
|
||||
using SchemaJsonValues = Cthangover.Mods.Schemas.SchemaJson;
|
||||
using System;
|
||||
using System.Text.Json.Nodes;
|
||||
using Godot;
|
||||
@@ -11,18 +13,18 @@ namespace Cthangover.Tools.Schemas
|
||||
private readonly SchemaFieldControl control;
|
||||
|
||||
/// <summary>Adds the row for <paramref name="field"/> to <paramref name="parent"/>.</summary>
|
||||
public ScalarFieldEditor(Container parent, FieldSchema field, Action changed)
|
||||
public ScalarFieldEditor(Container parent, SchemaFieldDefinition field, Action changed)
|
||||
{
|
||||
control = new SchemaFieldControl(parent, field, changed);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public FieldSchema Field => control.Field;
|
||||
public SchemaFieldDefinition Field => control.Field;
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Load(JsonNode node) => control.Value = SchemaJson.ToText(node);
|
||||
public void Load(JsonNode node) => control.Value = SchemaJsonValues.ToText(node);
|
||||
|
||||
/// <inheritdoc />
|
||||
public JsonNode Save() => SchemaJson.ToNode(control.Field, control.Value);
|
||||
public JsonNode Save() => SchemaJsonValues.ToNode(control.Field, control.Value);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
namespace Cthangover.Tools.Schemas
|
||||
{
|
||||
using Cthangover.Mods.Schemas;
|
||||
using SchemaFieldDefinition = Cthangover.Mods.Schemas.FieldSchema;
|
||||
using SchemaJsonValues = Cthangover.Mods.Schemas.SchemaJson;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
@@ -10,7 +12,7 @@ namespace Cthangover.Tools.Schemas
|
||||
using Godot;
|
||||
|
||||
/// <summary>
|
||||
/// The form control of one scalar <see cref="FieldSchema"/>, chosen by its type, as a
|
||||
/// The form control of one scalar <see cref="SchemaFieldDefinition"/>, chosen by its type, as a
|
||||
/// "label | editor" row. Everything reads and writes a text value, the way the DSL and
|
||||
/// most JSON fields hold it, so the palette and the data editor window share these rows:
|
||||
/// <list type="bullet">
|
||||
@@ -19,7 +21,8 @@ namespace Cthangover.Tools.Schemas
|
||||
/// the kind (by name), of player/party/characters;</item>
|
||||
/// <item><c>ref_list</c> — a comma list with a drop-down that appends an entity;</item>
|
||||
/// <item><c>picture</c> — a path with the picture grid of the editors;</item>
|
||||
/// <item>anything else — a text box (monospace for formulas, conditions and JSON).</item>
|
||||
/// <item><c>json</c> — a multiline source editor with syntax highlighting;</item>
|
||||
/// <item>anything else — a text box (monospace for formulas and conditions).</item>
|
||||
/// </list>
|
||||
/// A current value the options do not know is kept and shown first, so opening and
|
||||
/// saving never loses data the schema did not foresee.
|
||||
@@ -28,13 +31,14 @@ namespace Cthangover.Tools.Schemas
|
||||
{
|
||||
private readonly Action changed;
|
||||
private readonly LineEdit text;
|
||||
private readonly CodeEdit json;
|
||||
private readonly OptionButton picker;
|
||||
private readonly CheckBox check;
|
||||
private readonly List<string> pickerValues = new();
|
||||
private bool suppress;
|
||||
|
||||
/// <summary>Adds the row for <paramref name="field"/> to <paramref name="parent"/>; <paramref name="changed"/> runs on every edit.</summary>
|
||||
public SchemaFieldControl(Container parent, FieldSchema field, Action changed)
|
||||
public SchemaFieldControl(Container parent, SchemaFieldDefinition field, Action changed)
|
||||
{
|
||||
Field = field;
|
||||
this.changed = changed;
|
||||
@@ -74,10 +78,19 @@ namespace Cthangover.Tools.Schemas
|
||||
}
|
||||
Editor = ToolUi.Field(parent, label, row, tip);
|
||||
break;
|
||||
case "json":
|
||||
json = ToolUi.Code();
|
||||
json.Name = "Text_" + field.Key;
|
||||
json.Text = field.Default ?? string.Empty;
|
||||
json.CustomMinimumSize = new Vector2(0, 90);
|
||||
json.SizeFlagsVertical = Control.SizeFlags.Fill;
|
||||
json.TextChanged += OnJsonChanged;
|
||||
Editor = ToolUi.Field(parent, label, json, tip);
|
||||
break;
|
||||
default:
|
||||
text = ToolUi.Text(field.Default ?? string.Empty, OnTyped);
|
||||
text.Name = "Text_" + field.Key;
|
||||
if (Type is "formula" or "condition" or "json")
|
||||
if (Type is "formula" or "condition")
|
||||
text.AddThemeFontOverride("font", ToolUi.Mono());
|
||||
Editor = ToolUi.Field(parent, label, text, tip);
|
||||
break;
|
||||
@@ -86,7 +99,7 @@ namespace Cthangover.Tools.Schemas
|
||||
}
|
||||
|
||||
/// <summary>The described field.</summary>
|
||||
public FieldSchema Field { get; }
|
||||
public SchemaFieldDefinition Field { get; }
|
||||
|
||||
/// <summary>The editor control (the row's right part).</summary>
|
||||
public Control Editor { get; }
|
||||
@@ -103,6 +116,8 @@ namespace Cthangover.Tools.Schemas
|
||||
return check.ButtonPressed ? "1" : string.Empty;
|
||||
if (text != null)
|
||||
return text.Text.Trim();
|
||||
if (json != null)
|
||||
return json.Text.Trim();
|
||||
return picker != null && picker.Selected >= 0 && picker.Selected < pickerValues.Count ? pickerValues[picker.Selected] : string.Empty;
|
||||
}
|
||||
set
|
||||
@@ -112,6 +127,8 @@ namespace Cthangover.Tools.Schemas
|
||||
check.ButtonPressed = value is "1" or "true" or "True" or "yes";
|
||||
else if (text != null)
|
||||
text.Text = value ?? string.Empty;
|
||||
else if (json != null)
|
||||
json.Text = value ?? string.Empty;
|
||||
else
|
||||
FillPicker(value ?? string.Empty);
|
||||
suppress = false;
|
||||
@@ -155,6 +172,8 @@ namespace Cthangover.Tools.Schemas
|
||||
}
|
||||
}
|
||||
|
||||
private void OnJsonChanged() => OnTyped(json.Text);
|
||||
|
||||
private void OnTyped(string value)
|
||||
{
|
||||
if (!suppress)
|
||||
|
||||
@@ -2,6 +2,8 @@ namespace Cthangover.Tools.Schemas
|
||||
{
|
||||
using System;
|
||||
using Cthangover.Mods.Schemas;
|
||||
using SchemaFieldDefinition = Cthangover.Mods.Schemas.FieldSchema;
|
||||
using SchemaJsonValues = Cthangover.Mods.Schemas.SchemaJson;
|
||||
using Godot;
|
||||
|
||||
/// <summary>
|
||||
@@ -13,7 +15,7 @@ namespace Cthangover.Tools.Schemas
|
||||
public static class SchemaFieldEditors
|
||||
{
|
||||
/// <summary>Adds the editor of <paramref name="field"/> to <paramref name="parent"/>; <paramref name="changed"/> runs on every edit.</summary>
|
||||
public static ISchemaFieldEditor Create(Container parent, FieldSchema field, Action changed)
|
||||
public static ISchemaFieldEditor Create(Container parent, SchemaFieldDefinition field, Action changed)
|
||||
{
|
||||
switch (field.Type?.ToLowerInvariant())
|
||||
{
|
||||
|
||||
@@ -3,6 +3,7 @@ using Cthangover.Mods.Dialog.Scenarios;
|
||||
using Cthangover.Core.Scenarios;
|
||||
using Cthangover.Core.Factories.Impls;
|
||||
using Cthangover.Core.UI.Theming;
|
||||
using Cthangover.Mods.Interface.Theming;
|
||||
using Godot;
|
||||
|
||||
namespace Cthangover.Tools.Services
|
||||
@@ -20,36 +21,12 @@ namespace Cthangover.Tools.Services
|
||||
{
|
||||
/// <summary>
|
||||
/// Builds a <see cref="CodeHighlighter"/> for scenario DSL syntax.
|
||||
/// Comments (lines starting with <c>#</c>) are green, strings are bright
|
||||
/// Comments (lines starting with <c>#</c>) are faint, strings are bright
|
||||
/// gold, command names are blue, and argument keywords (e.g. <c>key</c>,
|
||||
/// <c>wait</c>, <c>quest_id</c>) are amber — all from <see cref="UiTokens"/>.
|
||||
/// </summary>
|
||||
public static CodeHighlighter CreateHighlighter()
|
||||
{
|
||||
var hl = new CodeHighlighter();
|
||||
hl.AddColorRegion("#", null, UiTokens.Success, true);
|
||||
hl.AddColorRegion("\"", "\"", UiTokens.AccentBright, false);
|
||||
hl.NumberColor = UiTokens.Info;
|
||||
hl.SymbolColor = UiTokens.Muted;
|
||||
|
||||
var cmdColor = UiTokens.Info;
|
||||
hl.KeywordColors = new Godot.Collections.Dictionary();
|
||||
|
||||
foreach (var cmd in ScenarioCommandStrategyFactory.GetAllCommandNames())
|
||||
hl.KeywordColors[cmd] = cmdColor;
|
||||
|
||||
foreach (var cmd in new[] {
|
||||
"option", "select"
|
||||
}) hl.KeywordColors[cmd] = cmdColor;
|
||||
|
||||
var argColor = UiTokens.Accent;
|
||||
foreach (var kw in new[] {
|
||||
"key", "first", "second", "hide_color", "wait", "speed", "hidden",
|
||||
"sprites", "loop", "target", "quest_id", "show", "hide", "duration"
|
||||
}) hl.KeywordColors[kw] = argColor;
|
||||
|
||||
return hl;
|
||||
}
|
||||
=> SourceSyntax.CreateScenarioHighlighter(ScenarioCommandStrategyFactory.GetAllCommandNames());
|
||||
|
||||
/// <summary>
|
||||
/// Splits a line into tokens, handling quoted strings (with backslash
|
||||
|
||||
@@ -25,6 +25,8 @@ namespace Cthangover.Tools.Tests.Windows
|
||||
/// <summary>Runs the checks for <paramref name="toolId"/>; <paramref name="check"/> records each result.</summary>
|
||||
public static void Run(string toolId, Window window, Action<bool, string> check)
|
||||
{
|
||||
foreach (var editor in window.FindChildren("*", "", true, false).OfType<CodeEdit>())
|
||||
check(editor.SyntaxHighlighter != null, toolId + ": source field has syntax highlighting");
|
||||
switch (toolId)
|
||||
{
|
||||
case "map_editor":
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
namespace Cthangover.Tools.Tests
|
||||
{
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Nodes;
|
||||
using Cthangover.Core.Mods.Testing;
|
||||
using Cthangover.Mods.Schemas;
|
||||
using Cthangover.Tools.Schemas;
|
||||
using Godot;
|
||||
|
||||
/// <summary>JSON schema fields preserve structured values through their highlighted multiline editor.</summary>
|
||||
public class SchemaFieldControlTests
|
||||
{
|
||||
[ModTest("schema/json_field_roundtrip")]
|
||||
static void JsonFieldRoundtrip(ModTestContext ctx)
|
||||
{
|
||||
var parent = new VBoxContainer();
|
||||
((SceneTree)Engine.GetMainLoop()).Root.AddChild(parent);
|
||||
try
|
||||
{
|
||||
var field = new SchemaFieldControl(parent, new FieldSchema { Key = "Extra", Type = "json" }, null);
|
||||
ModAssert.True(field.Editor is CodeEdit, "JSON field has a multiline code editor");
|
||||
var code = (CodeEdit)field.Editor;
|
||||
ModAssert.True(code.SyntaxHighlighter != null, "JSON field has syntax highlighting");
|
||||
var original = new JsonObject
|
||||
{
|
||||
["text"] = "Unicode text: \u041f\u0440\u0438\u0432\u0435\u0442",
|
||||
["active"] = true,
|
||||
["nested"] = new JsonArray(1, null, 3),
|
||||
};
|
||||
field.Value = JsonSerializer.Serialize(original, new JsonSerializerOptions { WriteIndented = true });
|
||||
var restored = JsonNode.Parse(field.Value);
|
||||
ModAssert.Equal(original["text"].GetValue<string>(), restored["text"].GetValue<string>(), "text survives the field");
|
||||
ModAssert.True(restored["active"].GetValue<bool>(), "boolean survives the field");
|
||||
ModAssert.Equal(3, restored["nested"].AsArray().Count, "array survives the field");
|
||||
ModAssert.True(restored["nested"][1] == null, "null survives the field");
|
||||
code.Text = "{\n \"number\": 42\n}";
|
||||
ModAssert.Equal(42, JsonNode.Parse(field.Value)["number"].GetValue<int>(), "edited JSON is returned by the form");
|
||||
}
|
||||
finally { parent.Free(); }
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user