---
title: 'WarpEngine Batocera Store'
url: 'https://wiki.teletypegames.org/hu/stores/warp-engine-batocera-store'
markdown: 'https://wiki.teletypegames.org/hu/stores/warp-engine-batocera-store.md'
lang: hu
date: '2026-08-15'
description: 'A warp-engine-batocera-store egy WarpEngine-katalógusból húzza le a játékokat egy Batocera-dobozra, EmulationStation-metaadatokkal és borítóképekkel, és saját bejegyzést ad az áruháznak az EmulationStation menüjében. Ez csak a motor: ismeri a WarpEngine API-t, és semmit nem tud egyetlen konkrét ol…'
taxonomy:
  tag:
    - engine
---

# WarpEngine Batocera Store

> A `warp-engine-batocera-store` egy [WarpEngine](https://wiki.teletypegames.org/hu/engines/warp-engine)-katalógusból húzza le a játékokat egy [Batocera](https://batocera.org)-dobozra, EmulationStation-metaadatokkal és borítóképekkel, és saját bejegyzést ad az áruháznak az EmulationStation menüjében. Ez csak a motor: ismeri a WarpEngine API-t, és semmit nem tud egyetlen konkrét oldalról sem. A hoszt, az áruház neve és az, hogy hova kerülnek a játékok, egy külön **áruházrepó** `config.json` fájljából jön. Az a fele, amely nem a Batoceráról szól, a [warpstore](https://wiki.teletypegames.org/hu/engines/warpstore), amelyen a [RetroArch-motorral](https://wiki.teletypegames.org/hu/stores/warp-engine-retroarch-store) osztozik.

```
warpstore                           a közös mag — warpstore.py
        ▲
warp-engine-batocera-store          ez a motor — store.py, install.sh
        ▲
        │ config.json
        │
  ┌─────┴─────┬───────────────┐
  │           │               │
ttg-…       my-…            other-…       áruházrepók
  │           │               │
  ▼           ▼               ▼
teletypegames.org   my.example   other.example
```

A referenciaáruház a [ttg-batocera-store](https://wiki.teletypegames.org/hu/stores/ttg-batocera-store).

**Repó:** <https://git.teletypegames.org/stores/warp-engine-batocera-store>**Katalógusoldal:** [WarpEngine](https://wiki.teletypegames.org/hu/engines/warp-engine)**Közös mag:** [warpstore](https://wiki.teletypegames.org/hu/engines/warpstore)**Testvérmotor:** [RetroArch áruházmotor](https://wiki.teletypegames.org/hu/stores/warp-engine-retroarch-store)**Batocera:** <https://batocera.org>

# Amit kapsz

- **Saját menübejegyzés** — egy körhinta-bejegyzés az áruház nevével, benne platformonként egy mappával. `es_systems_<id>.cfg` overlayként íródik ki; az indítóparancs és az emulátorlista a doboz saját rendszereiről másolódik, tehát semmi nincs az emulátorokból bedrótozva.
- **Oldalfüggetlen** — bármelyik hoszt, amely beilleszti a WarpEngine-t, kaphat áruházat; csak a konfiguráció változik.
- **Dobozonként több áruház** — mindegyiké egy ROM-mappa, egy menübejegyzés és a saját állapota, így az egyik áruház takarítása nem érheti el a másik játékait.
- **A dobozhoz nem nyúl** — a játékok az áruház mappájában élnek, nem a doboz rendszereiben. Ezen kívül semmihez nem lehet hozzányúlni, ezen belül pedig csak az törlődik, amit a `state.json` nyilvántart.
- **Biztonságos az EmulationStation mellett** — az ES-ből indított szinkron a gamelist írását az ES kilépéséig halasztja, és minden újraíráskor átviszi az ES tulajdonában lévő címkéket (kedvencek, játékszámlálók).
- **Nulla függőség** — csak a Python 3 szabványkönyvtára. A Batocera `python3`-at szállít, `pip`-et nem.

# Hogyan működik

```
"<áruház neve>" ▸ "Update <áruház neve>"
        │
        ├─ GET /api/software                        a teljes katalógus
        ├─ a doboz által futtatható platformok      c64 → c64, plus4 → cplus4, tic80 → tic80
        ├─ a legfrissebb nem dev kiadás             amely a megfelelő assetet hordozza
        ├─ GET /api/download?path=<asset>           .prg / .tic az áruház mappájába
        ├─ GET <software.imageUrl>                  borítókép
        ├─ gamelist.xml kiírása                     cím, leírás, szerző, kép
        └─ es_systems_<id>.cfg kiírása              az áruház menübejegyzése
```

---

# Az áruház saját menübejegyzése

Minden, amit az áruház telepít, egyetlen saját mappában él, a `/userdata/roms/<subfolder>` alatt, benne platformonként egy könyvtárral. Az EmulationStation felhasználói konfigurációjában lévő `es_systems_<id>.cfg` platformonként egy ES-rendszert deklarál, mindegyiket ugyanazzal a `<group>` értékkel — az ES pedig a csoportból egyetlen körhinta-bejegyzést csinál, benne rendszerenként egy mappával:

```
fő körhinta:  …  ▸  Teletype Games  ▸  ┌ Commodore 64
                                       ├ TIC-80
                                       ├ Ports
                                       └ Update Teletype Games
```

Semmi nincs az emulátorokból bedrótozva. A motor beolvassa a doboz saját `/usr/share/emulationstation/es_systems.cfg` fájlját, és arról a rendszerről másolja az indítóparancsot, a kiterjesztéseket, a platformot, a témát és az emulátorlistát, amelyiktől kölcsönöz — ez a fájl ehhez az image-hez készült a Batocerától, tehát pontosan azokat az emulátorokat sorolja fel, amelyek a dobozon megvannak. Az egyetlen átírt dolog a `%SYSTEM%`: ezt az ES az indított rendszer nevére cseréli, ami nálunk `ttg-c64` lenne, olyan név, amelyet a configgen sosem hallott. Helyette a doboz saját rendszerneve kerül bele, így a mi játékunk pontosan úgy indul, ahogy a doboz indítaná.

Öt részlet, mind az EmulationStationé, és kettő közülük egy délutánba került egy valódi dobozon:

- **A menübejegyzés deklarált, nem következtetett.** Az ES magától kitalálná a csoportszülőt, de akkor a témamappája a csoport neve lenne, amivel egyetlen téma sem rendelkezik — a `HideUniqueGroups` (alapból bekapcsolva) pedig feloldja azt a csoportot, amelyben egyetlen rendszer van, hacsak nem létezik ilyen nevű rendszer. A deklarált szülő mindkettőt megoldja: visz egy `<theme>` értéket (alapból `ports`, ami minden témában megvan), és a helyén tartja a bejegyzést olyan dobozon is, amelyen csak c64-es játékok vannak.
- **Azt a rendszert, amelynek nincs saját játéka, eldobja**, nem csak elrejti: a `loadSystem` ezt naplózza — `System "..." has no games! Ignoring it.` —, és kihajítja. Tehát a bejegyzés nem lehet üres polc: *maga* a `store/` mappa, és a benne lévő frissítő az a játék, amely életben tartja. Ezért is ül az *Update …* közvetlenül a bejegyzésben, nem egy almappában.
- **A bejegyzés nem lehet a rendszerek feletti könyvtár.** Az ES egy bejárt könyvtárat `<dir>/*` bejegyzéssel jelöl meg a fájl-gyorsítótárában, és a jelölést *azelőtt* teszi be, hogy beolvasná a tartalmat; onnantól minden alatta lévő útvonal, amely maga nincs gyorsítótárazva, azt válaszolja, hogy „nem létezik" (`FileSystemUtil.cpp`, `getCacheEntry`). A rendszerek szálkészletben töltődnek be, tehát egy, a rendszerek felett ülő bejegyzés véletlenszerűen elveszíti ezt a versenyt néhányukra nézve, és az ES eldobja őket ezzel: `System "..." path does not exist !` — minden indításkor másik kettőre, ami pontosan úgy néz ki, mint egy témaprobléma. A `store/` a testvérük, tehát nincs verseny, amit el lehetne veszíteni.
- **Az üres rendszer nem jelenik meg**, így a bejegyzésben soha nincs zsákutca.
- **Egy új rendszerhez ES-újraindítás kell**, amit a motor elvégez az olyan szinkron után, amely hozzáadott egyet.

Ha a dobozon már van olyan rendszer, amelynek a neve megegyezik az áruházazonosítóval — mondjuk egy `nes` nevű áruház esetén —, a bejegyzés `<id>-store` néven jön létre, és a napló ezt közli: az az overlay, amelynek a `<name>` értéke egy meglévő rendszerrel egyezik, *azt a rendszert módosítja*, nem újat ad hozzá.

## A logója

Az EmulationStation a rendszer körhinta-logóját a **témán** keresztül oldja fel (a `SystemData::getProperty("image")` a témától kéri a `system/logo` értéket, a téma pedig a rendszer témamappájából építi fel az útvonalat — a carbon az `art/logos/${system.theme}.png`, majd a `.svg` fájlt próbálja). Felhasználói szintű felülbírálás nincs, tehát egy egyedi rendszer vagy kölcsönvesz egy témamappát, amelyben már van grafika, vagy a fájl oda kerül, ahol a témák keresik. Mindkettő támogatott:

- `menu.logo` nélkül a bejegyzés a `ports` mappát kölcsönzi, ami minden témában megvan, tehát van *egy* ikonja — csak nem az áruházé;
- `menu.logo` esetén (útvonal vagy URL, illetve ezek listája több formátumhoz) a motor minden téma logómappájába telepíti. Ezt a mappát nem a témaelrendezések ismeretéből találja meg, hanem úgy, hogy megkeresi azoknak a rendszereknek a logóit, amelyek minden témában megvannak (`ports`, `snes`, `nes`, …); a fájlt `<menu.theme>.<ext>` néven írja ki — a `menu.theme` alapértéke ekkor az áruházazonosító, így a téma saját fájljaiból semmi nem íródik felül —, és minden útvonalat rögzít a `state.json` fájlban, így az eltávolítás pontosan ezeket veszi vissza, a névütközést pedig jelenti és kihagyja;
- ahová nem ér el, ott a téma az áruház **nevét mutatja szövegként**, ami az EmulationStation saját tartalékmegoldása hiányzó logókép esetén.

Batocera-fintor: a rendszerimage-dzsel szállított témák a `/usr/share` alatt vannak, a Batocera gyökere pedig RAM-overlay — a másolat azonnal megjelenik, de újraindítás után eltűnik. Ezért a motor (4.3.0-tól) egy jelölt blokkot tart a `/boot/postshare.sh`-ban — ez az egyetlen boot-hook, amely az EmulationStation előtt fut —, és az visszamásolja a gyorsítótárazott logót oda, ahonnan hiányzik; a `/boot`-ot csak az írás idejére csatolja írhatóra, a fájl többi részéhez nem nyúl, a `purge` pedig kiveszi a blokkot. A `/userdata/themes` alatti témák amúgy is megtartják.

A régi viselkedéshez — a játékok a doboz saját rendszerein belül, a gamelistjeibe olvasztva — állítsd az `emulationstation.menu.mode` értéket `merge`-re.

---

# Menübejegyzés előtt telepített áruház frissítése

A 4.0-s motorverzió hozza az elrendezésváltást. A frissítés utáni első szinkron leszedi a régi telepítést a dobozról — ROM-ok, borítóképek, port-tartalmak, a mi csomópontjaink a doboz gamelistjeiben, az üres mappák, a Ports-bejegyzés —, majd mindent újra letölt az áruház saját mappájába. A fájlokat szándékosan nem viszi át: a katalógus kicsi, és egy félig átköltöztetett telepítés rosszabb, mint egy kicsit hosszabb szinkron. A `-n` az egészet megmutatja anélkül, hogy bármit végrehajtana.

---

# Egy áruház telepítése

A telepítő paraméterként kapja az áruházat, így bármilyen konfigurációval működik:

```sh
curl -fsSL https://git.teletypegames.org/stores/warp-engine-batocera-store/raw/branch/master/install.sh |
  STORE_CONFIG=https://git.example.org/tools/my-store/raw/branch/master/config.json sh
```

Checkoutból, helyi konfigurációval:

```sh
scp -r warp-engine-batocera-store root@batocera:/tmp/
ssh root@batocera 'STORE_CONFIG=/tmp/my-config.json /tmp/warp-engine-batocera-store/install.sh'
```

Kiolvassa a `store.id` értéket a konfigurációból, a motort és a konfigurációt a `/userdata/system/batocera-store/<id>/` könyvtárba telepíti, kiírja az `<id>-store` indítót, és lefuttatja az első szinkront — ez hozza létre a menübejegyzést. Az EmulationStationnek újra kell indulnia, hogy lássa.

| Környezeti változó | Jelentés |
|---|---|
| `STORE_CONFIG` | **kötelező** — az áruház `config.json` fájljának útvonala vagy URL-je |
| `BATOCERA_STORE_ROOT` | hol élnek az áruházak (alapérték `/userdata/system/batocera-store`) |
| `BATOCERA_PORTS_DIR` | Ports-mappa (alapérték `/userdata/roms/ports`) |
| `BATOCERA_PORT_NAME` | a Ports-bejegyzés neve olyan áruháznak, amely még kér egyet (alapérték: az áruház `name` értéke) |
| `ENGINE_RAW_BASE` | honnan töltse le a `store.py` fájlt |
| `WARPSTORE_RAW_BASE` | honnan töltse le a `warpstore.py` fájlt |
| `WARPSTORE_SRC` | egy helyi `warpstore.py`, amit letöltés helyett telepítsen |

Minden telepítés eldobja az áruház könyvtárában gyorsítótárazott logókat is, így egy áruház, amely logót cserél, az újat juttatja a dobozra; helyi `STORE_CONFIG` esetén a `menu.logo`-ban megnevezett logókat a konfiguráció mellől veszi.

---

# Áruházrepó írása

Három fájl:

```
my-batocera-store/
├── config.json     az áruház: URL, név, almappa, platform-leképezés
├── install.sh      burkoló, amely átadja ezt a konfigurációt a motor telepítőjének
└── README.md
```

Az `install.sh` teljes egészében:

```sh
#!/bin/sh
set -eu
FORGE=https://git.teletypegames.org
ENGINE_REF="${ENGINE_REF:-commit/<engine sha>}"
WARPSTORE_REF="${WARPSTORE_REF:-commit/<warpstore sha>}"
export ENGINE_RAW_BASE="${ENGINE_RAW_BASE:-$FORGE/stores/warp-engine-batocera-store/raw/$ENGINE_REF}"
export WARPSTORE_RAW_BASE="${WARPSTORE_RAW_BASE:-$FORGE/engines/warpstore/raw/$WARPSTORE_REF}"
export STORE_CONFIG="${STORE_CONFIG:-https://git.example.org/tools/my-batocera-store/raw/branch/master/config.json}"
TMP_DIR="$(mktemp -d)"
trap 'rm -rf "$TMP_DIR"' EXIT
curl -fsSL --retry 3 "$ENGINE_RAW_BASE/install.sh" -o "$TMP_DIR/install.sh"
sh "$TMP_DIR/install.sh"
```

Három dolog benne szándékos. A motor és a `warpstore` **rögzített commitról** jön (`raw/commit/<sha>`), amellyel a konfigurációt kipróbáltuk, így egy push egyik `master`-re sem változtatja meg, mit kap egy friss telepítés — motorkiadás után az áruház mindkettőt átírja. A telepítő **fájlba töltődik**, nem a `sh`-ba csövezve, így egy sikertelen letöltés hangosan bukik el. Ez a fájl pedig **egyedül áll egy friss könyvtárban**: a motor telepítője minden mellette talált `store.py`-t és `warpstore.py`-t telepít, és egy puszta `mktemp`-fájlnál ez a `/tmp` lenne. Teljes példa a [TTG-áruház](https://wiki.teletypegames.org/hu/stores/ttg-batocera-store), CI-val, amely a rögzített motorral tölti be a konfigurációját.

Olyan `store.id` és `paths.subfolder` értéket válassz, amit senki más nem használ — ezek tartják távol egymástól az ugyanazon a dobozon lévő két áruházat, és az azonosító adja a menübejegyzés és az `es_systems` fájl nevét.

---

# Használat

**Az eszközön.** *„\\<áruház neve>" ▸ „Update \\<áruház neve>"*. A szkript letölt mindent, ami új, majd újraindítja az EmulationStationt. Az ES által indított szkriptnek nincs konzolja, így a kimenet az áruház könyvtárában lévő `store.log` fájlba megy.

**SSH-n**, a telepítő által kiírt indítón keresztül:

```sh
S=/userdata/system/batocera-store/example-store

$S list                 # kompatibilis katalógusbejegyzések; * telepítve, ^ van frissítés
$S sync                 # minden újdonság letöltése, a gamelistek és a menü frissítése
$S sync blessingofra    # csak egy cím (soha nem takarít)
$S -n sync              # szárazon futtatás
$S remove c64:demo      # eltávolítás (a csupasz név is jó)
$S purge                # minden eltávolítása, amit ez az áruház telepített
$S config               # az érvényes konfiguráció, és hogy hol van a menübejegyzés
```

A globális kapcsolók az alparancs **elé** jönnek: `$S --roms-root /tmp/roms sync`.

---

# Eltávolítás

```sh
ssh root@batocera 'curl -fsSL https://git.teletypegames.org/stores/warp-engine-batocera-store/raw/branch/master/uninstall.sh | sh'
```

Az eltávolítást a motor végzi, nem a shellszkript: előbb `purge`, majd az esetleges Ports-bejegyzés, az indító és az áruház könyvtára. Csak a `state.json` tudja, mely ROM-ok, borítóképek, port-tartalmak, gamelist-bejegyzések és ES-rendszerek voltak a mieink — és ha nem tud végezni (mondjuk egy felcsatolatlan ROM-gyökér miatt), semmi máshoz nem nyúl, így soha nem maradsz úgy, hogy a fájlok megvannak, de a motor nincs, amely ismerné őket.

| Környezeti változó | Jelentés |
|---|---|
| `STORE_ID` | melyik áruházat távolítsa el; csak több telepített áruház esetén kell |
| `STORE_CONFIG` | a `STORE_ID` alternatívája — az azonosítót a konfigurációból olvassa ki |
| `DRY_RUN` | `1` esetén kiírja, mi tűnne el, és semmit nem távolít el |
| `KEEP_HOME` | `1` esetén megtartja az áruház könyvtárát (állapot, katalógus-gyorsítótár, napló) az újratelepítéshez |
| `BATOCERA_STORE_ROOT`, `BATOCERA_PORTS_DIR`, `BATOCERA_PORT_NAME` | ugyanaz, mint a telepítőnél |

Az áruház saját elrendezésében az eltávolítás teljes: a ROM-mappa, a gamelistek és az `es_systems_<id>.cfg` mind eltűnnek, a doboz pedig olyan, mint volt. `merge` módban ezek szándékosan maradnak:

- **a felhasználó által az áruház almappájába tett ROM-ok** — egy könyvtár csak akkor tűnik el, ha üres, tehát egyetlen kósza fájl megtartja. A `ports/.data` szintén marad: egy másik áruház is tarthat ott tartalmat.
- **a gamelistek** — ezek a dobozéi. A mi `<game>` és `<folder>` csomópontjaink eltűnnek; a felhasználó saját játékai, játékszámlálói és kedvencei érintetlenül visszaíródnak. Az általunk *létrehozott*, üresen maradt gamelist törlődik, hiszen soha nem volt az övé.
- **a `gamelist.xml.<áruházazonosító>-backup` fájlok**, a futás végén kilistázva: a gamelistek abban az állapotban, ahogy először találtuk őket.

A szárazon futtatás fájlokat listáz, könyvtártörléseket nem: nem tudhatja, mely könyvtárak maradnak üresen.

Ha **minden** áruházat le akarsz szedni egy gépről — mindkét motort, a közös magot, az indítókat —, használd a [warpstore](https://wiki.teletypegames.org/hu/engines/warpstore) szkriptjét:

```sh
curl -fsSL https://git.teletypegames.org/engines/warpstore/raw/branch/master/uninstall.sh | sh
```

---

# Hova kerülnek a dolgok

```
/userdata/system/batocera-store/
├── example-store                       az alábbi áruház indítója
└── example/
    ├── store.py, warpstore.py          a motor és a közös magja
    ├── config.json                     az áruház, amely kiválasztotta
    └── state.json, catalog.json, store.log

/userdata/system/configs/emulationstation/es_systems_example.cfg   a menübejegyzés
<minden téma>/<a logómappája>/example.png                           menu.logo esetén: a bejegyzés logója
/boot/postshare.sh                      jelölt blokk, amely bootkor visszateszi a /usr-témák logóját

/userdata/roms/example/                 az áruház saját ROM-mappája
├── c64/
│   ├── blessingofra-2.2.0.prg, rabbit-1.0.0.prg, …
│   ├── images/blessingofra.png, …
│   └── gamelist.xml
├── ports/
│   ├── <name>.sh, images/<name>.png, .data/<name>/
│   └── gamelist.xml
└── store/                             maga a menübejegyzés
    ├── update.sh                       a szinkron, ahogy a menü indítja
    └── gamelist.xml
```

A doboz saját rendszermappáihoz egyáltalán nem nyúl. `merge` módban — a régi viselkedés, amely továbbra is elérhető — ugyanez a tartalom a `<roms_root>/<system>/<subfolder>/` alá kerül, az elsőként megérintett `gamelist.xml` fájlról `gamelist.xml.<áruházazonosító>-backup` másolat készül, és minden összeolvasztás csak az adott áruház almappája alatti csomópontokat írja újra, így két áruház osztozhat egy gamelisten.

---

# Konfiguráció

`config.json` az áruház könyvtárában; a sablon a repóban lévő `config.example.json`.

| Kulcs | Alapérték | Jelentés |
|---|---|---|
| `store.id` | `warp` | slug: ez adja az áruház könyvtárának nevét, a naplóelőtagot és a gamelist-mentés nevét |
| `store.name` | `WarpEngine Store` | a menübejegyzés megjelenített neve |
| `store.base_url` | — | a WarpEngine-hoszt |
| `store.api.catalog` | `/api/software` | katalógusvégpont, ha a motor máshova van beillesztve |
| `store.api.download` | `/api/download` | letöltési végpont |
| `paths.roms_root` | `/userdata/roms` | hol élnek a rendszerek |
| `paths.subfolder` | `warp` | az áruház saját mappája a `roms_root` alatt (`merge` módban: az almappája minden rendszeren belül) |
| `emulationstation.menu.mode` | `system` | `system`: az áruház saját menübejegyzést kap. `merge`: a doboz saját rendszereibe telepít |
| `emulationstation.menu.name` | `null` → `store.name` | a menübejegyzés felirata |
| `emulationstation.menu.theme` | `null` → logóval az áruházazonosító, anélkül a `ports` | az a témamappa, ahonnan a bejegyzés a logóját veszi, és a logófájl neve |
| `emulationstation.menu.logo` | `null` | a bejegyzés saját logója: útvonal vagy URL, illetve ezek listája; minden téma logómappájába települ |
| `emulationstation.menu.updater` | `true` | egy *Update …* bejegyzés a menüben, amely lefuttatja a szinkront |
| `emulationstation.menu.labels` | `{}` | rendszerenkénti mappafeliratok; a fel nem sorolt rendszer megtartja a doboz saját `<fullname>` értékét |
| `emulationstation.ports_entry` | `null` → `false` `system` módban | írjon ki egy Ports-bejegyzést is, amely a szinkront futtatja |
| `emulationstation.folder_name` | `WarpEngine Store` | csak `merge` módban: a mappánk megjelenített neve a doboz gamelistjében |
| `emulationstation.restart` | `true` | változás után indítsa újra az EmulationStationt |
| `emulationstation.config_dir` | `null` → `/userdata/system/configs/emulationstation` | hol tartja az ES a felhasználói konfigurációját |
| `catalog.statuses` | `["released", "archived"]` | mely katalógus-`status` értékeket telepítse |
| `catalog.owner_id` | `null` | szűkítés egyetlen kiadóra (`/api/software?owner_id=`) |
| `catalog.only` / `catalog.exclude` | `[]` | szoftvernév-engedélyező / -tiltó lista |
| `platforms` | c64, plus4, tic80 | platform → rendszer, asset típusa, kiterjesztés, engedélyezve |
| `behavior.prune` | `true` | távolítsa el azokat a játékokat, amelyek kikerültek a katalógusból vagy a szűrőkből |
| `behavior.timeout` | `30` | HTTP-időkorlát másodpercben |
| `behavior.insecure` | `false` | TLS-ellenőrzés kihagyása (saját üzemeltetésű tesztpéldányokhoz) |

## Platform-leképezés

Egy platform akkor telepíthető, ha a kiadási assetje olyan fájl, amelyet a dobozon meglévő valamelyik rendszer közvetlenül el tud indítani — a „meglévő" itt azt jelenti, hogy szerepel a doboz saját `es_systems.cfg` fájljában, tehát ebbe az image-be beleépült az emulátor (ROM-mappa attól még lehet ott, hogy nincs mögötte semmi):

| Katalógusplatform | Asset típusa | Batocera-rendszer | Kiterjesztés |
|---|---|---|---|
| [`c64`](https://wiki.teletypegames.org/hu/platforms/c64) | `cartridge` | `c64` (VICE) | `.prg` |
| [`plus4`](https://wiki.teletypegames.org/hu/platforms/plus4) | `cartridge` | `cplus4` (VICE `xplus4`) | `.prg` |
| [`tic80`](https://wiki.teletypegames.org/hu/platforms/tic80) | `cartridge` | `tic80` | `.tic` |

A többi (`ebitengine`, `love`, `godot`, `bevy`, `phaser`) `html` fájlt és operációs rendszerenkénti zipeket szállít, nem olyan ROM-ot, amit egy rendszer elindít, ezért alapból nincsenek leképezve. Egy hozzáadása konfigurációs szerkesztés:

```json
"platforms": { "godot": { "system": "godot", "kind": "linux_x64", "ext": ".zip", "enabled": true } }
```

---

# Hogyan marad biztonságos a szinkron az EmulationStation mellett

Az EmulationStation memóriában tartja a gamelisteket, és kilépéskor visszaírja őket, tehát egy futása közben végzett összeolvasztás felülíródhat. A menüből indítva (`sync-from-es`) a motor előbb letölt, majd az összeolvasztást egy leválasztott `apply-gamelists --wait-pid <es-pid>` gyerekfolyamatra bízza, amely megvárja a régi ES-folyamat halálát. SSH-ról, futó ES nélkül az összeolvasztás soron belül történik. Az `es_systems` overlaynek mindebből semmi nem kell: az ES beolvassa, és soha nem írja.

Az újrafuttatás idempotens: a meglévő fájlokhoz nem nyúl, egy kiadásemelés (`1.1` → `2.0.0`) törli a régi assetet, mielőtt lehúzná az újat, és azt a gamelist- vagy `es_systems`-fájlt, amelynek a tartalma nem változott, egyáltalán nem írja újra. A letöltések a `GET /api/download` végponton mennek, nem a `/file/` útvonalon, `warpstore/<verzió> (<áruház id>)` user agenttel; hogy beleszámítanak-e a katalógusstatisztikába, az a host döntése — a teletypegames.org szándékosan kihagyja a `warpstore/*`-ot (`ignored_user_agents`).

A szinkron megszakad, ha nem tudja megállapítani, mely rendszerek vannak a dobozon — egy olvashatatlan `es_systems.cfg` egy felcsatolatlan `/userdata/roms` mögött különben úgy nézne ki, mintha „már semmi nem kompatibilis", és letakarítana minden telepített játékot.

# Állapot

A `state.json` rögzíti, mit telepített az áruház, `<rendszer>:<név>` kulccsal, így ugyanaz a szoftvernév két rendszeren két külön bejegyzés marad. A `layout` megmondja, melyik könyvtárelrendezéshez tartoznak ezek a rekordok: ebből tudja az áruház saját mappájára való átállás, hogy egyszer kell lefutnia — eltávolítja a régi telepítést, a szinkron pedig újra letölti az új helyre. A szétválasztás előtti `ttg-store`-ból származó `version: 1` fájlt az első futáskor migrálja.

'; var prevLevel = 2; for (var i = 0; i < headings.length; i++) { var h = headings\[i\]; var text = h.textContent.trim(); var slug = text.toLowerCase() .replace(/\[áàâä\]/g,'a').replace(/\[éèêë\]/g,'e').replace(/\[íìîï\]/g,'i') .replace(/\[óòôöő\]/g,'o').replace(/\[úùûüű\]/g,'u') .replace(/\[^a-z0-9\]+/g, '-').replace(/^-|-$/g, ''); if (!slug) slug = 'heading-' + i; if (used\[slug\]) { slug += '-' + i; } used\[slug\] = true; h.id = slug; var level = parseInt(h.tagName.charAt(1)); var cls = level > 2 ? ' class="toc-child"' : ''; html += '- [' + text + '](#'%20+%20slug%20+%20')
'; } html += '
'; toc.innerHTML = html; // Scroll-spy: highlight current heading var links = toc.querySelectorAll('a'); var ids = \[\]; for (var j = 0; j < links.length; j++) ids.push(links\[j\].getAttribute('href').slice(1)); function updateActive() { var current = ''; for (var k = 0; k < ids.length; k++) { var el = document.getElementById(ids\[k\]); if (el && el.getBoundingClientRect().top <= 80) current = ids\[k\]; } for (var m = 0; m < links.length; m++) { links\[m\].parentNode.classList.toggle('active', links\[m\].getAttribute('href') === '#' + current); } } window.addEventListener('scroll', updateActive, { passive: true }); updateActive(); })();

---

## Navigation

- Parent: [Áruházak](https://wiki.teletypegames.org/hu/stores.md)
- Previous: [TTG RetroArch Store](https://wiki.teletypegames.org/hu/stores/ttg-retroarch-store.md)
- Next: [WarpEngine Client](https://wiki.teletypegames.org/hu/stores/warp-engine-client.md)
