diff --git a/DragonFruit.Six.API.Tests.Common/Dragon6DemoClient.cs b/DragonFruit.Six.API.Tests.Common/Dragon6DemoClient.cs index a4122f79..aecae058 100644 --- a/DragonFruit.Six.API.Tests.Common/Dragon6DemoClient.cs +++ b/DragonFruit.Six.API.Tests.Common/Dragon6DemoClient.cs @@ -35,7 +35,7 @@ protected override T ValidateAndProcess(HttpResponseMessage response, HttpReq catch (UbisoftErrorException) { //pretend to be ubisoft club and try again - AppId = UbisoftIdentifiers.Websites[UbisoftService.UbisoftClub]; + AppId = UbisoftService.UbisoftClub.AppId(); return Perform(request); } } diff --git a/DragonFruit.Six.API/Data/Deserializers/AccountInfoDeserializer.cs b/DragonFruit.Six.API/Data/Deserializers/AccountInfoDeserializer.cs index dc64ea34..e330db1d 100644 --- a/DragonFruit.Six.API/Data/Deserializers/AccountInfoDeserializer.cs +++ b/DragonFruit.Six.API/Data/Deserializers/AccountInfoDeserializer.cs @@ -14,9 +14,12 @@ public static class AccountInfoDeserializer { public static IEnumerable DeserializeAccountInfo(this JObject jObject) { - var json = JArray.FromObject(jObject[Misc.Profile]); + var accountsJson = jObject[Misc.Profile]; - foreach (var jToken in json) + if (accountsJson == null) + yield break; + + foreach (var jToken in JArray.FromObject(accountsJson)) { var item = (JObject)jToken; yield return new AccountInfo diff --git a/DragonFruit.Six.API/Data/Deserializers/AccountLoginInfoDeserializer.cs b/DragonFruit.Six.API/Data/Deserializers/AccountLoginInfoDeserializer.cs index 5ca7d1b5..4f8fbba3 100644 --- a/DragonFruit.Six.API/Data/Deserializers/AccountLoginInfoDeserializer.cs +++ b/DragonFruit.Six.API/Data/Deserializers/AccountLoginInfoDeserializer.cs @@ -7,6 +7,7 @@ using DragonFruit.Common.Data.Extensions; using DragonFruit.Six.API.Data.Containers; using DragonFruit.Six.API.Data.Strings; +using DragonFruit.Six.API.Helpers; using Newtonsoft.Json.Linq; namespace DragonFruit.Six.API.Data.Deserializers @@ -15,8 +16,10 @@ public static class AccountLoginInfoDeserializer { public static IEnumerable DeserializeAccountLoginInfo(this JObject jObject) { - var data = (JArray)jObject["applications"]; - var platformLookup = Endpoints.GameIds.ToDictionary(x => x.Value, x => x.Key); + var data = jObject["applications"] as JArray; + + if (data == null) + yield break; foreach (var jToken in data) { @@ -24,13 +27,13 @@ public static IEnumerable DeserializeAccountLoginInfo(this JOb yield return new AccountLoginInfo { Guid = entry.GetString(Login.Guid), + SessionCount = entry.GetUInt(Login.Sessions), + Platform = UbisoftIdentifiers.GameIds.SingleOrDefault(x => x.Value.Equals(entry.GetString(Login.PlatformId), StringComparison.OrdinalIgnoreCase)).Key, Activity = new ActivityDateContainer { First = DateTimeOffset.Parse(entry.GetString(Login.FirstLogin), References.Culture), Last = DateTimeOffset.Parse(entry.GetString(Login.LastLogin), References.Culture) - }, - SessionCount = entry.GetUInt(Login.Sessions), - Platform = platformLookup[entry.GetString(Login.PlatformId)] + } }; } } diff --git a/DragonFruit.Six.API/Data/Deserializers/GeneralStatsDeserializer.cs b/DragonFruit.Six.API/Data/Deserializers/GeneralStatsDeserializer.cs index 59ee8af1..a91f1f88 100644 --- a/DragonFruit.Six.API/Data/Deserializers/GeneralStatsDeserializer.cs +++ b/DragonFruit.Six.API/Data/Deserializers/GeneralStatsDeserializer.cs @@ -13,12 +13,11 @@ public static class GeneralStatsDeserializer { public static GeneralStats DeserializeGeneralStatsFor(this JObject jObject, string guid) { - if (jObject == null) - { - return new GeneralStats(); - } + // try to get the user but if there is nothing return null + var json = jObject[Misc.Results]?[guid] as JObject; - var json = (JObject)jObject[Misc.Results][guid]; + if (json == null) + return null; var result = new GeneralStats { diff --git a/DragonFruit.Six.API/Data/Deserializers/OperatorStatsDeserializer.cs b/DragonFruit.Six.API/Data/Deserializers/OperatorStatsDeserializer.cs index f24a7cd2..18747efb 100644 --- a/DragonFruit.Six.API/Data/Deserializers/OperatorStatsDeserializer.cs +++ b/DragonFruit.Six.API/Data/Deserializers/OperatorStatsDeserializer.cs @@ -14,7 +14,10 @@ public static class OperatorStatsDeserializer { public static IEnumerable DeserializeOperatorStatsFor(this JObject jObject, string guid, IEnumerable data) { - var json = (JObject)jObject[Misc.Results]![guid]; + var json = jObject[Misc.Results]?[guid] as JObject; + + if (json == null) + yield break; foreach (var op in data.Select(x => x.Clone())) { diff --git a/DragonFruit.Six.API/Data/Deserializers/PlayerLevelStatsDeserializer.cs b/DragonFruit.Six.API/Data/Deserializers/PlayerLevelStatsDeserializer.cs index 5e81f256..277acbe8 100644 --- a/DragonFruit.Six.API/Data/Deserializers/PlayerLevelStatsDeserializer.cs +++ b/DragonFruit.Six.API/Data/Deserializers/PlayerLevelStatsDeserializer.cs @@ -10,10 +10,17 @@ public static class PlayerLevelStatsDeserializer { public static IEnumerable DeserializePlayerLevelStats(this JObject jObject) { - foreach (var element in JArray.FromObject(jObject["player_profiles"])) + var profiles = jObject["player_profiles"]; + + if (profiles == null) + yield break; + + foreach (var profile in JArray.FromObject(profiles)) { - var result = element.ToObject(); - result.Guid = (string)element["profile_id"]; + var result = profile.ToObject(); + + // todo do we need a null check? + result!.Guid = (string)profile["profile_id"]; yield return result; } } diff --git a/DragonFruit.Six.API/Data/Deserializers/SeasonStatsDeserializer.cs b/DragonFruit.Six.API/Data/Deserializers/SeasonStatsDeserializer.cs index 00b73c00..bdd6ab44 100644 --- a/DragonFruit.Six.API/Data/Deserializers/SeasonStatsDeserializer.cs +++ b/DragonFruit.Six.API/Data/Deserializers/SeasonStatsDeserializer.cs @@ -13,7 +13,10 @@ public static class SeasonStatsDeserializer { public static SeasonStats DeserializeSeasonStatsFor(this JObject jObject, string guid) { - var json = (JObject)jObject[Misc.Players][guid]; + var json = jObject[Misc.Players]?[guid] as JObject; + + if (json == null) + return null; return new SeasonStats { diff --git a/DragonFruit.Six.API/Data/Deserializers/TokenDeserializer.cs b/DragonFruit.Six.API/Data/Deserializers/TokenDeserializer.cs index 8492a9dd..2ac25817 100644 --- a/DragonFruit.Six.API/Data/Deserializers/TokenDeserializer.cs +++ b/DragonFruit.Six.API/Data/Deserializers/TokenDeserializer.cs @@ -15,14 +15,18 @@ public static class TokenDeserializer public static UbisoftToken DeserializeToken(this JObject jObject) { var token = jObject.ToObject(); + + if (token == null) + return null; + token.Account = new AccountInfo { + Platform = PlatformParser.PlatformEnumFor(jObject.GetString(Accounts.PlatformIdentifier, "uplay")), + PlayerName = jObject.GetString(Accounts.Name), Identifiers = new UserIdentifierContainer { Platform = jObject.GetString(Accounts.ProfileIdentifier) - }, - Platform = PlatformParser.PlatformEnumFor(jObject.GetString(Accounts.PlatformIdentifier, "uplay")), - PlayerName = jObject.GetString(Accounts.Name), + } }; return token; diff --git a/DragonFruit.Six.API/Data/Deserializers/WeaponStatsDeserializer.cs b/DragonFruit.Six.API/Data/Deserializers/WeaponStatsDeserializer.cs index eb4b647e..907b00e7 100644 --- a/DragonFruit.Six.API/Data/Deserializers/WeaponStatsDeserializer.cs +++ b/DragonFruit.Six.API/Data/Deserializers/WeaponStatsDeserializer.cs @@ -12,7 +12,10 @@ public static class WeaponStatsDeserializer { public static IEnumerable DeserializeWeaponStatsFor(this JObject jObject, string guid) { - var json = (JObject)jObject[Misc.Results][guid]; + var json = jObject[Misc.Results]?[guid] as JObject; + + if (json == null) + yield break; foreach (var index in References.WeaponClasses.Keys) { diff --git a/DragonFruit.Six.API/Data/Extensions/AccountLoginInfoExtensions.cs b/DragonFruit.Six.API/Data/Extensions/AccountLoginInfoExtensions.cs index 851d6918..14285630 100644 --- a/DragonFruit.Six.API/Data/Extensions/AccountLoginInfoExtensions.cs +++ b/DragonFruit.Six.API/Data/Extensions/AccountLoginInfoExtensions.cs @@ -16,7 +16,7 @@ public static AccountLoginInfo GetLoginInfo(this T client, AccountInfo accoun public static IEnumerable GetLoginInfo(this T client, IEnumerable accounts) where T : Dragon6Client { - var data = client.Perform(new AccountLoginInfoRequest(Endpoints.GameIds.Select(x => x.Value), accounts)); + var data = client.Perform(new AccountLoginInfoRequest(accounts)); return data.DeserializeAccountLoginInfo(); } } diff --git a/DragonFruit.Six.API/Data/Extensions/GeneralStatsExtentions.cs b/DragonFruit.Six.API/Data/Extensions/GeneralStatsExtentions.cs index bf508562..1498cf1d 100644 --- a/DragonFruit.Six.API/Data/Extensions/GeneralStatsExtentions.cs +++ b/DragonFruit.Six.API/Data/Extensions/GeneralStatsExtentions.cs @@ -11,7 +11,7 @@ namespace DragonFruit.Six.API.Data.Extensions { public static class GeneralStatsExtentions { - public static GeneralStats GetStats(this T client, AccountInfo account) where T : Dragon6Client + public static GeneralStats GetStats(this T client, AccountInfo account) where T : Dragon6Client => GetStats(client, new[] { account }).First(); public static IEnumerable GetStats(this T client, IEnumerable accounts) where T : Dragon6Client diff --git a/DragonFruit.Six.API/Data/Requests/AccountLoginInfoRequests.cs b/DragonFruit.Six.API/Data/Requests/AccountLoginInfoRequests.cs index 6d02ee83..61593fa7 100644 --- a/DragonFruit.Six.API/Data/Requests/AccountLoginInfoRequests.cs +++ b/DragonFruit.Six.API/Data/Requests/AccountLoginInfoRequests.cs @@ -5,34 +5,21 @@ using System.Linq; using DragonFruit.Common.Data.Parameters; using DragonFruit.Six.API.Data.Requests.Base; +using DragonFruit.Six.API.Helpers; namespace DragonFruit.Six.API.Data.Requests { - public sealed class AccountLoginInfoRequest : UbiApiRequest + public class AccountLoginInfoRequest : UbiApiRequest { - public AccountLoginInfoRequest() + public AccountLoginInfoRequest(AccountInfo profile) + : this(new[] { profile }) { } - public AccountLoginInfoRequest(string appId, AccountInfo profileId) - : this(new[] { appId }, new[] { profileId }) + public AccountLoginInfoRequest(IEnumerable profiles) { - } - - public AccountLoginInfoRequest(string appId, IEnumerable profileIds) - : this(new[] { appId }, profileIds) - { - } - - public AccountLoginInfoRequest(IEnumerable appIds, AccountInfo profileId) - : this(appIds, new[] { profileId }) - { - } - - public AccountLoginInfoRequest(IEnumerable appIds, IEnumerable profileIds) - { - AppIds = appIds; - Accounts = profileIds; + Accounts = profiles; + AppIds = UbisoftIdentifiers.GameIds.Values; } public override string Path => $"{Endpoints.IdServer}/applications"; diff --git a/DragonFruit.Six.API/Data/Requests/Base/BasicStatsRequest.cs b/DragonFruit.Six.API/Data/Requests/Base/BasicStatsRequest.cs index 7830bed3..1a9785a9 100644 --- a/DragonFruit.Six.API/Data/Requests/Base/BasicStatsRequest.cs +++ b/DragonFruit.Six.API/Data/Requests/Base/BasicStatsRequest.cs @@ -2,7 +2,6 @@ // Licensed under Apache-2. Please refer to the LICENSE file for more info using System.Collections.Generic; -using System.Linq; using DragonFruit.Common.Data.Parameters; namespace DragonFruit.Six.API.Data.Requests.Base @@ -12,7 +11,7 @@ namespace DragonFruit.Six.API.Data.Requests.Base /// public class BasicStatsRequest : PlatformSpecificRequest { - public override string Path => Endpoints.Stats[Accounts.First().Platform]; + public override string Path => Platform.StatsEndpoint(); public BasicStatsRequest(AccountInfo account) : base(new[] { account }) diff --git a/DragonFruit.Six.API/Data/Requests/PlayerLevelStatsRequest.cs b/DragonFruit.Six.API/Data/Requests/PlayerLevelStatsRequest.cs index 9d8c4632..ac5083c1 100644 --- a/DragonFruit.Six.API/Data/Requests/PlayerLevelStatsRequest.cs +++ b/DragonFruit.Six.API/Data/Requests/PlayerLevelStatsRequest.cs @@ -10,7 +10,7 @@ namespace DragonFruit.Six.API.Data.Requests { public sealed class PlayerLevelStatsRequest : PlatformSpecificRequest { - public override string Path => Endpoints.ProfileInfo[Platform]; + public override string Path => Platform.ProfileStatsEndpoint(); protected override bool RequireAuth => true; diff --git a/DragonFruit.Six.API/Data/Requests/SeasonStatsRequest.cs b/DragonFruit.Six.API/Data/Requests/SeasonStatsRequest.cs index 4acc1963..03e019f4 100644 --- a/DragonFruit.Six.API/Data/Requests/SeasonStatsRequest.cs +++ b/DragonFruit.Six.API/Data/Requests/SeasonStatsRequest.cs @@ -12,7 +12,7 @@ namespace DragonFruit.Six.API.Data.Requests { public sealed class SeasonStatsRequest : PlatformSpecificRequest { - public override string Path => Endpoints.RankedStats[Platform]; + public override string Path => Platform.SeasonalStatsEndpoint(); public SeasonStatsRequest(IEnumerable accounts) : base(accounts) diff --git a/DragonFruit.Six.API/Dragon6Client.cs b/DragonFruit.Six.API/Dragon6Client.cs index 7d0dbb11..1c284404 100644 --- a/DragonFruit.Six.API/Dragon6Client.cs +++ b/DragonFruit.Six.API/Dragon6Client.cs @@ -41,7 +41,7 @@ protected Dragon6Client(string userAgent, string appId) protected Dragon6Client() { Serializer = new ApiJsonSerializer(References.Culture); - AppId = UbisoftIdentifiers.Websites[UbisoftService.RainbowSix]; + AppId = UbisoftService.RainbowSix.AppId(); if (string.IsNullOrEmpty(UserAgent)) { diff --git a/DragonFruit.Six.API/Endpoints.cs b/DragonFruit.Six.API/Endpoints.cs index 8772865d..66b49015 100644 --- a/DragonFruit.Six.API/Endpoints.cs +++ b/DragonFruit.Six.API/Endpoints.cs @@ -1,63 +1,38 @@ // Dragon6 API Copyright 2020 DragonFruit Network // Licensed under Apache-2. Please refer to the LICENSE file for more info -using System.Collections.Generic; -using DragonFruit.Six.API.Data; +using System; using DragonFruit.Six.API.Enums; +using DragonFruit.Six.API.Helpers; namespace DragonFruit.Six.API { public static class Endpoints { + /// + /// Public API endpoint + /// public static readonly string BaseEndpoint = "https://public-ubiservices.ubi.com"; - public static readonly string StatsBase = BaseEndpoint + "/v1/spaces"; - public static readonly string IdServer = BaseEndpoint + "/v3/profiles"; - /// - /// Used for + /// Public-facing endpoint for generating access tokens /// - public static readonly Dictionary GameIds = - new Dictionary - { - [Platform.PSN] = "fb4cc4c9-2063-461d-a1e8-84a7d36525fc", - [Platform.XB1] = "4008612d-3baf-49e4-957a-33066726a7bc", - [Platform.PC] = "e3d5ea9e-50bd-43b7-88bf-39794f4e3d40" - }; + public static readonly string IdServer = BaseEndpoint + "/v3/profiles"; /// - /// Game ids used for getting stats + /// Url of the platform-specific "sandbox", the place where all the stats are acquired from /// - public static readonly Dictionary GameSpaceIds = - new Dictionary - { - [Platform.PSN] = "05bfb3f7-6c21-4c42-be1f-97a33fb5cf66", - [Platform.XB1] = "98a601e5-ca91-4440-b1c5-753f601a2c90", - [Platform.PC] = "5172a557-50b5-4665-b7db-e3f2e8c5041d" - }; - - public static readonly Dictionary Stats = - new Dictionary - { - [Platform.PSN] = $"{StatsBase}/{GameSpaceIds[Platform.PSN]}/sandboxes/OSBOR_PS4_LNCH_A/playerstats2/statistics", - [Platform.XB1] = $"{StatsBase}/{GameSpaceIds[Platform.XB1]}/sandboxes/OSBOR_XBOXONE_LNCH_A/playerstats2/statistics", - [Platform.PC] = $"{StatsBase}/{GameSpaceIds[Platform.PC]}/sandboxes/OSBOR_PC_LNCH_A/playerstats2/statistics" - }; - - public static readonly Dictionary RankedStats = - new Dictionary - { - [Platform.PSN] = $"{StatsBase}/{GameSpaceIds[Platform.PSN]}/sandboxes/OSBOR_PS4_LNCH_A/r6karma/players", - [Platform.XB1] = $"{StatsBase}/{GameSpaceIds[Platform.XB1]}/sandboxes/OSBOR_XBOXONE_LNCH_A/r6karma/players", - [Platform.PC] = $"{StatsBase}/{GameSpaceIds[Platform.PC]}/sandboxes/OSBOR_PC_LNCH_A/r6karma/players" - }; - - public static readonly Dictionary ProfileInfo = - new Dictionary - { - [Platform.PSN] = $"{StatsBase}/{GameSpaceIds[Platform.PSN]}/sandboxes/OSBOR_PS4_LNCH_A/r6playerprofile/playerprofile/progressions", - [Platform.XB1] = $"{StatsBase}/{GameSpaceIds[Platform.XB1]}/sandboxes/OSBOR_XBOXONE_LNCH_A/r6playerprofile/playerprofile/progressions", - [Platform.PC] = $"{StatsBase}/{GameSpaceIds[Platform.PC]}/sandboxes/OSBOR_PC_LNCH_A/r6playerprofile/playerprofile/progressions" - }; + private static string SandboxUrlFor(this Platform platform) => $"{BaseEndpoint}/v1/spaces/{platform.GameSpaceId()}/sandboxes" + platform switch + { + Platform.PSN => "/OSBOR_PS4_LNCH_A", + Platform.XB1 => "/OSBOR_XBOXONE_LNCH_A", + Platform.PC => "/OSBOR_PC_LNCH_A", + + _ => throw new ArgumentOutOfRangeException() + }; + + public static string StatsEndpoint(this Platform platform) => $"{SandboxUrlFor(platform)}/playerstats2/statistics"; + public static string SeasonalStatsEndpoint(this Platform platform) => $"{SandboxUrlFor(platform)}/r6karma/players"; + public static string ProfileStatsEndpoint(this Platform platform) => $"{SandboxUrlFor(platform)}/r6playerprofile/playerprofile/progressions"; } } diff --git a/DragonFruit.Six.API/Helpers/PlatformParser.cs b/DragonFruit.Six.API/Helpers/PlatformParser.cs index 788838d5..ccd3786b 100644 --- a/DragonFruit.Six.API/Helpers/PlatformParser.cs +++ b/DragonFruit.Six.API/Helpers/PlatformParser.cs @@ -2,6 +2,7 @@ // Licensed under Apache-2. Please refer to the LICENSE file for more info using System; +using System.Collections.Generic; using DragonFruit.Six.API.Enums; namespace DragonFruit.Six.API.Helpers @@ -11,17 +12,21 @@ public static class PlatformParser /// /// Convert Platform ID -> API Enum /// - public static Platform GetPlatform(string platformId) => (Platform)Enum.Parse(typeof(Platform), platformId); + public static Platform GetPlatform(string platformId) + { + return Enum.Parse(platformId, true); + } /// /// Ubisoft string to (reverses ) /// - public static Platform PlatformEnumFor(string platformName) => platformName switch + public static Platform PlatformEnumFor(string platformName) => platformName.ToUpperInvariant() switch { - "uplay" => Platform.PC, - "psn" => Platform.PSN, - "xbl" => Platform.XB1, - _ => throw new ArgumentException("Cannot find the specified platform") + "UPLAY" => Platform.PC, + "PSN" => Platform.PSN, + "XBL" => Platform.XB1, + + _ => throw new ArgumentOutOfRangeException() }; /// @@ -32,7 +37,26 @@ public static class PlatformParser Platform.PSN => "psn", Platform.XB1 => "xbl", Platform.PC => "uplay", - _ => throw new ArgumentException("Platform Not Found") + + _ => throw new ArgumentOutOfRangeException() }; + + /// + /// Enumerates over all s, producing a + /// of platforms to a user-defined value + /// + internal static Dictionary PlatformsTo(Func selector) + { + var platforms = (Platform[])Enum.GetValues(typeof(Platform)); + var gameIds = new Dictionary(platforms.Length); + + foreach (var platform in platforms) + { + // for now none of them should throw an exception + gameIds.Add(platform, selector.Invoke(platform)); + } + + return gameIds; + } } } diff --git a/DragonFruit.Six.API/Helpers/UbisoftIdentifiers.cs b/DragonFruit.Six.API/Helpers/UbisoftIdentifiers.cs index 2351a58a..ef837204 100644 --- a/DragonFruit.Six.API/Helpers/UbisoftIdentifiers.cs +++ b/DragonFruit.Six.API/Helpers/UbisoftIdentifiers.cs @@ -1,6 +1,7 @@ // Dragon6 API Copyright 2020 DragonFruit Network // Licensed under Apache-2. Please refer to the LICENSE file for more info +using System; using System.Collections.Generic; using DragonFruit.Six.API.Enums; @@ -8,12 +9,48 @@ namespace DragonFruit.Six.API.Helpers { public static class UbisoftIdentifiers { - public static IReadOnlyDictionary Websites => new Dictionary + private static IReadOnlyDictionary _gameIds; + + /// + /// of platforms to game ids used for checking playtime stats + /// + internal static IReadOnlyDictionary GameIds => _gameIds ??= PlatformParser.PlatformsTo(p => p.GameId()); + + /// + /// Gets the Ubi-AppId for the specified service + /// + public static string AppId(this UbisoftService service) => service switch + { + UbisoftService.RainbowSix => "39baebad-39e5-4552-8c25-2c9b919064e2", + UbisoftService.UPlay => "e06033f4-28a4-43fb-8313-6c2d882bc4a6", + UbisoftService.UbisoftClub => "314d4fef-e568-454a-ae06-43e3bece12a6", + UbisoftService.UbisoftAccount => "c5393f10-7ac7-4b4f-90fa-21f8f3451a04", + + _ => throw new ArgumentOutOfRangeException() + }; + + /// + /// Ubisoft-assigned ids for getting account play stats + /// + public static string GameId(this Platform platform) => platform switch { - [UbisoftService.RainbowSix] = "39baebad-39e5-4552-8c25-2c9b919064e2", - [UbisoftService.UPlay] = "e06033f4-28a4-43fb-8313-6c2d882bc4a6", - [UbisoftService.UbisoftClub] = "314d4fef-e568-454a-ae06-43e3bece12a6", - [UbisoftService.UbisoftAccount] = "c5393f10-7ac7-4b4f-90fa-21f8f3451a04" + Platform.PSN => "fb4cc4c9-2063-461d-a1e8-84a7d36525fc", + Platform.XB1 => "4008612d-3baf-49e4-957a-33066726a7bc", + Platform.PC => "e3d5ea9e-50bd-43b7-88bf-39794f4e3d40", + + _ => throw new ArgumentOutOfRangeException() + }; + + /// + /// Ubisoft-assigned ids for getting game stats. Used in the "sandbox" + /// + public static string GameSpaceId(this Platform platform) => platform switch + { + Platform.PSN => "05bfb3f7-6c21-4c42-be1f-97a33fb5cf66", + Platform.XB1 => "98a601e5-ca91-4440-b1c5-753f601a2c90", + Platform.PC => "5172a557-50b5-4665-b7db-e3f2e8c5041d", + + _ => throw new ArgumentOutOfRangeException() }; } }