diff --git a/Runtime/Client/EndPointClass.cs b/Runtime/Client/EndPointClass.cs index 0aab85fc..f266daf0 100644 --- a/Runtime/Client/EndPointClass.cs +++ b/Runtime/Client/EndPointClass.cs @@ -27,22 +27,50 @@ public EndPointClass(string endPoint, LootLockerHTTPMethod httpMethod, LootLocke public string WithPathParameter(object arg0) { - return string.Format(endPoint, WebUtility.UrlEncode(arg0.ToString())); + try { + return string.Format(endPoint, WebUtility.UrlEncode(arg0?.ToString() ?? "null")); + } + catch (FormatException e) + { + LootLockerLogger.Log($"Error formatting endpoint \"{endPoint}\" with path parameter \"{WebUtility.UrlEncode(arg0?.ToString() ?? "null")}\": {e}", LootLockerLogger.LogLevel.Error); + return endPoint; + } } public string WithPathParameters(object arg0, object arg1) { - return string.Format(endPoint, WebUtility.UrlEncode(arg0.ToString()), WebUtility.UrlEncode(arg1.ToString())); + try { + return string.Format(endPoint, WebUtility.UrlEncode(arg0?.ToString() ?? "null"), WebUtility.UrlEncode(arg1?.ToString() ?? "null")); + } + catch (FormatException e) + { + LootLockerLogger.Log($"Error formatting endpoint \"{endPoint}\" with path parameters \"{WebUtility.UrlEncode(arg0?.ToString() ?? "null")}\", \"{WebUtility.UrlEncode(arg1?.ToString() ?? "null")}\": {e}", LootLockerLogger.LogLevel.Error); + return endPoint; + } } public string WithPathParameters(object arg0, object arg1, object arg2) { - return string.Format(endPoint, WebUtility.UrlEncode(arg0.ToString()), WebUtility.UrlEncode(arg1.ToString()), WebUtility.UrlEncode(arg2.ToString())); + try { + return string.Format(endPoint, WebUtility.UrlEncode(arg0?.ToString() ?? "null"), WebUtility.UrlEncode(arg1?.ToString() ?? "null"), WebUtility.UrlEncode(arg2?.ToString() ?? "null")); + } + catch (FormatException e) + { + LootLockerLogger.Log($"Error formatting endpoint \"{endPoint}\" with path parameters \"{WebUtility.UrlEncode(arg0?.ToString() ?? "null")}\", \"{WebUtility.UrlEncode(arg1?.ToString() ?? "null")}\", \"{WebUtility.UrlEncode(arg2?.ToString() ?? "null")}\": {e}", LootLockerLogger.LogLevel.Error); + return endPoint; + } } public string WithPathParameters(object arg0, object arg1, object arg2, object arg3) { - return string.Format(endPoint, WebUtility.UrlEncode(arg0.ToString()), WebUtility.UrlEncode(arg1.ToString()), WebUtility.UrlEncode(arg2.ToString()), WebUtility.UrlEncode(arg3.ToString())); + try { + return string.Format(endPoint, WebUtility.UrlEncode(arg0?.ToString() ?? "null"), WebUtility.UrlEncode(arg1?.ToString() ?? "null"), WebUtility.UrlEncode(arg2?.ToString() ?? "null"), WebUtility.UrlEncode(arg3?.ToString() ?? "null")); + } + catch (FormatException e) + { + LootLockerLogger.Log($"Error formatting endpoint \"{endPoint}\" with path parameters \"{WebUtility.UrlEncode(arg0?.ToString() ?? "null")}\", \"{WebUtility.UrlEncode(arg1?.ToString() ?? "null")}\", \"{WebUtility.UrlEncode(arg2?.ToString() ?? "null")}\", \"{WebUtility.UrlEncode(arg3?.ToString() ?? "null")}\": {e}", LootLockerLogger.LogLevel.Error); + return endPoint; + } } } } diff --git a/Runtime/Client/LootLockerEndPoints.cs b/Runtime/Client/LootLockerEndPoints.cs index 1dcea118..08b23bd1 100644 --- a/Runtime/Client/LootLockerEndPoints.cs +++ b/Runtime/Client/LootLockerEndPoints.cs @@ -274,7 +274,7 @@ public class LootLockerEndPoints [Header("Catalogs")] public static EndPointClass listCatalogs = new EndPointClass("catalogs", LootLockerHTTPMethod.GET); public static EndPointClass deprecatedListCatalogItemsByKey = new EndPointClass("catalog/key/{0}/prices", LootLockerHTTPMethod.GET); - public static EndPointClass listCatalogItemsByKey = new EndPointClass("catalogs/inspired-ibex/v1/catalog/key/{key}/list", LootLockerHTTPMethod.GET); + public static EndPointClass listCatalogItemsByKey = new EndPointClass("catalogs/inspired-ibex/v1/catalog/key/{0}/list", LootLockerHTTPMethod.GET); // Misc [Header("Misc")] diff --git a/Runtime/Client/LootLockerHTTPClient.cs b/Runtime/Client/LootLockerHTTPClient.cs index d00519ab..5157db3f 100644 --- a/Runtime/Client/LootLockerHTTPClient.cs +++ b/Runtime/Client/LootLockerHTTPClient.cs @@ -566,8 +566,11 @@ private void CallListenersAndMarkDone(LootLockerHTTPExecutionQueueItem execution executionItem.Done = true; response.requestContext = new LootLockerRequestContext(executionItem.RequestData.ForPlayerWithUlid, executionItem.RequestData.RequestStartTime); executionItem.Response = response; + if (!CompletedRequestIDs.Contains(executionItem.RequestData.RequestId)) + { + CompletedRequestIDs.Add(executionItem.RequestData.RequestId); + } executionItem.RequestData.CallListenersWithResult(response); - CompletedRequestIDs.Add(executionItem.RequestData.RequestId); } private IEnumerator RefreshSession(string refreshForPlayerUlid, string forExecutionItemId, Action onSessionRefreshedCallback) @@ -647,8 +650,6 @@ private IEnumerator RefreshSession(string refreshForPlayerUlid, string forExecut }, refreshForPlayerUlid); } break; - case LL_AuthPlatforms.PlayStationNetwork: - case LL_AuthPlatforms.XboxOne: case LL_AuthPlatforms.AmazonLuna: { LootLockerSDKManager.StartAmazonLunaSession(playerData.Identifier, (response) => @@ -658,6 +659,8 @@ private IEnumerator RefreshSession(string refreshForPlayerUlid, string forExecut }, playerData.SessionOptionals); } break; + case LL_AuthPlatforms.PlayStationNetwork: + case LL_AuthPlatforms.XboxOne: case LL_AuthPlatforms.NintendoSwitch: case LL_AuthPlatforms.Steam: { diff --git a/Runtime/Client/LootLockerHttpRequestData.cs b/Runtime/Client/LootLockerHttpRequestData.cs index 51d4976b..4bc2cb99 100644 --- a/Runtime/Client/LootLockerHttpRequestData.cs +++ b/Runtime/Client/LootLockerHttpRequestData.cs @@ -87,7 +87,14 @@ public void CallListenersWithResult(LootLockerResponse response) { foreach(var listener in Listeners) { - listener?.Invoke(response); + try + { + listener?.Invoke(response); + } + catch (Exception e) + { + LootLockerLogger.Log($"Exception thrown in HTTP request listener for request id {RequestId}. Exception was: {e}.", LootLockerLogger.LogLevel.Error); + } } HaveListenersBeenInvoked = true; } diff --git a/Runtime/Client/LootLockerStateData.cs b/Runtime/Client/LootLockerStateData.cs index 6548b789..e8116815 100644 --- a/Runtime/Client/LootLockerStateData.cs +++ b/Runtime/Client/LootLockerStateData.cs @@ -195,6 +195,9 @@ public static LootLockerPlayerData GetStateForPlayerOrDefaultStateOrEmpty(string } string playerULIDToGetDataFor = string.IsNullOrEmpty(playerULID) ? ActiveMetaData.DefaultPlayer : playerULID; + // Make this player the default for requests if there is no default yet or if the current default is not currently active + bool shouldBeMadeDefault = ActivePlayerData.Count == 0 && !playerULIDToGetDataFor.Equals(ActiveMetaData.DefaultPlayer, StringComparison.OrdinalIgnoreCase); + if (ActivePlayerData.TryGetValue(playerULIDToGetDataFor, out var data)) { return data; @@ -204,6 +207,10 @@ public static LootLockerPlayerData GetStateForPlayerOrDefaultStateOrEmpty(string { if (ActivePlayerData.TryGetValue(playerULIDToGetDataFor, out var data2)) { + if (shouldBeMadeDefault) + { + SetDefaultPlayerULID(data2.ULID); + } return data2; } } @@ -264,7 +271,7 @@ public static bool SetPlayerData(LootLockerPlayerData updatedPlayerData) { ActiveMetaData.WhiteLabelEmailToPlayerUlidMap[updatedPlayerData.WhiteLabelEmail] = updatedPlayerData.ULID; } - if (string.IsNullOrEmpty(ActiveMetaData.DefaultPlayer)) + if (string.IsNullOrEmpty(ActiveMetaData.DefaultPlayer) || !ActivePlayerData.ContainsKey(ActiveMetaData.DefaultPlayer)) { SetDefaultPlayerULID(updatedPlayerData.ULID); } diff --git a/Runtime/Game/LootLockerSDKManager.cs b/Runtime/Game/LootLockerSDKManager.cs index 634e5e95..3ac2a649 100644 --- a/Runtime/Game/LootLockerSDKManager.cs +++ b/Runtime/Game/LootLockerSDKManager.cs @@ -3242,6 +3242,40 @@ public static void LookupPlayerNamesByXboxIds(string[] xboxIds, Action + /// Get player names and important ids of a set of players from their last active platform by Epic Games ID's + /// + /// A list of multiple player Epic Games ID's + /// onComplete Action for handling the response of type PlayerNameLookupResponse + /// Optional : Execute the request for the specified player. If not supplied, the default player will be used. + public static void LookupPlayerNamesByEpicGamesIds(string[] epicGamesIds, Action onComplete, string forPlayerWithUlid = null) + { + if (!CheckInitialized(false, forPlayerWithUlid)) + { + onComplete?.Invoke(LootLockerResponseFactory.SDKNotInitializedError(forPlayerWithUlid)); + return; + } + + LootLockerAPIManager.LookupPlayerNames(forPlayerWithUlid, "epic_games_id", epicGamesIds, onComplete); + } + + /// + /// Get player names and important ids of a set of players from their last active platform by Google Play Games ID's + /// + /// A list of multiple player Google Play Games ID's + /// onComplete Action for handling the response of type PlayerNameLookupResponse + /// Optional : Execute the request for the specified player. If not supplied, the default player will be used. + public static void LookupPlayerNamesByGooglePlayGamesIds(string[] googlePlayGamesIds, Action onComplete, string forPlayerWithUlid = null) + { + if (!CheckInitialized(false, forPlayerWithUlid)) + { + onComplete?.Invoke(LootLockerResponseFactory.SDKNotInitializedError(forPlayerWithUlid)); + return; + } + + LootLockerAPIManager.LookupPlayerNames(forPlayerWithUlid, "google_play_games_id", googlePlayGamesIds, onComplete); + } + /// /// Mark the logged in player for deletion. After 30 days the player will be deleted from the system. /// @@ -4025,9 +4059,10 @@ public static void GetHeroInventory(int heroID, Action /// List the loadout of the specified hero that the current player owns /// + /// HeroID Id of the hero /// onComplete Action for handling the response of type LootLockerHeroLoadoutResponse /// Optional : Execute the request for the specified player. If not supplied, the default player will be used. - public static void GetHeroLoadout(Action onComplete, string forPlayerWithUlid = null) + public static void GetHeroLoadout(int HeroID, Action onComplete, string forPlayerWithUlid = null) { if (!CheckInitialized(false, forPlayerWithUlid)) { @@ -4035,7 +4070,7 @@ public static void GetHeroLoadout(Action onComple return; } - LootLockerAPIManager.GetHeroLoadout(forPlayerWithUlid, onComplete); + LootLockerAPIManager.GetHeroLoadout(forPlayerWithUlid, HeroID, onComplete); } /// @@ -4076,7 +4111,7 @@ public static void AddAssetToHeroLoadout(int heroID, int assetInstanceID, Action data.hero_id = heroID; - LootLockerAPIManager.AddAssetToHeroLoadout(forPlayerWithUlid, data, onComplete); + LootLockerAPIManager.AddAssetToHeroLoadout(forPlayerWithUlid, heroID, data, onComplete); } /// @@ -4102,7 +4137,7 @@ public static void AddAssetVariationToHeroLoadout(int heroID, int assetID, int a data.asset_id = assetID; data.asset_variation_id = assetInstanceID; - LootLockerAPIManager.AddAssetVariationToHeroLoadout(forPlayerWithUlid, data, onComplete); + LootLockerAPIManager.AddAssetVariationToHeroLoadout(forPlayerWithUlid, heroID, data, onComplete); } /// @@ -4113,7 +4148,7 @@ public static void AddAssetVariationToHeroLoadout(int heroID, int assetID, int a /// Id of the hero /// onComplete Action for handling the response of type LootLockerHeroLoadoutResponse /// Optional : Execute the request for the specified player. If not supplied, the default player will be used. - public static void RemoveAssetFromHeroLoadout(string assetID, string heroID, Action onComplete, string forPlayerWithUlid = null) + public static void RemoveAssetFromHeroLoadout(int assetID, int heroID, Action onComplete, string forPlayerWithUlid = null) { if (!CheckInitialized(false, forPlayerWithUlid)) { @@ -4121,12 +4156,7 @@ public static void RemoveAssetFromHeroLoadout(string assetID, string heroID, Act return; } - LootLockerGetRequest lootLockerGetRequest = new LootLockerGetRequest(); - - lootLockerGetRequest.getRequests.Add(assetID); - lootLockerGetRequest.getRequests.Add(heroID); - - LootLockerAPIManager.RemoveAssetFromHeroLoadout(forPlayerWithUlid, lootLockerGetRequest, onComplete); + LootLockerAPIManager.RemoveAssetFromHeroLoadout(forPlayerWithUlid, heroID, assetID, onComplete); } #endregion diff --git a/Runtime/Game/Requests/HeroRequest.cs b/Runtime/Game/Requests/HeroRequest.cs index 7199fbb4..cdd9c3cf 100644 --- a/Runtime/Game/Requests/HeroRequest.cs +++ b/Runtime/Game/Requests/HeroRequest.cs @@ -116,10 +116,7 @@ public static void ListPlayerHeroes(string forPlayerWithUlid, Action onComplete) { EndPointClass endPoint = LootLockerEndPoints.listOtherPlayersHeroesBySteamID64; - - string getVariable = endPoint.endPoint; - - LootLockerServerRequest.CallAPI(forPlayerWithUlid, getVariable, endPoint.httpMethod, SteamID64.ToString(), (serverResponse) => { LootLockerResponse.Deserialize(onComplete, serverResponse); }); + LootLockerServerRequest.CallAPI(forPlayerWithUlid, endPoint.WithPathParameter(SteamID64.ToString()), endPoint.httpMethod, SteamID64.ToString(), (serverResponse) => { LootLockerResponse.Deserialize(onComplete, serverResponse); }); } public static void CreateHero(LootLockerCreateHeroRequest data, @@ -154,19 +151,14 @@ public static void CreateHeroWithVariation(string forPlayerWithUlid, LootLockerC public static void GetHero(string forPlayerWithUlid, int HeroID, Action onComplete) { EndPointClass endPoint = LootLockerEndPoints.getHero; - - string getVariable = endPoint.endPoint; - - LootLockerServerRequest.CallAPI(forPlayerWithUlid, getVariable, endPoint.httpMethod, HeroID.ToString(), (serverResponse) => { LootLockerResponse.Deserialize(onComplete, serverResponse); }); + LootLockerServerRequest.CallAPI(forPlayerWithUlid, endPoint.WithPathParameter(HeroID.ToString()), endPoint.httpMethod, HeroID.ToString(), (serverResponse) => { LootLockerResponse.Deserialize(onComplete, serverResponse); }); } public static void GetOtherPlayersDefaultHeroBySteamID64(string forPlayerWithUlid, int steamID64, Action onComplete) { EndPointClass endPoint = LootLockerEndPoints.getOtherPlayersDefaultHeroBySteamID64; - string getVariable = endPoint.endPoint; - - LootLockerServerRequest.CallAPI(forPlayerWithUlid, getVariable, endPoint.httpMethod, steamID64.ToString(), (serverResponse) => { LootLockerResponse.Deserialize(onComplete, serverResponse); }); + LootLockerServerRequest.CallAPI(forPlayerWithUlid, endPoint.WithPathParameter(steamID64.ToString()), endPoint.httpMethod, steamID64.ToString(), (serverResponse) => { LootLockerResponse.Deserialize(onComplete, serverResponse); }); } public static void UpdateHero(string forPlayerWithUlid, LootLockerGetRequest lootLockerGetRequest, LootLockerUpdateHeroRequest data, Action onComplete) @@ -189,39 +181,31 @@ public static void DeleteHero(string forPlayerWithUlid, int HeroID, Action { LootLockerResponse.Deserialize(onComplete, serverResponse); }); + LootLockerServerRequest.CallAPI(forPlayerWithUlid, endPoint.WithPathParameter(HeroID.ToString()), endPoint.httpMethod, HeroID.ToString(), (serverResponse) => { LootLockerResponse.Deserialize(onComplete, serverResponse); }); } public static void GetHeroInventory(string forPlayerWithUlid, int HeroID, Action onComplete) { EndPointClass endPoint = LootLockerEndPoints.getHeroInventory; - string getVariable = endPoint.endPoint; - - LootLockerServerRequest.CallAPI(forPlayerWithUlid, getVariable, endPoint.httpMethod, HeroID.ToString(), (serverResponse) => { LootLockerResponse.Deserialize(onComplete, serverResponse); }); + LootLockerServerRequest.CallAPI(forPlayerWithUlid, endPoint.WithPathParameter(HeroID.ToString()), endPoint.httpMethod, HeroID.ToString(), (serverResponse) => { LootLockerResponse.Deserialize(onComplete, serverResponse); }); } - public static void GetHeroLoadout(string forPlayerWithUlid, Action onComplete) + public static void GetHeroLoadout(string forPlayerWithUlid, int HeroID, Action onComplete) { EndPointClass endPoint = LootLockerEndPoints.getHeroLoadout; - string getVariable = endPoint.endPoint; - - LootLockerServerRequest.CallAPI(forPlayerWithUlid, getVariable, endPoint.httpMethod, null, (serverResponse) => { LootLockerResponse.Deserialize(onComplete, serverResponse); }); + LootLockerServerRequest.CallAPI(forPlayerWithUlid, endPoint.WithPathParameter(HeroID.ToString()), endPoint.httpMethod, null, (serverResponse) => { LootLockerResponse.Deserialize(onComplete, serverResponse); }); } public static void GetOtherPlayersHeroLoadout(string forPlayerWithUlid, int HeroID, Action onComplete) { EndPointClass endPoint = LootLockerEndPoints.getOtherPlayersHeroLoadout; - string getVariable = endPoint.endPoint; - - LootLockerServerRequest.CallAPI(forPlayerWithUlid, getVariable, endPoint.httpMethod, HeroID.ToString(), (serverResponse) => { LootLockerResponse.Deserialize(onComplete, serverResponse); }); + LootLockerServerRequest.CallAPI(forPlayerWithUlid, endPoint.WithPathParameter(HeroID.ToString()), endPoint.httpMethod, HeroID.ToString(), (serverResponse) => { LootLockerResponse.Deserialize(onComplete, serverResponse); }); } - public static void AddAssetToHeroLoadout(string forPlayerWithUlid, LootLockerAddAssetToHeroLoadoutRequest data, Action onComplete) + public static void AddAssetToHeroLoadout(string forPlayerWithUlid, int HeroID, LootLockerAddAssetToHeroLoadoutRequest data, Action onComplete) { EndPointClass endPoint = LootLockerEndPoints.addAssetToHeroLoadout; @@ -232,12 +216,10 @@ public static void AddAssetToHeroLoadout(string forPlayerWithUlid, LootLockerAdd } string json = LootLockerJson.SerializeObject(data); - string getVariable = endPoint.endPoint; - - LootLockerServerRequest.CallAPI(forPlayerWithUlid, getVariable, endPoint.httpMethod, json, (serverResponse) => { LootLockerResponse.Deserialize(onComplete, serverResponse); }); + LootLockerServerRequest.CallAPI(forPlayerWithUlid, endPoint.WithPathParameter(HeroID.ToString()), endPoint.httpMethod, json, (serverResponse) => { LootLockerResponse.Deserialize(onComplete, serverResponse); }); } - public static void AddAssetVariationToHeroLoadout(string forPlayerWithUlid, LootLockerAddAssetVariationToHeroLoadoutRequest data, Action onComplete) + public static void AddAssetVariationToHeroLoadout(string forPlayerWithUlid, int HeroID, LootLockerAddAssetVariationToHeroLoadoutRequest data, Action onComplete) { EndPointClass endPoint = LootLockerEndPoints.addAssetVariationToHeroLoadout; @@ -248,18 +230,14 @@ public static void AddAssetVariationToHeroLoadout(string forPlayerWithUlid, Loot } string json = LootLockerJson.SerializeObject(data); - string getVariable = endPoint.endPoint; - - LootLockerServerRequest.CallAPI(forPlayerWithUlid, getVariable, endPoint.httpMethod, json, (serverResponse) => { LootLockerResponse.Deserialize(onComplete, serverResponse); }); + LootLockerServerRequest.CallAPI(forPlayerWithUlid, endPoint.WithPathParameter(HeroID.ToString()), endPoint.httpMethod, json, (serverResponse) => { LootLockerResponse.Deserialize(onComplete, serverResponse); }); } - public static void RemoveAssetFromHeroLoadout(string forPlayerWithUlid, LootLockerGetRequest lootLockerGetRequest, Action onComplete) + public static void RemoveAssetFromHeroLoadout(string forPlayerWithUlid, int HeroID, int assetID, Action onComplete) { EndPointClass endPoint = LootLockerEndPoints.removeAssetFromHeroLoadout; - string getVariable = endPoint.WithPathParameters(lootLockerGetRequest.getRequests[0], lootLockerGetRequest.getRequests[1]); - - LootLockerServerRequest.CallAPI(forPlayerWithUlid, getVariable, endPoint.httpMethod, null, (serverResponse) => { LootLockerResponse.Deserialize(onComplete, serverResponse); }); ; + LootLockerServerRequest.CallAPI(forPlayerWithUlid, endPoint.WithPathParameters(assetID.ToString(), HeroID.ToString()), endPoint.httpMethod, null, (serverResponse) => { LootLockerResponse.Deserialize(onComplete, serverResponse); }); } diff --git a/Runtime/Game/Requests/PlayerRequest.cs b/Runtime/Game/Requests/PlayerRequest.cs index ea6ce362..d23f54d4 100644 --- a/Runtime/Game/Requests/PlayerRequest.cs +++ b/Runtime/Game/Requests/PlayerRequest.cs @@ -270,7 +270,7 @@ public static void LookupPlayerNames(string forPlayerWithUlid, string idType, st queryParams.Add(idType, identifier); } - LootLockerServerRequest.CallAPI(forPlayerWithUlid, endPoint.endPoint += queryParams.Build(), endPoint.httpMethod, null, onComplete: (serverResponse) => { LootLockerResponse.Deserialize(onComplete, serverResponse); }); + LootLockerServerRequest.CallAPI(forPlayerWithUlid, endPoint.endPoint + queryParams.Build(), endPoint.httpMethod, null, onComplete: (serverResponse) => { LootLockerResponse.Deserialize(onComplete, serverResponse); }); } public static void LookupPlayer1stPartyPlatformIDs(string forPlayerWithUlid, LookupPlayer1stPartyPlatformIDsRequest lookupPlayer1stPartyPlatformIDsRequest, Action onComplete) @@ -289,7 +289,7 @@ public static void LookupPlayer1stPartyPlatformIDs(string forPlayerWithUlid, Loo queryParams.Add("player_public_uid", playerPublicUID); } - LootLockerServerRequest.CallAPI(forPlayerWithUlid, endPoint.endPoint += queryParams.Build(), endPoint.httpMethod, null, onComplete: (serverResponse) => { LootLockerResponse.Deserialize(onComplete, serverResponse); }); + LootLockerServerRequest.CallAPI(forPlayerWithUlid, endPoint.endPoint + queryParams.Build(), endPoint.httpMethod, null, onComplete: (serverResponse) => { LootLockerResponse.Deserialize(onComplete, serverResponse); }); } } } diff --git a/Runtime/Game/Requests/ReportRequets.cs b/Runtime/Game/Requests/ReportRequets.cs index e14a9bfa..54ea3e8a 100644 --- a/Runtime/Game/Requests/ReportRequets.cs +++ b/Runtime/Game/Requests/ReportRequets.cs @@ -115,7 +115,7 @@ public static void GetRemovedUGCForPlayer(string forPlayerWithUlid, GetRemovedUG queryParams.Add("since", input.Since); } - LootLockerServerRequest.CallAPI(forPlayerWithUlid, endPoint.endPoint += queryParams.Build(), endPoint.httpMethod, null, (serverResponse) => { LootLockerResponse.Deserialize(onComplete, serverResponse); }); + LootLockerServerRequest.CallAPI(forPlayerWithUlid, endPoint.endPoint + queryParams.Build(), endPoint.httpMethod, null, (serverResponse) => { LootLockerResponse.Deserialize(onComplete, serverResponse); }); } public static void CreatePlayerReport(string forPlayerWithUlid, ReportsCreatePlayerRequest data, Action onComplete) diff --git a/Runtime/Game/Utilities/LootLockerHttpUtilities.cs b/Runtime/Game/Utilities/LootLockerHttpUtilities.cs index 5881d8a6..1f2a9c97 100644 --- a/Runtime/Game/Utilities/LootLockerHttpUtilities.cs +++ b/Runtime/Game/Utilities/LootLockerHttpUtilities.cs @@ -59,7 +59,7 @@ public string Build() foreach (KeyValuePair pair in _queryParams) { - if (string.IsNullOrEmpty(pair.Value)) + if (string.IsNullOrEmpty(pair.Key) || string.IsNullOrEmpty(pair.Value)) continue; if (query.Length > 1) diff --git a/Tests/LootLockerTests/PlayMode/MultiUserTests.cs b/Tests/LootLockerTests/PlayMode/MultiUserTests.cs index b8a9b424..fe251728 100644 --- a/Tests/LootLockerTests/PlayMode/MultiUserTests.cs +++ b/Tests/LootLockerTests/PlayMode/MultiUserTests.cs @@ -806,7 +806,7 @@ public IEnumerator MultiUser_SetPlayerDataWhenPlayerCachesExistButNoPlayersAreAc // When bool loginCompleted = false; - LootLockerSDKManager.StartGuestSession(response => + LootLockerSDKManager.StartGuestSession("completely-novel-identifier", response => { ulids.Add(response.player_ulid); loginCompleted = true; @@ -826,6 +826,55 @@ public IEnumerator MultiUser_SetPlayerDataWhenPlayerCachesExistButNoPlayersAreAc yield return null; } + + [UnityTest, Category("LootLocker"), Category("LootLockerCI"), Category("LootLockerCIFast")] + public IEnumerator MultiUser_GetPlayerDataWhenPlayerCachesExistButNoPlayersAreActive_GetsPlayerAndSetsDefault() + { + // Setup Succeeded + Assert.IsFalse(SetupFailed, "Setup did not succeed"); + + // Given + List ulids = new List(); + int guestUsersToCreate = 3; + for (int i = 0; i < guestUsersToCreate; i++) + { + bool guestLoginCompleted = false; + LootLockerSDKManager.StartGuestSession(response => + { + ulids.Add(response.player_ulid); + guestLoginCompleted = true; + }); + yield return new WaitUntil(() => guestLoginCompleted); + } + + foreach (var ulid in ulids) + { + LootLockerStateData.SetPlayerULIDToInactive(ulid); + } + + // When + bool pingCompleted = false; + string pingUlid = null; + LootLockerSDKManager.Ping(response => + { + pingUlid = response.requestContext.player_ulid; + pingCompleted = true; + }, ulids[ulids.Count - 1]); + yield return new WaitUntil(() => pingCompleted); + + // Then + int postPingActivePlayerCount = LootLockerStateData.GetActivePlayerULIDs().Count; + var postPingDefaultPlayerPlayerData = LootLockerStateData.GetStateForPlayerOrDefaultStateOrEmpty(null); + var postPingDefaultPlayerUlid = LootLockerStateData.GetDefaultPlayerULID(); + + Assert.AreEqual(1, postPingActivePlayerCount); + Assert.IsNotNull(postPingDefaultPlayerUlid); + Assert.IsNotNull(postPingDefaultPlayerPlayerData); + Assert.AreEqual(ulids[ulids.Count - 1], postPingDefaultPlayerUlid); + Assert.AreEqual(ulids[ulids.Count - 1], postPingDefaultPlayerPlayerData.ULID); + + yield return null; + } [UnityTest, Category("LootLocker"), Category("LootLockerCI"), Category("LootLockerCIFast")] public IEnumerator MultiUser_GetPlayerUlidFromWLEmailWhenPlayerIsCached_ReturnsCorrectULID() diff --git a/package.json b/package.json index 38b3888f..560b3a1a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "com.lootlocker.lootlockersdk", - "version": "6.3.0", + "version": "6.4.0", "displayName": "LootLocker", "description": "LootLocker is a game backend-as-a-service with plug and play tools to upgrade your game and give your players the best experience possible. Designed for teams of all shapes and sizes, on mobile, PC and console. From solo developers, indie teams, AAA studios, and publishers. Built with cross-platform in mind.\n\n▪ Manage your game\nSave time and upgrade your game with leaderboards, progression, and more. Completely off-the-shelf features, built to work with any game and platform.\n\n▪ Manage your content\nTake charge of your game's content on all platforms, in one place. Sort, edit and manage everything, from cosmetics to currencies, UGC to DLC. Without breaking a sweat.\n\n▪ Manage your players\nStore your players' data together in one place. Access their profile and friends list cross-platform. Manage reports, messages, refunds and gifts to keep them hooked.\n", "unity": "2019.2",