# catalogue.json: metadata và bản địa hóa game PlayDrop

Tài liệu tham khảo về tên game, mô tả, thẻ thể loại, hình ảnh và video giới thiệu, bản dịch và trường server tùy chọn trong định dạng PlayDrop Connector.

Source: https://www.playdrop.ai/vi/create/learn/catalogue-json

[PlayDrop Connector](https://www.playdrop.ai/vi/create/connectors) gửi metadata `catalogue.json` của bạn cùng các tệp game; không cần công cụ dòng lệnh nào. PlayDrop Cloud duy trì metadata này cho các game Studio.

## Tải lên riêng tư hoàn chỉnh với prepare_catalogue_upload

Đây là một yêu cầu `prepare_catalogue_upload` hoàn chỉnh cho một game riêng tư mới. Hãy thay HTML ví dụ bằng game đã dựng của bạn và dùng một `requestId` duy nhất cho mỗi lần tải lên dự định. Đối tượng `catalogue` là nội dung của `catalogue.json`; `files` và `expectedCurrentVersion` thuộc về yêu cầu của công cụ, nằm ngoài đối tượng đó.

```json
{
  "requestId": "my-game-v1-unique-request",
  "catalogue": {
    "apps": [
      {
        "name": "my-game",
        "displayName": "My Game",
        "file": "index.html",
        "version": "1.0.0",
        "visibility": "PRIVATE",
        "authMode": "OPTIONAL",
        "surfaceTargets": {
          "desktop": true,
          "mobileLandscape": false,
          "mobilePortrait": false
        }
      }
    ]
  },
  "expectedCurrentVersion": {
    "my-game": null
  },
  "files": [
    {
      "path": "index.html",
      "text": "<!doctype html><html><head><title>My Game</title></head><body><button onclick=\"this.textContent=Number(this.textContent)+1\">0</button></body></html>"
    }
  ]
}
```

`apps[].file` phải khớp chính xác với một `files[].path`. Nếu bỏ `file`, mục này mặc định là `<name>.html`, không phải `index.html`. `surfaceTargets` là một đối tượng với các giá trị boolean `desktop`, `mobileLandscape` và `mobilePortrait`; hãy bật ít nhất một màn hình bạn đã thử. Hãy khai báo phiên bản và chế độ hiển thị một cách tường minh. Ví dụ dùng một tệp văn bản nội tuyến; tệp đính kèm hoặc tải byte có chữ ký có thể dùng cùng đường dẫn.

Sau khi chuẩn bị, hãy gửi các byte tệp được yêu cầu và gọi `complete_catalogue_upload` với cùng `requestId`. Mở phiên bản riêng tư để thử nó. Để cập nhật, hãy đọc `list_games`, giữ nguyên `name`, cung cấp một `version` mới và toàn bộ ảnh chụp, rồi đặt `expectedCurrentVersion[name]` bằng phiên bản công khai hiện tại do máy chủ trả về (hoặc `null` nếu chưa có). Đây là một kiểm tra xung đột, không phải phiên bản đang được tải lên. Hãy thử lại các lần tải lên bị gián đoạn với ID yêu cầu ban đầu. Khi sẵn sàng, hãy xuất bản phiên bản đã thử và được giữ lại bằng `publish_game_version`.

## Ví dụ tương thích cũ cho một game

Ví dụ dưới đây là dạng cũ cho một game. Các lần tải lên catalogue đầy đủ cũng hỗ trợ nhiều game, tài nguyên, gói và spec; hãy hỏi connector để biết schema hiện tại. Mỗi lần cập nhật cung cấp một ảnh chụp đầy đủ với chế độ hiển thị và phiên bản tường minh. Các mục catalogue bị bỏ sót không bị xóa.

Giữ slug chữ thường ổn định khi cập nhật. Thêm tên hiển thị, mô tả chính xác, cách điều khiển, ngôn ngữ nguồn và các thẻ đã biết khi cần. Ví dụ dưới đây dùng thẻ thể loại platformer có sẵn.

```json
{
  "apps": [{
    "name": "moon-jump",
    "displayName": "Moon Jump",
    "description": "Jump between lunar platforms and reach the finish.",
    "controls": "Arrow keys to move. Space to jump.",
    "sourceLocale": "en",
    "tags": ["game-genre/platformer"]
  }]
}
```

## Các trường được hỗ trợ và giới hạn

`name`: 1–100 chữ cái thường, chữ số hoặc dấu gạch ngang, bắt đầu bằng chữ cái hoặc chữ số. `displayName`: tên không được để trống. `subtitle`: tối đa 120 ký tự. `description`: tối đa 3.000 ký tự Markdown, không có tiêu đề H1, media nhúng hay bảng. `inspirationPrompt`: tối đa 400 ký tự văn bản thuần một dòng. Giới hạn văn bản tính theo đơn vị mã UTF-16 của JavaScript.

Các trường tùy chọn gồm `controls`, `releaseNotes`, `makingOf`, `emoji`, `color`, `sourceRepository`, `license`, `tags`, `sourceLocale`, `listingLocalizations`, `listingMedia` và `server`. Thẻ dùng các tham chiếu `group-slug/tag-slug` có sẵn, tối đa 20 thẻ duy nhất. `server` liệt kê các phòng Colyseus của một `server.js` đã tải lên, ví dụ `"server": { "rooms": ["game"] }`; xem [SDK server](https://www.playdrop.ai/vi/create/learn/server-sdk). Hãy hỏi connector về các giá trị giấy phép hiện được chấp nhận và quy tắc đầy đủ của từng trường trước khi xuất bản. Gợi ý tùy chọn cho ứng dụng gốc: `prefetch` liệt kê các tệp đã tải lên mà ứng dụng PlayDrop trên iOS, macOS và Android có thể tải trước khi chơi, ví dụ `"prefetch": { "required": ["game.js"], "optional": ["music.mp3"] }` (trang vào luôn được gồm), và `"offlineSupported": true` cho phép các ứng dụng đó cung cấp game ngoại tuyến sau khi đã lưu các tệp bắt buộc. Giá trị không hợp lệ bị bỏ qua và không bao giờ chặn việc tải lên; các trang web vẫn tải game như bình thường.

Game Instant: đặt `"instant": true` khi game chơi được trong vòng 2 giây từ tối đa 10 MB tệp khởi động (trang vào cộng với `prefetch.required`, hoặc mọi tệp đã tải lên khi không liệt kê tệp nào). Game Instant mang huy hiệu tia chớp và được chơi trong bảng tin Instant của ứng dụng PlayDrop trên điện thoại. Hãy đặt các màn sâu hơn và phần bổ sung vào `prefetch.optional`, hoàn tất biên dịch shader và các bước khởi động khác trước khi gọi `ready()`, làm cho bản xem trước hiển thị lối chơi thay vì màn hình tiêu đề, và cho phép khách (`authMode` là `OPTIONAL` hoặc `NONE`) để mọi người đều thấy game trong bảng tin. PlayDrop kiểm tra kích thước khi tải lên và gỡ huy hiệu khỏi các phiên bản mà điện thoại khởi động chậm; một game không đạt chuẩn vẫn được xuất bản.

## Hình ảnh và video giới thiệu

Tải media giới thiệu lên dưới dạng tệp cạnh `index.html`, đặt tên theo đường dẫn: `listing/icon.png`, `listing/hero-landscape.png` (16:9) và `listing/hero-portrait.png` (9:16) có tên game trong ảnh, ảnh chụp màn hình như `listing/screenshots/landscape/0.png`, và video `listing/videos/landscape/0.mp4` (trailer) và `listing/videos/portrait/0.mp4` (teaser cho di động). Video phát không tiếng trên thẻ game và trang game, trailer trên máy tính và TV, teaser trên điện thoại, nên đây là cách nhanh nhất để cho thấy lối chơi và có được lượt chơi đầu tiên. Ảnh là PNG và video là MP4.

## Dịch trang giới thiệu chính xác

Luôn xuất bản tiếng Anh cùng ngôn ngữ của bạn nếu khác. Đặt `sourceLocale` là ngôn ngữ gốc. `listingLocalizations` hỗ trợ tiếng Anh, tiếng Pháp, tiếng Đức, tiếng Tây Ban Nha, tiếng Bồ Đào Nha (Brazil), tiếng Indonesia, tiếng Nhật, tiếng Hàn, tiếng Trung phồn thể và tiếng Trung giản thể. Mỗi bản dịch cần `locale` và `displayName`; khi bạn tải lên cùng nguồn của nó, PlayDrop tự điền `sourceHash`. Tải ảnh đã dịch lên dưới `listing/locales/<locale>/`, ví dụ `listing/locales/fr/hero-landscape.png` với tên game bằng tiếng Pháp; nó được khớp với bản dịch của mình tự động. Làm mới bản dịch sau khi nguồn thay đổi. Dịch trang giới thiệu không dịch chính game.

## Người chơi, nhóm chơi và tay cầm

Khai báo cách game của bạn được chơi bằng `types`, `party`, `controller` và `roomVoice` trên mỗi mục game:

```json
{
  "types": ["solo", "online", "party"],
  "party": { "local": [1, 2, 3, 4], "online": [1, 2, 3, 4] },
  "controller": { "support": "optional", "type": "simpler" },
  "roomVoice": true
}
```

`types` kết hợp `solo` (chơi một mình), `online` (chơi cùng người khác qua mạng) và `party` (một nhóm chơi cùng nhau). `party.local` liệt kê chính xác số người có thể chơi trên một màn hình; `party.online` liệt kê các quy mô nhóm bạn bè, tối đa 4, có thể cùng vào trực tuyến, chứ không phải sức chứa của phòng. Quy mô là chính xác: `[2, 4]` loại trừ 3. `party` yêu cầu loại `party`, `party.online` yêu cầu `online`, và số 1 trong `party.local` yêu cầu `solo`. `roomVoice: true` bật thoại phòng và yêu cầu `online`.

`controller.support` là `off` (mặc định khi bỏ `controller`), `optional` hoặc `required`. Khi nó không phải `off`, `controller.type` nêu tên các điều khiển tối thiểu mà game cần:

- `any`: các hướng, Xác nhận và Hủy; mọi tay cầm đều dùng được, kể cả điều khiển từ xa.
- `simpler`: một cần analog, bốn nút mặt và Menu; tay cầm điện thoại PlayDrop và gamepad chuẩn đều đáp ứng.
- `standard`: D-pad, hai cần nhấn được, bốn nút mặt, hai nút vai, hai cò và Menu.
- `custom`: dành riêng cho điều khiển điện thoại riêng của từng game; chưa có.

Khi bật hỗ trợ tay cầm, mọi số lượng cục bộ đã khai báo đều phải chơi được bằng tay cầm; hãy đọc đầu vào tay cầm qua [SDK](https://www.playdrop.ai/vi/create/learn/sdk). Các game hiện có có thể giữ `players` và `controllerMode`, chúng vẫn hoạt động, nhưng game mới dùng các trường này, và một mục không thể trộn cả hai. Host chọn chơi cục bộ hoặc trực tuyến, không bao giờ cả hai. Các khai báo này được giữ qua các lần tải lên bằng Cloud, CLI và MCP, các phiên bản riêng tư được giữ lại và việc xuất bản. Tình trạng khả dụng còn phụ thuộc vào việc triển khai nền tảng và bản dựng host.

Với các lần tải lên máy chủ qua MCP, hãy cung cấp một gói ESM `.mjs`/`.js` đã dựng dưới dạng mô tả `SERVER` và trỏ `server.entry` tới nó. Dự án nguồn cho Cloud/CLI giữ nguyên điểm vào TypeScript. PlayDrop cung cấp runtime Colyseus và SDK server; không bao giờ đưa thông tin xác thực của nhà cung cấp thoại vào game.
