diff --git a/Assets/LiveOpsExamples/Scripts/CozyCollectorConsts.cs b/Assets/LiveOpsExamples/Scripts/CozyCollectorConsts.cs
index 040387b..235334e 100644
--- a/Assets/LiveOpsExamples/Scripts/CozyCollectorConsts.cs
+++ b/Assets/LiveOpsExamples/Scripts/CozyCollectorConsts.cs
@@ -23,6 +23,7 @@ namespace LiveOpsExamples
public const string LeaderboardSlug = "cozy-collector-score";
public const string StoreSlug = "cozy-camp-shop";
public const string OfferId = "moonberry-boost";
+ public const string QuestMetricCollectibles = "cozy_collectibles";
public const string StorageType = "cozy_fantasy_save";
public const string StorageId = "main";
public const string NicknamePrefsKey = "rudder_demo_nickname";
@@ -38,6 +39,7 @@ namespace LiveOpsExamples
public const string CapabilityStorage = "storage";
public const string CapabilityInventory = "inventory";
public const string CapabilityWallet = "wallet";
+ public const string CapabilityQuests = "quests";
public const string CapabilitySystem = "system";
/// Color used by the event inspector to tag a capability line.
@@ -53,6 +55,7 @@ namespace LiveOpsExamples
case CapabilityStorage: return new Color(0.56f, 0.87f, 0.87f);
case CapabilityInventory: return new Color(0.78f, 0.86f, 0.55f);
case CapabilityWallet: return new Color(1.00f, 0.88f, 0.63f);
+ case CapabilityQuests: return new Color(0.71f, 0.80f, 1.00f);
default: return new Color(0.75f, 0.75f, 0.75f);
}
}
diff --git a/Assets/LiveOpsExamples/Scripts/CozyCollectorController.cs b/Assets/LiveOpsExamples/Scripts/CozyCollectorController.cs
index d56c318..9c83823 100644
--- a/Assets/LiveOpsExamples/Scripts/CozyCollectorController.cs
+++ b/Assets/LiveOpsExamples/Scripts/CozyCollectorController.cs
@@ -7,6 +7,7 @@ using RudderSdk.Core;
using RudderSdk.Core.Models.Inventory;
using RudderSdk.Core.Models.Leaderboards;
using RudderSdk.Core.Models.Player;
+using RudderSdk.Core.Models.Quests;
using RudderSdk.Core.Models.Storage;
using RudderSdk.Core.Models.Stores;
using RudderSdk.Unity;
@@ -249,6 +250,7 @@ namespace LiveOpsExamples
await RefreshProfileAsync();
await RefreshStoresAsync();
await RefreshInventoryAsync();
+ await RefreshQuestsAsync();
try
{
@@ -456,6 +458,11 @@ namespace LiveOpsExamples
try { await RefreshInventoryAsync(); }
catch (Exception exception) { Log(CozyCollectorConsts.CapabilityInventory, "Inventory refresh failed", exception.Message); }
+
+ // Purchase metrics (purchase.offer:* / purchase.item:*) are reported
+ // server-side by the purchase fan-out; re-list to pick up new progress.
+ try { await RefreshQuestsAsync(); }
+ catch (Exception exception) { Log(CozyCollectorConsts.CapabilityQuests, "Quest refresh failed", exception.Message); }
}
// ---------------------------------------------------------------
@@ -573,6 +580,63 @@ namespace LiveOpsExamples
return mapped;
}
+ // ---------------------------------------------------------------
+ // Global quests (distinct from scenario quest nodes / QuestSession)
+ // ---------------------------------------------------------------
+
+ private async Task RefreshQuestsAsync()
+ {
+ var quests = await Rudder.Client.Quests.ListAsync();
+
+ var activeCount = 0;
+ if (quests != null)
+ {
+ foreach (var quest in quests)
+ {
+ if (quest.Status == "claimed")
+ continue;
+
+ activeCount += 1;
+ Log(CozyCollectorConsts.CapabilityQuests, "Quest " + (quest.Status ?? "active"), QuestProgressSummary(quest));
+
+ if (quest.Status == "completed" && !string.IsNullOrEmpty(quest.Id))
+ await ClaimQuestAsync(quest);
+ }
+ }
+
+ Log(CozyCollectorConsts.CapabilityQuests, "Quests loaded", activeCount + " active");
+ }
+
+ private async Task ClaimQuestAsync(Quest quest)
+ {
+ var result = await Rudder.Client.Quests.ClaimAsync(quest.Id);
+ if (result == null || !result.Success)
+ {
+ Log(CozyCollectorConsts.CapabilityQuests, "Quest claim rejected", result?.Error);
+ return;
+ }
+
+ if (!result.AlreadyClaimed)
+ Toast("Quest complete", quest.Name ?? quest.Id, CozyToastTone.Success);
+ Log(CozyCollectorConsts.CapabilityQuests, "Quest claimed", quest.Name ?? quest.Id);
+ await RefreshWalletsAsync();
+ }
+
+ private static string QuestProgressSummary(Quest quest)
+ {
+ var name = quest.Name ?? quest.Id;
+ if (quest.Objectives == null || quest.Objectives.Count == 0)
+ return name;
+
+ var parts = new List();
+ foreach (var objective in quest.Objectives)
+ {
+ parts.Add(objective.Metric + " " + objective.Current + "/" + objective.Target);
+ }
+
+ return name + " · " + string.Join(" · ", parts);
+ }
+
// ---------------------------------------------------------------
// Round flow
// ---------------------------------------------------------------
@@ -625,6 +689,23 @@ namespace LiveOpsExamples
{
Log(CozyCollectorConsts.CapabilityScenario, "Trigger failed", exception.Message);
}
+
+ try
+ {
+ var completedIds = await Rudder.Client.Quests.ReportProgressAsync(
+ CozyCollectorConsts.QuestMetricCollectibles,
+ collected);
+ Log(
+ CozyCollectorConsts.CapabilityQuests,
+ "Quest progress reported",
+ CozyCollectorConsts.QuestMetricCollectibles + " +" + collected +
+ (completedIds.Count > 0 ? " · completed " + completedIds.Count + " quest(s)" : string.Empty));
+ await RefreshQuestsAsync();
+ }
+ catch (Exception exception)
+ {
+ Log(CozyCollectorConsts.CapabilityQuests, "Quest progress failed", exception.Message);
+ }
}
public void PlayAgain()
diff --git a/Assets/LiveOpsExamples/Scripts/UI/EventInspectorPanel.cs b/Assets/LiveOpsExamples/Scripts/UI/EventInspectorPanel.cs
index ea3eafa..8f55cb9 100644
--- a/Assets/LiveOpsExamples/Scripts/UI/EventInspectorPanel.cs
+++ b/Assets/LiveOpsExamples/Scripts/UI/EventInspectorPanel.cs
@@ -16,6 +16,7 @@ namespace LiveOpsExamples
{ "storage", new Color(0.624f, 0.690f, 0.769f) },
{ "inventory", new Color(0.898f, 0.604f, 0.796f) },
{ "wallet", new Color(1f, 0.831f, 0.475f) },
+ { "quests", new Color(0.710f, 0.800f, 1f) },
{ "system", new Color(0.667f, 0.706f, 0.635f) },
};
@@ -29,6 +30,7 @@ namespace LiveOpsExamples
{ "storage", "Storage" },
{ "inventory", "Items" },
{ "wallet", "Wallet" },
+ { "quests", "Quests" },
{ "system", "System" },
};