# Katalog tatuaży

Katalog łączy tatuaże z CXG Base oraz z zainstalowanych pakietów. Zewnętrzne pakiety są opcjonalne: możesz nie włączać żadnego, włączyć jeden lub kilka. Jeśli pakietu brakuje albo jest zatrzymany, jego tatuaże znikają ze sklepu, a katalog CXG Base pozostaje dostępny.

Zobacz także: [Wprowadzenie](https://docs.cxgstudios.com/docs/pl/01-cxg-tattoos/01-introduccion.md), [Instalacja](https://docs.cxgstudios.com/docs/pl/01-cxg-tattoos/02-instalacion.md), [Konfiguracja](https://docs.cxgstudios.com/docs/pl/01-cxg-tattoos/03-configuracion.md), [Integracje](https://docs.cxgstudios.com/docs/pl/01-cxg-tattoos/05-integraciones.md) i [Interfejs](https://docs.cxgstudios.com/docs/pl/01-cxg-tattoos/06-interfaz.md).

## Opcjonalne pakiety

Początkowa konfiguracja zawiera następujące opcjonalne źródła:

| ID | Zasób | Plik katalogu |
| --- | --- | --- |
| `xgc-classic` | `xgc_TattooClasic` | `tatoo_clasic_full_packconfigdump.json` |
| `xgc-gangs` | `xgc_TattooGangs` | `gangs_full_packconfigdump.json` |
| `xgc-japanese-mafia` | `xgc_TattooJapaneseMafia` | `japanese_mafia_full_packconfigdump.json` |
| `xgc-police` | `xgc_TattooPolice` | `police_full_packconfigdump.json` |
| `xgc-world-countries` | `xgc_TattooWorldCountries` | `world_country_full_packconfigdump.json` |
| `cxg-blackout` | `CXGtatoo_balckout` | `blackout_full_packconfigdump.json` |

Instaluj wyłącznie posiadane pakiety i uruchamiaj je przed `cxg-tattoos`. Zachowaj nazwy zasobów i ścieżki zgodne z tymi na serwerze, uwzględniając wielkość liter. Aby tymczasowo ukryć źródło, ustaw jego `enabled` na `false`; aby je ponownie pokazać, ustaw `true` i upewnij się, że zasób działa.

CXG Base korzysta z `shared/tattoos.json` wewnątrz zasobu. Źródło `native-game` pobiera wzory z natywnych tatuaży gry i jest domyślnie wyłączone. Aby z niego korzystać, skonfiguruj też źródła walidacji w `native.serverMetas`, podając rzeczywiste zasoby i pliki serwera. Przykładowy wpis wskazuje `tatto` i `shop_tattoo.meta`; nie zakłada, że taki zasób jest zainstalowany. Samo ustawienie `enabled` nie gwarantuje, że te wzory będzie można kupić.

## Dodawanie źródła JSON

Każdy obiekt w `Config.TattooCatalog.sources` konfiguruje jedno źródło. Poniższy przykład odpowiada strukturze zasobów pakietów; możesz dostosować go, wpisując rzeczywistą nazwę zasobu i pliku:

```lua
{
    id = 'mi-pack',
    label = 'Mi Pack',
    color = '#62b6cb',
    enabled = true,
    resource = 'mi_pack',
    path = 'tattoos.json',
    thumbnailPattern = 'miniatures/{Name}.webp',
    root = { mode = 'auto', field = 'Overlays' },
    defaults = {
        collection = 'mi_pack_overlays',
        zone = 'ZONE_TORSO',
        price = 5000,
        requiredLevel = 1,
        overlayTarget = 'male',
    },
}
```

`id` powinno stabilnie identyfikować źródło; `label` i `color` pomagają rozpoznać je w interfejsie. `resource` i `path` wskazują plik JSON. Plik musi znajdować się w dostępnym zasobie. Nie dodawaj tego samego wzoru w dwóch źródłach, chyba że ma pojawiać się dwa razy; `deduplicateAcrossSources` pozwala usuwać duplikaty między źródłami.

Ustawienia globalne znajdują się w `Config.TattooCatalog`:

| Pole | Wartość początkowa | Zastosowanie |
| --- | --- | --- |
| `deduplicate` | `true` | Usuwa zduplikowane wzory w obrębie jednego źródła. |
| `deduplicateAcrossSources` | `false` | Pozwala zachować osobno wzory z różnych źródeł. |
| `serverFallback` | `true` | Prosi serwer o źródło, którego klient nie może odczytać. |
| `serverFallbackTimeoutMs` | `7000` | Maksymalny czas oczekiwania na to żądanie w milisekundach. |

Zapasowy odczyt nie sprawia, że zatrzymany pakiet staje się dostępny.

## Format pojedynczego tatuażu

Plik może zawierać tablicę JSON albo obiekt, którego właściwość zawiera tablicę. Przy `root.mode = 'auto'` czytnik obsługuje oba formaty; przy `root.mode = 'field'` pole `root.field` wskazuje listę. `root.mode = 'array'` wymusza tablicę na najwyższym poziomie dokumentu.

Poniższa tablica pokazuje format JSON. Kolekcja i hashe w przykładzie są fikcyjne: zastąp je rzeczywistymi nazwami zainstalowanego pakietu. Dodanie wpisu JSON nie instaluje graficznych overlayów.

```json
[
  {
    "Collection": "mi_pack_overlays",
    "Name": "Rosa del desierto",
    "HashNameMale": "MP_MI_PACK_ROSE_M",
    "HashNameFemale": "MP_MI_PACK_ROSE_F",
    "Zone": "ZONE_TORSO",
    "Price": 5000,
    "Xp": 15,
    "RequiredLevel": 2
  }
]
```

Do identyfikacji wzoru potrzebne są `Collection` i co najmniej jeden hash overlaya. Dodaj `HashNameMale` oraz `HashNameFemale`, jeśli tatuaż ma osobny wariant dla każdej postaci. Użyj jednej ze stref: `ZONE_HEAD`, `ZONE_TORSO`, `ZONE_LEFT_ARM`, `ZONE_RIGHT_ARM`, `ZONE_LEFT_LEG` lub `ZONE_RIGHT_LEG`. `Name` to nazwa widoczna dla kupującego. Jeśli pominiesz `Price`, użyta zostanie cena domyślna źródła; jeśli pominiesz `RequiredLevel`, obowiązuje `defaults.requiredLevel`, którego początkowa wartość to 1. XP może pochodzić z tatuażu albo konfiguracji poziomów.

W przypadku plików z innymi nazwami pól dostosuj `fields` w `Config.TattooCatalog`. Każda pozycja tej tabeli to lista aliasów sprawdzanych podczas wyszukiwania odpowiedniej wartości. Na przykład plik używający `OverlayHash`, `Cost` i `BodyZone` można zmapować tak:

```lua
fields = {
    collection = { 'Collection', 'CollectionName' },
    name = { 'Name', 'DisplayName' },
    overlay = { 'OverlayHash' },
    hashNameMale = { 'MaleOverlay' },
    hashNameFemale = { 'FemaleOverlay' },
    zone = { 'BodyZone' },
    price = { 'Cost' },
    xp = { 'Xp', 'Experience' },
    requiredLevel = { 'RequiredLevel' },
}
```

Możesz także przypisywać wspólne wartości przez `rootFields`, na przykład nazwę kolekcji lub strefę zdefiniowaną raz w obiekcie głównym. `defaults` każdego źródła uzupełnia brakujące wartości. Jeśli JSON zawiera tylko jedno ogólne pole, np. `OverlayHash`, `defaults.overlayTarget` określa, czy należy traktować je jako tatuaż męski (`male`), czy żeński (`female`).

Bardzo różne formaty można przekształcić za pomocą opcjonalnych funkcji `converters.decode(decoded, settings)` lub `converters.entry(entry, context)` w konfiguracji. Pierwsza dostosowuje cały dokument, druga pojedynczy wzór. Zwróć tabelę z polami przygotowanymi do standardowego mapowania.

## Miniatury

Aby używać obrazów z tego samego pakietu, zachowaj w nim folder `miniatures/` i ustaw wzorzec, na przykład:

```lua
thumbnailPattern = 'miniatures/{Name}.webp'
```

`{Name}`, `{HashNameMale}`, `{HashNameFemale}` i `{HashName}` są zastępowane danymi tatuażu. Wynikowy plik, np. `miniatures/Rosa del desierto.webp`, musi istnieć w zasobie, a sam zasób musi być uruchomiony. Interfejs pobiera miniaturę wtedy, gdy jej potrzebuje; nie kopiuj obrazów do pakietu CXG.

Możesz też ustawić `Thumbnail` lub `ThumbnailUrl` we wpisie, aby wskazać konkretny obraz. Adresy `http://`, `https://` i `data:` są używane bez zmian. Lokalna ścieżka miniatury w pakiecie musi odpowiadać jego `thumbnailPattern`; plik musi istnieć, a zasób musi udostępniać go interfejsowi NUI. Zasoby zewnętrzne powinny zachować plik we własnym pakiecie.

## Zmiany w konfiguracji i panelu administracyjnym

Edytuj konfigurację, aby dodawać źródła, zmieniać sposób odczytu, włączać lub wyłączać pakiety i ustawiać wartości domyślne. Panel administracyjny katalogu służy do zmiany nazw, ceny, poziomu i dostępności tatuaży bez edycji JSON. Zmiany administracyjne są zapisywane i pozostają po synchronizacji katalogu. Funkcja przywracania wartości ustawia danemu tatuażowi wartości ze źródła.

Tatuaże kupione wcześniej przez gracza pozostają przypisane do jego postaci, nawet jeśli pakiet, z którego pochodzą, zostanie tymczasowo wyłączony. Pakiet nie pojawi się w sklepie, dopóki znów nie będzie dostępny.
