From 10e0fc23b7a45fe35a6034c1747baa4e7e8b3671 Mon Sep 17 00:00:00 2001 From: calderarchinuk Date: Wed, 11 Dec 2024 17:23:59 -0800 Subject: [PATCH 1/6] initial tuning variable support --- Runtime/Components/TuningVariables.cs | 171 ++++++++++++++++++ Runtime/Components/TuningVariables.cs.meta | 11 ++ Runtime/Internal/CognitiveStatics.cs | 6 + Runtime/Internal/ILocalTuningVariables.cs | 58 ++++++ .../Internal/ILocalTuningVariables.cs.meta | 11 ++ Runtime/Internal/NetworkManager.cs | 93 +++++++++- Runtime/Scripts/Cognitive3D_Manager.cs | 12 +- 7 files changed, 358 insertions(+), 4 deletions(-) create mode 100644 Runtime/Components/TuningVariables.cs create mode 100644 Runtime/Components/TuningVariables.cs.meta create mode 100644 Runtime/Internal/ILocalTuningVariables.cs create mode 100644 Runtime/Internal/ILocalTuningVariables.cs.meta diff --git a/Runtime/Components/TuningVariables.cs b/Runtime/Components/TuningVariables.cs new file mode 100644 index 00000000..ffc45dae --- /dev/null +++ b/Runtime/Components/TuningVariables.cs @@ -0,0 +1,171 @@ +using UnityEngine; +using System.Collections; +using System.Collections.Generic; +using UnityEngine.XR; + +/// +/// gets variables from the cognitive3d backend to configure your app +/// + +//TODO debug startup flow +//TODO delay for some amount of time - if no participantId set, it should fetch using deviceId + +//set session properties DONE +//static generic funciton to get values DONE +//locally cache in network class DONE +//read from local cache if it fails DONE + +namespace Cognitive3D.Components +{ + #region Json + [System.Serializable] + internal class TuningVariableItem + { + public string name; + public string description; + public string type; + public int valueInt; + public string valueString; + public bool valueBool; + + public override string ToString() + { + if (type == "string") + { + return string.Format("name:{0}, description:{1}, type:{2}, value:{3}", name, description, type,valueString); + } + if (type == "int") + { + return string.Format("name:{0}, description:{1}, type:{2}, value:{3}", name, description, type,valueInt); + } + if (type == "bool") + { + return string.Format("name:{0}, description:{1}, type:{2}, value:{3}", name, description, type,valueBool); + } + + return string.Format("name:{0}, description:{1}, type:{2}", name, description, type); + } + } + + internal class TuningVariableCollection + { + public List tuningVariables = new List(); + } + #endregion + + [DisallowMultipleComponent] + [AddComponentMenu("Cognitive3D/Components/Tuning Variables")] + public class TuningVariables : AnalyticsComponentBase + { + bool hasFetchedVariables; + public float timeout = 3; + + static Dictionary tuningVariables = new Dictionary(); + + public delegate void onTuninVariablesAvailable(); + /// + /// Called after tuning variables are available (also called after a delay if no response) + /// + public static event onTuninVariablesAvailable OnTuninVariablesAvailable; + private static void InvokeOnTuninVariablesAvailable() { if (OnTuninVariablesAvailable != null) { OnTuninVariablesAvailable.Invoke(); } } + + protected override void OnSessionBegin() + { + base.OnSessionBegin(); + Cognitive3D_Manager.OnParticipantIdSet += Cognitive3D_Manager_OnParticipantIdSet; + Cognitive3D_Manager.OnPostSessionEnd += Cognitive3D_Manager_OnPostSessionEnd; + } + + private void Cognitive3D_Manager_OnParticipantIdSet(string participantId) + { + FetchVariables(participantId); + } + + void FetchVariables(string participantId) + { + NetworkManager.GetTuningVariables(participantId, TuningVariableResponse, timeout); + } + + void TuningVariableResponse(int responsecode, string error, string text) + { + if (hasFetchedVariables) + { + Util.logDevelopment("TuningVariableResponse called multiple times!"); + return; + } + + Util.logDevelopment("Tuning Variable reponse code " + responsecode); + try + { + var tvc = JsonUtility.FromJson(text); + if (tvc == null) + { + tuningVariables.Clear(); + foreach (var entry in tvc.tuningVariables) + { + tuningVariables.Add(entry.name, entry); + + if (entry.type == "string") + { + Cognitive3D_Manager.SetSessionProperty(entry.name, entry.valueString); + } + else if (entry.type == "int") + { + Cognitive3D_Manager.SetSessionProperty(entry.name, entry.valueInt); + } + else if (entry.type == "bool") + { + Cognitive3D_Manager.SetSessionProperty(entry.name, entry.valueBool); + } + } + } + } + catch (System.Exception e) + { + Debug.LogException(e); + } + + hasFetchedVariables = true; + InvokeOnTuninVariablesAvailable(); + } + + //bool onboardingType2 = TuningVariables.GetValue(variableName: "onboarding_type", defaultValue: false); + public static T GetValue(string variableName, T defaultValue) + { + TuningVariableItem returnItem; + if (tuningVariables.TryGetValue(variableName,out returnItem)) + { + if (typeof(T) == typeof(string)) + { + return (T)(object)returnItem.valueString; + } + if (typeof(T) == typeof(bool)) + { + return (T)(object)returnItem.valueBool; + } + if (typeof(T) == typeof(int) || typeof(T) == typeof(long) || typeof(T) == typeof(float) || typeof(T) == typeof(double)) + { + return (T)(object)returnItem.valueInt; + } + } + return defaultValue; + } + + private void Cognitive3D_Manager_OnPostSessionEnd() + { + hasFetchedVariables = false; + Cognitive3D_Manager.OnParticipantIdSet -= Cognitive3D_Manager_OnParticipantIdSet; + Cognitive3D_Manager.OnPostSessionEnd -= Cognitive3D_Manager_OnPostSessionEnd; + } + + public override string GetDescription() + { + return "Retrieves variables from the Cognitive3D server to adjust the user's experience"; + } + + public override bool GetWarning() + { + return false; + } + } +} diff --git a/Runtime/Components/TuningVariables.cs.meta b/Runtime/Components/TuningVariables.cs.meta new file mode 100644 index 00000000..977549f9 --- /dev/null +++ b/Runtime/Components/TuningVariables.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c2813dd9237bf1c4ead0e6276a28ed1e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Internal/CognitiveStatics.cs b/Runtime/Internal/CognitiveStatics.cs index d3e8a27e..220a68a5 100644 --- a/Runtime/Internal/CognitiveStatics.cs +++ b/Runtime/Internal/CognitiveStatics.cs @@ -143,6 +143,12 @@ internal static string PostExitpollResponses(string questionsetname, int questio return string.Concat(Cognitive3D_Preferences.Instance.Protocol, "://", Cognitive3D_Preferences.Instance.Gateway, "/v", version,"/questionSets/", questionsetname, "/",questionsetversion.ToString(), "/responses"); } + //GET request question set + internal static string GetTuningVariableURL(string userId) + { + return string.Concat(Cognitive3D_Preferences.Instance.Protocol, "://", Cognitive3D_Preferences.Instance.Gateway, "/v", version, "/tuningvariables?identifier=", userId); + } + /// /// Creates the GET request endpoint with access token and search parameters /// diff --git a/Runtime/Internal/ILocalTuningVariables.cs b/Runtime/Internal/ILocalTuningVariables.cs new file mode 100644 index 00000000..ce01d14e --- /dev/null +++ b/Runtime/Internal/ILocalTuningVariables.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.IO; +using UnityEngine; + +namespace Cognitive3D +{ + internal interface ILocalTuningVariables + { + bool GetTuningVariables(out string text); + void WriteTuningVariables(string text); + } + + internal class TuningVariablesLocalDataHandler : ILocalTuningVariables + { + string localTuningVariablePath; + + public TuningVariablesLocalDataHandler(string path) + { + localTuningVariablePath = path; + } + + public bool GetTuningVariables(out string text) + { + try + { + if (File.Exists(localTuningVariablePath + "tuningVariables")) + { + text = File.ReadAllText(localTuningVariablePath + "tuningVariables"); + return true; + } + } + catch (Exception e) + { + Debug.LogException(e); + } + text = ""; + return false; + } + + public void WriteTuningVariables(string text) + { + if (!Directory.Exists(localTuningVariablePath)) + Directory.CreateDirectory(localTuningVariablePath); + + try + { + File.WriteAllText(localTuningVariablePath + "tuningVariables", text); + } + catch (Exception e) + { + Debug.LogException(e); + } + } + } +} diff --git a/Runtime/Internal/ILocalTuningVariables.cs.meta b/Runtime/Internal/ILocalTuningVariables.cs.meta new file mode 100644 index 00000000..3252f983 --- /dev/null +++ b/Runtime/Internal/ILocalTuningVariables.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 26f7878bbdb61b34d833431294758211 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Internal/NetworkManager.cs b/Runtime/Internal/NetworkManager.cs index bd75ec6f..f05a99a4 100644 --- a/Runtime/Internal/NetworkManager.cs +++ b/Runtime/Internal/NetworkManager.cs @@ -29,19 +29,17 @@ internal class NetworkManager : MonoBehaviour static HashSet activeRequests = new HashSet(); internal ICache runtimeCache; - internal ILocalExitpoll exitpollCache; int lastDataResponse = 0; const float cacheUploadInterval = 2; const float minRetryDelay = 60; const float maxRetryDelay = 240; - internal void Initialize(ICache runtimeCache, ILocalExitpoll exitpollCache) + internal void Initialize(ICache runtimeCache) { DontDestroyOnLoad(gameObject); instance = this; this.runtimeCache = runtimeCache; - this.exitpollCache = exitpollCache; } System.Collections.IEnumerator WaitForExitpollResponse(UnityWebRequest www, string hookname, Response callback, float timeout) @@ -502,6 +500,95 @@ private float GetExponentialBackoff(float retryDelay) return minRetryDelay; } + public static void GetTuningVariables(string participantId, Response callback, float timeout) + { + string url = CognitiveStatics.GetTuningVariableURL(participantId); + var request = UnityWebRequest.Get(url); + request.SetRequestHeader("Content-Type", "application/json"); + request.SetRequestHeader("X-HTTP-Method-Override", "GET"); + request.SetRequestHeader("Authorization", CognitiveStatics.ApplicationKey); + request.SendWebRequest(); + + instance.StartCoroutine(instance.WaitForTuningVariableResponse(request, callback, timeout)); + } + + System.Collections.IEnumerator WaitForTuningVariableResponse(UnityWebRequest www, Response callback, float timeout) + { + float time = 0; + while (time < timeout) + { + yield return null; + if (www.isDone) break; + time += Time.deltaTime; + } + + var headers = www.GetResponseHeaders(); + int responsecode = (int)www.responseCode; + lastDataResponse = responsecode; + //check cvr header to make sure not blocked by capture portal + +#if UNITY_WEBGL + //webgl cors issue doesn't seem to accept this required header + if (!headers.ContainsKey("cvr-request-time")) + { + headers.Add("cvr-request-time", string.Empty); + } +#endif + + if (!www.isDone) + Util.logWarning("Network::WaitForTuningVariableResponse timeout"); + if (responsecode != 200) + Util.logWarning("Network::WaitForTuningVariableResponse responsecode is " + responsecode); + + if (headers != null) + { + if (!headers.ContainsKey("cvr-request-time")) + Util.logWarning("Network::WaitForTuningVariableResponse does not contain cvr-request-time header"); + } + + if (!www.isDone || responsecode != 200 || (headers != null && !headers.ContainsKey("cvr-request-time"))) + { + if (Cognitive3D_Preferences.Instance.LocalStorage) + { + string text; + if (Cognitive3D_Manager.TuningVariableHandler.GetTuningVariables(out text)) + { + if (callback != null) + { + callback.Invoke(responsecode, "", text); + } + } + else + { + if (callback != null) + { + callback.Invoke(responsecode, "", ""); + } + } + } + else + { + if (callback != null) + { + callback.Invoke(responsecode, "", ""); + } + } + } + else + { + if (callback != null) + { + callback.Invoke(responsecode, www.error, www.downloadHandler.text); + } + if (Cognitive3D_Preferences.Instance.LocalStorage) + { + Cognitive3D_Manager.TuningVariableHandler.WriteTuningVariables(www.downloadHandler.text); + } + } + www.Dispose(); + activeRequests.Remove(www); + } + //skip network cleanup if immediately/manually destroyed //gameobject is destroyed at end of frame //issue if ending session/destroy gameobject/new session all in one frame diff --git a/Runtime/Scripts/Cognitive3D_Manager.cs b/Runtime/Scripts/Cognitive3D_Manager.cs index 4b7fbc79..8304a4d2 100644 --- a/Runtime/Scripts/Cognitive3D_Manager.cs +++ b/Runtime/Scripts/Cognitive3D_Manager.cs @@ -156,6 +156,7 @@ public void BeginSession() #endif ExitpollHandler = new ExitPollLocalDataHandler(Application.persistentDataPath + "/c3dlocal/exitpoll/"); + TuningVariableHandler = new TuningVariablesLocalDataHandler(Application.persistentDataPath + "/c3dlocal/tuningvariables/"); if (Cognitive3D_Preferences.Instance.LocalStorage) { @@ -172,7 +173,7 @@ public void BeginSession() GameObject networkGo = new GameObject("Cognitive Network"); networkGo.hideFlags = HideFlags.HideInInspector | HideFlags.HideInHierarchy; NetworkManager = networkGo.AddComponent(); - NetworkManager.Initialize(DataCache, ExitpollHandler); + NetworkManager.Initialize(DataCache); GameplayReferences.Initialize(); DynamicManager.Initialize(); @@ -832,7 +833,15 @@ public static void FlushData() public static event onLevelLoaded OnLevelLoaded; private static void InvokeLevelLoadedEvent(Scene scene, LoadSceneMode mode, bool newSceneId) { if (OnLevelLoaded != null) { OnLevelLoaded(scene, mode, newSceneId); } } + public delegate void onParticipantIdSet(string participantId); + /// + /// Called after a participant id is set. May be called multiple times + /// + public static event onParticipantIdSet OnParticipantIdSet; + private static void InvokeOnParticipantIdSet(string participantId) { if (OnParticipantIdSet != null) { OnParticipantIdSet.Invoke(participantId); } } + internal static ILocalExitpoll ExitpollHandler; + internal static ILocalTuningVariables TuningVariableHandler; internal static ICache DataCache; internal static NetworkManager NetworkManager; @@ -992,6 +1001,7 @@ public static void SetParticipantId(string id) } ParticipantId = id; SetParticipantProperty("id", id); + InvokeOnParticipantIdSet(id); } /// From f17547994be05c95b31228d8387b0f4c7a50f5cd Mon Sep 17 00:00:00 2001 From: calderarchinuk Date: Wed, 11 Dec 2024 18:46:20 -0800 Subject: [PATCH 2/6] simplified tuning variable startup flow --- Runtime/Components/TuningVariables.cs | 95 ++++++++++++++++++++++----- 1 file changed, 79 insertions(+), 16 deletions(-) diff --git a/Runtime/Components/TuningVariables.cs b/Runtime/Components/TuningVariables.cs index ffc45dae..636a5196 100644 --- a/Runtime/Components/TuningVariables.cs +++ b/Runtime/Components/TuningVariables.cs @@ -7,8 +7,12 @@ /// gets variables from the cognitive3d backend to configure your app /// -//TODO debug startup flow -//TODO delay for some amount of time - if no participantId set, it should fetch using deviceId +//fetches the variables immediately if the participantId is already set at session start +//if not, it will wait 5 seconds for a participantId to be set +//if the timer elapses, use the deviceId as the argument +//if fetchVariablesAutomatically is false, call Cognitive3D.TuningVariables.FetchVariables + +//CONSIDER custom editor to display tuning variables //set session properties DONE //static generic funciton to get values DONE @@ -19,7 +23,7 @@ namespace Cognitive3D.Components { #region Json [System.Serializable] - internal class TuningVariableItem + public class TuningVariableItem { public string name; public string description; @@ -57,23 +61,51 @@ internal class TuningVariableCollection [AddComponentMenu("Cognitive3D/Components/Tuning Variables")] public class TuningVariables : AnalyticsComponentBase { - bool hasFetchedVariables; - public float timeout = 3; + static bool hasFetchedVariables; + const float requestTimeoutSeconds = 3; + const float maximumAutomaticDelay = 5; + + + public bool fetchVariablesAutomatically = true; static Dictionary tuningVariables = new Dictionary(); - public delegate void onTuninVariablesAvailable(); + public delegate void onTuningVariablesAvailable(); /// /// Called after tuning variables are available (also called after a delay if no response) /// - public static event onTuninVariablesAvailable OnTuninVariablesAvailable; - private static void InvokeOnTuninVariablesAvailable() { if (OnTuninVariablesAvailable != null) { OnTuninVariablesAvailable.Invoke(); } } + public static event onTuningVariablesAvailable OnTuningVariablesAvailable; + private static void InvokeOnTuningVariablesAvailable() { if (OnTuningVariablesAvailable != null) { OnTuningVariablesAvailable.Invoke(); } } protected override void OnSessionBegin() { base.OnSessionBegin(); - Cognitive3D_Manager.OnParticipantIdSet += Cognitive3D_Manager_OnParticipantIdSet; Cognitive3D_Manager.OnPostSessionEnd += Cognitive3D_Manager_OnPostSessionEnd; + + if (fetchVariablesAutomatically) + { + //get variables if participant id is already set + if (!string.IsNullOrEmpty(Cognitive3D_Manager.ParticipantId)) + { + FetchVariables(Cognitive3D_Manager.ParticipantId); + } + else + { + //listen for event + Cognitive3D_Manager.OnParticipantIdSet += Cognitive3D_Manager_OnParticipantIdSet; + //also start a timer + StartCoroutine(DelayFetch()); + } + } + } + + IEnumerator DelayFetch() + { + yield return new WaitForSeconds(maximumAutomaticDelay); + if (!hasFetchedVariables) + { + FetchVariables(Cognitive3D_Manager.DeviceId); + } } private void Cognitive3D_Manager_OnParticipantIdSet(string participantId) @@ -81,12 +113,17 @@ private void Cognitive3D_Manager_OnParticipantIdSet(string participantId) FetchVariables(participantId); } - void FetchVariables(string participantId) + public static void FetchVariables() { - NetworkManager.GetTuningVariables(participantId, TuningVariableResponse, timeout); + NetworkManager.GetTuningVariables(Cognitive3D_Manager.DeviceId, TuningVariableResponse, requestTimeoutSeconds); } - void TuningVariableResponse(int responsecode, string error, string text) + public static void FetchVariables(string participantId) + { + NetworkManager.GetTuningVariables(participantId, TuningVariableResponse, requestTimeoutSeconds); + } + + static void TuningVariableResponse(int responsecode, string error, string text) { if (hasFetchedVariables) { @@ -98,7 +135,7 @@ void TuningVariableResponse(int responsecode, string error, string text) try { var tvc = JsonUtility.FromJson(text); - if (tvc == null) + if (tvc != null) { tuningVariables.Clear(); foreach (var entry in tvc.tuningVariables) @@ -113,12 +150,16 @@ void TuningVariableResponse(int responsecode, string error, string text) { Cognitive3D_Manager.SetSessionProperty(entry.name, entry.valueInt); } - else if (entry.type == "bool") + else if (entry.type == "boolean") { Cognitive3D_Manager.SetSessionProperty(entry.name, entry.valueBool); } } } + else + { + Util.logDevelopment("TuningVariableCollection is null"); + } } catch (System.Exception e) { @@ -126,10 +167,16 @@ void TuningVariableResponse(int responsecode, string error, string text) } hasFetchedVariables = true; - InvokeOnTuninVariablesAvailable(); + InvokeOnTuningVariablesAvailable(); } - //bool onboardingType2 = TuningVariables.GetValue(variableName: "onboarding_type", defaultValue: false); + /// + /// + /// + /// + /// + /// + /// public static T GetValue(string variableName, T defaultValue) { TuningVariableItem returnItem; @@ -151,6 +198,11 @@ public static T GetValue(string variableName, T defaultValue) return defaultValue; } + public static Dictionary GetAllTuningVariables() + { + return tuningVariables; + } + private void Cognitive3D_Manager_OnPostSessionEnd() { hasFetchedVariables = false; @@ -167,5 +219,16 @@ public override bool GetWarning() { return false; } + + [ContextMenu("Test Fetch with DeviceId")] + void TestFetch() + { + FetchVariables(Cognitive3D_Manager.DeviceId); + } + [ContextMenu("Test Fetch with Random GUID")] + void TestFetchGUID() + { + FetchVariables(System.Guid.NewGuid().ToString()); + } } } From 0ef59b99c4021ce93c4d0c3ab859783941883c4d Mon Sep 17 00:00:00 2001 From: calderarchinuk Date: Fri, 13 Dec 2024 00:11:27 -0800 Subject: [PATCH 3/6] renamed component moved static functions to new class added check before re-requesting tuning variables --- ...riables.cs => TuningVariablesComponent.cs} | 136 ++++++++++-------- ....meta => TuningVariablesComponent.cs.meta} | 0 2 files changed, 77 insertions(+), 59 deletions(-) rename Runtime/Components/{TuningVariables.cs => TuningVariablesComponent.cs} (75%) rename Runtime/Components/{TuningVariables.cs.meta => TuningVariablesComponent.cs.meta} (100%) diff --git a/Runtime/Components/TuningVariables.cs b/Runtime/Components/TuningVariablesComponent.cs similarity index 75% rename from Runtime/Components/TuningVariables.cs rename to Runtime/Components/TuningVariablesComponent.cs index 636a5196..f8272334 100644 --- a/Runtime/Components/TuningVariables.cs +++ b/Runtime/Components/TuningVariablesComponent.cs @@ -1,7 +1,6 @@ using UnityEngine; using System.Collections; using System.Collections.Generic; -using UnityEngine.XR; /// /// gets variables from the cognitive3d backend to configure your app @@ -19,9 +18,62 @@ //locally cache in network class DONE //read from local cache if it fails DONE -namespace Cognitive3D.Components +namespace Cognitive3D { - #region Json + public static class TuningVariables + { + static Dictionary tuningVariables = new Dictionary(); + + public delegate void onTuningVariablesAvailable(); + /// + /// Called after tuning variables are available (also called after a delay if no response) + /// + public static event onTuningVariablesAvailable OnTuningVariablesAvailable; + internal static void InvokeOnTuningVariablesAvailable() { if (OnTuningVariablesAvailable != null) { OnTuningVariablesAvailable.Invoke(); } } + + internal static void Reset() + { + tuningVariables.Clear(); + } + internal static void SetVariable(TuningVariableItem entry) + { + tuningVariables.Add(entry.name, entry); + } + + /// + /// Returns a variable of a type using the variableName. Returns the default value if no variable is found + /// + /// The expected type of variable + /// The name of the variable to read + /// The value to return if no variable is found + /// The value of the tuning varible, or the defaultValue if not found + public static T GetValue(string variableName, T defaultValue) + { + Cognitive3D.TuningVariableItem returnItem; + if (tuningVariables.TryGetValue(variableName, out returnItem)) + { + if (typeof(T) == typeof(string)) + { + return (T)(object)returnItem.valueString; + } + if (typeof(T) == typeof(bool)) + { + return (T)(object)returnItem.valueBool; + } + if (typeof(T) == typeof(int) || typeof(T) == typeof(long) || typeof(T) == typeof(float) || typeof(T) == typeof(double)) + { + return (T)(object)returnItem.valueInt; + } + } + return defaultValue; + } + + public static Dictionary GetAllTuningVariables() + { + return tuningVariables; + } + } + [System.Serializable] public class TuningVariableItem { @@ -36,21 +88,26 @@ public override string ToString() { if (type == "string") { - return string.Format("name:{0}, description:{1}, type:{2}, value:{3}", name, description, type,valueString); + return string.Format("name:{0}, description:{1}, type:{2}, value:{3}", name, description, type, valueString); } if (type == "int") { - return string.Format("name:{0}, description:{1}, type:{2}, value:{3}", name, description, type,valueInt); + return string.Format("name:{0}, description:{1}, type:{2}, value:{3}", name, description, type, valueInt); } if (type == "bool") { - return string.Format("name:{0}, description:{1}, type:{2}, value:{3}", name, description, type,valueBool); + return string.Format("name:{0}, description:{1}, type:{2}, value:{3}", name, description, type, valueBool); } return string.Format("name:{0}, description:{1}, type:{2}", name, description, type); } } +} + +namespace Cognitive3D.Components +{ + #region Json internal class TuningVariableCollection { public List tuningVariables = new List(); @@ -58,8 +115,8 @@ internal class TuningVariableCollection #endregion [DisallowMultipleComponent] - [AddComponentMenu("Cognitive3D/Components/Tuning Variables")] - public class TuningVariables : AnalyticsComponentBase + [AddComponentMenu("Cognitive3D/Components/Tuning Variables Component")] + public class TuningVariablesComponent : AnalyticsComponentBase { static bool hasFetchedVariables; const float requestTimeoutSeconds = 3; @@ -68,15 +125,6 @@ public class TuningVariables : AnalyticsComponentBase public bool fetchVariablesAutomatically = true; - static Dictionary tuningVariables = new Dictionary(); - - public delegate void onTuningVariablesAvailable(); - /// - /// Called after tuning variables are available (also called after a delay if no response) - /// - public static event onTuningVariablesAvailable OnTuningVariablesAvailable; - private static void InvokeOnTuningVariablesAvailable() { if (OnTuningVariablesAvailable != null) { OnTuningVariablesAvailable.Invoke(); } } - protected override void OnSessionBegin() { base.OnSessionBegin(); @@ -102,10 +150,7 @@ protected override void OnSessionBegin() IEnumerator DelayFetch() { yield return new WaitForSeconds(maximumAutomaticDelay); - if (!hasFetchedVariables) - { - FetchVariables(Cognitive3D_Manager.DeviceId); - } + FetchVariables(Cognitive3D_Manager.DeviceId); } private void Cognitive3D_Manager_OnParticipantIdSet(string participantId) @@ -115,12 +160,18 @@ private void Cognitive3D_Manager_OnParticipantIdSet(string participantId) public static void FetchVariables() { - NetworkManager.GetTuningVariables(Cognitive3D_Manager.DeviceId, TuningVariableResponse, requestTimeoutSeconds); + if (!hasFetchedVariables) + { + NetworkManager.GetTuningVariables(Cognitive3D_Manager.DeviceId, TuningVariableResponse, requestTimeoutSeconds); + } } public static void FetchVariables(string participantId) { - NetworkManager.GetTuningVariables(participantId, TuningVariableResponse, requestTimeoutSeconds); + if (!hasFetchedVariables) + { + NetworkManager.GetTuningVariables(participantId, TuningVariableResponse, requestTimeoutSeconds); + } } static void TuningVariableResponse(int responsecode, string error, string text) @@ -137,10 +188,10 @@ static void TuningVariableResponse(int responsecode, string error, string text) var tvc = JsonUtility.FromJson(text); if (tvc != null) { - tuningVariables.Clear(); + TuningVariables.Reset(); foreach (var entry in tvc.tuningVariables) { - tuningVariables.Add(entry.name, entry); + TuningVariables.SetVariable(entry); if (entry.type == "string") { @@ -167,40 +218,7 @@ static void TuningVariableResponse(int responsecode, string error, string text) } hasFetchedVariables = true; - InvokeOnTuningVariablesAvailable(); - } - - /// - /// - /// - /// - /// - /// - /// - public static T GetValue(string variableName, T defaultValue) - { - TuningVariableItem returnItem; - if (tuningVariables.TryGetValue(variableName,out returnItem)) - { - if (typeof(T) == typeof(string)) - { - return (T)(object)returnItem.valueString; - } - if (typeof(T) == typeof(bool)) - { - return (T)(object)returnItem.valueBool; - } - if (typeof(T) == typeof(int) || typeof(T) == typeof(long) || typeof(T) == typeof(float) || typeof(T) == typeof(double)) - { - return (T)(object)returnItem.valueInt; - } - } - return defaultValue; - } - - public static Dictionary GetAllTuningVariables() - { - return tuningVariables; + TuningVariables.InvokeOnTuningVariablesAvailable(); } private void Cognitive3D_Manager_OnPostSessionEnd() diff --git a/Runtime/Components/TuningVariables.cs.meta b/Runtime/Components/TuningVariablesComponent.cs.meta similarity index 100% rename from Runtime/Components/TuningVariables.cs.meta rename to Runtime/Components/TuningVariablesComponent.cs.meta From 8aebc547afa09a819a4c17018280b19fa6bcead5 Mon Sep 17 00:00:00 2001 From: calderarchinuk Date: Fri, 13 Dec 2024 09:45:18 -0800 Subject: [PATCH 4/6] add option to use deviceid for tuning vars --- .../Components/TuningVariablesComponent.cs | 26 ++++++++++++------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/Runtime/Components/TuningVariablesComponent.cs b/Runtime/Components/TuningVariablesComponent.cs index f8272334..34ec9b3a 100644 --- a/Runtime/Components/TuningVariablesComponent.cs +++ b/Runtime/Components/TuningVariablesComponent.cs @@ -121,8 +121,7 @@ public class TuningVariablesComponent : AnalyticsComponentBase static bool hasFetchedVariables; const float requestTimeoutSeconds = 3; const float maximumAutomaticDelay = 5; - - + public bool useParticipantId = true; public bool fetchVariablesAutomatically = true; protected override void OnSessionBegin() @@ -132,17 +131,24 @@ protected override void OnSessionBegin() if (fetchVariablesAutomatically) { - //get variables if participant id is already set - if (!string.IsNullOrEmpty(Cognitive3D_Manager.ParticipantId)) + if (useParticipantId) { - FetchVariables(Cognitive3D_Manager.ParticipantId); + //get variables if participant id is already set + if (!string.IsNullOrEmpty(Cognitive3D_Manager.ParticipantId)) + { + FetchVariables(Cognitive3D_Manager.ParticipantId); + } + else + { + //listen for event + Cognitive3D_Manager.OnParticipantIdSet += Cognitive3D_Manager_OnParticipantIdSet; + //also start a timer + StartCoroutine(DelayFetch()); + } } - else + else //just use the hardware id to identify the user { - //listen for event - Cognitive3D_Manager.OnParticipantIdSet += Cognitive3D_Manager_OnParticipantIdSet; - //also start a timer - StartCoroutine(DelayFetch()); + FetchVariables(Cognitive3D_Manager.DeviceId); } } } From caecc318f5bbe6f6bb11bc8322ded392a1a01b2a Mon Sep 17 00:00:00 2001 From: calderarchinuk Date: Fri, 13 Dec 2024 09:59:04 -0800 Subject: [PATCH 5/6] exposed variables for configuring the component --- .../Components/TuningVariablesComponent.cs | 22 ++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/Runtime/Components/TuningVariablesComponent.cs b/Runtime/Components/TuningVariablesComponent.cs index 34ec9b3a..43d14009 100644 --- a/Runtime/Components/TuningVariablesComponent.cs +++ b/Runtime/Components/TuningVariablesComponent.cs @@ -119,9 +119,21 @@ internal class TuningVariableCollection public class TuningVariablesComponent : AnalyticsComponentBase { static bool hasFetchedVariables; - const float requestTimeoutSeconds = 3; - const float maximumAutomaticDelay = 5; + /// + /// the delay to hear a response from our backend. If there is no response in this time, try to use a local cache of variables + /// + const float requestTuningVariablesTimeout = 3; + /// + /// the delay waiting for participant id to be set (if not already set at the start of the session) + /// + public float waitForParticipantIdTimeout = 5; + /// + /// if true, uses the participant id (possibly with a delay) to get tuning variables. Otherwise, use the device id + /// public bool useParticipantId = true; + /// + /// if true, sends identifying data to retrieve variables as soon as possible + /// public bool fetchVariablesAutomatically = true; protected override void OnSessionBegin() @@ -155,7 +167,7 @@ protected override void OnSessionBegin() IEnumerator DelayFetch() { - yield return new WaitForSeconds(maximumAutomaticDelay); + yield return new WaitForSeconds(waitForParticipantIdTimeout); FetchVariables(Cognitive3D_Manager.DeviceId); } @@ -168,7 +180,7 @@ public static void FetchVariables() { if (!hasFetchedVariables) { - NetworkManager.GetTuningVariables(Cognitive3D_Manager.DeviceId, TuningVariableResponse, requestTimeoutSeconds); + NetworkManager.GetTuningVariables(Cognitive3D_Manager.DeviceId, TuningVariableResponse, requestTuningVariablesTimeout); } } @@ -176,7 +188,7 @@ public static void FetchVariables(string participantId) { if (!hasFetchedVariables) { - NetworkManager.GetTuningVariables(participantId, TuningVariableResponse, requestTimeoutSeconds); + NetworkManager.GetTuningVariables(participantId, TuningVariableResponse, requestTuningVariablesTimeout); } } From e6554c3b8341cc6bf96034b68e8697f9e5f01a5f Mon Sep 17 00:00:00 2001 From: calderarchinuk Date: Thu, 2 Jan 2025 11:14:02 -0800 Subject: [PATCH 6/6] minor fixes --- Runtime/Components/TuningVariablesComponent.cs | 6 +++++- Runtime/Internal/ILocalTuningVariables.cs | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Runtime/Components/TuningVariablesComponent.cs b/Runtime/Components/TuningVariablesComponent.cs index 43d14009..6ac6dac7 100644 --- a/Runtime/Components/TuningVariablesComponent.cs +++ b/Runtime/Components/TuningVariablesComponent.cs @@ -200,7 +200,11 @@ static void TuningVariableResponse(int responsecode, string error, string text) return; } - Util.logDevelopment("Tuning Variable reponse code " + responsecode); + if (responsecode != 200) + { + Util.logDevelopment("Tuning Variable reponse code " + responsecode + " " + error); + } + try { var tvc = JsonUtility.FromJson(text); diff --git a/Runtime/Internal/ILocalTuningVariables.cs b/Runtime/Internal/ILocalTuningVariables.cs index ce01d14e..dcb3380d 100644 --- a/Runtime/Internal/ILocalTuningVariables.cs +++ b/Runtime/Internal/ILocalTuningVariables.cs @@ -15,7 +15,7 @@ internal interface ILocalTuningVariables internal class TuningVariablesLocalDataHandler : ILocalTuningVariables { - string localTuningVariablePath; + readonly string localTuningVariablePath; public TuningVariablesLocalDataHandler(string path) {