Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tuning Variable Component #216

Open
wants to merge 7 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
274 changes: 274 additions & 0 deletions Runtime/Components/TuningVariablesComponent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,274 @@
using UnityEngine;
using System.Collections;
using System.Collections.Generic;

/// <summary>
/// gets variables from the cognitive3d backend to configure your app
/// </summary>

//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
//locally cache in network class DONE
//read from local cache if it fails DONE

namespace Cognitive3D
{
public static class TuningVariables
{
static Dictionary<string, Cognitive3D.TuningVariableItem> tuningVariables = new Dictionary<string, Cognitive3D.TuningVariableItem>();

public delegate void onTuningVariablesAvailable();
/// <summary>
/// Called after tuning variables are available (also called after a delay if no response)
/// </summary>
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);
}

/// <summary>
/// Returns a variable of a type using the variableName. Returns the default value if no variable is found
/// </summary>
/// <typeparam name="T">The expected type of variable</typeparam>
/// <param name="variableName">The name of the variable to read</param>
/// <param name="defaultValue">The value to return if no variable is found</param>
/// <returns>The value of the tuning varible, or the defaultValue if not found</returns>
public static T GetValue<T>(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<string, Cognitive3D.TuningVariableItem> GetAllTuningVariables()
{
return tuningVariables;
}
}

[System.Serializable]
public 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);
}
}
}


namespace Cognitive3D.Components
{
#region Json
internal class TuningVariableCollection
{
public List<TuningVariableItem> tuningVariables = new List<TuningVariableItem>();
}
#endregion

[DisallowMultipleComponent]
[AddComponentMenu("Cognitive3D/Components/Tuning Variables Component")]
public class TuningVariablesComponent : AnalyticsComponentBase
{
static bool hasFetchedVariables;
/// <summary>
/// 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
/// </summary>
const float requestTuningVariablesTimeout = 3;
/// <summary>
/// the delay waiting for participant id to be set (if not already set at the start of the session)
/// </summary>
public float waitForParticipantIdTimeout = 5;
/// <summary>
/// if true, uses the participant id (possibly with a delay) to get tuning variables. Otherwise, use the device id
/// </summary>
public bool useParticipantId = true;
/// <summary>
/// if true, sends identifying data to retrieve variables as soon as possible
/// </summary>
public bool fetchVariablesAutomatically = true;

protected override void OnSessionBegin()
{
base.OnSessionBegin();
Cognitive3D_Manager.OnPostSessionEnd += Cognitive3D_Manager_OnPostSessionEnd;

if (fetchVariablesAutomatically)
{
if (useParticipantId)
{
//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 //just use the hardware id to identify the user
{
FetchVariables(Cognitive3D_Manager.DeviceId);
}
}
}

IEnumerator DelayFetch()
{
yield return new WaitForSeconds(waitForParticipantIdTimeout);
FetchVariables(Cognitive3D_Manager.DeviceId);
}

private void Cognitive3D_Manager_OnParticipantIdSet(string participantId)
{
FetchVariables(participantId);
}

public static void FetchVariables()
{
if (!hasFetchedVariables)
{
NetworkManager.GetTuningVariables(Cognitive3D_Manager.DeviceId, TuningVariableResponse, requestTuningVariablesTimeout);
}
}

public static void FetchVariables(string participantId)
{
if (!hasFetchedVariables)
{
NetworkManager.GetTuningVariables(participantId, TuningVariableResponse, requestTuningVariablesTimeout);
}
}

static void TuningVariableResponse(int responsecode, string error, string text)
{
if (hasFetchedVariables)
{
Util.logDevelopment("TuningVariableResponse called multiple times!");
return;
}

if (responsecode != 200)
{
Util.logDevelopment("Tuning Variable reponse code " + responsecode + " " + error);
}

try
{
var tvc = JsonUtility.FromJson<TuningVariableCollection>(text);
if (tvc != null)
{
TuningVariables.Reset();
foreach (var entry in tvc.tuningVariables)
{
TuningVariables.SetVariable(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 == "boolean")
{
Cognitive3D_Manager.SetSessionProperty(entry.name, entry.valueBool);
}
}
}
else
{
Util.logDevelopment("TuningVariableCollection is null");
}
}
catch (System.Exception e)
{
Debug.LogException(e);
}

hasFetchedVariables = true;
TuningVariables.InvokeOnTuningVariablesAvailable();
}

private void Cognitive3D_Manager_OnPostSessionEnd()
{
hasFetchedVariables = false;

Check failure on line 248 in Runtime/Components/TuningVariablesComponent.cs

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

Runtime/Components/TuningVariablesComponent.cs#L248

Make the enclosing instance method 'static' or remove this set on the 'static' field.
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;
}

[ContextMenu("Test Fetch with DeviceId")]
void TestFetch()
{
FetchVariables(Cognitive3D_Manager.DeviceId);
}
[ContextMenu("Test Fetch with Random GUID")]
void TestFetchGUID()
{
FetchVariables(System.Guid.NewGuid().ToString());
}
}
}
11 changes: 11 additions & 0 deletions Runtime/Components/TuningVariablesComponent.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions Runtime/Internal/CognitiveStatics.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

/// <summary>
/// Creates the GET request endpoint with access token and search parameters
/// </summary>
Expand Down
58 changes: 58 additions & 0 deletions Runtime/Internal/ILocalTuningVariables.cs
Original file line number Diff line number Diff line change
@@ -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
{
readonly 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);
}
}
}
}
11 changes: 11 additions & 0 deletions Runtime/Internal/ILocalTuningVariables.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading