English
Switch to the English documentation
Open Play geliştirici dokümanı
Oyununuzu Open Play’e bağlamak ve yönetim panelini kullanmak için sayfalar aşağıdadır. Türkçe sayfalar kaynaktır; İngilizce sürüm çeviridir.
Henüz yazılmamış sayfalar planlıdır; bağlantıları sayfa eklenince çalışır. Durum: pages.yaml (docs/developer/pages.yaml).
Başlarken
- Genel bakış
- Temel kavramlar
- Hızlı başlangıç
- Mimari ve barındırma
- Yapay zekâ araçlarıyla kullanım (MCP)
- Oyununuz için AGENTS.md
Kimlik doğrulama
- Genel bakış
- Misafir girişi
- E-posta ve parola
- OAuth ile giriş
- Oturumlar ve CSRF
- Hesap bağlama
- Hesabı silme
- Sunucuda doğrulama
SDK’lar
Rehberler
- Karakterler
- Envanter ve eşyalar
- Ekonomi
- Mağaza ve uygulama içi satın alma
- Ödüller
- Sosyal özellikler
- Sohbet
- Yarışma ve skor tabloları
- Bildirimler
- Webhook’lar
- Sahneler, varlıklar ve modeller
- İçerik grupları
- Oyun kuralları
- Oyuncu verisi (bulut kaydı)
Gerçek zamanlı
Eklentiler
Başvuru
- Hatalar
- Idempotency ve eşzamanlılık
- Sayfalama
- Hız sınırları
- Sayılar ve kodlama
- Sürümleme
- Uç noktalar (üretilir)
- Webhook olayları (üretilir)
- Sözlük
Operasyon
Panel yardım sayfaları
Panel sayfaları yönetim panelindeki “Yardım” çekmecesinin ve bilgi balonlarının kaynağıdır.
Open Play’e genel bakış
Bu sayfa, Open Play’in oyununuz için hangi hazır parçaları sunduğunu ve bu parçalarla hangi kanaldan konuşacağınızı özetler. Entegrasyona başlamadan önce okuyun; ayrıntılar için her bölümün sonundaki bağlantıları izleyin.
Open Play nedir?
Open Play, oyunların arka uç ihtiyaçlarını tek bir sunucu olarak karşılar: oyuncu kimliği ve oturumu, karakterler, envanter, ekonomi, mağaza, ödüller, sosyal özellikler, skor tabloları, bildirimler, webhook’lar ve gerçek zamanlı bağlantı. Oyununuzu bu sunucuya HTTP (REST) ve WebSocket üzerinden bağlarsınız; oyunu yöneten ekip aynı sunucuyu yönetim panelinden yapılandırır.
Not
Open Play bugün bir Docker Compose yığınıdır ve sizin ya da ekibinizin altyapısında çalışır. Kurulum ve dağıtım için üretim dağıtımı rehberine (
docs/production-and-adapters.tr.md) bakın; bu belge oyun geliştiricisinin bakış açısını anlatır.
Neler sunar? Modül haritası
Özelliklerin çoğu modül olarak açılıp kapatılır. Kapalı bir modülün uçları çalışmaz ve 404 ile module_disabled kodunu döndürür (bkz. Kavramlar). Modüller panelde Oyun ayarları › Modüller sekmesinden yönetilir.
| Modül | Oyununuza ne verir? | Rehber |
|---|---|---|
characters | Karakter tanımları, karakterler, komutlar, kurallar, özellikler (trait), seviye eğrileri | Karakterler |
economy | Para birimleri, cüzdanlar, transferler, defter (ledger) | Ekonomi |
items | Eşya tanımları, eşya örnekleri, envanter | Eşyalar ve envanter |
trading | Tüccar ve oyuncular arası takas | Ham REST: uç noktalar |
store | Mağaza kataloğu, satın alma, uygulama içi satın alma (IAP) doğrulaması | Mağaza ve IAP |
rewards | Ödül tabloları, görev, NPC ödülü, VIP, günlük giriş ödülü | Ödüller |
social | Klan ve parti | Sosyal |
chat | Sohbet | Sohbet |
competition | Skor tabloları ve turnuvalar | Rekabet |
notifications | Bildirim kanalları, şablonlar, oyuncu gelen kutusu, web push | Bildirimler |
webhooks | Oyun olaylarını kendi sunucunuza imzalı olarak iletme | Webhook’lar |
scenes | Sahneler ve görsel varlıklar | Sahneler, varlıklar, modeller |
plugins | Eklenti platformu ve gerçek zamanlı yüzey | Eklentiler, Gerçek zamanlı |
Modül anahtarı olmayan çekirdek yüzeyler her zaman açıktır:
- Oyuncu kimliği ve oturumu: misafir, e-posta/parola, Google. Bkz. Kimlik doğrulama.
- İçerik grupları ve katalog: panelden yönetilen, oyunun okuduğu veri. Bkz. İçerik grupları.
- Oyun kuralları ve otomasyonlar. Bkz. Oyun kuralları.
- API anahtarları, ortamlar ve alan adları. Bkz. Kavramlar.
Hangi kanaldan konuşursunuz?
| Kanal | Kim kullanır? | Kimlik | Ne için? |
|---|---|---|---|
REST (/v1/...) + sunucu anahtarı | Oyun sunucunuz (güvenilen arka uç) | Authorization: Bearer crx_live_<önek>_<gizli> | Yönetim ve parayı/eşyayı değiştiren işlemler |
| REST + istemci anahtarı | Oyun istemciniz | aynı biçimde istemci anahtarı | Sınırlı, hassas olmayan işlemler |
| REST + oyuncu oturumu | Oyuncunun kendi istemcisi (tarayıcı, Unity) | çerez ya da oturum belirteci + x-crx-env | Oyuncunun kendi verisi: giriş, katalog, mağaza, sıralama, eklenti komutları |
WebSocket (/v1/realtime/ws vb.) | Oyuncunun istemcisi | tek kullanımlık bilet | Eklenti durumu, anlık girdi, kesintisiz akış |
| Webhook (Open Play → sizin sunucunuz) | Sizin sunucunuz | X-Crx-Signature imzası | Olay bildirimi |
| SDK | TypeScript ve Unity | yukarıdakilerin sarmalayıcısı | REST ve WebSocket’i tipli kullanmak |
Uyarı
Sunucu anahtarı bir sırdır. Tarayıcıya, mobil uygulamaya ya da oyun paketine koymayın. İstemci tarafında yalnızca oyuncu oturumu ve (gerekirse) istemci anahtarı kullanın.
gRPC arayüzü sunucu tarafında vardır ancak oyun geliştiricisi için dışa açık bir kanal değildir; varsayılan olarak yalnız loopback’te dinler ve SDK’lar kullanmaz. Bu belge onu anlatmaz.
Nereden başlamalı?
- Kavramlar: stüdyo, oyun, ortam, modül, anahtar türleri, oyuncu oturumu.
- Hızlı başlangıç: ilk sunucu çağrınız ve ilk oyuncu girişiniz.
- Mimari ve barındırma: aynı köken (same-origin) kuralı, alan adları, neyin nerede çalıştığı.
- Kimlik doğrulama ve SDK’lar.
Bugünkü sınırlar
Aşağıdakiler bilinçli olarak dürüst yazılmıştır; yol haritanızı buna göre kurun.
- CORS yalnız ortamın alan adı listesindeki origin’lere açıktır ve çerez aynı site ister. Tarayıcı oyunu, alan adı bir ortama bağlıysa Open Play’i doğrudan çağırabilir; oyun Open Play’den farklı bir kayıtlı alan adındaysa
SameSite=Laxoturum çerezi gitmez (ters vekil kullanın). Bkz. Mimari ve barındırma. - Üçüncü taraf eklenti yükleme desteklenmez. Eklentiler sunucuya derlenmiş olarak gelir; panelden eklenti yüklenmez. Bkz. Eklentiler.
- SDK kapsamı kısmidir. TypeScript SDK’sında tipli istemci olmayan modüller ham REST ile kullanılır. Bkz. TypeScript SDK.
- Unity’de yalnız Unity 6000.6.7f1 doğrulanmıştır. Bkz. Unity SDK.
- Hata gövdeleri çoğunlukla düz metindir. Yalnız birkaç yerde JSON hata zarfı vardır. Bkz. Hatalar.
Temel kavramlar
Open Play’de her şey birkaç kavramın etrafında döner: verinin ait olduğu ortam, özellikleri açıp kapatan modüller, iki farklı API anahtarı türü, oyuncunun oturumu ve oyuna özel mantığı taşıyan eklenti. Bu sayfayı bir kez okuyun; diğer sayfalar bu kelimeleri bilindiğini varsayar.
Stüdyo, oyun, ortam
Open Play üç katmanlı bir hiyerarşi kullanır. Panelde Stüdyolar ve oyunlar ekranında (yalnız süper yönetici görür) bu ağacı yönetirsiniz.
| Katman | Anlamı | Not |
|---|---|---|
| Stüdyo | Oyunlarınızı bir arada tutan kuruluş | Bir sunucuda birden çok stüdyo olabilir |
| Oyun | Tek bir ürün | Yeni oyun oluşturulunca dev ve prod ortamları otomatik açılır |
| Ortam | Oyunun yalıtılmış bir kopyası: dev, prod, istenirse staging | Oyuncular, karakterler, cüzdanlar, anahtarlar ortama aittir |
Ortam, veri sınırıdır. Bir ortamdaki oyuncu, karakter, cüzdan ya da anahtar başka bir ortamdan görünmez. Her API çağrısı tek bir ortama karşı çalışır:
- API anahtarıyla yapılan çağrılarda ortam anahtardan çıkar; ayrıca bir başlık göndermezsiniz.
- Oyuncu oturumuyla yapılan çağrılarda ortamı
x-crx-env: <ortam-kimliği>başlığıyla siz bildirirsiniz. Kimlik bir UUID’dir. SDK’lar bunuenvironmentIdayarından gönderir.
Not
Panel bugün ortam kimliğini (UUID) okunur bir alanda göstermez. Kimliği operatör ekibinizden isteyin ya da panel oturumundaki Oyun ayarları › Modüller sekmesinin yaptığı
GET /v1/panel/modulesisteğinin yanıtındakienvironmentIdalanından okuyun. Bu eksiklik kayıtlıdır.
Panel adımları için bkz. Hızlı başlangıç ve Oyun ayarları.
Modüller
Özelliklerin çoğu modüldür: characters, economy, items, trading, store, rewards, social, chat, competition, notifications, webhooks, scenes, plugins (13 modül). Modüller ortam başına açılıp kapatılır; kurulumda sihirbaz bir başlangıç kümesi seçtirir, sonrasında Oyun ayarları › Modüller sekmesi kullanılır (yalnız süper yönetici).
- Kapalı modülün uçları çalışmaz: HTTP
404ve gövde{"code":"module_disabled","message":"…","module":"<ad>"}. Kimliği geçersiz çağıran401alır; modülün kapalı olduğunu öğrenemez. - Kapatmak veriyi silmez, yalnız yüzeyi durdurur; yeniden açınca veri yerindedir.
- Bazı modüller başkalarına bağlıdır (örneğin
trading,economyveitems’a dayanır) ve etkin bir eklentinin ihtiyaç duyduğu modül kapatılamaz. - Çekirdek yüzeyler (oyuncu girişi, içerik grupları, API anahtarları) modül değildir ve kapatılamaz.
Hata ayrıntıları için bkz. Hatalar.
API anahtarları: sunucu ve istemci
API anahtarı, bir ortama bağlı gizli bir dizgedir ve Authorization: Bearer başlığıyla gönderilir. Biçimi:
crx_live_<önek>_<gizli>
Panelde yalnız crx_live_<önek> kısmı (önek) görünür; gizli değer oluşturulduğu anda bir kez gösterilir ve geri alınamaz. Kaybederseniz yeni anahtar oluşturur ya da anahtarı döndürürsünüz (rotate): eski gizli değer geçersiz olur, yenisi bir kez gösterilir.
| Sunucu anahtarı | İstemci anahtarı | |
|---|---|---|
| Nerede kullanılır? | Oyun sunucunuz, arka uç kodunuz | Oyun istemcisi (tarayıcı, mobil) |
| Gömülebilir mi? | Hayır, gizli tutulur | Evet |
| Ne yapabilir? | Tüm işlemler: tanım oluşturma, para verme, eşya basma, webhook kaydı, yönetim | Yalnız izin verilen, hassas olmayan işlemler |
| Örnek | add_xp komutu, para verme, eşya basma | karakteri okuma, set_flag komutu |
Kesin kural uç noktaya göre değişir ve kodda uç nokta başına sınanır. Hangi ucun hangi anahtar türünü kabul ettiği uç nokta başvurusunda listelenir. Anahtar türü yetersizse çağrı 403 alır.
Panelde anahtar oluşturma: Oyun ayarları › API anahtarları › Yeni API anahtarı (bkz. API anahtarları). Oluştururken ad, tür (Sunucu anahtarı ya da İstemci anahtarı), geçerlilik süresi ve denetim kaydına yazılan bir not (8–500 karakter) girilir.
Uyarı
Gelişmiş ayarlar (kapsam etiketleri, izinler, ek bilgiler) bugün yalnızca kayıt amaçlıdır; anahtarın neye erişebileceğini kısıtlamaz. Erişimi yalnızca anahtar türü belirler. Sunucu anahtarını “kısıtlı” saymayın.
Anahtar ve gizli değer yönetimi için bkz. Güvenlik.
Oyuncu oturumu
Oyuncular API anahtarıyla değil, kendi oturumlarıyla konuşur. Oturum şu yollarla açılır: misafir girişi, e-posta ve parola, Google. Başarılı girişte sunucu bir oturum çerezi (__Secure-crx.session) ve bir yenileme çerezi (__Secure-crx.refresh) yazar; aynı belirteçler yanıt gövdesinde de döner, böylece çerezsiz istemciler (Unity yerel derlemesi, komut satırı araçları) Authorization: Bearer <oturum-belirteci> kullanabilir.
Oyuncu oturumuyla yapılan her istek x-crx-env başlığı taşır. Çerezli (tarayıcı) oturumda durum değiştiren istekler ayrıca CSRF koruması ister (x-csrf-token başlığı). Bu ayrıntıları SDK’lar sizin yerinize yönetir; ham REST’te kendiniz uygularsınız:
Oyuncu oturumu oyun sunucunuza da taşınabilir: oyuncunun kısa ömürlü erişim JWT’si (EdDSA) ortak bir JWKS ile çevrimdışı doğrulanır. Bkz. Sunucuda doğrulama.
Eklenti (plugin)
Eklenti, bir oyuna özel sunucu mantığını (komutlar, sorgular, gerçek zamanlı modüller) taşıyan, sunucuya derlenmiş bir pakettir. Eklenti çağrıları /v1/plugins/{eklenti}/... altında yapılır; durum değiştiren komutlar idempotency anahtarı taşır ve şema isterse expectedVersion ile sürüm denetimi yapar. Eklentinin şeması bir artefakttır (<eklenti>.plugin.schema.json) ve TypeScript/Unity bağlamaları bu şemadan üretilir.
Not
Üçüncü taraf eklenti yükleme (panelden ya da API’den) bugün desteklenmez. Eklentiler Open Play sunucusunun yayınıyla birlikte gelir. Bkz. Eklentilere genel bakış.
Ortak çağrı kuralları
Birçok uçta aynı üç kural geçerlidir; ayrıntıları başvuru sayfalarında bulursunuz:
- Idempotency-Key: durum değiştiren komutlarda aynı anahtar ve aynı gövde sonucu yeniden oynatır; aynı anahtarla farklı gövde
422verir. Bkz. Idempotency ve eşzamanlılık. - If-Match / expectedVersion: kaynağın okuduğunuz sürümünü bildirerek eşzamanlı yazma çakışmasını yakalarsınız (
409). - Sayılar: büyük tam sayılar (
i64) JavaScript’tebigintolur; eklenti protokolünde ondalık dizge olarak taşınır. Bkz. Sayılar ve kodlama.
Terimlerin kısa tanımı için bkz. Sözlük.
Hızlı başlangıç
Bu rehberde sıfırdan şunları yaparsınız: panelde bir oyun ve sunucu anahtarı oluşturur, curl ve TypeScript ile ilk sunucu çağrınızı atar, tarayıcı oyununuzdan bir oyuncuyu misafir olarak girdirir ve aynısını Unity’den yaparsınız. Yaklaşık yarım saat sürer. Başlamadan önce Kavramlar sayfasına göz atın.
Ön koşullar
- Çalışan bir Open Play sunucusu ve panele giriş yapabilen bir yönetici hesabı (süper yönetici). Kurulum için üretim dağıtımı rehberine (
docs/production-and-adapters.tr.md) bakın. - Sunucunun genel HTTPS adresi. Bu sayfada
OPEN_PLAY_URLolarak anılır (örneğinhttps://oyun.example.com/open-play). - Node.js 22 ya da üstü ve
curl; ham REST örnekleri içinjqveopenssl.
1. Oyun ve ortam oluşturun
Kurulum sihirbazı ilk stüdyoyu ve oyunu zaten açtıysa bu adımı atlayın.
- Panelde Stüdyolar ve oyunlar ekranını açın ve Yeni stüdyo düğmesiyle bir stüdyo oluşturun.
- Stüdyo kartında Yeni oyun’u seçin; oyunun adını (ve isterseniz kısa adını) girin. Oyunla birlikte
devveprodortamları otomatik oluşur. - Üst çubuktaki Aktif oyun ve ortam seçicisinden oluşturduğunuz oyunun
devortamını seçin. Panelin geri kalanı seçili ortamın verisini gösterir.
Ayrıntılar: Stüdyolar ve oyunlar.
2. Modülleri kontrol edin
Oyun ayarları › Modüller sekmesinde bu rehberdeki çağrı için characters modülünün Açık olduğunu doğrulayın. Kapalı modül 404 ve module_disabled döndürür. Ayrıntılar: Modüller.
3. Sunucu anahtarı oluşturun
- Oyun ayarları › API anahtarları sekmesinde Yeni API anahtarı’nı seçin.
- Bir ad verin (örneğin
Oyun sunucusu), türü Sunucu anahtarı seçin, geçerlilik süresini belirleyin ve denetim kaydı için kısa bir not yazın (8–500 karakter). - Oluştur’a basın. Açılan karttaki gizli değeri hemen kopyalayıp sunucunuzun gizli ayarlarına kaydedin. Bu değeri bir daha göremezsiniz.
Anahtar şu biçimdedir: crx_live_<önek>_<gizli>. Bu sayfada ortam değişkeni olarak kullanacağız:
export OPEN_PLAY_URL="https://oyun.example.com/open-play"
export OPEN_PLAY_SERVER_KEY="crx_live_<önek>_<gizli>"
Uyarı
Gerçek anahtarı belgeye, depoya, sohbete ya da günlüğe yazmayın. Sızdığından şüphelenirseniz anahtarı panelden döndürün (rotate) ya da silin.
4. İlk sunucu çağrınız
Sunucu anahtarıyla ortamdaki karakterlerin ilk sayfasını isteyin. Ortam anahtardan çıktığı için ek başlık gerekmez.
curl -sS "$OPEN_PLAY_URL/v1/characters?limit=1" \
-H "Authorization: Bearer $OPEN_PLAY_SERVER_KEY"
Henüz karakter yoksa beklenen yanıt (200):
{"items":[],"next_cursor":null}
Aynı çağrı TypeScript SDK’sıyla (kurulum için TypeScript SDK):
import { CrxClient, CrxError } from "@ferdiunal/open-play-ts";
/**
* Sunucu anahtarıyla ilk çağrı: ortamdaki karakterlerin ilk sayfasını okur.
* Bu kod yalnızca güvenilen arka uçta çalışır; sunucu anahtarını tarayıcıya göndermeyin.
*/
export async function listFirstCharacters(baseUrl: string, serverKey: string): Promise<number> {
const client = new CrxClient({ baseUrl, apiKey: serverKey });
try {
const page = await client.listCharacters({ query: { limit: 1 } });
return page.items.length;
} catch (error) {
if (error instanceof CrxError) {
// kind, status ve attempts güvenlidir; anahtar ve istek gövdesi hata nesnesine girmez.
console.error("Open Play çağrısı başarısız:", error.kind, error.status);
}
throw error;
}
}
// Kullanım (Node 22, ESM):
// const count = await listFirstCharacters(process.env.OPEN_PLAY_URL!, process.env.OPEN_PLAY_SERVER_KEY!);
Olası sorunlar:
| Belirti | Neden | Çözüm |
|---|---|---|
401 | Anahtar yanlış, silinmiş, süresi dolmuş ya da Bearer öneki eksik | Anahtarı ve başlığı kontrol edin; gerekirse yeni anahtar oluşturun |
404, gövde {"code":"module_disabled",…} | characters modülü bu ortamda kapalı | Adım 2 |
403 | Anahtar türü bu işlem için yetersiz (istemci anahtarı) | Sunucu anahtarı kullanın |
| Bağlantı/TLS hatası | Adres yanlış ya da HTTPS değil | Genel HTTPS adresini kullanın; yerelde http://localhost yalnız geliştirme içindir |
5. Oyununuzun alan adını ortama bağlayın
Tarayıcı, durum değiştiren isteklere Origin başlığı ekler; sunucu bu origin’in o ortama ait olduğunu denetler. Oyun sayfanızın alan adı tanımlı değilse oyuncu girişi 403 ile reddedilir.
- Oyun ayarları › Ortamlar ve alan adları sekmesinde ilgili ortamın Alan adları alanına oyun sayfanızın alan adını yazın (satır başına bir alan adı; örneğin
oyun.example.com). Joker karakter, IP ve port kabul edilmez. - Bir gerekçe yazın ve Alan adlarını kaydet’e basın.
Alan adı girmezseniz sunucunun genel izinli listesi geçerlidir; bu liste operatörün ayarıdır. Ayrıntılar: Mimari ve barındırma.
6. Tarayıcıdan ilk oyuncu girişi (misafir)
Oyun sayfanız API’yi ya aynı origin’den (ters vekil) ya da alan adı bir ortama bağlıysa doğrudan Open Play adresinden (CORS) çağırır (bkz. Mimari ve barındırma). Aşağıdaki kod kayıtlı oturumu geri yükler; yoksa misafir oturumu açar. environmentId, ortamın UUID’sidir.
import { createPlayerClient, type PlayerClient } from "@ferdiunal/open-play-ts";
/**
* Tarayıcıdaki oyun sayfasından oyuncu oturumu açar: kayıtlı oturum varsa onu geri yükler,
* yoksa misafir oturumu açar. `baseUrl` oyun sayfasıyla aynı origin'dir (aynı köken kuralı).
*/
export async function signInAsGuest(environmentId: string): Promise<PlayerClient> {
const client = createPlayerClient({ baseUrl: window.location.origin, environmentId });
// restore() yalnızca bakar; oturum yoksa misafir yaratmaz.
const restored = await client.session.restore();
const session = restored.status === "authenticated" ? restored : await client.session.signInGuest();
console.log("oyuncu:", session.playerId, "misafir mi:", session.isGuest, "ad:", session.displayName);
return client;
}
SDK sizin yerinize misafir sırrını üretip saklar, CSRF belirtecini alır ve çerezleri yönetir. Aynı tarayıcıda sayfayı yenilediğinizde restore() aynı oyuncuyu geri getirir.
Aynısı ham REST ile
Aşağıdaki betik SDK’nın arka planda yaptığını gösterir (HTTPS gerekir; sunucu Secure çerez yazar):
export OPEN_PLAY_ENV="<ortam-kimliği-uuid>"
JAR="$(mktemp)"
# 1) CSRF belirteci al (çerez kavanozuna da yazılır)
TOKEN="$(curl -sS -c "$JAR" "$OPEN_PLAY_URL/v1/auth/csrf" | jq -r .token)"
# 2) 32 baytlık rastgele misafir sırrı: 64 küçük harfli onaltılık karakter. Sakladığınız sürece aynı oyuncuya döner.
BOOTSTRAP="$(openssl rand -hex 32)"
# 3) Misafir girişi
curl -sS -b "$JAR" -c "$JAR" -X POST "$OPEN_PLAY_URL/v1/auth/sign-in/guest" \
-H "content-type: application/json" \
-H "x-crx-env: $OPEN_PLAY_ENV" \
-H "x-csrf-token: $TOKEN" \
-d "{\"bootstrap_token\":\"$BOOTSTRAP\"}"
Yanıt (200; ilk kez ise is_new_player true):
{
"player": { "id": "0192…", "display_name": "Guest", "email": null, "email_verified": false, "is_guest": true, "image": null, "created_at": "2026-11-03T10:00:00+00:00" },
"tokens": { "session_token": "<64 hex>", "refresh_token": "<64 hex>", "access_token": "<jwt>", "expires_in_secs": 900 },
"is_new_player": true
}
Çerez kavanozunda artık __Secure-crx.session ve __Secure-crx.refresh vardır. Oturumu doğrulayın:
curl -sS -b "$JAR" "$OPEN_PLAY_URL/v1/auth/session" -H "x-crx-env: $OPEN_PLAY_ENV"
Her durum değiştiren istekte CSRF belirteci tek kullanımlıktır: yanıtın x-csrf-token başlığı bir sonrakini taşır. Ayrıntılar: Oturumlar ve CSRF, Misafir girişi.
7. Unity’den ilk oyuncu girişi
Unity paketini kurduktan sonra (Unity SDK) aşağıdaki bileşeni bir GameObject’e ekleyin. baseUrl ve environmentId alanlarını doldurun. WebGL derlemesinde baseUrl sayfayla aynı origin olmalıdır.
using System;
using OpenPlay;
using OpenPlay.Session;
using OpenPlay.Unity;
using UnityEngine;
/// <summary>
/// Misafir girişi: kayıtlı oturum varsa geri yükler, yoksa misafir oturumu açar.
/// Bir GameObject'e ekleyin; baseUrl ve environmentId alanlarını doldurun.
/// </summary>
public sealed class QuickstartGuest : MonoBehaviour
{
[SerializeField] private string baseUrl = "https://oyun.example.com"; // WebGL'de sayfayla aynı origin olmalı
[SerializeField] private string environmentId = ""; // ortam kimliği (UUID)
[SerializeField] private bool allowInsecureTransport = false; // yalnız http://localhost için
private OpenPlayClient _client;
private async void Start()
{
try
{
var options = OpenPlayUnity.Options(new Uri(baseUrl), Guid.Parse(environmentId));
options.AllowInsecureTransport = allowInsecureTransport;
_client = OpenPlayClient.Create(options);
var state = await _client.Session.RestoreAsync(); // oturum yoksa misafir YARATMAZ
if (state.Status != SessionStatus.Authenticated) state = await _client.Session.SignInGuestAsync();
if (state.Status == SessionStatus.Banned)
{
Debug.Log("Hesap askıya alındı."); // terminal durum; yalnız LogoutAsync ile çıkılır
return;
}
Debug.Log("hazır: oyuncu=" + state.PlayerId + " misafir=" + state.IsGuest);
}
catch (OpenPlayException ex)
{
Debug.LogError("Open Play hatası: " + ex.Kind + " (" + ex.Code + ")");
}
}
private async void OnDestroy()
{
if (_client != null) await _client.DisposeAsync();
}
}
Not
Unity SDK’sı yalnız Unity 6000.6.7f1 ile doğrulanmıştır. Ayrıntı için Unity SDK.
Sırada ne var?
- Kimlik doğrulama: e-posta, Google, hesap bağlama, oturum yönetimi.
- Karakterler, Ekonomi, Mağaza ve IAP: ilk özelliğinizi bağlayın.
- Webhook’lar: olayları sunucunuza imzalı alın.
- Üretim kontrol listesi: canlıya çıkmadan önce.
Mimari ve barındırma
Bu sayfa, oyununuzu Open Play ile nasıl konumlandıracağınızı anlatır: yığının parçaları, tarayıcı oyunlarının Open Play’i doğrudan (CORS) ya da ters vekille nasıl çağıracağı, ortama alan adı bağlama ve çerez/TLS gereksinimleri. Bir tarayıcı ya da WebGL oyunu yayımlayacaksanız bu sayfayı baştan sona okuyun.
Neyin nerede çalıştığı
Referans dağıtım bir Docker Compose yığınıdır:
| Parça | Görevi | Dışarı açık mı? |
|---|---|---|
| api | REST, WebSocket ve gerçek zamanlı yüzey; tüm iş mantığı | Yalnız ağ geçidi üzerinden |
| worker | Arka plan işleri: olay kuyruğu (outbox), webhook teslimatı, zamanlanmış işler, sıralama projeksiyonları | Hayır |
| PostgreSQL | Kalıcı veri | Hayır |
| Redis | Oran sınırları, CSRF kullanım kaydı, gerçek zamanlı anahtarlar | Hayır |
| converter | 3D model dönüştürme (yalnız amd64) | Hayır |
| public-gateway | Oyuncuya ve oyun sunucusuna açılan Caddy ağ geçidi; /v1/panel/* yolunu 404 ile keser | Evet (TLS’i önündeki katman sonlandırır) |
| admin-gateway | Yönetim paneli | Varsayılan olarak yalnız loopback |
| grpc-proxy | Güvenilen servisler için gRPC | Varsayılan olarak yalnız loopback |
Oyuncu tarayıcısı ──HTTPS──▶ oyun.example.com ─┬─ / ▶ oyununuzun statik dosyaları
└─ /open-play/* ▶ Open Play public-gateway ▶ api
Oyun sunucunuz ───────HTTPS──────────────────────────────────▶ Open Play public-gateway ▶ api
Open Play worker ──imzalı webhook──────────────────────────────▶ sizin sunucunuz
Public TLS, bu yığının içinde sonlandırılmaz; Cloudflare, bir yük dengeleyici ya da bir Caddy/nginx girişi gerekir. Panel çerezi Secure olduğundan panel de HTTPS ister. Kurulum, kaynak bütçeleri ve ağ ayrıntıları için üretim dağıtımı rehberine (docs/production-and-adapters.tr.md) bakın.
Not
gRPC arayüzü oyun geliştiricisi için dışa açık bir kanal değildir; varsayılan olarak yalnız loopback’te dinler ve SDK’lar onu kullanmaz.
Tarayıcıdan çağrı: doğrudan CORS ya da ters vekil
Oyununuzun alan adı ortamın alan adı listesindeyse tarayıcı oyununuz Open Play’i doğrudan çağırabilir. Sunucu, kamusal API’de (panel ve kurulum uçları hariç) CORS (cross-origin resource sharing, çapraz kaynak paylaşımı) başlıkları gönderir. İzin kümesi, panelde Oyun ayarları › Ortamlar ve alan adları altında tüm ortamlara yazılmış alan adları ile operatörün genel izinli listesinin (CRX_AUTH_TRUSTED_ORIGINS) birleşimidir; oyuna özel bir ayar yoktur. Örneğin oyun https://oyun.example.com adresinde, Open Play https://open-play.example.com adresinde çalışıyorsa ve oyun.example.com bir ortamın alan adıysa, oyun baseUrl: "https://open-play.example.com/open-play" ile doğrudan konuşur.
Kurallar:
- İzinli origin tam olarak
https://<alan adı>biçimindedir (yol yok, varsayılan olmayan port yok). YanıtAccess-Control-Allow-Originolarak o origin’i aynen yansıtır veAccess-Control-Allow-Credentials: trueekler;*hiçbir zaman kullanılmaz, bilinmeyen origin’e başlık verilmez. - Önkontrol (preflight,
OPTIONS) izinli origin için204, izinsiz için403döner;Access-Control-Max-Age600 sn’dir. - Üretim dışı ortamlarda (
CRX_ENVdevelopment ya da test) listedelocalhostya da127.0.0.1varsahttp://localhost:<port>vehttp://127.0.0.1:<port>de izinlidir. - Panelde yeni eklenen alan adı en geç birkaç saniyede (sunucu anlık görüntüsü 5 sn’de bir yenilenir) geçerli olur.
- CORS yetki değildir.
Origin/CSRF/ortam denetimleri aynen çalışır; CORS yalnız tarayıcının yanıtı okumasına izin verir. Panel yolu (/v1/panel/*) hiçbir koşulda CORS başlığı almaz. Gerçek zamanlı WebSocket el sıkışması değişmedi:Originortam başına denetlenir.
Uyarı
Oturum çerezi aynı site ister. Çerezler
__Secure-,HttpOnly,SameSite=Laxile yazılır. Oyun, Open Play’den farklı bir kayıtlı alan adındaysa (ör.oyun.example.comveopen-play.baska.dev) tarayıcı çapraz-sitefetchisteklerine oturum çerezini eklemez; CORS başlıkları doğru olsa da oturum kurulamaz. Aynı kayıtlı alan adının alt alanları (ör.oyun.example.comveopen-play.example.com) aynı sitedir ve çalışır. Farklı sitede bu desteklenmez; bu durumda aşağıdaki ters vekili kullanın.
Ters vekil hâlâ bir seçenektir. Oyunu ve API’yi aynı origin’den sunmak istiyorsanız (ya da oyun farklı bir sitedeyse), oyunun kendi ağ geçidinde API yolunu Open Play’e yönlendiren bir ters vekil (reverse proxy) kurarsınız; bu durumda CORS devreye girmez. Örnek (Caddy):
oyun.example.com {
# /open-play/ önekini sıyırıp Open Play public-gateway'e iletir.
handle_path /open-play/* {
reverse_proxy open-play-gateway:8080
}
# Geri kalan her şey oyununuzun statik dosyaları.
handle {
root * /srv/oyun
try_files {path} /index.html
file_server
}
}
Ters vekil kurulumunda istemci tarafı ayarı şudur:
| Ayar | Değer |
|---|---|
TypeScript baseUrl | https://oyun.example.com/open-play (SDK’lar yol önekini kabul eder) ya da önek kullanmıyorsanız window.location.origin |
Unity BaseUrl | aynı adres; Unity WebGL SDK’sı bugün sayfayla aynı origin’i şart koşar, aksi halde webgl_cross_origin_unsupported yapılandırma hatası alırsınız (sunucu CORS’u bunu kaldırmaz; bkz. Unity SDK) |
x-crx-env | ortam kimliği (SDK’lar environmentId ayarından gönderir) |
Ters vekilde dikkat edin:
- WebSocket yükseltmesi (
Upgrade/Connection) geçmelidir; gerçek zamanlı bağlantı/v1/realtime/wsüzerindedir. Caddyreverse_proxybunu kendiliğinden yapar; nginx’teproxy_http_version 1.1veUpgradebaşlıklarını açıkça verin. OriginveCookiebaşlıkları olduğu gibi iletilmelidir.- İstemci IP’si:
X-Forwarded-Forbaşlığını doğru yazın. Önde fazladan bir vekil varsa ve sunucuya güvenilen vekil adresleri tanıtılmadıysa bütün oyuncular tek IP kovasına düşer; belirtisi, farklı oyuncuların aynı anda429almasıdır. Bunu operatör ekibinizle çözün (bkz. Oran sınırları). - Panel yolunu açmayın.
/v1/panel/*yolu public-gateway’de404’tür; oyun alan adınız üzerinden panele yol vermeyin.
Çerez davranışı
| Çerez | Amaç | Özellikler |
|---|---|---|
__Secure-crx.session | Oyuncu oturumu | HttpOnly; Secure; SameSite=Lax; Path=/ |
__Secure-crx.refresh | Oturum yenileme | aynı |
__Secure-crx.csrf | CSRF çift gönderim (double-submit) çerezi | aynı; 15 dakikalık ömür |
Secure çerezler HTTPS ister. Yerel geliştirmede SDK’lar yalnız loopback adreslerinde (localhost, 127.0.0.1, ::1) düz http’ye izin verir; tarayıcınızın localhost için Secure çerezleri kabul edip etmediğini denetleyin, kabul etmiyorsa yerelde de HTTPS kullanın.
Alan adları ve güvenilir origin
Tarayıcı, durum değiştiren (POST, PUT, PATCH, DELETE) isteklere Origin başlığı ekler. Sunucu bu origin’in ilgili ortama bağlı bir alan adı olup olmadığını denetler:
- Ortama bağlı alan adı: panelde Oyun ayarları › Ortamlar ve alan adları › Alan adları alanına yazdığınız adlardır. Her satır tam bir alan adıdır (örneğin
oyun.example.com); joker karakter, IP ve port yoktur; ortam başına en çok 10 alan adı bağlanabilir. Aynı alan adı iki ortama bağlanamaz (409). - Genel izinli liste: operatörün sunucu ayarıdır (
CRX_AUTH_TRUSTED_ORIGINS: tam alan adı ya da*.alan). Ortamın kendi alan adı yoksa bu liste geçerlidir. - Bir alan adı başka bir ortama bağlıysa o alan adından gelen tarayıcı, bu ortama yazamaz ve bu ortamı okuyamaz (
403). Origingöndermeyen istemciler (oyun sunucunuz,curlgibi tarayıcı dışı istemciler) origin denetimine takılmaz; onları çerez kullanıyorlarsa CSRF çift gönderim koruması denetler.Sec-Fetch-Site: cross-siteileSec-Fetch-Mode: navigatebirlikte geliyorsa durum değiştiren istek reddedilir.
Gerçek zamanlı bilet de aynı origin kuralına bağlıdır: bilet tek kullanımlıktır ve alındığı origin’e bağlıdır.
Not
Unity yerel derlemeleri, bilet ve WebSocket isteklerinde yapılandırmadan türetilen sabit bir
Origingönderir (BaseUrl’in şeması, alan adı ve varsayılan olmayan portu;NativeOriginile değiştirilebilir). Bu origin’in ortamın alan adlarında ya da genel izinli listede bulunması gerekir. Bkz. Unity SDK.
Alan adı bağlama adımları: Ortamlar ve alan adları.
Oyun sunucunuzdan çağrı
Oyun sunucunuz sunucu anahtarıyla Open Play’e doğrudan (HTTPS) bağlanır. Ters vekil, CORS ya da alan adı bağlaması gerekmez (CORS yalnız tarayıcıyı ilgilendirir); ortam anahtardan çıkar. Anahtarı yalnız sunucu ortamında (ortam değişkeni ya da gizli yönetimi) tutun.
Oyuncunun kimliğini sunucunuzda doğrulamak için erişim JWT’sini çevrimdışı doğrulayabilirsiniz: Sunucuda doğrulama.
Webhook’lar (Open Play → sizin sunucunuz)
Worker, olayları imzalı HTTPS isteği olarak sizin adresinize gönderir. Adresiniz genel erişilebilir olmalı ve imzayı doğrulamalıdır. Bkz. Webhook’lar ve Güvenlik.
Yayın öncesi kontrol
Üretim kontrol listesi alan adı bağlama, anahtar yönetimi, TLS ve izleme maddelerini toplar.
Yapay zekâ araçlarıyla kullanım (MCP)
Open Play’in MCP (Model Context Protocol) sunucusu, yapay zekâ yardımcınızın (“misafir girişi nasıl yapılır”, “oyuncu verisi nasıl kaydedilir”, “eklenti nasıl çağrılır” gibi sorulara) tahmin yürütmek yerine bu sitedeki resmî belgelerden ve SDK API’sinden cevap vermesini sağlar. Sunucu yalnızca okur: Open Play sunucunuza, anahtarlarınıza dokunmaz; belgeler ve SDK dizini yalnızca herkese açık belge sitesinden okunur.
Kurulum
Barındırılan sunucu (önerilen)
Hiçbir şey kurmadan https://open-play.b4klabs.dev/mcp adresine bağlanın (Streamable HTTP, yalnız okur, kimlik doğrulama yok):
claude mcp add --transport http open-play https://open-play.b4klabs.dev/mcp
Cursor için .cursor/mcp.json, VS Code için .vscode/mcp.json (mcpServers yerine servers anahtarıyla) dosyasına şunu ekleyin:
{
"mcpServers": {
"open-play": {
"url": "https://open-play.b4klabs.dev/mcp"
}
}
}
Sunucu belge ve SDK dizinini https://open-play.b4klabs.dev/docs/mcp/index.json adresinden alır; dizin belge sitesiyle birlikte yenilenir, yani yeni bir belge yayımlandığında sunucuyu güncellemeniz gerekmez.
Yerel paket
Ağ yerine yerel süreç istiyorsanız paket @ferdiunal/open-play-mcp GitHub Packages üzerinden yayımlanır (kaynak: ferdiunal/open-play-mcp). Kullanıcı .npmrc dosyanıza @ferdiunal:registry=https://npm.pkg.github.com satırını ve read:packages izinli bir GitHub belirtecini ekleyin (belirteci belgeye ya da depoya yazmayın), sonra:
claude mcp add open-play -- npx -y @ferdiunal/open-play-mcp
Cursor ve VS Code için "command": "npx" ve "args": ["-y", "@ferdiunal/open-play-mcp"] kullanın. Yerel paket de aynı dizini canlı adresten alır; ağ yoksa son önbelleği, o da yoksa pakete gömülü anlık görüntüyü kullanır.
Araçlar
Araç adları ve açıklamaları İngilizcedir; belge içeriğini Türkçe istemek için lang: "tr" verin (varsayılan en).
| Araç | Ne yapar | Örnek girdi |
|---|---|---|
search_docs | Belgelerde arar; başlık, ara başlık ve gövde sırasıyla puanlanır; sonuç sayfa kimliği, açıklama ve genel adres verir | {"query": "guest sign in"} |
read_doc | Bir sayfanın tam markdown metnini verir (en çok 40 000 karakter) | {"page": "auth/guest"} |
list_docs | Sayfa kimliklerini ve başlıklarını listeler; section ile tek bölüm | {"section": "auth"} |
search_sdk | TypeScript ve Unity SDK’larında tür, işlev ve üye adı arar | {"query": "signInGuest", "sdk": "typescript"} |
get_sdk_symbol | Bir türün imzasını, özetini ve üyelerini verir; Tür.Üye biçimi desteklenir | {"name": "PlayerSession", "sdk": "unity"} |
Her belge sayfası ayrıca open-play-docs://<dil>/<sayfa> adresli bir kaynaktır (ör. open-play-docs://en/auth/guest) ve integrate_open_play adlı bir istem (platform: web, unity ya da server) entegrasyon adımlarını ve doğru sayfa bağlantılarını verir.
Sınır: Unity API dizini C# kaynağından hafif bir ayrıştırıcıyla çıkarılır; kalıtım ve genel tür parametreleri gibi ayrıntılar eksik olabilir. Kesin başvuru için Unity SDK sayfasındaki üretilmiş başvuruya bakın. SDK özetleri şimdilik Türkçedir, çünkü kaynak koddaki Türkçe yorumlardan gelir.
llms.txt ve llms-full.txt
MCP kullanamayan araçlar (ya da bir sohbete belge yapıştırmak istediğinizde) için belgeler llmstxt.org biçiminde düz metin olarak da yayımlanır:
| Dosya | İçerik |
|---|---|
https://open-play.b4klabs.dev/llms.txt | İngilizce dizin: her sayfanın başlığı, bir satırlık açıklaması ve .md kopyasının adresi |
https://open-play.b4klabs.dev/llms-full.txt | İngilizce belgelerin tamamı tek dosyada |
https://open-play.b4klabs.dev/docs/tr/llms.txt | Türkçe dizin |
https://open-play.b4klabs.dev/docs/tr/llms-full.txt | Türkçe belgelerin tamamı tek dosyada |
İngilizce dosyalar https://open-play.b4klabs.dev/docs/llms.txt ve https://open-play.b4klabs.dev/docs/llms-full.txt adreslerinde de durur. Her sayfanın markdown kopyası, HTML adresinin .html yerine .md ile bittiği adrestedir (ör. https://open-play.b4klabs.dev/docs/en/auth/guest.md). Dosyalar belge sitesiyle birlikte yenilenir.
Örnek sorular
- “Bir oyuncuyu misafir olarak nasıl girdiririm?” →
search_docs+read_doc(auth/guest). - “Oyuncu verisini nasıl kaydederim?” →
guides/player-data. - “Bir eklentiyi nasıl çağırırım?” →
plugins/calling-plugins. - “Unity’de
PlayerSessionhangi yöntemlere sahip?” →get_sdk_symbol.
İlk bakış için Hızlı başlangıç sayfasından başlayın. Ajanınızın oyununuzda Open Play’i doğru kullanması için deponuza koyacağınız hazır kural dosyası: Oyununuz için AGENTS.md.
Oyununuz için AGENTS.md
AGENTS.md, yapay zekâ kodlama ajanlarının (Claude Code, Cursor, Codex ve benzerleri) deponuzun kökünde otomatik okuduğu kural dosyasıdır. Open Play’i oyununuza bağlarken ajanların en sık yaptığı hatalar şunlardır: bir endpoint’i ya da header’ı tahmin etmek, sunucu anahtarını istemciye koymak, CSRF ve oturum kurallarını atlamak, eklenti şemasını sabitlememek, domain’i erken silmek ve eski önbellekteki JavaScript’i canlıda bırakmak. Bu sayfadaki şablon bu hataları önleyen kuralları tek dosyada toplar. Kurallar gerçek oyun entegrasyonlarında (ArenaRace ve LanternTide örnek oyunları) yaşanan sorunlardan çıkarılmıştır ve her kural ilgili belge sayfasına bağlanır.
Nasıl kullanılır
- Şablonu indirin:
https://open-play.b4klabs.dev/docs/AGENTS.md(ya da aşağıdaki bloğu kopyalayın) ve oyun deponuzun köküneAGENTS.mdolarak koyun. Zaten birAGENTS.mddosyanız varsa şablonu “Open Play entegrasyonu” başlığı altına ekleyin. - “Project facts” bölümündeki
<YOUR_DEV_ENV_ID>,<YOUR_PROD_ENV_ID>,<OPEN_PLAY_BASE_URL>,<DEV_GAME_ORIGIN>,<PROD_GAME_ORIGIN>ve<SDK_VERSION>yer tutucularını kendi değerlerinizle değiştirin. Ortam kimlikleri gizli değildir; anahtarları ve sırları dosyaya yazmayın. - Ajanınıza Open Play MCP sunucusunu ekleyin (Yapay zekâ araçlarıyla kullanım):
claude mcp add --transport http open-play https://open-play.b4klabs.dev/mcp. Şablon ajana öncesearch_docs,read_doc,search_sdkveget_sdk_symbolaraçlarını kullanmasını söyler; böylece ajan davranışı hafızasından değil güncel belgeden alır. - Oyununuzda kullanmadığınız bölümleri silin (örneğin eklenti kullanmıyorsanız 6. bölüm). Kendi kurallarınızı (kod stili, test komutları, dal düzeni) şablonun üstüne ya da altına ekleyin.
Şablonun kapsamı
| Bölüm | Neyi önler |
|---|---|
| MCP önce | Tahminle yazılmış endpoint, header ve alan adları |
| Anahtarlar ve ortamlar | Sunucu anahtarının istemciye sızması, dev ile prod karışması |
| Giriş ve oturum | Misafir akışı, Google popup + yönlendirme yedeği, yönlendirme tabanı (/auth/callback), CSRF yarışı, tek aktif oturum, hesap silme |
| Domain ve tarayıcı | Kayıtsız origin, canlı domain’i erken silmek, proxy’nin header kaybı |
| Oyuncu verisi | Bilinmeyen kaydetme formatı için ayrı sunucu, If-Match olmadan yazma |
| Eklentiler | Şema uyuşmazlığı, yeni anahtarla tekrar gönderilen komut, sürüm yükseltmede kapalı izin |
| Gerçek zamanlı | Bilet yeniden kullanımı, tekrar oynatılan girdi, gecikmeli girdi akışı |
| Önbellek ve dağıtım | CDN’in no-cache başlığını ezip eski JavaScript’i tutması |
| Hatalar ve sınırlar | Hata metnini ayrıştırmak, paylaşılan IP kovası |
| Test ve Yap / Yapma | Bitti demeden önce kontrol listesi |
Şablonun dili İngilizcedir: yapay zekâ araçları ve belge sitesinin MCP dizini İngilizce metinle en iyi çalışır. Şablon ayrıca https://open-play.b4klabs.dev/docs/llms.txt dizininde “Optional” bölümünde listelenir.
Not
Şablon bir kural dosyasıdır, Open Play’in garantisi değildir. Davranışın tek kaynağı belge sayfalarıdır; şablon ile bir sayfa ayrışırsa sayfa doğrudur. Şablonu gerçek bir ajan oturumunda deneyip kendi oyununuza göre sıkılaştırmanızı öneririz.
Şablonun tamamı
# AGENTS.md — integrating this game with Open Play
> Drop this file in the root of your game repository. Replace every `<PLACEHOLDER>` and delete rules that do not apply.
> Source and updates: https://open-play.b4klabs.dev/docs/AGENTS.md
This game uses **Open Play**, a game backend platform: player identity and sessions, player data (cloud save), characters, economy, store, rewards, social features, leaderboards, notifications, plugins and realtime connections. The game talks to Open Play over HTTP and WebSocket, through the TypeScript SDK (`@ferdiunal/open-play-ts`) or the Unity SDK. The game does **not** run its own account or save server for anything Open Play provides.
Docs root: https://open-play.b4klabs.dev/docs/en/ — every rule below links to its page.
## 0. Project facts (fill in)
- Environment ids (the `x-crx-env` value): dev `<YOUR_DEV_ENV_ID>`, prod `<YOUR_PROD_ENV_ID>`. One environment per stage; data is never shared between them.
- Open Play base URL: `<OPEN_PLAY_BASE_URL>` (the API address the browser calls).
- Game origins registered per environment: `<DEV_GAME_ORIGIN>`, `<PROD_GAME_ORIGIN>`.
- SDK version (exact, no `^`, no `latest`): `<SDK_VERSION>`.
## 1. Use the Open Play MCP server first
Before you write any call to Open Play, **look it up**. Never guess an endpoint, header, field or error code.
```bash
claude mcp add --transport http open-play https://open-play.b4klabs.dev/mcp
```
Cursor (`.cursor/mcp.json`) and VS Code (`.vscode/mcp.json`, key `servers`): `{"mcpServers":{"open-play":{"url":"https://open-play.b4klabs.dev/mcp"}}}`.
- `search_docs` then `read_doc` (for example `auth/oauth`) for behavior and HTTP contracts.
- `search_sdk` then `get_sdk_symbol` (for example `PlayerSession`, `sdk: "typescript"` or `"unity"`) for exact SDK signatures.
- The server is read-only and public; it never needs or sees a key. If the docs and your memory disagree, the docs win.
- No MCP available: read https://open-play.b4klabs.dev/docs/llms.txt (index) or `llms-full.txt` (everything).
Docs: [Using AI tools (MCP)](https://open-play.b4klabs.dev/docs/en/getting-started/ai-tools.html).
## 2. Keys and environments
- **Client** code (browser, WebGL, mobile) knows only the environment id and the player session. It carries **no secret**.
- A **server key** (`crx_live_<prefix>_<secret>`) lives only on your own server or backend-for-frontend (BFF): in its secret store, never in the client bundle, the repository, logs, or `.env` files that are committed. Use a separate key per environment and service, with an expiry.
- A client key is not a server key; calling a server endpoint with it is rejected. Player operations use the player session, not a key.
- Never point a dev build at the prod environment or the reverse. Read the environment id from per-stage configuration.
- Do not hard-code or print secrets, tokens, cookies or `x-csrf-token` values in code, tests, logs or analytics.
Docs: [Security](https://open-play.b4klabs.dev/docs/en/operations/security.html), [API keys](https://open-play.b4klabs.dev/docs/en/panel/game-settings-api-keys.html), [Production checklist](https://open-play.b4klabs.dev/docs/en/operations/production-checklist.html).
## 3. Sign-in and sessions
- **Guest first.** Open a guest session on first launch so the player plays at once; offer Google (or email) later and **link** it to the same player. Linking a guest upgrades the same player id; progress is kept.
- **Google OAuth:** try a popup window and fall back to a full-page redirect when the popup is blocked. Open the popup synchronously inside the click handler, before any `await`. Let the callback page hand the result back (for example through `BroadcastChannel`) and close itself.
- The server builds the Google `redirect_uri` from the configured **redirect base + `/google`**. The base must end at `/auth/callback` (not `/google`); the redirect URI registered with Google must be exactly `<base>/google`, and that path must be a page of your game that finishes the sign-in.
- The OAuth `code` and `state` are single-use: finish exactly once, then remove them from the address bar (`history.replaceState`). Use the SDK helpers; they bind `state` to the browser tab.
- A cookie session sends `x-crx-env` on every call and a CSRF token on every state-changing request. The token is **single-use and rotates**: never send two mutations at once with the same token, and keep the new token from each response. The SDKs serialize this for you; share the token between tabs with the SDK `csrf.channel` option. Retry a CSRF `403` once with a fresh token.
- Session lifetime is 30 days sliding, 180 days absolute. On `401` refresh or sign in again; do not loop.
- If the environment allows a **single active session**, a newer sign-in revokes the older one. Handle `reauthRequired` with a clear "signed in on another device" screen and a sign-in button, not a silent retry.
- Show the sign-in methods you actually enabled; hide the rest. Do not use SDK methods the docs mark as unsupported.
- **Account deletion** is a store requirement (Apple, Google Play): provide an in-game "Delete my account" action (`POST /v1/auth/account/delete`, `confirm: "delete_my_account"`). A linked account must have signed in within the last 10 minutes (`recent_sign_in_required`): ask the player to sign in again, then repeat.
- Verify identity on your own game server with the access JWT and the JWKS, never by trusting a client-sent player id.
Docs: [Auth overview](https://open-play.b4klabs.dev/docs/en/auth/overview.html), [Guest](https://open-play.b4klabs.dev/docs/en/auth/guest.html), [Google sign-in](https://open-play.b4klabs.dev/docs/en/auth/oauth.html), [Sessions and CSRF](https://open-play.b4klabs.dev/docs/en/auth/sessions-and-csrf.html), [Account linking](https://open-play.b4klabs.dev/docs/en/auth/account-linking.html), [Account deletion](https://open-play.b4klabs.dev/docs/en/auth/account-deletion.html), [Server-side verification](https://open-play.b4klabs.dev/docs/en/auth/server-verification.html).
## 4. Domains and calling from the browser
- Register **every origin your game runs on** in each environment's domain list (Game settings, Environments and domains): one full domain per line, no wildcards, no ports, at most 10, and a domain belongs to one environment only. An unregistered origin gets `403` on writes.
- Call Open Play either directly (your game domain is in the list; the server sends CORS headers with credentials) or through a same-origin reverse proxy that forwards `Cookie`, `Origin`, `x-crx-env`, `x-csrf-token`, `Idempotency-Key`, `If-Match` and the WebSocket upgrade, and that forwards the real client IP.
- **Moving to a new domain:** add the new domain and the new OAuth redirect first, test it, and only then retire the old one. **Removing a domain from an environment locks that live host out immediately.** Guest identities are per-origin: a new domain starts new guests.
- Send `Origin` only as the browser sets it. Never fake it in game code.
Docs: [Architecture and hosting](https://open-play.b4klabs.dev/docs/en/getting-started/architecture-and-hosting.html), [Environments and domains](https://open-play.b4klabs.dev/docs/en/panel/game-settings-environments.html).
## 5. Player data (cloud save)
- Use the generic per-player key-value store; **do not build a game-specific save server**. The value is an opaque JSON object the server never interprets; your game owns the format and its version field.
- Limits: key `^[a-z0-9][a-z0-9._-]{0,63}$`, at most 16 keys per player, 64 KiB per value, 60 writes per minute per player. Store large integers as strings.
- **There is no blind write.** Every `PUT` sends exactly one of `If-None-Match: *` (create) or `If-Match: "<version>"` (update). On `409 version_conflict` read the remote record, merge it with your own rule, retry. `428` means a precondition header is missing.
- Batch saves (on level end, on pause, on a timer), not every frame. Keep a local copy and reconcile on sign-in; a guest-to-Google link keeps the same player.
- Never write personal data you do not need. Player data is erased with the account.
Docs: [Player data](https://open-play.b4klabs.dev/docs/en/guides/player-data.html), [Idempotency and concurrency](https://open-play.b4klabs.dev/docs/en/reference/idempotency-and-concurrency.html).
## 6. Plugins (game-specific server logic)
- Call plugins only through **generated bindings**, never hand-written DTOs or copied field names. Get the schema document from `GET /v1/plugins/<PLUGIN_ID>/schema` and generate bindings from it.
- **Pin** `pluginId`, `schemaSha256`, `protocolVersion`, `codecProfile` and the plugin version in your release manifest. A mismatch must **fail closed**: show an "update the game" screen, never talk to the server with the wrong fields. After every server update compare the live digest with the pin (at startup or in CI).
- Every command carries an `Idempotency-Key`, generated **once** per logical action and reused on retries. If the outcome is uncertain (timeout, drop), resend with the **same key and body** or ask the result query; never generate a new key for the same action.
- Retry only when it is safe: idempotent calls on network errors, `429`, `503`, with exponential backoff and jitter, and honor `Retry-After`. Never retry business rejections (`422`).
- `int64` values travel as decimal strings. Send `If-Match` / `expectedVersion` when writing a shared resource; on `409` re-read first.
- If a plugin call suddenly returns `403`, check that the plugin is **enabled for that environment** and that the enabled version matches the server version. A server version bump needs its grant switched too.
Docs: [Plugins overview](https://open-play.b4klabs.dev/docs/en/plugins/overview.html), [Bindings and pinning](https://open-play.b4klabs.dev/docs/en/plugins/bindings.html), [Calling plugins](https://open-play.b4klabs.dev/docs/en/plugins/calling-plugins.html).
## 7. Realtime
- Use the SDK realtime client; if you implement the protocol yourself follow it exactly (single-use ticket, `Origin`, subprotocol).
- Ask for a **new ticket on every connection**. On a drop reconnect with exponential backoff, `Join` again with the last cursor (durable streams) or without one (ephemeral state), and on `ResyncRequired` drop the cursor and join fresh.
- Unacknowledged inputs are **not replayed**; continue from the latest snapshot. Pipeline inputs inside the SDK window (default 4 in flight); one input per round trip makes fast games feel laggy on real networks.
- Keep the frame rate below 40 per second; at most 4 sockets per player. Handle idle close (`4100`) with a "Continue" screen. An open socket does not keep the session alive.
- Notification and chat sockets cannot be opened straight from a browser; use inbox polling or REST.
Docs: [Realtime overview](https://open-play.b4klabs.dev/docs/en/realtime/overview.html), [Protocol](https://open-play.b4klabs.dev/docs/en/realtime/protocol.html), [Reconnect and limits](https://open-play.b4klabs.dev/docs/en/realtime/reconnect-and-limits.html).
## 8. Caching and deploys
- Serve your game's JavaScript modules and config (including the file that holds the environment id) with `Cache-Control: no-cache`, or content-hash the filenames. A stale config file after a deploy silently runs the old integration.
- If a CDN sits in front, set it to **respect existing headers** for HTML, JS and CSS. A CDN default browser TTL can override your `no-cache` and keep old code for hours.
- Never put a CDN cache in front of API responses that carry a cookie or `Authorization`.
- Deploy order when Open Play changes a plugin: new server and grant, then client with regenerated bindings. Pin the SDK version exactly and upgrade from the changelog.
Docs: [Production checklist](https://open-play.b4klabs.dev/docs/en/operations/production-checklist.html), [Versioning](https://open-play.b4klabs.dev/docs/en/reference/versioning.html).
## 9. Errors and rate limits
- Core endpoints return **plain-text** errors; plugin endpoints return a JSON envelope (`code`, `message`, `retryable`, `requestId`). Decide by status code and JSON `code`, **never by parsing message text**. Log `requestId` / `x-request-id`.
- There is no general per-key quota, but identity endpoints are limited per client IP (for example 30 guest sign-ins per minute). Behind a proxy or a shared network (NAT, a hosting platform's shared egress) many players share one IP: forward the real client IP.
- Back off on `429`, `503` and network errors; wait `Retry-After` when present. Never loop on `401`, `403` or `422`.
Docs: [Errors](https://open-play.b4klabs.dev/docs/en/reference/errors.html), [Rate limits](https://open-play.b4klabs.dev/docs/en/reference/rate-limits.html).
## 10. Testing checklist (before you call it done)
1. Fresh browser profile: guest sign-in, play, reload, same player and progress.
2. Guest upgraded to Google keeps progress; a second browser signs in to the same account and loads the save.
3. Two tabs open: no CSRF `403` storm; sign-out in one tab is handled in the other.
4. Same command sent twice with the same `Idempotency-Key` gives one effect.
5. Two devices write the same player-data key: the `409` is merged, nothing is lost.
6. Kill the network mid-command and mid-socket: the game recovers without duplicate effects.
7. Prod build points at the prod environment id and prod origin; dev at dev. No secrets in the bundle (search it).
8. Run these in a **headless browser or test harness** you control; do not test against another team's environment or real player data.
## Do
- Look up docs through MCP first; link the page you used in the PR description.
- Keep Open Play calls in one module/service layer, one writer per feature (never write the same state both locally and through Open Play).
- Handle every SDK session state, including `reauthRequired`, `banned` and `logoutUncertain`.
- Add a test with each integration change; report failing checks, never skip them.
## Don't
- Do not guess endpoints, headers, field names or error codes.
- Do not put a server key, token or cookie in client code, tests, logs or commits.
- Do not use `latest` or git/vendored copies of the SDK; do not hand-copy DTOs.
- Do not bypass CSRF, `Origin` or idempotency checks "just for testing".
- Do not remove a domain, redirect URI or environment that a live host still uses.
- Do not store save data in browser storage alone once the player can sign in.
- Do not write retry loops without backoff, or retry non-idempotent calls with new keys.
- Do not run production deploys or destructive operations unless the user explicitly asks.
Sonraki adım: Hızlı başlangıç ve Üretim kontrol listesi.
Kimlik doğrulamaya genel bakış
Bu sayfa oyuncunun Open Play’e nasıl giriş yaptığını özetler: hangi yöntemler var, hepsinin paylaştığı kurallar neler ve ayrıntı için hangi sayfaya gidilir. Oyuncu girişini bağlıyorsanız önce buradan başlayın.
Giriş yöntemleri
| Yöntem | Ne zaman? | SDK | Ayrıntı |
|---|---|---|---|
| Misafir | Hesapsız hızlı başlangıç; ilerleme aynı cihazda saklanır | TS: signInGuest · Unity: SignInGuestAsync | Misafir girişi |
| E-posta ve parola | Kalıcı hesap; parola sıfırlama ve değiştirme dahil | TS ve Unity: kayıt, giriş, terfi, parola işlemleri | E-posta ve parola |
| Google (OAuth) | Tek tıkla web girişi; doğrulanmış e-posta varsa mevcut hesaba otomatik bağlanır | TS: startGoogleOAuth, completeGoogleOAuth · Unity: yok | Google ile giriş |
| Yerel platform kanıtı (Apple, Game Center, Play Games) | Mobil yerel girişler | SDK yardımcısı henüz yok; yalnız HTTP ucu | Google ile giriş › Yerel kanıtlar |
| Magic link | E-postaya tek kullanımlık bağlantı | SDK yardımcısı henüz yok; sunucu ucu var | E-posta ve parola › Magic link |
Hangi yöntemlerin oyuncuya sunulacağı oyunun tercihidir; Google’ın çalışması için ortamda yapılandırılmış olması gerekir (Oyun ayarları › Giriş yöntemleri).
Giriş sonrası konular: Oturumlar ve CSRF, Hesap bağlama, Sunucuda doğrulama.
Hangi yöntemi seçmeliyim?
- Hesap zorunlu değilse misafirle başlayın; oyuncu ilerledikçe misafir terfisi ile e-postaya ya da Google’a bağlayın. Oyuncu kimliği (
playerId) değişmez. - Çoklu cihaz istiyorsanız e-posta/parola ya da Google gerekir; misafir kimliği cihazın sakladığı sırra bağlıdır.
- Mobil yerel giriş (Apple, Game Center, Play Games) için HTTP uçları vardır, ancak SDK’larda yardımcı yoktur.
Her çağrıda geçerli kurallar
Aşağıdaki kurallar /v1/auth/* altındaki tüm uçlar için geçerlidir.
1. Ortam başlığı. Her istek x-crx-env: <ortam-kimliği> taşır. Yoksa ya da UUID değilse 401.
2. İçerik türü. Gövdeli istekler Content-Type: application/json ile gönderilir.
3. CSRF. GET dışındaki her istek, çift gönderim (double-submit) CSRF koruması ister: __Secure-crx.csrf çerezi ve eşleşen x-csrf-token başlığı. Her başarılı kullanımda belirteç döner ve değişir. Önce GET /v1/auth/csrf ile bir belirteç alırsınız. Ayrıntı: Oturumlar ve CSRF.
4. Origin denetimi. Tarayıcıdan gelen durum değiştiren isteklerin Origin alan adı ortama bağlı olmalıdır. Bkz. Mimari ve barındırma.
5. Alan adları snake_case. İstek ve yanıt gövdeleri snake_case kullanır (display_name, bootstrap_token, old_password). İki istisna: GET /v1/auth/session yanıtında displayName ve POST /v1/auth/session/display-name gövdesi/yanıtı (displayName). SDK’lar bu farkı sizden saklar ve camelCase sunar.
6. Hata gövdeleri. Hatalar çoğunlukla düz metindir (permission denied, rate limited…). JSON gövdeli tek anlamlı hata, banlı hesap için 403 {"code":"account_banned","message":"account banned"} yanıtıdır. Durum kodları: 400 geçersiz girdi, 401 ortam ya da oturum yok/geçersiz, 403 reddedildi (yanlış parola, CSRF, süresi dolmuş token — ayrım bilerek sızdırılmaz), 409 çakışma, 422 işlenemez, 429 oran sınırı. Ayrıntı: Hatalar.
Başarılı giriş yanıtı
Giriş, kayıt, yenileme ve OAuth callback uçları aynı zarfı döndürür ve iki çerez yazar (__Secure-crx.session, __Secure-crx.refresh; HttpOnly; Secure; SameSite=Lax; Path=/, Max-Age=15552000 = 180 gün üst sınır):
{
"player": {
"id": "0192…",
"display_name": "Guest",
"email": null,
"email_verified": false,
"is_guest": true,
"image": null,
"created_at": "2026-11-03T10:00:00+00:00"
},
"tokens": {
"session_token": "<64 hex>",
"refresh_token": "<64 hex>",
"access_token": "<jwt>",
"expires_in_secs": 900
},
"is_new_player": true
}
| Alan | Anlamı |
|---|---|
player.id | Kalıcı oyuncu kimliği (UUID). Misafir terfisinde değişmez |
player.is_guest | Hesap hâlâ misafir mi |
tokens.session_token | Opak oturum belirteci. Çerez yerine Authorization: Bearer ile de kullanılabilir |
tokens.refresh_token | Yalnız /v1/auth/refresh ve /v1/auth/logout için |
tokens.access_token | Kısa ömürlü (15 dk) EdDSA JWT; oyun sunucunuzun çevrimdışı doğrulaması içindir. Bkz. Sunucuda doğrulama |
tokens.expires_in_secs | Erişim JWT’sinin ömrü (saniye) |
is_new_player | Çağrı yeni oyuncu yarattıysa true |
Uyarı
Tarayıcı oyunlarında oturum ve yenileme belirteçlerini JavaScript’te saklamayın; çerezler
HttpOnly’dir ve bunun için vardır. SDK’lar belirteç gövdelerini durumuna, günlüğe ve hatalara koymaz.
Oran sınırları
Kimlik uçları, sabit pencereli oran sınırlarına tabidir. Aşımda 429 ve düz metin rate limited döner; Retry-After başlığı yoktur: pencere süresini kendiniz beklemelisiniz. Başarısız denemeyi hemen yeniden göndermeyin.
| Sınır | Anahtar | Değer |
|---|---|---|
| Misafir açma (yeniden giriş dahil) | IP | 30 / 60 sn |
| E-posta girişi | IP | 5 / 60 sn |
| Başarısız e-posta girişi kilidi | adres + IP | 10 / 15 dk (kilitliyken doğru parola da 429; başarılı giriş hakkı iade eder) |
| Kayıt | IP · adres | 10 / 60 sn · 5 / 15 dk |
| Misafir terfisi | IP · misafir oyuncu · adres | 10 / 60 sn · 30 / 60 sn · 5 / 15 dk |
| Parola değiştirme | IP · hesap | 10 / 60 sn · 6 / 60 sn |
| Parola sıfırlama isteği (forgot) ve magic link | IP · adres | 5 / 60 sn · 5 / 15 dk |
| Parola sıfırlama (reset) | IP | 5 / 60 sn (forgot ve magic link ile ortak kova) |
| OAuth başlatma | IP | 30 / 60 sn |
| OAuth callback | IP | 60 / 60 sn |
| Görünen ad değiştirme | oyuncu | 10 / saat |
Sunucu önünde fazladan bir vekil varsa ve güvenilen vekil adresleri tanıtılmamışsa bütün oyuncular tek IP kovasına düşer. Bkz. Mimari ve barındırma.
Uç nokta özeti
| Yöntem ve yol | Oturum | Açıklama | Sayfa |
|---|---|---|---|
GET /v1/auth/csrf | gerekmez | CSRF belirteci üretir | Oturumlar ve CSRF |
POST /v1/auth/sign-in/guest | gerekmez | Misafir girişi | Misafir |
POST /v1/auth/sign-up/email | gerekmez | Kayıt | E-posta |
POST /v1/auth/sign-in/email | gerekmez | Giriş | E-posta |
POST /v1/auth/guest/upgrade/email | misafir oturumu | Misafiri e-postaya terfi ettirir | E-posta |
POST /v1/auth/change-password | var | Parola değiştirir; tüm oturumlar kapanır | E-posta |
POST /v1/auth/forgot-password | gerekmez | Sıfırlama e-postası ister | E-posta |
POST /v1/auth/reset-password | gerekmez | Token ile yeni parola | E-posta |
POST /v1/auth/sign-in/magic-link · GET /v1/auth/magic-link/verify | gerekmez | Magic link | E-posta |
GET /v1/auth/oauth/providers | gerekmez | Ortamda etkin sağlayıcılar | OAuth |
POST /v1/auth/sign-in/oauth/{provider} | gerekmez | OAuth başlatır ({url, state}) | OAuth |
GET /v1/auth/callback/{provider} · POST (form) | gerekmez ya da link için var | OAuth tamamlar | OAuth |
POST /v1/auth/native/{provider} | gerekmez | Yerel platform kanıtı | OAuth › Yerel |
POST /v1/auth/link/{provider} | var | Kimlik bağlamayı başlatır | Hesap bağlama |
POST /v1/auth/unlink/{provider} | var | Kimlik bağını çözer | Hesap bağlama |
GET /v1/auth/identities | var | Bağlı kimlikler | Hesap bağlama |
GET /v1/auth/session | var | Oturum ve profil | Oturumlar |
POST /v1/auth/session/display-name | var | Görünen ad değiştirir | Oturumlar |
POST /v1/auth/account/delete | var | Oyuncunun kendi hesabını siler (geri alınamaz) | Hesabı silme |
POST /v1/auth/refresh | yenileme belirteci | Oturumu yeniler (rotasyon) | Oturumlar |
POST /v1/auth/logout | yenileme belirteci | Oturumu kapatır | Oturumlar |
GET /v1/auth/jwks | gerekmez | JWT doğrulama anahtarları | Sunucuda doğrulama |
/v1/auth/organization/* uçları (oyuncu organizasyonları) kullanımdan kalkmaktadır: çalışır, ancak her yanıtı Deprecation başlığı taşır ve bu belgede anlatılmaz. /v1/auth/admin/* uçları sunucu anahtarıyla oyuncu yönetimi içindir (liste, ban, yeniden adlandırma, oturum iptali) ve uç nokta başvurusunda listelenir.
Banlı hesaplar
Operatör bir oyuncuyu banladığında oyuncunun tüm oturumları iptal edilir ve açık gerçek zamanlı bağlantısı kapanır. Oyuncu girişte nasıl görünür:
- Parolası doğru banlı e-posta hesabı:
403ve{"code":"account_banned","message":"account banned"}. Yanlış parola ya da bilinmeyen adres ayrımsız403düz metindir; ban durumu sızmaz. - Banlı misafir: aynı bootstrap sırrıyla ya da banlı oyuncunun eski oturumunu sunarak misafir girişi yapılırsa yine
403 account_banneddöner ve yeni oyuncu açılmaz. GET /v1/auth/sessionbanlı hesapta401döndürür (ban kodu sızmaz); refresh, OAuth callback ve misafir terfisi banlı sahibe ayrımsız reddedilir.- Yanıtta ban gerekçesi ya da bitişi yoktur.
- SDK davranışı: TypeScript’te oturum durumu
bannedolur; Unity’deSessionStatus.Banned. İkisi de yeni misafir açmaz ve kayıtlı misafir sırrını silmez (banlı oyuncu yeni misafir açarak kaçamasın). Oyuncuya hesabın askıya alındığını gösterin; yeniden deneme döngüsü kurmayın.
Misafir girişi
Misafir girişi, oyuncuya e-posta ya da parola sormadan kalıcı bir oyuncu kimliği verir. Oyuncu, cihazında saklanan bir sır sayesinde aynı hesaba geri döner; sonra isterse e-posta ya da Google ile kalıcı hesaba geçer. Bu sayfa HTTP ucunu, sırrın yaşam döngüsünü ve SDK davranışını anlatır.
Nasıl çalışır?
- İstemci 32 baytlık rastgele bir sır üretir ve 64 küçük harfli onaltılık karakter olarak yazar (
bootstrap_token). Bu sır, oyuncunun hesabının anahtarıdır. - İstemci sırrı
POST /v1/auth/sign-in/guestile gönderir. Sunucu sırrın yalnız SHA-256 özetini saklar; ham sır kaydedilmez, günlüğe yazılmaz. - Sır ilk kez geliyorsa yeni bir misafir oyuncu (
display_nameGuest) ve yeni bir oturum açılır (is_new_player: true). Aynı sır tekrar gelirse aynı oyuncu için yeni bir oturum açılır (is_new_player: false). - Sır, kullandıkça kayan 180 günlük bir ömre sahiptir. Süresi dolmuş ya da emekliye ayrılmış (örneğin hesap kalıcıya terfi etmiş) bir sır
403ile reddedilir.
Uyarı
Misafir sırrı bir yetkidir: sırrı bilen oyuncu hesabına girer. Başka oyunculara, günlüğe ya da analitiğe taşımayın.
İstek
Önce bir CSRF belirteci alın (Oturumlar ve CSRF); sonra:
POST /v1/auth/sign-in/guest
content-type: application/json
x-crx-env: <ortam-kimliği>
x-csrf-token: <csrf-belirteci>
cookie: __Secure-crx.csrf=<csrf-çerezi>
{"bootstrap_token":"<64 küçük harfli onaltılık karakter>"}
Gövde yalnız bootstrap_token alanını taşır.
Yanıt
200 ve ortak giriş zarfı:
{
"player": { "id": "0192…", "display_name": "Guest", "email": null, "email_verified": false, "is_guest": true, "image": null, "created_at": "2026-11-03T10:00:00+00:00" },
"tokens": { "session_token": "<64 hex>", "refresh_token": "<64 hex>", "access_token": "<jwt>", "expires_in_secs": 900 },
"is_new_player": false
}
Ayrıca iki Set-Cookie (__Secure-crx.session, __Secure-crx.refresh) ve yeni CSRF belirteci (x-csrf-token başlığı) döner.
| Durum | Anlamı |
|---|---|
400 | bootstrap_token biçimi bozuk (64 küçük harfli onaltılık karakter değil) ya da JSON bozuk |
401 | x-crx-env yok ya da UUID değil |
403 | Sır emekliye ayrılmış/süresi dolmuş, hesap silinmiş ya da CSRF/origin reddi (düz metin); banlı sahip için JSON {"code":"account_banned"} |
429 | IP başına 30 / 60 sn aşıldı (yeniden girişler de sayılır) |
Banlı misafir: istek, banlı bir oyuncuya ait eski bir oturum çerezi/Bearer taşıyorsa ya da sır banlı oyuncuya aitse yeni misafir açılmaz ve 403 account_banned döner; bu yanıt çerezleri silmez. Bkz. Banlı hesaplar.
Görünen ad
Misafirin adı Guest’tir. Oyuncu kendi adını POST /v1/auth/session/display-name ile değiştirebilir (gövde {"displayName":"…"}): ad NFC’ye çevrilir, kırpılır, iç boşluklar teklenir; kontrol/yön/sıfır genişlikli karakterler reddedilir; sonuç 2–24 karakter olmalıdır; oyuncu başına saatte 10 değişiklik. Unity’de Session.RenameAsync; TypeScript SDK’sında bu işlem için yöntem yoktur, ham REST kullanın.
TypeScript SDK
session.signInGuest() sırrı sizin yerinize üretir, istekten önce saklar ve CSRF belirtecini yönetir; böylece yanıt kaybolsa ya da çerez silinse aynı sır aynı misafire döner. session.restore() yalnızca mevcut oturumu geri yükler, misafir yaratmaz.
Sır saklama seçenekleri (createPlayerClient’ın guestBootstrap ayarı):
| Seçenek | Davranış |
|---|---|
| Varsayılan | Tarayıcıda localStorage (erişilemezse bellek); SSR/Node’da bellek |
false | Hiç saklanmaz; her signInGuest yeni bir misafir doğurur |
GuestBootstrapStore | Kendi deponuz (get/set/clear; Keychain, IndexedDB, dosya). Zaman aşımı 3 sn; depo hata verirse SDK belleğe düşer |
Davranış kuralları:
- Sır;
logout, başarılı e-posta girişi/kaydı,upgradeGuestveisGuest: falsegörülen oturumdan sonra silinir. Banlı durumdan yapılanlogoutsırrı silmez (banlı oyuncu yeni misafir açarak kaçamasın). - Sunucu sırrı reddederse (uç işleyicisinin
403’ü; CSRF/origin403’ü ve401sayılmaz) SDK sırrı bir kez siler ve yeni sırla tek yeniden deneme yapar. banneddurumunda yeniden deneme yapılmaz; yeni misafir açılmaz.
Uyarı
Varsayılan
localStoragedeposu aynı origin’deki her betiğe okunabilir; bir XSS açığı sırrı çalıp misafir hesabını devralabilir. Yüksek değerli hesaplardaguestBootstrap: falsekullanın ya da platformun güvenli deposunu verin.
import {
ACCOUNT_BANNED_CODE,
CrxError,
createMemoryGuestBootstrapStore,
createPlayerClient,
type PlayerClient,
} from "@ferdiunal/open-play-ts";
/** Varsayılan davranış: misafir kimliği tarayıcıda `localStorage`'da saklanır ve aynı oyuncuya döner. */
export function createDefaultClient(environmentId: string): PlayerClient {
return createPlayerClient({ baseUrl: window.location.origin, environmentId });
}
/** Kalıcı kimlik istemeyen oyun: her `signInGuest` yeni bir misafir oyuncu açar. */
export function createEphemeralGuestClient(environmentId: string): PlayerClient {
return createPlayerClient({ baseUrl: window.location.origin, environmentId, guestBootstrap: false });
}
/** Sunucu tarafında çalışan kod için (SSR/Node) isteğe özel bellek deposu; sır sunucu belleğinden çıkmaz. */
export function createRequestScopedClient(baseUrl: string, environmentId: string): PlayerClient {
return createPlayerClient({ baseUrl, environmentId, guestBootstrap: createMemoryGuestBootstrapStore() });
}
/** Misafir girişi; banlı hesabı ayrı bir ekranla karşılar. */
export async function signInGuestOrShowBan(client: PlayerClient, showBanned: () => void): Promise<void> {
try {
await client.session.signInGuest();
} catch (error) {
if (error instanceof CrxError && error.code === ACCOUNT_BANNED_CODE) {
showBanned(); // client.session.state.status === "banned"; yeniden deneme döngüsü kurmayın.
return;
}
throw error;
}
}
SSR’da (sunucuda çizim) SDK ortam localStorage’ını kullanmaz ve sır belleğe yazılır. Kalıcı misafir kimliği isteyen bir SSR uygulaması, istek başına kendi deposunu guestBootstrap ile vermelidir; yukarıdaki createRequestScopedClient örneği yalnızca süreçlik bellek deposu kullanır.
Unity SDK
Session.SignInGuestAsync() aynı akışı uygular; sır OpenPlayOptions.SecretStore içinde saklanır. Varsayılan PlayerPrefs deposu düz metindir ve güvenli depo değildir; üretimde Keychain/Keystore destekli kendi ISecretStore uygulamanızı verin (Unity SDK). Session.RestoreAsync() misafir yaratmaz. Banlı hesapta durum SessionStatus.Banned olur.
Misafiri kalıcı hesaba çevirme
Oyuncu ilerlemesini kaybetmeden kalıcı hesaba geçebilir; player.id değişmez:
- E-posta ve parola:
upgradeGuest - Google:
linkOAuth
Terfiden sonra misafir sırrı emekliye ayrılır; cihazdaki sır artık işe yaramaz.
E-posta ve parola
E-posta ve parola, oyuncuya cihazlar arası kalıcı bir hesap verir. Bu sayfada kayıt, giriş, misafirden kalıcı hesaba terfi, parola değiştirme ve sıfırlama akışlarını, istek ve yanıt örnekleriyle ve SDK çağrılarıyla bulacaksınız. Tüm çağrılar ortak kuralları (ortam başlığı, CSRF) izler.
Kurallar
- E-posta kırpılır ve küçük harfe çevrilir; tam bir
@içermeli ve alan kısmında nokta bulunmalıdır. Aynı ortamda bir adres yalnız bir hesapta olabilir. - Parola 8–128 karakter (Unicode karakter sayılır, bayt değil). Parola Argon2id ile saklanır.
- Görünen ad zorunludur; 1–100 karakter kullanın (sunucu bu sınırı misafir terfisinde uygular). Oyuncu sonradan adını 2–24 karakter kuralıyla değiştirebilir (Misafir girişi › Görünen ad).
- Bugün e-posta doğrulama ucu yoktur; kayıtta
email_verifiedfalsedöner. - SDK’lar istek göndermeden önce yalın sınır denetimi yapar (e-posta 3–320, parola en çok 1024, görünen ad en çok 256 birim; kontrol karakteri yok). Asıl politika sunucudadır.
Kayıt
POST /v1/auth/sign-up/email
content-type: application/json
x-crx-env: <ortam-kimliği>
x-csrf-token: <csrf-belirteci>
{"email":"[email protected]","password":"<en az 8 karakter>","display_name":"Ayşe"}
201 ve ortak giriş zarfı (is_new_player: true, player.is_guest: false, player.email dolu) + oturum çerezleri.
| Durum | Anlamı |
|---|---|
400 | E-posta biçimi ya da parola politikası ihlali |
409 | Adres bu ortamda kayıtlı (gövde adresi tekrar etmez) |
429 | IP başına 10 / 60 sn ya da adres başına 5 / 15 dk aşıldı |
Giriş
POST /v1/auth/sign-in/email
content-type: application/json
x-crx-env: <ortam-kimliği>
x-csrf-token: <csrf-belirteci>
{"email":"[email protected]","password":"<parola>"}
200 ve giriş zarfı (is_new_player: false).
- Yanlış parola ile bilinmeyen adres aynı yanıtı alır (
403düz metin); hangisi olduğu sızmaz. - Parolası doğru ama banlı hesap
403ve{"code":"account_banned","message":"account banned"}alır; çerez silinmez. - Aynı adres + IP için 15 dakikada 10 başarısız giriş hesabı kilitler; kilitliyken doğru parola da
429alır. Başarılı giriş hakkı iade eder. IP başına ayrıca 5 / 60 sn sınırı vardır. - İstekte başka bir oyuncunun (örneğin aynı tarayıcıdaki eski misafirin) kullanılabilir oturumu varsa, giriş başarılı olduktan sonra o oturum ailesi iptal edilir. Aynı oyuncunun oturumuna dokunulmaz.
Misafir terfisi
Misafir oyuncuyu aynı player.id ile kalıcı hesaba çevirir; ilerleme korunur. Misafir oturumu gerekir (çerez ya da Authorization: Bearer <oturum-belirteci>).
POST /v1/auth/guest/upgrade/email
content-type: application/json
x-crx-env: <ortam-kimliği>
x-csrf-token: <csrf-belirteci>
{"email":"[email protected]","password":"<parola>","display_name":"Ayşe"}
200; aynı player.id, is_guest: false, yalnız yeni oturum çifti. Terfi tek bir veritabanı işlemidir: kimlik eklenir, misafir sırrı emekliye ayrılır, eski oturumlar iptal edilir ve yeni oturum açılır.
| Durum | Anlamı |
|---|---|
400 | E-posta, parola ya da ad doğrulaması |
401 | Ortam başlığı ya da oturum yok |
403 | Oturum etkin değil, başka ortama ait ya da CSRF reddi |
409 | Adres bu ortamda başka bir hesapta kayıtlı; işlem geri alınır, misafir oturumu bozulmaz |
422 | Oyuncu artık misafir değil (yinelenen ya da eşzamanlı istek) |
429 | IP 10 / 60 sn, misafir oyuncu 30 / 60 sn ya da adres 5 / 15 dk aşıldı |
Yanıt kaybolursa (bağlantı koptu) eski misafir oturumları iptal edilmiş olabilir; kurtarma yolu normal e-posta girişidir.
Parola değiştirme
Oturum gerekir. Eski parola doğrulanır; başarıda tüm oturumlar (bu dahil) iptal edilir ve çerezler silinir; oyuncu yeniden giriş yapar.
POST /v1/auth/change-password
content-type: application/json
x-crx-env: <ortam-kimliği>
x-csrf-token: <csrf-belirteci>
{"old_password":"<mevcut>","new_password":"<yeni>"}
204. Hatalar: 400 yeni parola politikası ihlali, 403 oturum ya da eski parola reddi, 429 IP 10 / 60 sn ya da hesap 6 / 60 sn. Yanlış mevcut parola, giriş kilidinin sayacına da sayılır.
Parola sıfırlama
POST /v1/auth/forgot-passwordile sıfırlama e-postası istenir. Hesap olsa da olmasa da yanıt aynı200’dür (hesap varlığı sızmaz).- E-postadaki token ile
POST /v1/auth/reset-passwordçağrılır. Token tek kullanımlıktır ve 1 saat geçerlidir. Başarıda tüm oturumlar iptal edilir.
POST /v1/auth/forgot-password
content-type: application/json
x-crx-env: <ortam-kimliği>
x-csrf-token: <csrf-belirteci>
{"email":"[email protected]"}
POST /v1/auth/reset-password
content-type: application/json
x-crx-env: <ortam-kimliği>
x-csrf-token: <csrf-belirteci>
{"token":"<64 hex>","new_password":"<yeni>"}
reset-password hataları: 400 yeni parola politikası ihlali (token yanmaz, aynı bağlantıyla yeniden denenebilir), 403 token geçersiz/kullanılmış/süresi dolmuş ya da CSRF (ayrım sızmaz), 429 sınır aşımı (5 / 60 sn, forgot ve magic link ile ortak IP kovası).
Uyarı
Bilinen kısıt: Sıfırlama e-postasındaki bağlantı oyununuzun sayfasına değil, sunucunun API kökündeki
/v1/auth/reset-password?token=…adresine gider. Bu yoldaGETucu yoktur; yani bağlantıya tıklamak bir sayfa göstermez. Oyununuzda sıfırlamayı sunmak için oyuncunun e-postadakitokendeğerini kendi sıfırlama ekranınıza taşıması gerekir (örneğin kendi ters vekilinizde bu yolu bir oyun sayfasına yönlendirmek; bu yönlendirme bu repoda doğrulanmadı). E-posta gönderimi operatörün SMTP ayarına bağlıdır.
SDK
import { CrxError, ErrorKind, type PlayerClient } from "@ferdiunal/open-play-ts";
/** Yeni hesap açar ve oturumu başlatır. Adres kayıtlıysa sunucu 409 döner (`ErrorKind.Http`, status 409). */
export async function register(client: PlayerClient, email: string, password: string, displayName: string): Promise<void> {
await client.session.signUpEmail({ email, password, displayName });
}
/** Mevcut hesapla girer. Yanlış parola ile bilinmeyen adres aynı yanıtı alır; hangisi olduğu sızmaz. */
export async function login(client: PlayerClient, email: string, password: string): Promise<void> {
await client.session.signInEmail({ email, password });
}
/**
* Misafir ilerlemesini koruyarak kalıcı hesaba geçer: aynı `playerId`, yeni oturum.
* Önce misafir olarak girilmiş olmalıdır; adres başka bir hesapta kayıtlıysa 409 döner ve misafir oturumu bozulmaz.
*/
export async function upgradeGuestToEmail(client: PlayerClient, email: string, password: string, displayName: string): Promise<void> {
if (client.session.state.status !== "authenticated") await client.session.signInGuest();
try {
await client.session.upgradeGuest({ email, password, displayName });
} catch (error) {
if (error instanceof CrxError && error.kind === ErrorKind.Http && error.status === 409) {
throw new Error("Bu e-posta adresi başka bir hesapta kayıtlı.");
}
throw error;
}
}
/** Parola sıfırlama isteği: hesap olsa da olmasa da yanıt aynıdır. */
export async function requestReset(client: PlayerClient, email: string): Promise<void> {
await client.session.requestPasswordReset({ email });
}
/** E-postadaki token ile yeni parola belirler; başarıda tüm oturumlar kapanır, oyuncu yeniden giriş yapar. */
export async function finishReset(client: PlayerClient, token: string, newPassword: string): Promise<void> {
await client.session.resetPassword({ token, newPassword });
}
/** Oturum açıkken parola değiştirir; başarıda tüm oturumlar (bu dahil) kapanır. */
export async function changePassword(client: PlayerClient, currentPassword: string, newPassword: string): Promise<void> {
await client.session.changePassword({ currentPassword, newPassword });
}
| TypeScript | Unity | Uç |
|---|---|---|
signUpEmail | SignUpEmailAsync | sign-up/email |
signInEmail | SignInEmailAsync | sign-in/email |
upgradeGuest | UpgradeGuestAsync | guest/upgrade/email |
changePassword({ currentPassword, newPassword }) | ChangePasswordAsync | change-password (gövdede old_password) |
requestPasswordReset | RequestPasswordResetAsync | forgot-password |
resetPassword | ResetPasswordAsync | reset-password |
SDK’ların ortak davranışı:
- Parola ve token yalnız istek gövdesine yazılır; oturum durumuna, olay dinleyicilerine, hata nesnelerine ve günlüğe girmez.
- Kimlik uçlarında
403yalnızca CSRF katmanı reddettiyse (yanıtta yeni birx-csrf-tokenyoksa) SDK bir kez taze belirteçle yeniden dener. - İstek gönderildikten sonra bağlantı kaybolursa giriş uçları en çok bir oturum yoklaması yapar; sonuç belirsizse
UnknownOutcomehatası alırsınız. Parola değiştirme ve sıfırlama gibi sonuç döndürmeyen çağrılarda da kör yeniden deneme yapılmaz. upgradeGuestoturum yokken ağ isteği göndermez; sunucunun kesin ret yanıtları (4xx) misafir oturumunu düşürmez.changePasswordbaşarıdalogoutile aynı geçişi uygular (durumsignedOut).
Unity örneği:
using System.Threading.Tasks;
using OpenPlay;
using OpenPlay.Session;
using OpenPlay.Support;
/// <summary>E-posta ve parola akışları. Parola SecretText ile taşınır; günlüğe ve ToString()'e girmez.</summary>
public static class EmailAuth
{
public static Task<SessionState> Register(OpenPlayClient client, string email, string password, string displayName) =>
client.Session.SignUpEmailAsync(new SignUpEmailInput { Email = email, Password = new SecretText(password), DisplayName = displayName });
public static Task<SessionState> Login(OpenPlayClient client, string email, string password) =>
client.Session.SignInEmailAsync(new SignInEmailInput { Email = email, Password = new SecretText(password) });
/// <summary>Misafir ilerlemesini korur: aynı oyuncu, yeni oturum. Adres kayıtlıysa HTTP 409 gelir.</summary>
public static async Task<SessionState> UpgradeGuest(OpenPlayClient client, string email, string password, string displayName)
{
try
{
return await client.Session.UpgradeGuestAsync(new UpgradeGuestInput { Email = email, Password = new SecretText(password), DisplayName = displayName });
}
catch (OpenPlayException ex) when (ex.Kind == ErrorKind.Http && ex.Status == 409)
{
throw new System.InvalidOperationException("Bu e-posta adresi başka bir hesapta kayıtlı.");
}
}
public static Task RequestReset(OpenPlayClient client, string email) =>
client.Session.RequestPasswordResetAsync(new PasswordResetRequestInput { Email = email });
/// <summary>E-postadaki token ile yeni parola; başarıda tüm oturumlar kapanır.</summary>
public static Task FinishReset(OpenPlayClient client, string token, string newPassword) =>
client.Session.ResetPasswordAsync(new ResetPasswordInput { Token = new SecretText(token), NewPassword = new SecretText(newPassword) });
/// <summary>Görünen ad kuralı: normalize sonrası 2..24 karakter, saatte 10 değişiklik.</summary>
public static Task<SessionState> Rename(OpenPlayClient client, string displayName) =>
client.Session.RenameAsync(displayName);
}
Magic link
Magic link, e-postaya tek kullanımlık bir bağlantı gönderir. Sunucu uçları vardır, SDK yardımcısı henüz yoktur ve oyun içi bir akış olarak belgelenmemiştir.
POST /v1/auth/sign-in/magic-link
content-type: application/json
x-crx-env: <ortam-kimliği>
x-csrf-token: <csrf-belirteci>
{"email":"[email protected]","name":"Ayşe"}
200 (e-posta varlığı sızmaz); token yalnız e-postadadır, 5 dakika geçerlidir ve tek kullanımlıktır. Sınır: IP 5 / 60 sn, adres 5 / 15 dk. Token GET /v1/auth/magic-link/verify?token=<token> ile tüketilir; başarıda 200, giriş zarfı ve oturum çerezleri döner, geçersiz token 403 verir.
Uyarı
verifyucu dax-crx-envbaşlığı ister. Tarayıcıda e-postadaki bağlantıya doğrudan tıklamak bu başlığı göndermez ve401alır. Bir magic link akışı kurmak istiyorsanız token’ı oyun sayfanızın alıp başlıklı bir istekle doğrulaması gerekir; bu akış SDK’larda ve bu belgede kapsanmaz.
Google ile giriş
Google ile giriş, oyuncunun tek tıkla web üzerinden girmesini sağlar. Bu sayfa akışın iki adımını (başlatma ve tamamlama), callback sayfanızın ne yapması gerektiğini, mevcut e-posta hesabına otomatik bağlanma kuralını ve SDK’sı olmayan yerel platform kanıtlarının HTTP sözleşmesini anlatır.
Not
Web için SDK yardımcıları bugün yalnız Google içindir. Sunucuda Apple form callback’i ve genel bir sağlayıcı kaydı da bulunur, ancak onlar için SDK yardımcısı ve bu belgede ayrıntı yoktur.
Ön koşul: sağlayıcıyı yapılandırın
Google yalnız yapılandırılmış ortamlarda çalışır. Operatör (panelde süper yönetici) Oyun ayarları › Giriş yöntemleri › Google › OAuth bilgilerini düzenle ekranına Google istemci kimliğini, istemci sırrını ve yönlendirme tabanını girer; sır yalnız yazılır, bir daha okunamaz. Yapılandırılmamışsa GET /v1/auth/oauth/providers boş liste döner ve başlatma isteği 403 alır.
Google Cloud konsolundaki Authorized redirect URI, sunucunun kullandığı redirect_uri ile birebir aynı olmalıdır: <yönlendirme tabanı>/google. Örneğin taban https://oyun.example.com/auth/callback ise Google’a https://oyun.example.com/auth/callback/google kaydedilir. Bu adres, sizin oyun sayfanızdır (aşağıdaki callback sayfası). Oyuncu Google’dan oraya code ve state ile döner. Tabanın kendisi /google ile bitmemelidir: https://oyun.example.com/auth/callback/google yazılırsa sunucu …/google/google üretir (Google redirect_uri_mismatch verir); panel ve API bu değeri düzeltilmiş örnekle reddeder. Yapılandırma ayrıntıları operatöre aittir; panel yardımı: Giriş yöntemleri.
Akış
- Oyun sayfası
POST /v1/auth/sign-in/oauth/googleile{url, state}alır ve oyuncuyuurl’ye yönlendirir. - Oyuncu Google’da onay verir; Google oyuncuyu
<yönlendirme tabanı>/google?code=…&state=…adresine döndürür. - Callback sayfası
GET /v1/auth/callback/google?code=…&state=…çağrısıyla oturumu tamamlar. Yanıt ortak giriş zarfıdır ve oturum çerezlerini yazar.
1. Başlatma
POST /v1/auth/sign-in/oauth/google
content-type: application/json
x-crx-env: <ortam-kimliği>
x-csrf-token: <csrf-belirteci>
{"callback_url":"https://oyun.example.com/auth/callback/google"}
{"url":"https://accounts.google.com/o/oauth2/v2/auth?client_id=…&state=…&code_challenge=…","state":"<64 hex>"}
urlPKCE (code_challenge),stateve OIDCnoncetaşır;state10 dakika geçerlidir.callback_urlzorunludur (boşsa400), ancak yönlendirmeyi belirlemez: Google’a gidenredirect_urisunucuda yapılandırılan tabandan gelir. Adresi oyun sayfanızla tutarlı verin.403: sağlayıcı bilinmiyor, yapılandırılmamış ya da devre dışı.429: IP başına 30 / 60 sn.
2. Tamamlama
GET /v1/auth/callback/google?code=<code>&state=<state>
x-crx-env: <ortam-kimliği>
cookie: <varsa oturum çerezi>
Yanıt 200 ve giriş zarfı + çerezler. Tarayıcıda fetch(..., { credentials: "include" }) kullanın; çağrı ya API ile aynı origin’e gider ya da oyunun alan adı ortamın alan adı listesindeyse doğrudan Open Play adresine (CORS; bkz. Mimari ve barındırma). GET olduğu için CSRF belirteci istemez.
| Durum | Anlamı |
|---|---|
403 | state yok/tüketilmiş/süresi dolmuş, sağlayıcı reddi ya da imza/nonce hatası; bağlama niyetinde oturumsuz ya da başka oyuncunun oturumu. Ayrım sızdırılmaz |
409 | already exists: account_already_linked: Google kimliği başka bir oyuncuya bağlı; birleştirme yoktur |
422 | unprocessable: provider_already_linked: oyuncuda bu sağlayıcı zaten bağlı |
429 | Callback sınırı: IP başına 60 / 60 sn |
code ve state tek kullanımlıktır; callback’i ikinci kez çağırmayın.
TypeScript SDK
SDK state’i sizin yerinize tarayıcıya bağlar: başlatmada sessionStorage’a (crx-oauth-pending:v1) {state, provider, intent, startedAt} yazar, tamamlamada aynı sekmede denetler. Kayıt yoksa, 10 dakikadan eskiyse, bozuksa ya da sağlayıcı/state uyuşmuyorsa ağ isteği hiç gönderilmez ve oturum durumu değişmez; CrxError kodu OAuthBindingCode.Missing (yok/süresi dolmuş/bozuk) ya da OAuthBindingCode.Mismatch (başka tarayıcı/sekme) olur. Bu, başkasının callback bağlantısıyla oturum devralmayı engeller.
import { CrxError, OAuthBindingCode, type PlayerClient } from "@ferdiunal/open-play-ts";
// Google'ın kullanıcıyı döndürdüğü sayfa: sunucuda yapılandırılan yönlendirme tabanı + "/google" ile aynı yol olmalıdır
// (örn. taban https://oyun.example.com/auth/callback ise sayfa https://oyun.example.com/auth/callback/google).
const CALLBACK_PATH = "/auth/callback/google";
/** 1. adım: Google'a yönlendirin. State'i saklamanız gerekmez; SDK onu bu sekmeye bağlar (sessionStorage). */
export async function beginGoogleSignIn(client: PlayerClient): Promise<void> {
const callbackUrl = `${window.location.origin}${CALLBACK_PATH}`;
const { url } = await client.session.startGoogleOAuth(callbackUrl);
window.location.assign(url);
}
/** Misafir (ya da kayıtlı) oyuncunun hesabına Google kimliğini bağlar; tamamlama aynı callback sayfasında yapılır. */
export async function beginGoogleLink(client: PlayerClient): Promise<void> {
const callbackUrl = `${window.location.origin}${CALLBACK_PATH}`;
const { url } = await client.session.linkOAuth("google", callbackUrl);
window.location.assign(url);
}
/** 2. adım: Google'ın döndüğü sayfada (`/auth/callback/google`) code ve state ile oturumu tamamlayın. */
export async function finishGoogleSignIn(client: PlayerClient): Promise<string> {
const params = new URL(window.location.href).searchParams;
const code = params.get("code");
const state = params.get("state");
history.replaceState(null, "", window.location.pathname); // code ve state adres çubuğunda kalmasın
if (code === null || state === null) throw new Error("Callback adresinde code ya da state yok.");
try {
const session = await client.session.completeGoogleOAuth(code, state);
return session.playerId;
} catch (error) {
if (error instanceof CrxError && error.code === OAuthBindingCode.Mismatch) throw new Error("Giriş başka bir tarayıcıda başlatılmış.");
if (error instanceof CrxError && error.code === OAuthBindingCode.Missing) throw new Error("Giriş süresi dolmuş; yeniden başlatın.");
throw error;
}
}
/** Hesabıma bağlı sağlayıcı kimlikleri (sağlayıcı hesap kimliği ve e-posta dönmez). */
export async function linkedProviders(client: PlayerClient): Promise<string[]> {
const result = await client.session.listIdentities();
return result.identities.map((identity) => identity.provider);
}
startGoogleOAuth(callbackUrl)=startOAuth('google', callbackUrl);completeGoogleOAuth(code, state)=completeOAuth({ provider, code, state }).linkOAuth(provider, callbackUrl)bağlama akışını başlatır (aşağıya bakın); tamamlama yinecompleteOAuthiledir.listIdentities()bağlı kimlikleri verir.- Callback sayfasında
codevestate’i hemen adres çubuğundan kaldırın (history.replaceState). - Unity SDK’sında OAuth yardımcısı yoktur.
Uyarı
TypeScript SDK’sında
startIdentityTransferadlı bir yöntem görünür; sunucuda karşılığı yoktur (operatör destekli kimlik devri iptal edilmiştir). Kullanmayın.
Misafir ilerlemesini Google’a bağlama
Oturum açık bir oyuncu (misafir ya da kayıtlı) için linkOAuth kullanılır: POST /v1/auth/link/{provider} oturum ister ve {url, state} döner; tamamlama aynı callback ucudur, ancak callback isteği başlatan oyuncunun oturumuyla gelmelidir (çerez ya da Bearer), aksi halde 403.
- Oyuncu misafirse bağlama bir terfidir: aynı
player.id,is_guest: false, misafir sırrı emekliye ayrılır ve yeni oturum açılır. Misafirin kendi koyduğu ad korunur; ad hâlâ varsayılanGuestise Google adı uygulanır. - Oyuncu kayıtlıysa yalnızca yeni kimlik eklenir; adına dokunulmaz.
- Sağlayıcı başına tek kimlik vardır (
422 provider_already_linked). - Google kimliği başka bir oyuncuya bağlıysa
409 account_already_linkeddöner; ilerlemeler birleştirilmez.
Ayrıntılar: Hesap bağlama.
E-postayla otomatik bağlanma
Google ile yeni bir kimlikle giren oyuncunun e-postası, mevcut bir e-posta/parola hesabıyla eşleşiyorsa Google kimliği o hesaba otomatik bağlanır ve oyuncu o hesaba girer. Kuralın koşulları:
- E-posta Google tarafından doğrulanmış olmalıdır ve Google bu e-postanın güncel sahipliğine kefil olmalıdır: alan adı
gmail.com/googlemail.comya da imzalı ID token’ınhdtalebi e-postanın alan adına eşit (Google Workspace). Üçüncü taraf bir adresteemail_verifiedtek başına yetmez. - Eşleşme oyuncunun profil e-postasıyla (
players.email) yapılır; parolaya, mevcut oturumlara ya da profil e-postasına dokunulmaz. - Eşleşen hesap banlıysa bağ yazılmaz ve giriş reddedilir.
- Eşleşen hesapta zaten başka bir Google kimliği varsa otomatik bağlanma yapılmaz; yeni bir oyuncu açılır.
- Kayıt kapalı olsa da çalışır (yeni kayıt değildir).
- Bu davranışı kapatan bir ayar yoktur; yerel (native) ID-token yolunda bu bağlama uygulanmaz.
- Misafirin Google’a bağlanmasında (terfi) Google e-postası başka bir oyuncunun e-postasıyla eşleşiyorsa birleştirme yapılmaz;
409 account_already_linkeddöner.
Hesapta saklananlar: Google kimliği yalnız (ortam, sağlayıcı, sub) ile tanınır. Google’ın ad, doğrulanmış e-posta, dil ve profil görseli adresi kimliğe yazılabilir; sağlayıcının erişim ve yenileme belirteçleri saklanmaz. Bu bilgiler yalnız operatör panelinde görünür.
Yerel platform kanıtları
Mobil yerel girişler için tek bir uç vardır; SDK yardımcısı henüz yoktur (TypeScript’te ve Unity’de yok). Uç, ortak CSRF kurallarına tabidir ve çerez yazmaz: yanıtı Bearer olarak kullanın.
POST /v1/auth/native/{provider}
content-type: application/json
x-crx-env: <ortam-kimliği>
x-csrf-token: <csrf-belirteci>
provider | Gövde |
|---|---|
apple, google | {"id_token":"<OIDC ID token>","nonce":"<ham nonce>"} |
gamecenter | {"proof":{"player_id":"…","bundle_id":"…","public_key_url":"…","signature_b64":"…","salt_b64":"…","timestamp_ms":1700000000000,"game_player_id":"…"}} |
playgames | {"proof":{"server_auth_code":"…","application_id":"…"}} |
200 ve {player, tokens, is_new_player} (çerez yok). 400: sağlayıcı yerel girişe uygun değil ya da ortamda kayıtlı değil, zarf biçimi bozuk. 403: kanıt reddedildi (imza, sertifika zinciri, paket kimliği, zaman aşımı, nonce gibi hiçbir ayrım sızdırılmaz). Kullanım için ortamda ilgili platformun yapılandırılmış olması gerekir.
Not
Yerel kanıt yolu e-postayla otomatik bağlanma uygulamaz; aynı kişi yerel ve web yoluyla ayrı oyunculara bölünebilir.
Oturumlar ve CSRF
Giriş yapan oyuncuya bir oturum verilir. Bu sayfa oturumun nasıl taşındığını, ne kadar yaşadığını, nasıl yenilenip kapatıldığını ve durum değiştiren isteklerde zorunlu olan CSRF (çapraz site istek sahteciliği) korumasını anlatır. SDK kullanıyorsanız çoğunu sizin yerinize yönetir; ham REST yazıyorsanız bu sayfa sözleşmedir.
Oturum nasıl taşınır?
Sunucu oturumu iki yerden birinden okur; önce çerez, yoksa Authorization başlığı:
| Kanal | Kim kullanır? | Biçim |
|---|---|---|
| Çerez | Tarayıcı oyunları | __Secure-crx.session=<64 hex> (HttpOnly; Secure; SameSite=Lax; Path=/) |
| Bearer | Çerezsiz istemciler (komut satırı, bazı yerel istemciler) | Authorization: Bearer <session_token> (giriş yanıtındaki opak belirteç) |
Her oyuncu isteği ayrıca x-crx-env: <ortam-kimliği> taşır. Bearer yolunda taşınan opak oturum belirtecidir; erişim JWT’si değildir (o, oyun sunucunuzun çevrimdışı doğrulaması içindir: Sunucuda doğrulama).
Oturumu okuma
GET /v1/auth/session
x-crx-env: <ortam-kimliği>
{
"environment_id": "0192…",
"player_id": "0192…",
"session_id": "0192…",
"is_guest": false,
"active_organization_id": null,
"displayName": "Ayşe",
"email": "[email protected]"
}
email misafir ve e-postasız (yalnız Google) hesaplarda null’dır. Yanıt kişisel veri taşır ve Cache-Control: private, no-store ile gelir. Oturum yoksa, iptal edilmişse, süresi dolmuşsa ya da hesap banlıysa 401 döner (ayrım sızmaz).
Süreler
| Öğe | Süre |
|---|---|
| Oturum ve yenileme penceresi | 30 gün, kayan |
| Mutlak üst sınır | 180 gün (oturum ailesinin başlangıcından; hiçbir yolla aşılmaz) |
| Erişim JWT’si | 15 dakika |
Çerez Max-Age | 15 552 000 sn (180 gün); yalnız üst sınırdır, karar sunucudadır |
| CSRF çerezi | 15 dakika |
- Kayma: oyuncu oturumla günde en az bir kez istek yaptığında oturum bitişi 30 gün ileri alınır (üst sınırı aşmadan). Her yenileme (refresh) de süreyi 30 güne çeker.
- 30 gün hiç istek yapmayan oturum ölür. 180. günde aktif oturum bile biter; oyuncu yeniden giriş yapar (misafir, aynı sırla aynı hesaba döner).
- Gerçek zamanlı bağlantıyı açık tutmak oturumu uzatmaz.
Yenileme (refresh)
POST /v1/auth/refresh
content-type: application/json
x-crx-env: <ortam-kimliği>
x-csrf-token: <csrf-belirteci>
{}
Yenileme belirteci gövdede ({"refresh_token":"…"}) ya da __Secure-crx.refresh çerezinde taşınır (gövde öncelikli; çerez varsa gövde boş olabilir). Yanıt 200 ve yeni oturum ve yenileme çifti (çerezler de yenilenir; ortak giriş zarfı). Eski yenileme belirteci kullanılmış sayılır.
- Yeniden kullanım tespiti: kullanılmış bir yenileme belirtecinin tekrar sunulması tüm oturum ailesini iptal eder (çalıntı belirteç savunması).
- Hata:
403(belirteç geçersiz, süresi dolmuş, yeniden kullanılmış ya da CSRF reddi). - SDK’lar yenilemeyi gerektiğinde kendisi yapar; siz çağırmazsınız.
Çıkış
POST /v1/auth/logout
content-type: application/json
x-crx-env: <ortam-kimliği>
x-csrf-token: <csrf-belirteci>
{}
204; oturum iptal edilir ve çerezler silinir (Max-Age=0). Çağrı idempotenttir: bilinmeyen belirteç sessizce başarılı olur. Yenileme belirteci hiç yoksa (çerez ve gövde boşsa) 400 döner.
Parola değiştirme, parola sıfırlama ve operatör banı da oturumları iptal eder; ilgili sayfalara bakın.
Tek aktif oturum (isteğe bağlı)
Panelde Oyun ayarları › Giriş yöntemleri › Giriş ayarları › Tek aktif oturum anahtarı (yalnız süper yönetici), ortam başına açılır. Açıkken oyuncuya yeni oturum veren her giriş yolu, yeni oturum yazıldıktan sonra oyuncunun diğer oturumlarını iptal eder (“en son giriş kazanır”).
- Anahtar açıldığı anda açık oturumları kapatmaz; yalnız bir sonraki girişten itibaren uygulanır.
- Yenileme (refresh) bu politikayı tetiklemez.
- Diğer cihazdaki oturum bir sonraki istekte
401alır; SDK durumureauthRequiredolur. Oyununuz bu durumda “başka bir cihazdan giriş yapıldı” gibi bir ekran gösterebilir.
CSRF çift gönderim
Çerezle taşınan oturum, tarayıcı tarafından başka sitelerin isteklerine de otomatik eklenir. Bunu önlemek için durum değiştiren isteklerde çift gönderim (double-submit) CSRF koruması uygulanır: aynı belirteç hem çerezde hem başlıkta gelmelidir.
Kapsam. Aşağıdaki isteklerde zorunludur: /v1/auth/* altındaki tüm GET dışı istekler (giriş uçları dahil); oyuncu oturumuyla çağrılan eklenti komutları (ve POST ile çağrılan sorgular); oyuncu mağaza satın alma (yalnız çerez oturumunda; Authorization: Bearer oturumunda yalnız Origin ve Fetch Metadata denetimi uygulanır); gerçek zamanlı bilet isteği. GET istekleri muaftır. Sunucu anahtarıyla yapılan çağrılar CSRF’ye tabi değildir.
Akış.
GET /v1/auth/csrfçağrılır. Yanıt: gövde{"token":"<hex>"}, başlıkx-csrf-token: <aynı belirteç>veSet-Cookie: __Secure-crx.csrf=<mühürlü grant>.- Her durum değiştiren istek, çerezi (
__Secure-crx.csrf) ve başlığı (x-csrf-token) birlikte gönderir. Tarayıcı çerezi kendisi ekler; başlığı kodunuz ekler. - Başarılı her istekte belirteç döner (rotate): yanıt, yeni
x-csrf-tokenbaşlığı ve yeniSet-Cookietaşır. Bir sonraki istekte yenisini kullanın. - Belirteç tek kullanımlıktır. Eski belirteçle tekrar gönderilen istek
403alır (yeniden oynatma koruması).
# Belirteç al
TOKEN="$(curl -sS -c "$JAR" "$OPEN_PLAY_URL/v1/auth/csrf" | jq -r .token)"
# Kullan; yanıt başlığındaki yeni belirteci bir sonraki istek için sakla
curl -sS -D headers.txt -b "$JAR" -c "$JAR" -X POST "$OPEN_PLAY_URL/v1/auth/logout" \
-H "content-type: application/json" -H "x-crx-env: $OPEN_PLAY_ENV" -H "x-csrf-token: $TOKEN" -d '{}'
TOKEN="$(grep -i '^x-csrf-token:' headers.txt | awk '{print $2}' | tr -d '\r')"
Dikkat edilecekler:
- Eşzamanlı iki mutasyonu aynı belirteçle göndermeyin; biri başarılı olunca diğeri
403alır. İstekleri sıraya koyun. SDK’lar bunu tek bir kilitle yapar. - CSRF çerezi 15 dakika yaşar; süresi dolunca
403alırsınız. Taze belirteç alıp bir kez yeniden deneyin.403düz metindir ve CSRF ile yetki reddi arasında ayrım yapmaz; yanıtta yeni birx-csrf-tokenbaşlığı gelmediyse bunun CSRF katmanı reddi olduğunu anlarsınız. - Origin denetimi CSRF’nin ilk katmanıdır: tarayıcı isteğinin
Originalan adı ortama bağlı olmalıdır. Bkz. Mimari ve barındırma. - Çerezsiz (Bearer) istemciler de
/v1/auth/*ve eklenti uçlarında CSRF çerezini ve başlığını taşımalıdır (mağaza satın almadaki Bearer kolu istisnadır). Unity SDK’sı bunu yerel derlemede çerezleri kendisi yöneterek, WebGL’de tarayıcı çerezleriyle yapar.
SDK ve oturum durumları
TypeScript session.state.status değerleri:
| Durum | Anlamı |
|---|---|
signedOut | Oturum yok |
authenticating | Giriş ya da geri yükleme sürüyor |
authenticated | Oturum açık; playerId, sessionId, isGuest, displayName, email dolu |
refreshing | Yenileme sürüyor |
reauthRequired | Oturum kaybedildi ya da yenilenemedi; yeniden giriş gerekir |
signingOut / logoutUncertain | Çıkış sürüyor / sonucu belirsiz (yeniden denenebilir) |
banned | Hesap banlı; terminal |
Unity’de karşılığı SessionStatus (SignedOut, Authenticating, Authenticated, Refreshing, ReauthRequired, SigningOut, LogoutUncertain, Banned, Disposed) değerleridir; durum değişimleri Session.StateChanged olayıyla gelir.
import { CrxError, ErrorKind, createPlayerClient, type PlayerClient, type SessionState } from "@ferdiunal/open-play-ts";
/** Oturum durumunu arayüze bağlar; `state.status` değerleri kapalı bir kümedir. */
export function watchSession(client: PlayerClient, render: (label: string) => void): () => void {
const label = (state: SessionState): string => {
switch (state.status) {
case "authenticated": return state.isGuest === true ? "Misafir" : (state.displayName ?? "Oyuncu");
case "banned": return "Hesap askıya alındı";
case "reauthRequired": return "Yeniden giriş gerekiyor";
case "signedOut": return "Giriş yapılmadı";
default: return "…"; // authenticating, refreshing, signingOut, logoutUncertain
}
};
render(label(client.session.state));
return client.session.subscribe((state) => render(label(state))); // dönen işlev aboneliği kapatır
}
/** Sayfa kapanırken: sunucu oturumunu kapatmak için `logout`, yalnız yerel kaynakları bırakmak için `dispose`. */
export async function leave(client: PlayerClient, signOut: boolean): Promise<void> {
try {
if (signOut) await client.session.logout();
} catch (error) {
if (!(error instanceof CrxError && error.kind === ErrorKind.UnknownOutcome)) throw error;
// Yanıt kaybolduysa sunucu oturumu kapanmamış olabilir (durum `logoutUncertain`); gerekirse logout'u yeniden deneyin.
} finally {
await client.dispose();
}
}
export function createClient(environmentId: string): PlayerClient {
return createPlayerClient({ baseUrl: window.location.origin, environmentId });
}
dispose() yalnızca yerel kaynakları bırakır; sunucu oturumunu kapatmak için önce logout() çağırın. AuthenticatedSession.email yalnız oyuncunun kendi ekranı içindir; günlüğe ve analitiğe yazmayın.
Hesap bağlama
Bir oyuncunun kimliği player.id ile tanınır; giriş yöntemleri bu kimliğe bağlanan yollardır. Bu sayfa misafirin kalıcı hesaba geçişini, Google kimliğinin bağlanmasını ve çözülmesini, bağlı kimliklerin listelenmesini ve çakışma durumlarında ne olduğunu anlatır.
Not
Open Play hesapları birleştirmez. Bir kimlik başka bir oyuncuya bağlıysa istek reddedilir; iki oyuncunun ilerlemesi hiçbir yolla tek hesaba katılmaz. Tek istisna, Google’ın e-postayla otomatik bağlanma kuralıdır; o da yeni bir oyuncu açılmasını önleyip kimliği mevcut hesaba ekler.
Misafirden kalıcı hesaba (terfi)
Misafir oyuncu iki yoldan kalıcı hesaba geçer; ikisinde de player.id değişmez, misafir sırrı emekliye ayrılır ve yeni oturum açılır:
| Yol | Çağrı | Ayrıntı |
|---|---|---|
| E-posta ve parola | POST /v1/auth/guest/upgrade/email · TS upgradeGuest · Unity UpgradeGuestAsync | E-posta ve parola |
POST /v1/auth/link/google + callback · TS linkOAuth + completeOAuth | Google ile giriş |
Terfi yalnız misafir oyuncular içindir: misafir olmayan bir oyuncu için e-posta terfisi 422 verir. Google ile açılmış ya da zaten kayıtlı bir hesaba sonradan e-posta/parola eklenemez.
Bağlı kimlikleri listeleme
GET /v1/auth/identities
x-crx-env: <ortam-kimliği>
{
"player_id": "0192…",
"identities": [ { "provider": "google", "linked_at": "2026-11-03T10:00:00+00:00" } ]
}
- Oturum gerekir (yoksa
401). YanıtCache-Control: private, no-storetaşır. - Yalnız sağlayıcı kimlikleri listelenir (
google, …); e-posta/parola girişi listelenmez. Sağlayıcının hesap kimliği (sub), e-postası ve belirteçleri yanıtta yoktur. - TypeScript:
session.listIdentities(){ playerId, identities: [{ provider, linkedAt }] }döndürür (camelCase); yanıt sıkı doğrulanır, beklenmeyen biçimCrxError(Contract)olur ve oturumu düşürmez.
“Hesabım” ekranınızda “Google bağla” ya da “Google bağlı” göstermek için bu uç yeterlidir.
Kimlik bağlama
POST /v1/auth/link/{provider} oturumdaki oyuncu için OAuth akışı başlatır ve {url, state} döner; oyuncu url’ye yönlendirilir, dönüşte callback tamamlanır. Kurallar:
- Sağlayıcı başına tek kimlik: oyuncuda bu sağlayıcı zaten bağlıysa başlatma
422(unprocessable: provider_already_linked) verir. - Oturum bağı: callback, bağlamayı başlatan oyuncunun oturumuyla gelmelidir; oturumsuz ya da başka oyuncunun oturumuyla gelen callback
403alır. - Kimlik başka oyuncuda: Google kimliği başka bir oyuncuya bağlıysa callback
409(already exists: account_already_linked) verir; misafir ilerlemesi dokunulmadan kalır. - Doğrulanmış e-posta gerekmez; e-postasız hesaplar da bağlayabilir.
- Başlatma ve callback oranları: IP başına 30 / 60 sn ve 60 / 60 sn.
Kimlik çözme
POST /v1/auth/unlink/google
x-crx-env: <ortam-kimliği>
x-csrf-token: <csrf-belirteci>
204. Oturum gerekir. Hatalar:
| Durum | Anlamı |
|---|---|
400 | Son kalan sağlayıcı kimliği çözülemez (hesap kilitlenmesin diye) |
404 | Bu sağlayıcıya bağlı kimlik yok |
Not
Bugün bir oyuncunun genellikle tek sağlayıcı kimliği olduğundan, çözme çağrısı pratikte çoğunlukla
400alır. Uç, ikinci bir sağlayıcı eklendiğinde kullanılmak üzere yerindedir. Unlink için SDK yardımcısı yoktur; ham REST kullanın.
Çakışma tablosu
| Durum | Sonuç |
|---|---|
| Misafir, adresi başka hesapta kayıtlı bir e-postayla terfi etmeye çalışır | 409; misafir oturumu bozulmaz |
| Misafir, Google’a bağlanır ve Google kimliği başka oyuncuda | 409 account_already_linked |
| Misafir, Google’a bağlanır ve Google’ın doğruladığı e-posta başka oyuncunun e-postasıyla eşleşir | 409 account_already_linked (birleştirme yok) |
| Kayıtlı oyuncu aynı sağlayıcıyı ikinci kez bağlamaya çalışır | 422 provider_already_linked |
| Yeni Google kimliği, mevcut e-posta/parola hesabının e-postasıyla eşleşir (Google kefil) | Kimlik o hesaba otomatik bağlanır, oyuncu o hesaba girer |
| Banlı hesaba bağlanma | Reddedilir (403) |
Hesabı silme
Oyuncu, hesabını oyunun içinden kendisi silebilir. Apple App Store ve Google Play, hesap oluşturmaya izin veren uygulamaların uygulama içinden hesap silmeyi de sunmasını bekler; bu uç o beklentiyi karşılar. Silme geri alınamaz: ne oyuncu ne de operatör silinmiş hesabı geri getirebilir.
İstek
Önce bir CSRF belirteci alın (Oturumlar ve CSRF); sonra:
POST /v1/auth/account/delete
content-type: application/json
x-crx-env: <ortam-kimliği>
x-csrf-token: <csrf-belirteci>
{ "confirm": "delete_my_account" }
Oyuncu kimliği gövdeden gelmez, oturumdan gelir. confirm açık bir onaydır; eksik ya da başka bir değer 422 ile reddedilir. Başarılı istek 204 döner ve oturum ile yenileme çerezlerini siler.
Not
Bu uç yalnız oyuncu oturumuyla çalışır. Sunucu anahtarı (
Bearer crx_…) ile bir oyuncuyu bu uçtan silemezsiniz;401alırsınız. Bir oyuncuyu operatör olarak silmek için panelin oyuncu sayfasını kullanın.
Yakın giriş kuralı
- Misafir hesap doğrudan silinir.
- Bağlı kimliği olan hesap (e-posta/parola, Google ya da başka sağlayıcı) için oturumun giriş anı en çok 10 dakika önce olmalıdır. Aksi hâlde sunucu hiçbir şeyi silmeden
403ve şu gövdeyi döner:
{ "code": "recent_sign_in_required" }
Uygulama bu durumda oyuncuyu yeniden giriş yaptırır ve isteği tekrarlar. Süre, oturum yenilemesinden (refresh) değil girişin kendisinden sayılır; oyuncu gün boyu açık bir oturumda olsa bile yeniden giriş gerekir. Giriş anı kanıtlanamıyorsa sunucu güvenli tarafta kalır ve aynı 403’ü verir.
Neler silinir, neler kalır?
Silme tek bir veritabanı işleminde yapılır; ya hepsi olur ya hiçbiri:
| Veri | Sonuç |
|---|---|
| Oturumlar | Hepsi iptal edilir; açık gerçek zamanlı bağlantılar kapanır. |
| Bağlı kimlikler (e-posta/parola, Google…) | Ayrılır; parola ve sağlayıcı belirteçleri silinir. Aynı e-posta ya da aynı Google hesabı sonradan yeni bir oyuncu olarak başlayabilir. |
Oyuncu verisi (player data blob’ları) | Silinir. |
| Oyuncu satırı | Silinmez; anonimleştirilir (Deleted player, e-posta ve görsel temizlenir) ve silinmiş olarak işaretlenir. |
| Denetim olayları | Değişmez. Silme, yeni bir player_self_deleted olayı olarak eklenir; olayda e-posta ya da sağlayıcı kimliği yoktur. |
| Cüzdan defteri ve eklenti kayıtları | Değişmez (append-only); oyuncu satırı anonim olduğu için kişi bu kayıtlardan çözülemez. |
Uyarı
Eklentilerin kendi tablolarında tuttuğu serbest kişisel veri bu uçla silinmez. Eklentiniz kişisel veri saklıyorsa kendi silme akışınızı ayrıca bağlamanız gerekir.
Hata ve sınır tablosu
| Durum | Anlamı |
|---|---|
204 | Hesap silindi. |
401 | Oturum yok/geçersiz, oyuncu aktif değil (banlı ya da zaten silinmiş) ya da sunucu anahtarı sunuldu. Banlı oyuncu silme yoluyla yasaktan kaçamaz. |
403 gövdesiz | CSRF reddi. |
403 recent_sign_in_required | Yeniden giriş gerekli; hiçbir şey silinmedi. |
422 | confirm eksik ya da delete_my_account değil. |
429 | Oyuncu başına saatte 5 deneme aşıldı. |
SDK
TypeScript SDK’sında:
try {
await client.session.deleteAccount({ confirm: "delete_my_account" });
// state artık signedOut; oyuncuyu giriş ekranına götürün.
} catch (error) {
if (error instanceof CrxError && error.reason === "recent_sign_in_required") {
// oyuncuyu yeniden giriş yaptırın, sonra çağrıyı tekrarlayın
} else {
throw error;
}
}
Başarıda SDK, parola değişikliğindeki gibi oturumu sonlandırır ve { status: "signedOut" } döner. recent_sign_in_required durumunda oturum ve hesap değişmez. İstek gönderildikten sonra yanıt kaybolursa sonuç belirsizdir (UnknownOutcome): SDK kör tekrar yapmaz, gerçek durumu uygulamanın restore() çağrısı belirler. Unity SDK’da bu yöntem henüz yoktur.
Mağaza gizlilik notu
Uygulama içinden erişilebilir bir “Hesabımı sil” düğmesi koyun, tıklamadan önce açık bir onay isteyin ve düğmeyi deleteAccount çağrısına bağlayın. Hesap silinince oyuncuya hangi verinin kalacağını (cüzdan defteri anonimleşmiş olarak kalır) gizlilik metninizde belirtin. Silinen hesabın e-postası ve sağlayıcı kimliği serbest kalır; aynı kişi yeniden kayıt olursa sıfırdan başlar.
İlgili sayfalar
Oyuncuyu oyun sunucunuzda doğrulama
Oyun sunucunuz, kendisine gelen bir istek ya da bağlantının hangi oyuncuya ait olduğunu bilmek ister. Bu sayfa iki yolu anlatır: Open Play’in imzaladığı erişim JWT’sini çevrimdışı doğrulamak (JWKS ile) ve oturumu Open Play’e sorarak doğrulamak. Hangi yolun sizin için uygun olduğunu sayfanın sonundaki karşılaştırma tablosu söyler.
Uyarı
Bugünkü SDK sınırı: TypeScript ve Unity SDK’ları erişim JWT’sini uygulamaya açmaz; belirteç yalnızca ham REST giriş yanıtının gövdesinde (
tokens.access_token) bulunur. SDK kullanan bir istemci JWT’yi sunucunuza veremez. SDK’lı istemciler için aşağıdaki Yol B (oturum doğrulama) kullanılabilir. Bu eksiklik kayıtlıdır.
Yol A: erişim JWT’sini çevrimdışı doğrulama
Belirteç
Giriş, kayıt, yenileme ve OAuth callback yanıtları tokens.access_token döndürür: EdDSA (Ed25519) ile imzalı, 15 dakikalık compact JWT. Belirteç yalnız gövdededir; çerezde taşınmaz. Süresi dolunca POST /v1/auth/refresh yenisini verir.
Başlık: {"alg":"EdDSA","typ":"JWT","kid":"<anahtar-kimliği>"}. Yük:
| Alan | Anlamı |
|---|---|
sub | Oyuncu kimliği (UUID) |
env | Ortam kimliği (UUID) |
sid | Oturum kimliği (UUID) |
org | Etkin organizasyon (yoksa alan yok) |
iat, exp | Üretim ve bitiş anı: Unix milisaniye (saniye değil) |
Uyarı
iatveexpmilisaniyedir ve belirteçteiss/audyoktur. Standart JWT kütüphaneleriexp’i saniye sayar; milisaniye değerini uzak gelecekte bir tarih sanıp süresi dolmuş belirteci kabul eder. Kütüphane kullanırsanız imzayı ona doğrulatın amaexpdenetimini kendiniz yapın (exp > Date.now()).
Anahtarlar (JWKS)
curl -sS "$OPEN_PLAY_URL/v1/auth/jwks"
{"keys":[{"kty":"OKP","crv":"Ed25519","kid":"<anahtar-kimliği>","use":"sig","alg":"EdDSA","x":"<base64url genel anahtar>"}]}
Kimlik gerekmez. Sunucu imzalayıcıyı yayınlamadıysa 404 döner. Yanıtı önbelleğe alın ve yalnızca belirteçteki kid listede yoksa yenileyin; her istekte çekmeyin.
Doğrulama adımları
- Belirteci üç parçaya ayırın; başlıktaki
algdeğeriEdDSAolmalı, aksi halde reddedin. kidile JWKS’ten anahtarı bulun; yoksa JWKS’i bir kez yenileyin.- İmzayı
header.payloadmetni üzerinde Ed25519 ile doğrulayın. exp > şimdi (ms)olduğunu denetleyin.envdeğerini kendi ortam kimliğinizle karşılaştırın.
Uyarı
Aynı Open Play sunucusundaki bütün oyunların belirteçleri aynı JWKS ile doğrulanır.
envkarşılaştırmasını atlarsanız, başka bir oyunun oyuncusu sizin sunucunuzda geçerli görünür. Bu adım zorunludur.
Node.js (yalnız yerleşik node:crypto, bağımlılık yok):
import { createPublicKey, verify, type JsonWebKey } from "node:crypto";
/** Open Play erişim JWT'sinin (EdDSA) yük alanları. `iat` ve `exp` saniye değil, Unix MİLİSANİYEDİR. */
export interface AccessClaims {
readonly sub: string; // oyuncu kimliği
readonly env: string; // ortam kimliği
readonly sid: string; // oturum kimliği
readonly org?: string;
readonly iat: number;
readonly exp: number;
}
interface Jwks {
readonly keys: ReadonlyArray<JsonWebKey & { readonly kid?: string }>;
}
function decode(part: string): Buffer {
return Buffer.from(part, "base64url");
}
/**
* Oyuncunun erişim JWT'sini çevrimdışı doğrular: imza, süre ve ortam eşleşmesi.
* JWKS'i her istekte çekmeyin; `jwks` parametresini önbellekten verin (anahtar döndürülürse bilinmeyen `kid` gelince yenileyin).
*/
export function verifyAccessToken(token: string, jwks: Jwks, expectedEnvironmentId: string, nowMs: number = Date.now()): AccessClaims {
const parts = token.split(".");
const [header, payload, signature] = parts;
if (parts.length !== 3 || header === undefined || payload === undefined || signature === undefined) {
throw new Error("Biçimi bozuk JWT.");
}
const head = JSON.parse(decode(header).toString("utf8")) as { alg?: string; kid?: string };
if (head.alg !== "EdDSA") throw new Error("Beklenmeyen algoritma.");
const jwk = jwks.keys.find((key) => key.kid === head.kid);
if (jwk === undefined) throw new Error("Bilinmeyen anahtar kimliği; JWKS'i yenileyin.");
const publicKey = createPublicKey({ key: jwk, format: "jwk" });
const signed = Buffer.from(`${header}.${payload}`, "utf8");
if (!verify(null, signed, publicKey, decode(signature))) throw new Error("İmza doğrulanamadı.");
const claims = JSON.parse(decode(payload).toString("utf8")) as AccessClaims;
if (claims.exp <= nowMs) throw new Error("Belirtecin süresi dolmuş.");
// JWKS tüm oyunlar için ortaktır: başka bir ortamın oyuncusunu kabul etmemek için `env` mutlaka karşılaştırılır.
if (claims.env !== expectedEnvironmentId) throw new Error("Belirteç başka bir ortama ait.");
return claims;
}
/** JWKS'i çeker (kimlik gerekmez). */
export async function fetchJwks(baseUrl: string): Promise<Jwks> {
const response = await fetch(`${baseUrl}/v1/auth/jwks`);
if (!response.ok) throw new Error(`JWKS okunamadı: ${response.status}`);
return (await response.json()) as Jwks;
}
Sınırlar
- İptal görmez. Çevrimdışı doğrulama oturumun kapatıldığını, iptal edildiğini ya da oyuncunun banlandığını bilemez; belirteç
exp’ine kadar (en çok 15 dakika) geçerli görünür. İptal duyarlı olması gereken işlemlerde Yol B’yi kullanın ya da bu 15 dakikalık pencereyi kabul edin. - Anahtar döndürme. Anahtar değişimi sunucuyu yeniden başlatır; yeni
kidJWKS’te görünür. Önbelleğiniz bilinmeyenkidgörünce yenilenmelidir.
Yol B: oturumu Open Play’e sorma
Oyuncunun oturum belirtecini (çerez değeri ya da Authorization: Bearer belirteci) ve ortam kimliğini Open Play’e ileterek oyuncuyu çözersiniz. Tarayıcı oyununda oyunun origin’ine giden isteklerde oturum çerezi (__Secure-crx.session) zaten gelir; sunucunuz bu değeri okuyup Open Play’e Bearer olarak iletebilir.
curl -sS "$OPEN_PLAY_URL/v1/auth/session" \
-H "Authorization: Bearer $PLAYER_SESSION_TOKEN" \
-H "x-crx-env: $OPEN_PLAY_ENV"
200 ve {"environment_id","player_id","session_id","is_guest","displayName","email",…}. İptal edilmiş, süresi dolmuş ya da banlı oturum 401 verir. GET olduğu için CSRF belirteci gerekmez.
Uyarı
Oturum belirteci bir yetkidir. Açık metin günlüğe yazmayın, başka servislere yaymayın ve yalnızca TLS üzerinden iletin.
Hangi yolu seçmeliyim?
| Yol A: JWT çevrimdışı | Yol B: oturum sorgusu | |
|---|---|---|
| Open Play’e istek | Yok (JWKS önbellekte) | Her doğrulamada bir istek |
| İptal/ban görür | Hayır (en çok 15 dk gecikme) | Evet |
| Belirteç kaynağı | Yalnız ham REST giriş yanıtı; SDK vermez | Çerez ya da Bearer oturum belirteci; SDK’lı istemciyle de çalışır (tarayıcıda çerez) |
| Ortam doğrulaması | env talebini siz karşılaştırırsınız | Ortam, istekteki x-crx-env ile sınanır |
| Ne zaman? | Çok yüksek istek hacmi, iptal gecikmesi kabul edilebilir | Varsayılan öneri; oyuncu kimliği kritik işlemler |
Sunucu-sunucu çağrılarında oyuncu yerine sunucu anahtarı kullanılır (Kavramlar).
TypeScript SDK
TypeScript SDK’sı Open Play’e tarayıcıdan, Node.js’ten ve oyun motorlarının JavaScript katmanından bağlanmanın tipli yoludur: oyuncu girişi, eklenti komutları, gerçek zamanlı bağlantı ve sunucu anahtarıyla yönetim çağrıları. Bu sayfa kurulumu, giriş noktalarını, temel istemcileri ve hangi modüllerin tipli istemcisi olduğunu anlatır.
Not
Bu belge
@ferdiunal/open-play-ts0.1.15 sürümüyle doğrulanmıştır. Paket GitHub Packages’ta yayımlıdır; depo bugün özeldir, bu yüzden kurulum için yetkili bir GitHub belirteci gerekir.
API başvurusu: tüm tür ve işlevlerin üretilmiş başvurusu https://open-play.b4klabs.dev/docs/sdk/typescript/ adresindedir (@open-play/sdk ve @open-play/panel-kit).
Kurulum
Gereksinimler: Node.js 22 ya da üstü; paket yalnız ESM’dir (require ile yüklenmez). Tarayıcıda Fetch, AbortController ve BigInt destekli modern bir tarayıcı gerekir.
-
Kayıt defterini tanıtın. Projenizin kökündeki
.npmrcdosyasına kapsamı (scope) ve belirteç değişkenini yazın. Belirteçread:packagesyetkili bir GitHub klasik belirtecidir (ince ayarlı belirteç denenmedi); dosyaya değer yazmayın, ortam değişkeni kullanın:@ferdiunal:registry=https://npm.pkg.github.com //npm.pkg.github.com/:_authToken=${GITHUB_TOKEN} -
Paketi kurun:
export GITHUB_TOKEN="<read:packages yetkili belirteç>" npm install @ferdiunal/[email protected]pnpmaynı.npmrcile çalışır. Belirteci depoya, imaja ya da CI günlüğüne koymayın. -
İçe aktarın:
import { CrxClient, createPlayerClient } from "@ferdiunal/open-play-ts";
Uyarı
Paket adı
@ferdiunal/open-play-ts’tir. SDK deposundaki bazı dosyalarda ve örneklerde geçen@open-play/sdkadı yalnızca kaynak deposundaki iç addır; yayımlanan pakette kullanmayın.
Giriş noktaları
| İçe aktarma | İçerik | Ortam |
|---|---|---|
@ferdiunal/open-play-ts | CrxClient, createPlayerClient, createGameClient, hata ve sayı yardımcıları, katalog/mağaza/sıralama tipleri | Tarayıcı ve Node |
.../player | Oyuncu istemcisi ve eklenti bağlama oluşturma tipleri | Tarayıcı ve Node |
.../game | GameClient | Tarayıcı ve Node |
.../realtime | Gerçek zamanlı istemci tipleri | Tarayıcı ve Node |
.../browser | IndexedDB günlüğü ve sekme koordinasyonu (createBrowserAdapter) | Tarayıcı |
.../codegen | Bağlama ve tip üreticisi | Yalnız Node |
CLI: crx (npx crx --help). Kod üretimi bölümüne bakın.
İstemciler
CrxClient: sunucu anahtarıyla REST
CrxClient, API anahtarıyla çalışan tipli REST istemcisidir. Sunucu anahtarını yalnız güvenilen arka uçta kullanın; tarayıcıya ya da oyun paketine koymayın.
const client = new CrxClient({ baseUrl: "https://oyun.example.com/open-play", apiKey: serverKey });
ClientOptions: baseUrl, apiKey, isteğe bağlı fetch, timeoutMs (1–120 000 ms, varsayılan 15 sn), maxRetries (0–5, varsayılan 2), maxResponseBytes (varsayılan 2 MiB, en çok 16 MiB). Her çağrı { path, query, body, headers } girdisi ve isteğe bağlı { signal, timeoutMs, maxRetries } alır.
import { CrxClient, CrxError, ErrorKind } from "@ferdiunal/open-play-ts";
/**
* Sunucu anahtarıyla bir karaktere XP verir. Aynı `requestKey` ile yapılan tekrar aynı sonucu döndürür;
* `If-Match`, okuduğunuz sürümle yazdığınız sürümün çakışmasını yakalar.
*/
export async function grantXp(
baseUrl: string,
serverKey: string,
characterId: string,
amount: bigint,
requestKey: string,
): Promise<bigint> {
const client = new CrxClient({ baseUrl, apiKey: serverKey });
const current = await client.getCharacter({ path: { id: characterId } });
try {
const result = await client.executeCommand({
path: { id: characterId },
body: { type: "add_xp", amount },
headers: { "Idempotency-Key": requestKey, "If-Match": current.version.toString() },
});
return result.version;
} catch (error) {
if (error instanceof CrxError && error.kind === ErrorKind.Http && (error.status === 409 || error.status === 422)) {
// 409: sürüm çakışması; yeniden okuyup karar verin. 422: aynı anahtar başka bir gövdeyle kullanılmış.
// Yeni bir anahtarla kör yeniden deneme yapmayın.
throw error;
}
throw error;
}
}
/** Sayfalamayı SDK yürütür: imleç (cursor) opaktır, `break` yeni sayfa istemez. */
export async function countCharacters(baseUrl: string, serverKey: string, definitionKey: string): Promise<number> {
const client = new CrxClient({ baseUrl, apiKey: serverKey });
let total = 0;
for await (const _character of client.iterateListCharacters({ query: { definition: definitionKey, limit: 100 } })) {
total += 1;
}
return total;
}
Çağrı kuralları
baseUrlHTTPS olmak zorundadır; yalnızca loopback (localhost,127.0.0.1,[::1]) düz HTTP kabul eder. Adres kullanıcı bilgisi, sorgu ya da parça içeremez. Yönlendirmeler (redirect) izlenmez.- Anahtar yalnız
Authorizationbaşlığındadır; hata nesnelerinde ve hata ayıklama çıktısında görünmez. - Yeniden deneme yalnızca okuma
GET’lerinde ve gerçekten verilmiş aynıIdempotency-Keytaşıyan komutlarda yapılır. Geçici408,429,500,502,503,504ve güvenli işlemde ağ hatası, sınırlı üstel geri çekilmeyle denenir;Retry-Aftertoplam süre sınırı içindedir.409ve422yeniden denenmez. Oluşturma ve silme çağrıları otomatik tekrarlanmaz. - Komutlarda
If-Match(kaynağın okuduğunuz sürümü) veIdempotency-Keybaşlıklarını siz verirsiniz (Idempotency ve eşzamanlılık). - Sayfalama imleçleri opaktır;
iterate…yöntemleri (iterateListCharacters,iterateListCharacterEvents,iterateGetCharacterTimeline,iterateListRules,iterateListWebhooks) sayfaları sizin yerinize yürütür.
PlayerClient: oyuncu oturumu
createPlayerClient({ baseUrl, environmentId }) oyuncu tarafı istemcisidir (yalnız çerez kipi; sunucu anahtarı bu istemciye girmez). İçerdikleri:
| Üye | Ne yapar? |
|---|---|
session | Giriş, oturum durumu, yenileme, çıkış: Kimlik doğrulama |
plugin(binding) · publicPlugin(binding) | Eklenti komut/sorgu/modülleri: Eklenti bağlamaları |
realtime | Gerçek zamanlı soket (aşağıda) |
catalog | Panelden yönetilen eşya/veri/model/içerik grubu okuması (koşullu GET, watch… yoklayıcıları) |
leaderboard(key, { limit }) | Çekirdek skor tablosu okuması (limit 1–50) |
store.catalog() · store.buy() | Mağaza vitrini ve satın alma |
data.list() · data.get() · data.create() · data.update() · data.delete() | Oyuncu verisi (bulut kaydı): sürümlü yazım, çatışmada PlayerDataConflict; bkz. Oyuncu verisi |
notifications | Cihaz kaydı, gelen kutusu, web push |
dispose() | Yerel kaynakları bırakır (sunucu oturumunu kapatmaz) |
İlk kullanım için Hızlı başlangıç. Oturum durumları için Oturumlar ve CSRF.
createPlayerClient ağ isteğini kurucuda başlatmaz; baseUrl oyun sayfanızla aynı origin’dir (ters vekil) ya da oyunun alan adı ortama bağlıysa Open Play adresidir (CORS; aynı site gerekir) (Mimari ve barındırma).
GameClient: oyuncu + eklenti + realtime tek yaşam döngüsü
createGameClient, bir oyuncu istemcisini, eklenti bağlamalarını ve tek gerçek zamanlı soketi aynı yaşam döngüsünde tutar. dispose() çocuk bağlamaları ve kendi yarattığı oyuncu istemcisini kapatır; sunucu çıkışı için ayrıca game.session.logout() çağırın. Dışarıdan verdiğiniz PlayerClient GameClient tarafından sahiplenilmez.
import { createGameClient, type GameClient } from "@ferdiunal/open-play-ts";
import { createBrowserAdapter } from "@ferdiunal/open-play-ts/browser";
/**
* Bir oyunun oyuncu istemcisi, eklenti bağlamaları ve tek realtime soketi aynı yaşam döngüsünde tutulur.
* IndexedDB günlüğü (journal) yarım kalan eklenti komutlarının sayfa yenilendikten sonra kurtarılmasını sağlar.
*/
export function startGame(environmentId: string): { game: GameClient; stop: () => Promise<void> } {
const browser = createBrowserAdapter({ journal: "indexeddb", allowMemoryFallback: false });
const game = createGameClient({
playerOptions: { baseUrl: window.location.origin, environmentId, browser },
});
return {
game,
stop: async () => {
await game.dispose();
await browser.dispose();
},
};
}
journal: "indexeddb" yarım kalan eklenti komutlarının sayfa yenilendikten sonra kurtarılmasını sağlar. SSR/Node’da journal: "memory" seçin ve istemciyi istekler arasında paylaşmayın.
Gerçek zamanlı soket
client.realtime.connect() tek kullanımlık bilet alır, soketi açar ve kimlik doğrular; kopmada bileti yenileyip imleç/epoch ile kaldığı yerden sürdürür. Sunucu etkinlik göstermeyen soketi 4100 koduyla kapatır; onIdleClose verirseniz SDK otomatik yeniden bağlanmaz ve “Devam et” kararı sizindir. Protokol ayrıntıları Gerçek zamanlı bölümündedir.
import { createPlayerClient, isIdleClose, type PlayerClient } from "@ferdiunal/open-play-ts";
/**
* Realtime soketini açar. Sunucu, etkinlik göstermeyen soketi 4100 koduyla kapatır; `onIdleClose` verirseniz
* SDK otomatik yeniden bağlanmaz ve "Devam et" kararını size bırakır.
*/
export function createRealtimeClient(environmentId: string, showContinue: (resume: () => Promise<unknown>) => void): PlayerClient {
const client: PlayerClient = createPlayerClient({
baseUrl: window.location.origin,
environmentId,
realtime: {
onIdleClose: () => showContinue(() => client.realtime.connect()),
},
});
return client;
}
/** Durumu yoklayan uygulama aynı bilgiyi `lastClose` üzerinden okuyabilir. */
export function wasIdleClosed(client: PlayerClient): boolean {
return isIdleClose(client.realtime.lastClose);
}
/** Oturum açıldıktan sonra soketi kurar; bilet yenileme ve yeniden bağlanma SDK'dadır. */
export async function connect(client: PlayerClient): Promise<void> {
const connection = await client.realtime.connect();
console.log("realtime durumu:", connection.state);
}
Kapsam: hangi modülün tipli istemcisi var?
SDK, REST yüzeyinin tamamını sarmaz. Aşağıdaki tablo bugünkü durumu gösterir; “ham REST” olan modüller için uçları uç nokta başvurusunda bulur, HTTP çağrısını kendiniz yaparsınız (anahtar ve başlık kuralları aynıdır).
| Modül / alan | Tipli istemci | Nerede |
|---|---|---|
| Karakter tanımları, özellikler (trait), seviye eğrileri, karakterler, komutlar, geçmiş, istatistik | Var | CrxClient (sunucu anahtarı) |
| Kurallar | Var | CrxClient (createRule, listRules, dryRunRule, …) |
| Webhook uç kaydı (oluştur/listele/oku/sil) | Var | CrxClient; imza doğrulaması sizin kodunuzdur (Webhook’lar) |
| Klanlar | Var | CrxClient (20 işlem) |
| Katalog (eşya/veri/model) ve içerik grupları | Var | PlayerClient.catalog (oyuncu), CrxClient.catalog (sunucu) |
| Ödül tablosu kaydı ve verme | Var | CrxClient.createRewardTable, getRewardTable, grantRewardTable |
| Mağaza vitrini ve satın alma | Var | PlayerClient.store |
| Çekirdek skor tablosu okuma | Var | PlayerClient.leaderboard |
| Bildirimler: cihaz kaydı, gelen kutusu, web push | Var | PlayerClient.notifications |
| Eklentiler ve gerçek zamanlı | Var (şemadan üretilen bağlamayla) | PlayerClient.plugin, GameClient |
| Eşyalar ve envanter | Yok | Ham REST |
| Para birimleri, cüzdanlar, transferler, defter | Yok | Ham REST |
| Takas (trading), tüccarlar | Yok | Ham REST |
| Mağaza yönetimi, IAP doğrulama | Yok | Ham REST |
| Görev, VIP, günlük giriş ve NPC ödülleri | Yok | Ham REST |
| Partiler | Yok | Ham REST |
| Sunucu tarafı skor tabloları, turnuvalar | Yok | Ham REST |
| Sohbet | Yok | Ham REST/WebSocket |
| Sahneler, varlıklar | Yok | Ham REST |
| Magic link, hesap bağını çözme, yerel platform girişleri | Yok | Ham REST (Kimlik doğrulama) |
CrxClient’ta tipli işlem sayısı 45’tir (25 çekirdek + 20 klan) ve katalog ile ödül tablosu işlemleri bunlara eklenir. Tipli istemcisi olmayan bir modülü kullanmak sorun değildir; yalnızca tipleri elle yazarsınız.
Hatalar
Tüm hatalar CrxError olarak gelir: kind, status, attempts ve güvenli metadata (code, operation, deliveryState, reference, reason). HTTP gövdesi, istek URL’si ve anahtar hata nesnesine girmez.
ErrorKind | Anlamı |
|---|---|
Http | Sunucu hata durumu döndürdü (status dolu) |
Network | Bağlantı koptu; mutasyon uygulanmış olabilir |
Timeout | Toplam süre sınırı doldu |
Cancelled | signal ile iptal |
Contract | Girdi ya da yanıt sözleşmeye uymuyor |
Configuration | Güvensiz ya da bozuk ayar |
Auth | Oyuncu oturumu yeniden doğrulama istiyor |
UnknownOutcome | İstek gönderildi ama sonuç bilinmiyor; kör tekrar yapmayın, sonucu sorgulayın |
Storage | Günlük, tarayıcı koordinasyonu ya da OAuth bağ deposu kullanılamıyor |
Realtime · Backpressure · UpgradeRequired · ScopeChanged · Disposed | Gerçek zamanlı yaşam döngüsü, kuyruk dolu, eklenti sürüm uyuşmazlığı, oturum değişti, istemci kapatıldı |
Banlı hesap error.code === ACCOUNT_BANNED_CODE ile ayırt edilir (Kimlik doğrulamaya genel bakış).
Sayılar ve JSON
i64/u64alanlarbigint’tir; 32 bit alanlar sınır denetimlinumber’dır.9007199254740993nkayıpsız taşınır.- SDK yükünü
JSON.parse/JSON.stringifyile yeniden dolaştırmayın;parseJson,stringifyJson,encodeModel,decodeModelkullanın. Ondalık sayılarLosslessNumberolur. - Varsayılan sınırlar: JSON 2 MiB, derinlik 96, düğüm sayısı 200 000.
- Eklenti protokolünde
i64değerler ondalık dizgedir (plugin-v1-decimal-int64). Bkz. Sayılar ve kodlama.
Kod üretimi (crx)
Eklenti şemasından tipli bağlama ve karakter tanımından tip üretmek için CLI kullanılır (yalnız Node; ağ erişimi yoktur, girdi dosyadır, çıktı yalnız yeni dosyaya yazılır, --check bayt karşılaştırır):
# Eklenti bağlaması: şema özeti (sha256) sabitlenir; değişirse üretim reddedilir
npx crx plugins generate --input plugin.schema.json --schema-sha256 "$SCHEMA_SHA256" --output binding.ts
npx crx plugins generate --input plugin.schema.json --schema-sha256 "$SCHEMA_SHA256" --output binding.ts --check
# Karakter tanımı tipleri
npx crx types generate --input definition.json --version 1 --schema-sha256 "$SCHEMA_SHA256" --output hero.ts
Eklenti şemasını nereden alacağınızı ve schemaSha256 sabitlemenin anlamını Eklenti bağlamaları sayfası anlatır.
Bilinen sınırlar
- Yalnız çerez kipi vardır; oyuncu istemcisinde Bearer ya da sunucu anahtarı kipi yoktur.
- Erişim JWT’si uygulamaya açılmaz (Sunucuda doğrulama).
- Magic link, unlink ve yerel platform girişleri için yardımcı yoktur.
- Görünen ad değiştirme (
POST /v1/auth/session/display-name) için yöntem yoktur. - Sunucu CORS’u yalnız ortam alan adı listesindeki origin’lere verir; oturum çerezi
SameSite=Laxolduğundan oyun ile Open Play aynı sitede olmalıdır, değilse ters vekil kullanın.
Unity SDK
com.openplay.sdk, Unity’den Open Play’e bağlanan C# istemcisidir: misafir ve e-posta/parola oturumu, oturumun yeniden başlatmalar arasında geri yüklenmesi, eklenti komutları ve sorguları ve gerçek zamanlı soket. Bu sayfa kurulumu, kullanımı ve neyin doğrulandığını dürüstçe anlatır.
Uyarı
Paket yalnız Unity 6000.6.7f1 ile doğrulanmıştır; başka editör sürümleri ve çoğu platform doğrulanmadı (Doğrulanan platformlar). Bu belge paket sürümü 0.1.0 içindir.
API başvurusu: C# tiplerinin üretilmiş başvurusu https://open-play.b4klabs.dev/docs/sdk/unity/ adresindedir.
Kurulum
Paket, https://npm.pkg.github.com/@ferdiunal adresindeki GitHub Packages npm kayıt defterinden gelir. Paket adı kapsamsızdır (com.openplay.sdk); kapsam kayıt defteri adresindedir.
-
Kimlik. GitHub herkese açık paketlerde bile belirteç ister. Kullanıcı klasörünüzde
~/.upmconfig.tomloluşturun. Belirteçread:packagesyetkili bir klasik belirteçtir (ince ayarlı belirteç denenmedi) ve bir sırdır: depoya koymayın, günlüğe yazmayın.[npmAuth."https://npm.pkg.github.com/@ferdiunal"] token = "<read:packages yetkili belirteç>" alwaysAuth = true -
Manifest. Oyun projenizin
Packages/manifest.jsondosyasına kapsamlı kayıt defterini ve bağımlılığı ekleyin:{ "dependencies": { "com.openplay.sdk": "0.1.0" }, "scopedRegistries": [ { "name": "Open Play", "url": "https://npm.pkg.github.com/@ferdiunal", "scopes": ["com.openplay"] } ] } -
Unity’yi açın. İki bilinen davranış: Package Manager’ın arama ekranında paket görünmez (GitHub’ın arama uç noktası
405döner; paketimanifest.json’a elle yazarsınız) ve günlüktePackage 'com.openplay.sdk' has been installed without a signatureuyarısı çıkar (zararsızdır).
com.unity.nuget.newtonsoft-json 3.2.1 ve com.unity.modules.unitywebrequest bağımlılıkları kendiliğinden çözülür. Yedek yol olarak yerel yol ("com.openplay.sdk": "file:<yol>/sdks/unity") kullanılabilir; bu yalnız kaynak deposuna erişimi olanlar içindir.
Paket bir Basic Login örneği içerir (Package Manager › Open Play SDK › Samples).
Temel kullanım
OpenPlayClient.Create(OpenPlayUnity.Options(baseUrl, environmentId)) istemciyi kurar; Options ana iş parçacığı pompasını, PlayerPrefs deposunu ve platforma uygun taşımayı seçer. Hızlı başlangıçtaki bileşen kayıtlı oturumu geri yükler, yoksa misafir açar.
OpenPlayOptions ayarları:
| Ayar | Anlamı |
|---|---|
BaseUrl | API kökü. Mutlak https (geliştirmede loopback http); sorgu, parça ve kullanıcı bilgisi içeremez |
EnvironmentId | Ortam kimliği (x-crx-env); boş olamaz |
AllowInsecureTransport | Yalnız geliştirme: loopback adreslerinde (localhost, 127.0.0.1, ::1) düz http/ws. Varsayılan false |
NativeOrigin | Yerel derlemede bilet ve WebSocket isteklerinde gönderilen sabit Origin. Boşsa BaseUrl’den türetilir. Ortamın alan adlarında ya da genel izinli listede olmalıdır |
PageOrigin | Yalnız WebGL: sayfanın adresi; BaseUrl ile aynı origin olmalıdır (OpenPlayUnity.Options doldurur) |
SecretStore | Misafir sırrı ve yenileme belirtecinin kalıcı deposu (aşağıya bakın) |
TimeoutMs | Toplam istek süresi: 1–120 000, varsayılan 15 000 |
MaxResponseBytes | En büyük yanıt: 1 bayt–16 MiB, varsayılan 2 MiB |
UserAgent | Boşsa hiç gönderilmez |
Realtime | Gerçek zamanlı ayarları (AutoReconnect, ReconnectBaseMs, MaxReconnectAttempts, HeartbeatMs, AuthTimeoutMs, MaxPendingInputs, OnIdleClose) |
Yanlış ayar OpenPlayException ile ErrorKind.Configuration ve kodlu bir neden verir (örneğin base_url_scheme_invalid, insecure_transport_not_loopback, environment_id_required).
Oturum
client.Session:
| Yöntem | Ne yapar? |
|---|---|
RestoreAsync() | Kayıtlı oturumu geri yükler; yoksa misafir yaratmaz |
SignInGuestAsync() | Misafir girişi (Misafir) |
SignUpEmailAsync, SignInEmailAsync, UpgradeGuestAsync | E-posta kayıt/giriş/terfi (E-posta) |
ChangePasswordAsync, RequestPasswordResetAsync, ResetPasswordAsync | Parola işlemleri |
RenameAsync(displayName) | Görünen ad değiştirme (2–24 karakter, saatte 10) |
RefreshAsync() · LogoutAsync() | Yenileme ve çıkış |
StateChanged olayı · State | SessionState: Status, PlayerId, SessionId, IsGuest, DisplayName, Email |
SessionStatus: SignedOut, Authenticating, Authenticated, Refreshing, ReauthRequired, SigningOut, LogoutUncertain, Banned (terminal; yalnız LogoutAsync ile çıkılır), Disposed. Parola ve belirteçler SecretText ile taşınır; ToString() ve günlüklere girmez.
E-posta ve parola örnekleri için E-posta ve parola sayfasına bakın.
Sır depolama
Misafir sırrı ve yenileme belirteci ISecretStore ile saklanır. Varsayılan PlayerPrefs deposu düz metindir ve güvenli depo değildir (iOS Keychain, Android Keystore yok). Üretimde platformun güvenli deposuna yazan kendi ISecretStore uygulamanızı verin:
using System.Threading;
using System.Threading.Tasks;
using OpenPlay.Support;
/// <summary>Platformunuzun güvenli deposunu (iOS Keychain, Android Keystore, masaüstü kimlik deposu) temsil eden kendi arayüzünüz.</summary>
public interface IPlatformKeystore
{
string Read(string key);
void Write(string key, string value);
void Delete(string key);
}
/// <summary>
/// ISecretStore sözleşmesi: misafir bootstrap sırrı ve yenileme belirteci burada saklanır.
/// Varsayılan PlayerPrefs deposu düz metindir ve güvenli depo DEĞİLDİR; üretimde bunun gibi kendi deponuzu verin:
/// options.SecretStore = new KeystoreSecretStore(myKeystore);
/// </summary>
public sealed class KeystoreSecretStore : ISecretStore
{
private readonly IPlatformKeystore _keystore;
public KeystoreSecretStore(IPlatformKeystore keystore) { _keystore = keystore; }
public Task<string> GetAsync(string key, CancellationToken cancellationToken) => Task.FromResult(_keystore.Read(key));
public Task SetAsync(string key, string value, CancellationToken cancellationToken)
{
_keystore.Write(key, value);
return Task.CompletedTask;
}
public Task ClearAsync(string key, CancellationToken cancellationToken)
{
_keystore.Delete(key);
return Task.CompletedTask;
}
}
Sözleşme: değer günlüğe, istisna iletisine ve ToString()’e girmez; olmayan anahtar için GetAsync null döner; her işlem başarısız olabilir ya da geç dönebilir (SDK 3 sn sonra vazgeçer).
Eklenti komutları ve sorguları
client.Plugin(binding, pin) eklenti istemcisi verir (PrepareCommand, QueryAsync, PublicQueryAsync, VerifyServerSchemaAsync). Komut hazırlanırken tek bir Idempotency-Key üretilir ve gövde dondurulur; belirsiz sonuçta (ErrorKind.UnknownOutcome) aynı anahtarla LookupAsync ile sorgulanır, kaybolduysa ResumeAsync ile tam aynı komut yeniden gönderilir. Kör yeni komut üretilmez.
Not
Yayımlanan pakette yalnız
package-rideeklentisinin üretilmiş tipli bağlaması vardır (OpenPlay.PackageRide). Başka bir eklenti için bugün üretilmiş Unity bağlaması yoktur; hamPluginBindingile çalışırsınız. Bağlama, sunucudaki şema özetine (schemaSha256) sabitlenir: uyuşmazlıktaUpgradeRequiredalırsınız.
using System.Threading.Tasks;
using OpenPlay;
using OpenPlay.PackageRide;
using OpenPlay.Plugins;
/// <summary>
/// Eklenti komutu: yayımlı pakette yalnız package-ride için üretilmiş tipli bağlama vardır.
/// Komut hazırlanırken tek Idempotency-Key üretilir; belirsiz sonuçta AYNI anahtarla sorgulanır.
/// </summary>
public static class PluginCall
{
public static async Task ClaimLoginBonus(OpenPlayClient client, long expectedVersion)
{
var rides = PackageRideClient.Create(client); // bağlama sürümü ve şema özeti sunucuyla eşleşmezse UpgradeRequired
var command = rides.Commands.ClaimLoginBonus.Prepare(new LoginBonusInput { ExpectedVersion = expectedVersion });
try
{
var receipt = await command.SendAsync();
LoginBonusOutput output = rides.Commands.ClaimLoginBonus.ParseOutput(receipt); // tipli çıktı
UnityEngine.Debug.Log("giriş bonusu işlendi, HTTP durumu: " + receipt.Status + ", çıktı: " + output.GetType().Name);
}
catch (OpenPlayException ex) when (ex.Kind == ErrorKind.UnknownOutcome)
{
// Yanıt kayboldu; komut uygulanmış olabilir. Yeni komut üretmeyin, aynı anahtarla sorgulayın.
var lookup = await command.LookupAsync();
if (lookup.Status == CommandLookupStatus.NotFound) await command.ResumeAsync(); // tam aynı anahtar ve gövde
}
}
}
Gerçek zamanlı
client.Realtime.ConnectAsync() bileti alır, soketi açar ve kimlik doğrular; kopmada artan gecikmeyle yeniden bağlanır. Yerel derlemede bilet Authorization: Bearer + x-crx-env + sabit Origin ile alınır; çerez kullanılmaz. Abonelik açmak için RealtimeConnection.JoinAsync(modül, JoinTarget.PlayerSelf() / Room / Scene / InterestSet) kullanılır. Protokol ayrıntıları: Gerçek zamanlı.
using System;
using System.Threading.Tasks;
using OpenPlay;
using OpenPlay.Realtime;
using OpenPlay.Unity;
/// <summary>
/// Realtime soketi: bilet alma, bağlanma ve yeniden bağlanma SDK'dadır.
/// Sunucu etkinlik göstermeyen soketi 4100 koduyla kapatır; OnIdleClose verirseniz otomatik yeniden bağlanma olmaz.
/// </summary>
public static class RealtimeConnect
{
public static OpenPlayClient Create(Uri baseUrl, Guid environmentId, Action showContinue)
{
var options = OpenPlayUnity.Options(baseUrl, environmentId);
options.Realtime = new RealtimeOptions { OnIdleClose = _ => showContinue() }; // "Devam et" düğmesini gösterin
return OpenPlayClient.Create(options);
}
/// <summary>Oturum açıldıktan sonra çağrılır; "Devam et" onayında da aynı çağrı yeni bilet alıp sürdürür.</summary>
public static Task<RealtimeConnection> Connect(OpenPlayClient client) => client.Realtime.ConnectAsync();
}
WebGL
WebGL oynatıcısında SDK tarayıcı kipine geçer (OpenPlayUnity.Options bunu kendisi seçer): HTTP UnityWebRequest ile, gerçek zamanlı tarayıcının WebSocket’iyle (küçük bir jslib köprüsü) gider ve oturum çerezlerini tarayıcı yönetir. SDK Cookie, Origin, Authorization ya da User-Agent başlığı koymaz; her mutasyon x-csrf-token taşır.
- Yalnız aynı origin (SDK kısıtı). Unity WebGL SDK’sı bugün oyun sayfası ile Open Play API’sinin aynı kökten sunulmasını şart koşar; sunucu artık ortam alan adı listesindeki origin’lere CORS verir ama Unity SDK’sı bunu henüz kullanmaz (Mimari ve barındırma). Farklı origin
OpenPlayExceptionileConfigurationvewebgl_cross_origin_unsupportedkodunu verir; sessizce başarısız olmaz. - Gizli sekme. Kalp atışı tarayıcı zamanlayıcısıyla sürer, sekme arka plana alınınca bağlantı açık kalır. Gizliyken gelen mesajlar ve HTTP tamamlanmaları Unity karesini bekler ve sekme görünür olunca işlenir.
Application.runInBackgroundkapalıyken oyun döngüsü gizli sekmede durur; oyununuz gizliyken de ilerlemeliyseApplication.runInBackground = trueyapın. - Çok sekme. Aynı origin’deki sekmeler tek çerez kavanozunu paylaşır; ikinci sekmedeki giriş birincinin oturum çerezini değiştirir.
Doğrulanan platformlar
Düzey: R = Unity’de ölçüldü, B = yalnız belge ya da dotnet göstergesi, — = yok.
| Hedef | Düzey | Not |
|---|---|---|
| Unity 6000.6.7f1 Editör (Linux) | R | Mono ve IL2CPP ölçüldü |
| Windows | B | doğrulanmadı |
| macOS | B | doğrulanmadı |
| Android | B | doğrulanmadı (telefon ölçümü yapılmadı) |
| iOS | — | doğrulanmadı |
| WebGL (aynı origin) | R | BasicLogin WebGL oynatıcısı gerçek API’ye karşı: misafir ve e-posta girişi, eklenti sorgusu, gerçek zamanlı Ready, katılım ve girdi onayı; 35 sn gizli sekmede kalp atışı sürdü. Yalnız Chrome; Firefox ve Safari doğrulanmadı |
package.json içindeki unity: 2022.3 alanı yalnız alt sınırdır; Unity 2022.3 doğrulanmadı.
Hatalar
Tüm hatalar OpenPlayException olarak gelir: Kind (ErrorKind), Status, Attempts, Code, Operation, DeliveryState, Reference, Reason. ErrorKind değerleri: Http, Network, Timeout, Cancelled, Contract, Configuration, Pagination, Codegen, Auth, UnknownOutcome, Storage, Realtime, Backpressure, UpgradeRequired, CapabilityUnavailable, Disposed, ScopeChanged. Anlamları TypeScript SDK’sındakilerle aynıdır (TypeScript SDK › Hatalar).
Kapsam dışı ve bilinen sınırlar
- Unity SDK’sında yoktur: OAuth (Google), katalog, mağaza, skor tablosu, bildirimler ve sunucu anahtarıyla yönetim işlemleri. Bunlar için ham REST kullanın; sunucu anahtarını oyun istemcisine koymayın.
- Yanıt sıkıştırması (
permessage-deflate) yoktur. - Erişim JWT’si uygulamaya açılmaz (Sunucuda doğrulama).
- Android, iOS ve macOS oynatıcı koşuları yapılmadı; WebGL yalnız aynı origin’de çalışır.
PlayerPrefsdeposu güvenli değildir; üretimde kendi deponuzu verin.
Karakterler
Bu sayfa, oyuncunun oynadığı karakterin Open Play’de nasıl tanımlandığını, oluşturulduğunu ve değiştirildiğini anlatır. Karakter durumunu (özellikler, kaynaklar, XP, seviye, yetenekler, bayraklar) sunucuda tutmak ve hile yapılamayan komutlarla değiştirmek istiyorsanız okuyun.
Ne işe yarar
Karakter modülü (characters), oyuncuya bağlı karakter durumunu tek bir güvenilir yerde tutar. Durum yalnız komutlarla değişir ve her değişiklik değiştirilemez bir olay (event) olarak kaydedilir. Böylece bir karakterin herhangi bir andaki durumunu geri okuyabilir, hatalı bir değişikliği yeni bir olayla geri alabilirsiniz.
Modül kapalıysa bu sayfadaki uçların hepsi 404 ve {"code":"module_disabled","module":"characters"} döner. Modülü Oyun ayarları › Modüller sayfasından açın.
Panelde nerede
| Ne yapacaksınız | Panel sayfası |
|---|---|
| Karakter şablonu, özellik (trait) ve seviye eğrisi tanımlamak | Karakter şablonları |
| Karakterleri listelemek, birini açıp durumunu ve geçmişini görmek | Karakterler, Karakter profili |
| Oyuncunun hesabını ve karakterlerini birlikte görmek | Oyuncular, Oyuncu profili |
| Olay tetikli otomasyon yazmak | Oyun kuralları |
Veri modeli (düz dille)
- Özellik (trait): Yeniden kullanılabilir alan paketi. Örneğin “savaşçı” özelliği güç ve can alanlarını getirir. Bir şablon birden çok özelliği birleştirir.
- Şablon (definition): Anahtarla (
warrior) tanımlanan karakter türü. Hangi özellikleri kullandığını, alanların varsayılanlarını, karakterin nasıl yaratılacağını (defaults,point_buy,roll) ve hangi seviye eğrisini izlediğini söyler. Şablon her yayında yeni bir sürüm olur; var olan karakterler doğdukları sürüme bağlı kalır. - Seviye eğrisi (level curve): Seviyenin kaç XP’ye karşılık geldiğini tarif eder. Seviye saklanmaz, kümülatif XP’den türetilir; eğriyi değiştirmek karakter verisinde dönüşüm gerektirmez. Üç tür vardır:
table(eşik listesi),piecewise(seviye aralığı başına XP) veformula(kuadratik formül,max_levelile). - Karakter: Bir şablondan doğan örnek.
external_idalanına oyunun kendi oyuncu kimliğini yazabilirsiniz; aynı ortamda iki karaktere aynıexternal_idverilemez. - Durum (state):
attributes(özellik değerleri),resources(can/mana gibi tüketilen kaynaklar),progression(level,xp,highest_level),abilities,flags(evet/hayır bayrakları) ve serbestcustomalanı. - Sürüm (
version): Karakterin her komutla artan sayısı. Eşzamanlı yazmayı engellemek için kullanılır (aşağıda).
Sayılar tam sayıdır (i64); ondalık sayı yoktur. Yüzdeler baz puan (basis point) olarak yazılır, 10000 = %100. Ayrıntı: Sayılar ve kodlama.
Oyunun yaptığı çağrılar
Karakter uçları API anahtarıyla çağrılır; oyuncu oturumu (çerez ya da oturum belirteci) bu uçlarda geçerli değildir. İstek başlığı:
Authorization: Bearer crx_live_<önek>_<gizli>
Anahtarın türü önemlidir (bkz. Kavramlar): sunucu anahtarı her komutu çalıştırır, istemci anahtarı yalnız set_flag komutunu çalıştırabilir. Sunucu anahtarını oyuna gömmeyin.
| Yöntem ve yol | Anahtar | Ne yapar |
|---|---|---|
POST /v1/definitions | herhangi (aşağıdaki not) | Şablonu yeni sürüm olarak kaydeder |
GET /v1/definitions/{key} | herhangi | Güncel şablonu ve çözülmüş şemayı okur |
POST /v1/traits | herhangi (not) | Özellik kaydeder |
POST /v1/level-curves | herhangi (not) | Seviye eğrisi kaydeder |
GET /v1/level-curves/{key} | herhangi | Eğriyi okur |
POST /v1/characters | herhangi | Şablondan karakter oluşturur |
GET /v1/characters | herhangi | Karakterleri listeler (definition, cursor, limit) |
GET /v1/characters/{id} | herhangi | Karakteri durumuyla okur |
DELETE /v1/characters/{id} | herhangi | Karakteri siler (yumuşak silme, 204) |
POST /v1/characters/{id}/commands | komuta göre | Komut çalıştırır |
GET /v1/characters/{id}/stats | herhangi | Etkin değerleri ve hesap dökümünü verir |
GET /v1/characters/{id}/events | herhangi | Olay günlüğü (cursor, limit) |
GET /v1/characters/{id}/timeline | herhangi | Okunur zaman çizelgesi |
GET /v1/characters/{id}/state?at= | herhangi | Geçmiş bir andaki durumu yeniden kurar |
Kimlik ve modül kuralları ile hata gövdeleri: Hatalar. Sayfalama: Sayfalama (limit 1–200, varsayılan 50; next_cursor null ise son sayfadır).
Not
Hata gövdeleri bu uçlarda düz metindir (
text/plain). Yalnızmodule_disabledveaccount_bannedJSON döner.
Uyarı
Bilinen kısıt: Şablon, özellik, seviye eğrisi ve kural yazan uçlar ile karakter okuma/silme uçları anahtar türüne bakmaz; geçerli bir istemci anahtarı da çağırabilir. İstemci anahtarı ortam kapsamlıdır, oyuncu kapsamlı değildir: oyuna gömülen anahtarla o ortamdaki herhangi bir karakter okunabilir ya da silinebilir. Bu yüzden yönetim çağrılarını ve karakter silmeyi yalnız kendi sunucunuzdan yapın; oyuncudan gelen karakter kimliğine sunucunuzda sahiplik denetimi uygulayın. Anahtar türüne göre kapı henüz yok.
Karakter oluşturmak
POST /v1/characters
Authorization: Bearer crx_live_<önek>_<gizli>
Content-Type: application/json
{ "definition": "warrior", "external_id": "oyuncu-1234" }
{
"id": "0192f0f2-5b1a-7c3e-9d11-4a5b6c7d8e9f",
"definition": "warrior",
"definition_version": 3,
"external_id": "oyuncu-1234",
"version": 1,
"level": 1,
"state": {
"attributes": { "strength": 10 },
"resources": { "hp": 100 },
"progression": { "level": 1, "xp": 0, "highest_level": 1, "granted_rewards": [] },
"abilities": [],
"flags": {},
"custom": {}
},
"created_at": "2026-11-03T09:00:00Z"
}
Gövdede ayrıca allocation (puan dağıtımlı yaratımda alan → harcanan puan), seed (zarlı yaratımda zorunlu, belirleyici tohum) ve custom (en çok 64 KB serbest JSON) bulunabilir. Mod şablonda tanımlıdır; istek yalnız modun istediği girdiyi taşır.
Uyarı
Oluşturma ve silme uçları idempotency anahtarı almaz ve otomatik tekrar denenmez. Aynı
external_idile ikinci bir oluşturma409döner; bu, kopya karakter oluşmasını da engeller. Ağ hatasında önceexternal_idile aramadan körlemesine tekrar göndermeyin.
Komut çalıştırmak
POST /v1/characters/{id}/commands
Authorization: Bearer crx_live_<önek>_<gizli>
Content-Type: application/json
Idempotency-Key: gorev-17-oyuncu-1234
If-Match: 1
{ "type": "add_xp", "amount": 250 }
{
"id": "0192f0f2-5b1a-7c3e-9d11-4a5b6c7d8e9f",
"version": 2,
"state": { "...": "güncel durum" },
"events": [
{ "id": "…", "seq": 2, "type": "xp_added", "payload": { "...": "…" }, "created_at": "2026-11-03T09:01:00Z" }
],
"replayed": false
}
Komut türleri type alanıyla seçilir:
type | Gövde alanları | Anahtar |
|---|---|---|
set_flag | key, value (bool) | istemci veya sunucu |
set_attribute | key, value (tam sayı) | sunucu |
add_resource | key, delta (tam sayı, eksi olabilir) | sunucu |
add_modifier | stat, operation (flat_add, flat_sub, percent_add, percent_mul, clamp), value, priority, source_kind (item, buff, skill, curse, quest), source_id, expires_at | sunucu |
remove_modifier | source_kind, source_id | sunucu |
add_xp | amount | sunucu |
rollback | to_version | sunucu |
İstemci anahtarıyla set_flag dışında bir komut gönderirseniz 403 alırsınız ve idempotency anahtarınız yanmaz.
Bir komut birden çok olay üretebilir: örneğin add_xp bir seviye atlatırsa yanıtta xp_added ve level_up birlikte gelir; tanımlı kurallar da ek olay üretir.
Eşzamanlılık ve tekrar güvenliği
Idempotency-Key(isteğe bağlı, 1–200 karakter): Aynı anahtar ve aynı gövde ikinci kez gelirse komut tekrar çalışmaz, ilk yanıtreplayed: trueile döner. Aynı anahtarla farklı gövde422’dir. Anahtar yalnız komut başarılı olunca “yanar”; reddedilen komut anahtarı tüketmez. Aynı anda uçuşta olan aynı anahtar409alır.If-Match(isteğe bağlı): Okuduğunuzversiondeğeri,3ya da"3"biçiminde. Karakter bu sürümde değilse komut409ile reddedilir ve hiçbir şey değişmez.*ve zayıfW/biçimleri kabul edilmez (400).rollbackkomutundaIf-Matchişlenmez.
Genel kurallar: Idempotency ve eşzamanlılık.
Geri alma
rollback komutu geçmişi silmez. Karakteri to_version sürümündeki duruma döndüren yeni bir olay (character_rolled_back) yazar; olay günlüğü yalnızca eklenir.
Olaylar ve webhook’lar
Karakter olayları (flag_set, attribute_set, resource_changed, modifier_added, modifiers_removed, xp_added, level_up, ability_unlocked, event_emitted, character_rolled_back) webhook olarak da gönderilebilir. Zarfta event_id, type, character_id, environment_id, seq ve data bulunur. Kayıt ve doğrulama: Webhook’lar.
Sınırlar
customalanı en çok 64 KB; içinde ondalık sayı olamaz.- Liste uçlarında
limit1–200. - Seviye 1’den küçük olamaz; en çok 65535.
GET …/state?at=geleceğe ya da eksi bir zamana400döner.at, Unix milisaniyesi veya RFC 3339 zamanıdır.
Sık görülen hatalar
| Belirti | Neden | Çözüm |
|---|---|---|
403 permission denied | İstemci anahtarıyla set_flag dışında komut | Komutu sunucudan, sunucu anahtarıyla gönderin |
409 version conflict: expected 3, actual 4 | If-Match bayat | Karakteri yeniden okuyun, yeni sürümle tekrar gönderin |
409 already exists | Aynı external_id var | Var olan karakteri GET /v1/characters ile bulun |
422 idempotency mismatch | Aynı anahtar, farklı gövde | Yeni bir anahtar üretin; yalnız ağ tekrarında aynı anahtarı kullanın |
400 If-Match tam sürüm numarası olmalı | * ya da zayıf etiket gönderildi | Yalnız sayı gönderin |
404 + module_disabled | characters modülü kapalı | Modülü açın |
Çalışan örnek
Aşağıdaki örnek bir karakter oluşturur ve güvenle XP verir. Şablonun (warrior) panelden ya da POST /v1/definitions ile önceden tanımlı olması gerekir.
/** Güvenilir backend örneği: karakter oluşturur, XP verir. Server anahtarı yalnız sunucu ortamından gelir. */
import { CrxClient, CrxError } from "@ferdiunal/open-play-ts";
/** Oyuncunun karakterini açar ve ilk XP'yi güvenle (idempotent) verir. */
export async function createAndReward(baseUrl: string, serverApiKey: string, playerId: string): Promise<bigint> {
const crx = new CrxClient({ baseUrl, apiKey: serverApiKey });
// 1) Karakteri tanımdan oluştur. `external_id` oyunun kendi oyuncu kimliğidir.
const character = await crx.createCharacter({
body: { definition: "warrior", external_id: playerId },
});
// 2) XP ver: aynı Idempotency-Key ile tekrar denemek ikinci XP vermez.
// If-Match, karakterin okuduğunuz sürümüdür; araya başka komut girdiyse 409 döner.
try {
const result = await crx.executeCommand({
path: { id: character.id },
body: { type: "add_xp", amount: 250n },
headers: {
"Idempotency-Key": `quest-1-${playerId}`,
"If-Match": character.version.toString(),
},
});
return result.version;
} catch (error) {
if (error instanceof CrxError && error.status === 409) {
// Sürüm çakışması: karakteri yeniden okuyup komutu yeni sürümle gönderin.
throw new Error("Karakter bu arada değişti; yeniden okuyup tekrar deneyin.");
}
throw error;
}
}
İlgili sayfalar
- Kavramlar: anahtar türleri ve oturumlar
- Oyun kuralları ve otomasyonlar
- Envanter ve eşyalar
- Hatalar, Idempotency ve eşzamanlılık
Envanter ve eşyalar
Bu sayfa, oyunun eşyalarını (iksir, silah, kozmetik…) tanımlamayı, oyuncuya vermeyi, tüketmeyi, devretmeyi ve envanterde yerleştirmeyi anlatır. Envanter durumunun sunucuda güvenle tutulmasını istiyorsanız okuyun.
Ne işe yarar
Eşya modülü (items) iki ayrı şeyi yönetir:
- Eşya tanımı (item definition): “Küçük can iksiri” gibi bir tür. Anahtarı, türü, yığılabilir (stackable) olup olmadığı, takas edilebilirliği ve NPC alış/satış fiyatı burada durur.
- Eşya örneği (item instance): Bir oyuncunun elindeki gerçek eşya. Hangi tanım sürümünde doğduğunu, sahibini, adedini ve özelleştirme verisini (
metadata) taşır.
Envanter, bir sahibin eşyalarının yerleşimidir. Envanter yalnız hangi eşyanın hangi yuvada olduğunu tutar; adet ve özelleştirme eşya örneğindedir.
Modül kapalıysa uçlar 404 ve {"code":"module_disabled","module":"items"} döner. Modülü Oyun ayarları › Modüller sayfasından açın.
Panelde nerede
| Ne yapacaksınız | Panel sayfası |
|---|---|
| Eşya tanımlarını ve oyun verilerini (yerleşik eşya grubu) düzenlemek | İçerik |
| Eşyaya 3B model bağlamak | 3D modeller, Model profili |
| Bir oyuncunun envanterini ve cüzdanını görmek | Oyuncu profili |
| Eşyayı mağazada satmak | Mağaza |
Veri modeli (düz dille)
- Tür (
kind):consumable,equipment,material,cosmetic,vip_card. - Yığılabilir (
stackable) vemax_stack: Yığılabilir eşyada aynı tanım sürümünden ve boşmetadata’lı örnekler tek satırda birleşir.stackable: trueisemax_stackzorunludur (1 ile2147483647arası). tradeable:falseise eşya başka sahibe devredilemez (422). Varsayılantrue.npc_buy_price,npc_sell_price: En küçük birimde tam sayı.nullise tüccarla alım/satım kapalıdır.- Sürüm sabitleme (pin): Her örnek, doğduğu tanım sürümünü (
definition_version) taşır. Tanımı sonradan değiştirmek eski örneklerin kurallarını değiştirmez. - Sahip (
owner):<tür>:<uuid>biçimi; türplayer,character,clanya dasystemolabilir. Örnek:player:0192f0f2-5b1a-7c3e-9d11-4a5b6c7d8e9f. - Envanter: İlk komutta kendiliğinden açılır (varsayılan kapasite 32). Kapasite, dolu yuva sayısının üst sınırıdır; yuva numarası 0 veya daha büyük herhangi bir sayı olabilir. Hiç açılmamış envanteri okumak
404döner ve envanteri açmaz. version: Hem eşya örneğinin hem envanterin kendi sürümü vardır; her değişiklikte artar veIf-Matchile kullanılır.
Oyunun yaptığı çağrılar
Eşya ve envanter uçları API anahtarıyla çağrılır:
Authorization: Bearer crx_live_<önek>_<gizli>
Oyuncu tarafı iki okuma ucu sunar; bunlar oyuncu oturumuyla çağrılır (çerez ya da oturum belirteci, x-crx-env: <ortam uuid> başlığıyla):
| Yöntem ve yol | Kimlik | Ne yapar |
|---|---|---|
POST /v1/item-definitions | sunucu anahtarı | Tanımı yeni sürüm olarak kaydeder (content alanıyla oyun verisi de yazılabilir) |
GET /v1/item-definitions/{key} | API anahtarı | Güncel tanım sürümünü okur |
POST /v1/items | sunucu anahtarı | Eşya üretir (mint) |
GET /v1/items?owner=player:<uuid> | API anahtarı | Sahibin eşyalarını listeler (cursor, limit) |
GET /v1/items/{id} | API anahtarı | Tek örneği okur |
POST /v1/items/{id}/consume | API anahtarı | Adet tüketir |
POST /v1/items/{id}/destroy | sunucu anahtarı | Eşyayı yok eder |
POST /v1/items/{id}/transfer | API anahtarı | Sahipliği devreder |
GET /v1/inventories/{owner} | API anahtarı | Envanteri ve dolu yuvaları okur |
POST /v1/inventories/{owner}/move | API anahtarı | Eşyayı yuvaya yerleştirir ya da taşır |
POST /v1/inventories/{owner}/split | API anahtarı | Yığından adet ayırıp yeni yuvaya koyar |
POST /v1/inventories/{owner}/stack | API anahtarı | İki yığını birleştirir |
POST /v1/inventories/{owner}/equip | API anahtarı | Eşyayı kuşanma yuvasına koyar |
POST /v1/inventories/{owner}/unequip | API anahtarı | Kuşanılmış eşyayı başka yuvaya indirir |
GET /v1/player/inventory | oyuncu oturumu | Oyuncunun kendi envanteri (salt okunur) |
GET /v1/player/items | oyuncu oturumu | Oyuncunun kendi eşyaları (salt okunur) |
GET /v1/catalog/items, GET /v1/catalog/items/{key} | sunucu anahtarı ya da oyuncu oturumu | Eşya kataloğu (aşağıda) |
Not
TypeScript SDK’sında eşya ve envanter için tipli istemci yoktur; bu uçlar ham REST ile çağrılır. Oyuncu oturumuyla okuma (
/v1/player/*) için de SDK yardımcısı henüz yok. Kapsam tablosu: TypeScript SDK.
Uyarı
Bilinen kısıt:
consume,transfer,move,split,stack,equipveunequipuçları anahtar türüne bakmaz; geçerli bir istemci anahtarı da çağırabilir veownerya da eşya kimliği istekte serbestçe verilir. İstemci anahtarı ortam kapsamlıdır, oyuncu kapsamlı değildir. Oyuncunun yalnız kendi eşyasına dokunduğunu kendi sunucunuzda doğrulayın; hile riskine karşı bu çağrıları oyun sunucusundan yapın.mintvedestroyyalnız sunucu anahtarıyla çalışır.
Eşya üretmek (mint)
POST /v1/items
Authorization: Bearer crx_live_<önek>_<gizli>
Content-Type: application/json
Idempotency-Key: quest-17-potion-oyuncu-1234
{
"definition_key": "health_potion",
"owner": "player:0192f0f2-5b1a-7c3e-9d11-4a5b6c7d8e9f",
"quantity": 3,
"source": "quest"
}
{
"instance": {
"id": "0192f1aa-1111-7222-8333-944455556666",
"definition_id": "0192f0aa-0000-7000-8000-000000000001",
"definition_version": 2,
"owner_type": "player",
"owner_id": "0192f0f2-5b1a-7c3e-9d11-4a5b6c7d8e9f",
"quantity": 3,
"metadata": {},
"version": 1,
"created_event_id": "0192f1aa-2222-7333-8444-955566667777",
"created_at": "2026-11-03T09:00:00Z",
"updated_at": "2026-11-03T09:00:00Z"
},
"event": { "type": "item_instance_created" },
"replayed": false
}
quantity1 ile2147483647arasındadır.sourcemint,craft,purchase,questya dagrantolabilir; verilmezsemint.metadatadoluysa eşya yığılmaz, her zaman tek satır olur.- Yığılabilir tanımda, sahibin elinde aynı sürümde boş
metadata’lı bir yığın varsa yeni satır açılmaz, adet o yığına eklenir.max_stackaşılırsa422.
Tüketmek, yok etmek, devretmek
| Uç | Gövde | Not |
|---|---|---|
POST /v1/items/{id}/consume | {"amount": 1} | amount 1 ile mevcut adet arasında; aşım 422. Adet sıfıra inerse satır silinir ve sonraki GET 404 döner. Eşya türüne bakılmaz. |
POST /v1/items/{id}/destroy | {"amount": 1} | Yalnız sunucu anahtarı. Aynı kurala tabidir; geçmiş olaylar silinmez. |
POST /v1/items/{id}/transfer | {"to_owner": "player:<uuid>"} | tradeable: false ise 422. |
Bu uçların üçünde de Idempotency-Key zorunludur (yoksa 400). If-Match isteğe bağlıdır ve eşya örneğinin version değeridir.
Envanter yerleşimi
Yerleştirme komutları aynı şekli taşır:
POST /v1/inventories/player:0192f0f2-5b1a-7c3e-9d11-4a5b6c7d8e9f/move
Authorization: Bearer crx_live_<önek>_<gizli>
Content-Type: application/json
Idempotency-Key: move-1
If-Match: 4
{ "item_instance_id": "0192f1aa-1111-7222-8333-944455556666", "to_slot": 5 }
| Uç | Gövde |
|---|---|
move | item_instance_id, to_slot |
equip, unequip | item_instance_id, to_slot |
split | from_instance_id, amount, to_slot |
stack | from_instance_id, to_instance_id |
Yanıt { "inventory": {…}, "slots": [{ "slot_idx": 5, "item_instance_id": "…", "created_at": "…" }], "event": {…}, "replayed": false } biçimindedir.
Kurallar:
- Dolu yuvaya yerleştirme
422’dir. Yeni bir eşya yerleştirirken kapasite aşımı da422’dir; yerleşik bir eşyayı taşımak kapasite tüketmez. If-Match, envanterin sürümüdür. İlk açılışta (envanter henüz yokken)If-Matchgönderirseniz400alırsınız.- Aynı eşya başka bir envanterde yerleşikse
409(çift yerleşim kilidi). split:amount1 ile kaynak adedinin bir eksiği arasındadır; eşya yığılabilir olmalıdır. Yeni örneğin kimliği yanıttaki olayda (new_instance_id) döner.stack: iki yığın da yerleşik olmalı; aynı tanım sürümünde ve boşmetadata’lı olmalıdır.equip: tanımınmetadata’sındaequip_condition(CEL ifadesi) varsa kuşanma bu koşula bağlıdır. Koşul ya da değerlendirmesi hata verirse kuşanma reddedilir (422). Koşuldacharacterbağlamı şimdilik boştur,nowveseedsabit0’dır.
Eşya kataloğu
Oyunun istemcisi eşya tanımını, tipli veri satırlarını ve model adresini katalogdan okur. İki kitle vardır: oyuncu yalnız player görünürlüklü satırları görür; sunucu anahtarı bütün satırları, her satırın görünürlüğüyle ve content_revision ile görür. Yanıtlar ETag taşır; If-None-Match ile değişmediyse 304 döner. Ayrıntı ve izleme örneği: İçerik grupları ve Scene, görsel ve 3B modeller.
Sürümleme ve tekrar güvenliği
- Mint, consume, destroy, transfer ve bütün envanter komutlarında
Idempotency-Keyzorunludur. Aynı anahtar ve aynı gövde ikinci kez gelirse işlem tekrar çalışmaz; yanıtreplayed: trueile döner. Aynı anahtar, farklı gövde422’dir. Anahtar yalnız başarıda yanar. If-Matcheşzamanlı yazmayı engeller (uyuşmazlık409).- Genel kurallar: Idempotency ve eşzamanlılık.
Olaylar
Eşya olayları (item_instance_created, item_ownership_changed, item_consumed, item_stacks_merged, item_stack_split) kural otomasyonunda ve görev hedeflerinde kullanılabilir. Webhook uç noktasına filtre olarak seçilebilen olay türleri arasında eşya olayı yoktur. Filtresiz (event_types boş) kaydedilmiş bir uç nokta bütün olayları aldığı için eşya olaylarını da alır; bu olayların zarf biçimi belgelenmiş bir sözleşme değildir, ona güvenmeyin. Eşya değişikliğini dışarıya bildirmeniz gerekiyorsa kendi sunucunuzdan okuyun. Seçilebilir türler: Webhook olayları.
Sınırlar
- Liste uçlarında
limit1–200; sayfalama imleçlidir. - Varsayılan envanter kapasitesi 32 dolu yuvadır.
quantity,amountve fiyatlar tam sayıdır; ondalık yoktur.
Sık görülen hatalar
| Belirti | Neden | Çözüm |
|---|---|---|
400 (anahtar yok) | Idempotency-Key başlığı eksik | Her yazıda anahtar gönderin |
403 | İstemci anahtarıyla mint/destroy/tanım kaydı | Sunucu anahtarı kullanın |
404 (envanter) | Envanter hiç açılmadı | İlk envanter komutu (örn. move) envanteri açar; okuma açmaz |
409 | If-Match bayat ya da eşya başka envanterde | Yeniden okuyup tekrar deneyin |
422 yetersiz adet | amount mevcut adetten büyük | Adedi düşürün |
422 takas | tradeable: false | Tanımda takası açın |
422 yuva dolu | Hedef yuva dolu | Boş bir yuva seçin |
Çalışan örnek
Ham REST ile iksir verip tüketen örnek (SDK’da tipli istemci olmadığı için fetch kullanır):
/** Envanter ve eşya uçları için SDK'da tipli istemci yoktur; ham REST ile çağrılır (sunucu anahtarı). */
/** Küçük yardımcı: Bearer + Idempotency-Key ile JSON POST. */
async function post(baseUrl: string, key: string, path: string, idempotencyKey: string, body: unknown, ifMatch?: number): Promise<unknown> {
const headers: Record<string, string> = {
Authorization: `Bearer ${key}`,
"Content-Type": "application/json",
"Idempotency-Key": idempotencyKey,
};
if (ifMatch !== undefined) headers["If-Match"] = String(ifMatch);
const response = await fetch(`${baseUrl}${path}`, { method: "POST", headers, body: JSON.stringify(body) });
if (!response.ok) throw new Error(`${path}: HTTP ${response.status} ${await response.text()}`);
return response.json();
}
/** Oyuncuya bir iksir verir (mint, yalnız server anahtarı) ve 1 adedini tüketir. */
export async function grantAndDrink(baseUrl: string, serverKey: string, playerId: string): Promise<void> {
const minted = (await post(baseUrl, serverKey, "/v1/items", `mint-${playerId}-potion-1`, {
definition_key: "health_potion",
owner: `player:${playerId}`,
quantity: 3,
})) as { instance: { id: string; version: number } };
await post(
baseUrl,
serverKey,
`/v1/items/${minted.instance.id}/consume`,
`drink-${minted.instance.id}-1`,
{ amount: 1 },
minted.instance.version, // If-Match: okuduğunuz sürüm; uyuşmazlık 409
);
}
İlgili sayfalar
- Ekonomi: cüzdanlar, para birimleri, tüccar ve takas
- Mağaza ve uygulama içi satın alma
- İçerik grupları
- Hatalar
Ekonomi
Bu sayfa oyun içi paranın Open Play’de nasıl tutulduğunu ve hareket ettiğini anlatır: para birimi tanımı, cüzdan, defter (ledger), oyuncular arası transfer, NPC tüccar ve oyuncu takası. Oyuncuya para vermenin, harcatmanın ve ekonomiyi izlemenin güvenli yolunu arıyorsanız okuyun.
Ne işe yarar
Ekonomi iki modüle yayılır:
economy: para birimleri, cüzdanlar, defter, transfer ve raporlar.trading: NPC tüccar (merchants) ve oyuncular arası takas (trades).
Her para hareketi çift kayıtlıdır (double-entry): bir cüzdandan çıkan tutar başka bir cüzdana ya da bir sistem hesabına girer ve ikisi aynı işlem kimliğiyle (tx_id) defterde durur. Defter yalnızca eklenir; hiçbir satır güncellenmez ya da silinmez. Hata düzeltmek için ters kayıt yazılır.
Modül kapalıysa uçlar 404 ve {"code":"module_disabled","module":"economy"} (ya da trading) döner.
Panelde nerede
| Ne yapacaksınız | Panel sayfası |
|---|---|
| Para birimi oluşturmak, ikon, kuruş hanesi ve arz tavanı ayarlamak | Para birimleri, Para birimi profili |
| Günlük özet, bakiye sıralaması, takaslar ve cüzdan sorgusu görmek | Ekonomi raporları |
| Oyuncunun cüzdanını ve hareketlerini görmek | Oyuncu profili |
| Ödül tablosu kurmak | Ödül tabloları |
| Ürünü paraya bağlayıp satmak | Mağaza |
Veri modeli (düz dille)
- Para birimi (currency): Anahtarı (
gold), adı,transferable(oyuncular arası transfer serbest mi),max_supply(toplam arz tavanı; yoksa sınırsız) ve ikonu vardır. Aynı anahtarla yeniden kayıt yeni sürüm üretir; eski sürümler değişmez. Kuruş hanesi (display_decimals) ve ikon görseli panelden ayarlanır; REST kaydı onları0/boş bırakır. - Cüzdan (wallet): Bir sahibin bir para birimindeki bakiyesi. Sahip
<tür>:<uuid>biçimindedir (player,character,clan,system). Cüzdan yazma ucu yoktur; cüzdan ilk hareketle kendiliğinden doğar ve doğduğu para birimi sürümüne bağlanır. - Bakiye: En küçük birimde tam sayı (
i64). Ondalık sayı yoktur: “12,50 altın” gösterimi için panelde ayarlanan kuruş hanesini istemcide uygulayın. - Defter satırı:
direction(giriş/çıkış),amount,reason(transfer,grant,burn,merchant_purchase,merchant_sale,iap,iap_revoke,party_reward,clan_treasury,quest,login,npc_reward,reward_table,trade_lock,trade_refund,trade_settle…) vereference(bağlam). - Tüccar (merchant): Anahtarı, adı ve eşya başına alış/satış fiyat geçersiz kılmaları (
price_overrides) olan NPC. Eşyanın kendinpc_buy_price/npc_sell_pricedeğeri varsayılandır. - Takas (trade): İki oyuncu arasında durum makinesi:
draft→offered→locked→completedya dacancelled/expired.
Oyuncuya para nasıl verilir
Doğrudan “cüzdana şu kadar ekle” REST ucu yoktur. Para şu yollarla oyuncuya girer:
| Yol | Ne zaman |
|---|---|
Ödül tablosu verme (POST /v1/reward-tables/{key}/grant) | Görev, turnuva, giriş ödülü gibi oyunun verdiği paralar — bkz. Ödüller |
| Günlük giriş ödülü, görev, NPC ödülü | Ödüller |
| Uygulama içi satın alma (IAP) | Gerçek parayla alınan oyun parası — bkz. Mağaza |
Tüccara eşya satmak (POST /v1/merchants/{key}/sell) | Oyuncu eşyayı NPC’ye satar |
| Parti ödül dağıtımı, klan hazinesi | Sosyal |
| Panelden elle verme | Operatör; işlem denetim izine yazılır |
Her biri defterde kendi reason değeriyle görünür.
Oyunun yaptığı çağrılar
Uçlar Authorization: Bearer crx_live_<önek>_<gizli> ile çağrılır. Para birimi ve tüccar yönetimi sunucu anahtarı ister (403); okuma ve oyuncu işlemleri herhangi bir API anahtarıyla yapılabilir.
| Yöntem ve yol | Anahtar | Ne yapar |
|---|---|---|
POST /v1/currencies | sunucu | Para birimini yeni sürüm olarak kaydeder |
GET /v1/wallets?owner=player:<uuid> | API anahtarı | Sahibin cüzdanları (para birimi başına bir satır) |
POST /v1/transfers | API anahtarı | Cüzdandan cüzdana transfer (Idempotency-Key zorunlu) |
GET /v1/ledger?wallet_id=<uuid> | API anahtarı | Cüzdanın defter akışı (cursor, limit) |
POST /v1/merchants | sunucu | Tüccarı yeni sürüm olarak kaydeder |
GET /v1/merchants/{key} | API anahtarı | Tüccarın güncel içeriği |
POST /v1/merchants/{key}/buy | API anahtarı | Oyuncu tüccardan eşya alır |
POST /v1/merchants/{key}/sell | API anahtarı | Oyuncu tüccara eşya satar |
POST /v1/trades | API anahtarı | Takas taslağı açar |
GET /v1/trades/{id}?actor_id= | API anahtarı | Takası görüntüler (yalnız iki taraf) |
POST /v1/trades/{id}/offer | API anahtarı | Bacakları kilitler |
POST /v1/trades/{id}/accept | API anahtarı | Son onay; atomik takas |
POST /v1/trades/{id}/cancel | API anahtarı | İptal; kilitler açılır, para iade edilir |
GET /v1/economy/faucet-sink, /flags, /merchant-gap, /top-holders | sunucu | Günlük ekonomi raporları |
GET /v1/auth/admin/player-wallet-movements?player_id= | sunucu | Oyuncunun son cüzdan hareketleri (limit 1–100, varsayılan 20) |
Not
TypeScript SDK’sında bu modüller için tipli istemci yoktur; ham REST ile çağrılır. Bkz. TypeScript SDK.
Uyarı
Bilinen kısıt: Transfer, tüccar alım/satımı ve takas uçları anahtar türüne bakmaz; geçerli bir istemci anahtarı da çağırabilir ve cüzdan/oyuncu kimliği istekte serbestçe verilir. İstemci anahtarı ortam kapsamlıdır, oyuncu kapsamlı değildir. Para hareketlerini yalnız kendi oyun sunucunuzdan yapın ve oyuncudan gelen kimliği orada doğrulayın.
Para birimi kaydı
POST /v1/currencies
Authorization: Bearer crx_live_<önek>_<gizli>
Content-Type: application/json
{ "key": "gold", "name": "Altın", "transferable": true, "max_supply": 1000000000 }
{ "id": "0192f0aa-1000-7000-8000-000000000001", "key": "gold", "version": 1, "name": "Altın", "transferable": true, "max_supply": 1000000000, "icon": null }
key ve name boş olamaz; max_supply verilirse 0’dan büyük olmalıdır (400). transferable: false olan para birimi oyuncular arası transferde 422 döner (oyun içi harcamalar yine çalışır).
Transfer
POST /v1/transfers
Authorization: Bearer crx_live_<önek>_<gizli>
Content-Type: application/json
Idempotency-Key: transfer-2026-11-03-0001
{ "from_wallet": "0192f1…", "to_wallet": "0192f2…", "amount": 500, "reference": { "neden": "hediye" } }
{ "tx_id": "0192f3…", "from": { "id": "0192f1…", "balance": 1500, "version": 7 }, "to": { "id": "0192f2…", "balance": 500, "version": 3 }, "replayed": false }
(Yanıttaki from ve to cüzdan kayıtlarının tam alanları yer alır; yukarıda kısaltılmıştır.) Reddedilen durumlar: tutar 0 ya da eksi 400; para birimleri farklı 400; cüzdan yok 404; yetersiz bakiye, transferable: false ya da aynı anahtar farklı gövde 422; aynı anahtar uçuşta 409.
Tüccar alım ve satımı
POST /v1/merchants/blacksmith/buy
Authorization: Bearer crx_live_<önek>_<gizli>
Content-Type: application/json
Idempotency-Key: buy-oyuncu-1234-17
{ "player_id": "0192f0f2-…", "item_key": "iron_sword", "currency_key": "gold", "quantity": 1 }
Yanıt: { "event": {…}, "wallet_balance": 900, "wallet_version": 8, "inventory_id": "…", "inventory_version": 5, "replayed": false }.
Alım tek işlemde cüzdandan düşer, eşyayı yeni örnek olarak üretir, ilk boş yuvaya yerleştirir ve stoğu azaltır. Fiyat tanımsızsa, bakiye yetersizse ya da envanter doluysa 422; stok yetersizse 409. Satışta (sell) gövde { "player_id", "item_instance_id", "currency_key" } taşır ve yığının tamamı satılır; kısmi satış için önce split uygulayın. Her ikisinde Idempotency-Key zorunludur.
Oyuncu takası
POST /v1/trades—{ "initiator_player_id", "counterparty_player_id", "ttl_ms" }ile taslak açın (ttl_ms> 0; süre dolunca takasexpiredolur).- İki taraf da
POST /v1/trades/{id}/offerile bacaklarını kilitler:{ "actor_id", "legs": [ {"type":"item","item_instance_id":"…"}, {"type":"currency","currency_id":"…","amount":100} ] }. Eşya yerleşik, takas edilebilir ve başka bir takasta kilitli olmamalıdır (kilitliyse409); para escrow’ya (emanet hesabına) alınır. - Her iki taraf kilitleyince takas
lockedolur.POST /v1/trades/{id}/accept({ "actor_id" }) yalnız başlatan oyuncuyla çalışır ve tek işlemde bütün bacakları takas eder. Alıcının envanterinde yer yoksa422döner ve takas kilitli kalır. POST /v1/trades/{id}/canceliki taraftan biriyle çağrılabilir; kilitler açılır ve para iade edilir.
Taraf olmayan biri GET /v1/trades/{id} çağırırsa 404 alır (takasın varlığı gizlenir); actor_id sorgu parametresi zorunludur.
Sürümleme ve tekrar güvenliği
transfers,merchants/{key}/buy|sell,tradeskomutlarının hepsindeIdempotency-Keyzorunludur (yoksa400). Aynı anahtar ve aynı gövde işlemi tekrarlamaz,replayed: truedöner; farklı gövde422. Anahtar yalnız başarıda yanar.- Para birimi ve tüccar kaydı her seferinde yeni sürüm yazar; eski sürümler dokunulmazdır.
- Defter okuması imleçlidir (
limit1–200, varsayılan 50).
Raporlar
Rapor uçları (faucet-sink, flags, merchant-gap, top-holders) UTC’de kapanmış günler üzerinden hesaplanır: from ve to dahildir ve en çok 366 gün aralık verilebilir. Eksik günler yanıtta missing_dates olarak listelenir; sıfır sayılmaz. iap_net gerçek para değil oyun parasıdır. flags bir inceleme sinyalidir; otomatik yaptırım uygulanmaz.
Olaylar
Para hareketleri outbox’a olay yazar. Webhook filtresi olarak seçilebilen türler arasında ekonomiye özel bir tür yoktur; filtresiz kayıtlı uç noktalar bütün olayları aldığı için para olaylarını da alır, ancak bu olayların zarf biçimi belgelenmiş bir sözleşme değildir. Mağaza ve ödül olayları seçilebilir türlerdir: Webhook’lar.
Sınırlar
- Bakiye ve tutarlar
i64en küçük birimdir; tutar 0’dan büyük olmalıdır. - Para birimi
max_supplytavanını aşan üretim (ödül, IAP, satış)422döner. - Raporlarda en çok 366 gün.
Sık görülen hatalar
| Belirti | Neden | Çözüm |
|---|---|---|
400 (Idempotency-Key) | Başlık eksik | Her yazıda anahtar gönderin |
403 | İstemci anahtarıyla para birimi/tüccar kaydı | Sunucu anahtarı kullanın |
404 cüzdan | Transferde verilen cüzdan kimliği yok | Kimliği GET /v1/wallets ile okuyun; sahibin o para biriminde hiç hareketi yoksa cüzdan henüz doğmamıştır ve liste boş döner |
422 yetersiz bakiye | Bakiye tutardan az | Bakiyeyi GET /v1/wallets ile okuyun |
422 transferable=false | Para birimi transfer edilemez | Para biriminde transferi açın ya da başka yol kullanın |
409 stok | Tüccar stoğu yetmiyor | Adedi düşürün |
Çalışan örnek: para ver, sonra ürün satın al
Sunucu oyuncuya ödül tablosundan para verir; oyuncu kendi oturumuyla mağazadan ürün alır. İlk adım sunucuda, ikinci adım oyun istemcisinde çalışır. welcome_pack tablosu panelden (Ödül tabloları) ya da POST /v1/reward-tables ile önceden kurulmuş olmalıdır.
/** Ekonomi akışı: sunucu ödül tablosundan para verir, oyuncu kendi oturumuyla mağazadan ürün alır. */
import { CrxClient, StoreBuyErrorCode, storeBuyErrorCode, type PlayerClient } from "@ferdiunal/open-play-ts";
/** 1. adım (güvenilir sunucu): oyuncuya tablodan ödül verir. Aynı `requestKey` ile tekrar ödeme yapmaz. */
export async function grantWelcomeReward(baseUrl: string, serverApiKey: string, playerId: string, requestKey: string): Promise<void> {
const crx = new CrxClient({ baseUrl, apiKey: serverApiKey });
const grant = await crx.grantRewardTable("welcome_pack", {
playerId,
source: { type: "manual", operatorId: "game-server" },
idempotencyKey: requestKey,
});
// `rewards` verilen birleşik ödüllerdir; `replayed: true` ikinci çağrının aynı sonucu geri verdiği anlamına gelir.
console.log(grant.rewards, grant.replayed);
}
/** 2. adım (oyun istemcisi): oyuncunun gördüğü ilk ürünü satın alır. */
export async function buyFirstListing(player: PlayerClient, pageKey: string, idempotencyKey: string): Promise<string> {
const catalog = await player.store.catalog({ page: pageKey });
const listing = catalog.pages[0]?.listings[0];
if (listing === undefined || listing.version === null) return "Vitrinde ürün yok.";
try {
// Gördüğünüz sürümü geri gönderin: fiyat arada değiştiyse sunucu satmaz (409 listing_changed).
const result = await player.store.buy(listing.id, { expectedVersion: listing.version, quantity: 1, idempotencyKey });
return `Satın alındı. Kalan bakiye: ${result.balanceAfter}`;
} catch (error: unknown) {
switch (storeBuyErrorCode(error)) {
case StoreBuyErrorCode.InsufficientFunds: return "Bakiye yetmiyor.";
case StoreBuyErrorCode.OutOfStock: return "Stok tükendi.";
case StoreBuyErrorCode.ListingChanged: return "Ürün değişti; mağazayı yenileyin.";
default: throw error;
}
}
}
İlgili sayfalar
- Ödüller · Mağaza ve IAP · Envanter ve eşyalar · Sosyal
- Idempotency ve eşzamanlılık · Sayılar ve kodlama
Mağaza ve uygulama içi satın alma
Bu sayfa oyuncunun gördüğü mağaza vitrinini, oyun parasıyla satın alma akışını ve gerçek parayla yapılan uygulama içi satın almanın (IAP, in-app purchase) doğrulanmasını anlatır. Vitrin oluşturmak, ürün satmak ve ödemeyi sunucuda güvenle tamamlamak istiyorsanız okuyun.
Ne işe yarar
Mağaza modülü (store) üç şeyi birbirine bağlar:
- Vitrin (page) ve ürün (listing): Operatörün panelden kurduğu, oyuncuya gösterilen katalog.
- Ödeme: Ürün ya oyun parasıyla (
currency: bir tüccar üzerinden, eşya karşılığı para) ya da gerçek parayla (iap: App Store ya da Google Play makbuzu) satılır. - Rezervasyon: Satın alma önce bir hak ayırır (stok ve oyuncu limiti), sonra ödemeyi tek işlemde tamamlar. Ödeme ve teslimat birlikte ya olur ya hiç olmaz.
Modül kapalıysa uçlar 404 ve {"code":"module_disabled","module":"store"} döner. Modülü Oyun ayarları › Modüller sayfasından açın.
Panelde nerede
| Ne yapacaksınız | Panel sayfası |
|---|---|
| Vitrin ve ürün oluşturmak, fiyat, stok, görünürlük penceresi ve oyuncu limiti ayarlamak | Mağaza, Ürün |
| Fiyat için para birimi tanımlamak | Para birimleri |
| Satılacak eşyayı tanımlamak | İçerik |
Panelde IAP ürünleri ve makbuzları yalnız listelenir. Mağazaya IAP ürünü bağlamak ve platform kimlik bilgileri (App Store / Google Play) için bkz. Sınırlar.
Veri modeli (düz dille)
- Vitrin (page):
key(küçük harf, rakam,_,-; en çok 64),title,sort_orderve görünürlük. Açıklama, afiş görseli, ürün başlığı, rozet ve görsel gibi vitrin alanları panelden girilir; sunucu anahtarlı REST taslağı bunları taşımaz. - Ürün (listing): Bir vitrine bağlıdır. Ödeme biçimi
currency(tüccar + eşya tanımı + para birimi +price_amount) ya daiap(IAP ürün kimliği) olur.limit_per_player(en az 1) ömür boyu oyuncu başına adet sınırıdır. - Görünürlük:
active, tarih penceresi (starts_at/ends_at, Unix ms) ve isteğe bağlı bir CELvisibility_rule(oyuncuya özgü koşul; kayıtta derlenir, en çok 8192 bayt). Oyuncu vitrinini her okumada yeniden hesaplanır: koşul, saat ve kalan limit o anki duruma göre değerlendirilir. - Katalog sürümü (
version): Vitrinde yapılan her değişiklik katalog sürümünü artırır; yönetim komutlarındaIf-Matchbu sürümdür. - Ürün sürümü: Oyuncunun gördüğü ürünün
versionalanı; satın almadaexpected_versionolarak geri gönderilir. - Rezervasyon: Durumu
reserved,processing,completed,cancelled.reservedveprocessingödeme sayılmaz. - Fiyat: En küçük birimde tam sayı; vitrinde
display_decimals(0–4) ile birlikte gelir. Gösterimi tamsayı/dize işlemiyle kurun, ondalık sayıya çevirmeyin.
Oyunun yaptığı çağrılar
İki kimlik türü vardır:
- Oyuncu oturumu (çerez ya da oturum belirteci +
x-crx-env: <ortam uuid>): vitrini okur ve kendi adına satın alır. Çerezli oturumda mutasyonlar CSRF çift gönderimi (x-csrf-token) veOrigindenetimi ister; bkz. Oturumlar ve CSRF. - Sunucu anahtarı (
Authorization: Bearer crx_live_<önek>_<gizli>): katalog yönetimi, oyuncu önizlemesi, rezervasyon ve ödeme tamamlama.
| Yöntem ve yol | Kimlik | Ne yapar |
|---|---|---|
GET /v1/store/pages[?page=<key>&at=now] | oyuncu oturumu | Oyuncunun görebildiği vitrinler; page tek vitrine daraltır |
POST /v1/player/store/listings/{listing_id}/buy | oyuncu oturumu | Oyuncu kendi adına satın alır |
GET /v1/store/catalog | sunucu anahtarı | Ham yönetim kataloğu (görünürlük süzülmez) |
GET /v1/store/preview/{player_id}[?at=now] | sunucu anahtarı | Bir oyuncunun göreceği vitrini önizler |
POST /v1/store/pages, PUT/DELETE /v1/store/pages/{id}, POST /v1/store/pages/reorder | sunucu anahtarı | Vitrin yönetimi |
POST /v1/store/pages/{page_id}/listings, PUT/DELETE /v1/store/listings/{id}, POST …/listings/reorder | sunucu anahtarı | Ürün yönetimi |
POST /v1/store/listings/{listing_id}/reserve | sunucu anahtarı | Oyuncu için hak ayırır (ödeme değildir) |
POST /v1/store/reservations/{id}/checkout/currency | sunucu anahtarı | Oyun parasıyla ödemeyi tamamlar |
POST /v1/store/reservations/{id}/checkout/iap | sunucu anahtarı | Doğrulanmış IAP ile ödemeyi tamamlar |
POST /v1/store/reservations/{id}/cancel | sunucu anahtarı | reserved rezervasyonu iptal eder (iade değildir) |
POST /v1/iap/verify | API anahtarı | IAP makbuzunu doğrular ve ödülü verir |
POST /v1/webhooks/iap/{platform}/{environment_id} | anahtarsız (imza) | Platformun iade bildirimini alır |
Hata zarfları: yönetim ve rezervasyon uçlarının hataları text/plain’dir; oyuncu satın alma ucu tipli code taşıyan JSON döner (aşağıda). Genel liste: Hatalar.
Vitrini okumak
GET /v1/store/pages?page=garaj
x-crx-env: 0192f000-0000-7000-8000-00000000e001
{
"version": 12,
"pages": [
{
"id": "…", "key": "garaj", "title": "Garaj",
"listings": [
{
"id": "0192f111-…", "version": 3,
"title": "Hızlı Araba", "badge": "sale",
"price": { "currency_key": "gold", "currency_name": "Altın", "amount": 1250, "display_decimals": 0, "icon_url": null },
"item": { "key": "fast_car", "name": "Hızlı Araba" },
"remaining": 40
}
]
}
]
}
Yanıt Cache-Control: private, no-store taşır. Görünmeyen ya da bilinmeyen page anahtarı 404 döner. Oyuncu kimliği, saat ve CEL sonucu istemciden alınmaz; sorguya player_id ya da başka bir alan eklemek 400 döner.
Oyuncunun satın alması
POST /v1/player/store/listings/0192f111-…/buy
x-crx-env: 0192f000-0000-7000-8000-00000000e001
x-csrf-token: <csrf>
Idempotency-Key: buy-oyuncu-1234-0001
Content-Type: application/json
{ "quantity": 1, "expected_version": 3 }
{
"reservation_id": "…",
"payment_reference": "…",
"item_instance_ids": ["…"],
"balance_after": 750,
"replayed": false
}
Gövdede yalnız quantity (pozitif) ve expected_version bulunur; oyuncu kimliği, fiyat ya da ödeme iddiası kabul edilmez ve bilinmeyen alan 400 döner. Kimlik oturumdan gelir. Rezervasyon ve tahsilat tek işlemdedir. Idempotency-Key zorunludur: aynı anahtar ve aynı gövde kalıcı sonucu replayed: true ile tekrar eder ve ikinci tahsilat yapmaz; aynı anahtarla farklı gövde 422’dir. IAP ürünü bu uçta alınamaz (422).
Reddedilen satın almalar tipli JSON kod taşır, {"code": "...", "message": "..."}:
code | HTTP | Anlamı |
|---|---|---|
not_visible | 404 | Ürün bu oyuncuya görünmüyor ya da yok |
listing_changed | 409 | Ürün siz bakarken değişti (expected_version bayat); vitrini yenileyin |
out_of_stock | 422 | Stok bitti |
limit_reached | 422 | Oyuncu başına limit doldu |
insufficient_funds | 422 | Bakiye yetersiz |
inventory_full | 422 | Envanter dolu; işlem tamamen geri alınır |
Diğer hatalar (401, 403 CSRF/Origin, 400, 429 bütçe, 500) genel kurallara tabidir.
Sunucu tarafı akış: rezervasyon ve ödeme
Ödemeyi oyun sunucusunun yönettiği durumlarda (örneğin gerçek para makbuzunu sizin sunucunuz alıyorsa) iki adım kullanın:
POST /v1/store/listings/{listing_id}/reserve
Authorization: Bearer crx_live_<önek>_<gizli>
Idempotency-Key: reserve-oyuncu-1234-0001
If-Match: 12
Content-Type: application/json
{ "player_id": "0192f0f2-…", "quantity": 1 }
Yanıt { catalog_version, entity_id, event_id, event, reservation, replayed } biçimindedir; reservation.status reserved’dır. Ardından:
POST /v1/store/reservations/{id}/checkout/currency
Authorization: Bearer crx_live_<önek>_<gizli>
Content-Type: application/json
{ "player_id": "0192f0f2-…" }
{ "reservation_id": "…", "payment_reference": "…", "kind": "currency", "replayed": false }
checkout uçlarında Idempotency-Key ve If-Match gönderilmez (gönderilirse 400); kalıcı rezervasyon kimliği tekrar güvenliğinin çapasıdır. Para birimiyle ödemede hata olursa işlem geri alınır ve rezervasyon reserved kalır; yeniden deneyebilir ya da iptal edebilirsiniz. IAP ödemesinde sonuç belirsizse rezervasyon processing olur ve oyuncu limiti korunur; aynı credential ile yeniden deneyin. IAP ödemesinde quantity 1’dir.
reserve ve katalog yönetim komutlarında Idempotency-Key zorunludur; If-Match katalog sürümüdür ve isteğe bağlıdır (uyuşmazlık 409). Başarısız komut anahtarı yakmaz.
IAP doğrulaması
POST /v1/iap/verify
Authorization: Bearer crx_live_<önek>_<gizli>
Idempotency-Key: iap-oyuncu-1234-tx-abc
Content-Type: application/json
{ "platform": "app_store", "product_sku": "gems_500", "credential": "<transactionId>", "player_id": "0192f0f2-…" }
{ "receipt_id": "…", "status": "granted", "product_sku": "gems_500", "transaction_id": "…", "grants": [ … ], "replayed": false }
platform:app_storeya dagoogle_play.credential: App Store içintransactionId, Google Play içinpurchaseToken. Sunucu platformu kendisi sorgular; istemciye güvenilmez.- Aynı işlemi iki kez doğrulamak ikinci ödül vermez (
200,replayed: true). statusverified,granted,revokedya dafailedolabilir; mutlu yolgranted’dır.- Hatalar: sahte makbuz
403; ürün katalogda yok ya da işlem platformda tanınmıyor404;product_skuuyuşmazlığı, platform yapılandırılmamış ya da arz tavanı aşımı422; aynı anahtarla uçuşta başka istek409. - İade bildirimi: App Store (ASN V2) ve Google Play (RTDN) bildirimleri
POST /v1/webhooks/iap/{platform}/{environment_id}adresine gelir; uç anahtarsızdır, kimlik doğrulaması imzadır. Bilinen bir makbuzun iadesinde ödül ters kayıtlarla geri alınır ve makbuzrevokedolur; kısmen geri alınabilen durumlarflaggedolarak işaretlenir (varsayılan politika, tüketilmiş kısma dokunmaz). İade dışı bildirimler ve bilinmeyen işlemler200alır, yok sayılır.
Sürümleme ve tekrar güvenliği
- Oyuncu satın alma:
expected_version(ürün sürümü) +Idempotency-Key. - Katalog yönetimi ve rezervasyon:
Idempotency-Keyzorunlu,If-Match= katalog sürümü. - Ödeme tamamlama: kalıcı rezervasyon kimliği; başlık yok.
- Genel kurallar: Idempotency ve eşzamanlılık.
Olaylar ve webhook’lar
Mağaza olayları webhook olarak gönderilebilir: store_page_created, store_page_updated, store_page_deleted, store_pages_reordered, store_listing_created, store_listing_updated, store_listing_deleted, store_listings_reordered, store_purchase_initiated, store_payment_started, store_purchase_completed, store_reservation_cancelled. Zarfta event_id, environment_id, type, seq, now_ms, actor_api_key_id ve data bulunur. Kayıt ve doğrulama: Webhook’lar.
Sınırlar ve bilinen kısıtlar
- Vitrin anahtarı
^[a-z0-9_-]{1,64}$; sıralama isteğinde en çok 2000 giriş. - Oyuncu satın alma ucunda IAP ürünü desteklenmez; IAP ürünleri
checkout/iapya daiap/verifyile alınır. - IAP ürün kaydı: Panelde IAP ürünleri ve makbuzları salt okunurdur ve ürün kaydetmek için herkese açık bir HTTP ucu henüz yoktur. IAP ürünü eklenmesi şimdilik Open Play operatörü üzerinden yapılır.
- Platform kimlik bilgileri: App Store ve Google Play doğrulama kimlik bilgileri dağıtımda operatör tarafından tanımlanır. Tanımlı değilse
iap/verifyvecheckout/iap422döner. - Vitrini oyuncu açtığında ya da yenilediğinde okuyun; değişiklikler okuma anında yeniden hesaplanır.
Sık görülen hatalar
| Belirti | Neden | Çözüm |
|---|---|---|
409 listing_changed | Vitrinde okuduğunuz ürün sürümü eskidi | Vitrini yeniden okuyun, yeni version ile deneyin |
404 not_visible | Ürün oyuncuya görünmüyor (pencere, koşul, pasif) | Vitrini yenileyin; koşulu panelde kontrol edin |
422 insufficient_funds | Bakiye yetersiz | Bakiye gösterin; ödül ya da IAP ile para verin |
400 (bilinmeyen alan) | Satın alma gövdesine fazladan alan eklendi | Yalnız quantity ve expected_version gönderin |
400 (checkout) | Idempotency-Key/If-Match gönderildi | Checkout uçlarında bu başlıkları kaldırın |
403 (satın alma) | CSRF çifti ya da Origin reddi | CSRF belirtecini yenileyin; bkz. Oturumlar ve CSRF |
403 (iap/verify) | Sahte ya da imzası geçersiz makbuz | Makbuzu platformdan yeniden alın |
422 (iap) | Platform yapılandırılmamış ya da product_sku uyuşmuyor | Operatörle iletişime geçin; sku’yu kontrol edin |
Çalışan örnek
Vitrini okuyup ilk ürünü satın alma örneği Ekonomi sayfasında; hata kodlarına göre ayrı mesaj gösterir (storeBuyErrorCode). TypeScript SDK’sı player.store.catalog() ve player.store.buy() yardımcılarını sağlar; Idempotency-Key verilmezse çağrı başına üretir, ağ kesintisinden sonra aynı anahtarı kendiniz vermelisiniz.
İlgili sayfalar
Ödüller
Bu sayfa oyunun oyuncuya verdiği ödüllerin Open Play’de nasıl tanımlandığını ve verildiğini anlatır: şansa bağlı ödül tabloları, günlük giriş ödülü, görevler, NPC ödülleri ve VIP kartları. Ödülün sunucuda, hile yapılamadan ve tek seferlik verilmesini istiyorsanız okuyun.
Ne işe yarar
Ödül modülü (rewards) “oyuncuya para ya da eşya ver” işini tek bir güvenilir hat üzerinden yapar. Her ödül verme işlemi tek bir veritabanı işlemidir: para cüzdana yazılır, eşya envantere konur ve olay kaydedilir. Envanter doluysa ya da para birimi arz tavanını aşarsa hiçbir şey verilmez (422).
Tablolu ödüller belirlenimcidir (deterministic): aynı tohum aynı sonucu verir. Tohum sunucuda tutulur; yanıtta, webhook olayında ve defter kaydında görünmez.
Modül kapalıysa uçlar 404 ve {"code":"module_disabled","module":"rewards"} döner. Modülü Oyun ayarları › Modüller sayfasından açın.
Panelde nerede
| Ne yapacaksınız | Panel sayfası |
|---|---|
| Ödül tablosu kurmak, satır şanslarını ve garanti ödülleri düzenlemek, sürümleri görmek | Ödül tabloları, Ödül tablosu profili |
| Ödülde kullanılacak para birimini tanımlamak | Para birimleri |
| Ödülde kullanılacak eşyayı tanımlamak | İçerik |
| Olay tetikli otomasyonla ödül vermek | Oyun kuralları |
Veri modeli (düz dille)
- Ödül tablosu:
key,name,rolls(kaç kez çekiliş yapılacağı, 1–10),entries(satırlar) veguaranteed(her seferinde verilen ödüller). Her kayıt yeni bir sürüm olur; grant sırasında güncel sürüm kullanılır ve sonuçta sürüm numarası döner. - Satır (entry):
chance_bp(baz puan, 1–10000) vedrop. Bir çekilişin satır şansları toplamı tam 10000 (%100) olmalıdır; “ödül yok” bir satır olabilir. - Ödül (
drop):currency(key,min,max),item(key,min,max) ya danothing. Adet her zamanminilemaxarasından eşit dağılımla seçilir; adetler 1 ile 1.000.000 arasındadır. Tabloda en çok 50 satır, 10 garanti ödül bulunur. - Garanti ödül: Çekilişten bağımsız verilir;
nothingolamaz. - Kaynak (
source): Ödülün neden verildiğini tipli olarak yazar:content_entry,tournament,leaderboard_season,quest,npc_reward,ruleya damanual.
Oyunun yaptığı çağrılar
Tüm ödül uçları sunucu anahtarıyla (ya da yönetici türünde bir anahtarla) çağrılır; istemci anahtarı ve oyuncu oturumu reddedilir. Oyuncu kimliği güvenilir sunucu bileşeninin gövdesinde taşınır:
Authorization: Bearer crx_live_<önek>_<gizli>
| Yöntem ve yol | Ne yapar |
|---|---|
POST /v1/reward-tables | Ödül tablosunu yeni sürüm olarak kaydeder |
GET /v1/reward-tables/{key} | Güncel sürümü okur |
POST /v1/reward-tables/{key}/grant | Tablodan idempotent ödül verir |
GET /v1/login-rewards/{player_id} | Bugünün giriş ödülü durumunu okur |
POST /v1/login-rewards/{player_id}/claim | Günlük giriş ödülünü verir |
POST /v1/quests | Görev tanımı kaydeder |
GET /v1/quests, GET /v1/quests/{key} | Görevleri listeler / okur |
POST /v1/quests/{key}/claim | Görev dönemi ödülünü verir |
GET /v1/npc-rewards/{key}/eligibility | NPC ödülü uygunluğunu okur (yazmaz) |
POST /v1/npc-rewards/{key}/claim | NPC ödülünü verir |
GET /v1/vip/{player_id} | VIP katmanını okur |
POST /v1/vip/{player_id}/cards/{item_instance_id}/use | VIP kartı kullanır |
Not
TypeScript SDK’sında yalnız ödül tablosu için tipli istemci vardır (
CrxClient.createRewardTable,getRewardTable,grantRewardTable). Giriş ödülü, görev, NPC ve VIP uçları ham REST ile çağrılır. Bkz. TypeScript SDK.
Ödül tablosu kaydetmek
POST /v1/reward-tables
Authorization: Bearer crx_live_<önek>_<gizli>
Content-Type: application/json
{
"key": "welcome_pack",
"name": "Hoş geldin paketi",
"rolls": 1,
"entries": [
{ "chance_bp": 7000, "drop": { "type": "currency", "key": "gold", "min": 100, "max": 300 } },
{ "chance_bp": 2500, "drop": { "type": "item", "key": "health_potion", "min": 1, "max": 3 } },
{ "chance_bp": 500, "drop": { "type": "nothing" } }
],
"guaranteed": [ { "type": "currency", "key": "gold", "min": 50, "max": 50 } ]
}
Yanıt 201 ve { id, version, key, name, rolls, entries, guaranteed, created_at_ms } döner; çekiliş tohumu hiçbir yanıtta bulunmaz. Şans toplamı 10000 değilse, tablo boşsa ya da sınırlar aşılıyorsa kayıt 422 ve düz metin iletiyle reddedilir. validate anahtarı ayrılmıştır, tablo anahtarı olarak kullanılamaz.
Tablodan ödül vermek
POST /v1/reward-tables/welcome_pack/grant
Authorization: Bearer crx_live_<önek>_<gizli>
Idempotency-Key: welcome-oyuncu-1234
Content-Type: application/json
{ "player_id": "0192f0f2-5b1a-7c3e-9d11-4a5b6c7d8e9f", "source": { "type": "manual", "operator_id": "game-server" } }
{
"grant_id": "…", "tx_id": "…", "event_id": "…",
"table_key": "welcome_pack", "table_version": 1,
"rewards": [ { "drop": "currency", "key": "gold", "quantity": 250 }, { "drop": "item", "key": "health_potion", "quantity": 2 } ],
"replayed": false
}
Idempotency-Key zorunludur. Aynı anahtar ve aynı gövde ödülü ikinci kez vermez; ilk sonuç replayed: true ile döner. Aynı anahtar farklı gövdeyle 422’dir. source değişkenleri:
type | Ek alanlar |
|---|---|
manual | operator_id |
content_entry | group, entry |
quest | quest_key |
npc_reward | npc_key |
tournament | tournament_id, placement |
leaderboard_season | leaderboard_key, season |
rule | rule_key, event_id |
Para ve eşya tek işlemde verilir: envanter doluysa ya da para birimi arz tavanı aşılırsa bütün verme geri alınır ve 422 döner. Oyuncuya bağlı olmayan bir karakter için NPC ödülü verilemez.
Günlük giriş ödülü
GET /v1/login-rewards/{player_id} bugünün durumunu verir: period_date, claimed, streak_day, current_streak, config_version. POST /v1/login-rewards/{player_id}/claim ödülü verir ve { period_date, streak_day, rewards, event_id, tx_id, replayed } döner; aynı gün ikinci çağrı aynı makbuzu replayed: true ile geri verir, ikinci ödül vermez.
Gün, ortamın saat dilimine (timezone, Ortamlar ve alan adları) göre hesaplanır. Ödül çizelgesi (gün sayısı, her günün para ödülü) ve kaçırılan gün politikası (reset_on_miss: seri 1’e döner; freeze: seri korunur) sürümlü bir yapılandırmadır.
Not
Giriş ödülü yapılandırmasını (çizelge ve seri politikası) yazan herkese açık bir uç ya da panel ekranı henüz yoktur; yapılandırma şimdilik Open Play operatörü tarafından kurulur.
Görevler
POST /v1/quests görev tanımını yeni sürüm olarak kaydeder:
{
"key": "kill_10_wolves",
"name": "On kurt avla",
"objectives": [ { "key": "wolves", "event_type": "event_emitted", "count": 10, "filter_cel": "event.event_key == \"wolf_killed\"" } ],
"rewards": [ { "type": "currency", "key": "gold", "amount": 500 }, { "type": "table", "key": "welcome_pack" } ],
"recurrence": "daily"
}
objectives[].event_type: görevi ilerleten olay türü (karakter olayları,score_submitted,login, eşya ve para olayları gibi);countkaç kez gerektiği;filter_celisteğe bağlı koşul.rewards[].type:currency(key,amount) ya datable(ödül tablosu anahtarı).recurrence:none,daily,weekly.windowveprerequisite_cel(kayıt anında derlenir) isteğe bağlıdır.POST /v1/quests/{key}/claimgövdesi{ "player_id": "…", "period_key": "…" }’dir (period_keyen çok 160 karakter). Yanıt{ status: "claimed" | "already_claimed", reward_count, event_id }— aynı dönemi ikinci kez almakalready_claimeddöner, ödül tekrarlanmaz.GET /v1/questssearch,limit,offsetile listeler (sayfa içitotaldöner).
Not
Görev ilerlemesini (oyuncunun hangi görevde kaçta olduğunu) okuyan herkese açık bir REST ucu henüz yoktur. İlerleme olaylardan sunucuda hesaplanır;
period_keydeğerini bu nedenle oyun sunucunuzun kendisi bilmelidir.
NPC ödülleri
GET /v1/npc-rewards/{key}/eligibility?character_id=…&period_key=… yazmadan uygunluğu söyler: { eligible, reason } (reason: cooldown, daily_limit, condition). POST /v1/npc-rewards/{key}/claim (Idempotency-Key zorunlu, gövde { "character_id", "period_key" }) ya ödülü verir ya da rejected döner: { status: "claimed" | "rejected", reward_count, claim_count, tx_id, reason }. NPC kuralını (bekleme, günlük sınır, CEL koşulu, ödül) kaydeden herkese açık bir uç henüz yoktur.
VIP
VIP katmanı kümülatif puandan türetilir. GET /v1/vip/{player_id} { player_id, cumulative_points, tier, config_version } verir. POST /v1/vip/{player_id}/cards/{item_instance_id}/use (Idempotency-Key zorunlu) bir vip_card eşyasını tüketir ve puan ekler; kart bir üst katman koşulunu (mevcut katman + 1) karşılamıyorsa 422 döner. İstemci ve sunucu anahtarı aynı VIP yüzeyini kullanabilir.
Sürümleme ve tekrar güvenliği
- Tablo grant, NPC claim ve VIP kart kullanımı:
Idempotency-Keyzorunlu. - Giriş ödülü: aynı gün ikinci claim aynı makbuzu döner; başlık gerekmez.
- Görev claim: dönem anahtarı doğal tekrar güvenliğidir (
already_claimed). - Tablo ve görev kayıtları her seferinde yeni sürümdür; eski sürümler değişmez.
- Genel kurallar: Idempotency ve eşzamanlılık.
Olaylar ve webhook’lar
Tablodan veya sabit para ile verilen her ödül reward_granted olayı üretir ve webhook olarak gönderilebilir. Zarfta event_id, environment_id, player_id, type ve data (source_kind, table_key, table_version ve verilenler) bulunur; tohum yoktur. Kayıt ve doğrulama: Webhook’lar.
Sınırlar
- Tabloda en çok 50 satır, 10 garanti ödül, 10 çekiliş (
rolls); adetler 1–1.000.000. chance_bptoplamı tam 10000.- Görev
period_keyveclaimalanları en çok 160 karakter.
Sık görülen hatalar
| Belirti | Neden | Çözüm |
|---|---|---|
403 | İstemci anahtarı ya da oyuncu oturumuyla çağrı | Çağrıyı sunucu anahtarıyla, sunucunuzdan yapın |
422 (tablo kaydı) | Şanslar 10000’e tamamlanmıyor ya da sınır aşıldı | Satırları düzeltin; nothing satırıyla tamamlayın |
422 envanter dolu | Verilecek eşya için boş yuva yok | Oyuncuya yer açtırın; işlem hiç yazılmadı, tekrar denenebilir |
422 arz tavanı | Para birimi max_supply sınırı | Tavanı panelden yükseltin |
422 idempotency mismatch | Aynı anahtar, farklı gövde | Yeni anahtar kullanın |
404 tablo yok | key yanlış ya da tablo henüz kaydedilmedi | GET /v1/reward-tables/{key} ile doğrulayın |
Çalışan örnek
Hoş geldin tablosundan para verme ve ardından mağazadan alma akışı Ekonomi sayfasındadır. TypeScript’te crx.grantRewardTable("welcome_pack", { playerId, source, idempotencyKey }) çağrısı aynı uca gider; idempotencyKey verilmezse SDK çağrı başına üretir, ağ tekrarında aynı anahtarı kendiniz vermelisiniz.
İlgili sayfalar
Klanlar ve partiler
Bu sayfa kalıcı oyuncu topluluklarını (klan) ve geçici takımları (parti) Open Play’de nasıl kuracağınızı ve yöneteceğinizi anlatır. Üyelik, davet, klan hazinesi, klan XP’si ve parti ödül dağıtımını güvenilir bir sunucudan yönetmek istiyorsanız okuyun.
Ne işe yarar
Sosyal modül (social) iki yapıyı yönetir:
- Klan (clan): Kalıcı topluluk. Lider, subay ve üye rolleri, davet ve başvuru akışı, ortak hazine (para birimi) ve XP/seviye vardır.
- Parti (party): Geçici takım. Kapasitesi, ganimet kuralı ve ödül bölüştürmesi vardır; dağılınca sona erer.
Önemli: Bu uçların hepsi sunucu anahtarıyla çağrılır. Oyuncu istemcisi doğrudan klan ya da parti ucunu çağıramaz; oyuncunun kimliği isteğin gövdesinde (actor_player_id gibi) sizin güvenilir sunucunuz tarafından yazılır. Oyuncunun “kendi klanını yönetebildiğini” doğrulamak sizin sunucunuzun işidir; Open Play klan içindeki rol kurallarını (kimin kimi atabileceği, hazineden kimin çekebileceği) uygular.
Modül kapalıysa uçlar 404 ve {"code":"module_disabled","module":"social"} döner. Modülü Oyun ayarları › Modüller sayfasından açın.
Panelde nerede
| Ne yapacaksınız | Panel sayfası |
|---|---|
| Klanları listelemek, üyelik, davet, başvuru, kasa ve komut geçmişini görmek | Klanlar |
| Partileri, üyelerini, ganimet kuralını ve ödül dağıtımlarını görmek | Partiler |
| Klan ve parti sohbeti | Sohbet, Şehir sohbeti |
| Klan hazinesinde kullanılan para birimi | Para birimleri |
Veri modeli (düz dille)
Klan
name(3–64 karakter),tag(2–8 karakter),leader_player_id,xp,highest_level_reached,state(activeya dadisbanded) vemembers.- Roller:
leader,officer,member. - Ortam ayarları (
/v1/clan-settings):max_members(üye sınırı),request_ttl_seconds(davet ve başvuru ömrü),officer_can_withdraw(subay hazineden çekebilir mi) velevel_curve_key(klan seviyesi için seviye eğrisi). - Davet (invite): Klanın oyuncuya gönderdiği çağrı. Durumları
pending,accepted,declined,revoked,expired. - Başvuru (application): Oyuncunun klana başvurusu. Durumları
pending,accepted,rejected,cancelled,expired. - Hazine: Klanın cüzdanı;
depositvewithdrawile para birimi hareketi yapılır ve defterdeclan_treasuryolarak görünür.
Parti
leader_player_id,capacity(pozitif),loot_rule(equal: eşit pay,weighted: baz puan payları),state(active,disbanded) vemembers.- Davet:
share_bp(üyenin baz puan payı;weightedkuralda payların toplamı tam 10000 olmalıdır) taşır ve 24 saat geçerlidir. Durumlarıpending,accepted,expired. - Ödül dağıtımı: Tek bir para birimi tutarını üyelere böler. Eşit dağıtımda artık kuruşlar
player_idsırasına göre dağıtılır; sonuç her zaman belirlenimcidir. Dağıtım kaydı üye anlık görüntüsünü, bacakları,delivery_mode(inlineya daoutbox) ve durumu (processing,queued,completed) taşır.
Oyunun yaptığı çağrılar
Hepsi sunucu (ya da yönetici) anahtarıyla:
Authorization: Bearer crx_live_<önek>_<gizli>
İstemci anahtarı ve oyuncu oturumu reddedilir (403).
Klan
| Yöntem ve yol | Gövde | Ne yapar |
|---|---|---|
GET /v1/clan-settings, PATCH /v1/clan-settings | max_members, request_ttl_seconds, officer_can_withdraw, level_curve_key | Ortam ayarlarını okur / günceller |
GET /v1/clans | — | Klanları listeler |
POST /v1/clans | leader_player_id, name, tag | Klan kurar |
GET /v1/clans/{clan_id} | — | Klanı üyeleriyle okur |
PATCH /v1/clans/{clan_id} | actor_player_id, name, tag | Ad ve etiketi günceller |
POST /v1/clans/{clan_id}/invites | inviter_player_id, invitee_player_id | Davet gönderir |
GET /v1/clan-invites/{invite_id}, POST …/respond | actor_player_id, decision (accept, decline, revoke, expire) | Daveti okur / yanıtlar |
POST /v1/clans/{clan_id}/applications | applicant_player_id | Başvuru açar |
GET /v1/clan-applications/{application_id}, POST …/resolve | actor_player_id, decision (accept, reject, cancel, expire) | Başvuruyu okur / çözer |
POST /v1/clans/{clan_id}/leave | actor_player_id | Üye ayrılır |
POST /v1/clans/{clan_id}/members/kick | actor_player_id, target_player_id | Üyeyi çıkarır |
POST /v1/clans/{clan_id}/members/role | actor_player_id, target_player_id, role | Rol değiştirir |
POST /v1/clans/{clan_id}/leadership | actor_player_id, target_player_id | Liderliği devreder |
POST /v1/clans/{clan_id}/disband | actor_player_id | Klanı dağıtır |
POST /v1/clans/{clan_id}/treasury/deposit, …/withdraw | actor_player_id, currency_id, amount | Hazineye yatırır / çeker |
POST /v1/clans/{clan_id}/xp | amount | Klana XP ekler |
Klan yazma komutlarının hepsinde Idempotency-Key zorunludur. Yanıt hep aynı zarftadır: { "type": "clan" | "invite" | "application" | "settings" | "treasury" | "xp", "<tür>": { … }, "replayed": false }. Örneğin klan kurma:
POST /v1/clans
Authorization: Bearer crx_live_<önek>_<gizli>
Idempotency-Key: clan-kur-oyuncu-1234
Content-Type: application/json
{ "leader_player_id": "0192f0f2-5b1a-7c3e-9d11-4a5b6c7d8e9f", "name": "Kurt Sürüsü", "tag": "KRT" }
201 döner ve type: "clan" zarfı içinde klan kaydı gelir. TypeScript SDK’sı bu uçları tipli olarak sunar (createClan, getClan, createClanInvite, respondClanInvite, depositClanTreasury, addClanXp …); bkz. TypeScript SDK.
Parti
| Yöntem ve yol | Gövde | Ne yapar |
|---|---|---|
POST /v1/parties | leader_player_id, capacity, loot_rule | Parti kurar |
GET /v1/parties?player_id= | — | Oyuncunun partilerini listeler |
GET /v1/parties/{party_id} | — | Partiyi üyeleriyle okur |
PATCH /v1/parties/{party_id} | actor_player_id, capacity | Kapasiteyi günceller |
POST /v1/parties/{party_id}/invites | inviter_player_id, invitee_player_id, share_bp | Davet gönderir |
POST /v1/party-invites/{invite_id}/accept | actor_player_id | Daveti kabul eder |
POST /v1/parties/{party_id}/leave | actor_player_id | Üye ayrılır |
POST /v1/parties/{party_id}/disband | actor_player_id | Partiyi dağıtır |
POST /v1/parties/{party_id}/rewards | currency_key, amount | Ödülü üyelere böler |
Parti ödül dağıtımında Idempotency-Key zorunludur; aynı anahtarla tekrar aynı dağıtımı replayed: true ile döndürür, ikinci dağıtım yapmaz. Diğer parti komutları Idempotency-Key istemez.
Not
TypeScript SDK’sında parti uçları için tipli istemci yoktur; ham REST ile çağrılır.
Sürümleme ve tekrar güvenliği
- Klan komutları ve parti ödül dağıtımı
Idempotency-Keyister: aynı anahtar ve aynı gövde tekrar çalışmaz (replayed: true); aynı anahtar farklı gövde422; uçuşta aynı anahtar409. If-Matchbu modülde kullanılmaz.- Genel kurallar: Idempotency ve eşzamanlılık.
Olaylar
Klan ve parti olayları (ClanMemberJoined, ClanXpAdded, PartyMemberJoined, RewardDistributed …) kural otomasyonunda ve görev hedeflerinde kullanılabilir. Webhook filtresi olarak seçilebilen türler arasında klan ya da parti olayı yoktur; filtresiz kayıtlı uç noktalar bütün olayları alır ve bunlara klan/parti olayları dahildir, ancak zarf biçimi belgelenmiş bir sözleşme değildir. Seçilebilir türler: Webhook olayları.
Sınırlar
- Klan adı 3–64, etiketi 2–8 karakter.
- Parti kapasitesi pozitif olmalı; kapasite aşımı reddedilir. Parti daveti 24 saat geçerlidir.
- Klan üye sınırı ve davet/başvuru ömrü ortam ayarlarındadır.
- Parti ödülünde
weightedpayların toplamı 10000 olmalıdır;amountpozitif olmalıdır.
Sık görülen hatalar
| Belirti | Neden | Çözüm |
|---|---|---|
403 | Oyuncu oturumu ya da istemci anahtarıyla çağrı; ya da actor_player_id’nin klan içinde bu işlem için yetkisi yok (örn. üye başka üyeyi atamaz) | Çağrıyı sunucu anahtarıyla yapın; actor_player_id rolünü kontrol edin |
400 | Idempotency-Key eksik; klan adı/etiketi uzunluk ya da karakter kuralına uymuyor; XP ya da tutar pozitif değil; parti kapasitesi pozitif değil | Girdiyi düzeltin |
409 | Aynı ad ya da etiketle klan var; oyuncu zaten başka bir aktif klanda/partide; bekleyen davet ya da başvuru zaten var; aynı anahtar uçuşta | Çakışan kaydı okuyup kararı oyuna bırakın |
422 | Parti kapasitesi/pay kuralları (kapasite aşımı, weighted pay toplamı 10000 değil, yinelenen oyuncu) ya da aynı anahtar farklı gövde | Girdiyi düzeltin; yeni anahtar kullanın |
404 | Klan, davet ya da parti yok | Kimlikleri GET ile doğrulayın |
Çalışan örnek
TypeScript’te klan kurup davet gönderme (SDK’nın tipli klan istemcisiyle):
/** Güvenilir backend örneği: klan kurar ve bir oyuncuya davet gönderir. Server anahtarı yalnız sunucuda durur. */
import { CrxClient } from "@ferdiunal/open-play-ts";
/** Lider için klan kurar, ardından davet gönderir; her yazma kendi `Idempotency-Key`'iyle tekrar güvenlidir. */
export async function foundClanAndInvite(baseUrl: string, serverApiKey: string, leaderId: string, friendId: string): Promise<string> {
const crx = new CrxClient({ baseUrl, apiKey: serverApiKey });
const created = await crx.createClan({
body: { leader_player_id: leaderId, name: "Kurt Sürüsü", tag: "KRT" },
headers: { "Idempotency-Key": `clan-kur-${leaderId}` },
});
if (created.type !== "clan") throw new Error("Beklenmeyen yanıt zarfı");
await crx.createClanInvite({
path: { clan_id: created.clan.id },
body: { inviter_player_id: leaderId, invitee_player_id: friendId },
headers: { "Idempotency-Key": `davet-${created.clan.id}-${friendId}` },
});
return created.clan.id;
}
İlgili sayfalar
Sohbet
Bu sayfa oyuncuların birbirine yazdığı kanal sohbetini (global, dünya, klan, parti ve birebir) anlatır. Oyuncu oturumuyla mesaj göndermek, geçmişi okumak ve canlı mesaj almak istiyorsanız okuyun.
Ne işe yarar
Sohbet modülü (chat) kanal tabanlı metin sohbeti sağlar. Mesajlar kalıcı arşive yazılır; canlı dağıtım ayrıca WebSocket ile yapılır. Aynı mesaj hem REST hem WebSocket üzerinden gönderilebilir ve ikisi de aynı kuralları (susturma, hız sınırı, küfür süzgeci, tekrar koruması) uygular.
Oyuncunun kendi oturumuyla çalışır. API anahtarıyla sohbet uçları çağrılamaz.
Modül kapalıysa uçlar 404 ve {"code":"module_disabled","module":"chat"} döner; sohbet soketi ise önce bir error çerçevesi (code: "module_disabled") gönderip kapanır. Modülü Oyun ayarları › Modüller sayfasından açın.
Panelde nerede
| Ne yapacaksınız | Panel sayfası |
|---|---|
| Modülü açmak ya da kapatmak | Oyun ayarları › Modüller |
| Şehir (sahne) eklentisinin sohbetini okumak, mesajı silmek, oyuncuyu susturmak | Şehir sohbeti |
Not
Panelin “Şehir sohbeti” ekranı sahne eklentisinin sohbetini yönetir; bu sayfadaki kanal sohbeti için panelde mesaj okuma, silme ya da susturma ekranı henüz yoktur.
Veri modeli (düz dille)
-
Kanal (channel):
kindile ayrılır:kindreference_idKim girebilir globalyok Ortamdaki herkes worldgerekli (dünya/harita UUID’si) Referansı bilen oyuncular clangerekli (klan UUID’si) Klanın üyeleri partygerekli (parti UUID’si) Partinin üyeleri directyok; direct_player_idgerekliYalnız iki oyuncu Aynı türde ve aynı referansta kanal bir kez kurulur; yeniden istemek var olan kanalı döndürür.
directkanalda diğer oyuncu kendiniz olamaz. -
Mesaj:
id,channel_id,sender_player_id,client_message_id,body,sent_at_ms. -
client_message_id: İstemcinin ürettiği tekrar anahtarı (boş olamaz, en çok 200 karakter). Aynı kanalda aynı değerle ikinci gönderim yeni mesaj üretmez; var olan mesajıduplicate: trueile geri döner. -
Susturma: Oyuncunun
all,global,world,clan,partyya dadirectkapsamında susturulması. Susturulmuş oyuncunun gönderimi403döner.
Oyunun yaptığı çağrılar
Bütün sohbet uçları oyuncu oturumuyla çağrılır: oturum çerezi ya da opak oturum belirteci (Authorization: Bearer <oturum belirteci>) ve ortam başlığı:
x-crx-env: <ortam uuid>
Bu uçlarda x-csrf-token çift gönderimi ve Origin denetimi uygulanmaz; oturum çerezi ya da oturum belirteci yeterlidir (mağaza satın alma ucundan farklı olarak). Oturum kuralları: Oturumlar ve CSRF.
| Yöntem ve yol | Ne yapar |
|---|---|
POST /v1/chat/channels | Kanal kurar ya da var olanı döndürür |
GET /v1/chat/channels | Oyuncunun yetkili olduğu kanalları listeler |
POST /v1/chat/channels/{channel_id}/messages | Mesaj gönderir |
GET /v1/chat/channels/{channel_id}/messages | Arşivi geriye doğru okur (before_ms, limit 1–100, varsayılan 50) |
GET /v1/chat/ws | Canlı sohbet WebSocket’i |
Not
TypeScript ve Unity SDK’larında sohbet için hazır istemci yoktur; uçlar ham REST ve WebSocket ile çağrılır. Bkz. TypeScript SDK.
Kanal kurmak
POST /v1/chat/channels
x-crx-env: <ortam uuid>
Content-Type: application/json
{ "kind": "clan", "reference_id": "0192f0aa-…" }
{ "channel": { "id": "0192f2bb-…", "environment_id": "…", "kind": "clan", "reference_id": "0192f0aa-…", "participant_a": null, "participant_b": null, "created_at_ms": 1790000000000 } }
Klan ya da parti üyesi olmayan oyuncunun o kanalı kurması ya da okuması reddedilir.
Mesaj göndermek
POST /v1/chat/channels/0192f2bb-…/messages
x-crx-env: <ortam uuid>
Content-Type: application/json
{ "client_message_id": "c-0001", "body": "Merhaba!" }
{ "message": { "id": "…", "channel_id": "0192f2bb-…", "sender_player_id": "…", "client_message_id": "c-0001", "body": "Merhaba!", "sent_at_ms": 1790000000123 }, "duplicate": false }
Kurallar, sırasıyla:
client_message_idboş ya da 200 karakterden uzunsa400.- Gövde 1–2000 Unicode karakter olmalı ve en az bir boşluk dışı karakter içermelidir; aksi
400. - Oyuncu o kanal için susturulmuşsa
403. - Hız sınırı: oyuncu başına 10 saniyede en çok 20 mesaj; aşımı
429döner. - Küfür süzgeci: mesajda yasaklı bir sözcük (boşlukla ayrılmış tam sözcük, büyük/küçük harf duyarsız) varsa
422döner. - Mesaj arşive yazılır, ardından canlı abonelere dağıtılır. Dağıtım başarısız olsa bile arşivlenmiş mesaj silinmez.
Arşivi okumak
GET /v1/chat/channels/{channel_id}/messages?before_ms=1790000000000&limit=50 yanıtı { "messages": [ … ] } döner. before_ms, bu Unix milisaniyesinden eski mesajları ister; bir sonraki sayfa için en eski mesajın sent_at_ms değerini verin.
Canlı sohbet (WebSocket)
GET /v1/chat/ws adresine bağlanırken x-crx-env ve oturum kimliği (çerez ya da Authorization: Bearer) başlık olarak gönderilir. Kimlik doğrulanmadan yükseltme yapılmaz (401); modül kapalıysa 404.
Uyarı
Tarayıcıdaki
WebSocketAPI’si özel başlık (x-crx-env) gönderemez; bu nedenle chat soketine tarayıcıdan doğrudan bağlanılamaz. Tarayıcı oyunları REST ile yoklayabilir; native istemciler (örneğin Unity masaüstü/mobil) başlık ekleyerek bağlanabilir. Başlık yerine sorgu parametresi ya da alt protokol henüz desteklenmez.
İstemci çerçeveleri (JSON; type alanı küçük camelCase, diğer alanlar snake_case):
type | Alanlar | Anlamı |
|---|---|---|
subscribe | channel_id | Kanalın canlı akışına abone ol |
unsubscribe | — | Aboneliği bırak |
send | channel_id, client_message_id, body | REST’teki gibi mesaj gönder |
ping | nonce | Canlılık yoklaması |
Sunucu çerçeveleri:
type | Alanlar |
|---|---|
subscribed | channel_id |
unsubscribed | — |
message | message, duplicate |
pong | nonce |
error | code (invalid_frame, invalid_payload, forbidden_channel, unavailable, message_rejected, module_disabled) |
Bir soket aynı anda tek kanala abonedir. Tanınmayan alan içeren çerçeve invalid_frame alır. Modül sonradan kapanırsa açık soket de kapatılır. Genel gerçek zamanlı yüzey için bkz. Gerçek zamanlı: genel bakış.
Sürümleme ve tekrar güvenliği
- Mesaj gönderiminde
Idempotency-Keybaşlığı yoktur; tekrar güvenliğiclient_message_idile sağlanır. Ağ hatasında aynı değerle yeniden gönderin: mesaj bir kez görünür (duplicate: true). If-Matchkullanılmaz.
Olaylar
Sohbet olayı webhook olarak gönderilmez; webhook olay türleri arasında sohbet yoktur. Canlı akış için WebSocket kullanın.
Sınırlar
- Mesaj gövdesi 1–2000 karakter;
client_message_iden çok 200 karakter. - Gönderim hızı: oyuncu başına 10 saniyede 20 mesaj.
- Arşiv sayfası 1–100 mesaj.
- Bir WebSocket aynı anda tek kanala abone olabilir.
Sık görülen hatalar
| Belirti | Neden | Çözüm |
|---|---|---|
401 | Oturum yok, süresi dolmuş ya da x-crx-env eksik | Oturumu yenileyin; başlığı ekleyin |
403 (gönderim) | Oyuncu susturulmuş ya da kanalda yetkisi yok | Kullanıcıya bilgi verin |
400 | Boş ya da çok uzun gövde / client_message_id | Girdiyi düzeltin |
422 | Küfür süzgeci mesajı reddetti | Mesajı değiştirin |
429 | 10 saniyede 20 mesaj aşıldı | Bekleyip yeniden deneyin |
error: forbidden_channel (WS) | Kanal için yetki yok | Kanalı önce REST ile kurun / yetkiyi doğrulayın |
Çalışan örnek
Oturum çerezi (cookies.txt) ile REST üzerinden bir kanala yazıp geçmişi okuma:
curl -X POST "$API/v1/chat/channels/$CHANNEL/messages" \
-H "x-crx-env: $ENV" \
-H "Content-Type: application/json" -b cookies.txt \
-d '{"client_message_id":"c-0001","body":"Merhaba!"}'
curl "$API/v1/chat/channels/$CHANNEL/messages?limit=20" \
-H "x-crx-env: $ENV" -b cookies.txt
İlgili sayfalar
Skor tabloları ve turnuvalar
Bu sayfa oyuncuların puanla yarıştığı skor tablolarını (leaderboard) ve eleme usulü turnuvaları anlatır. Puanı güvenilir sunucudan yazıp oyun içinde sıralamayı göstermek istiyorsanız okuyun.
Ne işe yarar
Rekabet modülü (competition) iki şey sağlar:
- Skor tablosu: Oyuncu başına en iyi puanı tutan, sezonlara bölünebilen sıralama.
- Turnuva: Oyuncu ya da klan katılımcılarıyla tek eleme, çift eleme ya da lig usulü bracket; final ödülü ile.
Puan yazma ve tablo yönetimi sunucu anahtarıyla yapılır. Oyun istemcisi tabloyu oyuncu oturumuyla okur ve sunucu anahtarı gerekmez.
Modül kapalıysa uçlar 404 ve {"code":"module_disabled","module":"competition"} döner. Modülü Oyun ayarları › Modüller sayfasından açın.
Panelde nerede
| Ne yapacaksınız | Panel sayfası |
|---|---|
| Tablo tanımlamak, sezon, birim ve görünürlük ayarlamak | Leaderboard |
| Bir tablonun en yüksek kayıtlarını ve sezon geçmişini görmek | Leaderboard ayrıntısı |
| Turnuva için ödül para birimi | Para birimleri |
Turnuvalar için panel ekranı yoktur; yalnız REST ile yönetilir.
Veri modeli (düz dille)
- Tablo tanımı:
key,name,metric_expr,order(asc: küçük puan iyi,desc: büyük puan iyi),season,tie_policy,player_visible,unitveunit_suffix. Tanım sürümlüdür. - Sezon (
season):none(hiç sıfırlanmaz),daily,weekly,monthly(UTC takvimine hizalı: gün 00:00 UTC’de, hafta Pazartesi 00:00 UTC’de, ay ayın birinde döner) ya dacustom(custom_period_msuzunluğunda dönem). Sezon kapanınca sıralaması değişmez bir kayda alınır. - Puan: Tam sayı (
i64). Bir oyuncunun sezondaki en iyi puanı sayılır (desc’te en yüksek,asc’te en düşük). Daha kötü bir puan göndermek sıralamayı değiştirmez. - Eşitlik (
tie_policy): Şimdilik tek seçenekscore_achieved_player_id: önce puan, sonra o puana ilk ulaşan, sonra oyuncu kimliği. - Sıra (
rank): 1’den başlar. - Birim (
unit):points,money(en küçük para birimi) ya daduration_ms;unit_suffix1–8 karakterlik ektir ($,ms…). Birim yalnız gösterim içindir. player_visible:trueise oyuncu oturumu tabloyu okuyabilir; varsayılanfalse.metric_expr: Kayıt anında derlenen CEL ifadesi (zorunlu, boş olamaz). Eklentilerin kendiliğinden kurduğu tablolarevent.scorekullanır; REST ile kurarken de aynı ifadeyi yazın.
Oyunun yaptığı çağrılar
| Yöntem ve yol | Kimlik | Ne yapar |
|---|---|---|
POST /v1/leaderboards | sunucu anahtarı | Tablo tanımı oluşturur |
GET /v1/leaderboards, GET /v1/leaderboards/{key} | sunucu anahtarı | Tanımları listeler / okur |
POST /v1/leaderboards/{key}/scores | sunucu anahtarı | Oyuncu puanı yazar (Idempotency-Key zorunlu, 202) |
GET /v1/leaderboards/{key}/entries?limit=&cursor= | sunucu anahtarı | İlk sıralar (sayfalı) |
GET /v1/leaderboards/{key}/around-me?player_id=&radius= | sunucu anahtarı | Oyuncunun çevresindeki sıralar |
GET /v1/player/leaderboards/{key}?limit= | oyuncu oturumu | Tablonun ilk sayfası ve oyuncunun kendi satırı |
POST /v1/tournaments | sunucu anahtarı | Turnuva oluşturur |
GET /v1/tournaments/{id} | sunucu anahtarı | Turnuva durumunu okur |
POST /v1/tournaments/{id}/participants | sunucu anahtarı | Katılımcı kaydeder (Idempotency-Key) |
POST /v1/tournaments/{id}/start | sunucu anahtarı | Bracket üretip başlatır |
POST /v1/tournaments/{id}/matches/{match_id}/result | sunucu anahtarı | Maç sonucu bildirir ya da itirazı çözer (Idempotency-Key) |
Sunucu uçları Authorization: Bearer crx_live_<önek>_<gizli> ister; istemci anahtarı ve oyuncu oturumu reddedilir. Oyuncu ucu çerez ya da oturum belirteci ve x-crx-env: <ortam uuid> ile çalışır; geliştirici anahtarı kabul edilmez.
Not
TypeScript SDK’sında oyuncu okuması için
player.leaderboard(key, { limit })vardır; sunucu uçları (puan yazma, tanım, turnuva) için tipli istemci yoktur ve ham REST ile çağrılır. Bkz. TypeScript SDK.
Tablo tanımı
POST /v1/leaderboards
Authorization: Bearer crx_live_<önek>_<gizli>
Content-Type: application/json
{
"key": "daily-earnings", "name": "Günlük kazanç",
"metric_expr": "event.score", "order": "desc",
"season": "daily", "tie_policy": "score_achieved_player_id",
"player_visible": true, "unit": "money", "unit_suffix": "$"
}
201 döner ve { id, key, name, metric_expr, order, season, custom_period_ms, tie_policy, season_key } gelir. season: "custom" için custom_period_ms pozitif olmalıdır.
Puan yazmak
POST /v1/leaderboards/daily-earnings/scores
Authorization: Bearer crx_live_<önek>_<gizli>
Idempotency-Key: score-oyuncu-1234-2026-11-03
Content-Type: application/json
{ "player_id": "0192f0f2-5b1a-7c3e-9d11-4a5b6c7d8e9f", "score": 4200 }
{ "entry": { "rank": 7, "player_id": "0192f0f2-…", "score": 4200, "achieved_at_ms": 1790000000000 }, "replayed": false }
Yanıt 202’dir: puan kalıcı olarak kabul edilmiştir; sıralama projeksiyonu kısa bir gecikmeyle güncellenir, bu yüzden hemen ardından okunan tablo birkaç saniye geride kalabilir. Idempotency-Key zorunludur: aynı anahtar ve aynı gövde aynı sonucu replayed: true ile döndürür.
Tabloyu oyuncu oturumuyla okumak
GET /v1/player/leaderboards/daily-earnings?limit=10
x-crx-env: 0192f000-0000-7000-8000-00000000e001
{
"leaderboard": { "key": "daily-earnings", "name": "Günlük kazanç", "order": "desc", "season": "daily", "seasonKey": "2026-11-03", "seasonEndsAtMs": 1790121600000, "unit": "money", "unitSuffix": "$" },
"entries": [ { "rank": "1", "playerId": "…", "displayName": "Ayşe", "score": "9800", "achievedAtMs": 1790000000000 } ],
"me": { "rank": "7", "playerId": "…", "displayName": "Siz", "score": "4200", "achievedAtMs": 1790000000000 }
}
- Yalnız
player_visibletablolar okunur; aksi404. Modül kapalıysa da404. limit1–50 (varsayılan 20).rankvescoreJSON’da ondalık metindir (kayıpsızi64); SDK bunlarıbigintyapar. Alan adları bu uçta camelCase’tir.- Yasaklı ve silinmiş oyuncular süzülür ve sıra sayfa içinde yoğun numaralanır;
me, görünür oyuncular arasındaki sıranızdır. Bu sezonda puanı yoksamenull’dır. - Birinci sayfa kısa süre (en çok birkaç saniye) önbelleğe alınır.
Turnuvalar
POST /v1/tournaments
Authorization: Bearer crx_live_<önek>_<gizli>
Content-Type: application/json
{
"name": "Kış Kupası", "format": "single_elimination", "participant_type": "player",
"capacity": 16,
"registration_opens_at_ms": 1790000000000, "registration_closes_at_ms": 1790086400000,
"seeding_source": "registration_order",
"prize_table": { "currency_key": "gold", "amount": 5000 }
}
format:single_elimination,double_elimination,round_robin.participant_type:playerya daclan.capacity2–1024; kayıt kapanışı açılıştan sonra olmalı;name1–200 karakter.seeding_source:registration_order(kayıt sırası;leaderboard_idverilmez) ya daleaderboard(yalnız oyuncu turnuvasında;leaderboard_idzorunlu).prize_table:currency_key(boşluksuz, en çok 200 karakter) ve pozitifamountiçeren nesne.- Akış: oluştur →
participantsile kaydet ({ "participant_id" }) →startile bracket’i üret → her maç içinresultbildir (reporter_id,reported_side:homeawayadmin,outcome:home_winaway_windraw,score).admintarafı itirazı çözmek içindir. - Yanıtlar turnuvanın güncel görünümünü (
{ "tournament": { … } }) taşır.
Sürümleme ve tekrar güvenliği
- Puan yazma, katılımcı kaydı ve maç sonucu
Idempotency-Keyister (aynı anahtar + aynı gövde: tekrar çalışmaz; farklı gövde:422). - Tablo tanımı sürümlüdür; liste ve sıralama okumaları sürüm başlığı istemez.
- Genel kurallar: Idempotency ve eşzamanlılık.
Olaylar
Puan kabulü score_submitted, sezon geçişi season_closed/season_opened olaylarını üretir; bunlar görev hedeflerinde ve kural otomasyonunda kullanılabilir. Webhook filtresi olarak seçilebilen türler arasında skor tablosu ya da turnuva olayı yoktur; filtresiz kayıtlı uç noktalar bütün olayları alır ve bunlara skor olayları da dahildir, ancak zarf biçimi belgelenmiş bir sözleşme değildir. Final ödülü için Ödüller sayfasındaki ödül verme akışını kullanın.
Sınırlar
- Oyuncu okumasında
limit1–50; sunucuentriesuçlarında sayfalama imleçlidir. - Turnuva
capacity2–1024. season: customiçin pozitifcustom_period_msgerekir.
Sık görülen hatalar
| Belirti | Neden | Çözüm |
|---|---|---|
404 (oyuncu okuması) | Tablo player_visible değil, yok ya da modül kapalı | Tanımı kontrol edin |
403 | İstemci anahtarı ya da oyuncu oturumuyla sunucu ucu | Sunucu anahtarını sunucudan kullanın |
400 (Idempotency-Key) | Puan yazarken başlık yok | Anahtar gönderin |
| Puan yazıldı ama sıralama değişmedi | Oyuncunun sezondaki en iyi puanı daha iyi | Yalnız daha iyi puan sıralamayı değiştirir |
| Puan yazıldı ama tablo hemen güncellenmedi | Projeksiyon gecikmesi | Birkaç saniye bekleyip okuyun |
400 (turnuva) | capacity, kayıt penceresi, prize_table ya da seed kuralı hatalı | Gövdeyi düzeltin |
Çalışan örnek: puan yaz, tabloyu oku
/** Skor tablosu: sunucu puan yazar (ham REST), oyun istemcisi tabloyu oyuncu oturumuyla okur. */
import type { PlayerClient } from "@ferdiunal/open-play-ts";
/** Sunucu: `POST /v1/leaderboards/{key}/scores`. Sunucu anahtarı gerekir; Idempotency-Key zorunludur. */
export async function submitScore(baseUrl: string, serverApiKey: string, board: string, playerId: string, score: number, requestKey: string): Promise<number> {
const response = await fetch(`${baseUrl}/v1/leaderboards/${encodeURIComponent(board)}/scores`, {
method: "POST",
headers: {
Authorization: `Bearer ${serverApiKey}`,
"Content-Type": "application/json",
"Idempotency-Key": requestKey,
},
body: JSON.stringify({ player_id: playerId, score }),
});
if (response.status !== 202) throw new Error(`Puan yazılamadı: HTTP ${response.status} ${await response.text()}`);
const body = (await response.json()) as { entry: { rank: number }; replayed: boolean };
return body.entry.rank;
}
/** Oyun istemcisi: tablonun ilk sayfası ve oyuncunun kendi satırı (`player_visible` tablolar). */
export async function showBoard(player: PlayerClient, board: string): Promise<void> {
const view = await player.leaderboard(board, { limit: 10 });
for (const row of view.entries) console.log(`${row.rank}. ${row.displayName} — ${row.score}`);
if (view.me !== null) console.log(`Siz: ${view.me.rank}. sıra, ${view.me.score} puan`);
}
İlgili sayfalar
Bildirimler
Bu sayfa oyuncuya oyun içi (gelen kutusu) ve push bildirimi göndermenin yolunu anlatır: panelde sağlayıcı, şablon ve kural kurulumu; oyunun cihaz kaydı, gelen kutusu okuması ve sunucudan doğrudan gönderim. Bildirim altyapısını kendiniz yazmadan kullanmak istiyorsanız okuyun.
Ne işe yarar
Bildirim modülü (notifications) bir bildirimi önce kuyruğa yazar, sonra arka plandaki işçi sağlayıcıya (FCM, APNs ya da OneSignal) gönderir. API’de senkron push gönderimi yoktur: isteğiniz kuyruğa yazıldığında 200 alırsınız; teslimat sonradan olur.
Bildirimin metni şablondan gelir. Şablon panelde yazılır; oyun yalnız şablon anahtarını ve doldurma verisini gönderir. Bildirimi iki yolla üretebilirsiniz:
- Sunucudan gönderim: Oyun sunucunuz
POST /v1/notificationsçağırır. - Kural: Panelde kurduğunuz kural, bir oyun olayı olunca (ör. seviye atlama, görev tamamlama, mağaza satın alma) otomatik bildirim üretir.
Modül kapalıysa uçlar 404 ve {"code":"module_disabled","module":"notifications"} döner. Modülü Oyun ayarları › Modüller sayfasından açın.
Panelde nerede
| Ne yapacaksınız | Panel sayfası |
|---|---|
| Push sağlayıcısı (FCM, APNs, OneSignal) kimlik bilgilerini girmek | Bildirimler › Sağlayıcılar |
| Şablon yazmak (dil başına başlık ve gövde, yer tutucular) | Bildirimler › Şablonlar |
| Olay tetikli kural kurmak, kuralı canlı önizlemek | Bildirimler › Kurallar |
| Oyuncuya test bildirimi göndermek, gönderim geçmişini ve cihazları görmek | Bildirimler › Geçmiş, Cihazlar |
Sağlayıcı kimlik bilgileri panelde yalnız yetkili rolle girilir ve sunucuda mühürlü saklanır; panel yalnız parmak izini gösterir.
Veri modeli (düz dille)
- Sağlayıcı (provider):
fcm,apns,one_signal. Her ortam için ayrı açılıp kapatılır. - Cihaz (device): Oyuncunun bir sağlayıcıdaki kayıtlı belirteci (
token) ve platformu (ios,android,web). Aynı (ortam, sağlayıcı, belirteç) tekrar kaydedilebilir; yanıt hangi dalın işlediğini söyler (created,revived,refreshed). - Şablon (template): Anahtar, dil başına başlık ve gövde,
{{yer_tutucu}}alanları. İstenen dil yoksa İngilizce (en) kullanılır. Her bildirim, gönderildiği andaki şablon sürümüne bağlanır. - Kanal:
in_game(yalnız gelen kutusu),push(yalnız push),both. - Bildirim (inbox satırı):
id,template_key,title,body,data,channel,status,created_at,sent_at,read_at. Durum:queued,sent,delivered,failed,read. - Tekrar anahtarı (
dedup_key): Aynı (ortam, oyuncu, anahtar) ikinci kez yazılmaz.
Oyunun yaptığı çağrılar
İki kimlik türü vardır: oyuncu oturumu (çerez ya da oturum belirteci + x-crx-env: <ortam uuid>) ve sunucu anahtarı (Authorization: Bearer crx_live_<önek>_<gizli>).
| Yöntem ve yol | Kimlik | Ne yapar |
|---|---|---|
POST /v1/notifications | sunucu anahtarı | Bir oyuncuya bildirim kuyruğa yazar |
GET /v1/notifications | oyuncu oturumu | Gelen kutusu (status, cursor, limit) |
POST /v1/notifications/{id}/read | oyuncu oturumu | Okundu işaretler |
POST /v1/devices | oyuncu oturumu | Push cihazını kaydeder |
DELETE /v1/devices/{token}?provider= | oyuncu oturumu | Cihaz kaydını iptal eder (204) |
GET /v1/push/config | kimliksiz (x-crx-env zorunlu) | Web push için istemciye açık ayarlar |
GET /v1/ws | oyuncu oturumu | Canlı bildirim itme soketi (yalnız sunucudan oyuncuya; ortam x-crx-env başlığıyla verilir, bu yüzden tarayıcı WebSocket API’siyle bağlanılamaz; çerçeveler en çok bir kez gelir, kalıcı yüzey gelen kutusudur) |
Oyuncu uçlarında x-csrf-token ve Origin denetimi uygulanmaz; oturum çerezi ya da oturum belirteci yeterlidir.
TypeScript SDK’sında oyuncu tarafı hazırdır: player.notifications altında getPushConfig, registerDevice, unregisterDevice, enableWebPush, disableWebPush, inbox ve markRead bulunur. Sunucudan gönderim için tipli istemci yoktur; ham REST kullanılır. Bkz. TypeScript SDK.
Sunucudan bildirim göndermek
POST /v1/notifications
Authorization: Bearer crx_live_<önek>_<gizli>
Content-Type: application/json
{
"player_id": "0192f0f2-5b1a-7c3e-9d11-4a5b6c7d8e9f",
"template_key": "daily_reward_ready",
"locale": "tr",
"data": { "amount": 250 },
"channel": "both",
"dedup_key": "daily-2026-11-03"
}
{ "id": "0192f400-…", "duplicate": false }
locale: kısa dil kodu (tr,en…). İstenen dil şablonda yoksaenkullanılır.dedup_key(isteğe bağlı, 1–256 karakter): aynı anahtar ikinci kez gelirse yeni satır yazılmaz;200veduplicate: trueile ilk bildirimin kimliği döner.403: istemci anahtarı ya da oyuncu oturumu.404: şablon hiçbir dilde yok.400:template_keyboş ya da 128 karakterden uzun,localebiçimi geçersiz ya da şablondaki bir yer tutucudataiçinde eksik.
Gelen kutusunu okumak
GET /v1/notifications?status=queued&limit=20
x-crx-env: 0192f000-0000-7000-8000-00000000e001
{
"items": [
{ "id": "0192f400-…", "template_key": "daily_reward_ready", "template_version": 2, "title": "Günlük ödülün hazır", "body": "250 altın seni bekliyor.", "data": { "amount": 250 }, "channel": "both", "status": "sent", "created_at": "2026-11-03T09:00:00Z", "sent_at": "2026-11-03T09:00:02Z", "read_at": null }
],
"next_cursor": null
}
Liste yeniden eskiye sıralıdır (created_at, id). limit 1–100; next_cursor null ise son sayfadır. Teslimi başarısız olan satırlar da listelenir. POST /v1/notifications/{id}/read satırı read yapar; ikinci çağrı aynı satırı döndürür ve yeni olay üretmez.
Push cihazı kaydetmek
POST /v1/devices
x-crx-env: 0192f000-0000-7000-8000-00000000e001
Content-Type: application/json
{ "provider": "fcm", "platform": "android", "token": "<cihaz belirteci>", "device_meta": { "model": "Pixel 8" } }
{ "id": "…", "registration": "created", "provider": "fcm", "platform": "android", "created_at": "2026-11-03T09:00:00Z" }
provider apns, fcm ya da one_signal; platform ios, android ya da web. Belirteç boş olamaz. Oyuncu kimliği gövdeden değil oturumdan gelir. app_key çok uygulamalı ortamlarda uygulamayı ayırır.
Not
Üretilmiş OpenAPI belgesi cihaz sağlayıcısını
onesignalolarak yazar; sunucu ve SDKone_signalkullanır. Bilinen bir belge sapmasıdır;one_signalgönderin.
Web push için player.notifications.enableWebPush tarayıcı izin akışını, GET /v1/push/config ile aldığı ayarlarla yürütür; çıkışta session.logout() bu sayfadan kaydedilmiş web cihazını kendiliğinden iptal eder.
Kurallar: olay olunca otomatik bildirim
Panelde bir kural; tetikleyici (kapalı bir listeden bir oyun olayı; örneğin level_up, quest_completed, store_purchase_completed, vip_tier_up), isteğe bağlı koşul, şablon, dil, kanal ve alıcı oyuncu yolundan oluşur. Kural sürümleri panelin geçmiş sekmesinde görünür. Bildirimin kendisi yeni bir kural tetiklemez. Kural editörü bir “canlı önizleme” ve test gönderimi sunar. Ayrıntılı alanlar için panel sayfasına bakın.
Sürümleme ve tekrar güvenliği
- Gönderim:
dedup_keyile tekrar güvenliği;Idempotency-Keybaşlığı yoktur. - Cihaz kaydı ve okundu işareti doğal olarak idempotenttir.
- Şablon sürümü bildirime bağlanır; şablonu sonradan değiştirmek eski bildirimi etkilemez.
Olaylar
Bildirim kuyruğa yazıldığında bir notification_queued olayı üretilir ve gönderim işçisi onu tüketir. Webhook filtresi olarak seçilebilen türler arasında bildirim yoktur; filtresiz kayıtlı uç noktalar bu iç olayı da alır, ancak zarf biçimi belgelenmiş bir sözleşme değildir.
Sınırlar
dedup_key1–256 karakter; gelen kutusulimit1–100.- Push teslimatı en-iyi-çabadır: sağlayıcı reddederse satır
failedolur. Cihaz kalıcı geçersizse (örn. silinmiş uygulama) cihaz otomatik iptal edilir. - Sağlayıcı kimlik bilgileri tanımlı değilse bildirim kuyrukta bekler ve panelde sağlayıcı durumu uyarı gösterir.
Sık görülen hatalar
| Belirti | Neden | Çözüm |
|---|---|---|
403 (gönderim) | Sunucu anahtarı yerine istemci anahtarı | Sunucu anahtarını kullanın |
404 (gönderim) | template_key hiçbir dilde yok | Şablonu panelde oluşturup yayınlayın |
duplicate: true | Aynı dedup_key zaten yazıldı | Beklenen davranış; yeni bildirim için yeni anahtar |
Bildirim queued kalıyor | Sağlayıcı kapalı ya da kimlik bilgisi hatalı | Panelde sağlayıcı durumunu kontrol edin |
400 (cihaz) | Boş belirteç ya da bilinmeyen sağlayıcı/platform | Girdiyi düzeltin |
Çalışan örnek
Oyuncu tarafında gelen kutusunu boşaltma:
/** Oyuncu tarafı: gelen kutusunu okur ve okunmamış bildirimleri okundu işaretler. */
import type { PlayerClient } from "@ferdiunal/open-play-ts";
/** İlk sayfadaki okunmamış bildirimleri yazdırır ve okundu yapar. */
export async function drainInbox(player: PlayerClient): Promise<number> {
const page = await player.notifications.inbox({ limit: 20 });
let marked = 0;
for (const item of page.items) {
if (item.readAt !== null) continue;
console.log(item.title, item.body, item.data);
await player.notifications.markRead(item.id);
marked += 1;
}
return marked;
}
Sunucudan gönderim için curl örneği yukarıdadır.
İlgili sayfalar
Webhook’lar
Bu sayfa Open Play’in oyun olaylarını kendi sunucunuza HTTP POST ile nasıl ilettiğini anlatır: uç nokta kaydı, olay türleri, imza doğrulaması, yeniden deneme ve tekrar eden teslimatla başa çıkma. Karakter, mağaza ya da ödül olayında kendi arka uç sisteminizi tetiklemek istiyorsanız okuyun.
Ne işe yarar
Open Play bir olay oluştuğunda (ör. level_up, store_purchase_completed, reward_granted) kayıtlı uç noktalarınıza imzalı bir POST gönderir. Teslimat en az bir kez (at-least-once) yapılır: aynı olay ağ hataları yüzünden birden çok gelebilir, bu yüzden alıcınız tekrarı X-Crx-Event-Id ile elemelidir.
Modül kapalıysa uçlar 404 ve {"code":"module_disabled","module":"webhooks"} döner. Modülü Oyun ayarları › Modüller sayfasından açın.
Panelde nerede
| Ne yapacaksınız | Panel sayfası |
|---|---|
| Kayıtlı uç noktaları, teslimat denemelerini, başarısız (DLQ) teslimatları ve olay kuyruğunu görmek | Webhook ve olay kuyruğu |
| Modülü açmak | Oyun ayarları › Modüller |
Panel bu sayfada salt okunurdur: uç nokta kaydı REST ile yapılır; panelde yeniden gönderme ya da başarısız teslimatı kurtarma düğmesi yoktur. Panel sırları, ham gövdeyi ve ham hata metnini göstermez.
Veri modeli (düz dille)
- Uç nokta (endpoint):
url, isteğe bağlıevent_typessüzgeci,enabledvecreated_at. - Sır (secret): Sunucu üretir (
whsec_+ 64 küçük harf hex), yalnız kayıt yanıtında bir kez döner ve şifreli saklanır. Sonra hiçbir uç onu vermez. Sır değiştirme ucu yoktur: yenilemek için uç noktayı silip yeniden kaydedin. - Olay zarfı: Gönderilen JSON gövdesi. Her zarfta
event_id,type,environment_idvedatabulunur. - Teslimat (delivery): Bir olayın bir uç noktaya gönderimi. Durumları bekleyen, teslim edilen ve başarısız (DLQ).
Seçilebilir olay türleri
event_types boşsa uç nokta bütün olayları alır (aşağıdaki not). Doluysa yalnız şu türlerden seçebilirsiniz:
| Alan | Türler |
|---|---|
| Karakter | flag_set, attribute_set, resource_changed, modifier_added, modifiers_removed, xp_added, level_up, ability_unlocked, event_emitted, character_rolled_back |
| Mağaza | store_page_created, store_page_updated, store_page_deleted, store_pages_reordered, store_listing_created, store_listing_updated, store_listing_deleted, store_listings_reordered, store_purchase_initiated, store_payment_started, store_purchase_completed, store_reservation_cancelled |
| Ödül | reward_granted |
Bilinmeyen bir tür 400 döner. Tam liste ve veri alanları: Webhook olayları.
Uyarı
Süzgeci boş bırakırsanız uç nokta yukarıdaki listeyle sınırlı kalmaz: outbox’a yazılan bütün olayları (eşya, cüzdan, klan, parti, skor, bildirim kuyruğu gibi) alır. Bu ek olayların zarf biçimi belgelenmiş bir sözleşme değildir ve haber verilmeden değişebilir. Üretimde
event_typessüzgecini her zaman açıkça verin.
Zarf biçimi
Karakter olayları:
{
"event_id": "0192f500-1111-7222-8333-944455556666",
"type": "level_up",
"character_id": "0192f0f2-5b1a-7c3e-9d11-4a5b6c7d8e9f",
"environment_id": "0192f000-0000-7000-8000-00000000e001",
"seq": 12,
"data": { "...": "olaya özgü alanlar" }
}
Mağaza olaylarında character_id yoktur; seq ile birlikte now_ms (olayın işlendiği an) ve actor_api_key_id bulunur. reward_granted olayında player_id ve data içinde source_kind, table_key, table_version ile verilenler yer alır; çekiliş tohumu hiçbir olayda yoktur.
Oyunun yaptığı çağrılar
Bütün yönetim uçları sunucu anahtarıyla çağrılır; istemci anahtarı 403 alır:
Authorization: Bearer crx_live_<önek>_<gizli>
| Yöntem ve yol | Ne yapar |
|---|---|
POST /v1/webhooks | Uç nokta kaydeder (201; sır yalnız burada) |
GET /v1/webhooks | Uç noktaları listeler (cursor, limit 1–200, varsayılan 50) |
GET /v1/webhooks/{id} | Tek uç noktayı okur (sırsız) |
DELETE /v1/webhooks/{id} | Uç noktayı siler (yumuşak silme, 204) |
TypeScript SDK’sı bu dört ucu tipli sunar: createWebhook, listWebhooks, getWebhook, deleteWebhook (bkz. TypeScript SDK).
Uç nokta kaydetmek
POST /v1/webhooks
Authorization: Bearer crx_live_<önek>_<gizli>
Content-Type: application/json
{
"url": "https://hooks.ornek-oyun.com/open-play",
"event_types": ["level_up", "store_purchase_completed"]
}
{
"id": "0192f600-…",
"url": "https://hooks.ornek-oyun.com/open-play",
"event_types": ["level_up", "store_purchase_completed"],
"enabled": true,
"created_at": "2026-11-03T09:00:00Z",
"secret": "whsec_<64 hex karakter>"
}
secret değerini hemen güvenli bir yere (gizli yönetim servisine) yazın; bir daha okunamaz.
Kayıt kuralları:
- URL
httpsolmalı; kullanıcı bilgisi (user:parola@) taşımamalı; harf dışı kontrol karakteri ve boşluk içermemeli. Loopback, özel ve link-local IP adresleri kayıtta reddedilir (400). - Ayrıca her gönderimde adın çözümlendiği IP yeniden denetlenir; özel ya da loopback adrese çözümlenen ad gönderilemez. Yönlendirme (redirect) takip edilmez.
- Aynı URL aktifken ikinci kayıt
409.
Teslimat
Her olay için uç noktanıza şu istek gelir:
POST /open-play
Content-Type: application/json
X-Crx-Signature: t=1790000000,v1=9c1f…e2
X-Crx-Event-Id: 0192f500-1111-7222-8333-944455556666
X-Crx-Event-Type: level_up
{ …zarf… }
| Başlık | Anlamı |
|---|---|
X-Crx-Signature | t=<unix saniye>,v1=<hex HMAC-SHA256> |
X-Crx-Event-Id | Olay kimliği; tekrar eleme anahtarınız |
X-Crx-Event-Type | Zarftaki type değeri |
İmzayı doğrulamak
İmza, "{t}.{ham gövde}" metninin, kayıtta dönen sırrın tamamı (whsec_… önekiyle) anahtar alınarak hesaplanan HMAC-SHA256 özetidir (küçük harf hex). Doğrulama adımları:
X-Crx-Signaturebaşlığındantvev1değerlerini ayırın.- Ham gövde baytlarını alın. JSON’u ayrıştırıp yeniden serileştirmeyin; imza tel üzerindeki birebir baytlar içindir.
HMAC-SHA256(secret, t + "." + ham_gövde)hesaplayın vev1ile sabit zamanlı karşılaştırın.tdeğerini kendi saatinizle karşılaştırın; çok eski (örneğin 5 dakikadan eski) istekleri reddedin. Her yeniden denemedetyenilenir, bu yüzden gerçek bir yeniden deneme bu pencerede kalır.X-Crx-Event-Iddaha önce işlendiyse işlemi tekrarlamadan2xxdönün.
Yanıt ve yeniden deneme kuralları
- Yalnız
2xxbaşarıdır. Başka her yanıt, zaman aşımı ve bağlantı hatası yeniden denemeyi tetikler. - Bağlantı için 5 saniye, DNS dahil toplam 10 saniye beklenir.
- Gövde 64 KB’ı aşarsa gönderilmez ve hata sayılır.
- Gecikme
min(1 sn × 2^deneme, 5 dk)’dır ve ±%20 rastgelelik içerir. En çok 10 deneme yapılır; 10. başarısız denemeden sonra teslimat başarısız (DLQ) durumuna alınır ve otomatik tekrar edilmez. - Uç noktayı sildiğinizde bekleyen teslimatlar da başarısız duruma alınır.
- Sıra garantisi yoktur: olaylar karakter için
seqile sıralanabilir, ama teslimat sırası değişebilir. - Uç nokta yokken oluşan olaylar sonradan gönderilmez; geriye dönük teslimat yoktur.
Sürümleme ve tekrar güvenliği
- Alıcı tarafı:
X-Crx-Event-Idile tekrar eleme zorunludur. Aynı olay yeniden denemede aynıevent_idile gelir; imza zamanı (t) yenilenir. - Kayıt ucunda
Idempotency-Keyyoktur; aynı URL’yi ikinci kez kaydetmek409döner. - Zarfta bir olay sürümü alanı yoktur; tanımadığınız alanları yok sayın ve gövdeyi sıkı bir şemayla reddetmeyin.
Sınırlar
- Gövde 64 KB; toplam bekleme 10 saniye; 10 deneme.
- Liste ucunda
limit1–200. - Redirect takip edilmez; yalnız
https.
Sık görülen hatalar
| Belirti | Neden | Çözüm |
|---|---|---|
Kayıtta 400 | URL https değil, IP adresi, kullanıcı bilgisi ya da bilinmeyen olay türü | URL ve event_types değerlerini düzeltin |
Kayıtta 403 | İstemci anahtarı | Sunucu anahtarı kullanın |
Kayıtta 409 | Aynı URL zaten aktif | Var olanı silin ya da kullanın |
| İmza doğrulanmıyor | Gövde yeniden serileştirildi; sırrın whsec_ öneki atıldı; saat farkı | Ham baytlarla, sırrın tamamıyla hesaplayın |
| Aynı olay iki kez geliyor | At-least-once teslimat | X-Crx-Event-Id ile eleyin |
| Teslimatlar durdu | 10 deneme doldu (DLQ) ya da uç nokta silindi | Alıcıyı düzeltin; kaçan olaylar için kendi kaynağınızdan okuyun |
| Teslimat hiç gelmiyor | Uç adı özel/loopback IP’ye çözümleniyor ya da yanıt 10 saniyeyi aşıyor | Genel bir adres kullanın; yanıtı hızlı verin |
Çalışan örnek: Node ile alıcı
Aşağıdaki sunucu imzayı doğrular, tekrar eden olayı eler ve 2xx döner. Sır ortam değişkeninden gelir; üretimde kalıcı bir depoyla tekrar elemesi yapın.
/** Webhook alıcısı (Node 22): imzayı doğrular, tekrar eden teslimatı `X-Crx-Event-Id` ile eler. */
import { createHmac, timingSafeEqual } from "node:crypto";
import { createServer } from "node:http";
const SECRET = process.env["OPEN_PLAY_WEBHOOK_SECRET"] ?? ""; // uç noktayı kaydederken bir kez dönen sır
const TOLERANCE_SECONDS = 300; // eski teslimatı (replay) reddetme penceresi: alıcının kendi politikası
const seen = new Set<string>(); // örnek amaçlı bellek; üretimde kalıcı depo kullanın
/** `X-Crx-Signature: t=<unix-sn>,v1=<hex>` değerini ham gövdeye karşı doğrular. */
export function verifySignature(secret: string, header: string, rawBody: Buffer, nowSeconds: number): boolean {
const parts = new Map(header.split(",").map((part) => part.split("=", 2) as [string, string]));
const t = parts.get("t");
const v1 = parts.get("v1");
if (t === undefined || v1 === undefined) return false;
if (Math.abs(nowSeconds - Number(t)) > TOLERANCE_SECONDS) return false;
const expected = createHmac("sha256", secret).update(`${t}.`).update(rawBody).digest("hex");
const a = Buffer.from(expected, "utf8");
const b = Buffer.from(v1, "utf8");
return a.length === b.length && timingSafeEqual(a, b);
}
createServer((req, res) => {
const chunks: Buffer[] = [];
req.on("data", (chunk: Buffer) => chunks.push(chunk));
req.on("end", () => {
const rawBody = Buffer.concat(chunks); // imza ham bayt üzerindendir: JSON'u yeniden serileştirmeyin
const signature = req.headers["x-crx-signature"];
if (typeof signature !== "string" || !verifySignature(SECRET, signature, rawBody, Math.floor(Date.now() / 1000))) {
res.writeHead(401).end();
return;
}
const eventId = String(req.headers["x-crx-event-id"] ?? "");
if (!seen.has(eventId)) {
seen.add(eventId);
const event = JSON.parse(rawBody.toString("utf8")) as { type: string; data: unknown };
console.log("olay", event.type, event.data);
}
res.writeHead(200).end(); // yalnız 2xx başarıdır; başka kod yeniden denemeyi tetikler
});
}).listen(8080);
İlgili sayfalar
Scene, görsel ve 3B modeller
Bu sayfa oyunun dünyasını oluşturan üç parçayı anlatır: gerçek zamanlı scene (sahne/oda) kaydı, panelden ve sunucudan yüklenen görseller ve operatörün yüklediği 3B modeller. Şehir odalarını sunucudan açmak, ikon ve afiş görselini yönetmek ya da modelleri oyuna sunmak istiyorsanız okuyun.
Ne işe yarar
- Scene: Gerçek zamanlı eklentinin oyuncuları topladığı oda. Oyun sunucusu açılışta ihtiyaç duyduğu scene’leri kaydeder; kayıt idempotenttir.
- Görsel (asset): PNG, JPEG ya da WebP. İçerik adreslidir: adres dosyanın
sha256özetidir, aynı dosya bir kez saklanır. Mağaza afişi, para birimi ikonu ve içerik grubuimagealanları bu depoyu kullanır. - 3B model: Operatörün panelde yüklediği
glb(ya da dönüştürülen kaynak dosya). Yayınlanınca eşyaya ya da karaktere bağlanır ve oyun onu katalogdan alır.
Scene ve görsel yazma uçları scenes modülüne bağlıdır; modül kapalıysa 404 ve {"code":"module_disabled","module":"scenes"} döner. Görsel ve model okuma uçları çekirdektir ve modül kapalıyken de çalışır. Modülü Oyun ayarları › Modüller sayfasından açın.
Panelde nerede
| Ne yapacaksınız | Panel sayfası |
|---|---|
| 3B model yüklemek, önizlemek, yayınlamak, arşivlemek, klip eklemek | 3D modeller, Model profili |
| Modeli eşyaya ya da karaktere bağlamak | İçerik (yerleşik eşya/karakter grupları) |
| Mağaza afişi ve ürün görseli, para birimi ikonu yüklemek | Mağaza, Para birimleri |
| Şehir sohbetini denetlemek (sahne eklentisi) | Şehir sohbeti |
| Scene eklentisinin kurulu olduğunu ve yetkisini görmek | Eklentiler |
Veri modeli (düz dille)
Scene
- Kimlik üç parçadan türetilir:
plugin_id(eklenti),module_id(gerçek zamanlı modül) vekey(en çok 96 karakter). Aynı üçlü her zaman aynı scene’e çıkar. capacity: Odanın oyuncu kapasitesi; en çok 10 000.state:open,draining(boşalıyor) ya daclosed.partition_id: Scene’in dağıtık çalıştığı bölüm kimliği (sunucu üretir).
Görsel
- Tür dosyanın ilk baytlarından çıkarılır;
Content-Typebaşlığı yalnız tavsiyedir. Kabul edilen türlerimage/png,image/jpeg,image/webp. - En çok 2 MiB; genişlik ve yükseklik her biri en çok 4096 piksel.
- Yanıt
sha256,contentType,byteSizevecreated(bu çağrıda yazıldı mı) verir.
3B model
- Yükleme
glbolabilir ya dafbx,obj,usdz,stl,blend,3mf,dxfgibi kaynak biçimlerinden dönüştürülür. Dönüştürme durumuqueued,converting,ready,failed’dır; başarısızlığın nedeni panelde Türkçe cümleyle görünür (ör. harici kaynağa başvuru, bütçe aşımı, 2B DXF). - Her model sürümlüdür; yayınlanan sürüm katalogda görünür. Yaşam döngüsü
active,archived,purged. - Varsayılan sınırlar: yüklenen dosya 50 MiB, ortam kotası 1 GiB, ortamda 200 model, model başına 20 sürüm, operatör başına 10 dakikada 10 yükleme.
- Dönüştürücü yalnız amd64 mimarisinde çalışır; başka mimaride yalnız
glbyüklenebilir.
Oyunun yaptığı çağrılar
| Yöntem ve yol | Kimlik | Ne yapar |
|---|---|---|
PUT /v1/scenes | sunucu anahtarı | Scene’i idempotent sağlar |
PUT /v1/assets | sunucu anahtarı | Görseli ham gövdeyle yükler |
GET /v1/assets | sunucu anahtarı | Ortamın görsellerini listeler (cursor, limit) |
DELETE /v1/assets/{sha256} | sunucu anahtarı | Görsel satırını siler (204) |
GET /v1/assets/{sha256} | kimliksiz | Görsel baytlarını okur |
GET /v1/model-files/{sha256} | kimliksiz | Yayınlanmış modelin glb dosyasını okur |
Yönetim uçları Authorization: Bearer crx_live_<önek>_<gizli> ister; istemci anahtarı 403 alır.
Scene sağlamak
PUT /v1/scenes
Authorization: Bearer crx_live_<önek>_<gizli>
Content-Type: application/json
{ "plugin_id": "package-ride", "module_id": "package-ride.presence", "key": "istanbul-1", "capacity": 200 }
{ "scene_id": "…", "plugin_id": "package-ride", "module_id": "package-ride.presence", "key": "istanbul-1", "partition_id": "…", "capacity": 200, "state": "open", "created": true }
- Scene yoksa yazılır (
201,created: true); varsa değiştirilmeden döner (200,created: false).Idempotency-Keygerekmez. 400: kimlik, anahtar ya da kapasite geçersiz (gövde hataları da400’dür).403: istemci anahtarı.409: aynı anahtarda farklı kimlikli scene.422: eklenti bu ortamda etkin değil.
Bir eklentinin gerçek zamanlı modüllerini ve oyuncu tarafı akışı için bkz. Gerçek zamanlı: genel bakış ve Eklentiler.
Görsel yüklemek
PUT /v1/assets
Authorization: Bearer crx_live_<önek>_<gizli>
Content-Type: image/png
<ham PNG baytları>
{ "sha256": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08", "contentType": "image/png", "byteSize": 18234, "created": true }
201 ve created: true ilk yazımdır; aynı baytlar zaten varsa 200 ve created: false döner ve satır değişmez, yani yükleme idempotenttir. Boş gövde, tanınmayan tür, 2 MiB’ı aşan boyut ya da 4096 pikseli aşan en/boy 400 ile reddedilir (hata kodları asset_empty, asset_unsupported_type, asset_too_large, asset_dimensions_too_large).
Görseli oyunda göstermek için <img src="…/v1/assets/<sha256>?env=<ortam uuid>"> kullanın: uç kimliksizdir, ortamı x-crx-env başlığından ya da (başlık gönderemeyen <img>/doku yükleyicileri için) env sorgu parametresinden alır. Yanıt ETag olarak sha256 taşır ve süresiz önbelleğe alınabilir (immutable); If-None-Match eşleşirse 304 döner. Yeni görsel yeni sha256, yani yeni adres demektir.
Not
Görsel ve model okuma uçları, tarayıcının doku yükleyicisinin kullanabilmesi için çapraz kökenden okunabilir yanıt başlıkları gönderir. Diğer kamusal uçlar CORS’u yalnız ortamın alan adı listesindeki origin’lere verir; bkz. Mimari ve barındırma.
Uyarı
DELETE /v1/assets/{sha256}yalnız satırı siler; depo, başka kayıtların (ürün, ikon, içerik) bu görsele başvurup başvurmadığını bilmez. Silmeden önce görselin kullanılmadığından emin olun.
3B modeli oyuna almak
Modeli panelde yükleyip yayınlayın ve eşyaya ya da karaktere bağlayın. Oyun modelin adresini ve hesaplanmış gerçeklerini (üçgen sayısı, kemik, klipler, sınır kutusu) katalogdan okur; model.glb.url /v1/model-files/<sha256>?env=<ortam uuid> biçimindedir. Ayrıntı: İçerik grupları › Katalog ve Oyun katalog entegrasyonu (docs/oyun-katalog-entegrasyonu.md).
GET /v1/model-files/{sha256} kimliksizdir ve içerik adreslidir:
- Ortam
x-crx-envbaşlığıyla ya daenvsorgusuyla verilir; ikisi de verilip farklıysa ya da ikisi de yoksa400. - Yalnız hazır, dosyaları tutulan ve silinmemiş modelin
glbdosyası döner; silinmiş modelde404. - Eşleşen
If-None-Matchdosyayı açmadan304verir.200yanıtıContent-Length,model/gltf-binarytürü ve süresiz önbellek başlıklarını taşır.Rangedesteklenmez. - Aynı
sha256her zaman aynı baytlardır: dosyayısha256ile önbelleğe alın, yeniden indirmeyin.
Not
Model yükleme ve yayınlama yalnız panelden yapılır; modeller için herkese açık bir yazma ucu yoktur. Unity SDK’sında katalog ve model okuma yardımcıları yoktur; ham REST kullanılır.
Sürümleme ve tekrar güvenliği
PUT /v1/scenesvePUT /v1/assetsdoğal olarak idempotenttir (türetilmiş kimlik, içerik adresi);Idempotency-Keyistemezler.- Model dosyası ve görsel içerik adreslidir: aynı adres hiçbir zaman başka bayt vermez.
- Model sürümleri panelde izlenir; oyun her zaman yayınlanmış güncel sürümü katalogdan görür.
Olaylar
Bu yüzeyler webhook olayı üretmez. Model değişikliği katalogda yeni sha256 olarak yansır; ETag ile yoklayın.
Sınırlar
- Görsel en çok 2 MiB ve 4096×4096 piksel; yalnız PNG, JPEG, WebP.
- Scene
keyen çok 96 karakter,capacityen çok 10 000. - Model varsayılan sınırları yukarıdadır (50 MiB, 1 GiB kota, 200 model, 20 sürüm).
GET /v1/assetssayfa boyu en çok 200 (varsayılan 50).
Sık görülen hatalar
| Belirti | Neden | Çözüm |
|---|---|---|
422 (scene) | Eklenti bu ortamda etkin değil | Eklentiyi etkinleştirin (Eklentiler) |
409 (scene) | Aynı anahtarda farklı kimlikli scene | Anahtarı değiştirin |
400 (görsel) | Tür tanınmadı, 2 MiB ya da 4096 piksel aşıldı | PNG/JPEG/WebP, 2 MiB ve 4096 piksel altında yükleyin |
<img> yüklenmiyor | env ya da x-crx-env eksik | Adrese ?env=<ortam uuid> ekleyin |
404 (model dosyası) | Model silinmiş ya da henüz hazır değil | Katalogdaki model alanını kontrol edin |
Panelde model failed | Dönüştürme hatası | Panelin gösterdiği nedene göre dosyayı düzeltin |
Çalışan örnek
Görsel yükleme ve okuma:
curl -X PUT "$API/v1/assets" \
-H "Authorization: Bearer $SERVER_KEY" -H "Content-Type: image/png" \
--data-binary @afis.png
curl "$API/v1/assets/<sha256>?env=$ENV" -o afis.png
İlgili sayfalar
İçerik grupları
Bu sayfa araçlar, silahlar, NPC’ler ya da polis birimleri gibi oyun verisini kod yayımlamadan değiştirmenizi sağlayan içerik gruplarını anlatır. Verinin panelde nasıl tanımlanıp yayınlandığını ve oyunun onu nasıl okuduğunu öğrenmek istiyorsanız okuyun.
Ne işe yarar
İçerik grubu, sizin tanımladığınız tipli bir tablodur: grubun alanları (ör. hiz, hasar, renk, model) vardır ve her kayıt (ör. sedan) bu alanlar için değer taşır. Operatör değeri panelde düzenler ve yayınlar; oyun yalnızca yayınlanmış güncel hâli okur. Böylece bir değeri değiştirmek için oyunu yeniden dağıtmanız gerekmez.
İçerik grupları çekirdektir: ayrı bir modül anahtarı yoktur ve her ortamda çalışır.
Panelde nerede
| Ne yapacaksınız | Panel sayfası |
|---|---|
| Grup oluşturmak, alan eklemek, şablondan başlamak | İçerik, Grup düzenle |
| Kayıt eklemek, değerleri düzenlemek, kaydı yayına almak ya da arşivlemek | Kayıt düzenle |
| Yayın geçmişini ve farkı görmek, değişiklikleri oyuna göndermek | İçerik › Yayınla |
| Model alanına 3B model bağlamak | 3D modeller |
Veri modeli (düz dille)
-
Grup:
key(^[a-z][a-z0-9_]{1,47}$, yani 2–48 karakter), ad ve alanlar. Anahtar oluşturulduktan sonra değişmez. -
Alan:
key(aynı kural) ve bir tür. On tür vardır:Tür ( kind)Ne tutar Ayarlar integerTam sayı (isteğe bağlı ondalık gösterim ölçeği) min,max,scale(0–3),unit(en çok 12 karakter),defaultpercentBaz puan yüzde (10000 = %100) min_bp,max_bp,default_bptextMetin max_chars(en çok 512),multilineboolEvet/hayır defaultselectSeçenek(ler) options(en çok 64),multiplecolorRenk #rrggbbmodel3B model model kütüphanesi kimliği imageGörsel varlığın sha256değerireferenceBaşka kayda bağlantı hedef: başka bir grup, yerleşik eşya ya da yerleşik karakter tableTekrarlanan satırlı matris columns(1–8),min_rows,max_rows(en çok 100) -
Görünürlük (audience): Her alan
player(oyuncuya gider) ya daserver(yalnız sunucu anahtarı görür) olabilir. -
Kayıt (entry):
key(^[a-z0-9][a-z0-9_-]{0,63}$) ve alan değerleri. Durumu:Yayında,Taslak değişikliği var,Arşivli,Henüz yayınlanmadı. -
Yayın: Panelde “Değişiklikleri oyuna gönder” ile yapılır; en çok 280 karakterlik bir not alır ve sıralı bir yayın sayacı (
seq) üretir. Bir sonraki yayın öncekini değiştirmez, yenisini ekler; geçmiş ve fark panelde görünür. Siz bakarken biri yayınladıysa panel farkı yeniler ve yeniden onay ister. -
Sayılar: Tamsayıdır; kesirli ya da üslü gösterim (
40.0,1e2) reddedilir. Ölçekli tamsayıyı oyundaformatScaledile gösterin.
Not
Eşya ve karakter şablonları da panelde yerleşik gruplar olarak görünür; onlar “kaydedince hemen oyunda” davranır ve yayın adımı istemez. Kullanıcı tanımlı gruplar yayın ister.
Sınırlar: ortamda en çok 64 grup, grupta 48 alan ve 1000 kayıt; bir kaydın tablo verisi 128 KiB’ı, sunucu kitlesi için yayın görüntüsü 1 MiB’ı aşamaz.
Katalog: eşya ve karakter
Oyun, eşya ve karakter tanımlarını (anahtar, ad, tipli veri satırları ve 3B model adresi) katalog uçlarından okur:
| Yöntem ve yol | Ne döner |
|---|---|
GET /v1/catalog/items, GET /v1/catalog/items/{key} | Eşya manifestleri |
GET /v1/catalog/characters, GET /v1/catalog/characters/{key} | Karakter manifestleri |
Bunlar items ve characters modüllerine bağlıdır; modül kapalıysa 404. Liste sayfalıdır (limit 1–100, varsayılan 50; cursor). Her manifest kind, key, name, definition_version, data (tipli satırlar), model (yoksa null) ve content_sha256 taşır. Ayrıntı, ETag ile izleme ve three ile model gösterme: Oyun katalog entegrasyonu (docs/oyun-katalog-entegrasyonu.md) ve Scene, görsel ve 3B modeller.
Oyunun yaptığı çağrılar (içerik grupları)
İçerik grupları salt okunur bir yüzeyle sunulur; oyun taslağa ulaşamaz. İki kimlik türü vardır:
- Oyuncu oturumu (çerez ya da oturum belirteci +
x-crx-env: <ortam uuid>): yalnızvisibility = playeralanları ve değerlerini görür. - Sunucu anahtarı (
Authorization: Bearer crx_live_<önek>_<gizli>): bütün alanları görünürlükleriyle veseqile görür. Geçersiz birBearer crx_…anahtarı geçerli bir çerezle bile401alır; çereze düşülmez.
| Yöntem ve yol | Ne döner |
|---|---|
GET /v1/catalog/groups | Yayınlanmış grupların anahtarı, adı ve kitleye göre content_sha256 değeri |
GET /v1/catalog/groups/{group} | Grubun güncel yayını: group, fields, entries, seq |
GET /v1/catalog/groups/{group}/entries/{key} | Aynı şekil, yalnız o kayıt |
Başlıklar:
| Başlık | Anlamı |
|---|---|
x-crx-env | Oyuncu oturumunda zorunlu; sunucu anahtarında ortam anahtardan gelir |
If-None-Match | Elinizdeki ETag; eşleşirse 304 ve gövde yoktur |
Yanıtlar kitleye özgü ETag taşır. Oyuncu ETag’i ve content_sha256 değeri süzülmüş gövdeden hesaplanır; bu yüzden yalnız-sunucu bir alanı değiştirmek oyuncu tarafında hiçbir değişiklik göstermez. Hiç yayınlanmamış ya da olmayan grup 404 döner.
Not
Yalnız-sunucu satırlar bir sır deposu değildir: panelde operatörler ve sunucu anahtarı tutanlar görür. Parola, anahtar ya da kişisel veri koymayın.
Tablo alanı
table alanı bir kayıtta tekrarlanan satırları tutar (silahın seviye → hasar tablosu, NPC ganimet listesi). Sütun türleri integer, percent, text, bool, select ve reference’tır. Değer, satır sırasını koruyan nesne dizisidir; sırayı değiştirmek yeni bir yayın özeti demektir. Yalnız-sunucu tablo oyuncu gövdesinde hiç yoktur.
Oyundan okumak
TypeScript SDK’sı iki kitle için de tipli okuyucu sağlar (player.catalog.groups, sunucuda CrxClient.catalog.groups; list, get, entry). İzleme için watchCatalogGroup ve ölçekli sayıyı göstermek için formatScaled vardır. Unity SDK’sında katalog yoktur; ham REST kullanılır.
Sürümleme ve tekrar güvenliği
- Okuma uçlarında
Idempotency-Keyya daIf-Matchyoktur;If-None-Matchile koşullu okuma yaparsınız. - Yayın sayacı (
seq) her yayında artar;seqdeğişmediyse içerik değişmemiştir. - Grup, alan ve kayıt anahtarları oluşturulduktan sonra değişmez; alan türü değişimi denetlenir ve panel sorunları yayın öncesinde listeler.
Olaylar
İçerik grubu yayını outbox’a olay yazmaz (yalnız denetim kaydı düşer), dolayısıyla webhook üretmez. Değişikliği oyunda yakalamak için ETag ile yoklayın: değişim oyuncuya en geç bir yoklama aralığı sonra ulaşır; bir dakikalık aralık yeterlidir.
Sınırlar
- 64 grup / 48 alan / 1000 kayıt; tablo en çok 8 sütun ve 100 satır; kayıt tablo verisi 128 KiB; sunucu yayın görüntüsü 1 MiB.
- Metin alanı en çok 512 karakter; seçim alanı en çok 64 seçenek.
- Yayın notu en çok 280 karakter.
Sık görülen hatalar
| Belirti | Neden | Çözüm |
|---|---|---|
404 (grup) | Grup hiç yayınlanmadı ya da yok | Panelde grubu yayınlayın |
401 | Kimlik yok ya da geçersiz Bearer crx_…; oyuncu oturumunda x-crx-env eksik | Kimliği ve başlığı düzeltin |
| Panelde yayın reddedildi | Başvuru (reference) hedefi yok; tablo ya da yayın boyutu aşıldı | Panelin listelediği sorunları giderin |
| Değeri değiştirdim, oyun görmüyor | Taslak yayınlanmadı ya da alan server görünürlüklü | Yayınlayın; görünürlüğü kontrol edin |
304 | ETag eşleşti | Beklenen davranış; elinizdeki kopya güncel |
Çalışan örnek
weapons grubunun güncel yayınını ETag ile okuma:
/** İçerik grubunu (panelde yayınlanan oyun verisi) oyuncu oturumuyla okur; ETag ile değişmediyse 304 döner. */
import type { PlayerClient } from "@ferdiunal/open-play-ts";
/** `weapons` grubunun güncel yayınındaki kayıt anahtarlarını döndürür; değişmediyse boş liste. */
export async function readWeapons(player: PlayerClient, previousEtag?: string): Promise<readonly string[]> {
const result = await player.catalog.groups.get("weapons", previousEtag === undefined ? {} : { ifNoneMatch: previousEtag });
if (result.status === 304) return [];
return result.value.entries.map((entry) => entry.key);
}
İlgili sayfalar
- İçerik grupları ödül kaynağı olarak · Envanter ve eşyalar · Karakterler · Scene, görsel ve 3B modeller
- Oyun katalog entegrasyonu (ayrıntılı rehber) (
docs/oyun-katalog-entegrasyonu.md) · TypeScript SDK
Oyun kuralları ve otomasyonlar
Bu sayfa panelin “Kurallar” ekranının iki parçasını anlatır: oyunun eklentisinin bildirdiği oyun kuralı değerleri (örneğin polis eşikleri) ve olay olunca otomatik iş yapan otomasyonlar. Oyunun davranışını kod yayımlamadan ayarlamak ya da bir olaya otomatik tepki vermek istiyorsanız okuyun.
Ne işe yarar
- Oyun kuralı değerleri: Oyunun eklentisi hangi sayıların ayarlanabilir olduğunu bildirir (ad, birim, alt ve üst sınır, adım, varsayılan). Operatör bu değerleri panelde değiştirir ve yayınlar; yeni değerler oyunda kısa süre içinde (en geç yaklaşık 6 saniye) geçerli olur. Her yayın yeni bir sürüm olur ve tek tıkla eski değerlere dönülebilir.
- Otomasyonlar: “Şu olay olunca, şu koşul doğruysa, şunu yap” biçiminde kurallar. Kural, karakter olaylarına (
level_up,xp_added…) bağlanır ve karaktere stat, kaynak, bayrak, değiştirici ya da ödül verir. Koşullar CEL ifadesiyle yazılır; panelde yapısal bir oluşturucu CEL’i sizin için üretir.
Oyun kuralı değerleri panel yüzeyidir: oyun sunucunuz bunları bir REST ucuyla yazmaz; eklenti değerleri sunucuda okur. Otomasyonlar ise hem panelden hem REST ile yönetilir (characters modülünün parçasıdır).
Panelde nerede
| Ne yapacaksınız | Panel sayfası |
|---|---|
| Kurallar ekranına genel bakış, konu ve kartlar | Kurallar |
| Bir oyun kuralı kartını düzenleyip yayınlamak, önizlemek | Kural kartı |
| Yayın geçmişini ve farkı görmek, geri almak | Kural geçmişi |
| Otomasyon oluşturmak, düzenlemek, açıp kapatmak | Otomasyon düzenleyici |
Oyun kuralı değerleri
Model
- Katalog: Oyunun eklentisi bildirir. Konular, kartlar ve her kartın parametreleri vardır; her parametre bir birimle (örn. saniye, metre, yüzde) ve sınırlarla gelir. Katalog yoksa ya da eklenti bildirmiyorsa panelde yalnız Otomasyonlar görünür.
- Sürüm: Etkin değerler en son sürümdür. Hiç yayın yoksa eklentinin kod varsayılanları kullanılır (“Kod varsayılanı”). Yayın ve geri alma yeni sürüm yazar; geçmiş silinmez.
- Uygulama zamanı: Parametre
canlıise yayından sonra kısa sürede uygulanır;yeniden başlatmadaise oyun sunucusu yeniden başlayana dek eski değer kalır ve panel “Yayında / Bekliyor” olarak ikisini birlikte gösterir. - Doğrulama: Değerler katalog sınırı, adım ve alanlar arası kısıtlarla sunucuda doğrulanır; hatalı alan alan başına bildirilir. Eklenti ayrıca aynı sınırlarla yeniden doğrular; geçersiz bir değer oyunu bozmaz, eklenti kod varsayılanlarına döner.
- Yetki: Okuma dört panel rolünde; yayın ve geri alma yalnız
super_adminvegame_managerrollerinde. Yayın ve geri alma 8–500 karakterlik bir gerekçe ister ve denetim kaydına yazılır. - Eşzamanlılık: Yayın, gördüğünüz sürümü (
expectedVersion) taşır; siz bakarken başka biri yayınladıysa409döner ve sekmeyi yenilemeniz gerekir. - Önizleme: Panel, bir senaryoyu (örn. sürekli hız ihlali) eklentinin gerçek mantığıyla bugünkü ve önerilen değerlerle çalıştırıp olay zaman çizelgesini gösterir; hiçbir şey kaydetmez.
- İstemci uyarısı: Bir parametre
clientVisibleise oyun istemcisi onu eklentinin sorgusundan okur. İstemci o değeri henüz okumuyorsa panel yayın sırasında sizi uyarır.
Oyuna etkisi
Oyun kuralı değerlerini oyun kodunuz REST ile okumaz. Eklenti değerleri sunucuda her adımda tek bir görüntüden alır; istemciye gereken değerler eklentinin kendi sorgusuyla gelir. Bu davranış eklentiye özgüdür; bugün yalnız package-ride eklentisi bir katalog bildirir. Üçüncü taraf eklentilerin katalog bildirmesi ve yüklenmesi henüz desteklenmez; bkz. Eklentiler: genel bakış.
Otomasyonlar
Model
- Kural (rule):
key(tekil anahtar),trigger_type(tetikleyici olay),condition(CEL ifadesi),actions(eylem listesi) vepriority. Kural sürümlüdür; her yayın yeni sürümdür. - Tetikleyici:
flag_set,attribute_set,resource_changed,modifier_added,modifiers_removed,xp_added,level_up,ability_unlocked,event_emitted,character_rolled_back. Bilinmeyen tür reddedilir. Panel oluşturucusucharacter_rolled_backseçeneğini sunmaz. - Eylemler:
add_stat(key,delta),add_resource(key,delta),set_flag(key,value),add_modifier,remove_modifiervegrant_reward(what: sabit para{ "type": "currency", "key", "amount" }ya da ödül tablosu{ "type": "table", "key" }). - CEL bağlamı: Koşulda
character,event,nowveseeddeğişkenleri vardır;has_ability,base_statveclampişlevleri kullanılabilir. Zamanı ve tohumu bağlam taşır, kural kendi saatini okuyamaz;now()verandom()yoktur. Kurallar kayıt anında derlenir, çalışma anında değil. - Bütçe (değişmez): Bir komut zincirinde en çok 50 kural değerlendirilir, 200 eylem üretilir, zincir derinliği 5’i, koşul ifadesi 500 düğümü aşamaz. Aşım fail-closed’dur: komut
429ile reddedilir ve hangi sınırın aşıldığı söylenir. Birbirini tetikleyen iki kural bu sınırla kesilir.
Panel oluşturucusu
Oluşturucu “Ne zaman → Koşullar → Ne yap” yapısından CEL üretir: koşul satırları (alan, işleç, değer) hepsi (&&) ya da herhangi biri (||) ile birleşir; en çok 20 koşul ve 10 eylem eklenebilir. Metin değerleri kaçışlanır; satır sonu ve kontrol karakterleri reddedilir. Oluşturucu varken sunucu kuralı yeniden derler (istemcinin gönderdiği CEL metni oluşturucu kuralında okunmaz). Yeni kural kapalı başlar; “hemen aç” seçeneği işaretsizdir. Yayın öncesi örnek bir olayla dry-run (deneme koşusu) yapabilirsiniz; zorunlu değildir.
Oyunun yaptığı çağrılar
Kural uçları API anahtarıyla çağrılır:
Authorization: Bearer crx_live_<önek>_<gizli>
| Yöntem ve yol | Ne yapar |
|---|---|
POST /v1/rules | Kuralı kaydeder (201) |
GET /v1/rules | Kuralları listeler (cursor, limit) |
GET /v1/rules/{key} | Kuralın güncel sürümünü okur |
POST /v1/rules/{key}/enable, POST /v1/rules/{key}/disable | Kuralı açar / kapatır (204) |
DELETE /v1/rules/{key} | Kuralı siler (204) |
POST /v1/rules/dry-run | Kuralı bir karaktere karşı yazmadan dener |
Uyarı
Bilinen kısıt: Kural yazan uçlar anahtar türüne bakmaz; geçerli bir istemci anahtarı da kural kaydedebilir ya da silebilir. İstemci anahtarını oyuna gömüyorsanız kural yönetimini kendi sunucunuzdan yapın ve bu uçları istemciden çağırmayın.
TypeScript SDK’sı bu uçları tipli sunar: createRule, listRules, getRule, deleteRule, enableRule, disableRule, dryRunRule (bkz. TypeScript SDK). Bu uçlar ham CEL metni alır; panel oluşturucusunun yapısal modeli yalnız panel yüzeyindedir.
Kural kaydetmek
POST /v1/rules
Authorization: Bearer crx_live_<önek>_<gizli>
Content-Type: application/json
{
"key": "lvl10_reward",
"trigger_type": "level_up",
"condition": "event.to == 10",
"actions": [
{ "type": "grant_reward", "what": { "type": "currency", "key": "gold", "amount": 1000 } },
{ "type": "set_flag", "key": "reached_level_10", "value": true }
],
"priority": 0
}
{ "key": "lvl10_reward", "current_version": 1, "enabled": true, "created_at": "2026-11-03T09:00:00Z" }
REST ile kaydedilen kural hemen açık başlar (enabled: true); panel oluşturucusundan farklı olarak kapalı başlatmak için kaydın ardından POST /v1/rules/{key}/disable çağırın. event.to seviye atlama olayının yeni seviyesidir; olay alanları tetikleyiciye göre değişir. Koşul derlenemezse, tetikleyici bilinmiyorsa ya da bütçe sınırı aşılıyorsa kayıt reddedilir.
Deneme koşusu
POST /v1/rules/dry-run
Authorization: Bearer crx_live_<önek>_<gizli>
Content-Type: application/json
{ "condition": "character.progression.level >= 10", "actions": [ { "type": "set_flag", "key": "veteran", "value": true } ], "character_id": "0192f0f2-…" }
{ "condition_result": true, "node_cost": 7, "would_produce_events": [ { "...": "…" } ], "would_grant": [], "warnings": [] }
Dry-run hiçbir olay yazmaz ve ödül vermez.
Sürümleme ve tekrar güvenliği
- Oyun kuralı yayını ve geri alma:
Idempotency-KeyveexpectedVersionile panel tarafından yapılır; aynı anahtarla tekrar aynı sürümü döndürür, tek denetim kaydı yazar. - Otomasyon yayını: her yayın yeni sürümdür; eski sürümler silinmez ve “geri al” eski sürümü yeni sürüm olarak yeniden yazar.
- REST kural uçlarında
Idempotency-KeyveIf-Matchyoktur.
Olaylar
Kuralın çalıştırdığı eylemler normal karakter olaylarını üretir (flag_set, xp_added …); bunlar webhook’larla iletilebilir. Kuralın ürettiği ödül reward_granted olayı da üretir.
Sınırlar
- Komut zincirinde 50 kural, 200 eylem, derinlik 5, koşul başına 500 düğüm.
- Panel oluşturucusunda en çok 20 koşul ve 10 eylem.
- Oyun kuralı gerekçesi 8–500 karakter.
- Oyun kuralı tam sayı değerleri panelde ±(2^53−1) ile sınırlıdır.
Sık görülen hatalar
| Belirti | Neden | Çözüm |
|---|---|---|
429 (komut) | Kural zinciri bütçeyi aştı | Birbirini tetikleyen kuralları sadeleştirin |
Kayıtta 400/422 | CEL derlenemedi, bilinmeyen tetikleyici ya da alan | Koşulu önce dry-run ile deneyin |
Panelde 409 (yayın) | Siz bakarken başka biri yayınladı | Sekmeyi yenileyip tekrar yayınlayın |
Panelde alan hatası (422) | Değer sınır, adım ya da kısıt dışında | Alanın gösterdiği sınıra uyun |
| Değeri yayınladım, oyun eski davranıyor | Parametre yeniden başlatmada uygulanıyor ya da 6 saniye dolmadı | Panelin “Bekliyor” göstergesine bakın |
Çalışan örnek
Yukarıdaki iki istek (lvl10_reward kaydı ve dry-run) birlikte tam bir akıştır: önce dry-run ile koşulu deneyin, sonra POST /v1/rules ile kaydedin, sonra bir karaktere add_xp komutuyla seviye atlatarak kuralın çalıştığını Karakterler sayfasındaki akışla doğrulayın.
İlgili sayfalar
Oyuncu verisi (bulut kaydı)
Bu sayfa oyuncunun ilerlemesini (seviye, ayarlar, oyun kaydı) Open Play’de saklayıp başka cihazdan kaldığı yerden sürdürmeyi anlatır. Oyununuz kendi kayıt biçimini taşıyorsa ve onu oyuncu hesabına bağlamak istiyorsanız okuyun.
Ne işe yarar
Oyuncu verisi, oyuncu başına anahtar-değer deposudur. Değer, sunucuda yorumlanmayan opak bir JSON nesnesidir: Open Play onu saklar, boyutunu ölçer ve aynen geri verir; alanlarını sorgulamaz, hesap yapmaz. Kayıt biçimini ve sürümünü oyununuz belirler.
Bu özellik çekirdektedir: bir ürün modülüne bağlı değildir ve Oyun ayarları › Modüller sayfasından kapatılamaz.
Panelde nerede
| Ne yapacaksınız | Panel sayfası |
|---|---|
| Bir oyuncunun anahtarlarını, boyutlarını ve değerini görmek; gerektiğinde silmek | Oyuncular › oyuncu profili › “Oyun verisi” bölümü |
Panelden değer yazılamaz; yalnız salt okunur biçimli JSON olarak görünür. Operatör silmesi gerekçe (8–500 karakter) ister ve denetim kaydına yazılır.
Sınırlar
| Sınır | Değer |
|---|---|
| Anahtar | ^[a-z0-9][a-z0-9._-]{0,63}$ (küçük harf, rakam, ., _, -; en çok 64 karakter) |
| Değer | Üst düzey JSON nesnesi; serileşmiş (kompakt) boyutu en çok 65 536 bayt |
| Anahtar sayısı | Oyuncu başına en çok 16 |
| Yazım hızı | Oyuncu başına dakikada en çok 60 yazım (PUT ve DELETE; okumalar sayılmaz) |
Değerde kayan noktalı sayılar serbesttir: değer opak veridir, sunucu onunla hesap yapmaz. İki sınır vardır: nesne anahtarlarının sırası korunmaz ve 2^64’ten büyük tam sayılar ile çift duyarlığı aşan ondalıklar yuvarlanabilir; büyük sayıları dize olarak saklayın.
Sürümlü yazım (CAS)
Her anahtarın bir sürümü vardır: ilk yazımda 1, her başarılı yazımda 1 artar. Sürüm bir i64’tür ve JSON’da ondalık dize olarak taşınır ("3"); HTTP başlığında ETag: "3" biçimindedir.
Önkoşulsuz yazım yoktur. Her PUT tam olarak birini taşır:
If-None-Match: *— yalnız anahtar yoksa oluştur.If-Match: "<sürüm>"— yalnız güncel sürüm buysa güncelle.
İki başlığı birden göndermek, hiçbirini göndermemek ya da biçimsiz değer göndermek 428 precondition_required döner. Sürüm tutmazsa (başka cihaz aynı sırada yazdı) 409 version_conflict ve güncel sürüm döner; uzak kaydı okuyun, kendi kuralınızla birleştirin ve yeniden deneyin. Kaynak: crx-domain::player_data.
Oyunun yaptığı çağrılar
Oyuncu uçları oyuncu oturumuyla çalışır: __Secure-crx.session çerezi ya da opak oturum belirteci (Authorization: Bearer) ve x-crx-env: <ortam uuid>. Yazımlar (PUT, DELETE) mağaza satın alma ucuyla aynı tarayıcı korumasını taşır: Origin denetimi ve çerez oturumunda x-csrf-token (bkz. Oturumlar ve CSRF). Geliştirici anahtarı oyuncu uçlarında kabul edilmez (401).
| Yöntem ve yol | Kimlik | Ne yapar |
|---|---|---|
GET /v1/player/data | oyuncu oturumu | Kendi anahtarlarının özetini listeler |
GET /v1/player/data/{key} | oyuncu oturumu | Bir anahtarı okur (ETag: "<sürüm>") |
PUT /v1/player/data/{key} | oyuncu oturumu | Önkoşullu oluşturur ya da günceller |
DELETE /v1/player/data/{key} | oyuncu oturumu | If-Match ile siler (204) |
GET /v1/players/{player_id}/data | sunucu anahtarı | Bir oyuncunun anahtar özetleri (yalnız okuma) |
GET /v1/players/{player_id}/data/{key} | sunucu anahtarı | Bir oyuncunun bir anahtarı (yalnız okuma) |
Sunucu uçları Authorization: Bearer crx_live_<önek>_<gizli> ister; istemci anahtarı 403, oyuncu oturumu 401 alır. Yanıtlar Cache-Control: private, no-store taşır.
Listele
GET /v1/player/data
x-crx-env: 0192f000-0000-7000-8000-00000000e001
{ "items": [ { "key": "my-game.save", "version": "3", "size": 214, "updatedAt": "2026-11-03T10:15:30.120Z" } ] }
Oluştur
PUT /v1/player/data/my-game.save
x-crx-env: 0192f000-0000-7000-8000-00000000e001
x-csrf-token: <csrf belirteci>
If-None-Match: *
Content-Type: application/json
{ "value": { "level": 4, "stars": 17, "playTimeSeconds": 913.5 } }
{ "key": "my-game.save", "version": "1", "updatedAt": "2026-11-03T10:15:30.120Z" }
Yanıt ETag: "1" başlığını da taşır. Gövde tam olarak { "value": <nesne> } olmalıdır; başka alan 422 invalid_value döner.
Güncelle ve sil
PUT /v1/player/data/my-game.save
If-Match: "1"
{ "value": { "level": 5, "stars": 21 } }
DELETE /v1/player/data/my-game.save
If-Match: "2"
Silme 204 döner. Oyuncu silmesi de önkoşulludur; operatör silmesi panelden yapılır.
Okumak
GET /v1/player/data/my-game.save
{ "key": "my-game.save", "value": { "level": 5, "stars": 21 }, "version": "2", "updatedAt": "2026-11-03T10:16:02.004Z" }
Anahtar yoksa 404 ve {"code":"not_found"} döner.
Hata kodları
Bu uçların hataları, çekirdeğin geri kalanından farklı olarak JSON’dur: { "code": "…", "message": "…" }.
| Durum | code | Ne zaman |
|---|---|---|
| 404 | not_found | Anahtar yok (sunucu uçlarında oyuncu bu ortamda yoksa da) |
| 409 | version_conflict | Sürüm tutmadı ya da var olan anahtara If-None-Match: *; currentVersion güncel sürümü (anahtar yoksa null) taşır |
| 413 | value_too_large | Değer 64 KiB’ı aştı; limit alanı sınırı verir |
| 422 | invalid_key | Anahtar kalıba uymuyor |
| 422 | invalid_value | Değer nesne değil, gövde { "value": … } değil ya da JSON değil |
| 422 | too_many_keys | Oyuncu 16 anahtarda; limit alanı sınırı verir |
| 428 | precondition_required | If-Match / If-None-Match: * yok, çift ya da biçimsiz |
| 429 | rate_limited | Dakikada 60 yazım aşıldı; Retry-After saniye cinsinden bekleme verir |
| 401 | — | Oturum yok, geçersiz ya da yasaklı oyuncu (kimlik katmanı ban ayrımını sızdırmaz) |
| 403 | — | Origin, Fetch Metadata ya da CSRF reddi; sunucu uçlarında istemci anahtarı |
Yasaklı bir oyuncunun yazımı kimlik katmanında 401 ile biter; depo da savunma olarak yazımı 403 ve {"code":"account_banned"} ile reddeder.
TypeScript SDK
PlayerClient.data bu uçların tipli karşılığıdır: list(), get(key), create(key, value), update(key, value, version), delete(key, version). Sürümler bigint’tir; değer normal JS nesnesidir (güvenli tam sayılar number, aralık dışı tam sayılar bigint, ondalıklar number). CSRF belirtecini ve çerezi SDK yönetir. 409 çatışması PlayerDataConflict (+ currentVersion: bigint | null) olarak fırlar; diğer retler CrxError’dır ve playerDataErrorCode(error) ile ayrışır. Bkz. TypeScript SDK.
Çalışan örnek: kaydet, çatışmada birleştir
/** Oyuncu verisi (bulut kaydı): kaydı oku, değiştir, sürümlü yaz; çatışmada uzak kayıtla birleştirip yeniden dene. */
import { PlayerDataConflict, type PlayerClient, type PlayerDataValue } from "@ferdiunal/open-play-ts";
const KEY = "my-game.save";
/** İki kaydı oyunun kendi kuralıyla birleştirir: burada her bölümde en iyi yıldız sayısı kalır. */
function merge(remote: PlayerDataValue, local: PlayerDataValue): PlayerDataValue {
const best = (a: unknown, b: unknown): number => Math.max(typeof a === "number" ? a : 0, typeof b === "number" ? b : 0);
return { ...remote, ...local, stars: best(remote.stars, local.stars) };
}
/** Kaydı buluta yazar; sürüm çatışırsa (başka cihaz yazmıştır) uzak kaydı okur, birleştirir ve en çok 3 kez dener. */
export async function saveToCloud(player: PlayerClient, local: PlayerDataValue): Promise<void> {
let value = local;
let current = await player.data.get(KEY).catch((error: unknown) => {
if (error instanceof Error && "status" in error && error.status === 404) return null;
throw error;
});
for (let attempt = 0; attempt < 3; attempt += 1) {
try {
if (current === null) await player.data.create(KEY, value);
else await player.data.update(KEY, value, current.version);
return;
} catch (error: unknown) {
if (!(error instanceof PlayerDataConflict)) throw error;
current = error.currentVersion === null ? null : await player.data.get(KEY);
if (current !== null) value = merge(current.value, value);
}
}
throw new Error("Kayıt üç denemede birleştirilemedi");
}
Saklama ve silme
- Oyuncu satırı hiç silinmez; terk edilmiş misafir hesapları kapatılırken (anonimleştirme) o hesabın oyuncu verisi aynı işlemde silinir.
- Operatör, panelden bir anahtarı gerekçeyle silebilir; oyuncu kendi anahtarını
If-Matchile siler. - Veri, oyuncu ve ortam başına yalıtılmıştır: bir ortamın oyuncusu başka ortamdan okunamaz.
Sık karşılaşılan durumlar
- Sürekli 409 alıyorum. Başka bir cihaz yazıyor ya da
update’e eski sürüm veriyorsunuz. Her yazımdan sonra dönenversiondeğerini saklayın; çatışmada uzak kaydı okuyup birleştirin, ham sürümü artırıp tekrar göndermeyin. - 429 alıyorum. Dakikada 60 yazım sınırı oyuncu başınadır. Her tuş vuruşunda değil, gecikmeli (debounce) ve anlamlı noktalarda yazın;
Retry-Afterkadar bekleyin. - 16 anahtar sınırı. Birden çok küçük anahtar yerine kayıt türü başına bir anahtar kullanın (ör.
my-game.save,my-game.settings).
İlgili sayfalar
Realtime genel bakış
Bu sayfa, Open Play’in sunduğu üç WebSocket’i ve hangisini ne zaman kullanacağınızı anlatır. Oyun içi durum (hareket, oda, sahne) için eklenti realtime soketini, bildirim ve sohbet için ise ayrı iki soketi kullanırsınız; hepsinin kimlik ve kapanış kuralları farklıdır.
Üç soket
| Soket | Yol | Ne için | Kim konuşur | Kimlik |
|---|---|---|---|---|
| Realtime (eklenti) | /v1/realtime/ws | Oyun durumu: anlık girdi, durum anlık görüntüsü (snapshot), kalıcı komut ve olay | İki yönlü | Tek kullanımlık bilet (ticket) |
| Bildirim | /v1/ws | Bildirimin oyuncuya canlı itilmesi | Yalnız sunucu → oyuncu | Oyuncu oturumu (çerez ya da Bearer) |
| Sohbet | /v1/chat/ws | Kanal sohbeti (abone ol, mesaj gönder) | İki yönlü | Oyuncu oturumu (çerez ya da Bearer) |
Kural: üçü de oyuncu soketidir. Sunucu anahtarı (server key) ile soket açılmaz; sunucudan sunucuya iş için REST uçlarını kullanın.
Hangisini kullanmalıyım
| İhtiyaç | Seçim |
|---|---|
| Aracın, oyuncunun ya da odanın anlık durumunu yayınlamak ve oyuncu girdisini sıralı almak | Realtime soketi, protokol |
| Bir komutun sonucunu kalıcı ve tekrar-güvenli almak (ödül, teslimat) | Realtime Command çerçevesi ya da HTTP komut ucu (eklentileri çağırma) |
| Oyuncuya “yeni bildirim” anlık göstermek | /v1/ws; kalıcı kaynak her zaman GET /v1/notifications gelen kutusudur (bildirimler) |
| Kanal sohbeti | /v1/chat/ws ya da REST (sohbet) |
| Skor tablosu, mağaza, envanter | REST; bunlar için soket yoktur |
Not
TypeScript SDK’sı realtime soketini sizin yerinize yönetir: bilet alma, kimlik doğrulama, yeniden bağlanma ve anlık görüntü kurtarma dahildir. Elle protokol yazmanız yalnız SDK’sı olmayan bir istemci (ör. Unity yerel soketi) için gerekir. SDK kullanımı için TypeScript SDK sayfasına bakın.
Bağlantı koşulları (ortak)
- HTTPS ve izinli origin. Tarayıcı oyununuz API’yi ters vekille aynı kökenden ya da alan adı bir ortamda kayıtlıysa doğrudan Open Play adresinden (CORS) çağırır. Soketler aynı adrese açılır:
wss://<oyun-alan-adınız>/<yol>ya dawss://<open-play-adresi>/<yol>; el sıkışmasındaOriginortam başına denetlenir (CORS bunu değiştirmez). Ayrıntı: mimari ve barındırma. - Ortam başlığı. Oyuncu kimliği her zaman bir ortama (environment) bağlıdır ve
x-crx-env: <ortam uuid>başlığı gerekir. Realtime soketinde başlık HTTP bilet isteğiyle verilir; WebSocket yükseltmesi başlık taşımaz, bilet ortamı bilir./v1/wsve/v1/chat/wsise başlığı yükseltme isteğinin kendisinde ister. Tarayıcının WebSocket API’si özel başlık ekleyemez; bu yüzden bu iki soket tarayıcıdan doğrudan açılamaz (bilinen kısıt). Tarayıcı oyunlarında bildirim için gelen kutusunu REST ile yoklayın, sohbet için REST uçlarını kullanın; tarayıcı dışı istemciler başlığı kendileri gönderebilir. - Sorgu dizesinde jeton yok. Hiçbir soket oturum jetonunu URL’de kabul etmez; erişim günlüklerine sızmasın diye
?token=desteklenmez. Realtime yükseltmesi sorgu dizesi taşıyorsa reddedilir. - Origin başlığı zorunludur (realtime): hem bilet isteği hem yükseltme
Origintaşımalıdır ve ortamın izinli kökenlerinden biri olmalıdır. Tarayıcı bunu kendisi ekler; tarayıcı dışı bir istemciyse izinli birOrigindeğerini kendiniz göndermelisiniz. - Modül kapısı. Realtime soketi
plugins,/v1/wsnotifications,/v1/chat/wschatmodülüne bağlıdır. Modül kapalıysa yükseltme404vemodule_disableddöner; açık soket, modül sonradan kapanırsa1008(nedenmodule_disabled) ile kapatılır, kapı durumu doğrulanamıyorsa1013ile. Modülleri panelden yönetirsiniz: Oyun ayarları: modüller.
Bildirim soketi (/v1/ws)
- Yalnız sunucudan oyuncuya akar. İstemciden gelen çerçeveler yok sayılır.
- Gelen çerçeve bir JSON nesnesidir:
{"type":"notification","notification_id":"…","title":"…","body":"…","data":{…},"channel":"in_game","sent_at_ms":1760000000000}. Alan adlarısnake_case’dir. - Canlı çerçeve en çok bir kez (at-most-once) teslim edilir. Kalıcı kaynak gelen kutusudur; aynı bildirim hem çerçeveyle hem gelen kutusu sorgusuyla gelebilir,
notification_idile tekilleştirin. - Bağlantı presence (çevrimiçi) sinyali olarak sayılır.
Sohbet soketi (/v1/chat/ws)
Çerçeveler type alanı (camelCase değerli) ile ayrılır; diğer alan adları snake_case’dir ve bilinmeyen alan reddedilir. Örnek: {"type":"send","channel_id":"…","client_message_id":"retry-1","body":"merhaba"}.
| Yön | type | Alanlar | Anlam |
|---|---|---|---|
| İstemci → sunucu | subscribe | channel_id | Kanal aboneliği (aynı anda tek kanal) |
| İstemci → sunucu | unsubscribe | — | Aboneliği bırakır |
| İstemci → sunucu | send | channel_id, client_message_id, body | REST ile aynı tekrar-güvenli mesaj gönderme |
| İstemci → sunucu | ping | nonce (sayı) | Canlılık yoklaması |
| Sunucu → istemci | subscribed / unsubscribed | channel_id (yalnız subscribed) | Kabul |
| Sunucu → istemci | message | message, duplicate | Kanal mesajı; duplicate: true ise client_message_id daha önce işlenmişti |
| Sunucu → istemci | pong | nonce | ping yanıtı |
| Sunucu → istemci | error | code | invalid_frame, invalid_payload, forbidden_channel, unavailable, message_rejected, modül kapanırken module_disabled |
Mesaj gönderme sınırı: oyuncu başına 10 saniyede 20 mesaj; aşımı message_rejected ya da REST’te 429 olarak görürsünüz (hız sınırları). Ayrıntılı kullanım için sohbet rehberi.
Sıradaki adım
- Eklenti realtime protokolünü baştan sona görmek için protokol.
- Bağlantı koptuğunda ne olduğunu, limitleri ve boşta kapanmayı görmek için yeniden bağlanma ve limitler.
Realtime protokolü
Bu sayfa, /v1/realtime/ws soketinin tel (wire) protokolünü anlatır: bilet alma, bağlanma, kimlik doğrulama ve her istemci ve sunucu çerçevesinin alanları. TypeScript SDK’sını kullanıyorsanız bu protokolü elle yazmazsınız; ama davranışı anlamak, başka bir istemci yazmak ya da sorun gidermek için buradan okuyun.
Not
Protokol sürümü
1’dir. Her çerçevedeprotocolVersion: 1bulunur; başka değerUnsupportedProtocolhatası alır (sürümleme).
Genel kurallar
- Her çerçeve tek bir WebSocket metin mesajı olarak giden bir JSON nesnesidir. İkili (binary) mesaj kabul edilmez.
typealanı çerçeve türünü belirler vePascalCase’dir (Authenticate,Join, …). Diğer alan adlarıcamelCase’dir. Bilinmeyen alan içeren çerçeve reddedilir.- Büyük tam sayılar (sıra numaraları, epoch, revizyon, sürüm) JSON sayısı değil ondalık metindir:
"sessionEpoch": "7". Kurallı biçim: boş değil, baştaki sıfır yok, yalnız rakam, negatif değil,i64aralığında. Ayrıntı: sayılar ve kodlama.protocolVersionveschemaVersionküçük tam sayıdır ve JSON sayısı olarak gider. requestId(UUID) istemcinin her deneme için ürettiği ilişki kimliğidir; sunucu yanıtı ve hatayı aynı kimlikle döndürür.- Kimlik doğrulamadan önce yalnız
Authenticate, sonraAuthenticatedışındaki çerçeveler geçerlidir; yanlış fazdaki çerçeveUnexpectedFramealır.
Bağlanma akışı
sequenceDiagram
participant C as "İstemci"
participant H as "HTTP (REST)"
participant S as "WebSocket /v1/realtime/ws"
C->>H: "POST /v1/realtime/tickets"
H-->>C: "200 ticket, expiresAt"
C->>S: "Upgrade (Sec-WebSocket-Protocol openplay.realtime.v1)"
C->>S: "Authenticate(protocolVersion 1, ticket)"
S-->>C: "Ready(connectionId, playerId, sessionEpoch, authorityGeneration)"
C->>S: "Join(pluginId, moduleId, target)"
S-->>C: "Joined(subscriptionId)"
S-->>C: "Snapshot veya DurableRecovery"
C->>S: "Input veya Command"
S-->>C: "Ack veya CommandResult"
1. Bilet al
POST /v1/realtime/tickets HTTP/1.1
Host: oyun.example.com
Origin: https://oyun.example.com
x-crx-env: 0192a3b4-0000-7000-8000-000000000001
Cookie: __Secure-crx.session=<oturum>; __Secure-crx.csrf=<csrf-çerezi>
x-csrf-token: <csrf-jetonu>
HTTP/1.1 200 OK
Cache-Control: no-store
Content-Type: application/json
{"ticket":"tkt_AbC123-xyz","expiresAt":"2026-11-03T10:15:30+00:00","protocol":"openplay.realtime.v1"}
| Başlık | Zorunlu | Not |
|---|---|---|
x-crx-env | evet | Oyuncunun ortamı. Oturumun ortamıyla uyuşmalıdır. |
Origin | evet | Ortamın izinli kökenlerinden biri olmalı; bilet bu kökene bağlanır. |
Cookie ya da Authorization: Bearer <oturum jetonu> | evet | Çerez varsa her zaman çerez kipi seçilir; bozuk çerezde Bearer’a düşülmez. |
x-csrf-token + __Secure-crx.csrf çerezi | yalnız çerez kipinde | Çift gönderim (double submit). Başarılı her istekte yeni CSRF değeri döner; yanıttaki x-csrf-token başlığını ve Set-Cookie’yi saklayın (oturumlar ve CSRF). |
- Bilet tek kullanımlıktır, 30 saniye geçerlidir ve
Origin’e bağlıdır. Soket açmadan önce alın; bekletmeyin. - Bu uçta kimlik, CSRF ve Origin hataları aynı yanıtı alır:
403ve düz metinpermission denied. Modül kapalıysa (plugins)404ve{"code":"module_disabled",…}.
2. Soketi aç
- Adres:
wss://<oyun-alan-adınız>/v1/realtime/ws. Sorgu dizesi olmamalıdır; olursa yükseltme reddedilir. Sec-WebSocket-Protocol: openplay.realtime.v1istenmelidir; sunucu bunu seçer. İstenmezse yükseltme reddedilir.Originzorunludur ve ortamın izinli kökenlerinden biri ya da genel izinli listede olmalıdır. Tarayıcı bunu kendisi gönderir.- Yükseltme reddi
401(düz metinunauthorized); modül kapalıysa404. - Adres başına ve oyuncu başına bağlantı sınırları vardır (limitler).
3. Authenticate gönder
Soket açılınca 5 saniye içinde ilk çerçeve gelmelidir; gelmezse sunucu AuthenticationFailed hatası yazıp kapatır. Kimlik doğrulama fazında çerçeve en çok 4 KiB olabilir.
{"type":"Authenticate","protocolVersion":1,"ticket":"tkt_AbC123-xyz"}
Sunucu bileti tüketir (kökeni ve alt protokolü doğrular), oturumu yeniden doğrular ve cevap verir:
{"type":"Ready","protocolVersion":1,"connectionId":"0192a3b4-0000-7000-8000-0000000000a1","playerId":"0192a3b4-0000-7000-8000-0000000000b2","sessionEpoch":"7","authorityGeneration":"42"}
| Alan | Anlam |
|---|---|
connectionId | Bu soketin sunucu kimliği. |
playerId | Doğrulanmış oyuncu. |
sessionEpoch | Bu soketin yazma dönemi (epoch). Input çerçevelerinde aynen geri verilir. Aynı oyuncunun daha yeni bir soketi aynı kaynağa yazmaya başlarsa eski soketin girdileri Stale alır. |
authorityGeneration | Ortamın yetki nesli; sunucu tarafı sınırlama içindir, istemci yalnız saklar. |
Geçersiz, kullanılmış, süresi dolmuş ya da başka kökene ait bilet AuthenticationFailed ile reddedilir; sunucu soketi kapatır. Yeni bilet alıp yeniden bağlanın.
İstemci çerçeveleri
Ready’den sonra gönderilebilir. Çerçeve boyutu en çok 16 KiB’dir; aşan çerçeve PayloadTooLarge alır.
Join: aboneliğe katıl
{"type":"Join","protocolVersion":1,"requestId":"0192a3b4-0000-7000-8000-000000000010","pluginId":"package-ride","moduleId":"package-ride.street","target":{"kind":"Scene","sceneId":"0192a3b4-0000-7000-8000-000000000031"}}
| Alan | Tür | Anlam |
|---|---|---|
requestId | UUID | Deneme kimliği. |
pluginId | metin | Modülün sahibi eklenti (eklentiler). |
moduleId | metin | Eklentinin tanımladığı realtime modülü; eklentinin şema belgesindeki modules bölümünde listelenir. |
target.kind | metin | PlayerSelf, Room, Scene ya da InterestSet. |
target.roomId / sceneId / interestSetId | UUID | Hedefin kimliği (kind’a göre; PlayerSelf kimlik taşımaz). |
cursor | UUID, isteğe bağlı | Önceki bir DurableRecovery’den gelen opak devam imleci. |
Sunucu hedefi yetkilendirir; ham bir Redis anahtarı ya da konu adı verilmez. Başarı: Joined. Ardından modülün türüne göre bir Snapshot ya da DurableRecovery gelir.
Leave: abonelikten çık
{"type":"Leave","protocolVersion":1,"requestId":"…","subscriptionId":"…"}
Yanıt Left’tir; tekrarlanan Leave zararsızdır.
Input: geçici girdi
Sunucu-otoriter modüllerde oyuncu girdisi (hareket, direksiyon). Kayıp kabul edilmez, sıra numarası zorunludur.
{"type":"Input","protocolVersion":1,"requestId":"…","pluginId":"arena","moduleId":"arena.movement","messageType":"arena.movement.input","schemaVersion":1,"subscriptionId":"…","sessionEpoch":"7","inputSeq":"42","payload":{"delta":1}}
| Alan | Anlam |
|---|---|
messageType, schemaVersion | Modülün şema belgesindeki girdi tanımıyla birebir eşleşmelidir. |
subscriptionId | Joined’dan gelen abonelik. |
sessionEpoch | Ready’deki değer. |
inputSeq | Artan sıra numarası (ondalık metin). Aynı numara ve aynı içerik tekrar gönderilirse Replayed alırsınız; aynı numara farklı içerikle Mismatch. |
payload | Eklentinin girdi şemasına uyan nesne. Kodlanmış boyutu en çok 4 KiB ve modülün maxBytes değeri kadardır; aşım InvalidPayload alır. |
Girdi hızı modülün şema belgesindeki ratePerSecond ve burst değerleriyle tanımlıdır; bağlantı başına genel çerçeve bütçesi ayrıca uygulanır (limitler).
Command: kalıcı komut
Veritabanı işlemiyle kalıcı yazan komut (ödül, teslimat); sonuç yalnız işlem kesinleştikten sonra döner. HTTP komut ucuyla aynı kurallara tabidir (eklentileri çağırma).
{"type":"Command","protocolVersion":1,"requestId":"…","pluginId":"package-ride","moduleId":null,"messageType":"package-ride.progression-missions.claim.input","schemaVersion":1,"idempotencyKey":"claim-7f3a","expectedVersion":"12","payload":{"missionId":"daily-1"}}
| Alan | Anlam |
|---|---|
idempotencyKey | Zorunlu mantıksal tekrar anahtarı. Aynı anahtar ve aynı içerik aynı sonucu döndürür (idempotency). |
expectedVersion | İsteğe bağlı iyimser sürüm (ondalık metin). Uyuşmazlık hata olur. |
moduleId | Oda kapsamlı komutlarda modül bağlamı; yoksa null. |
payload | Eklentinin komut şemasına uyar; kodlanmış boyutu en çok 16 KiB’dir, aşım InvalidPayload alır. |
Ping
{"type":"Ping","protocolVersion":1,"nonce":"a1"}
Yanıt {"type":"Pong","nonce":"a1"}. nonce isteğe bağlıdır. Uygulama düzeyi Ping bağlantı canlılığını ölçer; oyuncu etkinliği sayılmaz, boşta kapanmayı ertelemez (boşta kapanma).
Sunucu çerçeveleri
type | Ne zaman | Alanlar |
|---|---|---|
Ready | Authenticate başarılı | protocolVersion, connectionId, playerId, sessionEpoch, authorityGeneration |
Joined | Join yetkilendirildi | requestId, subscriptionId, target |
Left | Leave işlendi | requestId, subscriptionId |
CommandResult | Command kesinleşti | requestId, messageType, schemaVersion, payload |
Ack | Input işlendi | requestId, inputSeq, status, revision (isteğe bağlı) |
Snapshot | Geçici durum yayını | subscriptionId, resourceId, messageType, schemaVersion, streamEpoch, revision, payload |
DurableRecovery | Kalıcı akış için kurtarma bariyeri | subscriptionId, cursor, barrierSequence, coveredEventIds, snapshot (boş olabilir) |
DurableEvent | Kalıcı, sıralı eklenti olayı | subscriptionId, streamId, sequence, eventId, messageType, schemaVersion, cursor, payload |
Pong | Ping yanıtı | nonce |
Error | Hata | requestId (varsa), code, retryable |
Ack durumları
status | Anlam | Ne yapmalı |
|---|---|---|
Applied | Girdi durumu ilerletti. revision yeni revizyondur. | — |
Replayed | Aynı sıra numarası ve içerik zaten işlenmişti. | Yoksayın; güvenli tekrar. |
Stale | Sıra numarası güncel yazarın gerisinde ya da daha yeni bir soket aldı. | Bu girdiyi bırakın; yeni soket varsa bu soket artık yazar değildir. |
Mismatch | Aynı sıra numarası farklı içerikle geldi. | İstemci hatasıdır; sıra numarasını yeniden üretmeyin, tekrar etmeyin. |
ResyncRequired | Sıra boşluğu ya da kurtarılamayan durum. | Taze anlık görüntü için yeniden Join edin (cursor olmadan). |
Applied ve Replayed dışında revision bulunmayabilir. Alan yokken null gönderilmez; alan hiç yoktur.
Snapshot ve DurableRecovery
Snapshotgeçici durumdur:streamEpoch(sunucu önbelleği yeniden başladığında artar) verevision(monoton) birlikte sıralanır. AynıstreamEpochiçinde daha eski birrevision, yeni durumu ezmemelidir.streamEpochdeğişmişse yeni bir akış başlamıştır; eskirevisionile karşılaştırmayın.DurableRecoverykalıcı akışta taban çizgisidir:cursorbu noktaya bağlı yeni imleçtir,barrierSequenceanlık görüntünün ve tekrar oynatmanın kapsadığı akış başıdır,coveredEventIdsanlık görüntünün zaten içerdiği olay kimlikleridir (bunları ayrıca uygulamayın).snapshotyalnız tazeJoin’de dolu gelir;cursorile devam ederken yoktur.DurableEvent’lersequencesırasıyla gelir;eventIduçtan uca tekilleştirme anahtarıdır,cursoro olaya kadar ilerlemiş yeni imleçtir. İmleci saklayın: yeniden bağlanırkenJoin.cursorolarak verirsiniz (yeniden bağlanma).
Hata çerçevesi
{"type":"Error","requestId":"0192a3b4-0000-7000-8000-000000000010","code":"InvalidPayload","retryable":false}
Hata çerçevesi gerekçe metni taşımaz: yalnız kod ve retryable. Bir eklenti reddi (ör. iş kuralı) bile InvalidPayload olarak görünür; neden istemciye telden verilmez.
code | Ne zaman | retryable | Soket |
|---|---|---|---|
UnexpectedFrame | Fazına uymayan çerçeve (ör. kimlik doğrulamadan önce Join, ya da ikinci Authenticate) | hayır | kapanır |
UnsupportedProtocol | protocolVersion 1 değil | hayır | kapanır |
InvalidPayload | Bozuk JSON, bilinmeyen alan, şemaya uymayan yük, eklenti/iş kuralı reddi, kaynak yok, sürüm çakışması, modül kapalı | hayır | çerçeve bazlı hatada açık kalır; ayrıştırma hatasında kapanır |
AuthenticationFailed | Bilet geçersiz/kullanılmış/süresi dolmuş, 5 sn zaman aşımı, oturum iptal edildi | hayır | kapanır |
PermissionDenied | Hedef, modül ya da işlem için yetki yok; yasaklı hesap | hayır | açık kalır |
PayloadTooLarge | Çerçeve bütçesini aştı (4 KiB kimlik doğrulama, 16 KiB sonrası) | hayır | kapanır |
CapacityExceeded | Hız ya da kapasite sınırı doldu | çerçeve bütçesi ve oran sınırında evet; oyuncu/adres başına soket sayısı sınırında hayır | çerçeve bütçesi ve soket sayısı sınırında kapanır |
Unavailable | Bağımlılık geçici kullanılamıyor ya da yerleşim hazır değil | genellikle evet (IdempotencyExpired hâli hayır) | duruma göre |
ResyncRequired | İmleç yok, süresi dolmuş, uyuşmuyor, boşluklu ya da tekrar bütçesini aştı | — | açık kalır |
Uyarı
Soketin kapanıp kapanmayacağını yalnız
retryable’dan çıkarmayın. İstemci,Errorçerçevesinden sonra soketin hâlâ açık olup olmadığını bağlantı durumundan (kapanış olayı) öğrenmelidir. Uzun ömürlü soketlerde çerçeve bazlı hatalar (InvalidPayload,PermissionDenied) bağlantıyı düşürmez.
Kapanış kodları
| Kod | Neden | Anlam |
|---|---|---|
4100 | idle_timeout | Oyuncu etkinliği gelmedi; boşta kapanma (ayrıntı). Tipli Error çerçevesi olmaz. |
1008 | module_disabled | plugins modülü kapatıldı. |
1013 | unavailable | Modül kapısı doğrulanamadı; sonra yeniden deneyin. |
Örnek: elle bağlanma (özet)
Tarayıcıda SDK kullanın; aşağıdaki iskelet protokol sırasını gösterir.
const res = await fetch("/v1/realtime/tickets", {
method: "POST",
credentials: "include",
headers: { "x-crx-env": environmentId, "x-csrf-token": csrfToken },
});
const { ticket } = await res.json();
const ws = new WebSocket(`wss://${location.host}/v1/realtime/ws`, ["openplay.realtime.v1"]);
ws.onopen = () => ws.send(JSON.stringify({ type: "Authenticate", protocolVersion: 1, ticket }));
ws.onmessage = (event) => {
const frame = JSON.parse(event.data as string);
if (frame.type === "Ready") {
// Join gönderin, frame.sessionEpoch'u Input çerçeveleri için saklayın.
}
};
Sıradaki adım
Bağlantı koptuğunda imleç ve epoch ile nasıl devam edeceğiniz, limitler ve sıkıştırma için yeniden bağlanma ve limitler.
Yeniden bağlanma ve limitler
Bu sayfa, realtime soketi koptuğunda durumun nasıl kurtarıldığını, ResyncRequired geldiğinde ne yapılacağını, boşta kapanma (4100) davranışını ve sunucunun uyguladığı limitleri anlatır. Mobil ya da dengesiz ağda oynanan bir oyun yazıyorsanız bu sayfayı baştan sona okuyun.
Kopma sonrası kurtarma
Soket her zaman kopabilir (ağ, dağıtım, yük dengeleyici). Open Play’de kurtarma yeni soketle yeniden katılma (re-join) ile yapılır; eski soketin durumu sunucuda yeniden kullanılmaz.
- Yeni bilet al. Her bağlantı yeni bir bilet ister (tek kullanımlık, 30 sn); eski bilet yeniden kullanılamaz (protokol).
Authenticate,Ready. YenisessionEpochgelir. Yeni soket aynı kaynağa yazmaya başladığında oyuncunun eski soketi artık yazar değildir: eski soketin girdileriAck: Stalealır.- Her abonelik için yeniden
Join.- Kalıcı (durable) akışlarda: son aldığınız
cursor’ıJoin.cursorolarak verin. Sunucu kaldığınız yerdenDurableEvent’leri tekrar oynatır ve yeni birDurableRecoverybariyeri yollar (snapshotboştur). - Geçici (ephemeral) durumda:
cursoryoktur;Jointaze birSnapshotgetirir. Gönderilmiş amaAckalmamışInput’lar tekrar oynatılmaz: sonucu belirsizdir, oyun mantığınız en sonSnapshot’a göre devam etmelidir. - Kalıcı komutlarda (
Command):Ackgelmeden kopan komutun sonucu belirsizdir. AynıidempotencyKeyile yeniden gönderin ya da sonucu sorgulayın (eklentileri çağırma); yeni anahtar üretmeyin.
- Kalıcı (durable) akışlarda: son aldığınız
ResyncRequiredgelirse (imleç yok, süresi dolmuş, başka oyuncuya ait, boşluklu ya da tekrar bütçesini aşmış) imleci atın vecursorolmadan tekrarJoinedin; bu taze bir anlık görüntü getirir. Aynı imleçle ısrar etmeyin.
İmleç (cursor) kuralları
- Opaktır ve oyuncuya bağlıdır; başka oyuncunun imleci kullanılamaz. İçeriğini ayrıştırmayın.
- Her
DurableRecoveryve herDurableEventyeni bir imleç taşır; en sonuncusunu saklayın. - Tek kurtarmada en çok 256 kalıcı olay tekrar oynatılır; fazlası
ResyncRequiredile taze anlık görüntüye çevrilir. - İmleç ve teslimat saklama penceresi 24 saattir; ondan eski imleç
ResyncRequiredalır. coveredEventIds’deki olaylar taze anlık görüntüde zaten vardır; bunları ayrıca uygulamayın.
TypeScript SDK ne yapar
SDK bu akışı sizin yerinize yürütür (RealtimeClient, client.realtime):
| Davranış | Varsayılan | Ayar |
|---|---|---|
| Otomatik yeniden bağlanma | açık | autoReconnect |
| Deneme gecikmesi | min(reconnectBaseMs · 2^(n−1), 30 000) ms + [0, reconnectBaseMs) jitter | reconnectBaseMs: 1000 (100 ile 10 000 arası) |
| En çok deneme | 8 | maxReconnectAttempts: 0 ile 20 arası |
| Kimlik doğrulama zaman aşımı | 5 sn | authTimeoutMs (en çok 5 sn) |
Uygulama Ping aralığı | 15 sn | heartbeatMs: 10 ms ile 60 sn |
| Kalıcı komut zaman aşımı | 15 sn | commandTimeoutMs: 1 ms ile 120 sn |
| Cevap bekleyen girdi penceresi | 4 | maxPendingInputs: 1 ile 8 |
| Çerçeve boyutu | 16 KiB | maxFrameBytes (en çok 16 KiB) |
Durum makinesi idle, ticketing, connecting, authenticating, ready, recovering, live, backoff, reauthRequired, upgradeRequired, idleClosed ve closed değerlerinden geçer. Önemli olanlar:
recovering/backoff: SDK yeniden bağlanıyor; aboneliklerin imleçleri korunur.reauthRequired: bilet ya da kimlik reddedildi (AuthenticationFailed, 401/403). Oturumu yeniden kurun; SDK kendiliğinden sonsuz döngüye girmez.upgradeRequired: sunucu protokol sürümünü ya da çerçeveyi tanımadı (UnsupportedProtocol, 426). İstemciyi güncelleyin.- Sunucu
PayloadTooLargeya daCapacityExceededgönderirse SDK bunu geri basınç (backpressure) hatası olarak yüzeye çıkarır; bağlantı durumunu değiştirmez.
Not
Tamamlanmamış girdiler soket koptuğunda “belirsiz sonuçlu” olarak reddedilir ve yeniden bağlanınca otomatik tekrar gönderilmez. Sinyal (
best-effort) mesajları da tekrar edilmez.
Boşta kapanma (4100)
Sunucu, girdi kabul eden (etkileşimli) bir aboneliği olan ve belirli süre oyuncu etkinliği göndermeyen soketi kapatır.
- Kapanış kodu
4100, nedenidle_timeout. TipliErrorçerçevesi yoktur; yalnız WebSocket kapanış çerçevesi. - Süre varsayılan 5 dakikadır ve operatör tarafından değiştirilebilir ya da kapatılabilir. Kontrol aralığı
min(süre/4, 15 sn)olduğundan kapanış eşikten en çok bu kadar geç gelir. - Menüde ya da oyun öncesinde (girdi kabul eden abonelik yokken) sayaç işlemez.
- Etkinlik sayılan şey eklentinin tanımıdır: girdi çerçevesi genellikle sayılır; uygulama
Ping,Authenticateve protokol düzeyi ping sayılmaz. Oyununuz duraklatılmış ekranda da bağlı kalacaksa eklentinin tanımladığı canlı tutma girdisini gönderin; duraklatma, garaj gibi ekranlarda canlı tutma girdisi göndermek AFK sayılmamasını sağlar. - Açık bir soket oturumu yaşatmaz: oturum ömrü ancak oyuncu REST isteği yaptıkça uzar (güvenlik); sunucu soketteki oturumu 25 saniyede bir yeniden doğrular.
- Bu kapanışı bir hata olarak ele almayın: oyuncuya “Devam et” gösterin, onayında yeni bilet alıp yeniden bağlanın; imleçler sayesinde abonelikler kurtarılır.
SDK’da onIdleClose geri çağrısını verirseniz istemci idleClosed durumuna geçer ve kendiliğinden yeniden bağlanmaz; kullanıcı onayında connect() çağırın. Geri çağrıyı vermezseniz kapanış sıradan bir kopma gibi işlenir ve SDK kendisi yeniden bağlanır.
import { createPlayerClient, type PlayerClient } from "@ferdiunal/open-play-ts";
/**
* Sunucu boşta kapanışında (`4100`, `idle_timeout`) SDK kendiliğinden yeniden bağlanmaz; oyuncuya "Devam et"
* gösterin ve onayında `connect()` çağırın. Abonelikler imleçleriyle kurtarılır.
*/
export function createClientWithIdlePrompt(
baseUrl: string,
environmentId: string,
showContinueButton: (onContinue: () => void) => void,
): PlayerClient {
const client: PlayerClient = createPlayerClient({
baseUrl,
environmentId,
realtime: {
reconnectBaseMs: 250, // ilk yeniden bağlanma denemesi 250 ms (varsayılan 1000)
onIdleClose: () => showContinueButton(() => void client.realtime.connect()),
},
});
return client;
}
Limitler
| Limit | Değer | Aşılınca |
|---|---|---|
| Bilet ömrü | 30 sn, tek kullanım, Origin’e bağlı | AuthenticationFailed |
Authenticate bekleme süresi | 5 sn | AuthenticationFailed, soket kapanır |
| Kimlik doğrulama fazı çerçevesi | 4 KiB | PayloadTooLarge, kapanır |
| Çerçeve (kimlik doğrulama sonrası) | 16 KiB | PayloadTooLarge, kapanır |
| Taşıma katmanı mesajı | 64 KiB | 16 KiB ile 64 KiB arası tipli hata alır; 64 KiB üstü tipli hata olmadan soket hatasıyla düşer |
Input yükü | en çok 4 KiB ve modülün maxBytes değeri | InvalidPayload |
Command yükü | en çok 16 KiB | InvalidPayload |
| Bağlantı başına çerçeve hızı | 40 çerçeve/sn ortalama, 4 sn’lik (160 çerçeve) patlama payı | CapacityExceeded (retryable: true) ve soket kapanır |
| Oyuncu başına açık soket | 4 | CapacityExceeded (retryable: false), soket kapanır |
| Adres başına açık soket | 8 | CapacityExceeded (retryable: false), soket kapanır (operatör gözlem kipine alırsa yalnız sayılır) |
| Adres başına yeni bağlantı | 30/dakika | yükseltme reddedilir |
| Soket başına abonelik | 32 (sunucu varsayılanı) | Join reddedilir |
| Oturum yeniden doğrulama | 25 sn’de bir | oturum iptal edilmişse AuthenticationFailed ve kapanış |
| Modül kapısı yeniden kontrol | 2 sn’de bir | 1008 / 1013 ile kapanış |
| Kurtarmada tekrar oynatılan olay | 256 | ResyncRequired |
| İmleç saklama | 24 saat | ResyncRequired |
| Boşta kapanma | 5 dk (varsayılan) | 4100 idle_timeout |
Notlar:
- Çerçeve hızı bütçesi
Input’la sınırlı değildir; alınan her metin çerçevesi ve protokol düzeyiPingbir çerçeve sayılır (Pongsayılmaz). Dürüst bir istemci yaklaşık 30 ile 35 çerçeve/sn gönderir; 40/sn’nin altında kalın ve bir duraksamadan sonra biriken çerçeveleri toplu göndermeyin. - Sayılar sunucu varsayılanlarıdır; operatör bazılarını (boşta süresi, bağlantı sınırları, çerçeve bütçesi) ortam yapılandırmasıyla değiştirebilir. Barındırılan bir Open Play kullanıyorsanız değerleri sağlayıcınıza sorun.
Inputhızı ayrıca modülün şema belgesindekiratePerSecondveburstdeğerleriyle tanımlıdır.
Sıkıştırma
- Sunucu permessage-deflate (RFC 7692) sıkıştırmasını destekler, yalnız istemci teklif ederse devreye girer. Tarayıcılar bunu kendiliğinden teklif eder; ayrı bir şey yapmanız gerekmez. Benzer JSON çerçevelerinde belirgin küçülme sağlar.
- Operatör sıkıştırmayı kapatabilir; kapalıysa soket sıkıştırmasız çalışır, protokol değişmez.
- Unity yerel (native) WebSocket istemcisinde sıkıştırma henüz yoktur; bu bilinen bir kısıttır. WebGL’de tarayıcı bunu üstlenir (Unity SDK).
Sunucu tarafı canlılık sondası
Sunucu, bağlantı gecikmesini ölçmek için yaklaşık 5 saniyede bir protokol düzeyi WebSocket Ping gönderir. Tarayıcı ve standart istemci kütüphaneleri Pong’u kendiliğinden yanıtlar; elle WebSocket yazıyorsanız Pong yanıtını unutmayın. Bu sonda oyuncu etkinliği sayılmaz.
Sorun giderme
| Belirti | Olası neden | Çözüm |
|---|---|---|
Her bağlanışta hemen AuthenticationFailed | Bilet tekrar kullanıldı ya da 30 sn geçti; Origin bilet isteğinden farklı | Her bağlantıda yeni bilet alın; bileti aldığınız origin’den bağlanın |
CapacityExceeded ile kapanma | Çerçeve hızı ya da bağlantı sınırı | Çerçeve gönderim hızını düşürün; eski sekmeleri kapatın (oyuncu başına 4 soket) |
ResyncRequired döngüsü | Eski imleçle ısrar | İmleci atın, cursor olmadan Join edin |
| 5 dakika sonra kopma | Boşta kapanma (4100) | “Devam et” akışı kurun ya da canlı tutma girdisi gönderin |
Yükseltme 401 | Sorgu dizesi var, alt protokol istenmedi ya da Origin izinli değil | Protokol: soketi aç |
Daha fazlası için sorun giderme.
Eklentilere genel bakış
Bu sayfa, Open Play’de eklenti (plugin) kavramını açıklar: oyuna özgü komutları, sorguları ve gerçek zamanlı modülleri çekirdeğe oyun adı eklemeden sunan paketler. Çekirdek modüllerin (karakter, ekonomi, mağaza…) ötesinde bir oyunun mantığına nasıl bağlandığınızı ve neyin bugün desteklenmediğini burada görürsünüz.
Eklenti nedir
Bir eklenti, Open Play sunucusunun içinde çalışan ve şu üç yüzeyi tanımlayan bir pakettir:
| Yüzey | Ne verir | Nasıl çağrılır |
|---|---|---|
| Komut (command) | Durumu değiştiren, kalıcı ve tekrar-güvenli işlem (ör. ödül al, teslimatı tamamla) | HTTP POST ya da realtime Command çerçevesi: eklentileri çağırma |
| Sorgu (query) | Salt-okunur okuma (ör. aktif teslimat, katalog) | HTTP GET ya da POST |
| Realtime modülü | Anlık girdi ve durum yayını (hareket, oda, sahne) | /v1/realtime/ws: realtime protokolü |
Her eklenti bir şema belgesi (artifact) yayınlar: hangi komut, sorgu ve modülün hangi girdi ve çıktı şemasıyla var olduğunu, hangi kimlikle çağrılabildiğini ve yeniden deneme kuralını tarif eder. SDK’ların tipli bağlamaları bu belgeden üretilir: bağlamalar.
Komutlar tek bir veritabanı işleminde (transaction) kesinleşir: komutun etkisi, sonucu, olayı ve tekrar kaydı birlikte yazılır ya da hiç yazılmaz. Gerçek zamanlı geçici durum ise yalnız hız için tutulur ve ödeme, XP, eşya ya da ödül gibi kalıcı sonuçların otoritesi değildir.
Bugünkü durum: yalnız güvenilir, derlenmiş eklentiler
Uyarı
Üçüncü taraf eklenti yükleme henüz yok. Eklentiler, Open Play sunucusunun kendisine derlenmiş (Rust) kodlardır ve güvenilir kod sayılır. Bir oyun geliştiricisi olarak kendi eklentinizi paneldan ya da API’den yükleyemezsiniz; yalıtılmış (sandbox) çalıştırma, kaynak ölçümü ve imzalı dağıtım gelecekteki bir tasarımdır ve bugün çalışmaz.
Kendi oyun mantığınızı bugün şu yollarla bağlarsınız:
- Kurallar (panelde Kurallar ekranı): karakter olaylarına bağlı otomasyonlar. Bkz. oyun kuralları.
- Webhook’lar: Open Play olaylarını kendi sunucunuza bildirir. Bkz. webhook rehberi.
- Kendi sunucunuz + sunucu anahtarı: kendi mantığınızı kendi sunucunuzda çalıştırıp çekirdek REST uçlarını çağırın. Bkz. uç nokta referansı.
Depoda gelen eklentiler:
| Eklenti | Sürüm | Ne için | Yüzey |
|---|---|---|---|
package-ride | 1.44.0 | Teslimat oyunu: sürüş, görevler, yarış bahisleri, sahne | 36 komut, 33 sorgu, 3 realtime modülü |
arena | 1.0.0 | Minimal örnek: tek hareket modülü | 0 komut, 0 sorgu, 1 realtime modülü |
Bunlar sunucuyla birlikte gelir; sizin ortamınızda hangilerinin etkin olduğunu panelde Eklentiler ekranından görürsünüz (Eklentiler).
Ortam başına durum
Bir eklenti, her ortam (environment) için ayrı ayrı bir durumda bulunur:
| Durum | Komutlar | Sorgular |
|---|---|---|
Etkin (Enabled) | kabul edilir | kabul edilir |
Salt okunur (ReadOnly) | reddedilir | kabul edilir |
Boşaltılıyor (Draining) | yeni komut reddedilir, süren işler biter | kabul edilir |
Kapalı (Disabled) | reddedilir | reddedilir |
Reddedilen çağrı 403 ve forbidden alır (hatalar). Aynı sonuç, ortama verilen eklenti sürümü sunucudaki sürümle uyuşmadığında da görülür: sunucu yeni bir eklenti sürümüyle güncellendiyse ortamın eklenti yetkisi (grant) de o sürüme geçirilmelidir. Beklenmedik 403 forbidden alıyorsanız önce panelde eklentinin durumuna ve sürümüne bakın.
Ek olarak ürün modülü plugins kapalıysa tüm /v1/plugins/... ve realtime uçları 404 ve module_disabled döner (Oyun ayarları: modüller).
Kimlikle erişim
Her işlemin şema belgesinde bir access değeri vardır:
access | Kim çağırır |
|---|---|
player | Oyuncu oturumu (çerez ya da Bearer oturum jetonu) |
server | Yalnız sunucu anahtarı; oyuncu istemcisinde görünmez |
public | Kimlik gerektirmeyen, yalnız GET sorgusu (yalnız x-crx-env gerekir) |
Belirtilmemiş ya da bilinmeyen değer güvenli tarafa (player) düşer. İstemciye gömülen (client) API anahtarıyla eklenti çağrılamaz: 401 alır. Ayrıntı: eklentileri çağırma.
Sıradaki adım
- Komutu ve sorguyu çağırmak için eklentileri çağırma.
- Tipli istemci üretmek ve şema sürümünü sabitlemek için bağlamalar.
- Kendi sunucunuza yeni bir eklenti yazmak için eklenti yazmak.
Eklenti yazmak
Bu sayfa, Open Play’e yeni bir eklenti (plugin) yazmak isteyenler içindir: eklentinin parçalarını, küçük çalışan bir örneği, sürüm yükseltirken izlenecek güvenli sırayı ve gerçek olaylardan çıkan yaygın hataları gösterir. Eklentiyi kullanmak için eklentilere genel bakış, eklentileri çağırma ve bağlamalar sayfalarına bakın.
Bu sayfa kimin için
Uyarı
Barındırılan (hosted) stüdyolar bugün eklenti kodu yükleyemez. Eklentiler Open Play sunucusunun içine derlenen Rust kodudur ve güvenilir kod sayılır. Sandbox’lı çalıştırma, kaynak ölçümü ve imzalı dağıtım henüz yoktur. Bu rehber, Open Play’i kendi sunucusunda çalıştıran (self-hosted) ekipler ve Open Play’e katkı verenler içindir.
Kendi sunucunuzda kod derleyemiyorsanız oyun mantığınızı bugün şu yollarla bağlarsınız: panelde oyun kuralları, webhook’lar ya da kendi sunucunuz + sunucu anahtarı (uç nokta başvurusu).
Eklentinin anatomisi
Bir eklenti, tek bir Rust crate’idir (örneğin crx-plugin-arena, crx-plugin-work-items, crx-plugin-package-ride). Parçalar şunlardır:
| Parça | Ne işe yarar | Nerede tanımlanır |
|---|---|---|
| Manifest | Eklentinin kimliği (PluginId), sürümü (PluginVersion), host API major’ı, sağladığı ve gerektirdiği eklentiler, izinleri (PluginPermission), yapılandırma şeması, mesajları, migration özeti ve gerçek zamanlı modülleri | OpenPlayPlugin::manifest |
| Tipli mesajlar | Komut/sorgu girdisi ve çıktısı; her biri tek yönlü (CommandInput, CommandOutput, QueryInput, QueryOutput, gerçek zamanlı girdi/durum, olay), katı serde tipi | PluginMessage uygulayan struct’lar |
| Komut | Durumu değiştiren, kalıcı ve tekrar oynatması güvenli işlem. Karar fonksiyonu saftır: I/O, saat, rastgelelik yoktur | TypedCommand::decide, OpenPlayPlugin::register |
| Sorgu | Salt-okunur okuma; yalnız girdi/çıktı kodekleri kaydedilir | OpenPlayPlugin::register_queries |
| Artifact (şema belgesi) | İstemci SDK’larının ve bağlamaların okuduğu plugin.schema.json: şemalar, işlem tablosu, modüller, schemaSha256 | OpenPlayPlugin::artifact, PluginArtifact::from_manifest |
| Gerçek zamanlı modül (isteğe bağlı) | Sunucu-otoriter canlı girdi/durum indirgeyicisi (reducer) | OpenPlayPlugin::register_realtime, TypedRealtimeModule |
| Dispatcher | Komutun veritabanına gerçekten yazıldığı, sorgunun okunduğu yer; sunucudaki ortak işlem sınırını (PluginUnitOfWork) kullanır | PluginCommandDispatcher, PluginQueryDispatcher, PluginCommandResultLookup |
| Panel yüzeyi (isteğe bağlı) | Panelde bildirimsel yönetim ekranları, özel bileşenler, oyun kuralı kataloğu, leaderboard bildirimi | admin_surface, ui_components, game_rule_catalog, leaderboards |
Sorumluluk bölümü önemlidir: sunucu (host) idempotency’yi, iyimser kilidi (optimistic lock), tek veritabanı işlemini, olay (event) ve outbox yazımını, makbuzu (receipt) ve yetki kontrolünü yapar. Eklenti yalnızca mesajları, saf kararı ve yazılacak kayıtların planını (PluginMutationPlan) sağlar. Kalıcı sonuç (ödeme, XP, eşya, ödül) her zaman komut yolundan geçer; gerçek zamanlı durum yalnız hız içindir ve ekonomik etki üretemez.
Küçük örnek: “hello counter”
Aşağıdaki örnek, en küçük gerçek eklentilerin (crx-plugin-arena, crx-plugin-scene) kalıbını izler: bir komut (increment) ve bir sorgu (getCounter). Kod parçaları depodaki docs/developer/examples/rust/ dosyalarından birebir alınmıştır ve crx-plugin-arena crate’inin bir testinde gerçekten derlenip kayıt defterine kaydedilir; bu yüzden sayfadaki kod eskiyemez.
Üç parça aynı modülün içindedir (birinde yapılan use, diğerlerinde de görünür).
1. Mesajlar
Her mesaj kimliği eklenti kimliğiyle başlar (hello-counter. ön eki; aksi hâlde kayıt reddedilir). int64 değerler için PluginI64 kullanın: tel üzerinde ondalık metin olarak gider (sayılar ve kodlama). deny_unknown_fields bilinmeyen alanı reddeder.
#![allow(unused)]
fn main() {
// Mesajlar: her biri tek bir yönü olan, katı (deny_unknown_fields) serde tipleridir.
use crx_plugin::{MessageDirection, PluginI64, PluginMessage};
use serde::{Deserialize, Serialize};
pub const PLUGIN_ID: &str = "hello-counter";
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct IncrementInput {
pub by: i32,
}
impl PluginMessage for IncrementInput {
const MESSAGE_ID: &'static str = "hello-counter.increment.input";
const SCHEMA_VERSION: u32 = 1;
const DIRECTION: MessageDirection = MessageDirection::CommandInput;
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct IncrementOutput {
pub value: PluginI64, // int64 tel üzerinde ondalık metindir
}
impl PluginMessage for IncrementOutput {
const MESSAGE_ID: &'static str = "hello-counter.increment.output";
const SCHEMA_VERSION: u32 = 1;
const DIRECTION: MessageDirection = MessageDirection::CommandOutput;
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct GetInput {}
impl PluginMessage for GetInput {
const MESSAGE_ID: &'static str = "hello-counter.get.input";
const SCHEMA_VERSION: u32 = 1;
const DIRECTION: MessageDirection = MessageDirection::QueryInput;
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct GetOutput {
pub value: PluginI64,
}
impl PluginMessage for GetOutput {
const MESSAGE_ID: &'static str = "hello-counter.get.output";
const SCHEMA_VERSION: u32 = 1;
const DIRECTION: MessageDirection = MessageDirection::QueryOutput;
}
}
2. Eklenti: manifest, komut, sorgu
Komutun karar fonksiyonu decide eşzamansız değildir ve I/O yapmaz; yalnızca girdiyi doğrular ve sonucu üretir. Zaman ve tohum gerekiyorsa dispatcher bunları host’tan alır ve olaya yazar (eval_now_ms, eval_seed); decide içinde SystemTime veya rand kullanılmaz.
#![allow(unused)]
fn main() {
// Eklenti: manifest + komut/sorgu kaydı. Kalıcı yazım burada değil, dispatcher'ın mutasyon planındadır.
use crx_application::{
plugin_platform::{OpenPlayPlugin, PluginRegistryError},
plugin_runtime::{PluginRegistrar, PluginRuntimeError, TypedCommand},
};
use crx_plugin::{ManifestError, PluginArtifact, PluginId, PluginManifest, PluginPermission, PluginVersion};
use serde_json::json;
pub struct IncrementCommand;
impl TypedCommand for IncrementCommand {
type Input = IncrementInput;
type Output = IncrementOutput;
// Saf ve eşzamansız olmayan karar: yalnız doğrular, I/O yapmaz.
fn decide(&self, input: &Self::Input) -> Result<Self::Output, PluginRuntimeError> {
if !(1..=100).contains(&input.by) {
return Err(PluginRuntimeError::HandlerRejected);
}
Ok(IncrementOutput { value: PluginI64::new(i64::from(input.by)) })
}
}
pub struct HelloCounterPlugin;
fn plugin_id() -> PluginId {
PluginId::try_new(PLUGIN_ID).expect("static plugin id")
}
impl OpenPlayPlugin for HelloCounterPlugin {
fn manifest(&self) -> Result<PluginManifest, ManifestError> {
PluginManifest::new(
plugin_id(),
PluginVersion::new(1, 0, 0),
1, // host API major
vec![plugin_id()], // provides
vec![], // requires
vec![PluginPermission::Outbox],
json!({"type":"object","additionalProperties":false,"properties":{}}),
vec![
IncrementInput::descriptor().expect("descriptor"),
IncrementOutput::descriptor().expect("descriptor"),
GetInput::descriptor().expect("descriptor"),
GetOutput::descriptor().expect("descriptor"),
],
"0".repeat(64), // migration checksum (64 onaltılık karakter)
vec![], // realtime modülleri
)
}
fn register(&self, registrar: &mut PluginRegistrar) -> Result<(), PluginRuntimeError> {
registrar.register_command(IncrementCommand)?;
Ok(())
}
fn register_queries(&self, registrar: &mut PluginRegistrar) -> Result<(), PluginRuntimeError> {
registrar.register_query::<GetInput, GetOutput>()?;
Ok(())
}
fn artifact(&self) -> Result<Option<PluginArtifact>, PluginRegistryError> {
Ok(Some(plugin_artifact()?))
}
}
}
3. Artifact
Artifact, manifestteki her mesajı bir işleme veya modüle bağlamak zorundadır; fazla ya da eksik mesaj kayıtta hata verir. Komutlarda idempotency_required: true, pozitif bir makbuz saklama süresi ve Read olmayan bir retry politikası zorunludur; sorgularda tersi geçerlidir.
#![allow(unused)]
fn main() {
// Artifact: SDK'nın ve bağlamaların okuduğu şema belgesi; manifestle birebir eşleşmek zorundadır.
use std::collections::BTreeMap;
use crx_plugin::{
MessageId, PluginAccess, PluginArtifactSpec, PluginHttpMethod, PluginJournalPolicy,
PluginOperationDefinition, PluginOperationKind, PluginRetryPolicy,
};
fn operation(
name: &str,
kind: PluginOperationKind,
request: (&str, &str), // (şema adı, mesaj kimliği)
response: (&str, &str),
) -> PluginOperationDefinition {
let is_command = kind == PluginOperationKind::Command;
let segment = if is_command { "commands" } else { "queries" };
PluginOperationDefinition {
name: name.to_owned(),
kind,
path: format!("/v1/plugins/{PLUGIN_ID}/{segment}/{}", request.1),
method: if is_command { PluginHttpMethod::Post } else { PluginHttpMethod::Get },
request_schema: request.0.to_owned(),
response_schema: response.0.to_owned(),
schema_version: 1,
retry: if is_command { PluginRetryPolicy::SameKeyCommand } else { PluginRetryPolicy::Read },
journal: if is_command { PluginJournalPolicy::Full } else { PluginJournalPolicy::None },
resource: None,
result_path: is_command
.then(|| format!("/v1/plugins/{PLUGIN_ID}/commands/{}/result", request.1)),
success: Some(200),
access: PluginAccess::Player,
request_message_type: MessageId::try_new(request.1).expect("message id"),
response_message_type: MessageId::try_new(response.1).expect("message id"),
receipt_retention_seconds: is_command.then_some(86_400),
idempotency_required: is_command,
deprecated: None,
}
}
pub fn plugin_artifact() -> Result<PluginArtifact, PluginRegistryError> {
let value = json!({
"type":"object","additionalProperties":false,
"properties":{"value":{"type":"integer","format":"int64"}},
"required":["value"]
});
let schemas = BTreeMap::from([
("IncrementInput".to_owned(), json!({
"type":"object","additionalProperties":false,
"properties":{"by":{"type":"integer","format":"int32","minimum":1,"maximum":100}},
"required":["by"]
})),
("IncrementOutput".to_owned(), value.clone()),
("GetInput".to_owned(), json!({"type":"object","additionalProperties":false,"properties":{}})),
("GetOutput".to_owned(), value),
]);
let spec = PluginArtifactSpec {
schemas,
commands: BTreeMap::from([("increment".to_owned(), operation(
"increment",
PluginOperationKind::Command,
("IncrementInput", IncrementInput::MESSAGE_ID),
("IncrementOutput", IncrementOutput::MESSAGE_ID),
))]),
queries: BTreeMap::from([("getCounter".to_owned(), operation(
"getCounter",
PluginOperationKind::Query,
("GetInput", GetInput::MESSAGE_ID),
("GetOutput", GetOutput::MESSAGE_ID),
))]),
modules: BTreeMap::new(),
};
let manifest = HelloCounterPlugin.manifest().map_err(PluginRegistryError::Manifest)?;
Ok(PluginArtifact::from_manifest(&manifest, spec)?)
}
}
Örneğin yapmadığı şey: kalıcı yazım
IncrementCommand::decide yalnızca girdiyi doğrular. Sayacı gerçekten artıran kod, dispatcher’dadır. Dispatcher şunları yapar (gerçek örnek: crx-plugin-work-items, prepare_create ve prepare_claim):
PluginRegistry::prepare_commandile çağrıyı yetkilendirir, girdiyi katı çözer ve parmak izini (fingerprint) çıkarır.- Hedef kaydı okur (
PluginRecordQuery), iyimser kilit için sürümünü kontrol eder. - Bir
PluginMutationPlankurar: yazılacak kayıtlar (PluginRecordWrite, beklenen sürüm ve indeksleriyle) ve eklenecek olaylar (PluginEventAppend). - Planı
PluginUnitOfWorkile tek veritabanı işleminde uygular; sonuç ancak commit’ten (ya da aynı anahtarın makbuzundan) sonra döner.
Eklentiler kayıtlarını genel plugin_records (ve indeks, olay, makbuz) tablolarına yazar; eklenti başına özel SQL tablosu çoğunlukla gerekmez. Özel SQL gerekirse eklemeli bir migration ile ve eklentinin kendi migration alanında açılır.
Not
Bugün sunucuda komut yönlendirmesi eklenti başına dispatcher’larla yapılır ve bileşim kökünde (
bin/crx-api) bağlanır. Komutu olan yeni bir eklenti, kendi dispatcher’ını ve bu bağlamayı da gerektirir; yalnız manifest +registeryetmez. Yalnız realtime modülü olan eklentilerde (crx-plugin-arena,crx-plugin-scene) bu adım yoktur.
Sunucuya kaydetmek
Eklenti crate’i, bin/crx-api (ve zamanlayıcı/outbox işi varsa bin/crx-worker) bağımlılıklarına eklenir ve açılışta kayıt defterine verilir:
#![allow(unused)]
fn main() {
let mut registry = PluginRegistryBuilder::new();
registry.register_plugin(HelloCounterPlugin)?;
let registry = registry.freeze()?;
}
freeze kayıt defterini tüketip değiştirilemez hâle getirir. Tekrarlanan eklenti/mesaj/modül, eksik ya da uyumsuz bağımlılık, desteklenmeyen host API major’ı, karışık kodek ve ad alanı ihlali açılışı durdurur; hata çalışma zamanında değil, derlemeden hemen sonra görünür.
Artifact, sabitleme (pin) ve release lock
schemaSha256, artifact’taki şemaların kanonik JSON özetidir. Şemalar değişirse özet değişir; yalnız sürüm metni değişirse değişmez. İstemciler bu özeti bağlamalarına sabitler (bağlamalar).
Depoda üç yer aynı kaynaktan, aynı değişiklikte güncellenir:
artifacts/plugins/<eklenti>.plugin.schema.json: Rust’tan dışa aktarılır (PluginArtifact::to_pretty_json; örnek:crx-plugin-arenaiçindekiexport_arena_artifact).artifacts/plugins/release-lock.json: eklenti başına artifact yolu, üretilmiş bağlama yolu, tam sürüm,schemaSha256, protokol major’ı, kodek profili ve modül kimlikleri.- Üretilmiş istemci bağlaması: elle düzenlenmez, üreticiyle yenilenir.
Bir test, “depodaki JSON’un Rust’ın ürettiğinin tam kopyası olduğunu” doğrular (checked_in_artifacts_are_exact_rust_exports, crx-plugin-arena). Pin uyuşmazlığı yayını durdurur; eski özeti kabul eden bir uyumluluk katmanı eklenmez. Yeniden üretin.
Oyun istemcileri için bağlama üretmek
Oyun geliştirici, eklentinin artifact’ını alıp kendi bağlamasını üretir ve özeti bilinçli olarak sabitler:
npx crx plugins generate \
--input hello-counter.plugin.schema.json \
--schema-sha256 <artifact içindeki schemaSha256> \
--output src/generated/hello-counter.ts
CI’da --check ile dosyanın güncelliği doğrulanır. Ayrıntı ve Unity sınırı: bağlamalar. Unity için hazır bağlama bugün yalnız package-ride eklentisi içindir.
Sürümleme ve güvenli yayın
Ortamın eklenti yetkisi (grant) tam sürüm ile eşleşmelidir. Sunucuda yeni bir eklenti sürümü çalışırken ortamın yetkisi hâlâ eskisini gösteriyorsa, o ortamda eklenti ve gerçek zamanlı çağrıları reddedilir (403 forbidden; şema ucu 404). Bu, gerçekte yaşanmış bir olaydır: sürüm artırıp yetkiyi yeni sürüme geçirmeyi unutmak.
Sürüm yükseltme sırası:
- Kapılar: eklentinin testleri, artifact tam eşleşme testi ve
cargo xtask checkyeşil olmalı; migration varsa up + down çalışmalı. - Drain (boşaltma): ortamın eklenti yetkisini
Enabled→Drainingyapın. Yeni komut ve girdi hemen reddedilir. En az drain asgarisi kadar bekleyin: manifestteki en uzun gerçek zamanlı durum saklama süresi + 15 sn; gerçek zamanlı modülü olmayan eklentide 15 sn. - İkili: yeni sunucu imajını (varsa migration ile) dağıtın; migration’lar eklemeli (additive) olmalı.
- Yetkiyi yeni sürüme geçirin: panelde Sürüme geç (Eklentiler). Atlanırsa yeni ikili eklenti çağrılarını reddeder.
- İstemci: yeni bağlama ve (gerekirse) SDK ile oyun istemcisini yayınlayın.
- Doğrulama: komut sonucu, makbuz tekrar oynatma ve reddedilen çağrı sayılarını izleyin.
Geri alma kuralları: eklenti yeni sürümde henüz yazı üretmediyse Draining → önceki uyumlu ikili ve yetki. Yazı üretildikten sonra kör ikili geri alma yapılmaz: yazmaları ReadOnly ya da Disabled ile durdurun, makbuz/olay kayıtlarıyla durumu doğrulayın ve ileri düzeltme (forward-fix) sürümü çıkarın.
Ortam başına açmak
Eklenti, sunucuya derlenmiş olması yetmez; her ortamda ayrı bir yetki satırı gerekir. Panelde Eklentiler ekranından eklentiyi oyuna bağlarsınız; durumlar Enabled, ReadOnly, Draining, Disabled’dır (durumların anlamı: eklentilere genel bakış). Eklentinin izni başka bir ürün modülüne bağlıysa (örneğin leaderboard izni Competition modülüne), o modül kapalıyken geçiş 409 plugin_requires_module verir. Kanarya için önce ayrı bir test ortamında ReadOnly, sonra Enabled yapıp gözlemleyin.
Panel entegrasyonu
Eklentinin panelde ekran sunması isteğe bağlıdır ve eklentiye özel panel kodu gerektirmez:
admin_surface: bildirimsel yönetim yüzeyi. Yalnızservererişimli operatör işlemlerine bağlanır ve kayıtta manifest ve artifact’a karşı doğrulanır. Yüzey artifact’ın parçası değildir: oyunculara ve SDK’ya sunulmaz,schemaSha256’yı, sürümü ve yetkiyi değiştirmez.ui_components: eklentinininclude_str!ile derlemeye gömdüğü tek dosyalık HTML bileşenleri (izole çerçevede çalışır). Bildirimdeki özet, varlıktan hesaplanır; uyuşmazlık kayıtta reddedilir.game_rule_catalog: panelden ayarlanabilir oyun kuralı değerleri (oyun kuralları).leaderboards: eklentinin core leaderboard’a puan yazacağı tabloların bildirimi (PluginPermission::Leaderboardgerekir).
Yüzey kaydı için eklentinin bir artifact’ı olmalıdır; artifact’sız yüzey kayıtta reddedilir.
Testler
En az şunları ekleyin:
- Manifest ↔ artifact tam eşleşmesi ve şema özeti kayması (
PluginArtifact::validate_against). - Depodaki artifact JSON’u ve
release-lock.jsonsatırı Rust çıktısıyla aynı mı. int64kodeği, sınırlı girdi (uzunluk, aralık) ve reddedilen sınır değerleri.- Tek dondurulmuş kayıt defterinde birden çok eklenti (
PluginRegistryBuilder; örnek:crx-plugin-arena/tests/two_game_contract.rs). - Kalıcı komutlarda gerçek PostgreSQL ile işlem testi: aynı komutun tekrarında tek uygulama, sürüm çakışması, makbuz (örnek:
crx-infra-postgres/tests/plugin_uow_d1_integration.rs).
Kapanışta cargo xtask check ve izole bağımlılıklı tam kapı çalıştırılır; yalnız --lib koşusu tam kanıt sayılmaz.
Kontrol listesi
- Eklenti kimliği küçük harf ve kısa çizgiyle; her mesaj
eklenti.ön ekli. - Tüm girdi/çıktı tipleri
deny_unknown_fields; sınırlar şemada açık;int64içinPluginI64. - Karar fonksiyonu saf (I/O, saat, rastgelelik yok); kalıcı sonuç dispatcher’ın planında.
- Komutlar idempotent ve makbuz süreleri tanımlı; sorgular salt-okunur ve erişimi (
player,server,public) açık. - Artifact, depodaki JSON,
release-lock.jsonve üretilmiş bağlama aynı değişiklikte güncellendi. - Kayıt
bin/crx-api(gerekirsebin/crx-worker) içinde yapıldı; açılışfreezeile geçiyor. - Yayın sırası uygulandı: drain, ikili, yetkiyi yeni sürüme geçirme, istemci.
- Ortam yetkisi açık ve durumu doğru.
Sık yapılan hatalar
| Hata | Belirti | Doğrusu |
|---|---|---|
| Sürüm artırıldı, yetki geçirilmedi | Eklenti ve gerçek zamanlı çağrılar 403 forbidden, şema ucu 404 | Drain, ikili, sonra Sürüme geç |
| Şema değişti, artifact/pin yenilenmedi | Artifact tam eşleşme testi kırmızı; istemcide schemaSha256 uyuşmazlığı | Artifact’ı Rust’tan yeniden üretin; release lock ve bağlamayı aynı değişiklikte güncelleyin |
| Belirsiz sonuçlu komut yeni anahtarla tekrar gönderildi | Aynı işlem iki kez uygulanır | Aynı Idempotency-Key ve aynı gövde; emin değilseniz önce sonuç sorgusu (çağırma) |
int64 JSON sayısı olarak tanımlandı | Büyük değerlerde kayıp ya da kodek hatası | PluginI64; tel üzerinde ondalık metin |
decide içinde saat, rastgelelik veya ağ | Tekrar oynatma farklı sonuç verir | Zaman ve tohum host bağlamından gelir; kalıcı etki dispatcher planında |
| Ekonomik sonuç gerçek zamanlı reducer’da | Redis kaybında sonuç kaybolur | Kalıcı sonuç komut yoluna |
| Artifact’ta olmayan ya da fazla mesaj | Açılış freeze/kayıt hatası | Manifest ve artifact aynı Rust kaynağından türesin |
| Komut için istemci API anahtarı | 401 | Oyuncu oturumu ya da sunucu anahtarı |
| Ayrı dispatcher bağlanmadan komut eklendi | Komut yönlendirilemez | Dispatcher yazın ve bileşim kökünde bağlayın |
Bilinen sınırlar
- Üçüncü taraf eklenti yüklemek, sandbox’lı çalıştırma ve imzalı dağıtım yoktur.
- Depo dışında (out-of-tree) eklenti yazmak için ayrı bir SDK yoktur; eklenti, Open Play depo ağacındaki bir crate’tir.
- Yeni eklenti iskeleti (scaffold) üreten bir komut yoktur; kalıp, mevcut küçük eklentilerden kopyalanır.
- Komutu olan eklentiler için dispatcher bağlaması elle yapılır.
Sıradaki adım
- Eklentiyi çağırmak için eklentileri çağırma.
- İstemci bağlaması ve şema sürümü sabitleme için bağlamalar.
- Ortamda açıp sürüm değiştirmek için panel: Eklentiler.
Eklentileri çağırma
Bu sayfa, bir eklentinin komut ve sorgularını HTTP ile nasıl çağıracağınızı anlatır: başlıklar, sürüm denetimi, tekrar güvenliği, sonuç sorgusu ve hata zarfı. SDK kullanıyorsanız çoğunu SDK sizin yerinize yapar; yine de ne olduğunu bilmek hata ayıklamayı kolaylaştırır.
Not
Eklentiler için ortak bir
/openapi.jsonyoktur; eklentinin kendi şema belgesi (artifact)GET /v1/plugins/{plugin_id}/schemaucundan alınır. Kullanabileceğiniz işlemlerin listesi oradadır (bağlamalar).
Uçlar
| Yöntem ve yol | Amaç |
|---|---|
POST /v1/plugins/{plugin_id}/commands/{message_type} | Komutu çalıştırır |
GET /v1/plugins/{plugin_id}/commands/{message_type}/result | Komutun sonucunu idempotency anahtarıyla sorgular |
GET /v1/plugins/{plugin_id}/queries/{message_type} | Sorguyu çalıştırır (parametreler sorgu dizesinde) |
POST /v1/plugins/{plugin_id}/queries/{message_type} | Sorguyu çalıştırır (parametreler gövdede) |
GET /v1/plugins/{plugin_id}/schema | Eklentinin şema belgesini verir |
{plugin_id} eklenti kimliğidir (ör. package-ride). {message_type} işlemin istek mesaj türüdür (ör. package-ride.progression-missions.login-bonus.input); işlemin adı (claimLoginBonus) değildir. Tam yol ve mesaj türü şema belgesindeki her işlemin path ve requestMessageType alanında yazar. Hangi yöntemin (GET ya da POST) kullanılacağını da işlemin method alanı söyler: bazı sunucu sorguları POST ile çağrılır.
Kimlik
| Çağıran | Gönderilecek |
|---|---|
| Oyuncu (çerez) | Cookie (__Secure-crx.session) + x-crx-env: <ortam uuid>; değiştirici (POST) isteklerde ayrıca x-csrf-token + __Secure-crx.csrf çerezi |
| Oyuncu (Bearer) | Authorization: Bearer <oturum jetonu> + x-crx-env: <ortam uuid>. Eklenti ucu değiştirici isteklerde Bearer ile de CSRF çiftini (__Secure-crx.csrf çerezi + x-csrf-token) ister; çerezsiz istemci çifti GET /v1/auth/csrf ile alıp kendisi taşır (oturumlar ve CSRF) |
| Sunucu | Authorization: Bearer crx_live_<önek>_<gizli> (sunucu anahtarı). x-crx-env gönderirseniz anahtarın ortamıyla aynı olmalı, aksi halde 401. CSRF ve Origin denetimi uygulanmaz |
| Herkese açık sorgu | Yalnız x-crx-env; yalnız GET ve yalnız şema belgesinde access: public olan sorgular |
crx_ ile başlayan ama sunucu türünde olmayan (istemci) anahtar 401 unauthorized alır. Oyuncu isteklerinde Origin başlığı varsa ortamın izinli kökenlerinden biri olmalıdır (tarayıcı kendisi ekler); aksi halde 403 forbidden. Değiştirici bir çağrı başarılı olduğunda yanıt yeni CSRF çiftini (Set-Cookie ve x-csrf-token başlığı) döndürür; bir sonraki değiştirici istekte bunu kullanın.
Komut çağırma
POST /v1/plugins/package-ride/commands/package-ride.progression-missions.login-bonus.input HTTP/1.1
Host: oyun.example.com
Origin: https://oyun.example.com
Cookie: __Secure-crx.session=<oturum>; __Secure-crx.csrf=<csrf-çerezi>
x-crx-env: 0192a3b4-0000-7000-8000-000000000001
x-csrf-token: <csrf-jetonu>
x-crx-schema-version: 1
Idempotency-Key: 5d1f2c88-4f0b-4c8f-9f1e-9a3f6b0c1d22
If-Match: "3"
Content-Type: application/json
{"expectedVersion":"3"}
HTTP/1.1 200 OK
Content-Type: application/json
x-crx-message-type: package-ride.progression-missions.login-bonus.output
x-crx-schema-version: 1
{"version":"4","rewardMinor":"250","streak":"2","day":"19300","walletBalanceMinor":"1250","claimEventId":"0192a3b4-0000-7000-8000-0000000000c1","ledgerCorrelationId":"0192a3b4-0000-7000-8000-0000000000c2"}
| Başlık | Zorunlu | Anlam |
|---|---|---|
Idempotency-Key | komutlarda evet | Mantıksal tekrar anahtarı; boş olamaz. Kurallar |
x-crx-schema-version | evet | Gönderdiğiniz yükün şema sürümü (pozitif tam sayı); işlemin schemaVersion değeriyle eşleşmelidir. Sorgularda da zorunludur |
If-Match | hayır | Beklenen kaynak sürümü (iyimser kilit, optimistic lock). Ondalık tam sayı, tırnaklı ya da tırnaksız; * ve W/ önekli değerler 400 alır. Gerçek sürüm farklıysa 409 |
Content-Type: application/json | evet | Gövde JSON’dur ve işlemin istek şemasına uyar |
Not
Gövde alanlarındaki
int64değerler ondalık metin olarak gider ("expectedVersion":"3"), JSON sayısı olarak değil; yanıt da aynı biçimdedir. Ayrıntı: sayılar ve kodlama.int32veuint32alanlar JSON sayısıdır.
Başarılı yanıtın gövdesi, işlemin yanıt şemasına uyan JSON’dur; x-crx-message-type ve x-crx-schema-version yanıt başlıkları çıktı mesajını belirtir.
Aynı anahtarla tekrar
Ağ koparsa ya da yanıtı alamazsanız aynı Idempotency-Key ve aynı gövdeyle tekrar gönderin; sunucu işlemi ikinci kez uygulamaz, kayıtlı sonucu döner.
| Durum | Yanıt |
|---|---|
| İlk istek | İşlenir, 200 |
| Aynı anahtar, aynı gövde | Kayıtlı sonuç döner |
| Aynı anahtar, farklı gövde | 422 ve idempotency_mismatch |
| Aynı anahtarlı istek hâlâ işleniyor | 409 ve idempotency_in_flight (retryable: true); biraz sonra tekrar deneyin |
Kayıt süresi doldu (işlemin receiptRetentionSeconds değeri, örnekte 86 400 sn) | 410 ve idempotency_expired |
Yeni bir anahtar üretmek yeni bir işlem demektir; belirsiz sonuçlu bir komutu yeni anahtarla yeniden göndermeyin.
Sonuç sorgusu
Yanıtı hiç alamadığınız bir komutun sonucunu, tekrar göndermeden öğrenin:
GET /v1/plugins/package-ride/commands/package-ride.progression-missions.login-bonus.input/result?idempotency_key=5d1f2c88-4f0b-4c8f-9f1e-9a3f6b0c1d22&output_message_type=package-ride.progression-missions.login-bonus.output&output_schema_version=1 HTTP/1.1
x-crx-env: 0192a3b4-0000-7000-8000-000000000001
Cookie: __Secure-crx.session=<oturum>
Üç sorgu parametresi de zorunludur: idempotency_key, output_message_type ve output_schema_version. Yol, işlemin resultPath alanıyla aynıdır.
| Yanıt | Anlam | Ne yapmalı |
|---|---|---|
200 + gövde | Komut kesinleşmişti; gövde çıktıdır | Sonucu kullanın |
202 (boş gövde) | Henüz işleniyor | Kısa süre sonra tekrar sorgulayın |
404 | Bu anahtarla kayıt yok: komut hiç uygulanmamış | Yalnız bu durumda aynı anahtar ve gövdeyle komutu gönderebilirsiniz |
422 + reason | Komut işlendi ve iş kuralı tarafından reddedildi | Gönderme; reason makine kodudur |
410 | Kayıt süresi doldu | Sonuç bilinmiyor; durumu sorguyla yeniden okuyun |
Sorgu çağırma
GET ile parametreler sorgu dizesinde gider. Her değer önce JSON olarak ayrıştırılır; olmazsa metin sayılır; null değeri null olur. Aynı parametreyi iki kez vermek 400 alır.
GET /v1/plugins/package-ride/queries/package-ride.delivery-trip.active.input HTTP/1.1
x-crx-env: 0192a3b4-0000-7000-8000-000000000001
x-crx-schema-version: 1
Cookie: __Secure-crx.session=<oturum>
POST ile aynı alanlar JSON gövdesinde gider. Karmaşık ya da uzun girdiler için POST uygundur; hangi yöntemin geçerli olduğunu işlemin method alanından okuyun. Herkese açık sorgu örneği:
GET /v1/plugins/package-ride/queries/package-ride.world-catalog.get.input HTTP/1.1
x-crx-env: 0192a3b4-0000-7000-8000-000000000001
x-crx-schema-version: 1
Şema ucu
GET /v1/plugins/{plugin_id}/schema eklentinin şema belgesini (JSON) verir (Cache-Control: no-store). Oyuncu oturumu ya da sunucu anahtarı gerekir. Eklenti ortamınız için etkin değilse ya da grant sürümü uyuşmuyorsa 404’tür. Belgenin alanlarını ve schemaSha256 değerinin kullanımını bağlamalar sayfasında bulursunuz.
Hata zarfı
Eklenti uçları JSON hata zarfı döner (çekirdek REST uçlarının düz metin hatalarından farklı olarak; karşılaştırma için hatalar):
{"code":"conflict","message":"version conflict: expected 3, actual 5","retryable":false,"requestId":"0192a3b4-0000-7000-8000-0000000000d1"}
Yanıtta ayrıca x-request-id başlığı bulunur; destek talebinde bu kimliği iletin.
code | HTTP | retryable | Ne zaman |
|---|---|---|---|
unauthorized | 401 | hayır | Oturum/anahtar yok, geçersiz, istemci anahtarı ya da ortam uyuşmazlığı |
forbidden | 403 | hayır | CSRF ya da Origin reddi; eklenti etkin değil ya da sürüm uyuşmuyor; yasaklı hesap (message: account banned) |
module_disabled | 404 | hayır | plugins modülü kapalı (module alanı modül adını taşır) |
not_found | 404 | hayır | Bilinmeyen eklenti ya da mesaj türü; kayıt yok |
invalid_argument | 400 | hayır | Eksik/bozuk başlık, bilinmeyen şema sürümü, şemaya uymayan yük, kopya sorgu parametresi |
conflict | 409 | hayır | If-Match sürümü gerçekle uyuşmuyor |
idempotency_in_flight | 409 | evet | Aynı anahtarlı istek hâlâ işleniyor |
idempotency_mismatch | 422 | hayır | Aynı anahtar, farklı gövde |
unprocessable | 422 | hayır | İş kuralı reddi; reason alanı makine kodunu taşır |
idempotency_expired | 410 | hayır | Kayıt süresi doldu |
rate_limited | 429 | evet | Oran sınırı; Retry-After: 60 (hız sınırları) |
tenant_unavailable | 503 | evet | Ortamın yerleşimi geçici kullanılamıyor; Retry-After: 30 |
internal | 500 | evet | Sunucu hatası |
reason alanı yalnız iş kuralı reddinde (unprocessable) bulunur (ör. street_reset_too_early) ve eklentiye özgüdür; anlamı eklentinin belgesindedir. Sürüm uyuşmazlığında (conflict) mesaj beklenen ve gerçek sürümü içerir: durumu yeniden okuyup yeni sürümle tekrar deneyin.
Uyarı
Eklenti uçlarında yasaklı hesap
account_bannedkoduyla gelmez:403vecode: "forbidden",message: "account banned"döner.account_bannedkodu oyuncu kimlik uçlarına (giriş, kayıt) aittir (hatalar). İstemciniz bu iki durumu ayırt edecekse mesaja değil oturum durumuna bakın.
Örnek: komutu belirsiz sonuca karşı güvenle çağırmak
Aşağıdaki TypeScript örneği, SDK bağlamasıyla komutu hazırlar (tek Idempotency-Key üretilir), gönderir; sonuç belirsizse yeni komut üretmeden sonucu sorgular ve yalnız notFound yanıtında aynı anahtarla yeniden gönderir. demo-game eklentisi bu örnek için hazırlanmış bir kurgudur: gerçek eklentinizde işlem adlarını ve alanları kendi şema belgenizden alırsınız (bağlamalar).
import { CrxError, ErrorKind, type PlayerClient } from "@ferdiunal/open-play-ts";
import { DemoGameBinding } from "./generated/demo-game.js";
/**
* Günlük hediyeyi alır. `prepare` tek `Idempotency-Key` üretir; ağ hatasında sonuç belirsizse yeni komut üretilmez:
* önce sonuç sorgulanır, yalnız "kayıt yok" yanıtında AYNI anahtarla yeniden gönderilir.
*/
export async function claimDailyGift(client: PlayerClient, expectedVersion: bigint): Promise<bigint> {
const demo = client.plugin(DemoGameBinding);
const command = await demo.commands.claimDailyGift.prepare({ giftKey: "daily" }, { expectedVersion });
try {
const output = await command.send();
return output.walletBalanceMinor; // int64 alanlar bigint gelir
} catch (error) {
if (!(error instanceof CrxError) || error.kind !== ErrorKind.UnknownOutcome) throw error;
const outcome = await command.lookup();
if (outcome.status === "committed") return outcome.result.walletBalanceMinor;
if (outcome.status === "notFound") return (await command.resume()).walletBalanceMinor; // aynı anahtar, aynı gövde
throw error; // pending, rejected ya da expired: kör tekrar yok
}
}
/** Salt-okunur sorgu: tekrar güvenlidir, anahtar gerekmez. */
export async function hasClaimedToday(client: PlayerClient): Promise<boolean> {
const demo = client.plugin(DemoGameBinding);
const status = await demo.queries.getGiftStatus({ includeHistory: false });
return status.claimedToday;
}
Sıradaki adım
- Tipli istemci ve şema sabitleme: bağlamalar.
- Tekrar güvenliği ve sürüm denetimi kuralları: idempotency ve eşzamanlılık.
Bağlamalar ve şema sabitleme
Bu sayfa, bir eklentinin şema belgesinden (artifact) tipli istemci kodu üretmeyi ve istemcinizin hangi şema sürümüyle derlendiğini sabitlemeyi (pin) anlatır. Sabitleme sayesinde sunucu eklentiyi güncellediğinde istemciniz sessizce yanlış alanlarla konuşmak yerine uyuşmazlığı fark eder.
Şema belgesi ne içerir
GET /v1/plugins/{plugin_id}/schema ya da depodaki artifacts/plugins/<id>.plugin.schema.json aynı belgedir. Üst düzey alanlar:
| Alan | Anlam |
|---|---|
pluginId | Eklenti kimliği (ör. package-ride) |
version | Eklenti sürümü (ör. 1.44.0) |
schemaSha256 | schemas bölümünün özeti; şema sabitleme anahtarı (aşağıda) |
protocolVersion | Eklenti protokol ana sürümü (şimdilik 1) |
codecProfile | Tel kodlaması: plugin-v1-decimal-int64 (sayılar) |
schemas | Girdi ve çıktı JSON şemaları (bileşen adı → şema) |
queries, commands | İşlem tanımları |
modules | Realtime modülleri |
Bir işlem tanımı şu alanları taşır:
| Alan | Anlam |
|---|---|
name | İşlem adı; istemci kodunda yöntem adıdır (ör. claimLoginBonus) |
kind, method, path | command ya da query; HTTP yöntemi; tam yol |
requestSchema, responseSchema, schemaVersion | Girdi ve çıktı şemaları ve gönderilecek x-crx-schema-version |
requestMessageType, responseMessageType | Yoldaki {message_type} ve çıktı mesaj türü |
access | player, server ya da public |
retry | read (güvenle tekrar), same-key-command (yalnız aynı anahtarla tekrar), never |
journal | none, full ya da reference: SDK’nın komutu yerelde nasıl kaydettiği (yeniden yüklemeden sonra devam için) |
idempotencyRequired, receiptRetentionSeconds, resultPath | Komutlar için: anahtar zorunluluğu, kayıt süresi, sonuç sorgu yolu |
deprecated | Varsa kullanımdan kalkma bilgisi: since, sinceUnixS, replacement (sürümleme) |
Realtime modülü tanımı moduleId, input, state, events, signals, authorityMode, deliveryClass, interestPolicy, stateTtlMs ve sequencePolicy taşır; girdi ve durum mesajlarında maxBytes, ratePerSecond ve burst bulunur (protokol).
schemaSha256 nedir
schemaSha256, belgedeki schemas nesnesinin kurallı JSON (anahtarlar sıralı, boşluksuz, UTF-8) çıktısının SHA-256 özetidir (küçük harfli onaltılık, 64 karakter). Şema alanları değişirse özet değişir; sürüm numarası aynı kalsa bile. Bu yüzden “sürüm eşleşiyor” demek yetmez: özet eşleşmelidir.
Özeti kendiniz de yeniden hesaplayıp doğrulayabilirsiniz:
import { createHash } from "node:crypto";
type Json = null | boolean | number | string | Json[] | { [key: string]: Json };
/** Anahtarları özyinelemeli sıralar; sunucudaki kurallı JSON biçimiyle aynı baytları üretir (boşluksuz). */
function canonical(value: Json): Json {
if (Array.isArray(value)) return value.map(canonical);
if (value !== null && typeof value === "object") {
const sorted: { [key: string]: Json } = {};
for (const key of Object.keys(value).sort()) sorted[key] = canonical(value[key] as Json);
return sorted;
}
return value;
}
/** Şema belgesinin `schemas` bölümünden `schemaSha256` değerini yeniden hesaplar. */
export function schemaSha256(artifact: { schemas: Record<string, Json> }): string {
return createHash("sha256").update(JSON.stringify(canonical(artifact.schemas)), "utf8").digest("hex");
}
/** Belgenin kendi bildirdiği özet, içeriğiyle uyuşuyor mu? */
export function artifactIsConsistent(artifact: { schemaSha256: string; schemas: Record<string, Json> }): boolean {
return schemaSha256(artifact) === artifact.schemaSha256;
}
Not
Bu hesap yalnız
schemasbölümünü kapsar; işlem listesini (commands,queries) ya daversionalanını kapsamaz. Bir işlemin yolu ya da erişim türü değişirse özet değişmeyebilir; bu yüzden bağlamayı yeniden üretirken belgenin tamamının farkına da bakın.
TypeScript bağlaması üretme
- Şema belgesini alın ve bir dosyaya kaydedin. Sunucudan: oyuncu oturumuyla ya da sunucu anahtarıyla
GET /v1/plugins/{plugin_id}/schema. - Özeti belgeden okuyun (
schemaSha256) ve release manifestinize/CI’ya yazın: bu sizin sabitleme değerinizdir. - SDK’nın
crxkomutuyla bağlamayı üretin:
npx crx plugins generate \
--input demo-game.plugin.schema.json \
--schema-sha256 ffc38829f30ea0dd1b829f351f905854a9875806fbc8a2bbd591815c7ee52c2f \
--output src/generated/demo-game.ts
- CI’da üretilmiş dosyanın güncel olduğunu denetleyin;
--checkdosyayı yazmaz, byte karşılaştırır:
npx crx plugins generate --input demo-game.plugin.schema.json \
--schema-sha256 ffc38829f30ea0dd1b829f351f905854a9875806fbc8a2bbd591815c7ee52c2f \
--output src/generated/demo-game.ts --check
Davranış:
- Girdi belgesi yerel dosyadır; komut ağa çıkmaz ve belgeyi yürütmez.
--schema-sha256zorunludur ve belgedekischemaSha256ile aynı olmalıdır; farklıysa üretim reddedilir. Özet otomatik yenilenmez: değişikliği bilinçli onaylarsınız.- Çıktı yalnız yeni dosya yazar; var olan dosyayı ezmez (üretimi yenilemek için dosyayı silin). Çıktı klasörü önceden var olmalı ve yolu sembolik bağ içermemelidir (komut yolu gerçek yoluyla karşılaştırır); sembolik bağ ve özel dosya reddedilir; hedef
.tsolmalıdır. Girdi dosyası en çok 2 MiB olabilir. - Başarıda
CRX PLUGINS GENERATE PASS(--checkileCRX PLUGINS CHECK PASS) yazar ve0ile çıkar. - Hata durumunda komut ayrıntı vermez (yol ve içerik sızmasın diye); tek satır
CRX TYPES FAIL: input/version/hash/output reddedildiyazar ve1ile çıkar. Önce girdi dosyasını, özeti ve çıktı yolunu kontrol edin. - Aynı girdi her zaman aynı bayt çıktısını verir.
Üretilen dosya, şemalardan TypeScript tiplerini (bigint olarak int64), işlem tablolarını, modül tanımlarını ve gömülü artifact + özeti taşır. Kullanım:
import { DemoGameBinding } from "./generated/demo-game.js";
const demo = client.plugin(DemoGameBinding);
await demo.queries.getGiftStatus({ includeHistory: true });
const handle = await demo.commands.claimDailyGift.prepare({ giftKey: "daily" });
access: "server" olan işlemler oyuncu istemcisinde görünmez ve çağrılamaz; bunları sunucunuzdan sunucu anahtarıyla HTTP ile çağırın (eklentileri çağırma). access: "public" sorgular game.publicPlugin(...) ile kimliksiz çağrılır.
Not
Komut tanımı
retry: "same-key-command"ise SDK ağ hatasında yalnız aynı anahtarla yeniden dener;journal: "full"ise sayfa yeniden yüklenince yarım kalan komut aynı anahtarla devam ettirilir. SDK kurulumu ve journal seçenekleri TypeScript SDK sayfasındadır.
Sabitleme (pin) ve uyuşmazlık
İstemci iki yerde sürüm uyumunu denetler:
- Derleme/başlatma zamanı, yerel:
createGameClientile bağlama kurarken oyununuzun release manifestindeki beklentiyi (pin) verirsiniz. Bağlama içindekipluginId,schemaSha256,protocolVersion,codecProfile(ve verdiysenizversion) beklentiyle birebir eşleşmezseCrxError(kind: upgrade_required,code: plugin_binding_mismatch) fırlatır; hiçbir istek gitmez. Bu denetim sunucuya sormaz; yalnız elinizdeki bağlamanın beklediğiniz bağlama olduğunu doğrular. - Sunucudaki gerçek belge: TypeScript SDK’sı çalışma zamanında
/schemaucunu kendiliğinden çağırmaz. Sunucu eklentiyi güncellediyse istemcinizin eski bağlamasıyla uyuşmazlığı görmek için belgeyi başlangıçta kendiniz sorgulayıp özeti karşılaştırın:
import { DemoGameBinding } from "./generated/demo-game.js";
/**
* Sunucudaki şema belgesini alır ve elinizdeki bağlamayla karşılaştırır. Uyuşmazsa istemciyi güncelleyin:
* yeni belgeyi alın, yeni `schemaSha256`'yı manifestinize yazın, bağlamayı yeniden üretin.
* Çerez oturumu açıkken tarayıcıda çalışır (aynı kökenden, `credentials: "include"`).
*/
export async function serverSchemaMatches(baseUrl: string, environmentId: string): Promise<boolean> {
const response = await fetch(`${baseUrl}/v1/plugins/${DemoGameBinding.pluginId}/schema`, {
credentials: "include",
headers: { "x-crx-env": environmentId },
});
if (!response.ok) throw new Error(`şema belgesi alınamadı: HTTP ${response.status}`);
const live = (await response.json()) as {
pluginId: string;
schemaSha256: string;
protocolVersion: number;
codecProfile: string;
};
return (
live.pluginId === DemoGameBinding.pluginId &&
live.schemaSha256 === DemoGameBinding.schemaSha256 &&
live.protocolVersion === DemoGameBinding.protocolVersion &&
live.codecProfile === DemoGameBinding.codecProfile
);
}
Unity SDK’sında bu denetim hazırdır: PluginClient.VerifyServerSchemaAsync() sunucunun belgesini alır ve pluginId, schemaSha256, protocolVersion, codecProfile (ve pin’de verilmişse version) alanlarını bağlamanın pin’iyle karşılaştırır. Uyuşmazlıkta OpenPlayException (ErrorKind.UpgradeRequired, kod plugin_binding_mismatch) fırlatır; pin alanı yok ya da bozuksa ErrorKind.Contract.
using System.Threading.Tasks;
using OpenPlay;
using OpenPlay.PackageRide;
/// <summary>
/// Oyuna girerken sunucudaki eklenti şemasının, pakete gömülü bağlamayla aynı olduğunu doğrular.
/// Uyuşmazlıkta (<c>UpgradeRequired</c>, kod <c>plugin_binding_mismatch</c>) oyuncuyu güncellemeye yönlendirin.
/// </summary>
public static class PluginPinCheck
{
public static async Task<bool> ServerSchemaMatches(OpenPlayClient client)
{
var rides = PackageRideClient.Create(client); // pin: pluginId, schemaSha256, protocolVersion, codecProfile, version
try
{
await rides.Plugin.VerifyServerSchemaAsync(); // GET /v1/plugins/package-ride/schema; yalnız pin alanlarını okur
return true;
}
catch (OpenPlayException ex) when (ex.Kind == ErrorKind.UpgradeRequired)
{
UnityEngine.Debug.LogWarning("Eklenti şeması değişti; istemciyi güncelleyin: " + ex.Code);
return false;
}
}
}
Uyuşmazlık olursa istemci ne görür
Sunucu eklentiyi güncelleyip istemciniz eski bağlamayla çağırırsa:
| Değişiklik | İstemci görür |
|---|---|
İşlemin schemaVersion değeri arttı | 400 invalid_argument (bilinmeyen şema sürümü). x-crx-schema-version eskiyi gönderiyordu |
| İşlem ya da mesaj türü kalktı | 404 not_found |
| Girdi şemasına zorunlu alan eklendi | 400 invalid_argument (şemaya uymayan yük) |
| Çıktı şeması değişti | SDK yanıtı bağlamaya göre çözemez; contract türünde hata |
| Eklenti ortamınız için etkin değil / sürüm yetkisi uyuşmuyor | 403 forbidden |
Çözüm hep aynıdır: güncel şema belgesini alın, bilinçli olarak yeni schemaSha256’yı manifestinize yazın, bağlamayı yeniden üretin ve istemciyi yayınlayın. Eski istemcilerin bir süre daha çalışması gerekiyorsa sunucuda eski şema sürümünün korunup korunmadığını eklenti sağlayıcınıza sorun; bunun garantisi platformda yoktur.
Unity bağlaması
Unity SDK’sında bağlama yalnız package-ride eklentisi için hazır gelir (OpenPlay.PackageRide: PackageRideBinding, PackageRideClient). Başka bir eklenti için Unity bağlaması bugün üretilemez: SDK’nın üretici betiği depo içi bir araçtır ve yayımlanan pakette gelmez. Üretici yalnız access değeri player ya da public olan işlemleri paketler (sunucuya özel işlem pakete girmez) ve yalnız plugin-v1-decimal-int64 kodlamasını kabul eder; int64 alanlar C# long olur.
Kullanım için Unity SDK sayfasındaki PluginCall örneğine bakın.
Sıradaki adım
- Sürüm kavramlarının tamamı (protokol, şema, kullanımdan kalkma): sürümleme.
- Sayı kodlaması: sayılar ve kodlama.
Hata referansı
Bu sayfa, Open Play’in döndürdüğü her hata türünü, durum kodunu ve gövde biçimini listeler. Hata yönetimi kodu yazarken önce hangi uç ailesinin (çekirdek REST mi, eklenti mi) çağrıldığına bakın: iki ailenin hata gövdesi farklıdır.
Uyarı
Çekirdek REST uçlarının çoğu düz metin (
text/plain) hata döner, JSON değil. Yalnız bu sayfada “JSON” diye işaretlenen birkaç hata JSON zarfı taşır. Hata metnini ayrıştırmayın; durum koduna ve (varsa) JSONcodealanına göre karar verin. Düz metin mesajlar sürümler arasında değişebilir.
Hata aileleri
| Aile | Hangi uçlar | Gövde |
|---|---|---|
| Çekirdek REST | /v1/characters…, /v1/wallets…, /v1/store…, /v1/auth/… vb. (uç noktalar) | Düz metin; birkaç hata JSON {code, message[, module]} |
| Eklenti | /v1/plugins/… | Her zaman JSON {code, message, retryable, requestId[, reason, module]} + x-request-id başlığı |
| Realtime | /v1/realtime/ws | Error çerçevesi: {type, requestId?, code, retryable} (protokol) |
| Sohbet soketi | /v1/chat/ws | {"type":"error","code":"…"} (realtime genel bakış) |
Çekirdek REST: durum tablosu
| Durum | Gövde (düz metin, aksi belirtilmedikçe) | Ne zaman | Yeniden dene? |
|---|---|---|---|
400 | Hatanın açıklaması | Eksik ya da bozuk başlık, geçersiz alan, bilinmeyen komut türü, If-Match biçimi | Hayır; isteği düzeltin |
401 | unauthorized | API anahtarı ya da oyuncu oturumu yok, geçersiz, süresi dolmuş; x-crx-env yok ya da bozuk; yasaklı hesap (ayrım yapılmaz) | Hayır; kimliği yenileyin |
403 | permission denied | Anahtar türü yetmiyor (ör. istemci anahtarıyla sunucu ucu), CSRF ya da Origin reddi | Hayır |
403 | JSON {"code":"account_banned","message":"account banned"} | Giriş uçlarında, sahiplik kanıtlandıktan sonra yasaklı hesap | Hayır; döngü kurmayın |
404 | not found | Kaynak yok ya da silinmiş | Hayır |
404 | JSON {"code":"module_disabled","message":"module disabled","module":"store"} | Ürün modülü ortamda kapalı | Hayır; modülü açın (modüller) |
409 | version conflict: expected 3, actual 5 | If-Match sürümü gerçekle uyuşmuyor | Durumu yeniden okuyup yeni sürümle tekrar edin |
409 | already exists: <kaynak> | Aynı kimlik/anahtarla kaynak zaten var | Hayır |
409 | idempotent request in progress | Aynı Idempotency-Key ile ilk istek hâlâ işleniyor | Evet, kısa süre sonra aynı anahtarla |
410 | idempotent request result expired | Anahtarın kayıt süresi (24 saat) doldu | Yeni anahtarla, durumu önce okuyarak |
413 | Gövdesiz | İstek gövdesi 2 MiB sınırını aştı (görsel yükleme ucu kendi sınırına tabidir) | Hayır |
422 | idempotency mismatch | Aynı anahtar, farklı içerik | Hayır; anahtarı yeniden kullanmayın |
422 | unprocessable: <neden> | İş kuralı reddi (yetersiz bakiye, stok, limit…) | Hayır; durumu değiştirmeden tekrar etmeyin |
422 | rejected: <kod> | Eklenti iş kuralı reddi (çekirdek rotalar üzerinden) | Hayır |
429 | rate limited ya da rule budget exceeded: <kural> | Oran sınırı ya da kural bütçesi | Evet, bekleyerek (hız sınırları); Retry-After yoktur |
500 | internal error | Beklenmeyen sunucu hatası; ayrıntı sızdırılmaz | Evet, sınırlı |
503 | tenant unavailable; başlık Retry-After: 30 | Ortamın yerleşimi taşınıyor ya da geçici kullanılamıyor | Evet, Retry-After sonra |
Notlar:
- Gövde ayrıştırma hatalarında çıkarıcıya göre
415(yanlışContent-Type) ya da422(şemaya uymayan JSON) da görülebilir. Karar için yalnız durum koduna güvenin. 401ve403farkı: kimlik yok ya da çözümlenemiyorsa401; kimlik geçerli ama bu işleme yetmiyorsa403. Oyuncu bilet ucunda tüm kimlik hataları403döner (realtime protokolü).- İstemci anahtarıyla bir sunucu ucunu çağırırsanız
403 permission deniedalırsınız; anahtarın bilinmemesi ise401’dir.
Satın alma (POST /v1/player/store/listings/{listing_id}/buy) hata kodları
Oyuncu satın alma ucu, ret nedenini JSON code ile söyler: {"code":"out_of_stock","message":"…"} (message ayrıntı metnidir, kararınızı code’a göre verin).
code | Durum | Anlam |
|---|---|---|
not_visible | 404 | İlan yok ya da bu oyuncuya görünmüyor |
listing_changed | 409 | İlanın sürümü (expected_version) değişti; kataloğu yenileyip yeniden gösterin |
out_of_stock | 422 | Stok bitti |
limit_reached | 422 | Oyuncu başına satın alma sınırı doldu |
insufficient_funds | 422 | Bakiye yetmiyor |
inventory_full | 422 | Envanter dolu |
Bunun dışındaki hatalar (400 başlık/gövde, 401, 403 Origin ya da CSRF, idempotency uyuşmazlığı 422) yukarıdaki genel tablodaki gibidir. IAP ilanı bu uçtan alınamaz (422). Ayrıntı: mağaza rehberi.
Eklenti uçları
Eklenti uçları JSON zarf döner; requestId değerini destek taleplerinde iletin (aynı değer x-request-id başlığında da bulunur).
{"code":"unprocessable","message":"plugin command rejected","retryable":false,"requestId":"0192a3b4-0000-7000-8000-0000000000d1","reason":"street_reset_too_early"}
code | Durum | retryable | Not |
|---|---|---|---|
unauthorized | 401 | hayır | Oturum/anahtar yok ya da geçersiz; istemci anahtarı |
forbidden | 403 | hayır | CSRF/Origin reddi; eklenti etkin değil; sürüm yetkisi uyuşmuyor; yasaklı hesap (message: account banned) |
module_disabled | 404 | hayır | module alanı kapalı modülü söyler |
not_found | 404 | hayır | Bilinmeyen eklenti ya da mesaj türü |
invalid_argument | 400 | hayır | Bozuk/eksik başlık, bilinmeyen şema sürümü, şemaya uymayan yük |
conflict | 409 | hayır | If-Match sürümü uyuşmuyor |
idempotency_in_flight | 409 | evet | Aynı anahtarlı istek işleniyor |
idempotency_mismatch | 422 | hayır | Aynı anahtar, farklı gövde |
unprocessable | 422 | hayır | İş kuralı reddi; reason eklentiye özgü makine kodudur |
idempotency_expired | 410 | hayır | Kayıt süresi doldu |
rate_limited | 429 | evet | Retry-After: 60 |
tenant_unavailable | 503 | evet | Retry-After: 30 |
internal | 500 | evet |
Ayrıntı ve örnekler: eklentileri çağırma.
Not
Eklenti ucunda yasaklı hesap, çekirdek kimlik uçlarının aksine
account_bannedkoduyla gelmez:403,forbiddenvemessage: "account banned"döner. Bu ayrıma yalnız bir kullanıcı arayüzü mesajı için ihtiyaç duyarsınız; yeniden deneme döngüsü kurmayın.
Çekirdek ile eklenti arasındaki farklar
| Çekirdek REST | Eklenti | |
|---|---|---|
| Gövde | Düz metin (birkaç JSON istisna) | Daima JSON |
| Makine kodu | Yalnız JSON olan hatalarda | Her hatada code |
retryable | Yok; durum koduna göre karar verin | Var |
| Yeniden deneme süresi | Yalnız 503 (30 sn) | 429 (60 sn) ve 503 (30 sn) |
| Yasaklı hesap | 403 account_banned (giriş uçlarında) | 403 forbidden |
x-request-id | Yok | Var |
Hata işleme önerisi
- Önce durum koduna bakın;
401oturumu yenileyin ya da yeniden giriş yaptırın,403yetki ya da yapılandırma sorunudur (anahtar türü, CSRF, modül, eklenti durumu). 404için gövdeyi okuyun: JSON vemodule_disabledise modül kapalıdır, yoksa kaynak yoktur.409’u iki ayrı biçimde ele alın: sürüm çakışması (durumu yeniden okuyun) ile idempotency “işleniyor” (bekleyip aynı anahtarla tekrar edin).429ve503’te üstel geri çekilme kullanın;Retry-Aftervarsa onu bekleyin (idempotency ve eşzamanlılık sayfasındaki örnek).422iş kuralı reddidir; aynı isteği olduğu gibi tekrarlamak sonuç değiştirmez.- Sunucu hata ayrıntısı sızdırmaz; sorun bildirirken durum kodunu, istek zamanını ve (eklenti uçlarında)
requestId’yi iletin (sorun giderme).
Idempotency ve eşzamanlılık
Bu sayfa, ağ koptuğunda bir isteği iki kez uygulamadan nasıl tekrar edeceğinizi (idempotency, yani tekrar güvenliği) ve iki istemcinin aynı kaynağı aynı anda değiştirmesini iyimser sürüm denetimiyle (optimistic locking) nasıl yöneteceğinizi anlatır. Para, eşya ya da ödül veren her çağrıda bu iki kuralı kullanın.
Idempotency-Key
Değiştiren bir istek (POST, bazı PUT/PATCH/DELETE) Idempotency-Key başlığı taşıyabilir ya da taşımak zorundadır. Anahtarın kuralları:
| Kural | Değer |
|---|---|
| Uzunluk | 1 ile 200 karakter (boş olamaz) |
| Karakter kümesi | Boşluksuz yazdırılabilir ASCII (SDK yalnız bunu üretir ve kabul eder) |
| Önerilen değer | Rastgele UUID (v4); bazı uçlar UUID biçimini zorunlu kılar (klan, grup ve turnuva uçları: geçerli UUID olmalıdır) |
| Kapsam | Çekirdek komutlarda anahtar ortam genelinde benzersizdir: aynı ortamda iki farklı çağıran aynı anahtarı kullanırsa çakışır. Eklenti komutlarında anahtar eklenti ve çağıran (oyuncu ya da sunucu) başınadır. Bu yüzden her zaman rastgele UUID kullanın, oyuncu-1 gibi tahmin edilebilir değerler kullanmayın |
| Kayıt süresi | 24 saat (komut kayıtları); eklenti komutlarında işlemin receiptRetentionSeconds değeri (şimdilik 86 400 sn) |
Hangi uçta anahtarın zorunlu, hangisinde isteğe bağlı olduğunu uç nokta referansı gösterir. Örnek: karakter komutlarında isteğe bağlıdır, cüzdan aktarımında, envanter ve eşya işlemlerinde, ticarette, mağaza ve eklenti komutlarında zorunludur.
Anahtar nasıl çalışır
- İlk istek anahtarla gelir; sunucu işlemi uygular ve sonucu anahtara bağlı saklar.
- Aynı anahtar + aynı içerik tekrar gelirse işlem yeniden uygulanmaz; kayıtlı sonuç döner. Bazı yanıtlar bunu
replayed: truealanıyla bildirir (karakter komutları, mağaza satın alma). - Aynı anahtar + farklı içerik
422veidempotency mismatch(eklentideidempotency_mismatch) alır. - İlk istek hâlâ işleniyorsa ikincisi
409(idempotent request in progressya daidempotency_in_flight) alır; kısa süre sonra aynı anahtarla tekrar deneyin. - Kayıt süresi dolduysa
410döner. - Çekirdek komutlarda anahtar yalnız başarıda “yanar”: yetki reddi (ör. istemci anahtarıyla sunucu komutu), doğrulama hatası ya da geri alınan işlem anahtarı tüketmez; düzeltip aynı anahtarla tekrar gönderebilirsiniz.
Uyarı
Belirsiz sonuçlu bir isteği yeni anahtarla tekrarlamayın. Yeni anahtar yeni işlem demektir ve çift ödül, çift harcama yaratır. Anahtarı bir kez üretin, saklayın (istek ve yeniden denemeler boyunca aynı kalsın) ve gerekirse sonucu sorgulayın.
Ne zaman yeni anahtar üretilir
- Kullanıcı aynı işlemi bilerek yeniden başlattığında (ör. ikinci mağaza satın alması).
- İş kuralı reddinden (
422) sonra durumu değiştirip yeniden denediğinizde. 410(anahtar süresi doldu) sonrasında, durumu okuyup işlemin gerçekten uygulanmadığından emin olduktan sonra.
Örnek: güvenli yeniden deneme
Aşağıdaki yardımcı anahtarı bir kez üretir, ağ hatalarında ve 408, 429, 5xx yanıtlarında aynı anahtarla yeniden dener ve Retry-After süresini bekler:
/** `Retry-After` değerini milisaniyeye çevirir; saniye ya da HTTP tarihi olabilir, bilinmiyorsa `null`. */
function retryAfterMs(header: string | null): number | null {
if (header === null) return null;
if (/^\d+$/.test(header)) return Number(header) * 1000;
const date = Date.parse(header);
return Number.isNaN(date) ? null : Math.max(0, date - Date.now());
}
const RETRYABLE_STATUS = new Set([408, 429, 500, 502, 503, 504]);
/**
* Bir değiştirici isteği AYNI `Idempotency-Key` ile güvenle yeniden dener.
* Anahtarı bir kez üretin ve her denemede aynen gönderin; yeni anahtar yeni işlem demektir.
* 429 ve 503'te sunucunun `Retry-After` süresini bekler; yoksa üstel geri çekilme kullanır.
*/
export async function postWithRetry(url: string, body: unknown, headers: Record<string, string>, maxAttempts = 4): Promise<Response> {
const idempotencyKey = crypto.randomUUID();
let lastError: unknown;
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
let response: Response | undefined;
try {
response = await fetch(url, {
method: "POST",
credentials: "include",
headers: { ...headers, "content-type": "application/json", "idempotency-key": idempotencyKey },
body: JSON.stringify(body),
});
} catch (error) {
lastError = error; // ağ hatası: istek uygulanmış olabilir, aynı anahtarla tekrar güvenlidir
}
if (response !== undefined) {
if (!RETRYABLE_STATUS.has(response.status)) return response; // başarı ya da kalıcı hata
lastError = new Error(`HTTP ${response.status}`);
if (attempt === maxAttempts) return response;
const wait = retryAfterMs(response.headers.get("retry-after")) ?? Math.min(200 * 2 ** (attempt - 1), 5000);
await new Promise((resolve) => setTimeout(resolve, wait));
continue;
}
if (attempt < maxAttempts) await new Promise((resolve) => setTimeout(resolve, Math.min(200 * 2 ** (attempt - 1), 5000)));
}
throw lastError;
}
TypeScript SDK’sı bunu sizin yerinize yapar: CrxClient (sunucu anahtarı) GET isteklerini ve Idempotency-Key taşıyan istekleri 408, 429, 500, 502, 503, 504 durumlarında (varsayılan 2 deneme, maxRetries ile 0 ile 5 arası) üstel geri çekilmeyle ve Retry-After’a saygı göstererek yeniden dener. Eklenti komutlarında PlayerClient anahtarı hazırlama anında üretir ve tarayıcı günlüğüne (journal) yazar; sayfa yenilense bile aynı anahtarla devam eder (bağlamalar).
Sonucu sorgulama (eklenti komutları)
Eklenti komutu için yanıtı hiç alamadıysanız, tekrar göndermeden GET …/commands/{message_type}/result?idempotency_key=… ile sonucu sorgulayın. Yalnız 404 (kayıt yok) yanıtında aynı anahtarla yeniden gönderin (eklentileri çağırma). Çekirdek komutlarda ayrı bir sorgu ucu yoktur; aynı anahtar ve gövdeyle yeniden göndermek aynı kayıtlı sonucu döndürür.
İyimser sürüm denetimi
Sunucu, değiştirilebilir kaynaklara (karakter, envanter, eklenti kaynağı, mağaza ilanı) artan bir sürüm (version) tutar. İsteğinizde “şu sürümü görüp karar verdim” derseniz ve bu arada başkası kaynağı değiştirdiyse, istek uygulanmaz ve çakışma döner. Böylece iki istemci birbirinin değişikliğini sessizce ezmez.
| Kullanım yeri | Nasıl gönderilir |
|---|---|
Karakter komutları (POST /v1/characters/{id}/commands) | If-Match: 3 (tırnaklı "3" de kabul edilir) |
Envanter ve eşya işlemleri (If-Match destekleyen uçlar) | If-Match |
| Mağaza yönetim uçları (sayfa, ilan değişiklikleri) | If-Match (isteğe bağlı) |
| Eklenti komutları (HTTP) | If-Match: "12" |
Eklenti komutları (realtime Command çerçevesi) | expectedVersion: "12" (ondalık metin) |
Oyuncu satın alma (/v1/player/store/listings/{id}/buy) | If-Match kullanılmaz; ilan sürümü gövdedeki expected_version alanıdır (başlık gönderirseniz 400) |
If-Match biçimi: tam sayı sürüm numarası. * ve zayıf doğrulayıcılar (W/"3") reddedilir (400); negatif sayı ve sayısal olmayan değer 400 alır. Başlık verilmezse sürüm denetimi yapılmaz (son yazan kazanır); para ve eşya gibi kritik kaynaklarda göndermenizi öneririz.
Çakışma gelince
| Uç ailesi | Yanıt |
|---|---|
| Çekirdek REST | 409 ve version conflict: expected 3, actual 5 |
| Eklenti | 409 ve {"code":"conflict","message":"version conflict: expected 3, actual 5",…} |
| Mağaza oyuncu satın alma | 409 ve {"code":"listing_changed",…} |
| Realtime komutu | Error çerçevesi InvalidPayload (retryable: false); ayrıntı telden verilmez |
Çözüm döngüsü:
- Kaynağı yeniden okuyun (güncel
versionile). - Kullanıcının niyeti hâlâ geçerli mi karar verin (ör. hâlâ yeterli bakiye var mı).
- Yeni anahtarla (bu yeni bir deneme) güncel sürümle tekrar gönderin.
Not: sürüm çakışması iş kuralı değil, eşzamanlılık sonucudur; aynı isteği körlemesine tekrar göndermeniz yine çakışır. Idempotency anahtarı tekrar içindir, sürüm denetimi çakışma içindir; ikisini birlikte kullanabilirsiniz: aynı anahtar + aynı If-Match ile gönderilen tekrar kayıtlı sonucu döner.
Özet kural listesi
- Para, eşya, ödül ve komut gönderen her isteğe anahtar ekleyin; anahtarı bir kez üretin, yeniden denemelerde değiştirmeyin.
- Belirsiz sonucu sorgulayın ya da aynı anahtarla tekrarlayın; yeni anahtarla asla.
- Paylaşılan kaynak yazarken
If-Match/expectedVersiongönderin;409’da yeniden okuyun. 422iş kuralı reddidir; tekrar etmek sonuç değiştirmez.- Ayrıntılı hata tablosu için hata referansı.
Sayfalama
Bu sayfa, liste döndüren uçların sayfalarını nasıl gezeceğinizi anlatır. Open Play’de tek bir sayfalama biçimi yoktur: çoğu uç opak imleç (cursor) kullanır, birkaç uç ise farklı bir yöntem kullanır. Aşağıdaki tablo hangi uçta hangisinin geçerli olduğunu ve sayfa boyutu sınırlarını gösterir.
İmleç (keyset) sayfalama
Çekirdek liste uçlarının çoğu imleç tabanlıdır:
- İstek:
?limit=<n>&cursor=<imleç>. İlk sayfadacursorvermezsiniz. - Yanıt:
{"items":[…],"next_cursor":"…"}.next_cursornullise son sayfadasınız. - Sonraki sayfa:
cursorolarak bir önceki yanıttakinext_cursordeğerini aynen verin. - İmleç opaktır: içeriğini ayrıştırmayın, değiştirmeyin, saklayıp uzun süre sonra kullanmayı varsaymayın. Bozuk imleç
400alır. - Sıralama sabittir ve
OFFSETkullanılmaz; sayfalar arasında yeni kayıt eklenirse atlama ya da tekrar oluşmaz (kayıtlar sabit anahtara göre sıralanır). - Sayfa boyutu
limitile verilir; sınırların dışındaki değer çoğu uçta kısılır (hata vermez). İstisnalar tabloda belirtilmiştir.
GET /v1/characters?limit=2 HTTP/1.1
Authorization: Bearer crx_live_<önek>_<gizli>
{"items":[{"id":"…","definition":"hero","version":3}],"next_cursor":"<opak-imleç>"}
GET /v1/characters?limit=2&cursor=<opak-imleç> HTTP/1.1
Authorization: Bearer crx_live_<önek>_<gizli>
Uca göre biçimler
| Uç | Biçim | Varsayılan | Sınır |
|---|---|---|---|
GET /v1/characters | İmleç (definition süzgeci) | 50 | 1 ile 200 arası kısılır |
GET /v1/characters/{id}/events, …/timeline | İmleç (artan seq) | 50 | 1 ile 200 arası kısılır |
GET /v1/rules, GET /v1/webhooks | İmleç | 50 | 1 ile 200 arası kısılır |
GET /v1/ledger | İmleç (wallet_id zorunlu) | 50 | 1 ile 200 arası kısılır |
GET /v1/items, GET /v1/player/items | İmleç (owner ile) | 50 | 1 ile 200 arası kısılır |
GET /v1/assets | İmleç | 50 (0 ya da yok = varsayılan) | en çok 200 |
GET /v1/catalog/items, GET /v1/catalog/characters | İmleç | 50 | 1 ile 100 arası kısılır |
GET /v1/notifications | İmleç (status, limit, cursor) | 50 | 1 ile 100 arası kısılır |
GET /v1/leaderboards/{key}/entries | İmleç | 20 (0 ya da yok = varsayılan) | en çok 100; fazlası 400 (kısılmaz) |
GET /v1/leaderboards/{key}/around-me | Oyuncu çevresi (player_id, radius) | — | Sayfa yok; çevre pencereleri sınırlıdır |
GET /v1/player/leaderboards/{key} | Tek sayfa (limit) | 20 | 1 ile 50; dışı 400 |
GET /v1/chat/channels/{channel_id}/messages | Zaman tabanlı (before_ms + limit) | 50 | 1 ile 100 (service doğrular) |
GET /v1/quests | offset + limit (search süzgeci) | 20 (0 ya da yok = varsayılan) | limit en çok 100, offset en çok 100000; fazlası 400 |
GET /v1/auth/admin/list-players | İmleç (UUID) | uç varsayılanı | Uca özgü |
GET /v1/clans, GET /v1/parties | Sayfalama yok; tüm sonuç (parti için player_id süzgeci) | — | — |
GET /v1/wallets, GET /v1/inventories/{owner} | Sayfalama yok (sahibe göre tüm liste) | — | — |
Eklenti sorguları (/v1/plugins/…/queries/…) | Eklentiye özgü; girdi şemasında tanımlıdır | — | Eklentinin şema belgesi |
Not
Yanıtta imleç alanı çekirdek REST’te
next_cursor(yılan_harf) olarak gelir. Sohbet mesajlarında yeni sayfa için en eski mesajınsent_at_msdeğerinibefore_msolarak verirsiniz. Panel API’lerinin sayfalaması (offset/ızgara) panel arayüzünün iç kullanımıdır ve bu dokümanın kapsamında değildir.
SDK’da sayfalama
TypeScript SDK’sı imleçli listeler için yineleyiciler sunar: iterateListCharacterEvents, iterateGetCharacterTimeline, iterateListRules, iterateListWebhooks. Bu yineleyiciler next_cursor’ı sizin yerinize izler. Önemli kurallar:
- İmleç opaktır; yineleyici onu çevirmeden geri verir.
- Boş
next_cursordöngüyü bitirir; imleç döngüsü (aynı imlecin tekrar gelmesi) ya damaxPagesaşımı sessiz kesme değil,paginationtüründe hatadır. limittel üzerindeu32’dir; sunucu 1 ile 200 aralığına kısar.
Örüntüler
Hepsini gezmek (sunucudan sunucuya iş): imleç boş gelene kadar döngü kurun; her sayfada kısa bir üst sınır (ör. en çok 1000 sayfa) koyun.
cursor = yok
tekrarla:
sayfa = GET /v1/rules?limit=200[&cursor=cursor]
sayfa.items işlenir
cursor = sayfa.next_cursor
cursor boşsa dur
Oyun içi “daha fazla yükle” listesi: küçük limit (20 ile 50) kullanın, next_cursor’ı bellekte tutun, kullanıcı kaydırdıkça bir sonraki sayfayı isteyin. İmleci kalıcı saklamayın.
Tutarlılık: imleçli sayfalar canlı veriyi gezer; gezerken eklenen yeni kayıtlar, imlecin gerisinde kalıyorsa görünmeyebilir. Anlık görüntü gerektiren raporlar için sorgu zamanını (örneğin as of) kendi tarafınızda kaydedin.
İlgili: uç noktalar, hız sınırları.
Hız sınırları
Bu sayfa, Open Play’in bugün uyguladığı hız sınırlarını (rate limit) ve 429 aldığınızda ne yapacağınızı anlatır. Önemli bir dürüstlük notu: API anahtarı başına genel bir hız sınırı yoktur. Sınırlar belirli işlemlere (giriş, kayıt, sohbet, eklenti komutu, soket bağlantısı) konmuştur; geri kalan uçlar sınırsızdır ve yükü sizin yönetmeniz gerekir.
Bilinmesi gerekenler
- Genel bir “dakikada N istek” kotası yok. Sunucu anahtarıyla yapılan çağrılar için anahtar ya da ortam başına genel sınır bulunmaz.
- Sayaçlar Redis’te tutulur ve Redis’e ulaşılamazsa sınır uygulanmaz (fail-open); tek istisna, aşağıda belirtilen denetim satırı tavanıdır. Sınırı tek başına güvenlik kontrolü olarak kullanmayın.
Retry-Afterbaşlığı yalnız eklenti429’unda (60 sn) ve503yanıtlarında (30 sn) vardır. Çekirdek ve kimlik uçlarının429’uRetry-Aftertaşımaz; kendi geri çekilmenizi uygulayın.- İstemci IP’si, kimlik uçlarındaki sınırların anahtarıdır. Ters vekil istemci IP’sini iletmiyorsa tüm oyuncular aynı kovayı paylaşır (üretim kontrol listesi).
Kimlik uçları (oyuncu giriş hattı)
Bu sınırlar servis katmanında uygulanır; REST’in kendisinde de aynıdır. Pencere sabittir (ilk istekle başlar ve süre dolunca sayaç sıfırlanır; kayan pencere değildir); aşım 429 ve düz metin rate limited döner (Retry-After yok).
| Kova | Limit | Pencere | Anahtar | Hangi uçlar |
|---|---|---|---|---|
| Misafir açma | 30 | 60 sn | İstemci IP’si | POST /v1/auth/sign-in/guest (yeniden giriş de sayılır) |
| E-posta girişi | 5 | 60 sn | İstemci IP’si | POST /v1/auth/sign-in/email (her deneme) |
| Başarısız giriş kilidi | 10 | 900 sn | Adres + IP | Yanlış parola denemeleri; başarılı girişte hak iade edilir; parola değiştirmede yanlış mevcut parola da sayılır |
| Kayıt (IP) | 10 | 60 sn | İstemci IP’si | POST /v1/auth/sign-up/email, misafir terfisi |
| Kayıt (oturum) | 30 | 60 sn | Oturum sahibi | POST /v1/auth/guest/upgrade/email |
| Kayıt (adres) | 5 | 900 sn | E-posta adresi | Kayıt ve terfi |
| Parola değiştirme (IP) | 10 | 60 sn | İstemci IP’si | POST /v1/auth/change-password |
| Parola değiştirme (hesap) | 6 | 60 sn | Oyuncu | POST /v1/auth/change-password |
| Kurtarma (IP) | 5 | 60 sn | İstemci IP’si | forgot-password, reset-password, sign-in/magic-link (üç uç tek kovayı paylaşır) |
| Kurtarma (adres) | 5 | 900 sn | E-posta adresi | forgot-password, sign-in/magic-link |
| OAuth başlangıcı | 30 | 60 sn | İstemci IP’si | sign-in/oauth/{provider}, link/{provider} |
| OAuth dönüşü | 60 | 60 sn | İstemci IP’si | callback/{provider} |
Ek olarak:
| Sınır | Limit | Anahtar | Not |
|---|---|---|---|
| Görünen ad değiştirme | 10 / 3600 sn | Oyuncu | POST /v1/auth/session/display-name; aşım 429 |
| Hesap silme denemesi | 5 / 3600 sn | Oyuncu | POST /v1/auth/account/delete; aşım 429 |
| Başarısız giriş denetim satırı | 20 / 3600 sn | Hesap | Girişi reddetmez; yalnız arka plan denetim kaydını kısar. Redis kesintisinde kayıt atlanır (fail-closed) |
Not
Misafir açma kovası IP başınadır. Ters vekil istemci IP’sini iletmiyorsa ya da bir NAT/yurt ağı arkasından çok oyuncu bağlanıyorsa 30 misafir/dakika sınırı hızla dolar. Bir lansman ya da yük testi planlıyorsanız IP iletimini doğrulayın.
Sohbet ve bildirim
| Sınır | Limit | Pencere | Anahtar | Aşılınca |
|---|---|---|---|---|
| Sohbet mesajı gönderme | 20 | 10 sn | Ortam + oyuncu | REST’te 429; sohbet soketinde message_rejected |
| Bildirim teslimi | 60 | 60 sn | Ortam + oyuncu | Teslim ertelenir (sağlayıcıya inilmez), oyuncuya hata dönmez |
Eklenti komutları
Eklenti komut ve sorguları oyuncu başına, kova başına dakikalık bütçelere tabi olabilir. Bütçeyi eklenti tanımlar; sunucu bunu REST, realtime komutu ve gRPC yolunda aynı kararla uygular. Aşım eklenti zarfıyla gelir: 429, code: "rate_limited", retryable: true, Retry-After: 60.
Bugün bütçe tanımlayan eklenti package-ride’dır: 60 sn’lik pencerede kova başına 6 ile 60 komut (ör. teslimat kabul/başlatma/tamamlama 12, giriş bonusu 10, görev ödülü ve garaj 30, çarpışma/yarış bahsi 60). Kova değerleri eklentiye özgüdür ve değişebilir; kesin sayılar için eklentinin belgesine bakın. Operatör bazı kovaları “gözlem” kipine alabilir; bu kipte aşım yalnız sayılır, komut reddedilmez.
Unity SDK’sında PluginClient.RetryAfter(hata) eklenti 429’u için 60 saniye döndürür.
Realtime soket
| Sınır | Değer | Aşılınca |
|---|---|---|
| Adres başına yeni bağlantı | 30 / dakika | Yükseltme reddedilir |
| Adres başına açık soket | 8 | CapacityExceeded, soket kapanır |
| Oyuncu başına açık soket | 4 | CapacityExceeded, soket kapanır |
| Bağlantı başına çerçeve hızı | 40/sn (160 çerçevelik patlama payı) | CapacityExceeded (retryable: true), soket kapanır |
Ayrıntı: yeniden bağlanma ve limitler.
429 aldığınızda
HTTP/1.1 429 Too Many Requests
Content-Type: text/plain; charset=utf-8
rate limited
Eklenti ucunda:
HTTP/1.1 429 Too Many Requests
Content-Type: application/json
Retry-After: 60
x-request-id: 0192a3b4-0000-7000-8000-0000000000d1
{"code":"rate_limited","message":"rate limited","retryable":true,"requestId":"0192a3b4-0000-7000-8000-0000000000d1"}
Retry-Aftervarsa o kadar bekleyin; yoksa üstel geri çekilme kullanın (ör. 1, 2, 4, 8 sn; üst sınır 30 sn) ve rastgele bir sapma (jitter) ekleyin.- İstek değiştiriciyse aynı
Idempotency-Keyile tekrar edin (idempotency ve eşzamanlılık). - Kullanıcı eylemiyle tetiklenen sınırlarda (giriş, kayıt) otomatik tekrar yerine kullanıcıya bekleme süresini gösterin; parola ve kayıt uçlarında otomatik tekrar kilit süresini uzatır.
CrxClient(sunucu anahtarı)429’u,GETve anahtarlı isteklerde,Retry-After’a saygı göstererek kendisi yeniden dener (varsayılan 2 deneme).
Uyarı
Kural bütçesi aşımı da (
rule budget exceeded: <kural>)429döner; bu bir hız sınırı değil, kural motoru bütçesidir (komut başına 50 kural, 200 eylem, 500 değerlendirme düğümü ve zincir derinliği 5). Yeniden deneme sonuç değiştirmez; kuralı sadeleştirin (oyun kuralları).
Kendi tarafınızda yapmanız gerekenler
Genel bir sunucu sınırı olmadığı için büyük yükte sizin koruma eklemeniz gerekir:
- Sunucudan sunucuya toplu işlerde eşzamanlılığı sınırlayın (ör. aynı anda 5 ile 10 istek) ve hataları geri çekilmeyle yönetin.
- Anahtar bazında istek hızını kendi tarafınızda ölçün; tek bir sızmış anahtar sınırsız çağrı yapabilir (güvenlik).
- Lansman öncesi
GET /v1/…okumalarını önbelleğe alın (katalog uçlarıETagveIf-None-Matchile koşullu okumayı destekler; oyuncu başına yoklamayı 15 sn’den sık yapmayın).
Sayılar ve kodlama
Bu sayfa, Open Play’in sayıları, parayı, zamanı ve kimlikleri JSON üzerinde nasıl taşıdığını anlatır. En sık yapılan hata, 64 bit tam sayıları JavaScript number’ına çevirip hassasiyet kaybetmektir; bu sayfayı o hatadan kaçınmak için okuyun.
Kısa kurallar
| Alan türü | Çekirdek REST | Eklenti ve realtime |
|---|---|---|
64 bit tam sayı (int64) | JSON sayısı ("amount": 250) | Ondalık metin ("amount": "250") |
| 32 bit tam sayı | JSON sayısı | JSON sayısı |
| Kayan nokta | Hiçbir yerde yok | Hiçbir yerde yok |
| Para | Küçük birim tam sayısı (amount, balance) | Küçük birim, ...Minor alanları, int64 |
| Yüzde | Baz puan (10000 = %100) | Baz puan |
| Zaman | RFC 3339 metni (created_at) | Unix milisaniye tam sayı (...Ms) |
| Kimlik | UUID metni | UUID metni |
| Enum | snake_case metin | snake_case (eklenti), PascalCase (realtime çerçeve türleri) |
64 bit tam sayılar
JavaScript’in JSON.parse işlevi sayıları double’a çevirir; 2^53 − 1 (9 007 199 254 740 991) üstü tam sayılar sessizce bozulur. Open Play bu yüzden iki profil kullanır:
- Çekirdek REST
int64alanları JSON sayısı olarak gönderir (version,balance,amount). Değerler pratikte güvenli aralıkta kalır, ama garantibigintile okuyan bir ayrıştırıcıdır. TypeScript SDK’sılossless-jsonile okur vebigintdöner. - Eklenti ve realtime (
plugin-v1-decimal-int64kodlama profili)int64alanları ondalık metin olarak gönderir ve bekler:{"expectedVersion":"3"},{"sessionEpoch":"7"}. Böylece her istemci dili kayıpsız taşır.
Kurallı ondalık metin
Eklentilerde işaretli int64 kurallı biçimde yazılmalıdır; sunucu başka biçimi reddeder (400 invalid_argument):
| Geçerli | Geçersiz | Neden |
|---|---|---|
"0", "42", "-7" | "+1" | Artı işareti yok |
"9223372036854775807" | "01", "007" | Baştaki sıfır yok |
"-9223372036854775808" | "-0" | Eksi sıfır yok |
" 5", "5 " | Boşluk yok | |
"1.5", "1e3" | Kesir ve üs yok | |
"9223372036854775808" | int64 sınırı aşıldı | |
5 (JSON sayısı) | Eklenti int64 alanı metin ister |
Realtime çerçevelerindeki sayaçlar (sessionEpoch, inputSeq, revision, sequence, expectedVersion, streamEpoch, barrierSequence) aynı metin biçimindedir ve negatif olamaz. protocolVersion, schemaVersion ve diğer küçük sayaçlar JSON sayısıdır.
Eklenti şema belgesinde int64 alanın sınırları da metin olarak yazılır ("minimum": "0", "maximum": "9223372036854775807"); bu normaldir.
İstemci dillerinde
| Dil | Eşleme |
|---|---|
| TypeScript SDK | int64 → bigint. Sayıya çevirmeyin; gösterim için value.toString() kullanın. JSON’u kendiniz JSON.parse ile okumayın |
| Unity (C#) | int64 → long; eklenti çıktılarında ham JSON JsonValue ondalık metin olarak kalır |
| Ham JSON (başka dil) | Eklenti alanlarını string olarak okuyup int64’e çevirin |
TypeScript’te JSON’u kendiniz ayrıştırıyorsanız lossless-json gibi bir kütüphane kullanın; aksi halde büyük değerler bozulur.
Para ve ölçekli değerler
- Para değerleri küçük birimli tam sayıdır (ör. kuruş):
250kaç ana birim ettiği, oyununuzun gösterim kararına bağlıdır (panelde para biriminin “kuruş hanesi” ayarı gösterimi belirler); API yalnız tam sayıyı taşır. Bakiye ve tutar alanlarıamount,balance, eklentilerde...Minoradıyla gelir. - Kayan nokta (
float/double) hiçbir yerde kullanılmaz: ne istek, ne yanıt, ne de hesaplama. Kendi tarafınızda da para içinfloatkullanmayın; tam sayıyla çalışıp yalnız gösterimde ondalığa çevirin. - İçerik gruplarındaki ölçekli değerler
tamsayı + ölçekçiftidir:4350ve ölçek2→43.50. TypeScript SDK’sındaformatScaled(değer: bigint, ölçek)bunu kayıpsız biçimlendirir (0 ile 18hane). Kendifloatbölmenizi yapmayın.
Yüzdeler: baz puan
Yüzde ve oran alanları baz puan (basis point) tam sayısıdır: 10000 = %100, 2500 = %25, 1 = %0,01. Örnek: grup ödül payı share_bp 0 ile 10000 arasında olmalıdır; dışı 400 alır.
Zaman
| Yer | Biçim | Örnek |
|---|---|---|
Çekirdek REST yanıtları (created_at, as_of) | RFC 3339 | 2026-11-03T10:15:30+00:00 |
Eklenti ve realtime (createdAtMs, sent_at_ms) | Unix epoch milisaniye, tam sayı | 1793700930000 |
Sohbet sorgusu before_ms | Unix epoch milisaniye | 1793700930000 |
Webhook imzasındaki t | Unix epoch saniye | 1793700930 |
Deprecation başlığı | @<unix saniye> (RFC 9745) | @1793491200 |
Eklenti kullanımdan kalkma (sinceUnixS) | Unix saniye | 1793577600 |
Sunucu saatlerini UTC olarak yorumlayın. İstemci saati sunucu kararında kullanılmaz: zaman ve rastgelelik sunucuda üretilir ve olaya yazılır.
Kimlikler ve anahtarlar
- UUID: küçük harfli, tireli metin (
0192a3b4-0000-7000-8000-000000000001). Çoğu kaynak kimliği zamana göre sıralanan UUID v7’dir; sıralama için kullanabilirsiniz, ama biçimden anlam çıkarmayın. keyalanları (tanım anahtarları, skor tablosu, görev): oyun geliştiricinin verdiği okunabilir kimlikler; oluşturduktan sonra aynen kullanın, büyük/küçük harf ya da boşluk değiştirmeyin.- Eklenti kimlikleri: küçük harf ve tire (
package-ride). Mesaj türleri: nokta ile ayrılmış, eklenti önekli (package-ride.delivery-trip.active.input). - İmleçler: opak metin; içeriğini ayrıştırmayın (sayfalama).
- API anahtarları:
crx_live_<önek>_<gizli>; önek yalnız tanımlama içindir, gizli kısım yalnız bir kez gösterilir (güvenlik).
Numaralandırma (enum) değerleri
Tüm numaralandırma değerleri sunucuda tek bir tanımdan gelir ve bilinmeyen değer reddedilir (sessizce yok sayılmaz):
- Çekirdek REST alanları
snake_casemetindir ("type": "set_flag","channel": "in_game","status": "pending"). - Realtime çerçeve
typevekinddeğerleriPascalCase’tir (Authenticate,PlayerSelf); alan adlarıcamelCase’tir. - Sohbet soketi çerçeve
typedeğerlericamelCase, alan adlarısnake_case’tir (channel_id). - Webhook olay türleri
snake_case’tir (webhook olayları). - Eklenti şema belgesinde
enumolarak listelenen değerler (ör."image/png") birebir kullanılır.
İstemcinizde bilinmeyen bir enum değeri gelirse (yeni sürümde eklenmiş olabilir) çökmek yerine güvenli bir varsayılana düşün; SDK’lar bilinmeyen değeri kimi yerde reddeder, kimi yerde atlar, bu yüzden sürüm yükseltmelerini değişiklik günlüğünden izleyin.
Metin
- Tüm metin UTF-8 JSON metnidir.
- Alanların uzunluk sınırları vardır (ör.
Idempotency-Key200 karakter, eklenti dize alanlarındaminLength/maxLength); sınır ihlali400alır. - Düz metin hata mesajları (çekirdek REST) İngilizce ya da Türkçe olabilir ve sürümler arasında değişir; makine kararı için kullanmayın (hatalar).
Sürümleme
Bu sayfa, Open Play’de karşılaşacağınız sürüm numaralarını (API yolu, protokol, eklenti şeması, SDK) ve bir uç ya da işlem kullanımdan kalkarken sunucunun size nasıl haber verdiğini anlatır. Önemli: yazılı bir kırıcı değişiklik ve kaldırma politikası henüz yok; aşağıda yalnız bugün kodda olan davranış anlatılır.
Hangi sürüm neyi söyler
| Sürüm | Nerede görünür | Anlamı |
|---|---|---|
API yolu /v1 | Tüm uç yolları | Tek yol sürümü; /v2 yoktur |
Realtime protocolVersion | Her çerçevede (1) | Soket protokolü ana sürümü; farklı değer UnsupportedProtocol alır |
Eklenti protocolVersion | Şema belgesi (1) | Eklenti sözleşmesinin ana sürümü |
codecProfile | Şema belgesi (plugin-v1-decimal-int64) | Tel kodlaması; şimdilik tek profil |
Eklenti version | Şema belgesi (ör. 1.44.0) | Eklentinin sürüm metni |
schemaVersion | Her işlem ve mesaj tanımı; x-crx-schema-version başlığı | Tek bir mesajın şema sürümü (pozitif tam sayı) |
schemaSha256 | Şema belgesi | Şemaların özeti; sabitleme anahtarı (bağlamalar) |
| SDK sürümü | Paket sürümü | TypeScript @ferdiunal/open-play-ts (0.x), Unity com.openplay.sdk (0.x) |
/v1 ve sunucu sürümü
Tüm HTTP uçları /v1 altındadır. Sunucunun ayrı bir “API sürüm” başlığı yoktur; hangi uçların var olduğunu uç nokta referansı ve (çekirdek REST için) GET /openapi.json gösterir. /openapi.json elle derlenmiş, çekirdek REST’i kapsayan bir belgedir: eklentileri, WebSocket’leri ve panel API’sini kapsamaz ve her uç için tam olmayabilir.
Protokol sürümü
Realtime çerçevelerinde protocolVersion: 1 zorunludur; başka değer UnsupportedProtocol hatası alır ve soket kapanır. İstemciniz bu hatayı alırsa yeniden denemek yerine kullanıcıdan güncelleme isteyin (TypeScript SDK’sı bu durumda upgradeRequired durumuna geçer).
Eklenti şema sürümleri
Bir eklenti şeması iki düzeyde sürümlenir:
- İşlem/mesaj düzeyi
schemaVersion: her istektex-crx-schema-versionile bildirilir. Sunucunun bildiğinden farklı bir sürüm gönderirseniz400 invalid_argumentalırsınız. - Belge düzeyi
schemaSha256: şemalarda herhangi bir değişiklik özeti değiştirir. İstemcinizi bu özete sabitlersiniz.
Sürüm metni (1.44.0) bilgilendiricidir; uyumluluk kararını özetle verin. Eklenti sürümünü ve özet eşleşmesini nasıl doğrulayacağınız için bağlamalar.
Kullanımdan kalkma (Deprecation)
Bir uç ya da işlem kullanımdan kalkarken çalışmaya devam eder; davranışı, durum kodları ve gövdesi değişmez. Kalkış size şu işaretlerle bildirilir:
| İşaret | Nerede |
|---|---|
Deprecation: @<unix saniye> yanıt başlığı (RFC 9745) | Kullanımdan kalkan her yanıtta (başarılı ya da hatalı) |
OpenAPI deprecated: true | /openapi.json içindeki ilgili işlemde |
Şema belgesinde deprecated nesnesi | Eklenti işlemlerinde: since (sürüm metni), sinceUnixS ve replacement (yerine geçen yüzeyin kısa adı) |
SDK’da @deprecated | Üretilen TypeScript bağlamasında ilgili işlem |
Bugün kullanımdan kalkanlar:
| Yüzey | Başlık değeri | Yerine |
|---|---|---|
/v1/auth/organization/* (oyuncu organizasyonları, 19 uç) | @1793491200 (2026-11-01 UTC) | Yok; organizasyon özelliği kullanımdan kalkıyor, stüdyo kavramıyla karıştırmayın |
package-ride eklentisinin günlük skor sorguları (getDailyBoard, getLeaderboard) | @1793577600 (2026-11-02 UTC) | Çekirdek skor tablosu (“Günlük kazanç”) |
package-ride operatör oyuncu görünümü (operatorPlayer, operatorPlayers) | @1793577600 | Çekirdek karakter profili ve listesi |
Başlığın değeri, kullanımdan kalkmanın başladığı anı (UTC unix saniyesi) verir; bir kaldırma tarihi vermez. Yanıtta Sunset başlığı yoktur.
Uyarı
Kaldırma tarihi, minimum duyuru süresi ya da “kullanımdan kalkan uç en az N ay çalışır” gibi bir söz yoktur. Kullanımdan kalkan bir yüzeye yeni bağımlılık eklemeyin ve
Deprecationbaşlığını görünce geçiş planı yapın. Başlığı günlüğünüzde izlemek için yanıt başlıklarını kaydedin.
SDK sürümleri
- TypeScript SDK’sı
0.xsürümlerindedir;0.xsürümler arasında kırıcı değişiklik olabilir. Her sürümün değişikliklerini paketin değişiklik günlüğünden ve sürüm notlarından izleyin; sürümü tam (0.1.15gibi) sabitleyin,^aralığı kullanmayın. - Unity SDK’sı
0.1.0sürümündedir ve yalnız Unity6000.6.7f1ile doğrulanmıştır (Unity SDK). - SDK ve sunucu birlikte gelişir: yeni bir SDK özelliği (ör. skor tablosu, mağaza), o özelliği taşıyan sunucu sürümünü gerektirir. SDK’yı sunucudan önce güncellemeyin.
- Eklenti bağlamalarında uyum, SDK sürümüne değil
schemaSha256sabitlemesine bağlıdır (bağlamalar).
Ne yapmalı
- SDK sürümünüzü ve eklenti
schemaSha256değerlerinizi sürüm manifestinize yazın. - Her sunucu güncellemesinden sonra şema belgesini karşılaştırın ve gerekirse bağlamayı yeniden üretin.
Deprecationbaşlığı gören her çağrı için geçiş işi açın.- Realtime ve eklenti protokol sürümü uyuşmazlığında kullanıcıdan güncelleme isteyin; yeniden deneme döngüsü kurmayın.
Uç nokta referansı
Bu sayfa, her HTTP ucu için hangi kimlikle çağrılacağını ve hangi başlıkların beklendiğini gösterir. Tablo koddaki rota kayıt defterinden üretilir; yeni bir uç eklendiğinde sayfa da güncellenir.
Nasıl okunur
- Modül: Kapalı bir modülün uçları
404vemodule_disableddöner (hatalar). Çekirdek uçlar kapatılamaz. - Kimlik: Sunucu anahtarı ve istemci anahtarı
Authorization: Bearer crx_live_<önek>_<gizli>başlığıyla gönderilir. Oyuncu oturumu çerezle ya da Bearer oturum jetonuyla gelir vex-crx-env: <ortam uuid>başlığı ister; çerez oturumunda değiştirici isteklerex-csrf-tokenve izinliOrigineklenir. - Sunucu anahtarı olarak işaretli uçları istemci anahtarıyla çağırırsanız
403alırsınız. Sunucu veya istemci anahtarı olarak işaretli uçlarda kodda anahtar türü kapısı yoktur; istemciye gömülen anahtarla çağrılabilir olmaları bir güvenlik kararıdır, bu uçları yalnız sunucunuzdan çağırın (güvenlik). - Idempotency-Key:
zorunluise başlık olmadan istek400alır;isteğe bağlıise gönderirseniz tekrar güvenli olur (idempotency). If-Match: uç iyimser sürüm denetimini destekler. - Eklenti uçları (
/v1/plugins/...) için gereksinimler eklentinin şema belgesindedir; ayrıntı eklentileri çağırma sayfasındadır.
Toplam uç sayısı: 225.
Karakterler
Modül: characters
| Yöntem | Yol | Kimlik | Idempotency-Key | If-Match | Açıklama |
|---|---|---|---|---|---|
GET | /v1/characters | Sunucu veya istemci anahtarı | — | — | Karakterleri listeler (imleç sayfalama, definition süzgeci). |
POST | /v1/characters | Sunucu veya istemci anahtarı | — | — | Bir tanımdan (definition) yeni karakter üretir. |
GET | /v1/characters/{id} | Sunucu veya istemci anahtarı | — | — | Tek karakteri durumuyla okur. |
DELETE | /v1/characters/{id} | Sunucu anahtarı | — | — | Karakteri siler (yumuşak silme). |
POST | /v1/characters/{id}/commands | Sunucu anahtarı (istemci anahtarı yalnız set_flag) | isteğe bağlı | evet | Karakter komutunu çalıştırır (set_flag, set_attribute, add_resource, add_modifier, remove_modifier, add_xp, rollback). |
GET | /v1/characters/{id}/events | Sunucu veya istemci anahtarı | — | — | Karakterin olay akışını listeler (imleç sayfalama, artan seq). |
GET | /v1/characters/{id}/state | Sunucu veya istemci anahtarı | — | — | Karakterin at anındaki durumunu olayları yeniden oynatarak verir. |
GET | /v1/characters/{id}/stats | Sunucu veya istemci anahtarı | — | — | Etkin istatistikleri adım adım döküm (breakdown) ile verir. |
GET | /v1/characters/{id}/timeline | Sunucu veya istemci anahtarı | — | — | Olay akışını okunabilir özetlerle verir. |
POST | /v1/definitions | Sunucu anahtarı | — | — | Karakter tanımını kaydeder (değişmez sürüm üretir). |
GET | /v1/definitions/{key} | Sunucu veya istemci anahtarı | — | — | Güncel tanımı çözülmüş şemasıyla okur. |
POST | /v1/level-curves | Sunucu anahtarı | — | — | Seviye eğrisini doğrulayıp kaydeder (değişmez sürüm). |
GET | /v1/level-curves/{key} | Sunucu veya istemci anahtarı | — | — | Güncel seviye eğrisini okur. |
GET | /v1/rules | Sunucu veya istemci anahtarı | — | — | Kuralları listeler (imleç sayfalama). |
POST | /v1/rules | Sunucu anahtarı | — | — | Kural kaydeder; derlenemeyen kural hiç yazılmaz. |
POST | /v1/rules/dry-run | Sunucu veya istemci anahtarı | — | — | Kuralı gerçek bir karakter üzerinde yazmadan simüle eder. |
GET | /v1/rules/{key} | Sunucu veya istemci anahtarı | — | — | Kuralın güncel sürümünü okur. |
DELETE | /v1/rules/{key} | Sunucu anahtarı | — | — | Kuralı siler (yumuşak silme). |
POST | /v1/rules/{key}/disable | Sunucu anahtarı | — | — | Kuralı değerlendirme zincirinden çıkarır. |
POST | /v1/rules/{key}/enable | Sunucu anahtarı | — | — | Kuralı değerlendirme zincirine alır. |
POST | /v1/traits | Sunucu anahtarı | — | — | Özelliği (trait) kaydeder (değişmez sürüm). |
GET | /v1/catalog/characters | Sunucu anahtarı veya oyuncu oturumu | — | — | Karakter kataloğunu listeler. |
GET | /v1/catalog/characters/{key} | Sunucu anahtarı veya oyuncu oturumu | — | — | Karakter katalog girdisini okur. |
Ekonomi
Modül: economy
| Yöntem | Yol | Kimlik | Idempotency-Key | If-Match | Açıklama |
|---|---|---|---|---|---|
GET | /v1/auth/admin/player-wallet-movements | Sunucu anahtarı veya oyuncu oturumu (yönetici rolü) | — | — | Bir oyuncunun cüzdan hareketlerini listeler. |
POST | /v1/currencies | Sunucu anahtarı | — | — | Para birimi tanımlar. |
GET | /v1/economy/faucet-sink | Sunucu anahtarı | — | — | Günlük kaynak (faucet) ve gider (sink) toplamlarını verir. |
GET | /v1/economy/flags | Sunucu anahtarı | — | — | Ekonomi anomali işaretlerini listeler. |
GET | /v1/economy/merchant-gap | Sunucu anahtarı | — | — | Tüccar alış-satış farkı raporunu verir. |
GET | /v1/economy/top-holders | Sunucu anahtarı | — | — | Bir para biriminde en çok bakiyeye sahip oyuncuları listeler. |
GET | /v1/ledger | Sunucu veya istemci anahtarı | — | — | Bir cüzdanın defter (ledger) kayıtlarını listeler (imleç sayfalama). |
POST | /v1/transfers | Sunucu anahtarı | zorunlu | — | İki cüzdan arasında para aktarır. |
GET | /v1/wallets | Sunucu veya istemci anahtarı | — | — | Bir sahibin cüzdanlarını (owner) listeler. |
Eşyalar
Modül: items
| Yöntem | Yol | Kimlik | Idempotency-Key | If-Match | Açıklama |
|---|---|---|---|---|---|
GET | /v1/inventories/{owner} | Sunucu veya istemci anahtarı | — | — | Sahibin envanterini okur. |
POST | /v1/inventories/{owner}/equip | Sunucu anahtarı | zorunlu | evet | Eşyayı donatır. |
POST | /v1/inventories/{owner}/move | Sunucu anahtarı | zorunlu | evet | Eşyayı envanterde başka bir yuvaya taşır. |
POST | /v1/inventories/{owner}/split | Sunucu anahtarı | zorunlu | evet | Bir yığını ikiye böler. |
POST | /v1/inventories/{owner}/stack | Sunucu anahtarı | zorunlu | evet | İki yığını birleştirir. |
POST | /v1/inventories/{owner}/unequip | Sunucu anahtarı | zorunlu | evet | Donatılmış eşyayı çıkarır. |
POST | /v1/item-definitions | Sunucu anahtarı | — | — | Eşya tanımını kaydeder. |
GET | /v1/item-definitions/{key} | Sunucu veya istemci anahtarı | — | — | Eşya tanımını okur. |
GET | /v1/items | Sunucu veya istemci anahtarı | — | — | Bir sahibin eşya örneklerini listeler (imleç sayfalama). |
POST | /v1/items | Sunucu anahtarı | zorunlu | — | Yeni eşya örneği üretir (mint). |
GET | /v1/items/{id} | Sunucu veya istemci anahtarı | — | — | Tek eşya örneğini okur. |
POST | /v1/items/{id}/consume | Sunucu anahtarı | zorunlu | evet | Eşyayı tüketir. |
POST | /v1/items/{id}/destroy | Sunucu anahtarı | zorunlu | evet | Eşyayı yok eder. |
POST | /v1/items/{id}/transfer | Sunucu anahtarı | zorunlu | evet | Eşyayı başka bir sahibe aktarır. |
GET | /v1/player/inventory | Oyuncu oturumu | — | — | Oturumdaki oyuncunun envanterini okur. |
GET | /v1/player/items | Oyuncu oturumu | — | — | Oturumdaki oyuncunun eşyalarını listeler (imleç sayfalama). |
GET | /v1/catalog/items | Sunucu anahtarı veya oyuncu oturumu | — | — | Eşya kataloğunu listeler. |
GET | /v1/catalog/items/{key} | Sunucu anahtarı veya oyuncu oturumu | — | — | Eşya katalog girdisini okur. |
Ticaret
Modül: trading
| Yöntem | Yol | Kimlik | Idempotency-Key | If-Match | Açıklama |
|---|---|---|---|---|---|
POST | /v1/merchants | Sunucu anahtarı | — | — | Tüccar tanımlar. |
GET | /v1/merchants/{key} | Sunucu veya istemci anahtarı | — | — | Tüccarı okur. |
POST | /v1/merchants/{key}/buy | Sunucu anahtarı | zorunlu | — | Oyuncunun tüccardan satın almasını yürütür. |
POST | /v1/merchants/{key}/sell | Sunucu anahtarı | zorunlu | — | Oyuncunun tüccara satışını yürütür. |
POST | /v1/trades | Sunucu anahtarı | zorunlu | — | İki oyuncu arasında takas başlatır. |
GET | /v1/trades/{id} | Sunucu anahtarı | — | — | Takası okur. |
POST | /v1/trades/{id}/accept | Sunucu anahtarı | zorunlu | — | Takası kabul eder. |
POST | /v1/trades/{id}/cancel | Sunucu anahtarı | zorunlu | — | Takası iptal eder. |
POST | /v1/trades/{id}/offer | Sunucu anahtarı | zorunlu | — | Takasa teklif ekler ya da günceller. |
Mağaza
Modül: store
| Yöntem | Yol | Kimlik | Idempotency-Key | If-Match | Açıklama |
|---|---|---|---|---|---|
POST | /v1/iap/verify | Sunucu anahtarı | zorunlu | — | Mağaza makbuzunu doğrular ve ürünü teslim eder (IAP). |
GET | /v1/store/catalog | Sunucu anahtarı | — | — | Ham mağaza kataloğunu verir (yönetim görünümü). |
PUT | /v1/store/listings/{id} | Sunucu anahtarı | zorunlu | evet | Mağaza ilanını günceller. |
DELETE | /v1/store/listings/{id} | Sunucu anahtarı | zorunlu | evet | Mağaza ilanını siler. |
POST | /v1/store/listings/{listing_id}/reserve | Sunucu anahtarı | zorunlu | evet | İlan için rezervasyon açar. |
GET | /v1/store/pages | Oyuncu oturumu | — | — | Oturumdaki oyuncunun görebildiği mağaza sayfalarını verir. |
POST | /v1/store/pages | Sunucu anahtarı | zorunlu | evet | Mağaza sayfası oluşturur. |
POST | /v1/store/pages/reorder | Sunucu anahtarı | zorunlu | evet | Mağaza sayfalarını yeniden sıralar. |
PUT | /v1/store/pages/{id} | Sunucu anahtarı | zorunlu | evet | Mağaza sayfasını günceller. |
DELETE | /v1/store/pages/{id} | Sunucu anahtarı | zorunlu | evet | Mağaza sayfasını siler. |
POST | /v1/store/pages/{page_id}/listings | Sunucu anahtarı | zorunlu | evet | Sayfaya ilan ekler. |
POST | /v1/store/pages/{page_id}/listings/reorder | Sunucu anahtarı | zorunlu | evet | Sayfadaki ilanları yeniden sıralar. |
GET | /v1/store/preview/{player_id} | Sunucu anahtarı | — | — | Belirli bir oyuncunun göreceği vitrini önizler. |
POST | /v1/store/reservations/{id}/cancel | Sunucu anahtarı | zorunlu | evet | Rezervasyonu iptal eder. |
POST | /v1/store/reservations/{id}/checkout/currency | Sunucu anahtarı | isteğe bağlı | evet | Rezervasyonu oyun içi para ile tahsil eder. |
POST | /v1/store/reservations/{id}/checkout/iap | Sunucu anahtarı | isteğe bağlı | evet | Rezervasyonu mağaza makbuzu ile tahsil eder. |
POST | /v1/player/store/listings/{listing_id}/buy | Oyuncu oturumu | zorunlu | evet | Oyuncu, kendi oturumuyla ilanı oyun içi para ile satın alır. |
POST | /v1/webhooks/iap/{platform}/{environment_id} | Mağaza platformu imzası | — | — | Mağaza platformunun iade/iptal bildirimini alır. |
Ödüller
Modül: rewards
| Yöntem | Yol | Kimlik | Idempotency-Key | If-Match | Açıklama |
|---|---|---|---|---|---|
GET | /v1/login-rewards/{player_id} | Sunucu anahtarı | — | — | Giriş ödülü durumunu verir. |
POST | /v1/login-rewards/{player_id}/claim | Sunucu anahtarı | — | — | Giriş ödülünü teslim eder. |
POST | /v1/npc-rewards/{key}/claim | Sunucu anahtarı | zorunlu | — | NPC ödülünü teslim eder. |
GET | /v1/npc-rewards/{key}/eligibility | Sunucu anahtarı | — | — | NPC ödülüne uygunluğu sorgular. |
POST | /v1/reward-tables | Sunucu anahtarı | — | — | Ödül tablosunu kaydeder. |
GET | /v1/reward-tables/{key} | Sunucu anahtarı | — | — | Ödül tablosunu okur. |
POST | /v1/reward-tables/{key}/grant | Sunucu anahtarı | zorunlu | — | Ödül tablosundan oyuncuya ödül verir. |
GET | /v1/quests | Sunucu anahtarı | — | — | Görevleri listeler (offset + limit). |
POST | /v1/quests | Sunucu anahtarı | — | — | Görev tanımlar. |
GET | /v1/quests/{key} | Sunucu anahtarı | — | — | Görevi okur. |
POST | /v1/quests/{key}/claim | Sunucu anahtarı | — | — | Görev ödülünü teslim eder. |
GET | /v1/vip/{player_id} | Sunucu veya istemci anahtarı | — | — | Oyuncunun VIP durumunu verir. |
POST | /v1/vip/{player_id}/cards/{item_instance_id}/use | Sunucu veya istemci anahtarı | zorunlu | — | VIP kartını kullanır. |
Sosyal
Modül: social
| Yöntem | Yol | Kimlik | Idempotency-Key | If-Match | Açıklama |
|---|---|---|---|---|---|
GET | /v1/clan-applications/{application_id} | Sunucu anahtarı | — | — | Klan başvurusunu okur. |
POST | /v1/clan-applications/{application_id}/resolve | Sunucu anahtarı | zorunlu | — | Klan başvurusunu kabul ya da reddeder. |
GET | /v1/clan-invites/{invite_id} | Sunucu anahtarı | — | — | Klan davetini okur. |
POST | /v1/clan-invites/{invite_id}/respond | Sunucu anahtarı | zorunlu | — | Klan davetini yanıtlar. |
GET | /v1/clan-settings | Sunucu anahtarı | — | — | Klan çalışma ayarlarını okur. |
PATCH | /v1/clan-settings | Sunucu anahtarı | zorunlu | — | Klan çalışma ayarlarını günceller. |
GET | /v1/clans | Sunucu anahtarı | — | — | Klanları listeler. |
POST | /v1/clans | Sunucu anahtarı | zorunlu | — | Klan kurar. |
GET | /v1/clans/{clan_id} | Sunucu anahtarı | — | — | Klanı okur. |
PATCH | /v1/clans/{clan_id} | Sunucu anahtarı | zorunlu | — | Klan bilgilerini günceller. |
POST | /v1/clans/{clan_id}/applications | Sunucu anahtarı | zorunlu | — | Klana başvuru oluşturur. |
POST | /v1/clans/{clan_id}/disband | Sunucu anahtarı | zorunlu | — | Klanı dağıtır. |
POST | /v1/clans/{clan_id}/invites | Sunucu anahtarı | zorunlu | — | Klana davet gönderir. |
POST | /v1/clans/{clan_id}/leadership | Sunucu anahtarı | zorunlu | — | Klan liderliğini devreder. |
POST | /v1/clans/{clan_id}/leave | Sunucu anahtarı | zorunlu | — | Üyeyi klandan çıkarır (ayrılma). |
POST | /v1/clans/{clan_id}/members/kick | Sunucu anahtarı | zorunlu | — | Üyeyi klandan atar. |
POST | /v1/clans/{clan_id}/members/role | Sunucu anahtarı | zorunlu | — | Üyenin rolünü değiştirir. |
POST | /v1/clans/{clan_id}/treasury/deposit | Sunucu anahtarı | zorunlu | — | Klan kasasına para yatırır. |
POST | /v1/clans/{clan_id}/treasury/withdraw | Sunucu anahtarı | zorunlu | — | Klan kasasından para çeker. |
POST | /v1/clans/{clan_id}/xp | Sunucu anahtarı | zorunlu | — | Klana XP ekler. |
GET | /v1/parties | Sunucu anahtarı | — | — | Bir oyuncunun gruplarını (party) listeler (player_id). |
POST | /v1/parties | Sunucu anahtarı | — | — | Grup kurar. |
GET | /v1/parties/{party_id} | Sunucu anahtarı | — | — | Grubu okur. |
PATCH | /v1/parties/{party_id} | Sunucu anahtarı | — | — | Grup kapasitesini günceller. |
POST | /v1/parties/{party_id}/disband | Sunucu anahtarı | — | — | Grubu dağıtır. |
POST | /v1/parties/{party_id}/invites | Sunucu anahtarı | — | — | Gruba davet gönderir. |
POST | /v1/parties/{party_id}/leave | Sunucu anahtarı | — | — | Üyeyi gruptan çıkarır (ayrılma). |
POST | /v1/parties/{party_id}/rewards | Sunucu anahtarı | zorunlu | — | Grup ödülünü üyelere paylaştırır. |
POST | /v1/party-invites/{invite_id}/accept | Sunucu anahtarı | — | — | Grup davetini kabul eder. |
Sohbet
Modül: chat
| Yöntem | Yol | Kimlik | Idempotency-Key | If-Match | Açıklama |
|---|---|---|---|---|---|
GET | /v1/chat/channels | Oyuncu oturumu | — | — | Sohbet kanallarını listeler. |
POST | /v1/chat/channels | Oyuncu oturumu | — | — | Sohbet kanalı oluşturur. |
GET | /v1/chat/channels/{channel_id}/messages | Oyuncu oturumu | — | — | Kanal mesajlarını listeler (before_ms + limit). |
POST | /v1/chat/channels/{channel_id}/messages | Oyuncu oturumu | — | — | Kanala mesaj gönderir (client_message_id ile tekrar güvenli). |
GET | /v1/chat/ws | Oyuncu oturumu (çerez veya Bearer) | — | — | Sohbet WebSocket’i (kanal aboneliği ve mesaj gönderme). |
Rekabet
Modül: competition
| Yöntem | Yol | Kimlik | Idempotency-Key | If-Match | Açıklama |
|---|---|---|---|---|---|
GET | /v1/leaderboards | Sunucu anahtarı | — | — | Skor tablosu tanımlarını listeler. |
POST | /v1/leaderboards | Sunucu anahtarı | — | — | Skor tablosu tanımı kaydeder (değişmez sürüm). |
GET | /v1/leaderboards/{key} | Sunucu anahtarı | — | — | Skor tablosu tanımını ve etkin sezonu okur. |
GET | /v1/leaderboards/{key}/around-me | Sunucu anahtarı | — | — | Bir oyuncunun çevresindeki sıraları verir. |
GET | /v1/leaderboards/{key}/entries | Sunucu anahtarı | — | — | Sıralamanın üst sayfasını verir. |
GET | /v1/player/leaderboards/{key} | Oyuncu oturumu | — | — | Oturumdaki oyuncunun gördüğü sıralamayı verir. |
POST | /v1/leaderboards/{key}/scores | Sunucu anahtarı | zorunlu | — | Oyuncu skoru gönderir. |
POST | /v1/tournaments | Sunucu anahtarı | — | — | Turnuva oluşturur. |
GET | /v1/tournaments/{tournament_id} | Sunucu veya istemci anahtarı | — | — | Turnuvayı okur. |
POST | /v1/tournaments/{tournament_id}/matches/{match_id}/result | Sunucu anahtarı | zorunlu | — | Maç sonucunu bildirir. |
POST | /v1/tournaments/{tournament_id}/participants | Sunucu anahtarı | zorunlu | — | Turnuvaya katılımcı kaydeder. |
POST | /v1/tournaments/{tournament_id}/start | Sunucu anahtarı | — | — | Turnuvayı başlatır. |
Bildirimler
Modül: notifications
| Yöntem | Yol | Kimlik | Idempotency-Key | If-Match | Açıklama |
|---|---|---|---|---|---|
POST | /v1/devices | Oyuncu oturumu | — | — | Bildirim cihazı kaydeder. |
DELETE | /v1/devices/{token} | Oyuncu oturumu | — | — | Bildirim cihazı kaydını siler. |
GET | /v1/notifications | Oyuncu oturumu | — | — | Oyuncunun bildirim kutusunu listeler. |
GET | /v1/push/config | Kimlik gerektirmez (x-crx-env) | — | — | Web push için istemci yapılandırmasını verir (sırsız). |
POST | /v1/notifications | Sunucu anahtarı | — | — | Oyuncuya bildirim gönderir. |
POST | /v1/notifications/{id}/read | Oyuncu oturumu | — | — | Bildirimi okundu işaretler. |
GET | /v1/ws | Oyuncu oturumu (çerez veya Bearer) | — | — | Bildirim WebSocket’i (yalnız sunucudan oyuncuya canlı itme). |
Webhook’lar
Modül: webhooks
| Yöntem | Yol | Kimlik | Idempotency-Key | If-Match | Açıklama |
|---|---|---|---|---|---|
GET | /v1/webhooks | Sunucu anahtarı | — | — | Webhook uç noktalarını listeler (sırsız). |
POST | /v1/webhooks | Sunucu anahtarı | — | — | Webhook uç noktası kaydeder; gizli anahtar yalnız bu yanıtta döner. |
GET | /v1/webhooks/{id} | Sunucu anahtarı | — | — | Webhook uç noktasını okur (sırsız). |
DELETE | /v1/webhooks/{id} | Sunucu anahtarı | — | — | Webhook uç noktasını siler. |
Sahneler ve görseller
Modül: scenes
| Yöntem | Yol | Kimlik | Idempotency-Key | If-Match | Açıklama |
|---|---|---|---|---|---|
GET | /v1/assets | Sunucu anahtarı | — | — | Görselleri listeler (imleç sayfalama). |
PUT | /v1/assets | Sunucu anahtarı | — | — | Görsel yükler (içerik adresli, SHA-256). |
DELETE | /v1/assets/{sha256} | Sunucu anahtarı | — | — | Görseli siler (kullanımdaysa reddedilir). |
PUT | /v1/scenes | Sunucu anahtarı | — | — | Sahneyi oluşturur ya da var olanı döndürür. |
Eklentiler ve realtime
Modül: plugins
| Yöntem | Yol | Kimlik | Idempotency-Key | If-Match | Açıklama |
|---|---|---|---|---|---|
POST | /v1/plugins/{plugin_id}/commands/{message_type} | Oyuncu oturumu veya sunucu anahtarı (işleme göre) | zorunlu | evet | Eklenti komutunu çalıştırır (Idempotency-Key zorunlu). |
GET | /v1/plugins/{plugin_id}/commands/{message_type}/result | Oyuncu oturumu veya sunucu anahtarı (işleme göre) | — | — | Komut sonucunu idempotency anahtarıyla sorgular. |
GET | /v1/plugins/{plugin_id}/queries/{message_type} | Oyuncu oturumu veya sunucu anahtarı (işleme göre) | — | — | Eklenti sorgusunu çalıştırır (parametreler sorgu dizesinde). |
POST | /v1/plugins/{plugin_id}/queries/{message_type} | Oyuncu oturumu veya sunucu anahtarı (işleme göre) | — | — | Eklenti sorgusunu çalıştırır (parametreler gövdede). |
GET | /v1/plugins/{plugin_id}/schema | Oyuncu oturumu veya sunucu anahtarı (işleme göre) | — | — | Eklentinin şema belgesini (artifact) verir. |
POST | /v1/realtime/tickets | Oyuncu oturumu (çerez kipinde CSRF) | — | — | Realtime WebSocket için tek kullanımlık bilet üretir. |
GET | /v1/realtime/ws | Tek kullanımlık bilet | — | — | Realtime WebSocket’i (openplay.realtime.v1). |
Çekirdek: Keşif
| Yöntem | Yol | Kimlik | Idempotency-Key | If-Match | Açıklama |
|---|---|---|---|---|---|
GET | /openapi.json | Kimlik gerektirmez | — | — | Küratörlü OpenAPI belgesi (çekirdek REST yüzeyi; eklentiler ve WebSocket dahil değil). |
Çekirdek: Oyuncu kimliği ve oturumu
| Yöntem | Yol | Kimlik | Idempotency-Key | If-Match | Açıklama |
|---|---|---|---|---|---|
POST | /v1/auth/account/delete | Oyuncu oturumu | — | — | Oyuncunun kendi hesabını siler; geri alınamaz. |
GET | /v1/auth/callback/{provider} | Kimlik gerektirmez | — | — | OAuth dönüş adresi (code + state ile oturumu tamamlar). |
POST | /v1/auth/callback/{provider} | Kimlik gerektirmez | — | — | OAuth form_post dönüş adresi (Apple). |
POST | /v1/auth/change-password | Oyuncu oturumu | — | — | Parolayı değiştirir; tüm oturumlar düşer. |
GET | /v1/auth/csrf | Kimlik gerektirmez (x-crx-env) | — | — | Yeni CSRF jetonu verir. |
GET | /v1/auth/identities | Oyuncu oturumu | — | — | Oyuncunun bağlı kimlik sağlayıcılarını listeler. |
POST | /v1/auth/forgot-password | Kimlik gerektirmez (x-crx-env) | — | — | Parola sıfırlama bağlantısı gönderir. |
POST | /v1/auth/guest/upgrade/email | Oyuncu oturumu | — | — | Misafir hesabı aynı oyuncu kimliğiyle e-posta hesabına yükseltir. |
GET | /v1/auth/jwks | Kimlik gerektirmez (x-crx-env) | — | — | Erişim JWT’sini çevrimdışı doğrulamak için açık anahtar kümesini verir. |
POST | /v1/auth/link/{provider} | Oyuncu oturumu | — | — | Mevcut oyuncuya sağlayıcı kimliği bağlamayı başlatır. |
POST | /v1/auth/logout | Oturum ya da yenileme çerezi | — | — | Oturumu kapatır (bilinmeyen jeton sessizce başarılıdır). |
GET | /v1/auth/magic-link/verify | Kimlik gerektirmez (x-crx-env) | — | — | Sihirli bağlantıyı doğrular ve oturum açar. |
POST | /v1/auth/native/{provider} | Kimlik gerektirmez (x-crx-env) | — | — | Yerel platform kanıtıyla (Apple, Game Center, Play Games) giriş yapar. |
GET | /v1/auth/oauth/providers | Kimlik gerektirmez (x-crx-env) | — | — | Ortamda etkin OAuth sağlayıcılarını listeler. |
POST | /v1/auth/refresh | Oturum ya da yenileme çerezi | — | — | Oturumu yeniler (jeton döndürme). |
POST | /v1/auth/reset-password | Kimlik gerektirmez (x-crx-env) | — | — | Sıfırlama jetonunu tüketir ve yeni parolayı yazar. |
GET | /v1/auth/session | Oyuncu oturumu | — | — | Oturum kapsamını ve oyuncunun profil özetini verir. |
POST | /v1/auth/session/display-name | Oyuncu oturumu | — | — | Oyuncunun görünen adını değiştirir. |
POST | /v1/auth/sign-in/email | Kimlik gerektirmez (x-crx-env) | — | — | E-posta ve parola ile giriş yapar. |
POST | /v1/auth/sign-in/guest | Kimlik gerektirmez (x-crx-env) | — | — | Misafir olarak giriş yapar (aynı sır aynı oyuncuya döner). |
POST | /v1/auth/sign-in/magic-link | Kimlik gerektirmez (x-crx-env) | — | — | Sihirli bağlantı gönderir. |
POST | /v1/auth/sign-in/oauth/{provider} | Kimlik gerektirmez (x-crx-env) | — | — | OAuth yetkilendirme adresi ve state üretir. |
POST | /v1/auth/sign-up/email | Kimlik gerektirmez (x-crx-env) | — | — | E-posta ve parola ile kayıt olur, oturum açar. |
POST | /v1/auth/unlink/{provider} | Oyuncu oturumu | — | — | Sağlayıcı kimlik bağlantısını kaldırır. |
Çekirdek: Sunucu tarafı oyuncu yönetimi
| Yöntem | Yol | Kimlik | Idempotency-Key | If-Match | Açıklama |
|---|---|---|---|---|---|
POST | /v1/auth/admin/ban-player | Sunucu anahtarı veya oyuncu oturumu (yönetici rolü) | — | — | Oyuncuyu yasaklar. |
POST | /v1/auth/admin/create-player | Sunucu anahtarı veya oyuncu oturumu (yönetici rolü) | — | — | Yönetici eliyle oyuncu hesabı açar. |
GET | /v1/auth/admin/list-player-sessions | Sunucu anahtarı veya oyuncu oturumu (yönetici rolü) | — | — | Oyuncunun oturumlarını listeler. |
GET | /v1/auth/admin/list-players | Sunucu anahtarı veya oyuncu oturumu (yönetici rolü) | — | — | Oyuncuları listeler (imleç sayfalama). |
GET | /v1/auth/admin/player-security-events | Sunucu anahtarı veya oyuncu oturumu (yönetici rolü) | — | — | Bir oyuncunun güvenlik olaylarını listeler. |
POST | /v1/auth/admin/rename-player | Sunucu anahtarı veya oyuncu oturumu (yönetici rolü) | — | — | Oyuncunun görünen adını değiştirir. |
POST | /v1/auth/admin/reset-password | Sunucu anahtarı veya oyuncu oturumu (yönetici rolü) | — | — | Oyuncunun parolasını sıfırlar. |
POST | /v1/auth/admin/revoke-player-sessions | Sunucu anahtarı veya oyuncu oturumu (yönetici rolü) | — | — | Oyuncunun tüm oturumlarını kapatır. |
GET | /v1/auth/admin/security-events | Sunucu anahtarı veya oyuncu oturumu (yönetici rolü) | — | — | Ortamın güvenlik olay günlüğünü listeler. |
POST | /v1/auth/admin/set-player-role | Sunucu anahtarı veya oyuncu oturumu (yönetici rolü) | — | — | Oyuncunun rolünü değiştirir. |
POST | /v1/auth/admin/unban-player | Sunucu anahtarı veya oyuncu oturumu (yönetici rolü) | — | — | Oyuncunun yasağını kaldırır. |
POST | /v1/auth/admin/upgrade-guest | Sunucu anahtarı veya oyuncu oturumu (yönetici rolü) | — | — | Misafir oyuncuyu e-posta hesabına yükseltir. |
Çekirdek: İçerik grubu kataloğu
| Yöntem | Yol | Kimlik | Idempotency-Key | If-Match | Açıklama |
|---|---|---|---|---|---|
GET | /v1/catalog/groups | Sunucu anahtarı veya oyuncu oturumu | — | — | Yayınlanmış içerik gruplarını listeler. |
GET | /v1/catalog/groups/{group} | Sunucu anahtarı veya oyuncu oturumu | — | — | İçerik grubunu okur. |
GET | /v1/catalog/groups/{group}/entries/{key} | Sunucu anahtarı veya oyuncu oturumu | — | — | İçerik grubu girdisini okur. |
Çekirdek: Oyuncu verisi (bulut kaydı)
| Yöntem | Yol | Kimlik | Idempotency-Key | If-Match | Açıklama |
|---|---|---|---|---|---|
GET | /v1/player/data | Oyuncu oturumu | — | — | Oyuncunun bulut kaydı anahtarlarını (sürüm, boyut, zaman) listeler. |
GET | /v1/player/data/{key} | Oyuncu oturumu | — | — | Bir bulut kaydı anahtarını okur; yanıt ETag taşır. |
PUT | /v1/player/data/{key} | Oyuncu oturumu | — | evet | Bulut kaydı yazar; If-None-Match: * (oluştur) ya da If-Match (güncelle) zorunludur. |
DELETE | /v1/player/data/{key} | Oyuncu oturumu | — | evet | Bulut kaydı anahtarını siler; If-Match zorunludur. |
GET | /v1/players/{player_id}/data | Sunucu anahtarı | — | — | Bir oyuncunun bulut kaydı anahtarlarını sunucu anahtarıyla listeler (salt okuma). |
GET | /v1/players/{player_id}/data/{key} | Sunucu anahtarı | — | — | Bir oyuncunun bulut kaydı anahtarını sunucu anahtarıyla okur (salt okuma). |
Çekirdek: Genel içerik okuma
| Yöntem | Yol | Kimlik | Idempotency-Key | If-Match | Açıklama |
|---|---|---|---|---|---|
GET | /v1/assets/{sha256} | Kimlik gerektirmez | — | — | Görsel baytlarını verir (içerik adresli, kimliksiz). |
GET | /v1/model-files/{sha256} | Kimlik gerektirmez | — | — | 3D model dosyasını (GLB) verir (içerik adresli, kimliksiz). |
Çekirdek: Oyuncu organizasyonları (kullanımdan kalkıyor)
Bu uçlar Deprecation: @1793491200 yanıt başlığı taşır; çalışmaya devam eder.
| Yöntem | Yol | Kimlik | Idempotency-Key | If-Match | Açıklama |
|---|---|---|---|---|---|
POST | /v1/auth/organization/accept-invitation | Oyuncu oturumu | — | — | Kullanımdan kalkıyor: organizasyon davetini kabul eder. |
POST | /v1/auth/organization/add-team-member | Oyuncu oturumu | — | — | Kullanımdan kalkıyor: takıma üye ekler. |
POST | /v1/auth/organization/cancel-invitation | Oyuncu oturumu | — | — | Kullanımdan kalkıyor: daveti iptal eder. |
POST | /v1/auth/organization/create | Oyuncu oturumu | — | — | Kullanımdan kalkıyor: organizasyon kurar. |
POST | /v1/auth/organization/create-team | Oyuncu oturumu | — | — | Kullanımdan kalkıyor: takım kurar. |
POST | /v1/auth/organization/delete | Oyuncu oturumu | — | — | Kullanımdan kalkıyor: organizasyonu siler. |
POST | /v1/auth/organization/delete-team | Oyuncu oturumu | — | — | Kullanımdan kalkıyor: takımı siler. |
POST | /v1/auth/organization/invite-member | Oyuncu oturumu | — | — | Kullanımdan kalkıyor: üye davet eder. |
GET | /v1/auth/organization/list | Oyuncu oturumu | — | — | Kullanımdan kalkıyor: oturumdaki oyuncunun üyeliklerini listeler. |
GET | /v1/auth/organization/list-members | Oyuncu oturumu | — | — | Kullanımdan kalkıyor: üyeleri listeler. |
GET | /v1/auth/organization/list-team-members | Oyuncu oturumu | — | — | Kullanımdan kalkıyor: takım üyelerini listeler. |
GET | /v1/auth/organization/list-teams | Oyuncu oturumu | — | — | Kullanımdan kalkıyor: takımları listeler. |
POST | /v1/auth/organization/reject-invitation | Oyuncu oturumu | — | — | Kullanımdan kalkıyor: daveti reddeder. |
POST | /v1/auth/organization/remove-member | Oyuncu oturumu | — | — | Kullanımdan kalkıyor: üyeyi çıkarır. |
POST | /v1/auth/organization/remove-team-member | Oyuncu oturumu | — | — | Kullanımdan kalkıyor: takımdan üye çıkarır. |
POST | /v1/auth/organization/set-active | Oyuncu oturumu | — | — | Kullanımdan kalkıyor: oturuma etkin organizasyonu yazar. |
POST | /v1/auth/organization/update | Oyuncu oturumu | — | — | Kullanımdan kalkıyor: organizasyonu yeniden adlandırır. |
POST | /v1/auth/organization/update-member-role | Oyuncu oturumu | — | — | Kullanımdan kalkıyor: üye rolünü değiştirir. |
POST | /v1/auth/organization/update-team | Oyuncu oturumu | — | — | Kullanımdan kalkıyor: takımı yeniden adlandırır. |
Webhook olayları
Bu sayfa, bir webhook uç noktasına abone olurken kullanabileceğiniz olay türlerini ve her teslimatla gelen başlıkları listeler. Kayıt ve imza doğrulama adımları için webhook rehberine bakın.
Teslim başlıkları
| Header | Açıklama |
|---|---|
X-Crx-Signature | t=<unix-sn>,v1=<hex>; v1 = HMAC-SHA256(gizli, "{t}.{ham gövde}"). |
X-Crx-Event-Id | Olay kimliği (UUID); tekrar eden teslimatları ayıklamak için kullanın. |
X-Crx-Event-Type | Olay türü (aşağıdaki tablodaki değerlerden biri). |
Webhook olayları
Toplam olay türü: 23.
| Olay türü | Kaynak | Ne zaman gönderilir |
|---|---|---|
flag_set | Karakter | Bir bayrak (flag) ayarlandı. |
attribute_set | Karakter | Bir öznitelik değeri ayarlandı. |
resource_changed | Karakter | Bir kaynağın değeri değişti (yeni değer olayda yer alır). |
modifier_added | Karakter | Karaktere bir değiştirici (modifier) eklendi. |
modifiers_removed | Karakter | Bir kaynaktan gelen değiştiriciler kaldırıldı. |
xp_added | Karakter | Karaktere XP eklendi. |
level_up | Karakter | Karakter seviye atladı. |
ability_unlocked | Karakter | Karakterin bir yeteneği açıldı. |
event_emitted | Karakter | Bir kural özel bir olay yayınladı. |
character_rolled_back | Karakter | Karakter önceki bir sürüme geri alındı (yeni olay olarak yazılır). |
store_page_created | Mağaza | Mağaza sayfası oluşturuldu. |
store_page_updated | Mağaza | Mağaza sayfası güncellendi. |
store_page_deleted | Mağaza | Mağaza sayfası silindi. |
store_pages_reordered | Mağaza | Mağaza sayfaları yeniden sıralandı. |
store_listing_created | Mağaza | Mağaza ilanı oluşturuldu. |
store_listing_updated | Mağaza | Mağaza ilanı güncellendi. |
store_listing_deleted | Mağaza | Mağaza ilanı silindi. |
store_listings_reordered | Mağaza | Bir sayfadaki ilanlar yeniden sıralandı. |
store_purchase_initiated | Mağaza | Satın alma rezervasyonu açıldı. |
store_payment_started | Mağaza | Satın alma için ödeme başladı. |
store_purchase_completed | Mağaza | Satın alma tamamlandı ve ürün teslim edildi. |
store_reservation_cancelled | Mağaza | Satın alma rezervasyonu iptal edildi. |
reward_granted | Ödül | Bir ödül tablosundan oyuncuya ödül verildi. |
Sözlük
Bu sayfa, dokümanda geçen terimleri kısaca tanımlar ve ilgili sayfaya bağlar. Terimler alfabetik değil, konuya göre gruplanmıştır.
Yapı: stüdyo, oyun, ortam
| Terim | Tanım |
|---|---|
| Stüdyo (studio) | En üstteki sahiplik düzeyi; bir ekibi ya da şirketi temsil eder. Birden çok oyun barındırır. Yönetimi panelde Sunucu bölümündedir. |
| Oyun (game) | Stüdyonun altındaki ürün. Kendi ortamları, modülleri ve API anahtarları vardır. |
| Ortam (environment) | Bir oyunun yalıtılmış çalışma kopyası (ör. geliştirme, canlı). Veriler ortamlar arasında paylaşılmaz. Her API anahtarı ve oyuncu oturumu tek bir ortama bağlıdır. |
| Ortam alan adı (environment domain) | Ortama bağlı alan adı; aynı zamanda tarayıcı isteklerinde izinli köken (Origin) listesi olarak kullanılır. |
| Modül (module) | Açılıp kapatılabilen ürün parçası: karakterler, ekonomi, eşyalar, ticaret, mağaza, ödüller, sosyal, sohbet, rekabet, bildirimler, webhook’lar, sahneler ve eklentiler. Kapalı modülün uçları 404 module_disabled döner. |
| Panel (admin panel) | Oyunu yönettiğiniz web arayüzü. Panel API’si oyuncu API’sinden ayrıdır ve bu dokümanın kapsamında değildir. |
Kimlik ve anahtarlar
| Terim | Tanım |
|---|---|
| Sunucu anahtarı (server key) | crx_live_<önek>_<gizli> biçimli, yalnız sizin sunucunuzda tutulan gizli API anahtarı. Tüm sunucu uçlarını çağırabilir. İstemciye ya da oyun paketine asla konmaz. |
| İstemci anahtarı (client key) | İstemciye gömülebilen API anahtarı. Hassas komutlar (ör. add_xp) çalıştıramaz; ancak bazı uçlarda tür kapısı yoktur, bu yüzden yalnız gerçekten gerekliyse kullanın (uç noktalar). |
| Oyuncu oturumu (player session) | Oyuncunun girişinden sonra oluşan oturum. Çerezle (__Secure-crx.session) ya da Bearer oturum jetonuyla taşınır ve x-crx-env başlığı ister. |
| Erişim JWT’si (access JWT) | Oturum açıldığında gövdede dönen, oyun sunucunuzun JWKS ile çevrimdışı doğrulayabildiği kısa ömürlü jeton. Oturum jetonu ile aynı şey değildir. |
| JWKS | Erişim JWT’sini doğrulamak için açık anahtar kümesi (GET /v1/auth/jwks). |
| Misafir (guest) | Kayıt gerektirmeyen oyuncu; aynı gizli değerle her seferinde aynı oyuncuya döner ve sonradan e-posta hesabına yükseltilebilir. |
| CSRF | Tarayıcının kullanıcı adına istenmeyen istek göndermesini engelleyen çift gönderim: çerez + x-csrf-token başlığı. Çerez oturumunda değiştirici isteklerde gerekir. |
| Origin denetimi | Değiştirici isteklerde Origin başlığının ortamın izinli kökenlerinden olması kuralı. Sunucu CORS başlıklarını yalnız aynı alan adı listesindeki origin’lere gönderir; CORS yetki değildir, bu denetim ayrıca çalışır. |
| Aynı köken (same-origin) | Oyunun ve API’nin aynı alan adı altında (ters vekil ile) sunulması; mimari ve barındırma. |
| Oyuncu bileti (realtime ticket) | Realtime soketine bağlanmak için alınan tek kullanımlık, 30 saniyelik kimlik belirteci (protokol). |
Güvenilirlik: tekrar ve çakışma
| Terim | Tanım |
|---|---|
| Idempotency (tekrar güvenliği) | Aynı isteğin birden çok kez gönderilse de tek kez uygulanması. Idempotency-Key başlığıyla sağlanır (idempotency ve eşzamanlılık). |
| Idempotency-Key | İstemcinin ürettiği, bir işlemi tanımlayan 1 ile 200 karakterlik anahtar. |
| İyimser kilit (optimistic lock) | Kaynağın sürümünü isteğe ekleyip, sürüm değiştiyse isteğin reddedilmesi. If-Match ya da expectedVersion ile yapılır. |
expectedVersion | Beklenen kaynak sürümü: HTTP’de If-Match başlığı, realtime Command çerçevesinde alan, SDK’da seçenek. |
| Fail-open | Bir sınırlayıcı bağımlılığına (Redis) ulaşılamazsa isteğin sınırlanmadan geçmesi (hız sınırları). |
Eklentiler
| Terim | Tanım |
|---|---|
| Eklenti (plugin) | Oyuna özgü komut, sorgu ve realtime modülleri sunan, sunucuya derlenmiş güvenilir paket (genel bakış). Üçüncü taraf eklenti yükleme henüz yoktur. |
| Komut (command) | Durumu değiştiren, kalıcı ve tekrar-güvenli işlem. |
| Sorgu (query) | Salt-okunur okuma. |
| Şema belgesi (artifact) | Eklentinin tüm işlem ve şemalarını tarif eden JSON belge (GET /v1/plugins/{id}/schema). |
schemaSha256 | Şema belgesindeki schemas bölümünün özeti; sürüm sabitleme anahtarı (bağlamalar). |
| Bağlama (binding) | Şema belgesinden üretilen tipli istemci kodu. |
| Sabitleme (pin) | İstemcinin hangi eklenti ve şema özetiyle derlendiğinin kaydı; uyuşmazlıkta upgrade_required hatası. |
Erişim türü (access) | Eklenti işleminin kimlik sınırı: player, server ya da public. |
| Eklenti durumu (grant state) | Eklentinin bir ortamdaki durumu: etkin, salt okunur, boşaltılıyor, kapalı. |
plugin-v1-decimal-int64 | Eklenti ve realtime int64 değerlerini ondalık metin olarak taşıyan kodlama profili (sayılar ve kodlama). |
Realtime
| Terim | Tanım |
|---|---|
| Abonelik (subscription) | Join ile açılan, bir modül ve hedefe bağlı veri akışı; subscriptionId ile tanınır. |
| Hedef (target) | Aboneliğin neye bağlandığı: PlayerSelf, Room, Scene ya da InterestSet. |
| Anlık görüntü (snapshot) | Geçici durumun tam yayını; streamEpoch ve revision ile sıralanır. |
| Kalıcı olay (durable event) | Veritabanından kurtarılabilen, sequence sıralı eklenti olayı. |
| İmleç (cursor) | Kalıcı akışta kaldığınız yeri gösteren opak, oyuncuya bağlı değer (yeniden bağlanma). |
| Dönem (epoch) | sessionEpoch: bir soketin yazma dönemi; yeni soket eskisinin girdilerini geçersiz kılar. streamEpoch: durum akışının sıfırlanma sayısı. |
| Boşta kapanma (idle close) | Girdi kabul eden abonelikte oyuncu etkinliği gelmeyince sunucunun 4100 ile soketi kapatması. |
| Geri basınç (backpressure) | İstemci kuyruğunun dolması ya da sunucunun çerçeve hızı sınırı nedeniyle işin reddedilmesi. |
Veri ve oyun içi kavramlar
| Terim | Tanım |
|---|---|
| Tanım (definition) | Karakterin şeması ve başlangıç değerleri; değişmez sürümlerle saklanır. |
| Özellik (trait) | Tanımlara karıştırılan yeniden kullanılabilir şema parçası. |
| Değiştirici (modifier) | Bir istatistiği etkileyen geçici ya da kalıcı bonus (ör. eşyadan gelen). |
| Kural (rule) | Karakter olaylarına bağlı otomasyon (oyun kuralları). |
| Küçük birim (minor unit) | Para değerinin tam sayı karşılığı (ör. kuruş). |
| Baz puan (basis point) | 10000 = %100 olan yüzde birimi. |
| Yumuşak silme (soft delete) | Kaydın görünmez olması ama olay geçmişinin korunması. |
| İçerik grubu (content group) | Panelden yayınlanan, oyuna katalog olarak sunulan veri kümesi (içerik grupları). |
| Webhook | Open Play’in olayları kendi sunucunuza imzalı HTTP isteğiyle bildirmesi (webhook rehberi). |
| At-least-once | Webhook teslimatının en az bir kez, gerekirse birden çok kez yapılması; X-Crx-Event-Id ile tekilleştirin. |
Güvenlik
Bu sayfa, Open Play ile entegre bir oyunu güvenli işletmek için bilmeniz gerekenleri toplar: anahtarları nerede tutacağınız, nasıl döndüreceğiniz, tarayıcı oturumunun nasıl korunduğu ve webhook isteklerini nasıl doğrulayacağınız. Üretime çıkmadan önce üretim kontrol listesi ile birlikte okuyun.
1. API anahtarları
İki tür anahtar vardır ve ikisi de tek bir ortama bağlıdır:
| Tür | Nerede tutulur | Ne yapabilir |
|---|---|---|
Sunucu anahtarı (server) | Yalnız sunucunuzda (gizli yönetim aracı ya da ortam değişkeni) | Tüm sunucu uçları |
İstemci anahtarı (client) | İstemciye gömülebilir | Hassas komutlar (ör. add_xp, set_attribute) çalışmaz; ama bazı uçlarda anahtar türü kapısı yoktur (uç noktalar) |
Uyarı
İstemci anahtarı “zararsız” değildir. Karakter oluşturma/silme, envanter hareketleri, takas, tüccar alım-satımı ve cüzdan aktarımı gibi uçlarda kodda anahtar türü kapısı yoktur; istemciye gömülen anahtar bunları çağırabilir. Bu uçları yalnız sunucunuzdan çağırın, oyuncu için ise oyuncu oturumuyla çalışan uçları (
/v1/player/..., eklentiler,PlayerClient) kullanın.
Anahtar biçimi ve saklama
- Biçim:
crx_live_<önek>_<gizli>. Sunucu yalnız anahtarın özetini saklar (argon2id); gizli kısmı geri üretemez. - Gizli değer yalnız oluşturma anında bir kez gösterilir. Kaybederseniz geri alınamaz; yeni anahtar üretirsiniz.
- Anahtarı depoya, günlüğe, hata raporuna, istemci paketine, ekran görüntüsüne koymayın.
Authorizationbaşlığını günlüklerden süzün. - Ortam başına ve hizmet başına ayrı anahtar kullanın (ör. canlı API sunucusu, toplu iş, yönetim betiği); bir sızıntıda yalnız birini iptal edersiniz.
- Anahtara son kullanma tarihi verin. Panelde oluştururken
expiresAtayarlanabilir; süresi dolan anahtar reddedilir.
Yaşam döngüsü
Anahtarlar panelde Oyun ayarları: API anahtarları ekranında yönetilir (API anahtarları):
| Eylem | Etki |
|---|---|
| Oluştur | Yeni anahtar; gizli değer bir kez gösterilir |
| Devre dışı bırak / etkinleştir | Geçici ve geri alınabilir |
| Döndür (rotate) | Aynı adla yeni anahtar üretir ve eskisini aynı işlemde hemen iptal eder |
| İptal et (revoke) | Kalıcı; geri alınamaz |
| Sil | Yumuşak silme + iptal |
Anahtar durumu her istekte veritabanından yeniden okunur: iptal ya da devre dışı bırakma bir sonraki istekte etkili olur (yalnız gizli değerin doğrulama sonucu 60 sn önbelleğe alınır, durum alınmaz). Her işlem için gerekçe yazılır ve işlem geçmişine düşer.
Kesintisiz döndürme
Paneldeki Döndür eylemi eski anahtarı hemen iptal eder; yeni anahtarı dağıtana kadar çağrılarınız 401 alır. Kesintisiz döndürmek için:
- Panelde farklı bir adla ikinci bir anahtar oluşturun (aynı ad ve sahiple aynı anda tek etkin anahtar olabilir).
- Yeni anahtarı gizli yönetim aracınıza yazın ve hizmetlerinizi yeniden başlatarak dağıtın.
- Hiçbir hizmet eski anahtarı kullanmadığını doğrulayın (işlem geçmişi ve kendi günlükleriniz).
- Eski anahtarı iptal edin.
Sızıntı olursa
- Sızan anahtarı hemen iptal edin (etkisi bir sonraki istektedir).
- Yeni anahtarı yukarıdaki sırayla dağıtın.
- İşlem geçmişinde ve kendi günlüklerinizde, sızıntı anından sonraki beklenmeyen işlemleri (cüzdan aktarımları, eşya üretimi, webhook kaydı) arayın.
- Anahtarın erişebildiği ortamlarda webhook uç noktalarını gözden geçirin; saldırgan bir uç nokta kaydetmiş olabilir (kayıtlı sırlar bir kez gösterilir, ama yeni kayıt yeni sır üretir).
2. Oyuncu oturumu ve tarayıcı güvenliği
- Oyuncu girişinden sonra sunucu üç çerez yazar:
__Secure-crx.session(oturum),__Secure-crx.refresh(yenileme) ve__Secure-crx.csrf(CSRF). Üçü deHttpOnly,Secure,Path=/veSameSite=Laxtaşır (betikler okuyamaz); CSRF jetonunun betiğe verilen düz değeri çerezde değil, yanıt başlığı ve gövdesindedir.__Secure-öneki HTTPS gerektirir: düz HTTP’de oturum kurulamaz. - Oturum 30 gün kayar: oyuncu günde en az bir kez istek yaparsa uzar. Mutlak tavan 180 gündür: ne kadar aktif olursa olsun 180 gün sonra yeniden giriş gerekir. Açık bir realtime soketi oturumu yaşatmaz. Süreler sunucu kodunda sabittir.
- Ortam isterse tek aktif oturum kuralı açabilir (yeni giriş eskisini düşürür); bu, panelde giriş ayarlarındandır.
- Erişim JWT’si (EdDSA) oturum jetonu değildir; oyun sunucunuz onu
GET /v1/auth/jwksile çevrimdışı doğrular (sunucu doğrulaması).
CSRF
Çerez oturumunda her değiştirici (POST, PUT, PATCH, DELETE) istek iki koruma geçer:
- Origin denetimi:
Origin(ya daReferer) başlığındaki host, ortamın izinli kökenlerinden olmalıdır. Ortama bağlı bir host yalnız o ortama yönelebilir.Sec-Fetch-Site: cross-siteveSec-Fetch-Mode: navigatebirlikteyse engellenir.Originhiç göndermeyen istemciler (curl, sunucudan sunucuya) bu denetimden geçer; onları koruyan katman çift gönderimdir. - Çift gönderim (double submit):
__Secure-crx.csrfçerezi ilex-csrf-tokenbaşlığı birlikte gelmeli ve eşleşmelidir. Jeton tek kullanımlıktır ve her başarılı doğrulamada döner: yanıttaki yeniSet-Cookievex-csrf-tokendeğerini bir sonraki istek için saklayın. Yeni jeton içinGET /v1/auth/csrf.
TypeScript SDK’sı bunu otomatik yönetir; elle HTTP yazıyorsanız oturumlar ve CSRF sayfasına bakın. Hata durumu: 403 ve düz metin permission denied.
CORS ve aynı köken
Sunucu CORS başlıklarını yalnız ortam alan adı listesindeki (ve operatörün genel izinli listesindeki) https://<alan adı> origin’lerine, yalnız kamusal API’de gönderir: izinli origin aynen yansıtılır, Access-Control-Allow-Credentials: true eklenir, * kullanılmaz, panel yolu (/v1/panel/*) hiçbir koşulda CORS almaz. CORS yetki değildir: Origin, CSRF çift gönderimi ve ortam denetimleri aynen çalışır; CORS yalnız tarayıcının yanıtı okumasına izin verir. Kendi vekilinize ek CORS başlığı eklemeyin: çift başlık tarayıcıda hata verir.
Oturum çerezi SameSite=Lax olduğundan doğrudan çağrı yalnız oyun ile Open Play aynı sitede (aynı kayıtlı alan adının alt alanları) ise çalışır; farklı sitede ters vekil kullanın. Topoloji: mimari ve barındırma.
İzinli kökenler ortam alan adlarınızdır. Panelde ortam için tanımladığınız alan adı hem o ortama yönlendirmenin hem de Origin denetiminin dayanağıdır (Oyun ayarları: ortamlar). Bilinmeyen bir host’tan gelen değiştirici istek reddedilir.
3. Webhook doğrulaması
Open Play, abone olduğunuz olayları uç noktanıza imzalı bir POST ile gönderir. Her isteği doğrulamak zorundasınız; imzasız isteği işlemeyin.
| Başlık | Anlam |
|---|---|
X-Crx-Signature | t=<unix saniye>,v1=<hex> |
X-Crx-Event-Id | Olay kimliği (UUID); tekilleştirme anahtarı |
X-Crx-Event-Type | Olay türü (webhook olayları) |
İmza: HMAC-SHA256(gizli, "{t}.{ham gövde}"), küçük harfli onaltılık. Anahtar, kayıtta aldığınız whsec_… metninin kendisidir (bayt olarak). Kurallar:
- Ham gövdeyi imzalayın/doğrulayın: JSON’u çözüp yeniden yazarsanız baytlar değişir ve imza tutmaz.
- Sabit zamanlı karşılaştırma kullanın (
timingSafeEqual,hmac.compare_digest). tdeğerini kendi saatinizle karşılaştırın ve pencere dışını reddedin (5 dakika önerilir; bu alıcı politikasıdır, sunucu zorlamaz).- At-least-once: aynı olay birden çok kez gelebilir.
X-Crx-Event-Idile tekilleştirin ve işlemi tekrar-güvenli yapın. - Yalnız
2xxyanıt başarıdır. Yanıtı hızlı verin (işi kuyruğa alın); diğer durumlar yeniden denenir.
Teslimat davranışı:
| Davranış | Değer |
|---|---|
| Yeniden deneme | Üstel geri çekilme: 1 sn ile başlar, 2’nin kuvvetiyle artar, 5 dakikada tavanlanır, ±%20 sapma |
| En çok deneme | 10; sonra teslimat failed (ölü mektup kuyruğu, DLQ) olur |
| Yönlendirme (redirect) | Takip edilmez |
| Gövde sınırı | 64 KiB üstü gövde gönderilmez |
| Uç nokta adresi | Yalnız https; özel, loopback ve link-local IP adresleri ile kullanıcı bilgisi (kullanici:parola@) içeren adresler kayıtta reddedilir (SSRF koruması) |
| Gizli anahtar | Kayıt yanıtında yalnız bir kez döner; döndürme = uç noktayı silip yeniden kaydetmek |
Not
Webhook gizli anahtarını döndürmek için yerinde bir “rotate” yoktur. Kesintisiz geçiş: yeni uç noktayı (yeni gizli anahtarla) kaydedin, alıcınız ikisini birden doğrulasın, eski uç noktayı silin.
Doğrulama örneği (Node, node:crypto):
import { createHmac, timingSafeEqual } from "node:crypto";
/** İmzalı webhook isteğinin doğrulama sonucu. */
export type WebhookCheck = { ok: true; eventId: string; eventType: string } | { ok: false; reason: string };
const TOLERANCE_SECONDS = 300; // yeniden oynatma penceresi: alıcı politikasıdır, 5 dakika önerilir
/**
* Open Play webhook isteğini doğrular. `rawBody`, ayrıştırılmamış HAM bayt dizisi olmalıdır:
* JSON'u çözüp yeniden yazarsanız imza tutmaz.
* İmza: HMAC-SHA256(secret, "{t}.{ham gövde}"), başlık biçimi `t=<unix saniye>,v1=<hex>`.
*/
export function verifyWebhook(
secret: string,
rawBody: Buffer,
headers: { signature: string | undefined; eventId: string | undefined; eventType: string | undefined },
nowSeconds: number = Math.floor(Date.now() / 1000),
): WebhookCheck {
const parts = Object.fromEntries((headers.signature ?? "").split(",").map((part) => part.trim().split("=", 2) as [string, string]));
const timestamp = Number(parts["t"]);
const received = parts["v1"];
if (!Number.isInteger(timestamp) || received === undefined) return { ok: false, reason: "imza başlığı bozuk" };
if (Math.abs(nowSeconds - timestamp) > TOLERANCE_SECONDS) return { ok: false, reason: "zaman damgası pencere dışında" };
const expected = createHmac("sha256", secret).update(`${timestamp}.`).update(rawBody).digest("hex");
const a = Buffer.from(expected, "utf8");
const b = Buffer.from(received, "utf8");
if (a.length !== b.length || !timingSafeEqual(a, b)) return { ok: false, reason: "imza uyuşmuyor" };
if (headers.eventId === undefined || headers.eventType === undefined) return { ok: false, reason: "olay başlıkları eksik" };
return { ok: true, eventId: headers.eventId, eventType: headers.eventType };
}
Teslimat durumu ve DLQ’yu panelde izleyin: Webhook ve olay kuyruğu. Kayıt ve uç nokta yönetimi için webhook rehberi.
4. Sırların döndürülmesi: özet
| Sır | Nasıl döndürülür |
|---|---|
| Sunucu/istemci API anahtarı | İkinci anahtar oluştur, dağıt, eskiyi iptal et (yukarıda) |
| Webhook gizli anahtarı | Yeni uç nokta kaydet, alıcıyı ikisini kabul edecek şekilde güncelle, eskiyi sil |
| Oyuncu parolası | Oyuncu kendi parolasını değiştirir (tüm oturumlar düşer) ya da parola sıfırlama akışı (e-posta ve parola) |
| Oyuncu oturumları | Kullanıcı çıkış yapar; yönetici oyuncunun oturumlarını iptal eder (panel ya da POST /v1/auth/admin/revoke-player-sessions) |
5. Neleri günlüğe yazmayın
API anahtarı, oturum ve yenileme jetonu, CSRF jetonu, realtime bileti, webhook gizli anahtarı, OAuth state ve code değerleri, parola ve misafir gizli değeri. SDK’lar hata nesnelerinde bunları içermez; kendi günlükleme kodunuzda da isteği ham yazdırmayın.
6. Diğer notlar
- Hata ayrıntısı sızdırılmaz: sunucu
500yanıtında iç ayrıntı vermez; hesap varlığı da sızdırılmaz (yanlış parola ile bilinmeyen adres aynı yanıtı alır). - Yasaklı hesap: giriş uçlarında, sahiplik kanıtlandıktan sonra
403 account_banned; diğer uçlarda ayrım yapılmaz (hatalar). - Güvenlik şalterleri: panelde ortam başına bazı koruma kurallarını gevşetebilir ya da geri zorlayabilirsiniz; her değişiklik gerekçeyle kaydedilir (Güvenlik şalterleri).
- Eklentiler sunucuya derlenmiş güvenilir koddur; üçüncü taraf eklenti çalıştırma ve yalıtım henüz yoktur (eklentiler).
- Panel yönetici hesapları için ayrı bir kimlik hattı ve iki aşamalı doğrulama vardır; oyuncu hesaplarında iki aşamalı doğrulama yoktur.
Üretim kontrol listesi
Bu sayfa, canlıya çıkmadan önce tek tek işaretleyeceğiniz maddeleri toplar. Her madde kısa bir nedenle gelir ve ilgili sayfaya bağlanır. Listeyi lansmandan önce bir kez ve her büyük değişiklikten sonra yeniden gözden geçirin.
1. Ağ ve barındırma
- Her şey HTTPS. Oturum çerezleri
__Secure-öneklidir veSecurebayrağı taşır; düz HTTP’de oturum kurulamaz. Soketlerwss://ile açılır. Yerel geliştirmedehttp://localhostkullanıyorsanız tarayıcınızınlocalhostistisnasını doğrulayın. - Tarayıcıdan çağrı yolu seçildi. Ya oyunun alan adı bir ortamın alan adı listesindedir ve oyun Open Play’i doğrudan çağırır (sunucu CORS başlıklarını gönderir; oyun ile Open Play aynı kayıtlı alan adının alt alanları olmalıdır, yoksa
SameSite=Laxoturum çerezi gitmez), ya da oyun API’yi kendi alan adı altından ters vekille çağırır (mimari ve barındırma). - Vekil şu başlıkları olduğu gibi iletir:
Authorization,Cookie(ve yanıttaSet-Cookie),Origin,x-crx-env,x-csrf-token,Idempotency-Key,If-Match,x-crx-schema-version,Sec-WebSocket-*(alt protokol ve uzantı pazarlığı dahil). Yanıt başlıklarını (x-csrf-token,Deprecation,Retry-After,ETag) silmez. - WebSocket yükseltmesi vekilde açıktır,
Upgrade/Connectionbaşlıkları iletilir ve bağlantı en az 5 dakika boşta kalabilir (sunucu boşta kapatmayı kendisi yapar: limitler). - İstek gövdesi sınırı en az 2 MiB. Sunucu 2 MiB üstünü
413ile reddeder; vekiliniz daha düşük bir sınır koymasın. - Zaman aşımı: vekilin yanıt-başlık bekleme süresi uzun işlemleri kesmez (Open Play’in kendi ağ geçidi 65 sn kullanır).
- İstemci IP’si iletilir. Kimlik uçlarındaki hız sınırları istemci IP’sine bağlıdır. Vekil
X-Forwarded-Foreklemiyorsa tüm oyuncular tek kovada toplanır (ör. misafir açma dakikada 30). Birden çok vekil zincirliyse operatör güvenilir vekil bloklarını tanımlamalıdır. - Panel yolu internete kapalı.
/v1/panel/*yolu halka açık ağ geçidinde404döndürülür; panele yalnız yönetim ağından ya da ayrı bir alan adından erişilir. - Önbellek: çerez ya da
Authorizationtaşıyan API yanıtları paylaşımlı önbelleğe (CDN) alınmaz. Yalnız herkese açık, içerik adresli yanıtlar (/v1/assets/{sha256},/v1/model-files/{sha256}) veETagtaşıyan katalog yanıtları uygun önbellek kuralına tabidir.
2. Ortamlar ve alan adları
- Geliştirme, hazırlık ve canlı için ayrı ortamlar kullanıyorsunuz; veriler paylaşılmaz.
- Her ortamın alan adı panelde tanımlı (Oyun ayarları: ortamlar); izinli
Originlistesi budur. - İstemci yapılandırmasına doğru ortam kimliği (
x-crx-envdeğeri) konmuş; canlı istemci hazırlık ortamını göstermiyor. - Yalnız gereken modüller açık (modüller). Kapalı modül
404 module_disableddöner; açık bıraktığınız her modül saldırı yüzeyidir. - Giriş yöntemleri panelde yapılandırılmış (misafir, e-posta, Google); kullanmadığınız yöntem kapalı (Giriş yöntemleri).
3. Anahtarlar ve sırlar
- Sunucu anahtarları yalnız sunucuda. İstemci paketinde, mobil uygulamada, WebGL derlemesinde, depoda yoktur (güvenlik).
- Ortam ve hizmet başına ayrı anahtar; anahtarlara son kullanma tarihi verildi.
- İstemci anahtarı kullanıyorsanız hangi uçları çağırabildiğini bildiğinizi doğruladınız; oyuncu işlemleri oyuncu oturumuyla yapılıyor (uç noktalar).
- Anahtar döndürme provası yapıldı: ikinci anahtar, dağıtım, eskiyi iptal.
- Anahtar ve jetonlar günlüklerde yok;
Authorization,Cookievex-csrf-tokensüzülüyor. - Webhook gizli anahtarı alıcınızda gizli yönetim aracında; kayıtta yalnız bir kez gösterildiği için yedeği var.
4. Tekrar güvenliği ve eşzamanlılık
- Para, eşya, ödül ve komut gönderen her çağrı
Idempotency-Keytaşıyor; anahtar bir kez üretilip tekrarlarda aynen kullanılıyor (idempotency). - Belirsiz sonuçta (zaman aşımı, ağ kopması) komut yeni anahtarla değil aynı anahtarla ya da sonuç sorgusuyla tamamlanıyor.
- Paylaşılan kaynak yazan çağrılar
If-Match/expectedVersiongönderiyor;409’da durum yeniden okunuyor. -
429,503ve ağ hatalarında üstel geri çekilme + sapma (jitter) var;Retry-Afterdikkate alınıyor (hız sınırları). - Hata işleme durum koduna göre; düz metin mesajı ayrıştırılmıyor (hatalar).
5. Oyuncu kimliği
- Oturum kaybı akışı kurulu:
401gelince oturum yenileme, olmazsa yeniden giriş; yasaklı hesap için ayrı ekran (oturumlar ve CSRF). - Misafir kimliğinin saklama davranışı ve e-posta ya da Google’a yükseltme akışı kuruldu (misafir ilerlemesi yükseltmeyle korunur).
- Oyun sunucunuz erişim JWT’sini JWKS ile doğruluyor, süre ve ortam alanlarını denetliyor (sunucu doğrulaması).
- Kimlik hız sınırları (misafir 30/dk, e-posta girişi 5/dk, kayıt 10/dk, IP başına) beklenen lansman trafiğinizi taşıyor; gerekirse yük testi yapıldı.
6. Realtime
- İstemci SDK’yı kullanıyor ya da protokolü (bilet,
Origin, alt protokol) eksiksiz uyguluyor (protokol). - Yeniden bağlanma: her bağlantıda yeni bilet, üstel geri çekilme, kalıcı akışlarda son imleçle
Join,ResyncRequired’da imleçsizJoin(yeniden bağlanma). - Boşta kapanma (
4100) için “Devam et” ekranı var; duraklatma ekranlarında canlı tutma girdisi gönderiliyor. - Çerçeve hızı 40/sn altında; oyuncu başına 4 sekme/soket sınırı biliniyor.
- Bildirim ve sohbet soketleri tarayıcıdan doğrudan açılamaz (başlık kısıtı); gelen kutusu yoklaması ya da REST uçları kullanılıyor (realtime genel bakış).
7. Eklentiler
- Kullandığınız eklentinin şema özeti (
schemaSha256) sürüm manifestinize yazılı ve bağlamalar bu özetle üretildi (bağlamalar). - Sunucu güncellemesinden sonra özet karşılaştırması (başlangıçta ya da CI’da) yapılıyor.
- Eklentinin ortamdaki durumu etkin (Eklentiler); beklenmedik
403 forbiddeniçin ilk bakılacak yer burasıdır. -
Deprecationbaşlığı taşıyan çağrılar için geçiş işi açıldı (sürümleme).
8. Webhook’lar
- Uç nokta
https; imza her istekte doğrulanıyor, zaman damgası penceresi denetleniyor,X-Crx-Event-Idile tekilleştirme yapılıyor (güvenlik). - Alıcı hızlı
2xxdöner (işi kuyruğa alır); 10 deneme sonundafailed(DLQ) olan teslimatlar için izleme planı var (Webhook ve olay kuyruğu yalnız izleme sunar, yeniden gönderme yoktur); kaçırılan olayları ilgili kaynağı REST ile okuyarak telafi eden bir yolunuz var.
9. Gözlem ve işletme
- İstek günlüğünüzde durum kodu, süre, çağrılan yol ve (eklenti uçlarında)
x-request-idvar; gizli değerler yok. -
5xxve429oranı için uyarınız var;503+Retry-Afteryanıtlarının yeniden denendiği doğrulandı. - Panel yönetici hesapları kişiye özel, iki aşamalı doğrulama açık (Panel yöneticileri).
- İşlem geçmişi düzenli gözden geçiriliyor; güvenlik şalterleri varsayılan konumunda (bilerek değiştirdiyseniz gerekçesi kayıtlı).
- SDK sürümü tam sabitlenmiş (
^yok); yükseltmeler değişiklik günlüğünden izleniyor (sürümleme).
10. Lansman öncesi son deneme
- Canlı ortama benzer bir hazırlık ortamında uçtan uca akışı koşun: giriş, ödül, satın alma, soket bağlantısı, bağlantı kopması ve yeniden bağlanma.
- Bilerek
Idempotency-Keyile aynı isteği iki kez gönderin; ikinci yanıtın aynı sonucu döndüğünü doğrulayın. - Sunucu anahtarını bir kez iptal edin ve ikinci anahtara geçişi gözlemleyin.
- Webhook alıcınıza hatalı imzayla bir istek gönderin; reddettiğini doğrulayın.
- Kimlik uçlarında lansman trafiğinizi taklit eden bir deneme yapın;
429oranına bakın.
Sorun çıkarsa sorun giderme sayfasına bakın.
Sorun giderme
Bu sayfa, entegrasyonda karşılaşacağınız sorunları belirti, neden, çözüm üçlüsüyle listeler. Belirtiyi hata kodundan ya da durum kodundan bulun. Kod tablolarının tamamı için hata referansı.
Not
Sorun bildirirken şunları ekleyin: çağrılan yol ve yöntem, durum kodu ve gövde (gizli değerler çıkarılmış), istek zamanı (UTC) ve eklenti uçlarında
x-request-id/requestId. Sunucu hata ayrıntısı dışarı sızdırmaz; bu bilgiler incelemeyi hızlandırır.
Kimlik ve oturum
| Belirti | Olası neden | Çözüm |
|---|---|---|
Sunucu çağrısı 401 unauthorized | Authorization: Bearer crx_live_… başlığı yok ya da biçimi yanlış; anahtar iptal edilmiş, devre dışı ya da süresi dolmuş; anahtar başka ortama ait | Başlığı ve anahtarı kontrol edin; panelde anahtarın durumuna ve ortamına bakın (API anahtarları). Sunucu “yanlış anahtar” ile “iptal edilmiş“i ayırt etmez |
Sunucu çağrısı 403 permission denied | İstemci anahtarıyla sunucu ucu çağırıyorsunuz | Sunucu anahtarı kullanın (uç noktalar: “Sunucu anahtarı” olan uçlar) |
Oyuncu çağrısı 401 | x-crx-env başlığı yok ya da UUID değil; oturum yok, süresi dolmuş ya da iptal; ortam uyuşmuyor | Başlığı ekleyin; oturumu yenileyin ya da yeniden giriş yapın. Yasaklı hesap da 401 görünür (ayrım yapılmaz) |
Oyuncu 403 permission denied (POST) | CSRF çifti eksik/eşleşmiyor; jeton zaten kullanılmış; Origin izinli değil | Aşağıdaki CSRF satırlarına bakın |
Girişte 403 ve {"code":"account_banned"} | Hesap yasaklı | Oyuncuya askı ekranı gösterin; yeniden deneme döngüsü kurmayın; yeni misafir açmayın |
| Oturum beklenenden önce bitiyor | 30 gün hiç istek yapılmadı; ya da 180 günlük mutlak tavan doldu; parola değişti (tüm oturumlar düşer); ortamda “tek aktif oturum” açık ve başka cihazdan girildi | Yeniden giriş akışı kurun; davranış güvenlik sayfasında |
| Tarayıcıda oturum çerezi hiç kurulmuyor | HTTP üzerinden çalışıyorsunuz (Secure + __Secure- öneki); API başka bir alan adında (çerez üçüncü taraf olur, SameSite=Lax); tarayıcı çerezleri engelliyor | HTTPS ve aynı köken kullanın (mimari ve barındırma) |
429 rate limited giriş/kayıtta | IP başına hız sınırı doldu (misafir 30/dk, e-posta girişi 5/dk…) | Bekleyin; çok oyuncu tek IP’den geliyorsa ya da vekil istemci IP’sini iletmiyorsa hız sınırları ve üretim kontrol listesi |
| E-posta girişi başarısız, parola doğru | Başarısız deneme kilidi (adres + IP başına 10/15 dk) | 15 dakika bekleyin ya da parola sıfırlayın |
CSRF ve Origin
| Belirti | Olası neden | Çözüm |
|---|---|---|
Her POST 403 | x-csrf-token başlığı ya da __Secure-crx.csrf çerezi gönderilmiyor | GET /v1/auth/csrf ile jeton alın; çerezi ve başlığı birlikte gönderin. SDK bunu otomatik yapar |
İlk POST geçiyor, ikincisi 403 | CSRF jetonu tek kullanımlıktır ve her başarılı yanıtla yenilenir; yanıtın yeni değerini saklamadınız ya da iki isteği aynı jetonla paralel gönderdiniz | Her yanıttaki yeni x-csrf-token ve Set-Cookie değerini kullanın; değiştirici istekleri sıraya koyun |
Yalnız tarayıcıda 403, curl’de çalışıyor | Origin ortamın izinli kökenlerinde değil; Sec-Fetch-Site: cross-site ile gezinme isteği | Oyunun alan adını ortam alan adı olarak tanımlayın (Oyun ayarları: ortamlar); API’yi aynı kökenden çağırın |
| Tarayıcı konsolunda “CORS policy” hatası | Oyunun alan adı hiçbir ortamın alan adı listesinde ya da genel izinli listede değil (sunucu o origin’e CORS vermez); ya da https://<alan adı> dışında bir origin (http, port, null) | Alan adını ortam alan adı olarak ekleyin (Oyun ayarları: ortamlar); olmuyorsa aynı köken ters vekil kurun. Vekilinize ek CORS başlığı eklemeyin |
Çağrı hataları
| Belirti | Olası neden | Çözüm |
|---|---|---|
404 ve JSON module_disabled (module alanı) | Ürün modülü ortamda kapalı | Panelde modülü açın (modüller) |
404 not found | Kaynak yok, silinmiş ya da yanlış ortam | Kimliği ve ortamı kontrol edin |
400 “Idempotency-Key zorunlu” benzeri mesaj | Anahtar zorunlu uçta başlık yok ya da boş/200+ karakter | Başlığı ekleyin (idempotency) |
400 “geçerli UUID olmalı” | Klan, grup ya da turnuva ucunda anahtar UUID değil | UUID v4 üretin |
400 If-Match hatası | *, W/"3", negatif ya da sayısal olmayan değer | Tam sürüm numarası gönderin (3 ya da "3") |
409 version conflict | Kaynak siz okuduktan sonra değişti | Yeniden okuyun, yeni sürümle tekrar edin |
409 idempotent request in progress | Aynı anahtarlı istek hâlâ işleniyor | Kısa süre sonra aynı anahtarla tekrar edin |
422 idempotency mismatch | Aynı anahtarı farklı gövdeyle kullandınız | Her farklı işlem için yeni anahtar; aynı işlemin tekrarında gövdeyi değiştirmeyin (anahtarın ortam genelinde benzersiz olduğunu unutmayın) |
422 unprocessable: … | İş kuralı reddi (bakiye, stok, limit) | Durumu okuyup kullanıcıya gösterin; aynı isteği tekrarlamayın |
410 | Anahtarın 24 saatlik kayıt süresi doldu | Durumu okuyup işlem uygulanmadıysa yeni anahtarla yeniden başlatın |
413 | Gövde 2 MiB üstü | Gövdeyi küçültün; görsel için görsel yükleme ucunu kullanın |
429 | Oran sınırı ya da kural bütçesi | Bekleyip aynı anahtarla tekrar edin; kural bütçesi için kuralı sadeleştirin |
503 ve Retry-After: 30 | Ortamın yerleşimi geçici kullanılamıyor | Retry-After kadar bekleyip tekrar edin |
Büyük sayı bozuk (9007199254740993 yerine 9007199254740992) | JSON’u JSON.parse ile okudunuz; int64 JS number’ına sığmadı | SDK’nın bigint okumasını ya da lossless-json kullanın (sayılar) |
Contract türünde SDK hatası | Yanıt, SDK’nın bildiği şemaya uymuyor (sunucu daha yeni) ya da yanıt 2 MiB üstü | SDK’yı güncelleyin; sunucu ve SDK sürümlerini eşleştirin |
Eklentiler
| Belirti | Olası neden | Çözüm |
|---|---|---|
403 ve forbidden | Eklenti ortamda etkin değil (salt okunur, boşaltılıyor, kapalı) ya da ortamın eklenti sürümü sunucudakiyle uyuşmuyor; CSRF/Origin reddi | Panelde eklentinin durumuna ve sürümüne bakın (Eklentiler) |
400 ve invalid_argument (“x-crx-schema-version is required”) | x-crx-schema-version başlığı yok ya da şema sürümü yanlış; yük şemaya uymuyor; sorguda aynı parametre iki kez | İşlemin schemaVersion değerini ve girdi şemasını şema belgesinden doğrulayın |
404 ve not_found | Eklenti kimliği ya da mesaj türü yanlış; mesaj türü ile işlem adını karıştırdınız | Şema belgesindeki requestMessageType değerini yola yazın |
409 idempotency_in_flight | Aynı anahtarlı komut işleniyor | retryable: true; bekleyip aynı anahtarla tekrar edin |
422 unprocessable + reason | Eklenti iş kuralı reddi | reason eklentiye özgü koddur; eklentinin belgesine bakın; tekrar etmek işe yaramaz |
| Komut sonucu belirsiz | Ağ koptu | …/result?idempotency_key=… ile sorgulayın ya da aynı anahtarla tekrar edin (eklentileri çağırma) |
SDK upgrade_required (plugin_binding_mismatch) | Bağlamanın sabitlemesi (pin) elinizdeki beklentiyle ya da sunucudaki belgeyle uyuşmuyor | Güncel belgeyi alıp bağlamayı yeniden üretin (bağlamalar) |
Üretilmiş bağlamada Cannot find module '@open-play/sdk/player' | Üretici içe aktarımı @open-play/sdk adıyla yazar; yayımlanan paketin adı @ferdiunal/open-play-ts’tir | package.json’da takma ad tanımlayın: "@open-play/sdk": "npm:@ferdiunal/open-play-ts@<sürüm>" |
crx plugins generate hatası: CRX TYPES FAIL | Özet uyuşmuyor, çıktı dosyası zaten var, çıktı klasörü yok ya da yolda sembolik bağ var | Özeti belgedeki schemaSha256 ile eşleyin; mevcut çıktıyı silin; klasörü oluşturun |
Realtime
| Belirti | Olası neden | Çözüm |
|---|---|---|
Bilet isteği 403 | Kimlik, CSRF, Origin ya da x-crx-env hatası (hepsi aynı yanıtı alır) | CSRF ve Origin kontrol edin; oyunun alan adı ortam alan adı listesinde olmalıdır |
Yükseltme 401 | Sorgu dizesi var, openplay.realtime.v1 alt protokolü istenmedi ya da Origin izinli değil | Protokol: soketi aç |
Hemen AuthenticationFailed ve kapanma | Bilet kullanılmış (tek kullanım), 30 sn dolmuş ya da farklı Origin’den alınmış; 5 sn içinde Authenticate gelmedi | Her bağlantıda yeni bilet; soket açılınca hemen Authenticate gönderin |
UnexpectedFrame | Yanlış fazda çerçeve (kimlik doğrulamadan önce Join, ikinci Authenticate) | Sırayı protokole göre kurun |
InvalidPayload | Bozuk JSON, bilinmeyen alan, şemaya uymayan yük, int64 sayı olarak gönderildi | Sayaçları ondalık metin gönderin; yükü şemaya göre doğrulayın |
CapacityExceeded ve kapanma | Çerçeve hızı 40/sn üstü; oyuncu başına 4 ya da adres başına 8 soket | Gönderimi azaltın; eski sekmeleri kapatın |
Soket 5 dakikada kapanıyor (4100) | Boşta kapanma | “Devam et” akışı; canlı tutma girdisi (limitler) |
Girdiler Ack: Stale | Aynı oyuncunun daha yeni bir soketi açıldı | Eski soketi kapatın; tek soketle çalışın |
ResyncRequired döngüsü | Süresi geçmiş ya da boşluklu imleçle ısrar | İmleci atın, imleçsiz Join edin |
/v1/ws ya da /v1/chat/ws tarayıcıda 401 | Bu iki soket yükseltmede x-crx-env başlığı ister; tarayıcı başlık ekleyemez | Tarayıcıda REST kullanın (realtime genel bakış) |
Webhook’lar
| Belirti | Olası neden | Çözüm |
|---|---|---|
| Uç noktama hiç istek gelmiyor | Uç nokta kayıtlı değil, silinmiş ya da devre dışı; olay türü abone listesinde yok; webhooks modülü kapalı (teslimatlar yerinde bekler, veri silinmez); uç nokta herkese açık değil | Panelde uç noktayı ve modülü kontrol edin (Webhook ve olay kuyruğu) |
Kayıt 400 | Adres https değil; özel/loopback IP ya da kullanıcı bilgisi içeriyor | Genel erişilebilir https adres verin (güvenlik) |
| İmza uyuşmuyor | Gövdeyi ayrıştırıp yeniden serileştirdiniz (ham bayt gerekir); gizli anahtar yanlış (whsec_… metnin kendisi, base64 değil); t. önekini unuttunuz | Ham gövdeyi doğrulayın; örnek: güvenlik |
| Zaman damgası reddi | Sunucunuzun saati sapmış | Saati NTP ile eşitleyin; pencereyi 5 dakikada tutun |
| Aynı olay iki kez geldi | Teslimat en az bir kez (at-least-once) | X-Crx-Event-Id ile tekilleştirin |
Teslimatlar failed | 10 denemede 2xx alınamadı | Alıcı hatasını giderin. Panel teslimatları yalnız izlemek içindir (yeniden gönderme/replay eylemi yoktur); kaçırılan olayların etkisini ilgili kaynağı REST ile okuyarak telafi edin |
| Büyük olay gelmedi | Gövde 64 KiB üstü gönderilmez | Olay boyutunu küçültün |
Unity
| Belirti | Olası neden | Çözüm |
|---|---|---|
| Paket kurulmuyor | ~/.upmconfig.toml ya da kapsamlı kayıt defteri yapılandırması eksik; belirteçte read:packages yok | Unity SDK kurulum adımları |
| WebGL’de istekler engelleniyor | Oyun ve API aynı kökende değil; Unity WebGL SDK’sı bugün aynı kökeni şart koşar | Aynı köken ters vekil kurun (Unity SDK) |
UpgradeRequired (plugin_binding_mismatch) | Pakete gömülü package-ride bağlaması sunucudakiyle uyuşmuyor | SDK’yı güncelleyin |
| Çalışma zamanında oturum geri yüklenmiyor | Gizli saklama varsayılanı güvenli değil (PlayerPrefs) | Unity SDK: kendi güvenli saklamanızı bağlayın |
Hâlâ çözülmediyse
- Aynı isteği
curlile (gizli değerleri koruyarak) tekrarlayın; sorun SDK’da mı, ağda mı, sunucuda mı ayırın. - Durum kodunu hata referansında bulun.
- Üretim kontrol listesindeki ağ maddelerini (başlık iletimi, istemci IP’si, HTTPS) gözden geçirin.
- Destek talebine yukarıdaki bilgileri ekleyin.
Sık sorulan sorular
Bu sayfa, entegrasyonda en sık gelen soruları kısa yanıtlarla toplar. Ayrıntı için bağlı sayfalara geçin.
Başlangıç ve topoloji
Sunucu anahtarını oyunun içine koyabilir miyim? Hayır. Sunucu anahtarı yalnız sizin sunucunuzdadır. Oyun istemcisi oyuncu oturumuyla çalışır; istemciye gömülen anahtar gerekiyorsa istemci anahtarı vardır, ama onun da çağırabildiği uçlar sınırlıdır ve bazı uçlarda anahtar türü kapısı yoktur (güvenlik, uç noktalar).
Neden CORS hatası alıyorum?
Oyunun alan adı bir ortamın alan adı listesinde (ya da operatörün genel izinli listesinde) değilse sunucu o origin’e CORS başlığı vermez. Alan adını panelden ekleyin; origin tam https://<alan adı> olmalıdır. Oyun, Open Play’den farklı bir kayıtlı alan adındaysa oturum çerezi (SameSite=Lax) gitmez; o durumda aynı köken ters vekil kullanın. Kendi vekilinize ek CORS başlığı eklemeyin (mimari ve barındırma).
Oyunum mobil uygulama ya da Unity masaüstü; tarayıcı kısıtları geçerli mi?
CORS ve aynı site kuralı yalnız tarayıcıyı ilgilendirir. Tarayıcı dışı istemciler çerez yerine Bearer oturum jetonu kullanabilir; ama eklenti komutlarında CSRF çifti ve realtime bilet isteğinde Origin gibi kurallar yine geçerlidir (eklentileri çağırma, protokol). Unity için Unity SDK.
Open Play’in gRPC arayüzünü kullanabilir miyim? Dışa açık bir yüzey olarak desteklenmiyor. Oyun entegrasyonları REST, WebSocket ve SDK’lar üzerindendir.
Hangi SDK’lar var?
TypeScript (@ferdiunal/open-play-ts) ve Unity (com.openplay.sdk). Tipli CrxClient’ı olmayan modüller için ham REST kullanırsınız (uç noktalar). Ayrıntı TypeScript SDK ve Unity SDK sayfalarında.
Kimlik
Sunucu bir oyuncunun kim olduğunu nasıl doğrular? Oyuncu girişinde dönen erişim JWT’sini oyun sunucunuz JWKS ile çevrimdışı doğrular (sunucu doğrulaması). Oturum jetonu ya da çerez değildir.
Oturum ne kadar yaşar? 30 gün kayar (günde bir istek yeterlidir), mutlak tavan 180 gündür. Açık bir realtime soketi oturumu yaşatmaz (güvenlik).
Yasaklı oyuncuya ne olur?
Giriş uçlarında, sahiplik kanıtlandıktan sonra 403 ve account_banned alır; diğer uçlarda 401 görünür. Eklenti uçlarında 403 forbidden (message: account banned) (hatalar).
Tekrar güvenliği, sürüm, sayılar
Idempotency-Key ne zaman yeni üretilir?
Her yeni işlem için. Aynı işlemin yeniden denemelerinde aynı anahtar kullanılır; belirsiz sonuçlu komutu yeni anahtarla tekrarlamak çift uygulamaya yol açar (idempotency).
409 aldım. Aynı isteği tekrarlasam olur mu?
İki farklı 409 vardır: sürüm çakışmasında (version conflict) önce durumu yeniden okuyun; “işleniyor” (idempotent request in progress) yanıtında aynı anahtarla kısa süre sonra tekrar edin.
Bakiye neden büyük bir tam sayı? Para küçük birimli tam sayıdır; kayan nokta hiçbir yerde kullanılmaz. Gösterim ondalığını kendiniz hesaplarsınız (sayılar ve kodlama).
Neden bazı sayılar metin olarak geliyor?
Eklenti ve realtime int64 alanları JavaScript number’ının güvenli aralığını aşabilir; bu yüzden ondalık metin taşınır. TypeScript SDK’sı bunları bigint yapar.
Yüzde alanları neden 10000 üzerinden? Baz puan: 10000 = %100 (sayılar ve kodlama).
Hata gövdesi neden bazen düz metin, bazen JSON?
Çekirdek REST düz metin döner (birkaç JSON istisna), eklenti uçları her zaman JSON döner. Karar için durum koduna ve varsa code alanına bakın (hatalar).
Hız sınırları
Anahtar başına istek sınırı var mı? Hayır; genel bir kota yok. Belirli işlemlerin (giriş, kayıt, sohbet, eklenti komutları, soket bağlantısı) sınırları vardır. Büyük toplu işlerde kendi eşzamanlılık sınırınızı uygulayın (hız sınırları).
Lansmanda yüzlerce misafir aynı anda açılacak. Sorun olur mu? Misafir açma IP başına dakikada 30’dur. Oyuncular ayrı IP’lerdense sorun olmaz; ama ters vekiliniz istemci IP’sini iletmiyorsa hepsi tek kovada toplanır. IP iletimini doğrulayın ve yük testi yapın (üretim kontrol listesi).
Eklentiler
Kendi eklentimi yükleyebilir miyim? Hayır, henüz yok. Eklentiler sunucuya derlenmiş güvenilir koddur; üçüncü taraf yükleme ve yalıtım yoktur. Bugünkü yollar: kurallar, webhook’lar ve kendi sunucunuz (eklentilere genel bakış).
Eklenti şeması değişti, istemcim bozulur mu?
Eklenti şemaları özetle (schemaSha256) sabitlenir. Sunucu şemayı değiştirirse eski bağlama uyuşmazlığı görür ve güncel belgeden yeniden üretmeniz gerekir (bağlamalar).
Eklenti çağrısı 403 forbidden döndü. Neden?
Çoğunlukla eklenti ortamınızda etkin değildir ya da yetki sürümü sunucudakiyle uyuşmuyordur; ya da CSRF/Origin reddi. Panelde eklentinin durumuna bakın (Eklentiler).
Realtime
Soket kopunca ne yapmalıyım?
Yeni bilet alın, yeniden bağlanın ve kalıcı akışlarda son imleçle yeniden katılın; ResyncRequired gelirse imleçsiz katılın. TypeScript SDK’sı bunu kendiliğinden yapar (yeniden bağlanma).
Soket neden 5 dakikada bir kapanıyor?
Girdi kabul eden bir abonelikte oyuncu etkinliği gelmediği için sunucu boşta kapatır (4100). “Devam et” ekranı gösterin ya da canlı tutma girdisi gönderin.
Bildirim ve sohbet için soket kullanabilir miyim?
Tarayıcıdan doğrudan hayır: /v1/ws ve /v1/chat/ws yükseltmede x-crx-env başlığı ister ve tarayıcı bunu ekleyemez. Tarayıcıda gelen kutusunu REST ile okuyun, sohbet için REST uçlarını kullanın (realtime genel bakış).
Webhook’lar
Webhook’ları imzasız kabul edebilir miyim?
Hayır. Her isteğin imzasını ham gövde üzerinde doğrulayın ve X-Crx-Event-Id ile tekilleştirin (güvenlik).
Kaçırdığım olayı yeniden gönderebilir miyim? Panelde yeniden gönderme eylemi yoktur; teslimatlar yalnız izlenir. İlgili kaynağın durumunu REST ile okuyarak telafi edin.
Yönetim
Anahtarı kaybettim, geri alabilir miyim? Hayır; gizli değer yalnız oluşturma anında gösterilir. Yeni anahtar üretin ve eskisini iptal edin (güvenlik).
Panelde ne yapabilirim, API ile ne yapmalıyım? Panel, oyunun yönetimi içindir (içerik, mağaza, ekonomi raporları, kurallar, ayarlar). Oyun içi akışlar API ve SDK ile yapılır. Panel ekranları için ilgili panel yardım sayfalarına bakın.
Dokümanda bulamadığım bir şey var. Önce sorun giderme ve sözlüğe bakın; bulamazsanız sorunuzu durum kodu, yol ve zaman bilgisiyle iletin.
Oyun özeti
Amaç
Bu sayfa, paneli açtığınızda ilk gördüğünüz ekrandır. Seçili oyunun ve ortamın durumunu özetler; her kartın “Aç” düğmesi ilgili ayrıntı sayfasına götürür. Sayfanın başlığı “oyun adı · ortam adı” biçimindedir (örneğin “Benim Oyunum · Production”), böylece hangi ortamda çalıştığınızı her zaman görürsünüz.
Ne zaman kullanılır
- Güne başlarken oyunun genel durumuna bakmak için.
- Bir değişiklikten sonra beklediğiniz sayıların (oyuncu, karakter, kural) yerinde olduğunu doğrulamak için.
- Son işlemleri görüp kimin neyi değiştirdiğini hızlıca anlamak için.
- Güvenlik korumalarından birinin gevşek bırakılıp bırakılmadığını fark etmek için.
Adım adım
- Sol üstteki seçiciden doğru oyunu ve ortamı seçtiğinizden emin olun. Bu sayfadaki her sayı yalnızca seçili ortamı kapsar.
- Kartlara bakın. Kartın altında bir not görüyorsanız sayı alınamamıştır (aşağıdaki tabloya bakın).
- Ayrıntı için kartın Aç düğmesine basın.
- “Son işlemler” kartında en yeni altı yönetim işlemini görürsünüz. Tümü için Tüm kayıtları gör düğmesini kullanın.
Alanlar ve seçenekler
Bu sayfada doldurulacak bir form yoktur. Kartlar şunları gösterir:
| Kart | Gösterdiği | Aç düğmesi |
|---|---|---|
| Oyuncular | Seçili ortamdaki toplam oyuncu hesabı sayısı | Oyuncular |
| Oyuncu karakterleri | Karakter sayısı; liste uzunsa sayının sonunda “+” görünür | Karakterler |
| İçerik | Karakter şablonu ve eşya tanımı sayısı | İçerik |
| Kurallar | “açık kural / toplam kural” (örneğin 3/5) | Kurallar |
| Eklenti | Oyuna bağlı eklentinin durumu: Açık, Salt okunur, Drain (kapanıyor, kalan saniye ile), Yetki yok ya da Eklenti yok | Eklentiler |
“Son işlemler” kartı yalnızca denetim kaydını okuma yetkiniz varsa görünür. Her satırda işlem adı, zaman, işlemi yapan, hedef ve işlem nedeni bulunur.
Bir güvenlik koruması gevşekse sayfanın üstünde sarı bir bant çıkar (“N koruma gevşek”); durumu okunamadıysa “bilinmiyor” bandı çıkar. Şalterleri aç düğmesi güvenlik şalterleri sayfasına götürür.
Sık karşılaşılan durumlar
| Durum | Ne yapmalı |
|---|---|
| Kartta “Bu sayıyı görme yetkiniz yok.” yazıyor | Hesabınızın rolü o alanı okuyamıyor; bir yöneticiden rolünüzü genişletmesini isteyin. |
| Kartta “Sayı alınamadı.” yazıyor | Geçici bir okuma hatasıdır; sayfayı yenileyin. Sürerse sunucu durumunu kontrol edin. |
| “Bu oyunda henüz oyuncu yok” yazısı görünüyor | Oyun istemciniz henüz giriş yapmamıştır; ilk oyuncu girişinden sonra sayı güncellenir. |
| Eklenti kartında “Yetki yok” yazıyor | Eklentinin bu ortam için etkin bir izni yok; Eklentiler sayfasından durumu inceleyin. |
| Sayılar beklediğimden farklı | Başka bir ortamı seçmiş olabilirsiniz (örneğin canlı yerine geliştirme). Başlıktaki ortam adını kontrol edin. |
İlgili dokümanlar
Kullanıcılar
Amaç
Bu sayfa, seçili oyunun ve ortamın oyuncu hesaplarını listeler. Bir oyuncuyu bulmak, hesabının durumunu görmek, profiline geçmek ve gerekirse elle yeni hesap oluşturmak için kullanın. Soldaki menüde bu sayfa “Oyuncular” adıyla görünür.
Ne zaman kullanılır
- Bir oyuncunun yardım isteği geldiğinde hesabını bulmak için.
- Yasaklı ya da şüpheli hesapları süzmek için.
- Test için elle oyuncu hesabı oluşturmak için.
Adım adım
Oyuncu bulma
- Sayfanın üstündeki ortam seçiciden doğru oyunu ve ortamı seçtiğinizden emin olun. Liste yalnızca seçili ortamı gösterir.
- Tablonun arama kutusuna oyuncunun adını ya da e-postasını yazın.
- Durum, giriş yöntemi ya da tarih gibi koşullarla daraltmak için tablonun filtre menüsünü kullanın.
- Profili açmak için satıra tıklayın ya da Detay düğmesine basın.
Elle hesap oluşturma
- Kullanıcı oluştur düğmesine basın. Düğmeyi yalnızca hesap oluşturma yetkisi olan yöneticiler görür.
- Görünen adı yazın. E-posta, parola ve ek bilgiler isteğe bağlıdır.
- İşlem nedeni alanına kısa bir gerekçe yazın.
- Kullanıcı oluştur düğmesiyle kaydedin. Hesap listede görünür.
Not
Oyuncular çoğunlukla oyundan kendileri giriş yapar; bu formu yalnızca test ve destek durumlarında kullanın.
Alanlar ve seçenekler
Hesap oluşturma formu
| Alan | Zorunlu | Açıklama |
|---|---|---|
| Görünen ad | Evet | Oyuncunun görünen adı; en az 2 karakter |
| E-posta | Hayır | Oyuncunun e-posta adresi |
| E-posta doğrulandı | Hayır | Adresin doğrulanmış sayılmasını sağlar |
| Geçici parola | Hayır | En az 12 karakter; boşsa parolalı hesap oluşmaz |
| Metadata JSON | Hayır | Ek bilgiler, JSON nesnesi |
| İşlem nedeni | Evet | İşlem geçmişine yazılan gerekçe, 8-500 karakter |
Listedeki sütunlar
Kullanıcı, Durum, Giriş yöntemi, Aktif oturum, Son giriş ve Oluşturulma sütunları varsayılan olarak görünür. E-posta, Oyuncu kimliği, Hesap türü, Güncellenme ve E-posta doğrulandı sütunlarını tablonun sütun menüsünden açabilirsiniz.
Sık karşılaşılan durumlar
| Durum | Ne yapmalı |
|---|---|
| Liste boş görünüyor | Doğru ortamı seçtiğinizi ve filtrelerin kapalı olduğunu kontrol edin. |
| Oyuncuyu bulamıyorum | Misafir hesapların e-postası olmaz; adı, kimliğini ya da giriş yöntemini kullanarak arayın. |
| “Kullanıcı oluştur” düğmesi yok | Hesabınızın rolünde hesap oluşturma yetkisi yoktur; bir yöneticiden isteyin. |
| Form “metadata” hatası veriyor | Alana geçerli bir JSON nesnesi yazın; dizi ya da düz metin kabul edilmez. |
İlgili dokümanlar
Oyuncu karakterleri
Amaç
Bu sayfa seçili ortamdaki karakterleri listeler. Karakter, oyuncunun oyunda oynadığı varlıktır; durumu (seviye, özellik, kaynak) komutlarla değişir ve her değişiklik kayıt altına alınır. Bir karakteri bulmak, profiline geçmek ve gerekirse elle yeni karakter oluşturmak için kullanın. Karakter şablonları (tanımlar) bu sayfada değil İçerik sayfasındadır.
Ne zaman kullanılır
- Bir oyuncunun karakterinin durumuna bakmak için.
- Sürücü gibi belirli bir türdeki karakterleri süzmek için.
- Test ya da destek amacıyla elle karakter oluşturmak için.
Not
Karakter modülü kapalıysa bu sayfa menüde görünmez. Modülü Oyun ayarları › Modüller sayfasından açın.
Adım adım
Karakter bulma
- Doğru oyunu ve ortamı seçtiğinizden emin olun; liste yalnızca seçili ortamı gösterir.
- Üstteki Tümü, Sürücüler ve Diğer düğmeleriyle türe göre daraltın.
- Tablonun arama kutusunu ve filtre menüsünü kullanarak ad, tür, seviye ya da tarihe göre daraltın.
- Profili açmak için satıra tıklayın. Profil sayfası için bkz. Karakter profili.
Yeni karakter oluşturma
- Yeni karakter düğmesine basın. Düğmeyi yalnızca karakter oluşturma yetkisi olan yöneticiler görür.
- Tanım listesinden karakterin türünü seçin. Tanım yoksa önce İçerik sayfasından bir tanım yayınlayın.
- İsterseniz Dış kimlik alanına oyun sunucunuzdaki kimliği yazın.
- İşlem nedeni yazıp Oluştur düğmesine basın. Karakter hemen oluşturulur ve profiline geçilir.
Alanlar ve seçenekler
Yeni karakter formu
| Alan | Zorunlu | Açıklama |
|---|---|---|
| Tanım (ya da Tanım anahtarı) | Evet | Karakterin üretileceği tanım; güncel sürümü kullanılır |
| Dış kimlik | Hayır | Oyun sunucunuzla eşleştirme kimliği; aynı kimlikle ikinci karakter oluşturulamaz |
| İşlem nedeni | Evet | İşlem geçmişine yazılan gerekçe, 8-500 karakter |
Listedeki sütunlar
Oyuncu, Tür, Seviye, Puan, Teslimat, Son değişiklik ve Oluşturulma sütunları varsayılan olarak görünür. Dış kimlik ve Oyuncu kimliği sütunlarını sütun menüsünden açabilirsiniz. Oyuncusu olmayan eski yer tutucu sürücü kayıtları “Taşınmamış” rozetini taşır.
Sık karşılaşılan durumlar
| Durum | Ne yapmalı |
|---|---|
| Liste boş görünüyor | Doğru ortamı seçtiğinizi ve filtrelerin kapalı olduğunu kontrol edin. |
| “Bu ortamda henüz tanım yok” yazıyor | Karakter bir tanımdan üretilir. İçerik sayfasından bir tanım yayınlayıp geri dönün. |
| “Bu anahtarla yayınlanmış bir tanım yok” hatası | Tanım anahtarı yanlış ya da yayınlanmamış. Listeden seçin ya da tanımı yayınlayın. |
| “Bu dış kimlikle zaten bir karakter var” hatası | Başka bir dış kimlik girin ya da alanı boş bırakın. |
| “Yeni karakter” düğmesi yok | Hesabınızın rolünde karakter oluşturma yetkisi yoktur; bir yöneticiden isteyin. |
İlgili dokümanlar
Klanlar
Amaç
Bu sayfa seçili ortamdaki klanları listeler ve seçtiğiniz klanın ayrıntısını gösterir: klan ayarları, üyeler, davetler, başvurular, klan kasası (hazine) transferleri ve tamamlanmış komut kayıtları. Sayfa salt okunurdur; panelden klan oluşturamaz, üye ekleyemez ya da kasadan para çekemezsiniz. Klan işlemleri oyundan, sunucu çağrılarıyla yapılır.
Ne zaman kullanılır
- Bir klanın üyelerini, liderini ve seviyesini görmek için.
- Bir oyuncunun klan kasasına yatırdığı ya da çektiği tutarı doğrulamak için.
- Bir başvuru ya da davetin durumunu incelemek için.
Adım adım
- Doğru oyunu ve ortamı seçtiğinizden emin olun. Liste yalnızca seçili ortamı gösterir.
- “Klan atlası” tablosunda ada, etikete, duruma, seviyeye ya da tarihe göre arayın ve süzün.
- Ayrıntıyı açmak için klanın adına tıklayın ya da satırı açın. Sayfa ilk açıldığında en yeni klan otomatik seçilir.
- “Klan detay ve ilişkiler” kartında üyeleri, davetleri, başvuruları, kasa transferlerini ve komut kayıtlarını görürsünüz. Uzun tablolar sayfalanır.
- Bir oyuncunun profiline geçmek için tablodaki oyuncu bağlantısını kullanın.
Alanlar ve seçenekler
Bu sayfada doldurulacak bir form yoktur.
Listedeki sütunlar
Klan (ad ve köşeli parantez içinde etiket), Durum, Seviye, XP, Üye, Oluşturulma varsayılan olarak görünür. Etiket, Lider ve Güncellenme sütunlarını sütun menüsünden açabilirsiniz. Durum “active” (etkin) ya da “disbanded” (dağıtılmış) olur.
Ayrıntı kartları
| Kart | İçerik |
|---|---|
| Klan ayarları | Ortamın klan kuralları; yalnızca okunur |
| Üyeler | Oyuncu, rol, katılım ve ayrılış zamanı. Ayrılmış üyeler de listelenir ve “Ayrıldı” rozetiyle işaretlenir |
| Davetler | Davet edilen oyuncu, durum ve son geçerlilik |
| Başvurular | Başvuran oyuncu, durum ve oluşturulma zamanı |
| Kasa transferleri | Yatırma ya da çekme, miktar, işlemi yapan oyuncu, bakiyeler ve para birimi. Tutarlar metin olarak gösterilir |
| Komut geçmişi | Tamamlanmış komutun türü, istek özeti (hash) ve zamanı; yanıt gövdesi gösterilmez |
Sık karşılaşılan durumlar
| Durum | Ne yapmalı |
|---|---|
| Liste boş görünüyor | Doğru ortamı seçtiğinizi ve filtrelerin kapalı olduğunu kontrol edin. |
| Üye sayısı ile satır sayısı uyuşmuyor | Ayrılmış üyeler de listelenir; “Ayrıldı” rozetli satırlar aktif üye sayısına girmez. |
| Panelden klanı düzenleyemiyorum | Sayfa salt okunurdur; klan işlemleri oyundan ya da sunucu çağrılarıyla yapılır. |
| “Bu sayıyı görme yetkiniz yok” benzeri bir uyarı çıkıyor | Rolünüzün klan okuma yetkisi yoktur; bir yöneticiden isteyin. |
İlgili dokümanlar
Partiler
Amaç
Bu sayfa seçili ortamdaki partileri listeler; seçtiğiniz partinin üyelerini, davetlerini ve bir ödül dağıtımının sonucunu gösterir. Sayfa salt okunurdur: panelden parti kuramaz, üye çıkaramaz ya da ödül dağıtamazsınız. Parti işlemleri oyundan, sunucu çağrılarıyla yapılır.
Ne zaman kullanılır
- Bir partinin üyelerini, liderini ve ganimet kuralını görmek için.
- Bir oyuncunun neden partiye giremediğini, davet durumuna bakarak anlamak için.
- Bir ödül dağıtımının tutarını, durumunu ve teslim biçimini doğrulamak için.
Adım adım
Parti inceleme
- Doğru oyunu ve ortamı seçtiğinizden emin olun.
- “Party roster” tablosunda durum, kapasite, ganimet kuralı ya da tarihe göre süzün. Sayfa açıldığında en yeni parti otomatik seçilir.
- Başka bir partiyi seçmek için adına tıklayın ya da satırı açın.
- “Party detay ve ilişkiler” kartında lideri, ganimet kuralını, kapasiteyi, üyeleri ve davetleri görürsünüz.
Ödül dağıtımı sorgulama
- Bir parti seçili olsun.
- “Reward distribution lookup” kartındaki Dağıtım kimliği alanına dağıtımın UUID’sini yapıştırın.
- Yükle düğmesine basın. Kimlik geçerli bir UUID değilse istek gönderilmez ve alanın yanında hata görünür.
- Sonuç olarak miktar, durum ve teslim biçimi görünür. Ham ödül içeriği gösterilmez.
Alanlar ve seçenekler
| Alan | Zorunlu | Açıklama |
|---|---|---|
| Dağıtım kimliği | Evet (Yükle için) | Ödül dağıtımının UUID kimliği; seçili partiye aittir, parti değişince alan sıfırlanır |
Listedeki sütunlar
Party (kısaltılmış kimlik), Durum, Üye (“üye sayısı/kapasite”), Ganimet kuralı, Lider ve Oluşturulma varsayılan olarak görünür. Kapasite ve Güncellenme sütunlarını sütun menüsünden açabilirsiniz. Durum “active” ya da “disbanded”, ganimet kuralı “equal” (eşit) ya da “weighted” (ağırlıklı) olur. Üye ve davet tablolarında “Pay” sütunu her kaydın ödül payını yüzde olarak gösterir.
Sık karşılaşılan durumlar
| Durum | Ne yapmalı |
|---|---|
| Liste boş görünüyor | Doğru ortamı seçtiğinizi ve filtrelerin kapalı olduğunu kontrol edin. |
| “Dağıtım kimliği 8-4-4-4-12 biçiminde olmalı” hatası | Kimliği eksiksiz ve tireli kopyalayın; başında ya da sonunda fazladan karakter olmasın. |
| Dağıtım bulunamıyor | Kimlik başka bir partiye ya da ortama ait olabilir; doğru partiyi seçtiğinizden emin olun. |
| Panelden partiyi değiştiremiyorum | Sayfa salt okunurdur; parti işlemleri oyundan ya da sunucu çağrılarıyla yapılır. |
İlgili dokümanlar
Şehir sohbeti
Amaç
Bu sayfa, oyunun şehir sohbetine yazılan mesajları gösterir ve moderasyon yapmanızı sağlar: zararlı bir mesajın metnini silebilir, mesajı yazan oyuncuyu süreli susturabilir ve aktif susturmaları kaldırabilirsiniz. Mesaj metni düz metin olarak gösterilir. Mesajlar 30 gün saklanır, sonra otomatik silinir.
Ne zaman kullanılır
- Bir oyuncu hakkında sohbetle ilgili şikâyet geldiğinde mesajı bulup incelemek için.
- Küfür, spam ya da zararlı bir mesajı silmek için.
- Kural ihlali yapan bir oyuncuyu bir süre susturmak için.
Not
Bu sayfa yalnızca seçili oyunun bağlı eklentisi sahne sohbeti sunuyorsa çalışır. Sunmuyorsa “Bu oyunda sahne sohbeti yok” yazısı görünür. Menüde de yalnızca böyle oyunlarda görünür.
Adım adım
Mesajı silme
- Aktarım sekmesinde mesajı bulun. Tabloyu oda, yazar, hesap türü, silinmiş mi ve zamana göre süzebilirsiniz; en yeni mesaj üstte durur.
- Satırdaki Sil düğmesine basın.
- İşlem nedeni yazıp Mesajı sil düğmesiyle onaylayın. Mesajın metni silinir; uzunluğu kayıtta kalır ve satırda “Silindi · N karakter” görünür. Bu işlem geri alınamaz.
Oyuncuyu susturma
- Mesajın satırında Yazarı sustur düğmesine basın.
- Süre listesinden süreyi seçin. “Özel bitiş…” seçerseniz bitiş anını girin.
- İşlem nedeni yazın ve Sustur düğmesine basın. Oyuncunun mesajları reddedilir; oyuncuya neden iletilmez ve oturumu düşmez.
Susturmayı kaldırma
- Aktif susturmalar sekmesini açın. Süresi dolan susturmalar kendiliğinden listeden çıkar.
- Satırdaki Susturmayı kaldır düğmesine basın, nedeni yazıp onaylayın. Oyuncu hemen yeniden yazabilir.
Uyarı
Misafir hesap yeni bir misafir oluşturularak susturmayı aşabilir. Kalıcı çözüm hesabı yasaklamaktır; bunun için Oyuncu profili sayfasındaki “Banla” işlemini kullanın.
Alanlar ve seçenekler
Susturma penceresi
| Alan | Zorunlu | Açıklama |
|---|---|---|
| Süre | Evet | 5 dakika, 1 saat, 24 saat, 7 gün ya da Özel bitiş |
| Bitiş anı | Yalnız özel sürede | Gelecekte olmalı, en çok 30 gün sonra |
| İşlem nedeni | Evet | 8-500 karakter |
Mesaj silme ve susturmayı kaldırma pencerelerinde yalnızca İşlem nedeni alanı vardır.
Tablo sütunları
Aktarım: Zaman, Yazar (hesap türü rozetiyle: Misafir ya da Kayıtlı), Oda, Mesaj ve Eylemler. Hesap türü, Silindi, Uzunluk ve Oyuncu kimliği sütunları sütun menüsünden açılır. Aktif susturmalar: Oyuncu, Bitiş (kalan süreyle), Gerekçe, Susturan ve Eylem.
Sık karşılaşılan durumlar
| Durum | Ne yapmalı |
|---|---|
| “Bu oyunda sahne sohbeti yok” yazıyor | Seçili oyunun eklentisi sahne sohbeti sunmuyor; sahne bildiren bir eklenti bağlanınca sayfa çalışır. |
| Sil ve Sustur düğmeleri görünmüyor | Rolünüzün sohbet yazma yetkisi yoktur; yalnızca okuyabilirsiniz. |
| Özel bitiş hata veriyor | Bitiş gelecekte olmalı ve 30 günden uzak olmamalı. |
| Eski mesajı bulamıyorum | Mesajlar 30 gün sonra otomatik silinir. |
| Susturulan oyuncu yeniden yazıyor | Misafir hesap yeni bir misafir açmış olabilir; hesabı yasaklamayı düşünün. |
İlgili dokümanlar
Oyuncu organizasyonları
Amaç
Bu sayfa, oyuncuların kurduğu organizasyonları listeler ve seçtiğiniz organizasyonun üyelerini, davetlerini, takımlarını ve rollerini yönetmenizi sağlar. Organizasyon bir stüdyo değildir; stüdyolar için Stüdyolar ve oyunlar sayfasını kullanın.
Uyarı
Bu ekran kullanımdan kalkıyor. Çalışmaya devam eder ve menüde varsayılan olarak gizlidir; yeni işlerde oyuncu grupları için Klanlar kullanılmalıdır.
Ne zaman kullanılır
- Mevcut organizasyonlara üye, davet, takım ya da rol eklemek için.
- Bir organizasyonu düzeltmek ya da kaldırmak için.
- Eski bir kurulumun organizasyon verisini incelemek için.
Adım adım
Organizasyon oluşturma
- Organizasyon oluştur düğmesine basın. Düğmeyi yalnızca organizasyon yazma yetkisi olan yöneticiler görür.
- Ad ve Plan alanlarını doldurun.
- İşlem nedeni yazıp kaydedin. Organizasyonun sayfası açılır.
Üye davet etme
- Organizasyon sayfasında Üyeler ya da Davetler sekmesinde Davetle üye ekle ya da Davet oluştur düğmesine basın.
- E-posta, rol ve son geçerlilik tarihini girin; nedeni yazıp kaydedin.
- Davet Davetler sekmesinde görünür. Süresi dolmuş ya da beklemede olan daveti Yeniden gönder ile yeni bir son tarihle yenileyebilir, bekleyen daveti İptal ile kullanılamaz yapabilirsiniz.
Not
Panel yalnızca davet kaydını oluşturur ve yönetir; davet e-postasını göndermez.
Üye rolünü değiştirme
- Üyeler sekmesinde üyenin satırındaki Düzenle düğmesine basın.
- Yerleşik rolü seçin, gerekirse dinamik rolleri ekleyin, nedeni yazıp kaydedin.
- Üyeyi çıkarmak için satırdaki Çıkar düğmesini kullanın; onay için üyenin adını (yoksa e-postasını) yazarsınız.
Takım ve rol yönetimi
- Takımlar sekmesinde Takım oluştur ile takım ekleyin; Üye düğmesiyle organizasyon üyelerinden birini takıma ekleyin.
- Roller sekmesinde Dinamik rol oluştur ile yeni rol ekleyin. Yerleşik roller (“Built-in”) silinemez ve adı değiştirilemez.
Alanlar ve seçenekler
| Alan | Pencere | Açıklama |
|---|---|---|
| Ad, Plan | Organizasyon | Ad ve plan metni (plan en çok 64 karakter) |
| Built-in rol, Dinamik roller | Üyeyi düzenle | Yerleşik rol ve ek dinamik roller |
| E-posta, Rol, Son geçerlilik | Davet | Rol admin ya da member; geçerlilik en çok 30 gün |
| Yeni son geçerlilik | Daveti yeniden gönder | Yeni son tarih |
| Takım adı | Takım | Takımın adı |
| Oyuncu | Takıma üye ekle | Organizasyon üyelerinden biri |
| Rol adı, Permissions JSON | Dinamik rol | Rol adı ve izin nesnesi |
| İşlem nedeni | Hepsi | 8-500 karakter |
| Onay metni | Silme ve çıkarma | Kaydın adını aynen yazın; ad yoksa “SİL” yazılır |
Sık karşılaşılan durumlar
| Durum | Ne yapmalı |
|---|---|
| Sayfayı menüde göremiyorum | Kullanımdan kalktığı için varsayılan olarak gizlidir; hesap menünüzdeki “Gizlenen eski ekranları göster” anahtarını açın ya da adresi doğrudan kullanın. |
| Davet “geçerlilik” hatası veriyor | Son tarih gelecekte olmalı ve 30 günü aşmamalı. |
| “Permissions JSON” hatası | İzin nesnesi { "kaynak": ["eylem"] } biçiminde olmalı; eylemler boş ve yinelenen olamaz. |
| Oyuncuyu takıma ekleyemiyorum | Yalnızca organizasyonun üyeleri takıma eklenebilir; önce üye olarak ekleyin. |
| Yerleşik rolü silemiyorum | Yerleşik roller silinemez; yalnızca dinamik roller silinir. |
İlgili dokümanlar
Oturum merkezi
Amaç
Bu sayfa, seçili ortamdaki oyuncuları açık oturum sayılarıyla birlikte listeler. Oturum, oyuncunun giriş yaptığı bir cihaz ya da tarayıcıdır. Burada yalnızca özet görürsünüz; cihaz bilgisini görmek ve oturumları kapatmak için oyuncunun profiline geçersiniz. Sayfa menüde yer almaz; Oyuncular sayfasındaki oturum merkezi bağlantısıyla açılır.
Ne zaman kullanılır
- Hangi oyuncuların açık oturumu olduğunu görmek için.
- Çok sayıda açık oturumu olan ya da uzun süredir girmemiş hesapları bulmak için.
- Bir oyuncunun oturumlarını kapatmak üzere profiline gitmek için.
Adım adım
- Doğru oyunu ve ortamı seçtiğinizden emin olun.
- Tabloyu durum ve açık oturum sayısına göre sıralayın ya da süzün.
- Oyuncunun oturumlarını görmek ve kapatmak için satırdaki Oturumları yönet düğmesine basın. Oyuncu profili açılır; Oturumlar sekmesinde tek tek oturumları, Diğer işlemler menüsünde “Tüm oturumları kapat” işlemini bulursunuz.
Alanlar ve seçenekler
Bu sayfada doldurulacak bir form yoktur. Sütunlar: Kullanıcı, Durum, Aktif oturum, Son giriş ve Güvenlik. Oluşturulma sütununu sütun menüsünden açabilirsiniz.
Sık karşılaşılan durumlar
| Durum | Ne yapmalı |
|---|---|
| Oturumu bu sayfadan kapatamıyorum | Sayfa yalnızca özettir; kapatma işlemi oyuncu profilindedir. |
| Oturumları kapatma seçeneği görünmüyor | Rolünüzün oturum iptal yetkisi yoktur; bir yöneticiden isteyin. |
| Oyuncu yeniden giriş yapabildi | Oturumları kapatmak girişi engellemez; girişi engellemek için hesabı yasaklayın. |
İlgili dokümanlar
İçerik
Amaç
Bu sayfa, oyununuzun içeriğini gruplar halinde toplar: araçlar, NPC’ler, silahlar gibi. Her grup, sizin tanımladığınız alanlardan (sayı, metin, renk, 3D model…) oluşan bir şemaya ve o şemayla doldurulan kayıtlara sahiptir. Oyun içeriği yalnızca yayınladığınız hâliyle görür; taslakta yaptığınız değişiklik, yayınlayana kadar oyuncuya yansımaz.
Ne zaman kullanılır
- Oyununuza yeni bir tür içerik (örneğin araçlar) eklemek için ilk grubu kurarken.
- Bir grubun kayıtlarını değiştirip oyuna göndermek (yayınlamak) için.
- Daha önce yayınladığınız bir hâle geri dönmek için.
Adım adım
Yeni grup oluşturma
- Yeni grup düğmesine basın. Düğmeyi yalnızca içerik yazma yetkisi olan yöneticiler görür.
- Boş bir grupla başlayabilir ya da hazır şablonlardan birini seçebilirsiniz; şablon yalnızca alan önerisi doldurur, kayıt oluşturmaz.
- Grup adını, simgesini ve açıklamasını yazıp Devam: alanlar ile alanları kurun. Ayrıntılar için Grubu düzenle sayfasına bakın.
Kayıtları değiştirme ve yayınlama
- Grup kartına tıklayın; kayıtların listesi açılır. Kartlar ya da tablo görünümü arasında geçebilirsiniz.
- Bir kaydı açın, Düzenle ile değiştirin ve Taslağı kaydet deyin. Değişiklik yalnızca taslaktadır. Ayrıntılar için Kayıt sayfasına bakın.
- Listenin üstündeki Yayınla düğmesine basın. Açılan pencere neyin oyuna gideceğini kayıt kayıt gösterir; Engelleyici satırları varsa önce onları düzeltmeniz gerekir, Uyarı satırları yayını durdurmaz.
- İsterseniz “Ne değişti?” notunu yazın ve yayınlayın.
Eski bir yayına dönme
- Kayıt listesinde Geçmiş düğmesine basın.
- Dönmek istediğiniz yayının yanındaki Farkı gör ile neyin değişeceğine bakın.
- Bu hale geri dön deyin. Bu işlem yeni bir yayın oluşturur; taslağınıza dokunmaz.
Önerilen gruplar
Bir eklenti kendi içeriğini hazır sunuyorsa sayfanın üstünde Önerilen bölümü çıkar. Kur düğmesi o grubu bugünkü değerlerle oluşturur; sonra istediğiniz gibi düzenleyebilirsiniz.
Alanlar ve seçenekler
| Alan | Nerede | Açıklama |
|---|---|---|
| Ara | Kayıt listesi (kart görünümü) | Kayıt adı ya da anahtarıyla arar |
| Taslak değişikliği olanlar | Kayıt listesi (kart görünümü) | Yalnızca yayınlanmamış değişikliği olan kayıtları gösterir |
| Ne değişti? | Yayınla penceresi | İsteğe bağlı yayın notu, en çok 280 karakter |
Sayfadaki bölümler
- Önerilen: Eklentilerin sunduğu hazır gruplar.
- Gruplarınız: Sizin oluşturduğunuz gruplar; kartta kayıt sayısı, son yayın zamanı ve “N yayınlanmamış değişiklik” rozeti görünür.
- Yerleşik içerik: Karakter ve eşya tanımları gibi sistemin kendi grupları. Bunlarda yayın adımı yoktur: kaydedince hemen oyunda geçerli olur. Kartlar Karakter şablonları sayfasına gider.
- 3D model kütüphanesi: 3D modeller sayfasına bağlantı. Sahneler modülü kapalıysa bağlantı yerine nedeni yazılır.
Sık karşılaşılan durumlar
| Durum | Ne yapmalı |
|---|---|
| “Yeni grup” düğmesi yok | Hesabınızın rolünde içerik yazma yetkisi yoktur; bir yöneticiden isteyin. |
| Yayınla düğmesi çalışmıyor, “Engelleyici” görüyorum | Engelleyici satırındaki bağlantıyla ilgili kaydı açın ve eksik ya da hatalı değeri düzeltin. |
| Oyuncular yaptığım değişikliği görmüyor | Değişiklik taslakta kalmıştır; grubu Yayınla. |
| 3D model kütüphanesi bağlantısı görünmüyor | Sahneler modülü bu ortamda kapalıdır; Oyun ayarları içindeki modüller sekmesinden açın. |
İlgili dokümanlar
Karakter şablonları
Amaç
Bu sayfa, oyunun karakter ve eşya kalıplarını tutar. Dört bölümden oluşur: karakter tanımları, eşya tanımları, seviye eğrileri ve özellikler. Karakter tanımı bir karakterin hangi özelliklerle ve hangi seviye eğrisiyle doğacağını belirler; eşya tanımı oyunda verilebilen her eşyanın kalıbıdır. Bir kalıbı değiştirdiğinizde eski sürüm silinmez; yeni sürüm yayınlanır.
Ne zaman kullanılır
- Yeni bir eşya (silah, tüketilebilir, kozmetik…) tanımlamak için.
- Karakterlerin hangi özelliklerle doğacağını değiştirmek için.
- Seviye başına gereken XP’yi ayarlamak için.
- Bir tanımın yayınlamadan önce geçerli olup olmadığını denemek için.
Adım adım
Yeni eşya ekleme
- Eşya tanımları bölümünde Yeni silah’a basın. Düğmeyi yalnızca ilgili yazma yetkisi olan yöneticiler görür. Silah ayrı bir tür değildir: “Silah / ekipman” türüdür; formdan türü değiştirebilirsiniz.
- Temel bilgiler: ad, anahtar, tür; eşya yığınlanıyorsa en çok yığın.
- Ticaret: takas edilebilirlik ve NPC alış ile satış fiyatları.
- Görünüm (3D): isterseniz yayınlanmış bir model seçin.
- Oyun verisi: oyunun okuyacağı ek değerleri satır satır ekleyin.
- Kayıt: bir neden yazıp kaydedin. Eşyanın sistem bilgileri ve ayrıntıları satıra basınca açılır.
Karakter tanımı için yeni sürüm yayınlama
- Karakter tanımları bölümünde Yeni sürüm yayınla’ya basın; ya da bir tanımı açıp Bu tanımla yeni sürüm hazırla’yı seçin.
- Anahtarı yazın ve en az bir özellik seçin.
- Gerekirse Üzerine yazılacak değerler ile özelliklerden gelen değerleri bu tanım için değiştirin.
- Görünen adı, modeli ve oyun verisini ayarlayın.
- Bir neden yazın ve yayınlayın. Panel, kaydetmeden önce yapılacak işi bir cümleyle söyler.
Not
Özellik sırası ve değerler yayın anında birleştirilir ve yeni sürüm olur. Görünen ad, model ve oyun verisi ise sürümden bağımsızdır; kaydedince hemen yansır.
Yayınlamadan deneme
Doğrula / önizle ile tanımın geçerli olup olmadığını ve birleşik hâlini hiçbir şey kaydetmeden görebilirsiniz. Seviye eğrisi bölümündeki Önizle de eğrinin en yüksek seviyesini ve bu seviye için toplam XP’yi sunucuda hesaplar.
Seviye eğrisi yayınlama
- Seviye eğrileri bölümünde Yeni sürüm yayınla’ya basın.
- Eğri anahtarını ve eğrinin JSON tanımını yazın; önce Önizle ile sonucu kontrol edin.
- Bir neden yazıp Yayınla’ya basın. Yeni sürüm eskisini değiştirmez.
Alanlar ve seçenekler
Eşya formu
| Alan | Zorunlu | Açıklama |
|---|---|---|
| Ad | Evet | Oyuncunun göreceği ad |
| Anahtar | Evet | Küçük harf, rakam, alt çizgi; kayıttan sonra sabit |
| Tür | Evet | Tüketilebilir, Silah / ekipman, Malzeme, Kozmetik, VIP kartı |
| Yığınlanabilir | Evet | Evet ya da Hayır |
| En çok yığın | Yığınlanabilirse | 1 ile 2147483647 |
| Takas edilebilir | Evet | Evet ya da Hayır |
| NPC alış fiyatı, NPC satış fiyatı | Hayır | Boşsa o yönde ticaret kapalı; 0 bedava |
| 3D model | Hayır | Yayınlanmış model |
| Değerler | Hayır | Oyun verisi satırları |
| İşlem nedeni | Evet | En az 8 karakter |
Karakter tanımı formu
| Alan | Zorunlu | Açıklama |
|---|---|---|
| Tanım anahtarı | Evet | Kayıttan sonra sabit |
| Özellik anahtarları | Evet | En az bir; sıra önemli |
| Üzerine yazılacak değerler | Hayır | Bölüm, ad, alan ve değer satırları |
| Görünen ad | Hayır | Oyunda görünen ad |
| 3D model | Hayır | Yayınlanmış model |
| Oyun verisi | Hayır | Ek değerler |
| İşlem nedeni | Evet | En az 8 karakter |
Üzerine yazma satırlarında Bölüm şunlardan biridir: Nitelikler (alanlar: Varsayılan değer, En az, En çok), Kaynaklar (Varsayılan değer, En çok (ifade), Dakikada yenilenme, Sıfıra inince) ve Türetilmiş değerler (İfade). Bir eklentinin kullandığı sistem alanları kilitlidir.
Sık karşılaşılan durumlar
| Durum | Ne yapmalı |
|---|---|
| “Yayın için en az bir özellik anahtarı yazın” | Özelliksiz sürüm tanımı boşaltır; en az bir özellik seçin. |
| “Yeni sürüm yayınla” ya da “Yeni silah” düğmesi yok | Hesabınızın rolünde ilgili yazma yetkisi yoktur; sayfa salt okunurdur. |
| Başkası aynı kaydı değiştirdi, çakışma uyarısı çıktı | Güncel hâli yükle ile son hâli görün; ya da bilerek Yine de kaydet ile üzerine yazın. |
| “Bu anahtar zaten var” | Yeni sürüm formuna var olan bir anahtar yazamazsınız; tanımı ayrıntısından Bu tanımla yeni sürüm hazırla ile düzenleyin. |
| “Sistem” rozetli kaydı silemiyorum | Bir eklentinin kullandığı sistem kaydıdır; silinmez, değişiklikler yeni sürüm olur. |
| Özellikleri bu sayfadan değiştiremiyorum | Özellikler bu ekranda yalnızca incelenir. |
| Eşya türü listesinde “silah” yok | Silah ayrı tür değildir; “Silah / ekipman” türüdür. |
İlgili dokümanlar
3D modeller
Amaç
Bu sayfa, oyununuzun kullanacağı 3D modellerin kütüphanesidir. Modeli yüklersiniz; sunucu onu oyunun okuyabileceği glb biçimine dönüştürür ve doğrular. Hazır olan modeli yayınlar ve bir eşyaya ya da karaktere bağlarsınız; oyun değişikliği, oyunu yeniden dağıtmadan görür.
Ne zaman kullanılır
- Yeni bir araç, silah ya da karakter modelini oyuna eklemek için.
- Dönüştürmesi süren ya da başarısız olan modelin durumuna bakmak için.
- Bir modelin yayınlanmış sürümünü, kullanan tanımları ya da sürüm geçmişini incelemek için (satıra tıklayın; bkz. Model profili).
Adım adım
Model yükleme
- Model yükle düğmesine basın. Düğmeyi yalnızca model yazma yetkisi olan yöneticiler görür.
- Yükleme türünü seçin: tek dosya ya da zip paket.
- Dosyayı seçin. Dosya 50 MiB’ı aşamaz.
- İsterseniz bir ad yazın. Obj, stl, 3mf, dxf dosyalarında ve zip paketlerde Birim ve Yukarı eksen de gelir; varsayılanlar dosya biçimine göre doldurulur, değerleri kontrol edin.
- Yükle’ye basın. Yükleme sırasında ilerleme çubuğu görünür; Yüklemeyi iptal et ile durdurabilirsiniz.
- Model listede Sırada ve Dönüştürülüyor durumlarından geçip Hazır olur. Liste bu süre içinde kendiliğinden yenilenir.
Modeli yayınlama
Hazır bir model hemen oyuna gitmez. Model satırını açıp Model profilindeki Sürümler tablosundan sürümü Yayınla’yın.
Not
Animasyon taşımayan biçimler (obj, stl, 3mf, dxf) listede “Bu biçim animasyon taşımaz” notuyla görünür. Bu modellere klip eklenemez.
Alanlar ve seçenekler
Yükleme formu
| Alan | Zorunlu | Açıklama |
|---|---|---|
| Yükleme türü | Evet | Tek dosya ya da zip paket |
| Dosya | Evet | En çok 50 MiB |
| Ad | Hayır | Boşsa dosya adı kullanılır, en çok 200 karakter |
| Ana dosya | Hayır | Yalnızca zip kipinde; birden çok model dosyası varsa zip içindeki yol |
| Birim | Biçime göre | Mikron, milimetre, santimetre, inç, fit, metre |
| Yukarı eksen | Biçime göre | Y yukarı ya da Z yukarı |
Liste sütunları
Ad, Biçim, Son sürüm (durumla birlikte), Yayında, Sürümler ve Eklendi sütunları varsayılan olarak görünür. Son sürüm no ve Yaşam döngüsü sütunlarını tablonun sütun menüsünden açabilirsiniz. Yaşam döngüsü: Etkin, Arşivli.
Sık karşılaşılan durumlar
| Durum | Ne yapmalı |
|---|---|
| Model “Başarısız” durumda | Modelin satırını açın; sürümün altında nedeni Türkçe cümleyle yazar (örneğin harici dosyaya başvuru ya da 2B dxf). Dosyayı düzeltip yeniden yükleyin. |
| Zip yükledim, hangi dosyanın ana dosya olduğunu bilmiyor | Ana dosya alanına model dosyasının zip içindeki yolunu yazın. |
| Model çok büyük ya da çok küçük görünüyor | Yükleme sırasında birimi yanlış seçmişsinizdir; modeli yeniden yükleyin. |
| Model yükle düğmesi yok | Hesabınızın rolünde model yazma yetkisi yoktur. |
| Dönüştürme hiç başlamıyor, “yalnız glb” uyarısı | Dönüştürücü yalnızca amd64 sunucularda çalışır; bu ortamda yalnız glb yükleyebilirsiniz. |
| Kütüphane listesi boş | Seçili oyun ve ortamı kontrol edin; Sahneler modülü kapalıysa model kütüphanesi bu ortamda kullanılamaz. |
İlgili dokümanlar
Mağaza
Amaç
Bu sayfa, oyuncuların oyun içinde satın aldığı ürünleri yönetir. Ürünler vitrinlere ayrılır: vitrin, oyunundaki bir mağaza ekranıdır (örneğin Garaj ya da Silahçı). Her ürün bir eşyayı oyun parasıyla ya da gerçek parayla satar; fiyatını, stoğunu, rozetini ve ne zaman satışta olacağını buradan ayarlarsınız.
Ne zaman kullanılır
- Oyununuza yeni bir mağaza ekranı (vitrin) eklemek için.
- Vitrine ürün koymak, fiyatını ya da stoğunu değiştirmek için (Ürün sayfası).
- Ürünleri durumuna göre süzmek, vitrinleri ve ürünleri sıralamak için.
Adım adım
Hazırlık
Bir ürünü satabilmek için önce fiyat verebileceğiniz bir para birimi ve satılacak bir eşya (İçerik ya da Karakter şablonları altında) gerekir. Eksikse sayfa bunu uyarı kutusunda söyler ve ilgili sayfaya bağlantı verir.
Vitrin oluşturma
- Yeni vitrin’e (ya da hiç vitrin yoksa İlk vitrini oluştur’a) basın. Düğmeyi yalnızca mağaza yazma yetkisi olan yöneticiler görür.
- Adı yazın; anahtar addan önerilir. Anahtar, oyunun vitrini açarken kullandığı kimliktir.
- İsterseniz açıklama ve afiş ekleyin, durumu ve satış zamanını seçin.
- Bir neden yazın (panel bir öneri doldurur) ve Vitrini oluştur’a basın.
Bir vitrini düzenlemek için vitrin sekmesini seçip Vitrini düzenle’ye basın. Düzenleme penceresinden vitrin silinebilir; silinince içindeki ürünler de silinir, geçmiş satışlar korunur.
Ürünleri görüntüleme ve sıralama
- Üstteki vitrin sekmelerinden vitrini seçin.
- Izgara ve Liste düğmeleriyle görünümü değiştirin. Liste görünümü tabloyu kendi araç çubuğuyla aratır ve süzer.
- Sırala açıkken her ürünün yanındaki düğmelerle ürünü yukarı ya da aşağı, Vitrini sola/sağa taşı ile vitrinin kendisini taşıyabilirsiniz. Sıralama açıkken süzgeçler kapalıdır.
- Ürünün ayrıntısına gitmek için kartına ya da satırına tıklayın; yeni ürün için Yeni ürün’e basın.
Araçları mağazaya ekleme
Araçlar içerik grubu yayınlanmışsa Araçları mağazaya ekle düğmesi görünür. Garaj vitrinini ve her araç için kilitli bir ürünü tek adımda hazırlar; sonuç sayfada özetlenir.
Alanlar ve seçenekler
Vitrin formu
| Alan | Zorunlu | Açıklama |
|---|---|---|
| Ad | Evet | En çok 120 karakter |
| Anahtar | Evet | Küçük harf, rakam, tire, alt çizgi; en çok 64 karakter |
| Açıklama | Hayır | En çok 500 karakter |
| Vitrin afişi | Hayır | PNG, JPEG ya da WebP görsel |
| Durum | Evet | Taslak ya da Yayında |
| Ne zaman satışta? | Evet | Hemen ya da tarih aralığı |
| Başlangıç, Bitiş | Aralıkta | Boş uç sınırsızdır |
| İşlem nedeni | Evet | 8-500 karakter |
Süzgeçler
Ara, Durum ve (dar ekranda) Vitrin. Durumlar: Yayında, Taslak, Zamanlanmış, Süresi doldu, Tükendi.
Bölümler
- Ürünler: Vitrinler ve ürünler.
- NPC tüccarları: Salt okunur liste. Mağaza ürünleri arka planda otomatik “Mağaza” tüccarını kullanır; burada bir şey yapmanız gerekmez.
- Uygulama içi ürünler: Salt okunur liste; App Store ve Google Play ürünleri. Bir mağaza ürününü bunlardan birine bağlayabilirsiniz.
Sık karşılaşılan durumlar
| Durum | Ne yapmalı |
|---|---|
| “Mağaza bu ortamda kapalı” | Mağaza modülü kapalıdır; Oyun ayarları içindeki modüller sekmesinden açın. |
| “Fiyat vermek için önce bir para birimi oluşturun” | Para birimleri sayfasından bir para birimi ekleyin. |
| “Satacak bir eşya yok” | Önce İçerik sayfasından bir eşya ekleyin. |
| Ürün oyunda görünmüyor | Ürünün ve vitrinin durumunun Yayında olduğunu ve satış zamanının geldiğini kontrol edin. |
| “Bu sırada başka biri mağazayı değiştirdi” | Mağaza kataloğu sürüm kontrolüyle yazılır; Yeniden yükle’ye basıp değişikliği tekrar yapın. |
| Vitrin anahtarını değiştirdim, oyun vitrini bulamıyor | Oyun vitrini anahtarıyla açar; oyundaki çağrıyı da yeni anahtarla güncelleyin. |
İlgili dokümanlar
Para birimleri
Amaç
Bu sayfa, oyununuzun para birimlerini listeler. Para birimi, mağazada fiyat vermek ve ödül tablolarında para vermek için kullanılan birimdir (altın, elmas, kuruş gibi). Her kartta para biriminin adı, ikonu, anahtarı, kuruş hanesi, arz tavanı ve oyuncular arası gönderilip gönderilemediği görünür.
Ne zaman kullanılır
- Mağazada fiyat vermeden ya da ödül tablosu kurmadan önce bir para birimi oluşturmak için.
- Mevcut para biriminin ayrıntısını açmak için (karta tıklayın; bkz. Para birimi).
Adım adım
- Üstteki ortam seçicisinden doğru oyunu ve ortamı seçin.
- Yeni para birimi düğmesine basın. Düğmeyi yalnızca para birimi yazma yetkisi olan yöneticiler görür.
- Açılan formu Para birimi sayfasındaki yönergeyle doldurun.
- Kaydedince para birimi listeye eklenir.
Not
Bu sayfada para birimi silmek yoktur. Aynı anahtarla yapılan her kayıt yeni bir sürüm üretir; eski sürümler değişmez.
Alanlar ve seçenekler
Bu sayfada doldurulacak bir form alanı yoktur; oluşturma formu Para birimi sayfasında anlatılır. Kartta görünen bilgiler:
| Bilgi | Açıklama |
|---|---|
| Ad ve ikon | Oyuncuların gördüğü ad ve görsel |
| Anahtar | Oyunun para birimini bulduğu kimlik |
| Kuruş hanesi | Tutarın kaç ondalık haneyle gösterileceği |
| Arz tavanı | Toplam basılabilecek miktar; yoksa “Sınırsız” |
| Gönderilebilir | Oyuncuların birbirine gönderip gönderemediği |
Sık karşılaşılan durumlar
| Durum | Ne yapmalı |
|---|---|
| “Ekonomi bu ortamda kapalı” | Ekonomi modülü kapalıdır; Oyun ayarları içindeki modüller sekmesinden açın. |
| “Henüz para birimi yok” | Yeni para birimi ile ilkini oluşturun. |
| Yeni para birimi düğmesi yok | Hesabınızın rolünde para birimi yazma yetkisi yoktur. |
İlgili dokümanlar
Ödül tabloları
Amaç
Ödül tablosu, bir NPC’nin, yaratığın, turnuvanın ya da görevin hangi ödülü hangi şansla vereceğini tanımlar. Bu sayfa ortamdaki bütün tabloları kart olarak listeler: ad, anahtar, satır sayısı, “her zaman verilen” ödül sayısı ve tablonun kaç yerde kullanıldığı görünür.
Ne zaman kullanılır
- Yeni bir ödül tablosu oluşturmak için.
- Bir tablonun nerede kullanıldığına ya da kaç satırı olduğuna hızlıca bakmak için.
- Tabloyu açıp düzenlemek, denemek ya da silmek için (karta tıklayın; bkz. Ödül tablosu).
Adım adım
- Üstteki ortam seçicisinden doğru oyunu ve ortamı seçin.
- Yeni ödül tablosu’na basın. Düğmeyi yalnızca ödül tablosu yazma yetkisi olan yöneticiler görür.
- Formu Ödül tablosu sayfasındaki yönergeyle doldurun.
- Kaydedince tablo listeye eklenir.
Not
Tablo tek başına ödül vermez. NPC, görev ya da kural tabloyu anahtarıyla çağırdığında ödül verilir; ayrıntı için Ödüller rehberine bakın.
Alanlar ve seçenekler
Bu sayfada doldurulacak bir form alanı yoktur; oluşturma formu Ödül tablosu sayfasında anlatılır. Kartta görünen bilgiler:
| Bilgi | Açıklama |
|---|---|
| Ad ve anahtar | Tablonun adı ve oyunun onu çağırdığı kimlik |
| Satırlar | Şansa bağlı ödül satırı sayısı |
| Her zaman verilen | Çekilişten bağımsız, her seferinde verilen ödül sayısı |
| Kullanım | Tablonun kaç yerde kullanıldığı; hiç kullanılmıyorsa “Kullanılmıyor” |
Sık karşılaşılan durumlar
| Durum | Ne yapmalı |
|---|---|
| “Ödüller bu ortamda kapalı” | Ödüller modülü kapalıdır; Oyun ayarları içindeki modüller sekmesinden açın. |
| “Henüz ödül tablosu yok” | Yeni ödül tablosu ile ilkini oluşturun. |
| Yeni tablo düğmesi yok | Hesabınızın rolünde ödül tablosu yazma yetkisi yoktur. |
İlgili dokümanlar
Ekonomi raporları
Amaç
Bu sayfa, oyununuzdaki paranın durumunu gösterir. Üç iş yapar: bir oyuncunun, karakterin, klanın ya da sistemin cüzdanını, envanterini ve eşyalarını sorgulatır; gerektiğinde cüzdana bakiye ekler ya da düşer; para biriminin günlük özetini, en çok bakiyesi olanları ve uyarıları, ayrıca oyuncular arası takasları gösterir.
Ne zaman kullanılır
- Bir oyuncunun parasının nereye gittiğini araştırmak için.
- Yanlış bakiyeyi düzeltmek için (destek işi).
- Paranın oyunda çok mu basıldığını ya da çok mu yakıldığını izlemek için.
- Bir takasın durumuna bakmak için.
Adım adım
Cüzdan sorgulama
- Sahip türünü seçin (oyuncu, karakter, klan ya da sistem).
- Sahibi adıyla arayıp seçin. Sistem sahibi için kimliği yazıp Sorgula’ya basın.
- Sonuçta o sahibin Cüzdanlar, Envanter ve Eşyalar bölümleri görünür. Bir cüzdan satırındaki Hareketler düğmesi o cüzdanın defter hareketlerini açar.
Not
Oyun parası oyuncunun cüzdanındadır. Karakter seçerseniz panel karakteri sahibi olan oyuncuya çözer ve bunu ekranda söyler; oyuncusuz karakter karakter olarak kalır. Oyuncu için asıl yer, oyuncu profilindeki cüzdan bölümüdür; sonuçtaki “Oyuncu profilinde aç” bağlantısı oraya götürür.
Bakiye ekleme ya da düşme
- Cüzdan satırındaki bakiye işlemi düğmesine basın. Düğmeyi yalnızca bakiye verme ya da düşme yetkisi olan yöneticiler görür.
- Tutar’ı yazın.
- İşlem nedenini yazın.
- Bakiye ekle ya da Bakiyeden düş’e basın.
Uyarı
Bakiye işlemi parayı gerçekten değiştirir ve defterde kalıcı olarak görünür; geri alınamaz, ancak ters işlemle düzeltilir. Cüzdan siz bakarken başka bir işlemle değişirse işlem reddedilir; sayfayı yenileyip tekrar deneyin.
Günlük rapor
- Günlük raporlar bölümünü açın.
- Para birimi anahtarını, Başlangıç ve Bitiş günlerini girin.
- Günlük özet, En çok bakiyesi olanlar ve Uyarılar kutuları dolar.
Not
Günlük raporlar şimdilik ham veri olarak (anahtar ve değer çiftleri) gösterilir; grafik henüz yoktur. Para birimi başına okunaklı özet için Para birimi sayfasındaki “Son 30 gün” kartına bakın.
Takaslar
Takaslar bölümü, oyuncular arası takasları toplam sayı, durum, taraf sayısı ve bacakları (verilen para ya da eşya) ile listeler.
Alanlar ve seçenekler
| Alan | Nerede | Açıklama |
|---|---|---|
| Sahip türü | Sahip sorgusu | Oyuncu, karakter, klan ya da sistem |
| Sahip (arama) | Sahip sorgusu | Ada göre arayıp seçin |
| Sahip kimliği | Sahip sorgusu | Yalnızca sistem sahibi için |
| Cüzdan kimliği | Sahip sorgusu | Cüzdanları görme yetkisi yoksa; UUID |
| Tutar | Bakiye penceresi | Para biriminin ondalık haneleriyle |
| İşlem nedeni | Bakiye penceresi | En az 8 karakter |
| Para birimi anahtarı | Günlük raporlar | Örneğin gold |
| Başlangıç, Bitiş | Günlük raporlar | Kapanmış günler |
Sık karşılaşılan durumlar
| Durum | Ne yapmalı |
|---|---|
| “Henüz bir sahip seçilmedi” | Yukarıdan sahip türünü seçip sahibi arayın. |
| Cüzdanlar bölümü yetki uyarısı gösteriyor | Hesabınızın rolünde cüzdan okuma yetkisi yoktur. Bakiye yetkiniz varsa cüzdan kimliğini yapıştırarak işlem yapabilirsiniz; hareketler yine de listelenemez. |
| “Geçerli bir kimlik (UUID) girin” | Kimlik tireli 8-4-4-4-12 biçiminde olmalı. |
| Bakiye işlemi reddedildi | Cüzdan siz bakarken değişmiş olabilir; sayfayı yenileyin. Tutarın para biriminin hane sayısına uyduğunu da kontrol edin. |
| Rapor boş | Para birimi anahtarını ve kapanmış bir tarih aralığı girdiğinizden emin olun. Yalnızca kapanmış günler raporlanır. |
| “Takas yok” | Bu ortamda takas kaydı bulunamamıştır. Bölüm yetki uyarısı gösteriyorsa hesabınızın rolünde takasları okuma yetkisi yoktur. |
İlgili dokümanlar
Kurallar
Amaç
Bu sayfa oyununuzun davranışını kod yazmadan ayarladığınız yerdir. İki tür şey görürsünüz: oyunun eklentisinin sunduğu oyun kuralı kartları (örneğin polis ya da şehir kalabalığı değerleri) ve sizin yazdığınız otomasyonlar (“seviye 10’a çıkınca karaktere güç ekle” gibi). Değişiklikler yayınlayana kadar oyuna geçmez; her yayın geri alınabilir.
Ne zaman kullanılır
- Oyunun hazır ayarlarını (hız, süre, yoğunluk gibi) kod değiştirmeden ayarlamak için.
- Bir oyun olayı olduğunda karaktere otomatik ödül, puan ya da bayrak vermek için.
- Yanlış yayınlanan bir ayarı önceki sürüme döndürmek için (Kural geçmişi).
Adım adım
Bir oyun kuralını değiştirme
- Listeden bir karta tıklayın; kartın ayar sayfası açılır (Kural kartı).
- Değeri değiştirin. Değişiklik henüz oyuna geçmez; sayfanın altında “N değişiklik yayınlanmadı” çubuğu görünür.
- Başka kartlara geçip oradaki ayarları da değiştirebilirsiniz. Bekleyen değişikliklerin hepsi tek yayına girer.
- Gözden geçir ve yayınla düğmesine basın, nedeninizi yazın ve onaylayın.
Otomasyon ekleme
- Yeni kural düğmesine basın ya da liste boşsa Şablondan başla düğmesini kullanın.
- Otomasyon düzenleyicisinde olayı, koşulları ve yapılacak işi seçin (Otomasyon düzenleyici).
- Yayınlayın. Kural varsayılan olarak kapalı kaydedilir; hazır olunca listedeki Aç düğmesiyle açarsınız.
Otomasyonu açma ve kapatma
Kartın sağındaki Aç ya da Kapat düğmesi bir onay penceresi açar. Nedeninizi yazıp onaylayın; kapatılan kural oyunda çalışmayı bırakır, silinmez.
Alanlar ve seçenekler
| Alan | Zorunlu | Açıklama |
|---|---|---|
| Kural ara | Hayır | Kart başlığı, açıklaması ve otomasyon anahtarında arar |
| Konu düğmeleri | Hayır | Listeyi seçtiğiniz konulara daraltır; hiçbiri seçili değilse hepsi görünür |
| İşlem nedeni (aç/kapat penceresi) | Evet | 8-500 karakter; işlem geçmişine yazılır |
Üstteki durum şeridi yayındaki sürümü, yayınlayan kişiyi ve yazdığı nedeni gösterir. Henüz hiçbir şey yayınlanmadıysa “oyun bugünkü (kod) değerlerle çalışıyor” yazar.
Sık karşılaşılan durumlar
| Durum | Ne yapmalı |
|---|---|
| “Bu oyunun eklentisi panelden ayarlanabilir kural sunmuyor” yazıyor | Oyunun eklentisi kural kartı bildirmiyordur. Otomasyonları yine bu sayfadan ekleyebilirsiniz. |
| “Kuralları görmek için yetkiniz yok” yazıyor | Rolünüzde kural okuma yetkisi yoktur; bir yöneticiden isteyin. |
| Yeni kural düğmesi yok | Düğmeyi yalnızca kural yazma yetkisi olan yöneticiler görür. |
| Kartta “Gözlemde” rozeti var | Kuralın koruması gevşetilmiştir; kural oyuna uygulanmıyor, yalnızca kaydediliyor. Ayrıntı için Güvenlik şalterleri sayfasına bakın. |
| Kartta “Yeniden başlatınca” rozeti var | Değer yayınlandı ama canlı dünya yeni değeri sunucu yeniden başlayınca alır. |
| Bildirim kuralları nerede? | Bildirim kuralları ayrı bir ekrandadır; sayfanın altındaki Bildirimler kartından açılır. |
İlgili dokümanlar
Leaderboard · Sıralama tabloları
Amaç
Leaderboard (sıralama tablosu), oyuncuların puanlarına göre sıralandığı tablodur. Bu sayfa ortamınızdaki tabloları kart olarak listeler: ad, sıfırlama aralığı, oyunda görünüp görünmediği, bu sezonki oyuncu sayısı, lider ve bir sonraki sıfırlamaya kalan süre. Yeni tabloyu da buradan kurarsınız. Puanları oyun sunucunuz gönderir; panel puan yazmaz.
Ne zaman kullanılır
- Oyun sunucunuz puan göndermeden önce bir tablo kurmak için.
- Hangi tablonun görünür olduğunu, ne zaman sıfırlanacağını ve liderini görmek için.
- Bir tablonun ayrıntısına (sıralama, geçmiş sezonlar, ayarlar) geçmek için.
Adım adım
Yeni tablo kurma
- Yeni tablo düğmesine basın. Düğmeyi yalnızca tablo yönetme yetkisi olan yöneticiler görür.
- Tablonun adı alanına bir ad yazın; anahtar otomatik dolar. İsterseniz anahtarı kendiniz değiştirin.
- Hangi puan önde? ve Ne zaman sıfırlansın? seçeneklerini belirleyin. “Özel aralık” seçerseniz gün ve saat yazın.
- Puan nasıl gösterilsin? seçeneğini belirleyin; gerekirse bir birim eki yazın.
- Oyuncuların tabloyu oyunda görmesini istiyorsanız Oyunda görünsün anahtarını açın.
- Altındaki önizleme satırında puanın nasıl görüneceğine bakın ve Tabloyu oluştur düğmesine basın. Başarılı olunca tablonun ayrıntı sayfası açılır.
Uyarı
Anahtar, sıralama yönü ve sıfırlama aralığı tablo kurulduktan sonra değiştirilemez. Değiştirmek için yeni bir tablo kurmanız gerekir; bu yüzden kurmadan önce dikkatle seçin.
Bir tabloyu açma
Kartın adına tıklayın; ayrıntı sayfası açılır (Leaderboard ayrıntısı).
Alanlar ve seçenekler
| Alan | Zorunlu | Açıklama |
|---|---|---|
| Tablonun adı | Evet | 1-400 karakter |
| Anahtar | Evet | Küçük harf ya da rakamla başlar; küçük harf, rakam, nokta, tire, alt çizgi; en fazla 200 karakter |
| Hangi puan önde? | Evet | Yüksek puan ya da düşük puan |
| Ne zaman sıfırlansın? | Evet | Hiç, her gün, her hafta (Pazartesi), her ay ya da özel aralık |
| Gün, Saat | Yalnızca özel aralıkta | Gün ya da saatten en az biri; toplam en az 1 saat, tam sayı |
| Puan nasıl gösterilsin? | Evet | Sayı, para ya da süre |
| Birim eki | Hayır | En fazla 8 karakter; süre biriminde yoktur |
| Oyunda görünsün | Hayır | Varsayılan kapalı |
Sık karşılaşılan durumlar
| Durum | Ne yapmalı |
|---|---|
| “Bu anahtar kullanılıyor ya da bir eklentiye ayrılmış” | Başka bir anahtar seçin. Bazı anahtar önekleri oyunun eklentisine ayrılmıştır. |
| Listede tablo yok ve “package-ride eklentisi ‘Günlük kazanç’ tablosunu ilk teslimatta kendiliğinden kurar” yazıyor | Eklenti tabloyu ilk teslimatta kurar; henüz teslimat olmamıştır. Beklemeniz yeterlidir. |
| “Sıralama (Competition) modülü bu ortamda kapalı” | Oyun ayarları › Modüller sayfasından modülü açın. |
| “Yeni tablo” düğmesi yok | Tablo yönetme yetkiniz yoktur; bir yöneticiden isteyin. |
| Yalnızca ilk tabloları görüyorum | Liste en fazla belirli sayıda tablo gösterir; sınıra gelince sayfa bunu yazar. Daha fazlası bu sürümde listelenmiyor. |
| Kartta “Kaynak: … eklentisi (otomatik)” yazıyor | Tabloyu bir eklenti kurmuştur ve yalnız o eklenti puan yazar. |
İlgili dokümanlar
Bildirimler
Amaç
Bu sayfa oyuncuya giden bildirimleri yönettiğiniz yerdir. Bildirimin gidebilmesi için üç şey gerekir: bir sağlayıcı (Firebase, Apple ya da OneSignal gibi anlık bildirim servisi), bir şablon (mesajın metni) ve bir kural ya da elle test gönderimi (mesajın ne zaman gideceği). Sayfa altı sekmeden oluşur: Genel bakış, Şablonlar, Kurallar, Sağlayıcılar, Gönderim geçmişi ve Cihazlar.
Ne zaman kullanılır
- Bildirim altyapısını ilk kez kurarken (Genel bakış sekmesindeki üç adımı izleyin).
- Seviye atlama gibi bir olayda otomatik bildirim göndermek için.
- Bir bildirimin neden gitmediğini araştırmak için (Gönderim geçmişi ve Cihazlar sekmeleri).
Adım adım
1. Sağlayıcı bağlama
- Sağlayıcılar sekmesinde kullandığınız servisin kartında Bağla düğmesine basın. Bu işlem yalnızca süper yöneticiye açıktır.
- Servisin istediği bilgileri girin ve anahtar dosyasını seçin. Anahtar yalnızca yazılır; kaydedildikten sonra bir daha görüntülenmez, yalnızca parmak izi görünür.
- Nedeninizi ve doğrulayıcı uygulamanızdaki 6 haneli kodu yazıp Kaydet düğmesine basın.
- Kart birkaç saniye içinde Hazır olur; sunucu ayarı yükler. Hata görürseniz kartta nedeni düz Türkçe yazılır.
2. Şablon yazma
- Şablonlar sekmesinde Yeni şablon düğmesine basın (ya da boşsa İlk şablonu oluştur; Örnekle başla hazır bir örnek getirir).
- Anahtar, görünen ad ve dili yazın; başlığı ve metni girin. Oyuncuya özel değerler için metne
{{ad}}yazın ve aynı adı Değişkenler listesine ekleyin. - Sağdaki canlı önizlemede telefon kilit ekranı ve tarayıcı bildirimi görünümüne bakın, Şablonu oluştur düğmesine basın.
- Başka dil eklemek için şablonun ayrıntısında + Dil ekle düğmesini kullanın. Her kayıt yeni bir sürüm olarak saklanır; sürüm geçmişinden eski sürüme dönebilirsiniz.
Not
Oyuncunun dilinde sürüm yoksa yedek dil olan İngilizce (en) sürümü kullanılır. İngilizce sürüm de yoksa bildirim gönderilmez.
3. Kural ekleme ya da test gönderme
- Kural: Kurallar sekmesinde Yeni kural ile olayı, koşulları, şablonu, dili ve kanalı seçin; Örnek olayla dene bölümünde kuralı hiçbir bildirim göndermeden deneyin.
- Test: Gönderim geçmişi sekmesinde Test gönder düğmesine basın; oyuncuyu, şablonu, dili ve kanalı seçip gönderin. Sayfa sonucu en fazla 60 saniye izler. Sık denemeler sınırlanır (15 dakikada 10 deneme).
Alanlar ve seçenekler
| Alan | Zorunlu | Açıklama |
|---|---|---|
| Şablon anahtarı, görünen ad, açıklama, dil | Anahtar, ad, dil zorunlu | Anahtar değişmez; ad en fazla 120, açıklama 500 karakter |
| Başlık, Metin | Evet | Başlık için 65, metin için 240 karakterlik yumuşak sınır |
| Değişken adı, tür, örnek değer, zorunlu | Değişken eklenince | En fazla 32 değişken; sayı değişkenine tam sayı |
| Sürüm notu | Hayır | En fazla 200 karakter |
| Kural anahtarı, kural adı | Evet | Anahtar en fazla 64 karakter, değişmez; ad en fazla 120 |
| Ne zaman, koşullar | Ne zaman zorunlu | En fazla 20 koşul satırı; koşul yoksa olay her olduğunda çalışır |
| Şablon, dil, kanal | Evet | Kanal: oyun içi, anlık bildirim ya da ikisi |
| Sağlayıcı bilgileri ve anahtar dosyası | Evet | Firebase: hizmet hesabı JSON; Apple: Team ID, Key ID, Bundle ID, ortam ve .p8; OneSignal: App ID ve REST API anahtarı |
| İşlem nedeni, doğrulama kodu | Evet | Neden 8-500 karakter; kod 6 hane |
Bir ortamda en fazla 50 bildirim kuralı olabilir.
Sık karşılaşılan durumlar
| Durum | Ne yapmalı |
|---|---|
| “Bu oyunda bildirimler kapalı” | Oyun ayarları › Modüller sayfasından Bildirimler modülünü açın. |
| Kartta “Bağlı değil” yazıyor | Sağlayıcı bu ortamda bağlı değildir; Bağla ile bilgileri girin. Bağlamak süper yönetici yetkisi ister. |
| “Sağlayıcı anahtarı reddetti” | Firebase için hizmet hesabı dosyasını, Apple için .p8 anahtarını ve Team ID, Key ID, Bundle ID değerlerini, OneSignal için REST API anahtarını yenileyin. |
| “Anahtar dosyası biçimi tanınmadı” | Firebase için hizmet hesabı JSON dosyası, Apple için .p8 dosyası gerekir; Google OAuth istemci dosyası ya da .p12 sertifikası olmaz. |
| Test “oyuncunun ulaşılabilir cihazı yok” diyor | Oyuncu oyunda bildirimleri açmamıştır. Oyun içi kanalı seçin ya da Cihazlar sekmesinde oyuncunun cihazı olup olmadığına bakın. |
| Kural kaydedilemiyor: “Şablon arşivlenmiş” ya da “bu dilde şablon yok” | Şablonu arşivden çıkarın ya da seçtiğiniz dili şablona ekleyin. |
| Sunucu ayarından gelen kurallar çalışıyor | Panelde ilk kuralı eklediğinizde bu ortamda onların yerini panel kuralları alır. |
| Kural ya da şablon düzenlenemiyor | Bildirim yönetimi yetkiniz yoktur; görünüm salt okunurdur. Bir yöneticiden isteyin. |
İlgili dokümanlar
Genel
Amaç
Oyun ayarları sayfasının Genel sekmesi seçili oyunun kimliğini gösterir: oyun adı, kısa ad, bağlı olduğu stüdyo ve kullandığı eklenti. Yetkili yöneticiler buradan oyunu yeniden adlandırabilir ya da arşivleyebilir. Bu sekme sunucuya istek atmaz; bilgiler seçili oyun ve ortamdan okunur.
Ne zaman kullanılır
- Hangi oyun ve stüdyonun seçili olduğunu doğrulamak için.
- Oyunun adını değiştirmek için (süper yönetici).
- Artık kullanılmayan bir oyunu listelerden ve seçiciden gizlemek için (süper yönetici).
Adım adım
Oyunu yeniden adlandırma
- Üstteki ortam seçicisinden oyunu seçin.
- Yeniden adlandır düğmesine basın. Düğmeyi yalnızca süper yönetici görür; diğerleri için sayfa salt okunurdur.
- Yeni adı yazın (1-160 karakter), nedeninizi yazın ve Adı kaydet düğmesine basın.
Kısa ad değişmez.
Oyunu arşivleme
- Sayfanın altındaki Tehlikeli işlemler kutusunda Arşivle düğmesine basın.
- Nedeninizi yazıp onaylayın.
Uyarı
Arşiv oyunu listelerden ve seçiciden gizler; veri silinmez. Oyunun canlı yetkisi ya da etkin bir API anahtarı varsa arşivleme reddedilir; pencere nedenini gösterir. Seçili ortam bu oyuna aitken Arşivle düğmesi kapalıdır; önce başka bir oyunun ortamını seçin.
Alanlar ve seçenekler
| Alan | Zorunlu | Açıklama |
|---|---|---|
| Oyun adı | Salt okunur | Yeniden adlandırma penceresinden değişir |
| Kısa ad | Salt okunur | Oyun kurulurken verilir, değişmez |
| Stüdyo | Salt okunur | Oyunun bağlı olduğu stüdyo |
| Eklenti | Salt okunur | Eklenti yoksa “Eklenti yok” yazar; yetkiniz varsa Eklentiler sayfasına bağlantı çıkar |
| Yeni ad (yeniden adlandırma penceresi) | Evet | Mevcut addan farklı olmalı |
| İşlem nedeni (pencerelerde) | Evet | 8-500 karakter |
Sık karşılaşılan durumlar
| Durum | Ne yapmalı |
|---|---|
| “Ortam seçilmedi” yazıyor | Üst çubuktan bir oyun ve ortam seçin. |
| Yeniden adlandır ve Arşivle düğmeleri yok | Bu işlemler yalnızca süper yöneticiye açıktır; “bu sayfa sizin için salt okunurdur” yazısını görürsünüz. |
| “Önce başka bir ortam seçin” yazıyor | Arşivlemek istediğiniz oyunun ortamı şu an seçili. Başka bir oyunun ortamını seçip yeniden deneyin. |
| Arşivleme reddedildi | Oyunun canlı yetkisi ya da etkin bir API anahtarı vardır. Pencerede yazan nedene göre etkin API anahtarlarını iptal edin ya da Eklentiler sayfasından eklentinin durumunu kapatın, sonra yeniden deneyin. |
İlgili dokümanlar
Eklentiler
Amaç
Eklenti, oyunun sunucu tarafı mantığını çalıştıran modüldür: oyuna özel komutlar, sorgular ve panel ekranları sunar. Bu sayfa oyunun eklentisini, seçili ortamda yetkili diğer eklentileri ve her birinin durumunu gösterir. Eklentinin yönetim ekranlarına buradan ve kenar çubuğundan gidilir.
Ne zaman kullanılır
- Eklentinin bu ortamda açık olup olmadığını görmek için.
- Bir eklentiyi geçici olarak salt okunur yapmak, boşaltmak ya da kapatmak için (yetkili yönetici).
- Eklentinin sürümünü, izinlerini, işlemlerini ve bağımlılıklarını incelemek için.
- Oyuna eklenti bağlamak ya da yeni sürüme geçmek için.
Adım adım
Eklentinin ayrıntılarını görme
Kartın Ayrıntılar düğmesi sürümü, izinleri, bağımlılıkları ve eklentinin sunduğu işlemleri (sorgu ya da komut, kimin erişebildiği) listeler. Bilgiler eklentinin kendi bildiriminden okunur; buradan değiştirilemez.
Eklentinin durumunu değiştirme
- Kartın Durumu değiştir düğmesine basın. Düğmeyi yalnızca eklenti yönetme yetkisi olan yöneticiler görür.
- Yeni durum listesinden hedefi seçin; seçtiğiniz durumun oyuncu ve yönetici etkisi pencerede yazar.
- Nedeninizi yazın ve Durumu değiştir düğmesine basın. Kapalı seçerseniz ayrıca bir onay sorulur.
Geçişler sınırlıdır: Açık durumdan salt okunur, boşaltılıyor ya da kapalıya; salt okunur ve boşaltılıyor durumlarından açık ya da kapalıya; kapalı durumdan salt okunur ya da açığa geçilebilir.
Oyuna eklenti bağlama ve sürüme geçme
Sayfanın başındaki oyun eklentisi kartı bu işlemler içindir:
- Eklenti bağlı değilse Eklenti bağla düğmesiyle listeden eklentiyi seçip bağlayın.
- Yeni derlenmiş sürüme geçmek için önce Drain başlat (boşaltma) ile oyuncuları boşaltın; onay için eklenti kimliğini yazın.
- Geri sayım bitince yeni sürümü dağıtın, sonra Sürüme geç düğmesine basın. Geri sayım bitene kadar düğme kapalıdır.
Uyarı
Kapalı durumunda oyuncular ve yöneticiler bu ortamda eklentiyi kullanamaz ve eklenti kenar çubuğundan kalkar. Geri açmak için durumu ayrıca değiştirmeniz gerekir.
Alanlar ve seçenekler
| Alan | Zorunlu | Açıklama |
|---|---|---|
| Yeni durum | Evet | Açık, Salt okunur, Boşaltılıyor ya da Kapalı |
| İşlem nedeni | Evet | 8-500 karakter |
| Eklenti (bağlama penceresi) | Evet | Sunucuda kurulu eklentilerden biri |
| Eklenti kimliği (boşaltma penceresi) | Evet | Kimlik aynen yazılmalı |
Kartın üstündeki rozet eklentinin bu ortamdaki durumunu gösterir. “Bu ortamda yetkisiz” yazıyorsa eklenti kurulu ama bu ortam için yetki satırı yoktur; eklenti burada kullanılamaz.
Sık karşılaşılan durumlar
| Durum | Ne yapmalı |
|---|---|
| “Kurulu eklenti yok” | Sunucu eklentisiz başlatılmıştır. Eklentiler sunucu derlemesine eklenir ve operatör tarafından etkinleştirilir. |
| Kartta “Yetki sürümü … kurulu sürüm …” uyarısı var | Ortam yetkisi kurulu sürümle eşleşmiyor; sürüm etkinleştirmesi bekleniyor. Bu durumda yalnızca boşaltma ve kapatma seçilebilir. |
| “Bu durum geçişine izin verilmiyor” | Durum siz bakarken değişmiş olabilir; sayfayı yenileyip yeniden deneyin. |
| Durumu değiştir düğmesi yok | Eklenti yönetme yetkiniz yoktur; bir yöneticiden isteyin. |
| Ekranları aç düğmesi yok | Eklenti panel ekranı tanımlamıyor ya da bu ortamda kapalı. |
| “Kullanımdan kalkan sorgular” kutusu görünüyor | Eklentinin bazı sorguları yeni bir yüzeyle değiştirilmiştir. Kutuda eski adı, yerine geçeni ve hangi sürümden beri kalktığını görürsünüz; oyun kodunuzu yeni yüzeye taşıyın. |
İlgili dokümanlar
Güvenlik şalterleri
Amaç
Güvenlik şalteri, oyunun bir koruma kuralını açıp gevşetmenizi sağlar. Zorla konumunda kural oyuna uygulanır. Gevşek konumunda kural oyuna uygulanmaz ya da yalnızca kaydedilir; ham ayardaki karşılığı “gözleme alındı”, “kapalı” ya da “devre dışı” olarak yazar. Şalteri sunucuyu yeniden dağıtmadan, ortam başına ve geri alınabilir biçimde değiştirirsiniz.
Ne zaman kullanılır
- Bir koruma kuralı oyuncuları haksız yere engelliyorsa kuralı geçici olarak gevşetmek için.
- Bir kuralın yalnızca kaydedildiğini (gözlemde olduğunu) görmek ve yeniden zorlamak için.
- Hangi korumaların gevşek olduğunu denetlemek için.
Adım adım
- Her satırda şalterin adını, ne yaptığını, konumunu (Zorla, Gözleme alındı, Kapalı, Devre dışı), kaynağını ve son değişikliği görürsünüz.
- Zorla konumundaki bir korumayı gevşetmek için Gevşet düğmesine basın. Açılan pencerede etkiyi okuyun, nedeninizi yazın ve Gevşet ile onaylayın.
- Gevşek bir korumayı geri açmak için Zorla düğmesine basın; onay sormaz.
- Panelden değiştirilmiş bir şalteri dağıtım varsayılanına döndürmek için Varsayılana dön düğmesine basın.
Satırın kaynak rozeti şalterin değerinin nereden geldiğini gösterir: panel (siz değiştirdiniz), dağıtım varsayılanı ya da yalnız dağıtım (panelden değiştirilemeyen ayarlar). Yalnız dağıtım satırları salt okunur gösterilir.
Not
Değişiklik en geç birkaç saniye içinde (sayfada yazan süre kadar) her sunucu kopyasında uygulanır; anında etki ve anlık itme yoktur.
Uyarı
Gevşek koruma, ilgili kuralın oyuna uygulanmadığı ya da yalnızca kaydedildiği anlamına gelir. Sayfanın üstündeki uyarı bandı kaç korumanın gevşek olduğunu söyler. Okuma hatası korumayı asla gevşetmez; sayfa hata gösterir.
Alanlar ve seçenekler
| Alan | Zorunlu | Açıklama |
|---|---|---|
| İşlem nedeni (gevşetme penceresi) | Evet | 8-500 karakter |
Sayfanın altındaki sayaç kartı çalışma sayaçlarını gösterir; yalnızca bu yetkisi olan yöneticiler görür.
Sık karşılaşılan durumlar
| Durum | Ne yapmalı |
|---|---|
| Düğmeler yok, “salt okunurdur” yazıyor | Şalterleri yalnızca süper yönetici değiştirebilir; siz değerleri okuyabilirsiniz. |
| “Güvenlik şalterleri okunamadı” | Liste yüklenemedi. Korumalar gevşetilmiş sayılmaz; Tekrar dene ile yeniden okuyun. |
| Bir kural kartında “Gözlemde” rozeti görüyorum | O kartın şalteri gevşektir. Bu sayfadan ya da Kurallar sayfasındaki kart sayfasından Zorla diyerek yeniden açın. |
| Neden sorulmadan değişti | Zorla ve Varsayılana dön düğmeleri gerekçe sormaz; denetim kaydına “operatör şalteri Zorla konumuna aldı (panel)” gibi sabit bir gerekçe yazılır. |
İlgili dokümanlar
İşlem geçmişi
Amaç
Panelden yapılan her değişiklik değiştirilemeyen bir kayıt bırakır: hangi yönetici, hangi kayıt üzerinde, ne zaman, hangi eylemi ve hangi nedenle yaptı. Bu sayfa o kayıtları tablo olarak gösterir. Kayıtlar yalnızca eklenir; hiçbiri silinmez ya da düzenlenmez.
Ne zaman kullanılır
- Bir ayarın kim tarafından, ne zaman ve neden değiştirildiğini bulmak için.
- Bir sorun sonrası “ne değişmişti” sorusunu yanıtlamak için.
- Bir işlemin önceki ve sonraki durumunu karşılaştırmak için.
Adım adım
- Tabloda en yeni kayıtlar üsttedir. Her satırda zaman, yönetici, eylem, hedef türü, hedef ve neden vardır.
- Süzgeçler ve arama ile listeyi daraltın: eylem, hedef, yönetici, oyuncu ve zaman aralığı. İstek kimliği, ortam ve oyuncu sütunları varsayılan olarak gizlidir; sütun menüsünden açabilirsiniz.
- Bir satırın İncele düğmesine basın. Açılan panelde yönetici, hedef, ortam, istek kimliği, neden ve işlemin Önce ve Sonra durumları görünür.
- Kayıt bir oyuncuya bağlıysa panelde oyuncunun sayfasını açan bir bağlantı çıkar.
Süper yöneticiler iki sekme görür: Ortam kayıtları (seçili ortama bağlı işlemler) ve Operatör işlemleri (görünen ad, parola, oturum, giriş ve yönetici yönetimi gibi hiçbir ortama bağlı olmayan işlemler).
Not
Operatör işlemleri sekmesindeki kayıtlar bir oyuncuya bağlı değildir; bu sekmede oyuncu süzgeci sonuç vermez.
Alanlar ve seçenekler
| Alan | Zorunlu | Açıklama |
|---|---|---|
| Süzgeçler ve arama | Hayır | Eylem, hedef, yönetici, oyuncu ve zaman aralığı; sunucuda uygulanır |
| Sütunlar | Hayır | Gizlenebilir ve sabitlenebilir; kayıt zamanı gizlenemez |
| Sayfa boyu | Hayır | 15, 25, 50, 100 ya da 500 |
| Kapsam sekmesi | Hayır | Yalnızca süper yöneticide: ortam kayıtları ya da operatör işlemleri |
Sık karşılaşılan durumlar
| Durum | Ne yapmalı |
|---|---|
| Operatör işlemleri sekmesi yok | Bu kayıtları yalnızca süper yönetici görür. |
| Aradığım kayıt görünmüyor | Seçili ortamı ve zaman aralığını kontrol edin. Ortam kayıtları seçili ortama aittir; ortamdan bağımsız işlemler Operatör işlemleri sekmesindedir. |
| Bir kaydı silmek ya da düzeltmek istiyorum | Mümkün değil; kayıtlar değiştirilemez. |
İlgili dokümanlar
Giriş yöntemleri
Amaç
Bu sekme seçili ortamda oyuncuların hangi sağlayıcılarla giriş yapabileceğini yönettiğiniz yerdir. Bugün panelden yönetilen sağlayıcı Google’dır; misafir girişi ve e-posta ile giriş burada ayarlanmaz. Sayfada ayrıca ortamın oturum politikası (tek aktif oturum) vardır. Her sağlayıcının ayrıntı sayfasında durumu, kapsamları, istemci bilgileri ve güvenli ek bilgileri bulunur.
Ne zaman kullanılır
- Google ile girişi ilk kez açarken (istemci kimliği, gizli anahtar ve yönlendirme tabanı girmek için).
- Google girişini geçici kapatmak ya da yeniden açmak için.
- Oyuncunun yeni girişinde eski oturumlarının kapanmasını istiyorsanız.
Adım adım
Google girişini yapılandırma
- Sekmenin üstünden ortamı seçin, listedeki Google satırında Detay düğmesine basın.
- OAuth istemci bilgisi kartında OAuth bilgilerini düzenle düğmesine basın. Düğmeyi yalnızca süper yönetici görür.
- İstemci kimliğini, istemci sırrını ve yönlendirme tabanını girin.
- Nedeninizi ve doğrulayıcı uygulamanızdaki 6 haneli kodu yazıp Kaydet düğmesine basın.
- Google Cloud konsolunda Authorized redirect URI olarak yönlendirme tabanınızın sonuna
/googleeklenmiş adresi kaydedin. - Sağlayıcı Etkin değilse ayrıntı sayfasında Etkinleştir düğmesine basın.
Uyarı
İstemci sırrı yalnızca yazılır. Kaydedildikten sonra panelde bir daha görünmez; kartta yalnızca “yapılandırıldı” durumu ve kısa bir parmak izi yer alır. Kaybederseniz Google’dan yenisini alıp yeniden girin.
Tek aktif oturum
- Giriş ayarları kartındaki Tek aktif oturum anahtarını açın ya da kapatın. Anahtarı yalnızca giriş yöntemi yazma yetkisi olan yöneticiler değiştirebilir.
- Açılan pencerede nedeninizi yazıp onaylayın.
Kartın altındaki satır değerin kaynağını gösterir: ortam ayarı ya da sunucu varsayılanı.
Panelden girilen bilgiyi kaldırma
Panelden girilmiş Google bilgisi için ayrıntı sayfasında Kaldır düğmesi görünür. Sağlayıcının kimliğini yazarak onaylar, nedeninizi ve doğrulama kodunu girersiniz. Sunucuda varsayılan bir değer varsa ortam ona döner; yoksa sağlayıcı bu ortamda yapılandırılmamış olur.
Alanlar ve seçenekler
| Alan | Zorunlu | Açıklama |
|---|---|---|
| Tek aktif oturum | Hayır | Ortam başına anahtar; açık oturumlara dokunmaz |
| İstemci kimliği (client id) | Evet | En fazla 256 karakter, boşluksuz görünür karakterler |
| İstemci sırrı (client secret) | Evet | En az 8, en fazla 1024 karakter; yalnızca yazılır |
| Yönlendirme tabanı | Canlıda evet | https ile başlar; sorgu, parça ya da kullanıcı bilgisi içermez |
| İşlem nedeni | Evet | 8-500 karakter |
| Doğrulama kodu | Evet | 6 haneli güncel kod |
| Onay metni (kaldırma) | Evet | Sağlayıcı kimliği aynen |
| Çalışma durumu etkin (sağlayıcı ayarları) | Hayır | Sağlayıcıyı açar ya da kapatır |
| Güvenli ek bilgiler (JSON) | Hayır | Sır içeren alan adları reddedilir |
Sık karşılaşılan durumlar
| Durum | Ne yapmalı |
|---|---|
Google düğmesi oyunda görünmüyor ya da başlatma 403 dönüyor | Google bu ortamda yapılandırılmamış ya da kapalıdır. Bilgileri girin ve sağlayıcıyı etkinleştirin. |
| Google “redirect_uri_mismatch” diyor | Google Cloud konsoluna kaydettiğiniz adres, yönlendirme tabanı + /google ile birebir aynı olmalıdır. |
| “Bilgileri düzenle” düğmesi yok | Yalnızca süper yönetici istemci bilgilerini yazabilir. |
| “Kaydet” doğrulama kodu hatası veriyor | Kurtarma kodu kabul edilmez; doğrulayıcı uygulamanızdaki güncel 6 haneli kodu girin. Her denemeden sonra kod silinir. |
| Sunucu varsayılanı kaynak olarak görünüyor | Bilgiler sunucu ayarından gelir. Panelden girdiğiniz değer bu ortamda onu ezer. |
| Oyuncu iki cihazda aynı anda oturumda kalamıyor | Tek aktif oturum açıktır. Kapatırsanız oyuncular birden çok cihazda aynı anda oturumda kalabilir. |
İlgili dokümanlar
Modüller
Amaç
Open Play özellikleri modüller halinde gelir: karakterler, ekonomi, mağaza, sıralama, bildirimler gibi. Bu sekme seçili ortamda hangi modüllerin açık olduğunu gösterir. Kapalı modülün ekranları panel menüsünden kalkar ve API’si 404 (module_disabled) döner; modülün verisi silinmez ve yeniden açınca geri gelir.
Ne zaman kullanılır
- Bir ekranın ya da API’nin neden görünmediğini araştırırken.
- Oyununuzun kullanmadığı bir özelliği kapatmak için.
- Kapatılmış bir modülü yeniden açmak için.
Adım adım
- Sekmenin üstündeki ortam seçicisinden ortamı seçin.
- Modülün kartında durumu ( Açık ya da Kapalı ), neye bağlı olduğunu ve varsa engelleyen nedeni görün.
- Yetkiniz varsa Aç ya da Kapat düğmesine basın.
- Açılan pencerede nedeninizi yazın. Kapatırken ayrıca bir onay sorulur.
- Değişiklik yaklaşık iki saniyede yayılır.
Modüller şunlardır: Karakterler ve kurallar, Ekonomi, Eşya ve envanter, Tüccar ve takas, Mağaza ve satın alma, Görevler ve ödüller, Parti ve klan, Sohbet, Sıralama ve turnuva, Bildirimler, Webhook’lar, Sahne ve varlıklar, Eklenti platformu.
Uyarı
Kapalı modüle yapılan API çağrıları
404ve{"code":"module_disabled"}döner. Oyununuz bir modüle bağlıysa kapatmadan önce oyunun bunu kullanmadığından emin olun.
Alanlar ve seçenekler
| Alan | Zorunlu | Açıklama |
|---|---|---|
| İşlem nedeni | Evet | 8-500 karakter |
Sık karşılaşılan durumlar
| Durum | Ne yapmalı |
|---|---|
| Aç ve Kapat düğmeleri yok | Modülleri yalnızca süper yönetici açıp kapatabilir; ekran sizin için salt okunurdur. |
| Düğme kapalı ve “Önce şu modülleri açın” yazıyor | Modül başka modüllere bağlıdır; önce yazılan modülleri açın. |
| Düğme kapalı ve “Önce şu modülleri kapatın” yazıyor | Başka modüller bu modüle bağlıdır; önce onları kapatın. |
| “Etkin eklentiler kullanıyor” yazıyor | Bir eklenti bu modüle ihtiyaç duyar. Eklentiler sayfasından o eklentileri kapatın, sonra modülü kapatın. |
| Kapattığım modülün verileri gitti mi? | Hayır. Veriler korunur; yalnızca ekranlar ve API durur. |
İlgili dokümanlar
API anahtarları
Amaç
API anahtarları, oyununuzun sunucusunun Open Play’e kimliğini kanıtlamasını sağlar. Bu sayfa seçili oyunun ve ortamın anahtarlarını listeler; yeni anahtar oluşturmanızı, süresini ve durumunu yönetmenizi sağlar. Sayfa, Oyun ayarları içindeki API anahtarları sekmesidir.
Ne zaman kullanılır
- Oyun sunucunuzu Open Play’e ilk kez bağlarken.
- Bir anahtar sızdıysa ya da artık gerekmiyorsa iptal etmek için.
- Anahtarın süresini uzatmak ya da adını değiştirmek için.
Adım adım
Yeni anahtar oluşturma
- Üstteki ortam seçicisinden anahtarın çalışacağı oyunu ve ortamı seçin.
- Anahtar oluştur düğmesine basın. Düğmeyi yalnızca anahtar yazma yetkisi olan yöneticiler görür.
- Anahtara bir ad verin ve Anahtar türü seçin: oyun sunucunuz için Sunucu anahtarı, oyun istemcisi için İstemci anahtarı.
- Geçerlilik bölümünden bir süre seçin. Emin değilseniz 90 gün gibi bir süre seçip düzenli yenilemek daha güvenlidir.
- Not alanına kısa bir gerekçe yazın.
- Anahtarı oluştur düğmesine basın.
- Sayfada görünen gizli değeri hemen kopyalayıp güvenli bir yere kaydedin.
Uyarı
Gizli değer yalnızca oluşturulurken bir kez gösterilir; sonradan görüntülenemez. Kaybederseniz anahtarı yenilemeniz (rotate) gerekir.
Anahtarı kullanma
Oyun sunucunuz anahtarı her istekte Authorization başlığıyla gönderir:
curl https://<sunucu-adresiniz>/v1/<uç-nokta> \
-H "Authorization: Bearer crx_live_<önek>_<gizli>"
Yer tutucuları kendi değerlerinizle değiştirin. Gerçek anahtarı kaynak koduna ya da oyun istemcisine yazmayın.
Anahtarı düzenleme, yenileme ve iptal etme
- Listeden anahtarın satırına tıklayarak ayrıntı sayfasını açın.
- Düzenle ile adı, süreyi ve notları değiştirin; gizli değer değişmez.
- Rotate (yenile) eski gizli değeri iptal eder ve yeni değeri bir kez gösterir.
- Devre dışı bırak anahtarı geçici durdurur, Etkinleştir geri açar; Revoke (iptal) kalıcıdır.
Alanlar ve seçenekler
| Alan | Zorunlu | Açıklama |
|---|---|---|
| Anahtar adı | Evet | Listede tanımak için ad; en az 2 karakter |
| Anahtar türü | Evet | Sunucu (gizli) ya da istemci (oyuna gömülebilir) |
| Geçerlilik | Evet | Süresiz, 30 gün, 90 gün, 1 yıl ya da özel tarih; düzenlemede ayrıca “Değiştirme” |
| Not | Evet | İşlem geçmişine yazılan gerekçe, 8-500 karakter |
| Anahtarın sahibi | Hayır | Varsayılan “Bu ortam”; “Gelişmiş ayarlar” içindedir |
| Sahip oyuncu / organizasyon | Sahip türüne bağlı | Sahibi seçtiğinizde zorunludur |
| Kapsam etiketleri | Hayır | Yalnızca not amaçlı etiketler |
| İzinler | Hayır | Ad-değer notları; erişimi kısıtlamaz |
| Ek bilgiler | Hayır | Ad-değer notları; erişimi kısıtlamaz |
Not
Kapsam etiketleri, izinler ve ek bilgiler şimdilik yalnızca kayıt amaçlıdır. Anahtarın neye erişebileceğini anahtar türü (sunucu ya da istemci) belirler.
Sık karşılaşılan durumlar
| Durum | Ne yapmalı |
|---|---|
| Gizli değeri kaybettim | Anahtarı Rotate ile yenileyin; yeni değeri kaydedin ve sunucunuzda güncelleyin. |
| Anahtar bir gün çalışmayı bıraktı | Süresi dolmuş, devre dışı bırakılmış ya da iptal edilmiş olabilir; ayrıntı sayfasından durumunu ve bitiş tarihini kontrol edin. |
| “Anahtar oluştur” düğmesi yok | Rolünüzde anahtar yazma yetkisi yoktur; bir yöneticiden isteyin. |
| Sunucu anahtarı istemciye gömüldü | Anahtarı hemen iptal edin, yenisini oluşturun ve yalnızca sunucuda kullanın. |
İlgili dokümanlar
Webhook ve olay kuyruğu
Amaç
Webhook, Open Play’in bir olay oluştuğunda kendi sunucunuza gönderdiği imzalı HTTP isteğidir. Bu sayfa kayıtlı uç noktaları, her olayın uç noktaya gönderim denemelerini ve gönderilmeyi bekleyen olay kuyruğunu (outbox) gösterir. Sayfa salt okunurdur: uç nokta eklemek, silmek, başarısız teslimatı yeniden göndermek ya da sırrı görmek için panelde düğme yoktur. Uç noktalar REST ile kaydedilir; ayrıntı için Webhook’lar rehberine bakın.
Ne zaman kullanılır
- Sunucunuzun webhook’ları alıp almadığını doğrulamak için.
- Bir olayın neden gelmediğini (bekliyor mu, başarısız mı, hangi hata) anlamak için.
- Bir uç noktanın etkin olup olmadığını ve hangi olay türlerini dinlediğini görmek için.
Not
Webhook modülü kapalıysa webhook uçları yanıt vermez (
404,module_disabled). Modülü Oyun ayarları › Modüller sayfasından açın. Sayfayı görmek için rolünüzde webhook okuma yetkisi de gerekir.
Adım adım
- Doğru oyunu ve ortamı seçtiğinizden emin olun.
- “Webhook endpoints” tablosunda uç noktanızın adresini (URL), dinlediği olay türlerini ve durumunu kontrol edin. Süzgeç boşsa “tümü” yazar, yani uç nokta bütün olayları alır.
- “Delivery attempts / DLQ” tablosunda teslimatları durumuna göre süzün. Başarısız (failed) olanlar yeniden deneme hakkını tüketmiş teslimatlardır (DLQ, ölü mektup kuyruğu).
- “Hata” sütununda hatanın sınıfını ve varsa sunucunuzun döndüğü HTTP kodunu görürsünüz. Ham hata metni gösterilmez.
- “Outbox” tablosunda gönderilmeyi bekleyen ya da denenen olayları görürsünüz.
- Yeni verileri görmek için Yenile düğmesine basın.
Alanlar ve seçenekler
Bu sayfada doldurulacak bir form yoktur.
Tablolar
| Tablo | Sütunlar |
|---|---|
| Webhook endpoints | URL, Event filtreleri, Durum (enabled ya da disabled), Oluşturulma; Endpoint kimliği sütun menüsünden açılır |
| Delivery attempts / DLQ | Endpoint (URL, teslimat ve olay kimliği), Durum (pending, delivered, failed), Attempt (deneme sayısı), Hata, Oluşturma, Teslim; teslimat sırası ve outbox kimliği sütun menüsünden açılır |
| Outbox | Event (tür ve olay kimliği), Durum, Attempt, Retry (sonraki deneme zamanı), Oluşturma |
Yayımlanmış (tamamlanmış) outbox kaydında sonraki deneme zamanı “—” görünür. Olay türü gizli bir iç olaysa “redacted/private” yazar. Panel sırları, ham gövdeyi ve ham hata metnini hiçbir zaman göstermez.
Sık karşılaşılan durumlar
| Durum | Ne yapmalı |
|---|---|
| “Webhook yüzeyi yetki gerektiriyor” yazıyor | Rolünüzün webhook okuma yetkisi yok; bir yöneticiden isteyin. |
| Tablolar boş | Henüz uç nokta kaydetmemiş olabilirsiniz; doğru ortamı seçtiğinizi de kontrol edin. |
| Teslimat “failed” | Sunucunuz 2xx dönmüyor ya da ulaşılamıyor. Hata sütunundaki sınıfı ve kodu inceleyin; alıcınızı düzeltin. Panelden yeniden gönderme yoktur. |
| Aynı olay birden çok kez geldi | Teslimat en az bir kez yapılır; alıcınız olay kimliğiyle tekrarı elemelidir. Ayrıntı için rehbere bakın. |
| Uç noktanın sırrını göremiyorum | Sır yalnızca kayıt yanıtında bir kez döner; sonra hiçbir yerde gösterilmez. Yenilemek için uç noktayı silip yeniden kaydedin. |
İlgili dokümanlar
Arka plan işleri
Amaç
Bu sayfa iki şeyi salt okunur gösterir: (1) eklentilerin zamanlanmış komutlarının arka plan iş kayıtlarını ve (2) seçtiğiniz bir oyuncunun bağlı giriş hesaplarıyla cihaz bilgilerini. Sayfadan iş başlatamaz, yeniden deneyemez, oturum kapatamaz ya da parola değiştiremezsiniz. Bu işlemler için Oyuncu profili sayfasını kullanın.
Ne zaman kullanılır
- Bir eklentinin zamanlanmış işinin çalışıp çalışmadığını, başarısız olup olmadığını görmek için.
- Bir oyuncunun hangi giriş yöntemleriyle (Google, parola vb.) hesaba bağlandığını görmek için.
- Bir oyuncunun hangi cihazlardan giriş yaptığını kontrol etmek için.
Adım adım
İş kayıtları
- Doğru oyunu ve ortamı seçtiğinizden emin olun.
- “Worker job runs” tablosunda işleri durumlarına göre süzün: pending (henüz alınmadı ya da yeniden deneme için serbest), claimed (bir işçi aldı), done (tamamlandı), dead (kalıcı hata ya da deneme sınırı nedeniyle kapandı).
- Belirli bir zaman aralığı için filtre menüsünde “Oluşturulma” sütununu “arasında” ile kullanın.
- “Failure” sütunu başarısız işin hata kodunu gösterir. İş içeriği ve ham hata metni gösterilmez.
Oyuncu giriş ilişkileri
- “Player auth relations” kartında Oyuncu alanına oyuncuyu yazıp seçin.
- İlişkileri getir düğmesine basın.
- “Provider accounts” tablosu oyuncunun bağlı giriş hesaplarını, “Devices” tablosu cihaz bilgisini ve durumunu gösterir. İptal edilmiş kayıtlar da listelenir. Uzun listeler sayfalanır.
Not
İş çalıştırıcısının sağlık durumu bu sayfada gösterilmez: kalıcı bir sağlık sinyali kaynağı henüz yoktur, bu yüzden “çevrimiçi” ya da gecikme gibi değerler üretilmez. Sayfadaki “Worker health: gözlemlenemiyor” kartı bunu belirtir.
Alanlar ve seçenekler
| Alan | Zorunlu | Açıklama |
|---|---|---|
| Oyuncu | Evet (İlişkileri getir için) | İlişkileri görülecek oyuncu |
İş kayıtları tablosu
Plugin / mesaj (eklenti kimliği, mesaj ve zamanlama kimliği), Durum, Attempt (deneme sayısı), Deadline (son zaman), Failure (hata kodu) ve Oluşturulma varsayılan olarak görünür. Sonraki deneme, Bitiş ve Zamanlama kimliği sütun menüsünden açılır.
Sık karşılaşılan durumlar
| Durum | Ne yapmalı |
|---|---|
| “Operations yüzeyi yetki gerektiriyor” yazıyor | Rolünüzün iş kaydı okuma yetkisi yok; bir yöneticiden isteyin. |
| Oyuncu ilişkileri yüklenmiyor | Bu kart için oyuncu okuma yetkisi gerekir; yoksa bir not görürsünüz. |
| İş “dead” durumunda | İş kalıcı bir hatayla ya da deneme sınırına ulaşarak kapanmıştır. Failure sütunundaki kodu eklentinin sahibiyle birlikte inceleyin; panelden yeniden başlatılamaz. |
| İş kayıtları boş | Seçili ortamda zamanlanmış eklenti işi yoktur ya da süzgeç çok dar. |
| Cihazı kapatmak istiyorum | Bu sayfa salt okunur; oturumları Oyuncu profili sayfasından kapatın. |
İlgili dokümanlar
Stüdyolar ve oyunlar
Amaç
Bu sayfa, kurulumdaki stüdyoları ve her stüdyonun oyunlarını ortamlarıyla birlikte gösterir. Buradan yeni stüdyo ve oyun kurar, adları değiştirir, kayıtları arşivler ve bir oyunun ayarlarına geçersiniz. Sayfa yalnızca stüdyo yönetme yetkisi olan yöneticilere açıktır. Stüdyo, oyun ve ortam kavramları için Temel kavramlar sayfasına bakın.
Ne zaman kullanılır
- Yeni bir stüdyo ya da oyun kurmak için.
- Bir stüdyonun ya da oyunun adını düzeltmek için.
- Artık kullanılmayan bir oyunu ya da stüdyoyu listeden kaldırmak (arşivlemek) için.
- Başka bir oyunun ayarlarına geçmek için.
Adım adım
Yeni stüdyo
- Yeni stüdyo düğmesine basın.
- Stüdyo adını ve Gerekçe alanını doldurup Stüdyo oluştur düğmesine basın.
Yeni oyun
- Stüdyonun kartındaki Yeni oyun düğmesine basın.
- Oyun adını yazın. İsterseniz kısa adı (slug) da yazın; boş bırakırsanız addan üretilir.
- Gerekçeyi yazıp Oyun oluştur düğmesine basın. Oyun, geliştirme ve canlı ortamlarıyla birlikte kurulur.
Yeniden adlandırma ve arşivleme
- Stüdyo ya da oyun satırındaki üç noktalı menüden Yeniden adlandır ya da Arşivle seçin.
- Yeni adı ya da yalnızca gerekçeyi yazıp onaylayın.
- Arşivlenmiş kaydı aynı menüden Geri aç ile yeniden listelere döndürebilirsiniz.
Not
Arşivleme yalnızca gizler; veri silinmez. Seçili ortamı içeren oyun ya da stüdyo arşivlenemez; önce başka bir ortam seçin. Canlı yetkisi ya da etkin API anahtarı olan kayıtlar için sunucu arşivlemeyi reddeder.
Oyun ayarlarını açma
- Oyunun satırındaki Oyun ayarları düğmesine basın. Oyunun etkin bir ortamı yoksa düğme pasiftir.
- Başka bir oyunun ortamı seçiliyse panel o oyunun etkin ortamına geçer ve Oyun ayarları sayfasını açar.
Alanlar ve seçenekler
| Alan | Pencere | Zorunlu | Açıklama |
|---|---|---|---|
| Stüdyo adı | Yeni stüdyo | Evet | 1-160 karakter |
| Stüdyo | Yeni oyun | Evet | Oyunun ait olacağı stüdyo (stüdyo kartından açtıysanız seçilmiş gelir) |
| Oyun adı | Yeni oyun | Evet | 1-160 karakter |
| Kısa ad | Yeni oyun | Hayır | Küçük harf, rakam, tire; en çok 48 karakter |
| Yeni ad | Yeniden adlandır | Evet | 1-160 karakter |
| Gerekçe | Hepsi | Evet | 8-500 karakter |
Sık karşılaşılan durumlar
| Durum | Ne yapmalı |
|---|---|
| Sayfayı göremiyorum | Stüdyo yönetme yetkisi yalnızca en geniş yetkili rolde bulunur; bir süper yöneticiden isteyin. |
| “Arşivle” pasif, “Seçili ortam” notu var | Şu an çalıştığınız ortam bu kaydın içinde; başka bir oyunun ortamına geçip tekrar deneyin. |
| “Bu oyunun etkin ortamı yok” yazıyor | Oyunun etkin (arşivlenmemiş) ortamı kalmamıştır; önce ortamı geri açın. |
| Kısa ad hatası | Küçük harf, rakam ve tire kullanın; tire başta, sonda ya da art arda olamaz. |
| Arşivleme reddedildi | Oyunun canlı yetkisi ya da etkin API anahtarı olabilir; önce onları kapatın. |
İlgili dokümanlar
Panel yöneticileri
Amaç
Bu sayfa, admin paneline giren yönetici hesaplarını listeler ve yönetir. Yönetici, oyun oyuncusu değil, paneli kullanan kişidir; oyuncu hesapları için Oyuncular sayfasına bakın. Her yöneticinin bir rolü ve erişebildiği ortamların listesi vardır. Sayfa yalnızca yönetici okuma yetkisi olan hesaplara açıktır.
Ne zaman kullanılır
- Ekibe yeni bir yönetici eklemek için.
- Bir yöneticinin rolünü ya da ortam erişimini değiştirmek için.
- Ayrılan bir yöneticinin hesabını kapatmak ve oturumlarını sonlandırmak için.
- Telefonunu kaybeden yöneticinin iki adımlı doğrulamasını sıfırlamak için.
Adım adım
Yönetici oluşturma
- Operatör oluştur düğmesine basın. Düğmeyi yalnızca yönetici yazma yetkisi olan hesaplar görür.
- E-posta ya da kullanıcı adından en az birini, görünen adı, rolü ve geçici parolayı girin.
- Erişebileceği ortamları seçin. Varsayılan olarak şu an seçili ortam gelir.
- İşlem nedeni yazıp kaydedin. Yöneticinin sayfası açılır.
Rol ve ortam değiştirme
- Listeden yöneticiyi açın ve Düzenle düğmesine basın.
- Görünen adı, rolü ve ortamları değiştirin; nedeni yazıp kaydedin. E-posta, kullanıcı adı ve parola bu formdan değiştirilemez.
Hesabı kapatma, oturum ve 2FA
- Yöneticinin sayfasındaki “Güvenlik eylemleri” kartını kullanın.
- Devre dışı bırak yeni girişleri reddeder; açık oturumlar ayrıca Oturumları revoke et ile kapatılmalıdır. Etkinleştir hesabı yeniden açar.
- 2FA’yı sıfırla yöneticinin authenticator’ını ve kurtarma kodlarını siler, bütün oturumlarını kapatır. Yönetici yalnızca parolasıyla girer ve iki adımlı doğrulamayı yeniden kurmalıdır. Onay için kendi parolanızı yazarsınız.
Uyarı
Kendi hesabınızı devre dışı bırakamaz, oturumlarınızı kapatamaz ya da kendi 2FA’nızı sıfırlayamazsınız; bu güvenlik için kapalıdır.
Alanlar ve seçenekler
Roller
| Rol | Yapabilecekleri |
|---|---|
| super_admin | Bütün ortamlara ve bütün yönetim işlemlerine erişir; yönetici hesaplarını, stüdyoları, eklentileri ve güvenlik şalterlerini yalnızca bu rol yönetir |
| game_manager | Atanmış ortamlarda oyun ve oyuncu kaynaklarını yönetir; yönetici hesapları, stüdyolar, eklenti yönetimi, güvenlik şalterleri, giriş sağlayıcı kimlik bilgileri ve işlem geçmişindeki yönetici ayrıntıları dışında çoğu işlemi yapar |
| support | Atanmış ortamlarda destek yapar: oyuncuları, oturumları ve sohbeti okur; oyuncu bilgisini günceller, yasaklar, oturum kapatır, sohbette susturur |
| read_only | Atanmış ortamlarda yalnızca okur |
Oluşturma ve düzenleme formu
| Alan | Zorunlu | Açıklama |
|---|---|---|
| E-posta | Hayır* | *E-posta ya da kullanıcı adından en az biri; yalnız oluştururken |
| Kullanıcı adı | Hayır* | 3-32 karakter; yalnız oluştururken |
| Görünen ad | Evet | Panelde görünen ad |
| Rol | Evet | Dört rolden biri |
| Geçici parola | Evet (oluştururken) | En az 12 karakter |
| Ortamlar | Evet | Erişilecek ortamlar |
| İşlem nedeni | Evet | 8-500 karakter |
Listedeki sütunlar
Operatör, Rol, Durum (Etkin ya da Devre dışı), 2FA (Açık ya da Kapalı), Scope (erişilebilen ortam sayısı), Son giriş ve Oluşturulma varsayılan olarak görünür. E-posta, Kullanıcı adı ve Güncellenme sütunlarını sütun menüsünden açabilirsiniz.
Sık karşılaşılan durumlar
| Durum | Ne yapmalı |
|---|---|
| Sayfayı göremiyorum | Yönetici hesaplarını okuma yetkisi yalnızca en geniş yetkili roldedir; bir süper yöneticiden isteyin. |
| Ortam listesinde bir ortam yok | Listede yalnızca sizin de yetkili olduğunuz ortamlar çıkar; önce kendi erişiminizi genişletin. |
| “E-posta ya da kullanıcı adı gerekli” hatası | İkisini birden boş bırakamazsınız. |
| “Parola en az 12 karakter olmalı” hatası | Geçici parolayı 12 karakterden uzun yazın. |
| “2FA’yı sıfırla” düğmesi yok | Yöneticinin iki adımlı doğrulaması kapalı ya da kendi hesabınıza bakıyorsunuz. |
| Devre dışı bıraktığım yönetici hâlâ panelde | Devre dışı bırakma yeni girişleri engeller; açık oturumu Oturumları revoke et ile kapatın. |
İlgili dokümanlar
Oyuncu profili
Amaç
Bu sayfa tek bir oyuncunun hesabını gösterir: durum, hesap türü, son giriş, açık oturum sayısı, toplam oyun süresi ve ana para bakiyesi. Altındaki sekmelerde oyuncunun karakterlerini, cüzdanını, oturumlarını, giriş geçmişini, yasaklarını, bağlı hesaplarını ve işlem geçmişini görürsünüz. Sayfaya Oyuncular listesinden gelirsiniz.
Ne zaman kullanılır
- Bir oyuncunun yardım isteğini incelerken hesabının durumuna bakmak için.
- Oyuncunun adını, e-postasını ya da ek bilgilerini düzeltmek için.
- Parolayı sıfırlamak, misafiri kalıcı hesaba çevirmek için.
- Kural ihlali yapan oyuncuyu banlamak, banı kaldırmak ya da hesabı silmek için.
- Bir oyuncunun açık oturumlarını kapatmak ya da bağlı bir giriş yöntemini kaldırmak için.
Adım adım
İnceleme
- Sekmelerden birini seçin: Genel, Karakterler, Cüzdan ve envanter, Oyun süresi, Oturumlar, Giriş geçmişi, Yasaklar, Hesaplar, Geçmiş. Rolünüzün göremediği ya da modülü kapalı sekmeler görünmez ya da “yetki gerekir” notu gösterir.
- Genel sekmesinde profil bilgilerini, son güvenlik olaylarını ve ek bilgileri (metadata) görürsünüz.
Profili düzenleme
- Profili düzenle düğmesine basın. Düğmeyi yalnızca düzenleme yetkisi olan yöneticiler görür.
- Görünen adı, e-postayı, e-posta doğrulama durumunu, görseli ve ek bilgileri değiştirin. Yalnızca değiştirdiğiniz alanlar kaydedilir.
- Sayfanın altındaki İşlem nedeni alanını doldurup kaydedin. Kaydetmeden başka sayfaya geçmeye çalışırsanız panel sizi uyarır.
Parola yönetimi
- Kayıtlı hesapta Diğer işlemler menüsünden Parola yönet ile yeni parola verin (en az 12 karakter) ya da Rastgele parola üret ile sistemin parola üretmesini isteyin.
- Misafir hesapta Hesaba çevir işlemi misafire e-posta ve tek seferlik rastgele parola verir.
- Üretilen parola yalnızca bir kez gösterilir ve yeniden getirilemez. Oyuncuya güvenli bir kanaldan iletin; Gizle düğmesi, sekme ya da sayfa değişimi parolayı bellekten siler. Parola üretme ve dönüştürme açık oturumları kapatır.
Banlama ve ban kaldırma
- Diğer işlemler menüsünden Banla seçin (zaten yasaklıysa Yasağı düzenle ve Banı kaldır görünür).
- Süreyi seçin, isteğe bağlı yasak gerekçesini ve işlem nedenini yazın, Banla düğmesine basın.
- Oyuncunun bütün oturumları kapanır ve yeniden giriş yapamaz. Banı kaldırınca oyuncu yeniden giriş yapabilir ama kapatılan oturumlar geri gelmez.
Oturum, hesap bağı ve silme
- Oturumlar sekmesinden tek bir oturumu iptal edebilir, Diğer işlemler menüsünden Tüm oturumları kapat diyebilirsiniz.
- Hesaplar sekmesinden bir giriş yöntemi bağını kaldırabilirsiniz. Son giriş yöntemini kaldırırsanız oyuncu giremez; önce diğer yöntemleri kontrol edin.
- Oyuncuyu sil işlemi hesabı silinmiş olarak işaretler ve erişime kapatır; kayıt tamamen yok edilmez. Panelde silmeyi geri alan bir düğme yoktur. Onay için oyuncunun adını (yoksa e-postasını) yazarsınız.
Uyarı
Tüm bu işlemler değiştirilemeyen işlem geçmişine kaydedilir. Silme ve oturum kapatma işlemleri oyuncuyu hemen etkiler.
Alanlar ve seçenekler
Profil düzenleme formu
| Alan | Zorunlu | Açıklama |
|---|---|---|
| Görünen ad | Evet | Oyuncunun görünen adı |
| E-posta | Hayır | Boşsa e-posta kaldırılır; ayrı yetki gerekir |
| E-posta doğrulandı | Hayır | Adresin doğrulanmış sayılması; ayrı yetki gerekir |
| Görsel URL | Hayır | Oyuncu görselinin adresi |
| Metadata JSON | Hayır | JSON nesnesi |
| İşlem nedeni | Evet | 8-500 karakter |
Yasak penceresi
| Alan | Zorunlu | Açıklama |
|---|---|---|
| Süre | Evet | 1, 3, 7, 30 gün, süresiz ya da özel tarih ve saat (en çok 365 gün) |
| Yasak gerekçesi | Hayır | En çok 200 karakter; yalnız yönetici ekranlarında görünür |
| İşlem nedeni | Evet | 8-500 karakter |
Parola pencereleri
| Alan | Pencere | Açıklama |
|---|---|---|
| Yeni parola | Parola yönet | En az 12 karakter |
| E-posta | Hesaba çevir | Hesabın giriş e-postası |
| İşlem nedeni | Hepsi | Parola ve dönüştürme pencerelerinde en çok 200 karakter |
Sık karşılaşılan durumlar
| Durum | Ne yapmalı |
|---|---|
| E-posta alanı pasif | Rolünüzde e-posta ve doğrulama değiştirme yetkisi yoktur; bir yöneticiden isteyin. Görünen adı yine de değiştirebilirsiniz. |
| “Profili düzenle”, “Banla” ya da “Parola yönet” yok | İlgili yetki rolünüzde yok. Düğmeler yalnızca yetkili yöneticilere görünür. |
| Üretilen parolayı kaybettim | Parola yeniden gösterilmez; işlemi yeniden başlatıp yeni parola üretin. |
| “Parola daha önce gösterildi” notu çıktı | Aynı işlem zaten tamamlanmıştı; yeni bir parola için işlemi yeniden başlatın. |
| Banladığım oyuncunun oturumu görünüyor | Ban bütün oturumları kapatır; Oturumlar sekmesini yenileyip durumlarına bakın. |
| Metadata hatası | Geçerli bir JSON nesnesi yazın; dizi ya da düz metin kabul edilmez. |
İlgili dokümanlar
Karakter profili
Amaç
Bu sayfa tek bir karakterin ayrıntısını gösterir: seviye, XP, kayıt sürümü, hangi oyuncuya ait olduğu, özellikleri, cüzdanı ve olay geçmişi. Üstte en çok altı temel bilgi, altında bölüm sekmeleri bulunur. Sayfaya Oyuncu karakterleri listesinden satıra tıklayarak gelirsiniz.
Ne zaman kullanılır
- Bir oyuncunun karakter durumuyla ilgili şikâyeti incelemek için.
- Bir değişikliğin nasıl ve ne zaman olduğunu olay geçmişinden görmek için.
- Hatalı bir değişikliği düzeltmek için komut çalıştırmak ya da önceki sürüme dönmek için.
Adım adım
İncelemek
- Sekmelerden birini seçin: Genel, İstatistikler, Cüzdan ve envanter, Geçmiş, Gelişmiş. Yetkiniz olmayan ya da modülü kapalı bölüm görünmez ya da “yetki gerekir” notu gösterir.
- Oyuncuya geçmek için temel bilgilerdeki Oyuncu profiline git bağlantısını kullanın.
Komut çalıştırmak
- Gelişmiş sekmesinde Komut çalıştır düğmesine basın. Düğmeyi yalnızca komut yetkisi olan yöneticiler görür.
- Komut listesinden komutu seçin; seçime göre ilgili alanlar görünür.
- Değerleri girin, İşlem nedeni yazın ve komutu uygulayın.
- Komut karakterin o anki sürümü üzerinde çalışır. Siz formu doldururken karakter başka bir yerden değiştiyse işlem sürüm çakışmasıyla reddedilir; profili yenileyip tekrar deneyin.
Önceki sürüme dönmek
- Gelişmiş sekmesinde Geri al düğmesine basın. Düğmeyi yalnızca geri alma yetkisi olan yöneticiler görür.
- Hedef sürüm alanına dönmek istediğiniz sürüm numarasını yazın (en az 1) ve nedeni ekleyin.
Uyarı
Önceki sürüme dönmek geçmişi silmez. Karakteri o sürümdeki duruma getiren yeni bir olay yazılır; eski olaylar yerinde kalır.
Geçmişteki hâlini görmek
- Gelişmiş sekmesinde “Geçmişteki hâli” bölümüne zamanı yazın ve Hâlini göster düğmesine basın. Karakterin o andaki durumu olay geçmişinden yeniden hesaplanır.
Alanlar ve seçenekler
Komut penceresi
| Alan | Hangi komutlarda | Açıklama |
|---|---|---|
| Komut | Hepsi | Bayrak ayarla, Özellik değeri ata, Kaynak ekle ya da çıkar, Değiştirici ekle, Değiştirici kaldır, Deneyim puanı (XP) ekle, Önceki sürüme dön |
| Bayrak anahtarı, Bayrak değeri | Bayrak ayarla | Bayrağın adı ve açık/kapalı durumu |
| Anahtar | Özellik değeri ata, Kaynak ekle ya da çıkar | Özelliğin ya da kaynağın anahtarı |
| Değer / Miktar / XP miktarı / Hedef sürüm | Bayrak dışındaki komutlar (Değiştirici kaldır hariç) | Tam sayı |
| Etkilenen istatistik, Değiştirici türü | Değiştirici ekle | Hangi istatistik, nasıl etkilenecek |
| Kaynak türü, Kaynak kimliği | Değiştirici ekle ve kaldır | Değiştiricinin kaynağı |
| İşlem nedeni | Hepsi | En az 8 karakter |
Geçmişteki hâli
| Alan | Zorunlu | Açıklama |
|---|---|---|
| Tarih ve saat | Evet | RFC 3339 zamanı; gelecek ya da geçersiz zaman reddedilir |
Sık karşılaşılan durumlar
| Durum | Ne yapmalı |
|---|---|
| “Komut çalıştır” düğmesi pasif | Karakter bilgisi yüklenememiştir; profili yenileyin. |
| Komut sürüm çakışmasıyla reddedildi | Karakter başka bir yerden değişmiştir; profili yenileyip komutu tekrar çalıştırın. |
| “tanımsız attribute” ya da “tanımsız resource” hatası | Anahtar karakterin tanımında yoktur; tanımdaki yazımla birebir aynı olmalı. Hesaplanan alanlar da elle atanamaz. |
| Değer “min altında” ya da “max üstünde” hatası | Tanımdaki alt ya da üst sınırı aşıyorsunuz; değeri sınırlar içinde seçin. Kaynak eklerken miktar 0 olamaz. |
| Bir sekme görünmüyor | Rolünüzün o bölümü görme yetkisi yok ya da ilgili modül kapalı. |
| Geçmiş boş | “Bu karakter için olay kaydı yok.” yazar; karakter henüz komut almamıştır. |
İlgili dokümanlar
Model
Amaç
Bu sayfa tek bir 3D modelin ayrıntısıdır: önizleme, dosyadan hesaplanan değerler, sürümler, modeli kullanan tanımlar ve yayın geçmişi. Modelin hangi sürümünün oyuna gideceğini buradan seçersiniz.
Ne zaman kullanılır
- Dönüştürülen modeli oyuna yayınlamak için.
- Yanlış çıkan bir yayını önceki sürüme geri almak için.
- Modele animasyon klipleri eklemek için.
- Modeli arşivlemek, yeniden adlandırmak ya da kalıcı olarak silmek için.
Adım adım
Sürüm yayınlama
- Sürümler tablosunda durumu Hazır olan sürümün Yayınla düğmesine basın.
- Yayın, yayındaki sürümün klip ya da boyutlarında büyük bir değişiklik getirmiyorsa hemen yapılır.
- Sürüm yayındaki bir klibi kaldırıyorsa ya da sınır kutusunu belirgin biçimde değiştiriyorsa bir onay penceresi açılır. Pencere kaldırılan ve eklenen klipleri ve boyut farkını gösterir. Farkı gördüm, yine de yayınla kutusunu işaretleyin, bir neden yazın ve onaylayın.
Geri alma
Yayındakinden eski bir sürümde düğme Geri al olarak görünür ve her zaman onay penceresi açar. Geri alma yalnızca hâlâ saklanan sürümlere yapılabilir.
Uyarı
Yayından kalkan sürümler, varsayılan ayarda 14 gün sonra silinir; saklama süresi dolmuş sürüme geri dönülemez. Tabloda her sürümün saklama tarihi görünür.
Klip ekleme
- Klip ekle düğmesine basın. Düğme, iskeletli bir fbx ya da blend kaynaklı hazır sürüm yoksa kapalıdır ve nedeni yanında yazar.
- Taban sürümü seçin, klip dosyasını ya da zip paketi seçin ve Yükle’ye basın.
- Sunucu klipleri taban sürümün iskeletine bağlayıp yeni bir sürüm üretir; yeni sürümü sonra yayınlayabilirsiniz.
Yeniden adlandırma, arşivleme, silme
Üstteki düğmelerle yapılır; her biri bir neden ister.
- Yeniden adlandır: Yeni ad kütüphanede görünür; mevcut başvurular etkilenmez.
- Arşivle: Model yeni seçimlere kapanır; onu kullanan tanımlar çalışmaya devam eder. Arşivden çıkar ile geri açılır.
- Kalıcı sil: Yalnızca arşivlenmiş modelde ve hiçbir tanım kullanmıyorsa yapılır. Geri alınamaz; modelin bütün sürümleri silinir.
Alanlar ve seçenekler
| Alan | Nerede | Açıklama |
|---|---|---|
| Önizlenen sürüm | Önizleme | Hangi sürümün gösterileceği |
| Taban sürüm | Klip ekle | Klipleri alacak sürüm |
| Klip dosyası ya da zip | Klip ekle | fbx ya da zip |
| Yeni ad | Yeniden adlandır | En çok 200 karakter |
| Farkı gördüm, yine de yayınla | Yayın onayı | Zorunlu onay kutusu |
| İşlem nedeni | Yeniden adlandır, arşiv, silme, onaylı yayın | 8-500 karakter |
Sayfadaki bölümler
- Önizleme: 3D görüntüleyici; seçilen sürümün kliplerini oynatabilirsiniz.
- Olgular: Üçgen, köşe, kemik, malzeme, doku sayıları, boyut, glb dosya boyu ve klip listesi. Sunucu bunları glb dosyasından kendisi hesaplar.
- Uyarılar: Dönüştürme sırasındaki ufak sorunlar (örneğin eksik doku ya da atlanan klip). Yayını engellemez.
- Sürümler: Her sürümün kaynağı, durumu, kaynak dosyaları (indirilebilir), saklama süresi ve yayın düğmesi.
- Kullanan tanımlar: Bu modeli kullanan eşya, karakter ve içerik kaydı tanımları.
- Yayın geçmişi: Hangi sürümün ne zaman, hangi nedenle yayınlandığı.
Sık karşılaşılan durumlar
| Durum | Ne yapmalı |
|---|---|
| “Kalıcı sil” düğmesi kapalı, “bu modeli N tanım kullanıyor” yazıyor | Önce modeli kullanan tanımlardan çıkarın; sonra silebilirsiniz. |
| Yayınlarken “siz bakarken başka bir yayın yapıldı” notu çıktı | Fark yenilendi; yeni farkı inceleyip yeniden onaylayın. |
| “Klip ekle” kapalı | Klip yalnızca iskeletli, hazır fbx ya da blend kaynaklı sürümlere eklenebilir. |
| Eski sürüme geri dönemiyorum | Sürümün saklama süresi dolmuştur; modeli yeniden yükleyin. |
| Önizleme açılmıyor | Önizleme için hazır ve saklanan bir sürüm gerekir; dönüştürme bitmemiş ya da başarısız olabilir. |
İlgili dokümanlar
İçerik grubu düzenle
Amaç
Bu ekran bir içerik grubunu iki adımda kurar: önce adı, simgesi ve açıklaması; sonra grubun alanları. Alanlar, bu gruptaki her kaydın dolduracağı değerlerdir (azami hız, renk, 3D model gibi). Aynı ekran var olan bir grubun şemasını değiştirmek için de kullanılır; o durumda başlığı “Grubu düzenle” olur.
Ne zaman kullanılır
- Yeni bir içerik grubu kurarken.
- Mevcut gruba alan eklemek, alan sırasını değiştirmek ya da bir alanın sınırlarını güncellemek için.
Adım adım
Yeni grup kurma
- İçerik sayfasında Yeni grup’a basın; isterseniz bir şablon seçin.
- 1 / 2 adımında grup adını yazın. Yeni grupta anahtar addan önerilir; istediğiniz gibi değiştirebilirsiniz, kaydettikten sonra değişmez.
- Devam: alanlar ile ikinci adıma geçin.
- Alan ekle ile her alan için ad, tür ve gerekirse sınırları girin. Alanları yukarı ve aşağı oklarıyla sıralayın.
- Sayfadaki canlı önizlemeyle kayıt formunun nasıl görüneceğini kontrol edin ve Grubu oluştur deyin.
Var olan grubun şemasını değiştirme
- Grubun kayıt listesinde Şemayı düzenle’ye basın.
- Kaydedilmiş alanların anahtarı ve türü kilitlidir. Farklı bir tür gerekiyorsa Yeni alan olarak ekle ile yeni bir alan açın.
- Kaydet’e basın. Şema değişikliği de, kayıtlar gibi taslaktır; oyuna yayınlayınca gider.
Not
Kaydedilmemiş değişiklik varken Vazgeç’e basarsanız panel çıkmadan önce onay ister.
Alanlar ve seçenekler
Grup bilgileri
| Alan | Zorunlu | Açıklama |
|---|---|---|
| Grup adı | Evet | Panelde görünen ad |
| Anahtar | Evet | Oyunun grubu bulduğu kimlik; kayıttan sonra sabit |
| Simge | Hayır | Kartta görünen simge |
| Kısa açıklama | Hayır | En çok 500 karakter |
Alan türleri
| Tür | Ne tutar | Ek ayarlar |
|---|---|---|
| Sayı | Tam sayı | Birim, ondalık hane, en az, en çok, varsayılan |
| Yüzde | Yüzde değeri | En az, en çok, varsayılan |
| Metin | Metin | En çok karakter, çok satırlı |
| Evet / Hayır | Mantıksal değer | Varsayılan |
| Seçenek listesi | Listeden seçim | Seçenekler (en çok 64), birden fazla seçilebilir |
| Renk | #rrggbb renk | Yok |
| 3D model | Model kütüphanesinden bir model | Yok; Sahneler modülü kapalıysa seçilemez |
| Görsel | Yüklenmiş bir görsel | Yok |
| Başka bir kayıt | Başka bir kayda bağlantı | Hedef, hedef grup |
| Tablo | Tekrarlanan satırlar, örneğin seviye-hasar tablosu | En az satır, en çok satır, sütunlar (en çok 8) |
Her alan için ortak ayarlar
| Alan | Zorunlu | Açıklama |
|---|---|---|
| Alan adı | Evet | Formda görünen ad |
| Anahtar | Evet | Oyunun okuduğu kimlik; kayıttan sonra sabit |
| Tür | Evet | Kaydedilmiş alanda değişmez |
| Görünürlük | Evet | Oyuncu görebilir ya da yalnız oyun sunucusu |
| Yardım metni | Hayır | Formda alanın altında görünür |
| Zorunlu | Hayır | Boş bırakılırsa kayıt kaydedilemez |
| Listede göster | Hayır | Liste ve özette de gösterir |
Bir grupta en çok 48 alan olur.
Sık karşılaşılan durumlar
| Durum | Ne yapmalı |
|---|---|
| Anahtarı yanlış yazdım ve kaydettim | Anahtar değişmez. Doğru anahtarla yeni bir alan ekleyin; eskisi artık gerekmiyorsa kayıtlardan kaldırın. |
| “3D model” türü seçilemiyor | Sahneler modülü bu ortamda kapalıdır; modülü açın. |
| Bir alanın türünü değiştiremiyorum | Kaydedilmiş alanın türü sabittir. Yeni alan olarak ekle ile yeni tür için ayrı bir alan açın. |
| Bazı alanlarda kilit simgesi var | Bir eklenti (örneğin Package & Ride) o alanı kullanıyor; silinemez ve türü değişmez. |
| Kayıtlı tabloya zorunlu metin sütunu ekleyemiyorum | Önce isteğe bağlı olarak ekleyin; mevcut satırlarda değer olmadığı için yeni zorunlu sütun reddedilir. |
| “Devam: alanlar” sonraki adıma geçmiyor | 1. adımda ad ya da anahtar eksik ya da geçersizdir; kırmızı mesajları düzeltin. |
İlgili dokümanlar
İçerik kaydı
Amaç
Bu ekran, bir içerik grubundaki tek kaydı gösterir ve düzenler. Kaydın alanlarını grubun şeması belirler; yani formdaki alanlar gruptan gruba değişir. Burada yaptığınız değişiklik taslaktır: oyuna ancak grubun kayıt listesindeki Yayınla ile gider.
Ne zaman kullanılır
- Bir kaydın değerlerini (örneğin bir aracın hızını) güncellemek için.
- Gruba yeni kayıt eklemek için.
- Kaydı arşivlemek ya da arşivden çıkarmak için.
Adım adım
Kaydı düzenleme
- İçerik sayfasından grubu, listeden de kaydı açın.
- Düzenle’ye basın. Düğmeyi yalnızca içerik yazma yetkisi olan yöneticiler görür.
- Değerleri değiştirin. Zorunlu alanlar adlarının yanında “(zorunlu)” ile işaretlidir.
- Sayfanın altındaki Taslağı kaydet düğmesine basın. Değişiklik taslağa yazılır; liste ve kayıtta “Taslak değişikliği var” görünür.
- Oyuna göndermek için kayıt listesinde Yayınla’yı kullanın.
Yeni kayıt oluşturma
- Grubun kayıt listesinde Yeni kayıt’a basın.
- Kayıt adı’nı yazın; anahtar addan önerilir, isterseniz değiştirin.
- Alanları doldurun ve Taslağı kaydet deyin. Kayıt taslağa eklenir.
Not
Bir eklentinin kullandığı kapalı gruplarda (örneğin Package & Ride araçları) yeni kayıt eklenemez; panel nedenini sayfada yazar.
Arşivleme
Daha fazla menüsünden Arşivle ya da Arşivden çıkar’ı seçin. Arşiv de bir taslak değişikliğidir; yayınlanınca oyuna yansır.
Alanlar ve seçenekler
Her kayıtta bulunan alanlar
| Alan | Zorunlu | Açıklama |
|---|---|---|
| Kayıt adı | Evet | Panelde görünen ad |
| Anahtar | Yeni kayıtta | Oyundaki kimlik; kayıttan sonra sabit |
Grubun alanları
Geri kalan alanlar grubun şemasından gelir. Her alanın altındaki gri metin, grubu kuran kişinin yazdığı yardım metnidir. Türlere göre giriş şöyledir:
| Alan türü | Girişi |
|---|---|
| Sayı, Yüzde | Sınırlar içinde sayı; ondalık haneler grubun ayarına göredir |
| Metin | Serbest metin; üst karakter sınırı grubun ayarındadır |
| Evet / Hayır | Onay kutusu |
| Seçenek listesi | Tek ya da çoklu seçim |
| Renk | Renk seçici |
| 3D model | Model kütüphanesinden seçim; kaydın üstünde önizleme görünür |
| Görsel | Görsel yükleme |
| Başka bir kayıt | Hedef gruptan kayıt seçimi |
| Tablo | Satır ekleme, silme ve taşıma; kayıt başına tablo verisi toplamda 128 KiB’ı aşamaz |
“Yalnız oyun sunucusu” olarak işaretli alanlar oyuncuya gitmez; panelde rozetle görünür.
Bölümler
- Özellikler: Değerler.
- Bağlantılar: Bu kaydın bağlandığı kayıtlar ve bu kayda bağlanan kayıtlar.
- Kullanan: Bir eklenti bu grubu kullanıyorsa hangi özelliğin kullandığı.
- Geçmiş: Kaydın revizyon sayısı, son değişiklik zamanı ve son yayınlar.
Sık karşılaşılan durumlar
| Durum | Ne yapmalı |
|---|---|
| “N sorun var; alanların altındaki mesajlara bakın” | Kırmızı mesajı olan alanları düzeltin; mesajlar değer göstermeden neyin yanlış olduğunu söyler. |
| Anahtar hatası alıyorum | Anahtar küçük harf ya da rakamla başlamalı; yalnız küçük harf, rakam, alt çizgi ve tire içermeli. |
| Fiyat alanı düzenlenemiyor, “Mağazada yönetilir” yazıyor | Araç kaydının mağazada ürünü varsa fiyatın tek kaynağı üründür; Ürün sayfasından değiştirin. |
| Sayfadan çıkarken onay soruyor | Kaydedilmemiş değişiklik var; Düzenlemeye dön ile kaydedin ya da Değişiklikleri at deyin. |
| Başkası aynı anda kaydı değiştirdi | Kayıt sürüm kontrolüyle yazılır; sayfayı yenileyip değişikliği yeniden yapın. |
İlgili dokümanlar
Mağaza ürünü
Amaç
Bu sayfa tek bir mağaza ürününün ayrıntısını gösterir; aynı ürünü düzenlemek ya da yeni ürün oluşturmak için de kullanılır. Ürün, bir vitrinde duran ve bir eşyayı satan kayıttır. Fiyat, stok, kişi başı sınır, rozet ve satış zamanı buradan belirlenir.
Ne zaman kullanılır
- Vitrine yeni ürün eklemek için.
- Ürünün fiyatını, stoğunu ya da görselini değiştirmek için.
- Ürünü yayından kaldırmak, geri almak ya da silmek için.
- Ürünün satış geçmişine ve değişiklik geçmişine bakmak için.
Adım adım
Yeni ürün ekleme
- Mağaza sayfasında vitrini seçip Yeni ürün’e basın.
- Ne satılıyor? alanında eşyayı adıyla arayıp seçin.
- İsterseniz vitrindeki adı, açıklamayı ve görseli yazın.
- Nasıl ödenir? bölümünde oyun parası ya da gerçek parayı seçin; fiyatı ve para birimini ya da bağlanacak uygulama içi ürünü girin.
- Rozeti, stoğu ve kişi başı sınırı ayarlayın.
- Durumu (taslak ya da yayında), satış zamanını ve vitrini seçin.
- Bir neden yazın (panel değişiklikten bir öneri doldurur) ve Ürünü oluştur’a basın. Sağda ürünün oyunda nasıl görüneceğini gösteren bir önizleme bulunur.
Ürünü değiştirme
- Ürünün sayfasında Düzenle’ye basın.
- Alanları değiştirip Değişiklikleri kaydet’e basın.
Ürün sayfasındaki öteki düğmeler:
- Yayından kaldır ve Yayına al: Ürünü hemen taslağa çevirir ya da yayına alır.
- Sil: Ürünü siler; bir neden ister. Geçmiş satışlar korunur.
Not
Fiyatı, stoğu ya da zamanı değiştirmek için ürünü silmenize gerek yoktur; düzenleme mevcut ürünü günceller.
Alanlar ve seçenekler
| Alan | Zorunlu | Açıklama |
|---|---|---|
| Ne satılıyor? | Evet | Satılacak eşya |
| Vitrindeki adı | Hayır | En çok 120 karakter; boşsa eşya adı |
| Açıklama | Hayır | En çok 2000 karakter |
| Ürün görseli | Hayır | PNG, JPEG ya da WebP |
| Nasıl ödenir? | Evet | Oyun parası ya da gerçek para |
| Para birimi ve Fiyat | Oyun parasında | Fiyat 0’dan büyük |
| Uygulama içi ürün | Gerçek parada | App Store ya da Google Play ürünü |
| Rozet | Hayır | Yok, Yeni, İndirim, Sınırlı, Popüler |
| Stok | Evet | Sınırsız ya da sınırlı; sınırlıda adet |
| Bir oyuncu en çok kaç tane alabilir? | Hayır | Boşsa sınırsız |
| Durum | Evet | Taslak ya da Yayında |
| Ne zaman satışta? | Evet | Hemen ya da tarih aralığı |
| Vitrin | Evet | Oluşturduktan sonra değişmez |
| İşlem nedeni | Evet | 8-500 karakter |
Ürün sayfasındaki sekmeler
- Ayrıntılar: Satış (fiyat, stok, kişi başı sınır, rozet), yayın durumu ve zamanı, “Ne verir” (satılan eşya).
- Satışlar: Toplam adet ve gelir ile satış tablosu; durum, kaynak (mağaza ya da oyun içi) ve oyuncuya göre süzülür.
- Geçmiş: Ürünün değişiklik olayları, en yeni üstte.
Sık karşılaşılan durumlar
| Durum | Ne yapmalı |
|---|---|
| “Satılacak bir eşya seçin” | Önce eşyayı seçin; liste boşsa İçerik sayfasından eşya ekleyin. |
| “Fiyat 0’dan büyük bir sayı olmalı” | Fiyatı para biriminin kuruş hanesine uygun yazın; sıfır ya da boş olamaz. |
| “Stok, ayrılmış N adetten az olamaz” | Bu kadar adet zaten satın alma için ayrılmıştır; stoğu bunun altına indiremezsiniz. |
| “Bitiş, başlangıçtan sonra olmalı” | Tarih aralığını düzeltin; en az bir uç yazmalısınız. |
| “Bu ürünün API ile verilmiş bir görünürlük koşulu var” | Koşul panelden değiştirilemez; kaydedince olduğu gibi korunur. |
| Araç ürününün fiyatını İçerik’ten değiştiremiyorum | Mağazada ürünü olan aracın fiyatının tek kaynağı üründür; fiyatı burada değiştirin. |
İlgili dokümanlar
Para birimi
Amaç
Bu sayfa tek bir para biriminin ayrıntısıdır; aynı sayfa para birimi oluşturma ve düzenleme formu olarak da çalışır. Ayrıntı görünümünde para biriminin ikonu, anahtarı, sürümü, kuruş hanesi, arz tavanı ve gönderilebilirliği ile son 30 günün basılan ve yakılan miktarı, en çok bakiyesi olanlar, cüzdanlar, hareketler ve bu parayla fiyatlanan ürünler görünür.
Ne zaman kullanılır
- Yeni para birimi oluşturmak için.
- Kuruş hanesini, ikonu, arz tavanını ya da gönderilebilirliği değiştirmek için.
- Paranın oyunda nasıl dolaştığına bakmak için.
Adım adım
Yeni para birimi oluşturma
- Para birimleri sayfasında Yeni para birimi’ne basın.
- Ad’ı yazın. Anahtarı küçük harf, rakam, tire ve alt çizgiyle yazın; kaydettikten sonra değişmez.
- İsterseniz ikon görseli yükleyin.
- Kuruş hanesi’ni seçin. Sağdaki “Oyunda böyle görünür” önizlemesi örnek bir tutarı bu haneyle gösterir.
- Arz tavanını seçin ve Oyuncular arası gönderilebilir kutusunu gerektiği gibi işaretleyin.
- Bir neden yazın ve Para birimini oluştur’a basın.
Para birimini düzenleme
- Ayrıntı sayfasında Düzenle’ye basın.
- Alanları değiştirip Yeni sürüm olarak kaydet’e basın. Her kayıt yeni bir sürümdür; eski sürümler değişmez.
Uyarı
Kuruş hanesini değiştirmek yalnızca gösterimi değiştirir; saklanan bakiyeler ve fiyatlar aynı kalır. Bu yüzden hane değişince oyunculara gösterilen tutarlar farklı görünebilir. Değiştirmeden önce emin olun.
Alanlar ve seçenekler
| Alan | Zorunlu | Açıklama |
|---|---|---|
| Ad | Evet | En çok 120 karakter |
| Anahtar | Oluştururken | Küçük harf, rakam, tire, alt çizgi; sonradan değişmez |
| İkon görseli | Hayır | PNG, JPEG ya da WebP |
| Kuruş hanesi | Evet | 0 (tam sayı), 1, 2 (kuruş), 3 ya da 4 |
| Arz tavanı | Evet | Sınırsız ya da sınırlı |
| Toplam arz en çok | Sınırlıda | Kuruş haneli tutar |
| Oyuncular arası gönderilebilir | Hayır | Seçiliyse oyuncular birbirine gönderebilir |
| İşlem nedeni | Evet | 8-500 karakter |
Ayrıntı sayfasındaki kartlar
- Son 30 gün: Günlük basılan ve yakılan miktar.
- En çok bakiyesi olanlar: Dünün kapanışına göre bakiye sıralaması.
- Cüzdanlar ve Hareketler: Bu para birimindeki cüzdanlar (bakiyeye göre sıralanabilir) ve defter hareketleri. İlgili okuma yetkiniz yoksa görünmez.
- Bu parayla fiyatlanan ürünler: Mağazada bu para birimiyle fiyatlanan ürünler; ürün sayfasına bağlantı verir.
Sık karşılaşılan durumlar
| Durum | Ne yapmalı |
|---|---|
| “Bu anahtarla bir para birimi zaten var” | Başka bir anahtar yazın; mevcut para birimini değiştirmek için onu açıp Düzenle’yi kullanın. |
| “İkon görseli bu ortamda bulunamadı” | Görseli yeniden yükleyin. |
| Anahtarı değiştiremiyorum | Anahtar yalnızca oluştururken yazılır; yanlışsa yeni bir para birimi oluşturun. |
| “Bunu görme yetkiniz yok” yazan kartlar | Hesabınızın rolünde o bilgiyi okuma yetkisi yoktur. |
| Hane değiştirdim, tutarlar bozuk göründü | Hane yalnız gösterimdir; eski haneye dönüp yeni sürüm olarak kaydedin. |
İlgili dokümanlar
Ödül tablosu
Amaç
Bu sayfa tek bir ödül tablosunu gösterir; aynı sayfa tabloyu oluşturma ve düzenleme formu olarak da çalışır. Tablo iki parçadan oluşur: şans satırları (her çekilişte biri seçilir) ve her zaman verilenler (çekilişten bağımsız, her seferinde verilir). Tabloyu kaydetmeden önce deneyebilirsiniz.
Ne zaman kullanılır
- NPC, yaratık, turnuva ya da görev için yeni ödül tablosu kurmak için.
- Şansları ya da miktarları değiştirmek için.
- Tablonun nerede kullanıldığını ve son verilen ödülleri görmek için.
Adım adım
Yeni tablo oluşturma
- Ödül tabloları sayfasında Yeni ödül tablosu’na basın.
- Ad’ı ve Anahtar’ı yazın; anahtar kaydettikten sonra değişmez.
- Kaç çekiliş seçin.
- Satır ekle ile ödül satırlarını girin: tür, ne verdiği, en az ve en çok miktar ve şans. Satırları yukarı ve aşağı oklarıyla sıralayabilirsiniz.
- Şansların toplamını %100’e tamamlayın. Toplam, satırların altında canlı görünür; Kalanı ‘Ödül yok’ yap ile geri kalanı “ödül yok” satırına verebilirsiniz.
- İsterseniz Her zaman verilenler bölümüne çekilişten bağımsız ödüller ekleyin.
- Sağdaki Dene panelinden tabloyu kaydetmeden deneyin.
- Bir neden yazın ve Ödül tablosunu oluştur’a basın.
Tabloyu düzenleme
- Tablonun sayfasında Düzenle’ye basın.
- Satırları değiştirip Yeni sürüm olarak kaydet’e basın. Her kayıt yeni bir sürümdür; eski sürümler silinmez ve sürüm geçmişinde görünür.
Tabloyu deneme
Dene düğmesi tabloyla kaydetmeden 100 örnek çekiliş yapar ve hangi ödülün kaç kez çıktığını özetler. Hiçbir ödül verilmez ve her denemede sonuç değişir. Form eksikse (örneğin şanslar %100 değilse) düğme kapalıdır.
Tabloyu silme
Sil’e basın ve bir neden yazın. Tablo bir NPC kuralı, görev ya da içerik girdisi tarafından kullanılıyorsa silinemez; pencere kullanan yerleri listeler. Geçmişte verilen ödüller silinmez.
Alanlar ve seçenekler
Tablo bilgileri
| Alan | Zorunlu | Açıklama |
|---|---|---|
| Ad | Evet | En çok 120 karakter |
| Anahtar | Oluştururken | Küçük harf, rakam, tire, alt çizgi; sonradan değişmez |
| Kaç çekiliş | Evet | 1-10 |
Şans satırları (en çok 50)
| Alan | Açıklama |
|---|---|
| Ödül türü | Para, Eşya ya da Ödül yok |
| Ne | Para birimi ya da eşya |
| En az, En çok | Miktar aralığı; en çok boşsa en az ile aynı |
| Şans % | Satırın çıkma şansı; toplam tam %100 olmalı |
Her zaman verilenler (en çok 10)
Ödül türü (Para ya da Eşya), Ne, En az ve En çok alanlarından oluşur; şans yoktur.
Profil sayfasındaki kartlar
- Şans çubukları, Her zaman verilenler, Kaç çekiliş.
- Nerede kullanılıyor: Tabloyu kullanan NPC kuralları, görevler ve içerik girdileri.
- Son verilen ödüller: Tablodan verilen son ödüller; oyuncu, kaynak ve ödül.
- Sürüm geçmişi: Her sürümün tarihi ve satır sayısı; güncel olan rozetlidir.
Sık karşılaşılan durumlar
| Durum | Ne yapmalı |
|---|---|
| “Kaydetmek için toplam %100 olmalı” | Şansların toplamını tam %100’e getirin; eksik kalanı için “Ödül yok” satırı kullanabilirsiniz. |
| “Kaydetmek için en az bir ödül ekleyin” | En az bir şans satırı ya da bir “her zaman verilen” ödül gerekir. |
| “Bu anahtarla bir ödül tablosu zaten var” | Başka bir anahtar seçin; var olan tabloyu değiştirmek için onu açıp Düzenle’yi kullanın. |
| Tabloyu silemiyorum | Tablo kullanımdadır; önce kullanan yerlerden ayırın. Silme penceresi nerelerde kullanıldığını gösterir. |
| Miktar hatası alıyorum | Para miktarını para biriminin kuruş haneli biçimde yazın; en az 1, en çok 1.000.000 en küçük birim olabilir. |
| “Dene” kapalı | Formdaki eksikleri tamamlayın; şanslar %100 olmalıdır. |
İlgili dokümanlar
Leaderboard ayrıntısı
Amaç
Bu sayfa tek bir sıralama tablosunu profil sayfası düzeniyle gösterir. Üstte tablonun adı, kopyalanabilir anahtarı ve dört özet kutusu (bu sezon oyuncu sayısı, lider, son puan zamanı, sonraki sıfırlama) vardır. Altında üç sekme bulunur: Bu sezon, Geçmiş sezonlar ve Ayarlar.
Ne zaman kullanılır
- Tablonun en üst sıralarına ve belirli bir oyuncunun yerine bakmak için.
- Kapanmış sezonların kazananlarını ve kapanış tablosunu görmek için.
- Tablonun oyunda görünürlüğünü ya da puan biçimini değiştirmek için.
- Oyun kodunuzda tabloyu hangi anahtarla okuyacağınızı kopyalamak için.
Adım adım
Bu sezonun sırasını görme
- Bu sezon sekmesinde en üst sıralar listelenir. Her satırda sıra, oyuncu, puan ve son güncelleme zamanı vardır; oyuncunun adına tıklarsanız oyuncunun sayfası açılır.
- Belirli bir oyuncuyu görmek için Oyuncu bul alanına adını ya da e-postasını yazıp seçin. Oyuncunun çevresindeki satırlar ayrı bir kartta gösterilir.
Yasaklı ya da silinmiş oyuncular soluk gösterilir ve “oyunda gizli” diye etiketlenir; oyuncular bu satırları oyunda görmez.
Geçmiş sezonlara bakma
- Geçmiş sezonlar sekmesinde kapanmış sezonlar listelenir; her satır tarihi, oyuncu sayısını ve birinciyi gösterir.
- Bir satıra tıklayınca sezonun kapanış tablosu (ilk 100 satır) açılır. Kapanmış sezon değiştirilemez.
Ayarları değiştirme
- Ayarlar sekmesinde Oyunda görünsün, Puan nasıl gösterilsin? ve Birim eki alanlarını değiştirin.
- Kaydet düğmesine basın. Yalnızca değişen alanlar gönderilir.
Alttaki Tablo tanımı kartı anahtarı, sıralama yönünü, sıfırlama aralığını ve kaynağı salt okunur gösterir; bunlar kurulurken seçilir ve değiştirilemez. Geliştirici bilgisi bölümü oyuncu oturumuyla okuma ucunu ve SDK çağrısını gösterir.
Alanlar ve seçenekler
| Alan | Zorunlu | Açıklama |
|---|---|---|
| Oyuncu bul | Hayır | Yalnızca görüntüleme; oyuncunun çevresini gösterir |
| Oyunda görünsün | Hayır | Oyuncuların tabloyu görmesini açar ya da kapatır |
| Puan nasıl gösterilsin? | Evet | Sayı, para ya da süre |
| Birim eki | Hayır | En fazla 8 karakter; süre biriminde yoktur |
Sık karşılaşılan durumlar
| Durum | Ne yapmalı |
|---|---|
| “Bu sezon henüz puan yok” | Oyun sunucunuz bu sezon puan göndermemiştir. İlk puan gelince satır görünür. |
| “Tablo bulunamadı” | Bu anahtarla bir tablo yok ya da silinmiş; Leaderboard listesinden yeniden açın. |
| Ayarlar sekmesi kapalı | Alanları değiştirmek için tablo yönetme yetkisi gerekir; bir yöneticiden isteyin. |
| “Bu tabloya yalnız … eklentisi puan yazar” | Tabloyu bir eklenti kurmuştur. Puanları oyun sunucunuz değil eklenti yazar. |
| Sıralama yönünü ya da sıfırlamayı değiştirmek istiyorum | Bunlar kurulduktan sonra değişmez. Leaderboard sayfasından yeni bir tablo kurun. |
| Listede yalnızca ilk satırlar var | Sayfa ilk satırları gösterir; devamı bu sürümde listelenmiyor. |
İlgili dokümanlar
Kural kartı
Amaç
Bu sayfa tek bir oyun kuralının ayrıntısını gösterir: kural ne zaman çalışır, hangi koşullar vardır, ne yapar ve hangi değerleri siz ayarlarsınız. Burada yaptığınız değişiklikler hemen oyuna geçmez; sayfanın altında birikir ve tek bir yayınla birlikte uygulanır. Kuralın ne işe yaradığı oyunun eklentisi tarafından yazılmıştır; sayfanın başlığı ve metinleri eklentiden gelir.
Ne zaman kullanılır
- Bir kuralın değerini (süre, mesafe, hız eşiği gibi) değiştirmek için.
- Yayınlamadan önce değişikliğin sonucunu Ne değişir? önizlemesiyle görmek için.
- Kuralın korumasını geçici olarak gözleme almak ya da yeniden açmak için.
Adım adım
- Kurallar sayfasında bir karta tıklayın.
- Ne zaman, Koşullar ve Ne yap bölümlerini okuyun. Kilit simgeli koşullar değiştirilemez.
- Ne yap bölümünde bir değeri değiştirin. Alan, değeri birimiyle gösterir (örneğin saniye ya da km/sa); ondalık sayıyı virgülle yazabilirsiniz. Altında izin verilen aralık ve varsayılan değer yazar; Varsayılana dön düğmesi değeri eski haline getirir.
- İsterseniz sağdaki Ne değişir? kartında bir senaryo seçip Önizle düğmesine basın. Kart “şu an” ve “yeni” değerlerle olayların sırasını yan yana gösterir.
- Sayfanın altındaki çubukta Gözden geçir ve yayınla düğmesine basın. Açılan pencerede değişikliklerin listesini kontrol edin, nedeninizi yazın ve Yayınla düğmesine basın.
Not
Bekleyen değişiklikler yalnızca bu tarayıcı sekmesinde durur. Sayfayı yenilerseniz ya da sekmeyi kapatırsanız yayınlanmamış değişiklikler kaybolur. Başka kartlara geçmek onları silmez.
Uyarı
Bazı değerler yayından sonra hemen, bazıları ise sunucu yeniden başlayınca uygulanır. Kartta “Yayında: … · Bekliyor: …” satırı görürseniz değer yayınlanmıştır ama canlı dünya henüz eski değeri kullanıyordur.
Alanlar ve seçenekler
| Alan | Zorunlu | Açıklama |
|---|---|---|
| Ayar değeri | Hayır | Kartın her ayarı için bir satır; aralık dışı değer kabul edilmez |
| Kural şalteri (“Bu kural açık”) | Hayır | Yalnızca şalteri olan kartlarda görünür; yazma yetkisi ister |
| Senaryo (önizleme) | Hayır | Kartın sunduğu örnek durumlardan biri |
| Senaryo sayıları (önizleme) | Hayır | Senaryoya göre değişir; sınırlar alanın altında yazar |
| Neden değiştiriyorsunuz? (yayın penceresi) | Evet | 8-500 karakter |
Karttaki rozetler: Açık (koruma uygulanıyor), Gözlemde (kural oyuna uygulanmıyor), Değiştirildi (yayındaki değer varsayılandan farklı), Yayınlanmadı (bekleyen düzenleme var), Yeniden başlatınca (canlı dünya değeri yeniden başlatınca alır).
Sık karşılaşılan durumlar
| Durum | Ne yapmalı |
|---|---|
| Ayar alanları kapalı ve “yetkiniz yok” yazıyor | Değerleri okuyabilirsiniz ama değiştirmek için oyun kuralı yayın yetkisi gerekir; bir yöneticiden isteyin. |
| Yayın “başka bir değişiklik yayınlandı” diyor | Siz bakarken başka biri yayınlamıştır. Son durumu yükle düğmesine basın; düzenlemeleriniz korunur ve fark yeniden hesaplanır. |
| Yayın “bazı değerler kabul edilmedi” diyor | Listedeki ayar adına tıklayın; sayfa o alana gider. Mesajdaki sınıra göre düzeltip yeniden yayınlayın. |
| “Bu kural bulunamadı” yazıyor | Kart kimliği bu oyunun kataloğunda yoktur; Kurallar sayfasından yeniden açın. |
| Önizleme “yok” diyor | Bu kartın önizleme senaryosu bulunmuyor; yayınlamadan önce değerleri dikkatle kontrol edin. |
İlgili dokümanlar
Kural geçmişi
Amaç
Her oyun kuralı yayını yeni bir sürümdür. Bu sayfa sürümleri en yeniden eskiye sıralar: kim yayınladı, ne zaman, hangi nedenle ve hangi ayarlar değişti. Eski bir sürüme dönmek de yeni bir sürüm yazar; geçmiş hiçbir zaman silinmez.
Ne zaman kullanılır
- Yanlış yayınlanan bir ayarı hızla geri almak için.
- Bir ayarın ne zaman ve kim tarafından değiştirildiğini bulmak için.
- Bütün ayarları oyunun hazır (kod) değerlerine döndürmek için.
Adım adım
Bir sürümün değişikliklerini görme
- Sürümün altındaki Değişen ayarlar satırına tıklayın.
- Her ayar için “önceki değer → yeni değer” görürsünüz. Hiçbir ayarı değiştirmeyen sürüm bunu açıkça söyler.
Eski bir sürüme dönme
- Dönmek istediğiniz sürümün satırında Bu sürüme dön düğmesine basın. Yayında olan sürümde bu düğme görünmez.
- Açılan pencerede nedeninizi yazın ve Geri al düğmesine basın.
- O sürümün değerleri yeni bir sürüm olarak yayınlanır. Polis ayarları en geç 6 saniye içinde uygulanır.
Hazır (kod) değerlere dönme
- Sayfanın üstündeki Bugünkü (kod) değerlere döndür düğmesine basın.
- Nedeninizi yazıp Kod değerlerine döndür düğmesiyle onaylayın. Bütün ayarlar oyunun varsayılanlarına döner; bu da yeni bir sürümdür.
Not
Geri alma, “sürüm 7’ye geri alındı” gibi bir rozetle listede görünür. Hiçbir sürüm silinmez, yalnızca yeni bir sürüm eklenir.
Alanlar ve seçenekler
| Alan | Zorunlu | Açıklama |
|---|---|---|
| İşlem nedeni (geri alma penceresi) | Evet | 8-500 karakter |
Satırdaki rozetler: Yayında (şu an uygulanan sürüm), Geri alındı ya da Sürüm N’e geri alındı, Kod değerlerine döndürüldü.
Sık karşılaşılan durumlar
| Durum | Ne yapmalı |
|---|---|
| Geri alma düğmeleri yok | Geri almak için oyun kuralı yayın yetkisi gerekir; geçmişi okuyabilirsiniz. Bir yöneticiden isteyin. |
| “Henüz yayın yok” yazıyor | Ayarlar oyunun varsayılan değerlerinde; ilk yayından sonra sürümler burada görünür. |
| Geri alma “başka bir değişiklik yayınlandı” ile reddedildi | Siz bakarken başka biri yayınlamıştır. Sayfa güncel durumu yeniden okur; güncel sürümü görüp yeniden onaylayın. |
| Eski sürümleri göremiyorum | Liste sayfa sayfa yüklenir; sonda Daha eski sürümler düğmesine basın. |
İlgili dokümanlar
Otomasyon düzenleyici
Amaç
Otomasyon, “şu olay olunca, şu koşul doğruysa, şunu yap” biçiminde bir kuraldır. Bu sayfa kuralı üç adımda kurmanızı sağlar: Ne zaman (hangi olay), Koşullar (hangi durumda) ve Ne yap (karaktere ne yapılacağı). Kod yazmanız gerekmez; panel kuralı arkada sizin için hazırlar.
Ne zaman kullanılır
- Seviye atlayınca ödül, belirli bir yetenek açılınca kalıcı güç gibi otomatik sonuçlar tanımlamak için.
- Var olan bir kuralın koşulunu ya da eylemini değiştirip yeni sürüm yayınlamak için.
- Kuralı yayınlamadan önce bir karakter ve örnek olayla denemek için.
Adım adım
- Kurallar sayfasında Yeni kural düğmesine basın. Yeni kuralda önce Şablondan başla bölümünden hazır bir örnek seçebilir ya da Boş kural ile başlayabilirsiniz.
- Kural bölümüne bir ad yazın; anahtar otomatik üretilir.
- Ne zaman bölümünden olayı seçin.
- Koşullar bölümünde Koşul ekle ile koşul ekleyin. Hiç koşul eklemezseniz kural olay her olduğunda çalışır. Birden fazla koşulda “hepsi” ya da “herhangi biri” seçin.
- Ne yap bölümünde en az bir eylem bırakın; Eylem ekle ile ekleyebilir, okla sırasını değiştirebilirsiniz.
- İsterseniz Kuralı dene düğmesiyle bir karakter ve örnek olay seçip sonucu görün. Deneme hiçbir kayıt oluşturmaz.
- Dene ve yayınla bölümünde nedeninizi yazın. Yeni kural için Hemen açılsın kutusunu isteğe bağlı işaretleyin ve Yayınla düğmesine basın.
Var olan bir kuralı düzenlerken Yeni sürüm yayınla düğmesi görünür; anahtar değişmez.
Not
Yayınlanan kural varsayılan olarak kapalı kaydedilir. Kurallar listesindeki Aç düğmesi ya da Hemen açılsın kutusu onu çalıştırır.
Uyarı
Koşullarda ve eylemlerde yazdığınız özellik, kaynak, bayrak ve yetenek adları oyunun kendi adlarıyla birebir aynı olmalıdır. Yanlış yazılan ad kuralın beklediğiniz gibi çalışmasını engeller; yayınlamadan önce Kuralı dene ile gerçek bir karakterde sonucu görün.
Alanlar ve seçenekler
| Alan | Zorunlu | Açıklama |
|---|---|---|
| Kural adı | Evet | 1-120 karakter |
| Anahtar | Evet | Addan üretilir, en fazla 64 karakter; yayından sonra değişmez |
| Açıklama | Hayır | En fazla 500 karakter |
| Ne zaman | Evet | Olay seçimi (seviye atlama, kaynak değişimi, bayrak değişimi gibi) |
| Koşulların bağlacı | Birden fazla koşulda | Hepsi / herhangi biri |
| Neye bakılıyor, hangi bilgi, ad, karşılaştırma, değer, durum | Koşul eklenince | En fazla 20 koşul; sayı alanlarında tam sayı |
| Ne yapılsın, ad, miktar, durum | Evet (en az bir eylem) | En fazla 10 eylem; miktar sıfır olamaz |
| İşlem, değer, kaynak türü, kaynak adı | Güçlendirme eylemlerinde | Yüzde işlemlerinde değer yüzdenin 100 katıdır |
| Öncelik | Evet | 1-1000 arası tam sayı, varsayılan 100; “Gelişmiş” bölümündedir |
| Karakter, örnek olay bilgileri | Denemede | Yalnızca denemeyi etkiler |
| Neden değiştiriyorsunuz? | Evet | 8-500 karakter |
| Hemen açılsın | Hayır | Yalnızca yeni kuralda görünür |
Gelişmiş bölümü kuralın koşulunun CEL (koşul dili) karşılığını salt okunur gösterir; panel bunu koşul satırlarından kendisi üretir ve buradan düzenlenmez.
Sık karşılaşılan durumlar
| Durum | Ne yapmalı |
|---|---|
| “Yayınlamadan önce tamamlayın” listesi çıkıyor | Listedeki eksik alanları doldurun; yayınla düğmesi bunlar bitene kadar kapalı kalır. |
| “Bu anahtarla bir kural zaten var” | Kural adını ya da anahtarı değiştirin. |
| “Bu arada başka bir değişiklik yayınlandı” | Düzenlemeleriniz korunur. Son durumu yükle düğmesine basın ve yeniden yayınlayın. |
| “Kural kabul edilmedi” | Sunucu kuralı reddetmiştir; listedeki mesajlara göre düzeltin. Girdiğiniz değerler korunur. |
| Kural koşulunu değiştiremiyorum, “kodla (CEL) yazılmış” yazıyor | Kural panel dışından kodla yazılmıştır. Panelde görüntülenir, açılıp kapatılır ve eski sürüme döndürülür ama düzenlenemez. |
| Düzenleme alanları kapalı | Kural yazma yetkiniz yoktur; bir yöneticiden isteyin. |
| Deneme “karakter seçin” diyor | Denemek için karakter aramasından bir karakter seçmelisiniz. |
İlgili dokümanlar
Ortamlar ve alan adları
Amaç
Bir oyunun birden çok ortamı olabilir: geliştirme (dev), hazırlık (staging) ve canlı (prod). Her ortamın kendi oyuncuları, verisi ve API anahtarları vardır. Bu sekme oyunun ortamlarını kart olarak listeler; her ortamı kendi alan adlarına bağlamanızı, yeni ortam eklemenizi ve ortamı arşivlemenizi sağlar. Sekme yalnızca süper yöneticiye açıktır.
Ne zaman kullanılır
- Oyununuz tarayıcıda yeni bir adresten açılacaksa o adresi ortama bağlamak için.
- Hazırlık ya da geliştirme ortamı eklemek için.
- Kullanılmayan bir ortamı gizlemek için.
Adım adım
Alan adı bağlama
- Ortamın kartındaki Alan adları kutusuna her satıra bir alan adı yazın (örneğin
oyun.example.com). Adlar küçük harfe çevrilir; boş satırlar ve tekrarlar atılır. - Gerekçe alanına nedeninizi yazın.
- Alan adlarını kaydet düğmesine basın.
Ortam ekleme
- Sekmenin üstündeki Ortam ekle düğmesine basın.
- Ortam türünü seçin: Geliştirme (dev), Hazırlık (staging) ya da Canlı (prod). Pencere varsayılan olarak Hazırlık’ı seçer.
- Nedeninizi yazıp onaylayın. Alan adları ve Google girişi ortam eklendikten sonra ayrıca bağlanır.
Ortamı arşivleme ya da geri açma
Kartın altındaki Arşivle düğmesi ortamı gizler; veri silinmez. Arşivli ortamda Geri aç düğmesi görünür ve alan adı alanları kapalıdır.
Uyarı
Eski adresi, yeni adres çalışmaya başlayıp eski adres yönlendirilene kadar listede tutun. Bir adres listeden çıkarılınca o adresten açılan oyun hemen giriş yapamaz ve kayıt yazamaz. Kaydet’e basınca kaldırılan adresler bir pencerede listelenir; Yine de kaldır ve kaydet demeden değişiklik uygulanmaz. Liste tamamen boşalırsa sunucunun genel izinli listesi geçerli olur.
Not
Alan adları, tarayıcıdan gelen isteklerin kaynak (origin) kontrolünde izinli liste olarak kullanılır. Oyununuzu sunduğunuz her adresi ilgili ortama bağlayın; başka ortama bağlı bir alan adı kabul edilmez.
Alanlar ve seçenekler
| Alan | Zorunlu | Açıklama |
|---|---|---|
| Alan adları | Hayır | Satır başına bir alan adı; en fazla 10 |
| Gerekçe | Evet | 8-500 karakter |
| Ortam türü (ekleme penceresi) | Evet | Geliştirme, Hazırlık ya da Canlı |
| İşlem nedeni (pencerelerde) | Evet | 8-500 karakter |
Sık karşılaşılan durumlar
| Durum | Ne yapmalı |
|---|---|
| “Bu alan adı başka bir ortama bağlı” | Aynı alan adı iki ortama bağlanamaz. Önce diğer ortamdan kaldırın. |
| “En fazla 10 alan adı bağlanabilir” | Listeyi kısaltın; bir ortama en fazla 10 alan adı bağlanır. |
| “Önce başka bir ortam seçin” | Şu an seçili olan ortam arşivlenemez; üst çubuktan başka bir ortam seçin. |
| Sekme “yetki gerektiriyor” diyor | Bu sekme yalnızca süper yöneticiye açıktır. |
| Eski adresteki oyun giriş yapamıyor | Adres listeden çıkarılmış. Adresi listeye geri ekleyip kaydedin; ardından yeni adrese geçişi tamamlayın. |
| Arşivleme reddedildi | Ortamın canlı yetkisi ya da etkin bir API anahtarı vardır; pencere nedenini gösterir. |
İlgili dokümanlar
Eklenti sayfası
Amaç
Oyunun eklentisi, kendi yönetim ekranlarını panelde tanımlayabilir: oyuncu listesi, filtreli tablolar, ayrıntı sayfaları, grafikler ve eylem düğmeleri. Bu sayfa bu ekranların hepsi için ortak yardımdır; eklentiye özel içerik eklentinin kendi tanımından gelir ve burada anlatılmaz.
Ne zaman kullanılır
- Eklentinin bir ekranında arama, sayfalama ya da eylem yaparken ne olacağını anlamak için.
- Ekranın üstündeki durum uyarılarının ne anlama geldiğini öğrenmek için.
Adım adım
Ekranı tanıma
- Sayfanın başlığı eklentinin adıdır; altındaki ikinci başlık ekranın adıdır. Eklentinin ekranları başlığın altındaki sekmelerde listelenir.
- Yenile düğmesi yalnızca bu ekranın verisini yeniden okur.
- Başlığın altındaki Son okuma satırı verinin ne zaman okunduğunu gösterir.
Liste ve tablolarda gezinme
- Arama kutusuna yazdıkça liste daralır; arama metni ve sayfa numarası adres çubuğunda durur, bu yüzden bağlantıyı paylaşabilirsiniz.
- Sayfalayıcıda Sayfa başına listesinden 12, 25 ya da 50 satır seçebilirsiniz.
- CSV indir düğmesi varsa ekrana yüklenmiş satırları dosya olarak indirir; sayfalı tabloda yalnızca yüklü sayfayı içerir.
Eylem yapma
- Ekrandaki eylem düğmesine basın; bir pencere açılır. Düğmeyi yalnızca eklenti işletme yetkisi olan yöneticiler görür ya da kullanabilir.
- Alanları doldurun, nedeninizi İşlem nedeni alanına yazın ve onaylayın.
- Sonuç ekranda görünür; eylem işlem geçmişine yazılır.
Not
Eklentinin durumu ekranın üstünde bir uyarıyla görünür. Salt okunur durumda veriler görünür ama değişiklik yapılamaz; Boşaltılıyor durumunda yeni işlem kabul edilmez, açık işlemler tamamlanır. Durumu Eklentiler sayfasından yönetici değiştirir.
Alanlar ve seçenekler
| Alan | Zorunlu | Açıklama |
|---|---|---|
| Arama | Hayır | Eklentinin tanımladığı alanlarda arar |
| Sayfa başına | Hayır | 12, 25 ya da 50 |
| İşlem nedeni (eylem penceresi) | Evet | Sınırlar alanın altında yazar |
| Eylem alanları | Eylemine göre | Eklenti tanımlar; her alanın açıklaması pencerede yazar |
Sık karşılaşılan durumlar
| Durum | Ne yapmalı |
|---|---|
| “Bu eklenti bu ortamda salt okunur” | Eklenti yalnızca okumaya açık. Değişiklik gerekiyorsa bir yöneticiden Eklentiler sayfasında durumu açık yapmasını isteyin. |
| “Bu eklenti boşaltılıyor” | Sürüm geçişi öncesinde eklenti yeni işlem almıyor; boşaltma bitince açık duruma dönecektir. |
| Eylem düğmesi yok ya da kapalı | Eklenti işletme yetkiniz yoktur ya da eklenti salt okunurdur. |
| Ekranın üstünde “kullanımdan kalkıyor” bandı var | Ekran yeni bir ekranla değiştiriliyor; bandaki bağlantı yerine geçen ekrana götürür. |
| Eylem “başka bir değişiklik yapıldı” diyor | Kayıt siz bakarken değişmiştir. Güncel hâlini görüp yeniden onaylayın. |