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.