2.0.0: Rudder.Core 2.0.0 DLL, samples and skill docs on slugs and environments
CI / check (push) Successful in 2s
CI / publish (push) Has been skipped

Claude-Session: https://claude.ai/code/session_01SMCvdwDmuxoaqGgvGBLk1V
This commit is contained in:
edmand46
2026-09-06 22:25:33 +03:00
parent 01e27bde2c
commit b18c59450c
11 changed files with 73 additions and 29 deletions
+3 -3
View File
@@ -113,7 +113,7 @@ save format in a wrapper type.
```csharp
var stores = await client.Stores.ListAsync();
var result = await client.Stores.PurchaseAsync(storeSlug, offerId);
var result = await client.Stores.PurchaseAsync(storeSlug, offerSlug);
if (result != null && result.Success != true) { /* result.Error */ }
var items = await client.Inventory.GetAsync();
```
@@ -165,7 +165,7 @@ effects through the `On*` events.
```csharp
var quests = await client.Quests.ListAsync();
await client.Quests.ClaimAsync(quest.Id);
await client.Quests.ClaimAsync(quest.Slug);
var completedIds = await client.Quests.ReportProgressAsync("kills", 1);
```
@@ -175,7 +175,7 @@ Store purchases already report `purchase.offer:<id>` / `purchase.item:<id>`.
Progress is tied to a scenario battle-pass node. Prefer `BattlePassEffect`
from `Effects.OnBattlePass` (it binds scenario/node/run ids). Direct
`BattlePass.GetProgressAsync(scenarioId, nodeId)` needs those ids. Tracks:
`BattlePass.GetProgressAsync(scenarioSlug, nodeId)` needs those ids. Tracks:
`BattlePassService.TrackFree` / `TrackPremium`.
## Errors
+32
View File
@@ -1,5 +1,37 @@
# Changelog
## 2.0.0
Breaking changes, following Rudder.Core 2.0.0 and the backend environments
release. The bundled `Runtime/Plugins/Rudder.Core.dll` is rebuilt from
Rudder.Core 2.0.0.
A project now has exactly two environments, `staging` and `prod`. The SDK key
set in `RudderConfiguration` belongs to one of them, so the environment is
resolved at login and carried inside the tokens; nothing in the API takes an
environment argument and players do not cross between environments. Tokens
saved to PlayerPrefs by 1.x have no environment claim and are rejected with
401: the refresh fails, the stored tokens are cleared and
`Auth.AuthStateChanged` fires `SignedOut`, so call `LoginWithDeviceAsync`
again on that event.
Quests, scenarios and offers are addressed by slug instead of id, because ids
differ between staging and prod. `Quest.Id` became `Quest.Slug`,
`Quests.ClaimAsync` takes a quest slug, `Quests.ReportProgressAsync` returns
quest slugs, `Stores.PurchaseAsync` takes an offer slug and `Offer` carries a
`Slug`, `QuestMetrics.PurchaseOffer` builds its metric from the offer slug,
and every scenario-scoped effect and request exposes `ScenarioSlug` instead of
`ScenarioId` (`PendingEffect`, `ScenarioCompletedEffect`,
`ScenarioFailedEffect`, the battle pass requests,
`BattlePass.GetProgressAsync`). `Store.ScenarioId` is unchanged — it is an
authoring reference, not a player-facing one. The Store/Inventory and
Scenarios samples were updated to `offer.Slug`.
Also inherited from Core: the effects client reconciles against every pending
poll, so a run that disappeared server-side emits `OnScenarioCompleted`
instead of lingering, and `run_not_active` is a terminal rejection that drops
the run and emits `OnScenarioFailed`.
## 1.0.0
Breaking changes, following the Rudder.Core 1.0.0 rework:
Binary file not shown.
@@ -81,8 +81,8 @@ namespace RudderSdk.Unity.Samples
if (offer == null)
throw new InvalidOperationException("Store " + storeSlug + " has no offers.");
_page.Log("Stores.PurchaseAsync(" + storeSlug + ", " + offer.Id + ")");
var response = await client.Stores.PurchaseAsync(storeSlug, offer.Id);
_page.Log("Stores.PurchaseAsync(" + storeSlug + ", " + offer.Slug + ")");
var response = await client.Stores.PurchaseAsync(storeSlug, offer.Slug);
if (response != null && response.Success != true)
throw new InvalidOperationException(response.Error ?? "Purchase rejected");
@@ -55,11 +55,11 @@ namespace RudderSdk.Unity.Samples
foreach (var offer in store.Offers)
{
var slug = store.Slug;
var offerId = offer.Id;
var name = string.IsNullOrEmpty(offer.Name) ? offer.Id : offer.Name;
var offerSlug = offer.Slug;
var name = string.IsNullOrEmpty(offer.Name) ? offer.Slug : offer.Name;
var price = offer.Price == null ? "free" : offer.Price.Amount + " " + offer.Price.Currency;
if (_page.Button("Buy " + name + " — " + price))
_page.Run(this, () => Buy(slug, offerId, name));
_page.Run(this, () => Buy(slug, offerSlug, name));
}
}
});
@@ -74,11 +74,11 @@ namespace RudderSdk.Unity.Samples
_page.SetStatus(_stores.Count == 0 ? "No stores" : "Loaded " + _stores.Count + " store(s)");
}
async Task Buy(string storeSlug, string offerId, string name)
async Task Buy(string storeSlug, string offerSlug, string name)
{
var client = Rudder.Initialize();
_page.Log("Stores.PurchaseAsync(" + storeSlug + ", " + offerId + ")");
var response = await client.Stores.PurchaseAsync(storeSlug, offerId);
_page.Log("Stores.PurchaseAsync(" + storeSlug + ", " + offerSlug + ")");
var response = await client.Stores.PurchaseAsync(storeSlug, offerSlug);
if (response != null && response.Success != true)
throw new InvalidOperationException(response.Error ?? "Purchase rejected");
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "rudder.sdk",
"version": "1.0.0",
"version": "2.0.0",
"displayName": "Rudder SDK",
"description": "LiveOps SDK for Unity — player auth, remote config, stores, inventory, leaderboards, scenarios.",
"unity": "6000.0",