diff --git a/Runtime/Client/LootLockerEndPoints.cs b/Runtime/Client/LootLockerEndPoints.cs index d0d0071d8..a5f9d62a1 100644 --- a/Runtime/Client/LootLockerEndPoints.cs +++ b/Runtime/Client/LootLockerEndPoints.cs @@ -185,13 +185,6 @@ public class LootLockerEndPoints public static EndPointClass addingFilesToAssetCandidates = new EndPointClass("v1/player/assets/candidates/{0}/file", LootLockerHTTPMethod.UPLOAD_FILE); public static EndPointClass removingFilesFromAssetCandidates = new EndPointClass("v1/player/assets/candidates/{0}/file/{1}", LootLockerHTTPMethod.DELETE); - // Events - [Header("Events")] - public static EndPointClass gettingAllEvents = new EndPointClass("v1/missions", LootLockerHTTPMethod.GET); - public static EndPointClass gettingASingleEvent = new EndPointClass("v1/mission/{0}", LootLockerHTTPMethod.GET); - public static EndPointClass startingEvent = new EndPointClass("v1/mission/{0}/start", LootLockerHTTPMethod.POST); - public static EndPointClass finishingEvent = new EndPointClass("v1/mission/{0}/end", LootLockerHTTPMethod.POST); - // Missions [Header("Missions")] public static EndPointClass gettingAllMissions = new EndPointClass("v1/missions", LootLockerHTTPMethod.GET); diff --git a/Runtime/Client/LootLockerEventSystem.cs b/Runtime/Client/LootLockerEventSystem.cs index 94550e089..bff3a891f 100644 --- a/Runtime/Client/LootLockerEventSystem.cs +++ b/Runtime/Client/LootLockerEventSystem.cs @@ -432,7 +432,7 @@ public static void TriggerEvent(T eventData) where T : LootLockerEventData if (instance.logEvents) { - LootLockerLogger.Log($"LootLocker Event: {eventType} at {eventData.timestamp}. Notified {subscribers.Count} subscribers", LootLockerLogger.LogLevel.Debug); + LootLockerLogger.Log($"Triggered Event: {eventType} at {eventData.timestamp}. Notified {subscribers.Count} subscribers", LootLockerLogger.LogLevel.Debug); } } diff --git a/Runtime/Client/LootLockerHTTPClient.cs b/Runtime/Client/LootLockerHTTPClient.cs index 22c5da801..793e4b584 100644 --- a/Runtime/Client/LootLockerHTTPClient.cs +++ b/Runtime/Client/LootLockerHTTPClient.cs @@ -166,7 +166,7 @@ void ILootLockerService.Initialize() IsInitialized = true; _instance = this; } - LootLockerLogger.Log("LootLockerHTTPClient initialized", LootLockerLogger.LogLevel.Verbose); + LootLockerLogger.Log("HTTPClient initialized", LootLockerLogger.LogLevel.Verbose); } /// @@ -464,7 +464,7 @@ void Update() if((HTTPExecutionQueue.Count - CurrentlyOngoingRequests.Count) > configuration.ChokeWarningThreshold) { - LootLockerLogger.Log($"LootLocker HTTP Execution Queue is overloaded. Requests currently waiting for execution: '{(HTTPExecutionQueue.Count - CurrentlyOngoingRequests.Count)}'", LootLockerLogger.LogLevel.Warning); + LootLockerLogger.Log($"HTTP Execution Queue is overloaded. Requests currently waiting for execution: '{(HTTPExecutionQueue.Count - CurrentlyOngoingRequests.Count)}'", LootLockerLogger.LogLevel.Warning); } } diff --git a/Runtime/Client/LootLockerLifecycleManager.cs b/Runtime/Client/LootLockerLifecycleManager.cs index e7b8c3f66..d1519c550 100644 --- a/Runtime/Client/LootLockerLifecycleManager.cs +++ b/Runtime/Client/LootLockerLifecycleManager.cs @@ -59,7 +59,7 @@ private static void AutoInitialize() { if (_instance == null && Application.isPlaying) { - LootLockerLogger.Log("Auto-initializing LootLocker LifecycleManager on application start", LootLockerLogger.LogLevel.Debug); + LootLockerLogger.Log("Auto-initializing LifecycleManager on application start", LootLockerLogger.LogLevel.Debug); Instantiate(); } } diff --git a/Runtime/Client/LootLockerSessionResponse.cs b/Runtime/Client/LootLockerSessionResponse.cs new file mode 100644 index 000000000..5280893fc --- /dev/null +++ b/Runtime/Client/LootLockerSessionResponse.cs @@ -0,0 +1,88 @@ +using System; + +namespace LootLocker.Requests +{ + + [Serializable] + public class LootLockerLevel_Thresholds + { + public int current { get; set; } + public bool current_is_prestige { get; set; } + public int? next { get; set; } + public bool next_is_prestige { get; set; } + } + + + [Serializable] + public class LootLockerSessionResponse : LootLockerResponse + { + /// + /// The player's name if it has been set by using SetPlayerName(). + /// + public string player_name { get; set; } + /// + /// The session token that can now be used to use further LootLocker functionality. We store and use this for you. + /// + public string session_token { get; set; } + /// + /// The player id + /// + public int player_id { get; set; } + /// + /// Whether this player has been seen before (true) or is new (false) + /// + public bool seen_before { get; set; } + /// + /// The last time this player logged in + /// + public DateTime? last_seen { get; set; } + /// + /// The public UID for this player + /// + public string public_uid { get; set; } + /// + /// The player ULID for this player + /// + public string player_ulid { get; set; } + /// + /// The creation time of this player + /// + public DateTime player_created_at { get; set; } + /// + /// Whether this player has new information to check in grants + /// + public bool check_grant_notifications { get; set; } + /// + /// Whether this player has new information to check in deactivations + /// + public bool check_deactivation_notifications { get; set; } + /// + /// Whether this player has new information to check in dlcs + /// + public int[] check_dlcs { get; set; } + /// + /// The current xp of this player + /// + public int xp { get; set; } + /// + /// The current level of this player + /// + public int level { get; set; } + /// + /// The level_thresholds that the level and xp data relates to + /// + public LootLockerLevel_Thresholds level_thresholds { get; set; } + /// + /// The current balance in this account + /// + public int account_balance { get; set; } + /// + /// The id of the wallet for this account + /// + public string wallet_id { get; set; } + /// + /// Any errors that occurred during the request, for example if a player name was supplied in optionals but was invalid. + /// + public string[] errors { get; set; } + } +} \ No newline at end of file diff --git a/Runtime/Client/LootLockerSessionResponse.cs.meta b/Runtime/Client/LootLockerSessionResponse.cs.meta new file mode 100644 index 000000000..acabf2106 --- /dev/null +++ b/Runtime/Client/LootLockerSessionResponse.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: c68d6e7980f88ff488d92848278a2910 \ No newline at end of file diff --git a/Runtime/Editor/Editor UI/LootLockerAdminExtension.cs b/Runtime/Editor/Editor UI/LootLockerAdminExtension.cs index 35039753f..86cde51e5 100644 --- a/Runtime/Editor/Editor UI/LootLockerAdminExtension.cs +++ b/Runtime/Editor/Editor UI/LootLockerAdminExtension.cs @@ -171,7 +171,9 @@ private bool IsStageOnlyGame() if (game.created_at == default(System.DateTime) || game.created_at == null) return false; var cutoff = new System.DateTime(2025, 3, 10); return game.created_at >= cutoff; - } void SwapEnvironment() + } + + void SwapEnvironment() { if (isLoadingKeys) { diff --git a/Runtime/Editor/LogViewer/LootLockerLogViewerUI.cs b/Runtime/Editor/LogViewer/LootLockerLogViewerUI.cs index 506de51d0..32ead4a3c 100644 --- a/Runtime/Editor/LogViewer/LootLockerLogViewerUI.cs +++ b/Runtime/Editor/LogViewer/LootLockerLogViewerUI.cs @@ -124,9 +124,10 @@ private void SetupLogLevelDropdown() public void Log(LootLockerLogger.LogLevel logLevel, string message) { // Skip regular HTTP log lines (let the enriched HTTP log handle it) - if (message.StartsWith("[LL HTTP]") || message.StartsWith("[LL HTTP RESPONSE]")) + if (message.Contains("[HTTP]") || message.Contains("[HTTP RESPONSE]")) return; - var logEntry = new LogEntry { level = logLevel, message = message, Timestamp = DateTime.Now }; + string labelFreeMessage = message.Replace(LootLockerLogger.GetLogLabel(), "").Trim(); + var logEntry = new LogEntry { level = logLevel, message = labelFreeMessage, Timestamp = DateTime.Now }; logEntries.Add(logEntry); allLogEntries.Add(logEntry); if (logEntries.Count > MAX_LOG_ENTRIES) @@ -199,15 +200,15 @@ private void ExportLogs() var sb = new System.Text.StringBuilder(); if (http.Response?.success ?? false) { - sb.AppendLine($"[LL HTTP] {http.Method} request to {http.Url} succeeded"); + sb.AppendLine($"[HTTP] {http.Method} request to {http.Url} succeeded"); } else if (!string.IsNullOrEmpty(http.Response?.errorData?.message) && http.Response?.errorData?.message.Length < 40) { - sb.AppendLine($"[LL HTTP] {http.Method} request to {http.Url} failed with message {http.Response.errorData.message} ({http.StatusCode})"); + sb.AppendLine($"[HTTP] {http.Method} request to {http.Url} failed with message {http.Response.errorData.message} ({http.StatusCode})"); } else { - sb.AppendLine($"[LL HTTP] {http.Method} request to {http.Url} failed (details in expanded log) ({http.StatusCode})"); + sb.AppendLine($"[HTTP] {http.Method} request to {http.Url} failed (details in expanded log) ({http.StatusCode})"); } sb.AppendLine($"Duration: {http.DurationSeconds:n4}s"); sb.AppendLine("Request Headers:"); diff --git a/Runtime/Game/LootLockerLogger.cs b/Runtime/Game/LootLockerLogger.cs index 0cbdf6def..17f660664 100644 --- a/Runtime/Game/LootLockerLogger.cs +++ b/Runtime/Game/LootLockerLogger.cs @@ -8,6 +8,9 @@ public class LootLockerLogger { public static LootLockerLogger _instance = null; + private static readonly string LL_LOG_LABEL = $"[{LootLockerConfig.PackageShortName}]"; + private static string LogLabel = LL_LOG_LABEL; + private Dictionary logListeners = new Dictionary(); private class LogRecord { @@ -33,6 +36,16 @@ public enum LogLevel , None } + public static string GetLogLabel() + { + return LogLabel; + } + + public static void SetLogLabel(string newLabel) + { + LogLabel = newLabel; + } + /// /// Log message with the specified loglevel /// @@ -44,6 +57,7 @@ public static void Log(string message, LogLevel logLevel = LogLevel.Info) { return; } + string prependedMessage = $"{LogLabel} {message}"; Action logger; switch (logLevel) @@ -73,14 +87,14 @@ public static void Log(string message, LogLevel logLevel = LogLevel.Info) if(logger != null) { - logger(message); + logger(prependedMessage); } if(_instance == null) { _instance = new LootLockerLogger(); } - _instance.RecordAndBroadcastMessage(message, logLevel); + _instance.RecordAndBroadcastMessage(prependedMessage, logLevel); } private static bool ShouldLog(LogLevel logLevel) @@ -228,15 +242,15 @@ public static void LogHttpRequestResponse(LootLockerHttpLogEntry entry) var sb = new System.Text.StringBuilder(); if (entry.Response?.success ?? false) { - sb.AppendLine($"[LL HTTP] {entry.Method} request to {entry.Url} succeeded"); + sb.AppendLine($"[HTTP] {entry.Method} request to {entry.Url} succeeded"); } else if (!string.IsNullOrEmpty(entry.Response?.errorData?.message) && entry.Response?.errorData?.message.Length < 40) { - sb.AppendLine($"[LL HTTP] {entry.Method} request to {entry.Url} failed with message {entry.Response.errorData.message} ({entry.StatusCode})"); + sb.AppendLine($"[HTTP] {entry.Method} request to {entry.Url} failed with message {entry.Response.errorData.message} ({entry.StatusCode})"); } else { - sb.AppendLine($"[LL HTTP] {entry.Method} request to {entry.Url} failed (details in expanded log) ({entry.StatusCode})"); + sb.AppendLine($"[HTTP] {entry.Method} request to {entry.Url} failed (details in expanded log) ({entry.StatusCode})"); } sb.AppendLine($"Duration: {entry.DurationSeconds:n4}s"); sb.AppendLine("Request Headers:"); diff --git a/Runtime/Game/LootLockerSDKManager.cs b/Runtime/Game/LootLockerSDKManager.cs index d4e7fe507..fb37de911 100644 --- a/Runtime/Game/LootLockerSDKManager.cs +++ b/Runtime/Game/LootLockerSDKManager.cs @@ -114,7 +114,7 @@ public static bool CheckInitialized(bool skipSessionCheck = false, string forPla // Double check that initialization succeeded if (!LootLockerLifecycleManager.IsReady) { - LootLockerLogger.Log("LootLocker services are still initializing. Please try again in a moment.", LootLockerLogger.LogLevel.Warning); + LootLockerLogger.Log("The SDK services are still initializing. Please try again in a moment.", LootLockerLogger.LogLevel.Warning); return false; } } @@ -158,11 +158,11 @@ public static void SetStateWriter(ILootLockerStateWriter stateWriter) /// public static void ResetSDK() { - LootLockerLogger.Log("Resetting LootLocker SDK - all services and state will be cleared", LootLockerLogger.LogLevel.Info); + LootLockerLogger.Log("Resetting SDK - all services and state will be cleared", LootLockerLogger.LogLevel.Info); LootLockerLifecycleManager.ResetInstance(); - LootLockerLogger.Log("LootLocker SDK reset complete", LootLockerLogger.LogLevel.Info); + LootLockerLogger.Log("SDK reset complete", LootLockerLogger.LogLevel.Info); } #endregion @@ -5526,7 +5526,6 @@ public static void GrantAssetToPlayerInventory(int assetID, int? assetVariationI LootLockerAPIManager.GrantAssetToPlayerInventory(forPlayerWithUlid, data, onComplete); } - #endregion /// /// List assets with default parameters (no filters, first page, default page size). /// @@ -5577,6 +5576,8 @@ public static void ListAssets(LootLockerListAssetsRequest Request, Action /// Get all key/value pairs for all asset instances. diff --git a/Runtime/Game/Requests/AssetInstanceRequest.cs b/Runtime/Game/Requests/AssetInstanceRequest.cs index a2bbc99da..a165fb558 100644 --- a/Runtime/Game/Requests/AssetInstanceRequest.cs +++ b/Runtime/Game/Requests/AssetInstanceRequest.cs @@ -21,13 +21,6 @@ public class LootLockerInstanceStoragePair public LootLockerStorage storage { get; set; } } - public class LootLockerStorage - { - public int id { get; set; } - public string key { get; set; } - public string value { get; set; } - } - public class LootLockerAssetDefaultResponse : LootLockerResponse { diff --git a/Runtime/Game/Requests/AssetRequest.cs b/Runtime/Game/Requests/AssetRequest.cs index b431d2916..781166b6d 100644 --- a/Runtime/Game/Requests/AssetRequest.cs +++ b/Runtime/Game/Requests/AssetRequest.cs @@ -43,28 +43,6 @@ public enum OrderAssetListDirection namespace LootLocker.Requests { - public class LootLockerLinks : Dictionary - { - public string thumbnail - { - get - { - TryGetValue(nameof(thumbnail), out var value); - return value; - } - set - { - if (ContainsKey(nameof(thumbnail))) - { - this[nameof(thumbnail)] = value; - } - else - { - Add(nameof(thumbnail), value); - } - } - } - } public class LootLockerDefault_Loadouts_Info { @@ -183,66 +161,6 @@ public class LootLockerSingleAssetResponse : LootLockerResponse public LootLockerCommonAsset asset { get; set; } } - public class LootLockerRental_Options - { - public int id { get; set; } - public string name { get; set; } - public int duration { get; set; } - public int price { get; set; } - public object sales_price { get; set; } - public object links { get; set; } - } - - public class LootLockerRarity - { - public string name { get; set; } - public string short_name { get; set; } - public string color { get; set; } - } - - public class LootLockerFilter - { - public string value { get; set; } - public string name { get; set; } - } - - [Serializable] - public class LootLockerCommonAsset - { - public int id { get; set; } - public string uuid { get; set; } - public string ulid { get; set; } - public string name { get; set; } - public bool active { get; set; } - public bool purchasable { get; set; } - public string type { get; set; } - public int price { get; set; } - public int? sales_price { get; set; } - public string display_price { get; set; } - public string context { get; set; } - public string unlocks_context { get; set; } - public bool detachable { get; set; } - public string updated { get; set; } - public string marked_new { get; set; } - public int default_variation_id { get; set; } - public string description { get; set; } - public LootLockerLinks links { get; set; } - public LootLockerStorage[] storage { get; set; } - public LootLockerRarity rarity { get; set; } - public bool popular { get; set; } - public int popularity_score { get; set; } - public bool unique_instance { get; set; } - public LootLockerRental_Options[] rental_options { get; set; } - public LootLockerFilter[] filters { get; set; } - public LootLockerVariation[] variations { get; set; } - public bool featured { get; set; } - public bool context_locked { get; set; } - public bool initially_purchasable { get; set; } - public LootLockerFile[] files { get; set; } - public LootLockerAssetCandidate asset_candidate { get; set; } - public string[] data_entities { get; set; } - } - [Serializable] public class LootLockerCommonAssetResponse : LootLockerResponse { @@ -321,60 +239,16 @@ public class LootLockerSimpleAssetDataEntity public string data { get; set; } } - public class LootLockerAssetCandidate - { - public int created_by_player_id { get; set; } - public string created_by_player_uid { get; set; } - } - - public class LootLockerFile - { - public string url { get; set; } - public string[] tags { get; set; } - } - public class LootLockerDefault_Loadouts { public bool Default { get; set; } } - public class LootLockerVariation - { - public int id { get; set; } - public string name { get; set; } - public object primary_color { get; set; } - public object secondary_color { get; set; } - public Dictionary links { get; set; } - } - - - public class LootLockerContextResponse : LootLockerResponse - { - public LootLockerContext[] contexts { get; set; } - } - - public class LootLockerContext - { - public int id { get; set; } - public string uuid { get; set; } - public string name { get; set; } - public string friendly_name { get; set; } - public bool detachable { get; set; } - public bool user_facing { get; set; } - public object dependent_asset_id { get; set; } - public int max_equip_count { get; set; } - } - public class LootLockerFavouritesListResponse : LootLockerResponse { public int[] favourites { get; set; } } - public class LootLockerActivateRentalAssetResponse : LootLockerResponse - { - public int time_left { get; set; } - } - public class LootLockerGrantAssetResponse : LootLockerResponse { public int id { get; set; } diff --git a/Runtime/Game/Requests/EventRequest.cs b/Runtime/Game/Requests/EventRequest.cs deleted file mode 100644 index 3ce542b59..000000000 --- a/Runtime/Game/Requests/EventRequest.cs +++ /dev/null @@ -1,161 +0,0 @@ -using LootLocker.Requests; -using System; - -namespace LootLocker.Requests -{ - [Serializable] - public class LootLockerEventResponse : LootLockerResponse - { - public LootLockerEvent[] events { get; set; } - } - - [Serializable] - public class LootLockerSingleEventResponse : LootLockerResponse - { - public LootLockerEvent events { get; set; } - } - - [Serializable] - public class LootLockerFinishEventResponse : LootLockerResponse - { - public int score { get; set; } - public bool check_grant_notifications { get; set; } - } - - [Serializable] - public class LootLockerStartinEventResponse : LootLockerResponse - { - public string signature { get; set; } - } - - [Serializable] - public class LootLockerEvent - { - public int event_id { get; set; } - public int asset_id { get; set; } - public int rounds { get; set; } - public string round_length { get; set; } - public object difficulty_name { get; set; } - public object difficulty_multiplier { get; set; } - public string difficulty_color { get; set; } - public int difficulty_id { get; set; } - public LootLockerGoals goals { get; set; } - public LootLockerCheckpoint[] checkpoints { get; set; } - public bool player_access { get; set; } - public string best_goal { get; set; } - } - - [Serializable] - public class LootLockerGoals - { - public LootLockerGold gold { get; set; } - public LootLockerSilver silver { get; set; } - public LootLockerBronze bronze { get; set; } - } - - [Serializable] - public class LootLockerGold - { - public string goal { get; set; } - public string points { get; set; } - public LootLockerCommonAsset[] assets { get; set; } - } - - [Serializable] - public class LootLockerSilver - { - public string goal { get; set; } - public string points { get; set; } - public object[] assets { get; set; } - } - - [Serializable] - public class LootLockerBronze - { - public string goal { get; set; } - public string points { get; set; } - public object[] assets { get; set; } - } - - [Serializable] - public class LootLockerCheckpoint - { - public int index { get; set; } - public int time { get; set; } - public string your_key { get; set; } - public string your_second_key { get; set; } - } - - [Serializable] - public class FinishEventRequest - { - public string signature { get; set; } - public LootLockerEventPayload payload { get; set; } - } - - [Serializable] - public class LootLockerEventPayload - { - public string finish_time { get; set; } - public string finish_score { get; set; } - public LootLockerCheckpointTimes[] checkpoint_times { get; set; } - } - - [Serializable] - public class LootLockerCheckpointTimes - { - public int index { get; set; } - public int time { get; set; } - public int score { get; set; } - } -} - -namespace LootLocker -{ - public partial class LootLockerAPIManager - { - public static void GettingAllEvents(Action onComplete, string forPlayerWithUlid = null) - { - EndPointClass endPoint = LootLockerEndPoints.gettingAllEvents; - - string getVariable = endPoint.endPoint; - - LootLockerServerRequest.CallAPI(forPlayerWithUlid, getVariable, endPoint.httpMethod, null, onComplete: (serverResponse) => { LootLockerResponse.Deserialize(onComplete, serverResponse); }); - } - - public static void GettingASingleEvent(LootLockerGetRequest data, Action onComplete, string forPlayerWithUlid = null) - { - EndPointClass endPoint = LootLockerEndPoints.gettingASingleEvent; - - string getVariable = endPoint.WithPathParameter(data.getRequests[0]); - - LootLockerServerRequest.CallAPI(forPlayerWithUlid, getVariable, endPoint.httpMethod, null, onComplete: (serverResponse) => { LootLockerResponse.Deserialize(onComplete, serverResponse); }); - } - - public static void StartingEvent(LootLockerGetRequest data, Action onComplete, string forPlayerWithUlid = null) - { - EndPointClass endPoint = LootLockerEndPoints.startingEvent; - - string getVariable = endPoint.WithPathParameter(data.getRequests[0]); - - LootLockerServerRequest.CallAPI(forPlayerWithUlid, getVariable, endPoint.httpMethod, null, onComplete: (serverResponse) => { LootLockerResponse.Deserialize(onComplete, serverResponse); }); - } - - public static void FinishingEvent(LootLockerGetRequest lootLockerGetRequest, FinishEventRequest data, Action onComplete, string forPlayerWithUlid = null) - { - if(data == null) - { - onComplete?.Invoke(LootLockerResponseFactory.InputUnserializableError(forPlayerWithUlid)); - return; - } - - string json = LootLockerJson.SerializeObject(data); - - EndPointClass endPoint = LootLockerEndPoints.finishingEvent; - - string getVariable = endPoint.WithPathParameter(lootLockerGetRequest.getRequests[0]); - - LootLockerServerRequest.CallAPI(forPlayerWithUlid, getVariable, endPoint.httpMethod, json, (serverResponse) => { LootLockerResponse.Deserialize(onComplete, serverResponse); }); - } - } -} \ No newline at end of file diff --git a/Runtime/Game/Requests/EventRequest.cs.meta b/Runtime/Game/Requests/EventRequest.cs.meta deleted file mode 100644 index f2abc9c5c..000000000 --- a/Runtime/Game/Requests/EventRequest.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: ecb0a5d4925cdda4baba528dadc30687 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Runtime/Game/Requests/LootLockerCommonRequestTypes.cs b/Runtime/Game/Requests/LootLockerCommonRequestTypes.cs new file mode 100644 index 000000000..bae3617f4 --- /dev/null +++ b/Runtime/Game/Requests/LootLockerCommonRequestTypes.cs @@ -0,0 +1,167 @@ +using System; +using System.Collections.Generic; + +namespace LootLocker.Requests +{ + public class LootLockerStorage + { + public int id { get; set; } + public string key { get; set; } + public string value { get; set; } + } + + public class LootLockerLinks : Dictionary + { + public string thumbnail + { + get + { + TryGetValue(nameof(thumbnail), out var value); + return value; + } + set + { + if (ContainsKey(nameof(thumbnail))) + { + this[nameof(thumbnail)] = value; + } + else + { + Add(nameof(thumbnail), value); + } + } + } + } + + public class LootLockerRarity + { + public string name { get; set; } + public string short_name { get; set; } + public string color { get; set; } + } + + public class LootLockerRental_Options + { + public int id { get; set; } + public string name { get; set; } + public int duration { get; set; } + public int price { get; set; } + public object sales_price { get; set; } + public object links { get; set; } + } + + public class LootLockerFilter + { + public string value { get; set; } + public string name { get; set; } + } + + public class LootLockerVariation + { + public int id { get; set; } + public string name { get; set; } + public object primary_color { get; set; } + public object secondary_color { get; set; } + public Dictionary links { get; set; } + } + + public class LootLockerFile + { + public string url { get; set; } + public string[] tags { get; set; } + } + + public class LootLockerAssetCandidate + { + public int created_by_player_id { get; set; } + public string created_by_player_uid { get; set; } + } + + [Serializable] + public class LootLockerCommonAsset + { + public int id { get; set; } + public string uuid { get; set; } + public string ulid { get; set; } + public string name { get; set; } + public bool active { get; set; } + public bool purchasable { get; set; } + public string type { get; set; } + public int price { get; set; } + public int? sales_price { get; set; } + public string display_price { get; set; } + public string context { get; set; } + public string unlocks_context { get; set; } + public bool detachable { get; set; } + public string updated { get; set; } + public string marked_new { get; set; } + public int default_variation_id { get; set; } + public string description { get; set; } + public LootLockerLinks links { get; set; } + public LootLockerStorage[] storage { get; set; } + public LootLockerRarity rarity { get; set; } + public bool popular { get; set; } + public int popularity_score { get; set; } + public bool unique_instance { get; set; } + public LootLockerRental_Options[] rental_options { get; set; } + public LootLockerFilter[] filters { get; set; } + public LootLockerVariation[] variations { get; set; } + public bool featured { get; set; } + public bool context_locked { get; set; } + public bool initially_purchasable { get; set; } + public LootLockerFile[] files { get; set; } + public LootLockerAssetCandidate asset_candidate { get; set; } + public string[] data_entities { get; set; } + } + + [Serializable] + public class LootLockerRental + { + public bool is_rental { get; set; } + public string time_left { get; set; } + public string duration { get; set; } + public string is_active { get; set; } + } + + public class LootLockerContextResponse : LootLockerResponse + { + public LootLockerContext[] contexts { get; set; } + } + + public class LootLockerContext + { + public int id { get; set; } + public string uuid { get; set; } + public string name { get; set; } + public string friendly_name { get; set; } + public bool detachable { get; set; } + public bool user_facing { get; set; } + public object dependent_asset_id { get; set; } + public int max_equip_count { get; set; } + } + + public class LootLockerActivateRentalAssetResponse : LootLockerResponse + { + public int time_left { get; set; } + } + + [Serializable] + public class LootLockerInventoryResponse : LootLockerResponse + { + public LootLockerInventory[] inventory { get; set; } + } + + public class LootLockerInventory + { + public int instance_id { get; set; } + public int? variation_id { get; set; } + public string rental_option_id { get; set; } + public string acquisition_source { get; set; } + public DateTime? acquisition_date { get; set; } + public LootLockerCommonAsset asset { get; set; } + public LootLockerRental rental { get; set; } + + + public float balance { get; set; } + } +} \ No newline at end of file diff --git a/Runtime/Game/Requests/LootLockerCommonRequestTypes.cs.meta b/Runtime/Game/Requests/LootLockerCommonRequestTypes.cs.meta new file mode 100644 index 000000000..92ddc021f --- /dev/null +++ b/Runtime/Game/Requests/LootLockerCommonRequestTypes.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 1dbcaf3119bfdd64f944b86c9510dcc9 \ No newline at end of file diff --git a/Runtime/Game/Requests/LootLockerSessionRequest.cs b/Runtime/Game/Requests/LootLockerSessionRequest.cs index 2e2e360fc..e2b897b7a 100644 --- a/Runtime/Game/Requests/LootLockerSessionRequest.cs +++ b/Runtime/Game/Requests/LootLockerSessionRequest.cs @@ -99,79 +99,6 @@ public LootLockerWhiteLabelSessionRequest() } } - [Serializable] - public class LootLockerSessionResponse : LootLockerResponse - { - /// - /// The player's name if it has been set by using SetPlayerName(). - /// - public string player_name { get; set; } - /// - /// The session token that can now be used to use further LootLocker functionality. We store and use this for you. - /// - public string session_token { get; set; } - /// - /// The player id - /// - public int player_id { get; set; } - /// - /// Whether this player has been seen before (true) or is new (false) - /// - public bool seen_before { get; set; } - /// - /// The last time this player logged in - /// - public DateTime? last_seen { get; set; } - /// - /// The public UID for this player - /// - public string public_uid { get; set; } - /// - /// The player ULID for this player - /// - public string player_ulid { get; set; } - /// - /// The creation time of this player - /// - public DateTime player_created_at { get; set; } - /// - /// Whether this player has new information to check in grants - /// - public bool check_grant_notifications { get; set; } - /// - /// Whether this player has new information to check in deactivations - /// - public bool check_deactivation_notifications { get; set; } - /// - /// Whether this player has new information to check in dlcs - /// - public int[] check_dlcs { get; set; } - /// - /// The current xp of this player - /// - public int xp { get; set; } - /// - /// The current level of this player - /// - public int level { get; set; } - /// - /// The level_thresholds that the level and xp data relates to - /// - public LootLockerLevel_Thresholds level_thresholds { get; set; } - /// - /// The current balance in this account - /// - public int account_balance { get; set; } - /// - /// The id of the wallet for this account - /// - public string wallet_id { get; set; } - /// - /// Any errors that occurred during the request, for example if a player name was supplied in optionals but was invalid. - /// - public string[] errors { get; set; } - } - public class LootLockerGuestSessionResponse : LootLockerSessionResponse { /// @@ -223,15 +150,6 @@ public class LootLockerPlaystationV3SessionResponse : LootLockerSessionResponse public string player_identifier { get; set; } } - [Serializable] - public class LootLockerLevel_Thresholds - { - public int current { get; set; } - public bool current_is_prestige { get; set; } - public int? next { get; set; } - public bool next_is_prestige { get; set; } - } - [Serializable] public class LootLockerNintendoSwitchSessionRequest : LootLockerGetRequest { diff --git a/Runtime/Game/Requests/MissionsRequest.cs b/Runtime/Game/Requests/MissionsRequest.cs index 3f7648933..79653c342 100644 --- a/Runtime/Game/Requests/MissionsRequest.cs +++ b/Runtime/Game/Requests/MissionsRequest.cs @@ -27,6 +27,55 @@ public class LootLockerFinishingPayload public LootLockerCheckpointTimes[] checkpoint_times { get; set; } } + [Serializable] + public class LootLockerGoals + { + public LootLockerGold gold { get; set; } + public LootLockerSilver silver { get; set; } + public LootLockerBronze bronze { get; set; } + } + + [Serializable] + public class LootLockerGold + { + public string goal { get; set; } + public string points { get; set; } + public LootLockerCommonAsset[] assets { get; set; } + } + + [Serializable] + public class LootLockerSilver + { + public string goal { get; set; } + public string points { get; set; } + public object[] assets { get; set; } + } + + [Serializable] + public class LootLockerBronze + { + public string goal { get; set; } + public string points { get; set; } + public object[] assets { get; set; } + } + + [Serializable] + public class LootLockerCheckpoint + { + public int index { get; set; } + public int time { get; set; } + public string your_key { get; set; } + public string your_second_key { get; set; } + } + + [Serializable] + public class LootLockerCheckpointTimes + { + public int index { get; set; } + public int time { get; set; } + public int score { get; set; } + } + public class LootLockerFinishMissionRequest : LootLockerGetRequest { public string signature { get; set; } diff --git a/Runtime/Game/Requests/PlayerRequest.cs b/Runtime/Game/Requests/PlayerRequest.cs index 115e77c58..9fae1789a 100644 --- a/Runtime/Game/Requests/PlayerRequest.cs +++ b/Runtime/Game/Requests/PlayerRequest.cs @@ -52,29 +52,6 @@ public class LootLockerAssetClass public string Asset { get; set; } } - [Serializable] - public class LootLockerRental - { - public bool is_rental { get; set; } - public string time_left { get; set; } - public string duration { get; set; } - public string is_active { get; set; } - } - - public class LootLockerInventory - { - public int instance_id { get; set; } - public int? variation_id { get; set; } - public string rental_option_id { get; set; } - public string acquisition_source { get; set; } - public DateTime? acquisition_date { get; set; } - public LootLockerCommonAsset asset { get; set; } - public LootLockerRental rental { get; set; } - - - public float balance { get; set; } - } - /// /// A simplified view of an inventory item /// @@ -246,12 +223,6 @@ public class LootLockerBalanceResponse : LootLockerResponse public int? balance { get; set; } } - [Serializable] - public class LootLockerInventoryResponse : LootLockerResponse - { - public LootLockerInventory[] inventory { get; set; } - } - /// /// The response class for simplified inventory requests /// diff --git a/Runtime/Game/Requests/WhiteLabelRequest.cs b/Runtime/Game/Requests/WhiteLabelRequest.cs index 189b1fd54..68a2d6b13 100644 --- a/Runtime/Game/Requests/WhiteLabelRequest.cs +++ b/Runtime/Game/Requests/WhiteLabelRequest.cs @@ -83,8 +83,8 @@ public static void WhiteLabelLogin(LootLockerWhiteLabelUserRequest input, Action if (LootLockerConfig.current.domainKey.Length == 0) { - LootLockerLogger.Log("LootLocker domain key must be set in settings", LootLockerLogger.LogLevel.Error); - onComplete?.Invoke(LootLockerResponseFactory.ClientError("LootLocker domain key must be set in settings", null)); + LootLockerLogger.Log("Domain key must be set in settings", LootLockerLogger.LogLevel.Error); + onComplete?.Invoke(LootLockerResponseFactory.ClientError("Domain key must be set in settings", null)); return; } @@ -109,8 +109,8 @@ public static void WhiteLabelVerifySession(LootLockerWhiteLabelVerifySessionRequ if (LootLockerConfig.current.domainKey.Length == 0) { - LootLockerLogger.Log("LootLocker domain key must be set in settings", LootLockerLogger.LogLevel.Error); - onComplete?.Invoke(LootLockerResponseFactory.ClientError("LootLocker domain key must be set in settings", null)); + LootLockerLogger.Log("Domain key must be set in settings", LootLockerLogger.LogLevel.Error); + onComplete?.Invoke(LootLockerResponseFactory.ClientError("Domain key must be set in settings", null)); return; } @@ -132,8 +132,8 @@ public static void WhiteLabelSignUp(LootLockerWhiteLabelUserRequest input, Actio if (LootLockerConfig.current.domainKey.Length == 0) { - LootLockerLogger.Log("LootLocker domain key must be set in settings", LootLockerLogger.LogLevel.Error); - onComplete?.Invoke(LootLockerResponseFactory.ClientError("LootLocker domain key must be set in settings", null)); + LootLockerLogger.Log("Domain key must be set in settings", LootLockerLogger.LogLevel.Error); + onComplete?.Invoke(LootLockerResponseFactory.ClientError("Domain key must be set in settings", null)); return; } @@ -149,8 +149,8 @@ public static void WhiteLabelRequestPasswordReset(string email, Action("LootLocker domain key must be set in settings", null)); + LootLockerLogger.Log("Domain key must be set in settings", LootLockerLogger.LogLevel.Error); + onComplete?.Invoke(LootLockerResponseFactory.ClientError("Domain key must be set in settings", null)); return; } @@ -165,8 +165,8 @@ public static void WhiteLabelRequestAccountVerification(int userID, Action("LootLocker domain key must be set in settings", null)); + LootLockerLogger.Log("Domain key must be set in settings", LootLockerLogger.LogLevel.Error); + onComplete?.Invoke(LootLockerResponseFactory.ClientError("Domain key must be set in settings", null)); return; } @@ -181,8 +181,8 @@ public static void WhiteLabelRequestAccountVerification(string email, Action("LootLocker domain key must be set in settings", null)); + LootLockerLogger.Log("Domain key must be set in settings", LootLockerLogger.LogLevel.Error); + onComplete?.Invoke(LootLockerResponseFactory.ClientError("Domain key must be set in settings", null)); return; } diff --git a/Runtime/Game/Resources/LootLockerConfig.cs b/Runtime/Game/Resources/LootLockerConfig.cs index 548756679..2bf11f05f 100644 --- a/Runtime/Game/Resources/LootLockerConfig.cs +++ b/Runtime/Game/Resources/LootLockerConfig.cs @@ -10,62 +10,200 @@ namespace LootLocker { + [Serializable] public class LootLockerConfig : ScriptableObject { + public static readonly string PackageShortName = "LL"; // Standard is LL + private static readonly string PackageName = "LootLocker"; // Standard is LootLocker + private static readonly string SettingsName = $"{PackageName}Config"; + private static readonly string ConfigFolderName = $"{PackageName}SDK"; + private static readonly string ConfigAssetName = $"{SettingsName}.asset"; + private static readonly string ConfigAssetsPath = $"Assets/{ConfigFolderName}/Resources/Config/{ConfigAssetName}"; + private static readonly string ConfigResourceFolder = $"{Application.dataPath}/{ConfigFolderName}/Resources/Config"; + private static readonly string ConfigFileIdentifier = ""; // Optional extra package id if you want to be able to switch between multiple configurations + private static readonly string ConfigFileExtension = ".bytes"; + private static readonly string ConfigFileName = $"{SettingsName}" + (string.IsNullOrEmpty(ConfigFileIdentifier) ? "" : $"-{ConfigFileIdentifier}"); + private static readonly string ConfigFilePath = $"Assets/{ConfigFolderName}/Resources/Config/{ConfigFileName}{ConfigFileExtension}"; + + +#region User Config Variables + /** + * User Config Variables + * These are the variables that are exposed and recommended to change by the user + */ + public string apiKey; +#if UNITY_EDITOR + [HideInInspector] public string adminToken = null; +#endif + [HideInInspector] public string domainKey; + public string game_version = "1.0.0.0"; + [HideInInspector] public string sdk_version = ""; + public LootLockerLogger.LogLevel logLevel = LootLockerLogger.LogLevel.Info; + // Write JSON in a pretty and indented format when logging + public bool prettifyJson = true; + [HideInInspector] public bool obfuscateLogs = true; + public bool logErrorsAsWarnings = false; + public bool logInBuilds = false; + public bool allowTokenRefresh = true; + [Tooltip("Enable WebSocket presence system by default. Can be controlled at runtime via SetPresenceEnabled().")] + public bool enablePresence = false; + + [Tooltip("Automatically connect presence when sessions are started. Can be controlled at runtime via SetPresenceAutoConnectEnabled().")] + public bool enablePresenceAutoConnect = true; + + [Tooltip("Automatically disconnect presence when app loses focus or is paused (useful for battery saving). Can be controlled at runtime via SetPresenceAutoDisconnectOnFocusChangeEnabled().")] + public bool enablePresenceAutoDisconnectOnFocusChange = false; + + [Tooltip("Enable presence functionality while in the Unity Editor. Disable this if you don't want development to affect presence data.")] + public bool enablePresenceInEditor = true; - private static LootLockerConfig settingsInstance; - - public virtual string SettingName { get { return "LootLockerConfig"; } } +#endregion +#region Internal logic and configuration public static LootLockerConfig Get() { - if (settingsInstance != null) + if (_current != null) { #if LOOTLOCKER_COMMANDLINE_SETTINGS - settingsInstance.CheckForSettingOverrides(); + _current.CheckForSettingOverrides(); #endif - settingsInstance.ConstructUrls(); - return settingsInstance; + _current.ConstructUrls(); + return _current; + } + + var fileConfig = CheckForFileConfig(); + if (fileConfig != null && !string.IsNullOrEmpty(fileConfig.api_key)) + { + if(!File.Exists(ConfigAssetsPath)) + { + CreateConfigFile(); + } + else + { + _current = Resources.Load($"Config/{SettingsName}"); + } + _current.sdk_version = fileConfig.sdk_version; + _current.apiKey = fileConfig.api_key; + _current.game_version = fileConfig.game_version; + _current.domainKey = fileConfig.domain_key; + _current.enablePresence = fileConfig.enable_presence; + _current.enablePresenceAutoConnect = fileConfig.enable_presence_autoconnect; + _current.enablePresenceAutoDisconnectOnFocusChange = fileConfig.enable_presence_autodisconnect_on_focus_change; + _current.enablePresenceInEditor = fileConfig.enable_presence_in_editor; + _current.logLevel = fileConfig.log_level; + _current.logErrorsAsWarnings = fileConfig.log_errors_as_warnings; + _current.logInBuilds = fileConfig.log_in_builds; + _current.allowTokenRefresh = fileConfig.allow_token_refresh; + _current.prettifyJson = fileConfig.prettify_json; + _current.obfuscateLogs = fileConfig.obfuscate_logs; + _current.adminToken = null; + + return _current; } //Try to load it - settingsInstance = Resources.Load("Config/LootLockerConfig"); + _current = Resources.Load($"Config/{SettingsName}"); #if UNITY_EDITOR // Could not be loaded, create it - if (settingsInstance == null) + if (_current == null) { - // Create a new Config - LootLockerConfig newConfig = ScriptableObject.CreateInstance(); - - // Folder needs to exist for Unity to be able to create an asset in it - string dir = Application.dataPath+ "/LootLockerSDK/Resources/Config"; - - // If directory does not exist, create it - if (!Directory.Exists(dir)) - { - Directory.CreateDirectory(dir); - } - - // Create config asset - string configAssetPath = "Assets/LootLockerSDK/Resources/Config/LootLockerConfig.asset"; - AssetDatabase.CreateAsset(newConfig, configAssetPath); - EditorApplication.delayCall += AssetDatabase.SaveAssets; - AssetDatabase.Refresh(); - settingsInstance = newConfig; + CreateConfigFile(); } #else - if (settingsInstance == null) + if (_current == null) { - throw new ArgumentException("LootLocker config does not exist. To fix this, play once in the Unity Editor before making a build."); + throw new ArgumentException($"{ConfigFolderName} config does not exist. To fix this, play once in the Unity Editor before making a build."); } #endif #if LOOTLOCKER_COMMANDLINE_SETTINGS - settingsInstance.CheckForSettingOverrides(); + _current.CheckForSettingOverrides(); #endif - settingsInstance.ConstructUrls(); - return settingsInstance; + _current.ConstructUrls(); + return _current; + } + + private static ExternalFileConfig CheckForFileConfig() + { + ExternalFileConfig fileConfig = null; + try { + if(!File.Exists(ConfigFilePath)) + { + return fileConfig; + } + AssetDatabase.ImportAsset(ConfigFilePath, ImportAssetOptions.ForceUpdate | ImportAssetOptions.ForceSynchronousImport); + AssetDatabase.Refresh(); + + TextAsset configTextAsset = AssetDatabase.LoadAssetAtPath(ConfigFilePath); + + // Fallback: if Unity asset system isn't ready, read file directly from disk + string configText = null; + if(configTextAsset != null) + { + configText = configTextAsset.text; + } + else + { + // Direct file read as fallback + configText = File.ReadAllText(ConfigFilePath); + } + + if(!string.IsNullOrEmpty(configText)) + { + var encryptedBase64 = configText; + if (!LootLocker.Utilities.Encryption.LootLockerEncryptionUtilities.IsValidBase64String(encryptedBase64)) + { + fileConfig = LootLockerJson.DeserializeObject(configText); + if (fileConfig != null && !string.IsNullOrEmpty(fileConfig.api_key)) + { + return fileConfig; + } + return null; + } + var decryptedConfigJson = LootLocker.Utilities.Encryption.LootLockerEncryptionUtilities.SimpleDecryptFromBase64(encryptedBase64); + fileConfig = LootLockerJson.DeserializeObject(decryptedConfigJson); + if (fileConfig != null && !string.IsNullOrEmpty(fileConfig.api_key)) + { + return fileConfig; + } + } + else + { + } + } + catch (Exception ex) + { + LootLockerLogger.Log("Error while checking for file config: " + ex.Message, LootLockerLogger.LogLevel.Error); + return fileConfig; + } + return fileConfig; + } + + private static void CreateConfigFile() + { + // Create a new Config + LootLockerConfig newConfig = ScriptableObject.CreateInstance(); + + // If directory does not exist, create it + if (!Directory.Exists(ConfigResourceFolder)) + { + try + { + Directory.CreateDirectory(ConfigResourceFolder); + } + catch (Exception ex) + { + LootLockerLogger.Log($"Failed to create config directory at path '{ConfigResourceFolder}'. Config asset will not be created. Exception: {ex}", LootLockerLogger.LogLevel.Error); + return; + } + } + + // Create config asset + AssetDatabase.CreateAsset(newConfig, ConfigAssetsPath); + EditorApplication.delayCall += AssetDatabase.SaveAssets; + AssetDatabase.Refresh(); + _current = newConfig; } private void CheckForSettingOverrides() @@ -185,9 +323,8 @@ private static bool IsSemverString(string str) #if UNITY_EDITOR [InitializeOnLoadMethod] - static void CreateConfigFile() + static void InitializeOnLoad() { - // Get the path to the project directory string projectPath = Application.dataPath; @@ -201,15 +338,17 @@ static void CreateConfigFile() Get(); EditorPrefs.SetBool(configFileEditorPref, true); } + + StoreSDKVersion(); } protected static ListRequest ListInstalledPackagesRequest; - [InitializeOnLoadMethod] static void StoreSDKVersion() { - if ((!string.IsNullOrEmpty(LootLockerConfig.current.sdk_version) && - !LootLockerConfig.current.sdk_version.Equals("N/A")) || ListInstalledPackagesRequest != null) + if ((!string.IsNullOrEmpty(LootLockerConfig.current.sdk_version) && !LootLockerConfig.current.sdk_version.Equals("N/A")) + || ListInstalledPackagesRequest != null + || File.Exists(ConfigFilePath) /*Configured through config file, read sdk version there*/) { return; } @@ -234,7 +373,7 @@ static void ListInstalledPackagesRequestProgress() if (package.name.Equals("com.lootlocker.lootlockersdk")) { LootLockerConfig.current.sdk_version = package.version; - LootLockerLogger.Log($"LootLocker Version v{LootLockerConfig.current.sdk_version}", LootLockerLogger.LogLevel.Verbose); + LootLockerLogger.Log($"SDK Version v{LootLockerConfig.current.sdk_version}", LootLockerLogger.LogLevel.Verbose); return; } } @@ -242,7 +381,7 @@ static void ListInstalledPackagesRequestProgress() if (File.Exists("Assets/LootLockerSDK/package.json")) { LootLockerConfig.current.sdk_version = LootLockerJson.DeserializeObject(File.ReadAllText("Assets/LootLockerSDK/package.json")).version; - LootLockerLogger.Log($"LootLocker Version v{LootLockerConfig.current.sdk_version}", LootLockerLogger.LogLevel.Verbose); + LootLockerLogger.Log($"SDK Version v{LootLockerConfig.current.sdk_version}", LootLockerLogger.LogLevel.Verbose); return; } @@ -255,7 +394,7 @@ static void ListInstalledPackagesRequestProgress() if (!string.IsNullOrEmpty(packageDescription.name) && packageDescription.name.Equals("com.lootlocker.lootlockersdk")) { LootLockerConfig.current.sdk_version = packageDescription.version; - LootLockerLogger.Log($"LootLocker Version v{LootLockerConfig.current.sdk_version}", LootLockerLogger.LogLevel.Verbose); + LootLockerLogger.Log($"SDK Version v{LootLockerConfig.current.sdk_version}", LootLockerLogger.LogLevel.Verbose); return; } } @@ -404,13 +543,7 @@ public static LootLockerConfig current } public (string key, string value) dateVersion = ("LL-Version", "2021-03-01"); - public string apiKey; -#if UNITY_EDITOR - [HideInInspector] public string adminToken = null; -#endif - [HideInInspector] public string domainKey; - public string game_version = "1.0.0.0"; - [HideInInspector] public string sdk_version = ""; + [HideInInspector] private static readonly string UrlProtocol = "https://"; [HideInInspector] private static readonly string WssProtocol = "wss://"; [HideInInspector] private static readonly string UrlCore = "api.lootlocker.com"; @@ -442,24 +575,6 @@ public static bool IsTargetingProductionEnvironment() [HideInInspector] public string webSocketBaseUrl = WssProtocol + GetUrlCore() + UserUrlAppendage; [HideInInspector] public string baseUrl = UrlProtocol + GetUrlCore(); [HideInInspector] public float clientSideRequestTimeOut = 180f; - public LootLockerLogger.LogLevel logLevel = LootLockerLogger.LogLevel.Info; - // Write JSON in a pretty and indented format when logging - public bool prettifyJson = true; - [HideInInspector] public bool obfuscateLogs = true; - public bool logErrorsAsWarnings = false; - public bool logInBuilds = false; - public bool allowTokenRefresh = true; - [Tooltip("Enable WebSocket presence system by default. Can be controlled at runtime via SetPresenceEnabled().")] - public bool enablePresence = false; - - [Tooltip("Automatically connect presence when sessions are started. Can be controlled at runtime via SetPresenceAutoConnectEnabled().")] - public bool enablePresenceAutoConnect = true; - - [Tooltip("Automatically disconnect presence when app loses focus or is paused (useful for battery saving). Can be controlled at runtime via SetPresenceAutoDisconnectOnFocusChangeEnabled().")] - public bool enablePresenceAutoDisconnectOnFocusChange = false; - - [Tooltip("Enable presence functionality while in the Unity Editor. Disable this if you don't want development to affect presence data.")] - public bool enablePresenceInEditor = true; #if UNITY_EDITOR [InitializeOnEnterPlayMode] @@ -468,5 +583,6 @@ static void OnEnterPlaymodeInEditor(EnterPlayModeOptions options) _current = null; } #endif +#endregion } } \ No newline at end of file diff --git a/Runtime/Game/Resources/LootLockerExternalFileConfig.cs b/Runtime/Game/Resources/LootLockerExternalFileConfig.cs new file mode 100644 index 000000000..ad91eaa7e --- /dev/null +++ b/Runtime/Game/Resources/LootLockerExternalFileConfig.cs @@ -0,0 +1,23 @@ +using System; + +namespace LootLocker +{ +[Serializable] +public class ExternalFileConfig +{ + public string api_key { get; set; } + public string domain_key { get; set; } + public string game_version { get; set; } + public bool enable_presence { get; set; } + public bool enable_presence_autoconnect { get; set; } + public bool enable_presence_autodisconnect_on_focus_change { get; set; } + public bool enable_presence_in_editor { get; set; } + public string sdk_version { get; set; } + public LootLockerLogger.LogLevel log_level { get; set; } + public bool log_errors_as_warnings { get; set; } + public bool log_in_builds { get; set; } + public bool prettify_json { get; set; } + public bool obfuscate_logs { get; set; } + public bool allow_token_refresh { get; set; } +} +} \ No newline at end of file diff --git a/Runtime/Game/Resources/LootLockerExternalFileConfig.cs.meta b/Runtime/Game/Resources/LootLockerExternalFileConfig.cs.meta new file mode 100644 index 000000000..c38cb9395 --- /dev/null +++ b/Runtime/Game/Resources/LootLockerExternalFileConfig.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 75077bd522d25be449e229716a47ba94 \ No newline at end of file diff --git a/Runtime/Game/Utilities/LootLockerEncryptionUtilities.cs b/Runtime/Game/Utilities/LootLockerEncryptionUtilities.cs new file mode 100644 index 000000000..f0ffe5a2f --- /dev/null +++ b/Runtime/Game/Utilities/LootLockerEncryptionUtilities.cs @@ -0,0 +1,74 @@ +using System.Security.Cryptography; +using System.Linq; +using System.IO; + +namespace LootLocker.Utilities.Encryption +{ + public class LootLockerEncryptionUtilities + { + // We are satisfied with a hardcoded key for this simple encryption, as it's not meant to be highly secure, just obfuscate data. + private static readonly byte[] Key = { + 0x81, 0x71, 0xF7, 0xD6, 0xE5, 0xC4, 0xB3, 0xA2, + 0x8A, 0x9B, 0xAC, 0xBD, 0xCE, 0xDF, 0xE0, 0xF1 + }; + + public static string SimpleEncryptToBase64(string message) + { + using (Aes aes = Aes.Create()) + { + aes.Key = Key; + byte[] iv = aes.IV; + using (MemoryStream ms = new()) + { + using (CryptoStream cryptoStream = new(ms, aes.CreateEncryptor(), CryptoStreamMode.Write)) + { + using (StreamWriter writer = new(cryptoStream)) + { + writer.Write(message); + } + } + byte[] encryptedBytes = ms.ToArray(); + string encryptedBase64 = System.Convert.ToBase64String(iv.Concat(encryptedBytes).ToArray()); + return encryptedBase64; + } + } + } + + public static string SimpleDecryptFromBase64(string base64Message) + { + byte[] fullCipher = System.Convert.FromBase64String(base64Message); + using (Aes aes = Aes.Create()) + { + aes.Key = Key; + byte[] iv = fullCipher.Take(aes.BlockSize / 8).ToArray(); + byte[] cipherText = fullCipher.Skip(aes.BlockSize / 8).ToArray(); + using (MemoryStream ms = new(cipherText)) + { + using (CryptoStream cryptoStream = new(ms, aes.CreateDecryptor(Key, iv), CryptoStreamMode.Read)) + { + using (StreamReader reader = new(cryptoStream)) + { + return reader.ReadToEnd(); + } + } + } + } + } + + public static bool IsValidBase64String(string base64String) + { + if (string.IsNullOrEmpty(base64String)) + return false; + + try + { + System.Convert.FromBase64String(base64String); + return true; + } + catch (System.FormatException) + { + return false; + } + } + } +} \ No newline at end of file diff --git a/Runtime/Game/Utilities/LootLockerEncryptionUtilities.cs.meta b/Runtime/Game/Utilities/LootLockerEncryptionUtilities.cs.meta new file mode 100644 index 000000000..39d8b5e89 --- /dev/null +++ b/Runtime/Game/Utilities/LootLockerEncryptionUtilities.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 90909f2fcce79e14dac14d282a909506 \ No newline at end of file