Split catalog_export out of editor_tools
Code, locale and test suites moved from editor_tools; docs in seven languages with screenshots where the window has something to show; own cover.
This commit is contained in:
commit
2085c2dcc9
36 files changed
+799
No files matched your search
@@ -0,0 +1,30 @@
|
||||
# Line endings: LF everywhere, on every OS, whatever core.autocrlf says.
|
||||
* text=auto eol=lf
|
||||
|
||||
# cmd.exe misreads labels and goto in LF batch files, so they stay CRLF.
|
||||
*.bat text eol=crlf
|
||||
*.cmd text eol=crlf
|
||||
|
||||
# Binaries: never converted, never diffed as text.
|
||||
*.png binary
|
||||
*.jpg binary
|
||||
*.jpeg binary
|
||||
*.webp binary
|
||||
*.svg text
|
||||
*.ogg binary
|
||||
*.wav binary
|
||||
*.mp3 binary
|
||||
*.ttf binary
|
||||
*.otf binary
|
||||
*.woff binary
|
||||
*.woff2 binary
|
||||
*.dll binary
|
||||
*.so binary
|
||||
*.dylib binary
|
||||
*.pdb binary
|
||||
*.exe binary
|
||||
*.zip binary
|
||||
*.pck binary
|
||||
*.moc3 binary
|
||||
*.res binary
|
||||
*.scn binary
|
||||
+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: 101 KiB |
+23
@@ -0,0 +1,23 @@
|
||||
# Catalog Export — publish a mod in a mod catalog
|
||||
|
||||
A mod catalog is a JSON list the mod manager downloads mods from. Catalog Export writes a mod's entry for such a catalog — names and descriptions per language, category, tags, version limits, changelog, download link — and packs the mod into the archive the entry points to, with SHA-256 checksums of the archive and of the installed files.
|
||||
|
||||
## Opening it
|
||||
|
||||
Hammer button on the in-game toolbar → **Export Catalog Entry**.
|
||||
|
||||
## Exporting a mod
|
||||
|
||||

|
||||
|
||||
1. **Select a mod**. The form is filled from its manifest.
|
||||
2. Fill **Download URL** (where the archive will be uploaded; required), **Icon URL**, **Category**, **Tags (comma-separated)**, **Min Game Version**, **Status** and **Changelog**. **Add language** adds a name and a description in another language.
|
||||
3. The preview shows the resulting JSON. **Copy JSON** puts it on the clipboard.
|
||||
4. **Export to File**: for a folder mod, a `.zip` archive and its `.json` entry are written into the mods folder; for a mod that is already a `.zip`, only the `.json` is written next to it. The status line shows the written path.
|
||||
|
||||
Upload the archive to the download URL and add the entry to your catalog; the mod manager then offers the mod for installation.
|
||||
|
||||
## Dependencies
|
||||
|
||||
`tools_base`, `ui_base`. It uses the game's catalog and archive code and does not need the mod manager window.
|
||||
The older `editor_tools` package installs this mod together with the other authoring windows.
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
# Exportar catálogo — publica un mod en un catálogo de mods
|
||||
|
||||
Un catálogo de mods es una lista JSON desde la que el gestor de mods descarga mods. Exportar catálogo escribe la entrada de un mod para ese catálogo (nombres y descripciones por idioma, categoría, etiquetas, versiones, cambios, enlace de descarga) y empaqueta el mod en el archivo al que apunta la entrada, con sumas SHA-256 del archivo y de los archivos instalados.
|
||||
|
||||
## Cómo abrirlo
|
||||
|
||||
Botón del martillo en la barra del juego → **Exportar entrada del catálogo**.
|
||||
|
||||
## Exportar un mod
|
||||
|
||||

|
||||
|
||||
1. **Selecciona un mod**. El formulario se rellena desde su manifiesto.
|
||||
2. Rellena **URL de descarga** (donde se subirá el archivo; obligatoria), **URL del icono**, **Categoría**, **Etiquetas (separadas por comas)**, **Versión mínima del juego**, **Estado** y **Cambios**. **Añadir idioma** añade un nombre y una descripción en otro idioma.
|
||||
3. **JSON resultante** muestra el resultado. **Copiar JSON** lo copia al portapapeles.
|
||||
4. **Exportar a archivo**: para un mod de carpeta se escriben en la carpeta de mods un archivo `.zip` y su entrada `.json`; para un mod que ya es `.zip`, solo se escribe el `.json` a su lado. La línea de estado muestra la ruta escrita.
|
||||
|
||||
Sube el archivo al enlace de descarga y añade la entrada a tu catálogo; el gestor de mods ofrecerá el mod para instalar.
|
||||
|
||||
## Dependencias
|
||||
|
||||
`tools_base`, `ui_base`. Usa el código de catálogos y archivos del propio juego; no necesita la ventana del gestor de mods.
|
||||
El paquete antiguo `editor_tools` instala este mod junto con las demás ventanas de autor.
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
# カタログのエクスポート — MOD を MOD カタログで公開する
|
||||
|
||||
MOD カタログは、MOD マネージャーが MOD をダウンロードする元になる JSON の一覧です。カタログのエクスポートは、そうしたカタログ向けに MOD の項目(言語ごとの名前と説明、カテゴリー、タグ、バージョン、変更履歴、ダウンロードリンク)を書き出し、項目が指すアーカイブに MOD をまとめ、アーカイブとインストールされるファイルの SHA-256 チェックサムを付けます。
|
||||
|
||||
## 開き方
|
||||
|
||||
ゲームのツールバーのハンマーボタン → **カタログ項目を書き出す**。
|
||||
|
||||
## MOD の書き出し
|
||||
|
||||

|
||||
|
||||
1. **MOD を選択**します。フォームはそのマニフェストから埋まります。
|
||||
2. **ダウンロード URL**(アーカイブを置く場所、必須)、**アイコンの URL**、**カテゴリー**、**タグ(カンマ区切り)**、**最低ゲームバージョン**、**状態**、**変更履歴**を入力します。**言語を追加**で別の言語の名前と説明を加えます。
|
||||
3. **できあがる JSON** に結果が表示されます。**JSON をコピー**でクリップボードに入ります。
|
||||
4. **ファイルに書き出す**: フォルダー MOD なら MOD フォルダーに `.zip` アーカイブとその `.json` 項目が書かれます。すでに `.zip` の MOD なら、その横に `.json` だけが書かれます。ステータス行に書き出したパスが出ます。
|
||||
|
||||
アーカイブをダウンロードリンクの場所にアップロードし、項目をカタログに加えると、MOD マネージャーがその MOD をインストール候補として表示します。
|
||||
|
||||
## 依存関係
|
||||
|
||||
`tools_base`、`ui_base`。ゲーム自身のカタログ・アーカイブのコードを使い、MOD マネージャーのウィンドウは不要です。
|
||||
古い `editor_tools` パッケージは、この MOD をほかの作成用ウィンドウと一緒にインストールします。
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
# 카탈로그 내보내기 — 모드를 모드 카탈로그에 공개하기
|
||||
|
||||
모드 카탈로그는 모드 관리자가 모드를 내려받는 JSON 목록입니다. 카탈로그 내보내기는 그런 카탈로그용 모드 항목(언어별 이름과 설명, 분류, 태그, 버전, 변경 기록, 다운로드 링크)을 쓰고, 항목이 가리키는 아카이브로 모드를 묶으며 아카이브와 설치 파일의 SHA-256 체크섬을 붙입니다.
|
||||
|
||||
## 여는 방법
|
||||
|
||||
게임 툴바의 망치 버튼 → **카탈로그 항목 내보내기**.
|
||||
|
||||
## 모드 내보내기
|
||||
|
||||

|
||||
|
||||
1. **모드 선택**. 양식이 모드의 매니페스트로 채워집니다.
|
||||
2. **다운로드 URL**(아카이브를 올릴 곳, 필수), **아이콘 URL**, **분류**, **태그 (쉼표로 구분)**, **최소 게임 버전**, **상태**, **변경 기록**을 채웁니다. **언어 추가**로 다른 언어의 이름과 설명을 더합니다.
|
||||
3. **결과 JSON**에 결과가 보입니다. **JSON 복사**는 클립보드에 넣습니다.
|
||||
4. **파일로 내보내기**: 폴더 모드라면 모드 폴더에 `.zip` 아카이브와 그 `.json` 항목이 쓰이고, 이미 `.zip`인 모드라면 옆에 `.json`만 쓰입니다. 상태 줄에 기록된 경로가 표시됩니다.
|
||||
|
||||
아카이브를 다운로드 링크 위치에 올리고 항목을 카탈로그에 추가하면 모드 관리자가 그 모드를 설치 대상으로 보여 줍니다.
|
||||
|
||||
## 의존성
|
||||
|
||||
`tools_base`, `ui_base`. 게임 자체의 카탈로그·아카이브 코드를 쓰며 모드 관리자 창은 필요 없습니다.
|
||||
예전 `editor_tools` 패키지는 이 모드를 다른 제작 창과 함께 설치합니다.
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
# Экспорт каталога — опубликовать мод в каталоге модов
|
||||
|
||||
Каталог модов — это JSON-список, из которого менеджер модов скачивает моды. Экспорт каталога пишет запись мода для такого каталога (названия и описания на разных языках, категория, теги, версии, список изменений, ссылка на скачивание) и упаковывает мод в архив, на который указывает запись, с контрольными суммами SHA-256 архива и установленных файлов.
|
||||
|
||||
## Как открыть
|
||||
|
||||
Кнопка с молотком на игровом тулбаре → **Экспорт записи каталога**.
|
||||
|
||||
## Экспорт мода
|
||||
|
||||

|
||||
|
||||
1. **Выберите мод**. Форма заполнится из его манифеста.
|
||||
2. Заполните **URL скачивания** (куда будет загружен архив; обязательно), **URL иконки**, **Категорию**, **Теги (через запятую)**, **Мин. версию игры**, **Статус** и **Список изменений**. **Добавить язык** добавляет название и описание на другом языке.
|
||||
3. **Итоговый JSON** показывает результат. **Копировать JSON** кладёт его в буфер обмена.
|
||||
4. **Экспорт в файл**: для мода-папки в папку модов записываются архив `.zip` и его запись `.json`; для мода, который уже является `.zip`, рядом с ним пишется только `.json`. Строка статуса показывает путь записанного файла.
|
||||
|
||||
Загрузите архив по ссылке скачивания и добавьте запись в свой каталог — менеджер модов предложит мод к установке.
|
||||
|
||||
## Зависимости
|
||||
|
||||
`tools_base`, `ui_base`. Используется код каталогов и архивов самой игры; окно менеджера модов не нужно.
|
||||
Старый пакет `editor_tools` ставит этот мод вместе с остальными авторскими окнами.
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
# Xuất danh mục — đăng mod lên một danh mục mod
|
||||
|
||||
Danh mục mod là một danh sách JSON mà trình quản lý mod tải mod từ đó. Xuất danh mục ghi mục của một mod cho danh mục như vậy (tên và mô tả theo ngôn ngữ, thể loại, thẻ, phiên bản, nhật ký thay đổi, liên kết tải) và đóng gói mod thành tệp nén mà mục trỏ tới, kèm tổng kiểm SHA-256 của tệp nén và của các tệp được cài.
|
||||
|
||||
## Cách mở
|
||||
|
||||
Nút búa trên thanh công cụ trong trò chơi → **Xuất mục danh mục**.
|
||||
|
||||
## Xuất một mod
|
||||
|
||||

|
||||
|
||||
1. **Chọn một mod**. Biểu mẫu được điền từ manifest của nó.
|
||||
2. Điền **URL tải xuống** (nơi sẽ tải tệp nén lên; bắt buộc), **URL biểu tượng**, **Thể loại**, **Thẻ (cách nhau bằng dấu phẩy)**, **Phiên bản game tối thiểu**, **Trạng thái** và **Nhật ký thay đổi**. **Thêm ngôn ngữ** thêm tên và mô tả ở ngôn ngữ khác.
|
||||
3. **JSON kết quả** hiện kết quả. **Sao chép JSON** đưa nó vào bộ nhớ tạm.
|
||||
4. **Xuất ra tệp**: với mod dạng thư mục, tệp nén `.zip` và mục `.json` của nó được ghi vào thư mục mod; với mod vốn đã là `.zip`, chỉ ghi `.json` bên cạnh. Dòng trạng thái hiện đường dẫn đã ghi.
|
||||
|
||||
Tải tệp nén lên liên kết tải và thêm mục vào danh mục của bạn; trình quản lý mod sẽ đề xuất cài mod đó.
|
||||
|
||||
## Phụ thuộc
|
||||
|
||||
`tools_base`, `ui_base`. Nó dùng mã danh mục và tệp nén của chính trò chơi, không cần cửa sổ trình quản lý mod.
|
||||
Gói cũ `editor_tools` cài mod này cùng các cửa sổ tác giả khác.
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
# 目录导出 —— 把模组发布到模组目录
|
||||
|
||||
模组目录是一个 JSON 列表,模组管理器从中下载模组。目录导出为这样的目录写出模组条目(各语言的名称和描述、分类、标签、版本、更新日志、下载链接),并把模组打包成条目所指向的压缩包,附带压缩包和安装文件的 SHA-256 校验和。
|
||||
|
||||
## 打开方式
|
||||
|
||||
游戏工具栏上的锤子按钮 → **导出目录条目**。
|
||||
|
||||
## 导出模组
|
||||
|
||||

|
||||
|
||||
1. **选择模组**。表单会根据它的清单自动填写。
|
||||
2. 填写**下载 URL**(压缩包将上传的位置,必填)、**图标 URL**、**分类**、**标签(逗号分隔)**、**最低游戏版本**、**状态**和**更新日志**。**添加语言**会加上另一种语言的名称和描述。
|
||||
3. **生成的 JSON** 显示结果。**复制 JSON** 把它放进剪贴板。
|
||||
4. **导出到文件**:对于文件夹模组,会在模组文件夹中写出 `.zip` 压缩包及其 `.json` 条目;对于本身已是 `.zip` 的模组,只在它旁边写出 `.json`。状态栏显示写出的路径。
|
||||
|
||||
把压缩包上传到下载链接,并把条目加入你的目录;模组管理器就会提供该模组供安装。
|
||||
|
||||
## 依赖
|
||||
|
||||
`tools_base`、`ui_base`。它使用游戏自身的目录和压缩包代码,不需要模组管理器窗口。
|
||||
旧的 `editor_tools` 包会把这个模组和其他创作窗口一起安装。
|
||||
@@ -0,0 +1,5 @@
|
||||
# Catalog export tool — extra keys
|
||||
mods/catalog_select_mod = Select a mod:
|
||||
mods/catalog_add_locale = Add language
|
||||
mods/catalog_locale_name = Name in this language
|
||||
mods/catalog_locale_desc = Description in this language
|
||||
@@ -0,0 +1,5 @@
|
||||
# Catalog export tool — extra keys
|
||||
mods/catalog_select_mod = Selecciona un mod:
|
||||
mods/catalog_add_locale = Añadir idioma
|
||||
mods/catalog_locale_name = Nombre en este idioma
|
||||
mods/catalog_locale_desc = Descripción en este idioma
|
||||
@@ -0,0 +1,5 @@
|
||||
# Catalog export tool — extra keys
|
||||
mods/catalog_select_mod = MOD を選択:
|
||||
mods/catalog_add_locale = 言語を追加
|
||||
mods/catalog_locale_name = この言語での名前
|
||||
mods/catalog_locale_desc = この言語での説明
|
||||
@@ -0,0 +1,5 @@
|
||||
# Catalog export tool — extra keys
|
||||
mods/catalog_select_mod = 모드 선택:
|
||||
mods/catalog_add_locale = 언어 추가
|
||||
mods/catalog_locale_name = 이 언어의 이름
|
||||
mods/catalog_locale_desc = 이 언어의 설명
|
||||
@@ -0,0 +1,5 @@
|
||||
# Catalog export tool — дополнительные ключи
|
||||
mods/catalog_select_mod = Выберите мод:
|
||||
mods/catalog_add_locale = Добавить язык
|
||||
mods/catalog_locale_name = Название на этом языке
|
||||
mods/catalog_locale_desc = Описание на этом языке
|
||||
@@ -0,0 +1,5 @@
|
||||
# Catalog export tool — extra keys
|
||||
mods/catalog_select_mod = Chọn một mod:
|
||||
mods/catalog_add_locale = Thêm ngôn ngữ
|
||||
mods/catalog_locale_name = Tên bằng ngôn ngữ này
|
||||
mods/catalog_locale_desc = Mô tả bằng ngôn ngữ này
|
||||
@@ -0,0 +1,5 @@
|
||||
# Catalog export tool — extra keys
|
||||
mods/catalog_select_mod = 选择模组:
|
||||
mods/catalog_add_locale = 添加语言
|
||||
mods/catalog_locale_name = 此语言的名称
|
||||
mods/catalog_locale_desc = 此语言的描述
|
||||
@@ -0,0 +1,2 @@
|
||||
mod_catalog_export_name = Export Catalog Entry
|
||||
mod_catalog_export_desc = Export Catalog Entry
|
||||
@@ -0,0 +1,2 @@
|
||||
mod_catalog_export_name = Exportar entrada del catálogo
|
||||
mod_catalog_export_desc = Exportar entrada del catálogo
|
||||
@@ -0,0 +1,2 @@
|
||||
mod_catalog_export_name = カタログ項目を書き出す
|
||||
mod_catalog_export_desc = カタログ項目を書き出す
|
||||
@@ -0,0 +1,2 @@
|
||||
mod_catalog_export_name = 카탈로그 항목 내보내기
|
||||
mod_catalog_export_desc = 카탈로그 항목 내보내기
|
||||
@@ -0,0 +1,2 @@
|
||||
mod_catalog_export_name = Экспорт записи каталога
|
||||
mod_catalog_export_desc = Экспорт записи каталога
|
||||
@@ -0,0 +1,14 @@
|
||||
tools/catalog_export/hint = The archive and hashes are computed on export; the JSON is written next to the mod archive
|
||||
tools/catalog_export/mod_info = Mod
|
||||
tools/catalog_export/id = ID
|
||||
tools/catalog_export/name = Name
|
||||
tools/catalog_export/metadata = Catalog
|
||||
tools/catalog_export/locales = Localizations
|
||||
tools/catalog_export/locales_hint = With no rows the English name and description of the manifest are used.
|
||||
tools/catalog_export/remove_locale = Remove language
|
||||
tools/catalog_export/preview = Resulting JSON
|
||||
tools/catalog_export/copied = JSON copied to the clipboard.
|
||||
tools/catalog_export/export_tip = Build the archive, compute hashes and write the catalog entry JSON
|
||||
tools/catalog_export/exported = Exported: {0}
|
||||
tools/catalog_export/export_error = Export error
|
||||
tools/catalog_export/url_required = Set the download URL — a catalog entry is useless without it.
|
||||
@@ -0,0 +1,14 @@
|
||||
tools/catalog_export/hint = El archivo y los hashes se calculan al exportar; el JSON se escribe junto al archivo del mod
|
||||
tools/catalog_export/mod_info = Mod
|
||||
tools/catalog_export/id = ID
|
||||
tools/catalog_export/name = Nombre
|
||||
tools/catalog_export/metadata = Catálogo
|
||||
tools/catalog_export/locales = Localizaciones
|
||||
tools/catalog_export/locales_hint = Sin filas se usan el nombre y la descripción en inglés del manifiesto.
|
||||
tools/catalog_export/remove_locale = Quitar idioma
|
||||
tools/catalog_export/preview = JSON resultante
|
||||
tools/catalog_export/copied = JSON copiado al portapapeles.
|
||||
tools/catalog_export/export_tip = Crear el archivo, calcular los hashes y escribir el JSON de la entrada del catálogo
|
||||
tools/catalog_export/exported = Exportado: {0}
|
||||
tools/catalog_export/export_error = Error al exportar
|
||||
tools/catalog_export/url_required = Indica la URL de descarga: sin ella la entrada del catálogo no sirve.
|
||||
@@ -0,0 +1,14 @@
|
||||
tools/catalog_export/hint = アーカイブとハッシュは書き出し時に計算され、JSON は MOD のアーカイブの隣に書かれます
|
||||
tools/catalog_export/mod_info = MOD
|
||||
tools/catalog_export/id = ID
|
||||
tools/catalog_export/name = 名前
|
||||
tools/catalog_export/metadata = カタログ
|
||||
tools/catalog_export/locales = ローカライズ
|
||||
tools/catalog_export/locales_hint = 行がない場合は、マニフェストの英語の名前と説明が使われます。
|
||||
tools/catalog_export/remove_locale = 言語を削除
|
||||
tools/catalog_export/preview = できあがる JSON
|
||||
tools/catalog_export/copied = JSON をクリップボードにコピーしました。
|
||||
tools/catalog_export/export_tip = アーカイブを作り、ハッシュを計算し、カタログ項目の JSON を書き出す
|
||||
tools/catalog_export/exported = 書き出しました:{0}
|
||||
tools/catalog_export/export_error = 書き出しエラー
|
||||
tools/catalog_export/url_required = ダウンロード URL を設定してください——それがないカタログ項目は役に立ちません。
|
||||
@@ -0,0 +1,14 @@
|
||||
tools/catalog_export/hint = 압축 파일과 해시는 내보낼 때 계산되며, JSON은 모드 압축 파일 옆에 쓰입니다
|
||||
tools/catalog_export/mod_info = 모드
|
||||
tools/catalog_export/id = ID
|
||||
tools/catalog_export/name = 이름
|
||||
tools/catalog_export/metadata = 카탈로그
|
||||
tools/catalog_export/locales = 로컬라이즈
|
||||
tools/catalog_export/locales_hint = 줄이 없으면 매니페스트의 영어 이름과 설명이 쓰입니다.
|
||||
tools/catalog_export/remove_locale = 언어 제거
|
||||
tools/catalog_export/preview = 결과 JSON
|
||||
tools/catalog_export/copied = JSON을 클립보드에 복사했습니다.
|
||||
tools/catalog_export/export_tip = 압축 파일을 만들고 해시를 계산해 카탈로그 항목 JSON을 씁니다
|
||||
tools/catalog_export/exported = 내보냄: {0}
|
||||
tools/catalog_export/export_error = 내보내기 오류
|
||||
tools/catalog_export/url_required = 다운로드 URL을 설정하세요 — 그것 없는 카탈로그 항목은 쓸모가 없습니다.
|
||||
@@ -0,0 +1,14 @@
|
||||
tools/catalog_export/hint = Архив и хэши считаются при экспорте; JSON кладётся рядом с архивом мода
|
||||
tools/catalog_export/mod_info = Мод
|
||||
tools/catalog_export/id = ID
|
||||
tools/catalog_export/name = Название
|
||||
tools/catalog_export/metadata = Каталог
|
||||
tools/catalog_export/locales = Локализации
|
||||
tools/catalog_export/locales_hint = Без строк будет использовано английское название и описание из манифеста.
|
||||
tools/catalog_export/remove_locale = Убрать язык
|
||||
tools/catalog_export/preview = Итоговый JSON
|
||||
tools/catalog_export/copied = JSON скопирован в буфер обмена.
|
||||
tools/catalog_export/export_tip = Собрать архив, посчитать хэши и записать JSON записи каталога
|
||||
tools/catalog_export/exported = Экспортировано: {0}
|
||||
tools/catalog_export/export_error = Ошибка экспорта
|
||||
tools/catalog_export/url_required = Укажите URL скачивания — без него запись каталога бесполезна.
|
||||
@@ -0,0 +1,14 @@
|
||||
tools/catalog_export/hint = Tệp nén và mã băm được tính khi xuất; JSON được ghi cạnh tệp nén của mod
|
||||
tools/catalog_export/mod_info = Mod
|
||||
tools/catalog_export/id = ID
|
||||
tools/catalog_export/name = Tên
|
||||
tools/catalog_export/metadata = Danh mục
|
||||
tools/catalog_export/locales = Bản địa hóa
|
||||
tools/catalog_export/locales_hint = Nếu không có dòng nào thì dùng tên và mô tả tiếng Anh trong manifest.
|
||||
tools/catalog_export/remove_locale = Bỏ ngôn ngữ
|
||||
tools/catalog_export/preview = JSON kết quả
|
||||
tools/catalog_export/copied = Đã sao chép JSON vào bộ nhớ tạm.
|
||||
tools/catalog_export/export_tip = Tạo tệp nén, tính mã băm và ghi JSON của mục danh mục
|
||||
tools/catalog_export/exported = Đã xuất: {0}
|
||||
tools/catalog_export/export_error = Lỗi xuất
|
||||
tools/catalog_export/url_required = Hãy đặt URL tải xuống — thiếu nó thì mục danh mục vô dụng.
|
||||
@@ -0,0 +1,14 @@
|
||||
tools/catalog_export/hint = 归档和哈希在导出时计算;JSON 写在模组归档旁边
|
||||
tools/catalog_export/mod_info = 模组
|
||||
tools/catalog_export/id = ID
|
||||
tools/catalog_export/name = 名称
|
||||
tools/catalog_export/metadata = 目录
|
||||
tools/catalog_export/locales = 本地化
|
||||
tools/catalog_export/locales_hint = 没有任何行时,使用清单中的英文名称和描述。
|
||||
tools/catalog_export/remove_locale = 移除语言
|
||||
tools/catalog_export/preview = 生成的 JSON
|
||||
tools/catalog_export/copied = JSON 已复制到剪贴板。
|
||||
tools/catalog_export/export_tip = 打包归档、计算哈希并写入目录条目的 JSON
|
||||
tools/catalog_export/exported = 已导出:{0}
|
||||
tools/catalog_export/export_error = 导出错误
|
||||
tools/catalog_export/url_required = 请设置下载 URL——没有它的目录条目毫无用处。
|
||||
@@ -0,0 +1,2 @@
|
||||
mod_catalog_export_name = Xuất mục danh mục
|
||||
mod_catalog_export_desc = Xuất mục danh mục
|
||||
@@ -0,0 +1,2 @@
|
||||
mod_catalog_export_name = 导出目录条目
|
||||
mod_catalog_export_desc = 导出目录条目
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"id": "catalog_export",
|
||||
"name": "Catalog Export",
|
||||
"version": "1.0.0",
|
||||
"author": "ct",
|
||||
"description": "Export mod catalog metadata and installable archives.",
|
||||
"category": "tools, editor",
|
||||
"sources": [
|
||||
"src/**/*.cs"
|
||||
],
|
||||
"depends": [
|
||||
"tools_base>=1",
|
||||
"ui_base>=1"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
namespace Cthangover.Core.UI.Tool.CatalogExport
|
||||
{
|
||||
/// <summary>Exposes catalog export in the in-game toolbar's tools list.</summary>
|
||||
public class CatalogExportToolBoxButton : IToolBoxButton
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public string ToolId => "catalog_export";
|
||||
|
||||
/// <inheritdoc />
|
||||
public string IconPath => "";
|
||||
|
||||
/// <inheritdoc />
|
||||
public string LocaleKey => "mods/catalog_title";
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsVisible() => true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
using Cthangover.Core.UI.Tool;
|
||||
using Godot;
|
||||
|
||||
namespace Cthangover.Core.UI.Tool.CatalogExport
|
||||
{
|
||||
/// <summary>
|
||||
/// Registers the catalog export window as a developer tool. Moved here from
|
||||
/// the old mods menu when mod management UI was delegated to the
|
||||
/// <c>mod_manager</c> mod — exporting a catalog entry is an authoring task,
|
||||
/// not part of day-to-day mod management.
|
||||
/// </summary>
|
||||
public class CatalogExportToolProvider : IToolProvider
|
||||
{
|
||||
/// <summary>Unique tool identifier.</summary>
|
||||
public string Id => "catalog_export";
|
||||
|
||||
/// <summary>Translation key for the tool's display name.</summary>
|
||||
public string LocaleKey => "mods/catalog_title";
|
||||
|
||||
/// <summary>Creates the export window instance.</summary>
|
||||
public Window CreateWindow() => new CatalogExportWindow();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,367 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
using Cthangover.Core.Mods;
|
||||
using Cthangover.Core.UI.Theming;
|
||||
using Cthangover.Core.Utils;
|
||||
using Cthangover.Mods.Interface.Theming;
|
||||
using Cthangover.Mods.Interface.Tool;
|
||||
using Cthangover.Tools.Common;
|
||||
using Godot;
|
||||
|
||||
namespace Cthangover.Core.UI.Tool.CatalogExport
|
||||
{
|
||||
/// <summary>
|
||||
/// Developer tool that builds a catalog entry (JSON for the online mod
|
||||
/// catalog) from a locally installed mod's manifest. Ported out of the old
|
||||
/// mods menu so that mod-management UI can live in the <c>mod_manager</c>
|
||||
/// mod while this authoring utility stays a tool.
|
||||
/// <para/>
|
||||
/// Left: the form — read-only manifest data, catalog-only metadata
|
||||
/// (download URL, categories, tags, changelog, status, minimum game
|
||||
/// version, icon URL) and localized names. Right: the live JSON preview.
|
||||
/// Actions: copy the JSON or export it next to the mod's zip via
|
||||
/// <see cref="ModCatalogExporter"/> (archive and hashes are computed there).
|
||||
/// </summary>
|
||||
public partial class CatalogExportWindow : ToolWindow
|
||||
{
|
||||
private static readonly string[] Statuses = { "stable", "beta", "deprecated", "archived" };
|
||||
private static readonly CategoryType[] Categories = Enum.GetValues<CategoryType>();
|
||||
|
||||
private OptionButton _modSelect;
|
||||
private VBoxContainer _formHost;
|
||||
private CodeEdit _previewEdit;
|
||||
|
||||
private ModInfo _modInfo;
|
||||
private ModManifest _manifest;
|
||||
private LineEdit _urlEdit;
|
||||
private readonly List<CheckBox> _categoryChecks = new();
|
||||
private LineEdit _tagsEdit;
|
||||
private TextEdit _changelogEdit;
|
||||
private OptionButton _statusOpt;
|
||||
private LineEdit _minGameVerEdit;
|
||||
private LineEdit _iconUrlEdit;
|
||||
private VBoxContainer _localeContainer;
|
||||
|
||||
public CatalogExportWindow() : base("mods/catalog_title")
|
||||
{
|
||||
Size = new Vector2I(1200, 820);
|
||||
CthangoverTheme.Apply(this);
|
||||
|
||||
var outer = CreateFillContainer();
|
||||
AddChild(outer);
|
||||
|
||||
var toolbar = CreateToolbar();
|
||||
outer.AddChild(toolbar);
|
||||
_modSelect = new OptionButton { CustomMinimumSize = new Vector2(320, 0), TooltipText = ToolUi.Tr("mods/catalog_select_mod") };
|
||||
_modSelect.ItemSelected += OnModSelected;
|
||||
toolbar.AddChild(_modSelect);
|
||||
toolbar.AddChild(UiKit.Spacer());
|
||||
toolbar.AddChild(ToolUi.Button("mods/catalog_copy", OnCopyPressed));
|
||||
toolbar.AddChild(ToolUi.Button("mods/catalog_export_file", OnExportPressed, ButtonKind.Primary, "tools/catalog_export/export_tip"));
|
||||
|
||||
var split = new HSplitContainer
|
||||
{
|
||||
SizeFlagsHorizontal = Control.SizeFlags.ExpandFill,
|
||||
SizeFlagsVertical = Control.SizeFlags.ExpandFill
|
||||
};
|
||||
outer.AddChild(split);
|
||||
|
||||
_formHost = new VBoxContainer();
|
||||
var form = CreateSidebar(_formHost, 520);
|
||||
form.SizeFlagsHorizontal = Control.SizeFlags.ExpandFill;
|
||||
split.AddChild(form);
|
||||
|
||||
var previewColumn = new VBoxContainer
|
||||
{
|
||||
SizeFlagsHorizontal = Control.SizeFlags.ExpandFill,
|
||||
SizeFlagsVertical = Control.SizeFlags.ExpandFill
|
||||
};
|
||||
previewColumn.AddChild(ToolUi.Section("tools/catalog_export/preview"));
|
||||
_previewEdit = ToolUi.Code(editable: false);
|
||||
previewColumn.AddChild(_previewEdit);
|
||||
split.AddChild(previewColumn);
|
||||
|
||||
SetHint(ToolUi.Tr("tools/catalog_export/hint"));
|
||||
PopulateModList();
|
||||
}
|
||||
|
||||
private void PopulateModList()
|
||||
{
|
||||
var ordered = ModRegistry.Instance.GetOrderedModIds(filterDisabled: false);
|
||||
foreach (var id in ordered)
|
||||
{
|
||||
var info = ModRegistry.Instance.GetMod(id);
|
||||
if (info == null)
|
||||
continue;
|
||||
|
||||
_modSelect.AddItem($"{info.DisplayTitle} ({id})");
|
||||
_modSelect.SetItemMetadata(_modSelect.ItemCount - 1, id);
|
||||
}
|
||||
|
||||
if (_modSelect.ItemCount > 0)
|
||||
{
|
||||
_modSelect.Selected = 0;
|
||||
BuildForm(_modSelect.GetItemMetadata(0).AsString());
|
||||
}
|
||||
}
|
||||
|
||||
private void OnModSelected(long index)
|
||||
{
|
||||
BuildForm(_modSelect.GetItemMetadata((int)index).AsString());
|
||||
}
|
||||
|
||||
private void BuildForm(string modId)
|
||||
{
|
||||
foreach (var child in _formHost.GetChildren())
|
||||
child.QueueFree();
|
||||
_categoryChecks.Clear();
|
||||
|
||||
_modInfo = ModRegistry.Instance.GetMod(modId) as ModInfo;
|
||||
_manifest = _modInfo?.Manifest;
|
||||
if (_modInfo == null || _manifest == null)
|
||||
return;
|
||||
|
||||
_formHost.AddChild(ToolUi.Section("tools/catalog_export/mod_info"));
|
||||
AddReadOnly("tools/catalog_export/id", _modInfo.Id);
|
||||
AddReadOnly("tools/catalog_export/name", _modInfo.DisplayTitle);
|
||||
AddReadOnly("mods/version", _modInfo.Version ?? "—");
|
||||
AddReadOnly("mods/author", _modInfo.Author ?? "—");
|
||||
|
||||
_formHost.AddChild(ToolUi.Section("tools/catalog_export/metadata"));
|
||||
_urlEdit = ToolUi.Field(_formHost, "mods/catalog_download_url", ToolUi.Text("https://…/" + modId + ".zip", _ => UpdatePreview()));
|
||||
_statusOpt = ToolUi.Field(_formHost, "mods/catalog_status", new OptionButton());
|
||||
foreach (var status in Statuses)
|
||||
_statusOpt.AddItem(status);
|
||||
_statusOpt.ItemSelected += _ => UpdatePreview();
|
||||
_minGameVerEdit = ToolUi.Field(_formHost, "mods/catalog_min_game_version", ToolUi.Text("1.0.0", _ => UpdatePreview()));
|
||||
_iconUrlEdit = ToolUi.Field(_formHost, "mods/catalog_icon_url", ToolUi.Text("https://…/icon.png", _ => UpdatePreview()));
|
||||
_tagsEdit = ToolUi.Field(_formHost, "mods/catalog_tags", ToolUi.Text("story, ru", _ => UpdatePreview()));
|
||||
|
||||
_formHost.AddChild(ToolUi.Section("mods/catalog_category"));
|
||||
var grid = new GridContainer { Columns = 3 };
|
||||
grid.AddThemeConstantOverride("h_separation", UiTokens.Space5);
|
||||
var preselected = _manifest.Category ?? CategoryType.Other;
|
||||
foreach (var category in Categories)
|
||||
{
|
||||
var check = new CheckBox { Text = GetCategoryDisplayName(category), ButtonPressed = (preselected & category) != 0 };
|
||||
check.Toggled += _ => UpdatePreview();
|
||||
_categoryChecks.Add(check);
|
||||
grid.AddChild(check);
|
||||
}
|
||||
_formHost.AddChild(grid);
|
||||
|
||||
_formHost.AddChild(ToolUi.Section("mods/catalog_changelog"));
|
||||
_changelogEdit = new TextEdit
|
||||
{
|
||||
CustomMinimumSize = new Vector2(0, 80),
|
||||
WrapMode = TextEdit.LineWrappingMode.Boundary,
|
||||
};
|
||||
_changelogEdit.TextChanged += UpdatePreview;
|
||||
_formHost.AddChild(_changelogEdit);
|
||||
|
||||
_formHost.AddChild(ToolUi.Section("tools/catalog_export/locales"));
|
||||
_formHost.AddChild(ToolUi.Hint(ToolUi.Tr("tools/catalog_export/locales_hint")));
|
||||
_localeContainer = new VBoxContainer();
|
||||
_localeContainer.AddThemeConstantOverride("separation", UiTokens.Space1);
|
||||
_formHost.AddChild(_localeContainer);
|
||||
_formHost.AddChild(ToolUi.Button("mods/catalog_add_locale", () => AddLocaleRow(string.Empty, string.Empty, string.Empty)));
|
||||
|
||||
UpdatePreview();
|
||||
SetStatus(string.Empty);
|
||||
}
|
||||
|
||||
private void AddReadOnly(string labelKey, string value)
|
||||
{
|
||||
var label = UiKit.Label(value, UiTokens.FontBody, UiTokens.Body);
|
||||
label.AddThemeFontOverride("font", ToolUi.Mono());
|
||||
ToolUi.Field(_formHost, labelKey, label);
|
||||
}
|
||||
|
||||
private static string GetCategoryDisplayName(CategoryType cat) => cat switch
|
||||
{
|
||||
CategoryType.Story => ToolUi.Tr("mods/category_story"),
|
||||
CategoryType.Characters => ToolUi.Tr("mods/category_characters"),
|
||||
CategoryType.Gameplay => ToolUi.Tr("mods/category_gameplay"),
|
||||
CategoryType.Visual => ToolUi.Tr("mods/category_visual"),
|
||||
CategoryType.Audio => ToolUi.Tr("mods/category_audio"),
|
||||
CategoryType.UI => ToolUi.Tr("mods/category_ui"),
|
||||
CategoryType.Locale => ToolUi.Tr("mods/category_locale"),
|
||||
CategoryType.Library => ToolUi.Tr("mods/category_library"),
|
||||
CategoryType.Engine => ToolUi.Tr("mods/category_engine"),
|
||||
CategoryType.Overhaul => ToolUi.Tr("mods/category_overhaul"),
|
||||
CategoryType.Tools => ToolUi.Tr("mods/category_tools"),
|
||||
CategoryType.Editor => ToolUi.Tr("mods/category_editor"),
|
||||
CategoryType.Debug => ToolUi.Tr("mods/category_debug"),
|
||||
CategoryType.Other => ToolUi.Tr("mods/category_other"),
|
||||
_ => cat.ToString(),
|
||||
};
|
||||
|
||||
private void AddLocaleRow(string lang, string name, string description)
|
||||
{
|
||||
var row = new HBoxContainer();
|
||||
row.AddThemeConstantOverride("separation", UiTokens.Space1);
|
||||
|
||||
var langEdit = new LineEdit { CustomMinimumSize = new Vector2(52, 0), PlaceholderText = "en", MaxLength = 5, Text = lang };
|
||||
row.AddChild(langEdit);
|
||||
var nameEdit = new LineEdit { SizeFlagsHorizontal = Control.SizeFlags.ExpandFill, PlaceholderText = ToolUi.Tr("mods/catalog_locale_name"), Text = name };
|
||||
row.AddChild(nameEdit);
|
||||
var descEdit = new LineEdit { SizeFlagsHorizontal = Control.SizeFlags.ExpandFill, PlaceholderText = ToolUi.Tr("mods/catalog_locale_desc"), Text = description };
|
||||
row.AddChild(descEdit);
|
||||
|
||||
var removeBtn = UiKit.IconButton("✕", ToolUi.Tr("tools/catalog_export/remove_locale"));
|
||||
removeBtn.Pressed += () => RemoveLocaleRow(row);
|
||||
row.AddChild(removeBtn);
|
||||
|
||||
langEdit.TextChanged += _ => UpdatePreview();
|
||||
nameEdit.TextChanged += _ => UpdatePreview();
|
||||
descEdit.TextChanged += _ => UpdatePreview();
|
||||
|
||||
_localeContainer.AddChild(row);
|
||||
UpdatePreview();
|
||||
}
|
||||
|
||||
private void RemoveLocaleRow(HBoxContainer row)
|
||||
{
|
||||
_localeContainer.RemoveChild(row);
|
||||
row.QueueFree();
|
||||
UpdatePreview();
|
||||
}
|
||||
|
||||
private void UpdatePreview()
|
||||
{
|
||||
if (_previewEdit == null || _modInfo == null || _manifest == null || _changelogEdit == null)
|
||||
return;
|
||||
|
||||
var entry = BuildExportEntry();
|
||||
// Hashes are computed by the exporter from the real archive.
|
||||
entry.Downloads[0].ArchiveSha256 = "computed-on-export";
|
||||
entry.Downloads[0].InstallSha256 = "computed-on-export";
|
||||
_previewEdit.Text = JsonSerializer.Serialize(entry, JsonOptionsProvider.WriteIndentedIgnoreNullOptions);
|
||||
}
|
||||
|
||||
private List<CatalogLocaleEntry> CollectLocales()
|
||||
{
|
||||
var list = new List<CatalogLocaleEntry>();
|
||||
foreach (var child in _localeContainer.GetChildren())
|
||||
{
|
||||
if (child is not HBoxContainer row || row.IsQueuedForDeletion() || row.GetChildCount() < 3)
|
||||
continue;
|
||||
|
||||
var lang = ((LineEdit)row.GetChild(0)).Text.Trim();
|
||||
if (lang.Length == 0)
|
||||
continue;
|
||||
|
||||
list.Add(new CatalogLocaleEntry
|
||||
{
|
||||
Lang = lang,
|
||||
Name = NullIfEmpty(((LineEdit)row.GetChild(1)).Text),
|
||||
Description = NullIfEmpty(((LineEdit)row.GetChild(2)).Text),
|
||||
});
|
||||
}
|
||||
|
||||
if (list.Count == 0)
|
||||
list.Add(new CatalogLocaleEntry { Lang = "en", Name = _manifest.Name, Description = _manifest.Description });
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
private CatalogExportEntry BuildExportEntry()
|
||||
{
|
||||
var entry = BuildEntryFromManifest(_manifest);
|
||||
entry.Downloads = new List<CatalogEntryDownload>
|
||||
{
|
||||
new()
|
||||
{
|
||||
Version = entry.Version,
|
||||
Urls = new List<string> { _urlEdit.Text.Trim() },
|
||||
SizeBytes = 0,
|
||||
Changelog = NullIfEmpty(_changelogEdit.Text),
|
||||
},
|
||||
};
|
||||
entry.Category = CollectSelectedCategories();
|
||||
entry.Tags = ParseTags(_tagsEdit.Text);
|
||||
entry.Status = Statuses[Math.Max(0, _statusOpt.Selected)];
|
||||
entry.MinGameVersion = NullIfEmpty(_minGameVerEdit.Text);
|
||||
entry.IconUrl = NullIfEmpty(_iconUrlEdit.Text);
|
||||
entry.Locale = CollectLocales();
|
||||
return entry;
|
||||
}
|
||||
|
||||
private void OnCopyPressed()
|
||||
{
|
||||
DisplayServer.ClipboardSet(_previewEdit.Text);
|
||||
SetStatus(ToolUi.Tr("tools/catalog_export/copied"), ToolStatusKind.Ok);
|
||||
}
|
||||
|
||||
private void OnExportPressed()
|
||||
{
|
||||
if (_modInfo == null)
|
||||
return;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(_urlEdit.Text))
|
||||
{
|
||||
SetStatus(ToolUi.Tr("tools/catalog_export/url_required"), ToolStatusKind.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var entry = BuildExportEntry();
|
||||
var modsRoot = ModRegistry.ModsPath;
|
||||
var isZip = _modInfo.FileProvider.RootPath.EndsWith(".zip", StringComparison.OrdinalIgnoreCase);
|
||||
var path = isZip
|
||||
? ModCatalogExporter.ExportFromZip(_modInfo, entry, modsRoot)
|
||||
: ModCatalogExporter.ExportFromFolder(_modInfo, entry, modsRoot);
|
||||
SetStatus(string.Format(ToolUi.Tr("tools/catalog_export/exported"), path), ToolStatusKind.Ok);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
GameLogger.Log("CATALOG_EXPORT", $"export of '{_modInfo.Id}' failed: {ex.Message}", LogLevel.Error);
|
||||
SetStatus($"{ToolUi.Tr("tools/catalog_export/export_error")}: {ex.Message}", ToolStatusKind.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private static List<string> ParseTags(string text)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(text))
|
||||
return null;
|
||||
return text.Split(',').Select(t => t.Trim()).Where(t => t.Length > 0).ToList();
|
||||
}
|
||||
|
||||
private static string NullIfEmpty(string text)
|
||||
{
|
||||
var trimmed = text?.Trim();
|
||||
return string.IsNullOrEmpty(trimmed) ? null : trimmed;
|
||||
}
|
||||
|
||||
private static CatalogExportEntry BuildEntryFromManifest(ModManifest manifest)
|
||||
{
|
||||
var depends = manifest.Depends?.Select(d => d.ToString()).Where(s => s.Length > 0).ToList();
|
||||
|
||||
return new CatalogExportEntry
|
||||
{
|
||||
Id = manifest.Id,
|
||||
Name = manifest.Name,
|
||||
Author = manifest.Author,
|
||||
Version = manifest.Version,
|
||||
Description = manifest.Description,
|
||||
Category = manifest.Category ?? CategoryType.Other,
|
||||
Depends = depends,
|
||||
ConflictsWith = manifest.ConflictsWith,
|
||||
};
|
||||
}
|
||||
|
||||
private CategoryType CollectSelectedCategories()
|
||||
{
|
||||
var selected = (CategoryType)0;
|
||||
for (var i = 0; i < Categories.Length && i < _categoryChecks.Count; i++)
|
||||
{
|
||||
if (_categoryChecks[i].ButtonPressed)
|
||||
selected |= Categories[i];
|
||||
}
|
||||
return selected != 0 ? selected : CategoryType.Other;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user