Format projektu
Wersjonowany JSON projektu (formatVersion 2), walidacja, migracje, import/eksport z sumą kontrolną FNV-1a.
Po co wersjonowany format#
Projekt gry to dane, nie kod. Format JSON ma formatVersion, łańcuch migracji i walidację — dzięki temu stary projekt otworzy się w nowej wersji silnika (ADR 0002).
Struktura#
{
"formatVersion": 2,
"name": "MyGame",
"game": {
"width": 1280,
"height": 720,
"scaleMode": "fit",
"backgroundColor": "#0f1419"
},
"assets": [
{ "id": "hero", "type": "image", "src": "/assets/hero.png" },
{ "id": "theme", "type": "audio", "src": "/assets/theme.ogg" }
],
"scenes": [
{ "id": "menu", "objects": [] },
{ "id": "game", "objects": [] }
]
}
API#
validateProject(input): ValidationResult
migrateProject(input): { project, migrated, fromVersion }
importProject(text, options?): ImportResult
exportProject(project): string
Walidacja#
import { validateProject } from '@engine'
const result = validateProject(raw)
if (!result.valid) {
for (const error of result.errors) {
console.error(error)
}
}
Walidacja sprawdza typy, wymagane pola, duplikaty id assetów i referencje — błędy są czytelne i wskazują konkretne pole.
Migracje#
import { migrateProject } from '@engine'
const { project, migrated, fromVersion } = migrateProject(oldProject)
if (migrated) {
console.log(`Zmigrowano z wersji ${fromVersion} do 2`)
}
Migracje są addytywne i idempotentne — projekt w aktualnej wersji przechodzi bez zmian.
Import i eksport z sumą kontrolną#
Koperta eksportu zawiera sumę FNV-1a. importProject weryfikuje ją opcjonalnie:
import { exportProject, importProject } from '@engine'
const text = exportProject(project)
const result = importProject(text, { verifyChecksum: true })
if (!result.valid) throw new Error(result.errors.join('\n'))
async function saveToDisk(project: Project) {
const blob = new Blob([exportProject(project)], { type: 'application/json' })
const url = URL.createObjectURL(blob)
const a = document.createElement('a')
a.href = url
a.download = `${project.name}.json`
a.click()
URL.revokeObjectURL(url)
}
async function loadFromDisk(file: File) {
const result = importProject(await file.text(), { verifyChecksum: true })
if (!result.valid) throw new Error(result.errors.join('\n'))
return result.project
}
Wskazówka
Suma kontrolna chroni przed uszkodzeniem pliku (ucięty upload, ręczna edycja), nie przed złośliwą modyfikacją — FNV-1a nie jest funkcją kryptograficzną. Do integralności bezpieczeństwa użyj podpisu po stronie serwera.
Powiązane#
- Zapisy gry — repozytoria i backendy przechowywania.
- Konfiguracja — jak format projektu mapuje się na
EngineConfig.