examples: global quests usage in CozyCollector (list/claim/reportProgress), quests capability
CI / check (push) Successful in 6s
CI / publish (push) Has been skipped

This commit is contained in:
edmand46
2026-08-25 16:25:36 +03:00
parent 695a7210b1
commit b8e226722d
3 changed files with 86 additions and 0 deletions
@@ -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";
/// <summary>Color used by the event inspector to tag a capability line.</summary>
@@ -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);
}
}
@@ -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<string>();
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()
@@ -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" },
};