Skip to content

Commit b250338

Browse files
Merge pull request #446 from Unity-Technologies/improvements/schoen/feedback-editor
Serialized Feedback Editor
2 parents f565754 + ea541af commit b250338

8 files changed

Lines changed: 351 additions & 137 deletions

Editor/ProxyFeedbackEditor.cs

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using UnityEditor.Experimental.EditorVR.Modules;
4+
using UnityEditor.Experimental.EditorVR.Proxies;
5+
using UnityEngine;
6+
7+
namespace UnityEditor.Experimental.EditorVR.UI
8+
{
9+
sealed class ProxyFeedbackEditor : EditorWindow
10+
{
11+
readonly Dictionary<Type, SerializedProxyFeedback> m_SerializedFeedback = new Dictionary<Type, SerializedProxyFeedback>();
12+
Vector2 m_Scroll;
13+
14+
[MenuItem("Edit/Project Settings/EditorXR/Proxy Feedback")]
15+
static void Init()
16+
{
17+
GetWindow<ProxyFeedbackEditor>("Proxy Feedback Editor").Show();
18+
}
19+
20+
void OnEnable()
21+
{
22+
Refresh();
23+
}
24+
25+
void OnGUI()
26+
{
27+
if (Event.current.Equals(Event.KeyboardEvent("^w")))
28+
{
29+
Close();
30+
GUIUtility.ExitGUI();
31+
}
32+
33+
if (GUILayout.Button("Reload Data"))
34+
Refresh();
35+
36+
if (GUILayout.Button("Clear Data"))
37+
{
38+
ClearData();
39+
Refresh();
40+
}
41+
42+
if (GUILayout.Button("Save Data"))
43+
{
44+
SaveData();
45+
Refresh();
46+
}
47+
48+
m_Scroll = GUILayout.BeginScrollView(m_Scroll);
49+
var hasFeedback = false;
50+
foreach (var kvp in m_SerializedFeedback)
51+
{
52+
GUILayout.Label(kvp.Key.Name, EditorStyles.boldLabel);
53+
DrawPreferences(kvp.Value);
54+
hasFeedback = true;
55+
}
56+
57+
if (!hasFeedback)
58+
GUILayout.Label("No serialized feedback");
59+
60+
GUILayout.EndScrollView();
61+
}
62+
63+
static void DrawPreferences(SerializedProxyFeedback feedback)
64+
{
65+
GUILayout.Label("Left Hand");
66+
DrawNode(feedback.leftNode);
67+
GUILayout.Label("Right Hand");
68+
DrawNode(feedback.rightNode);
69+
}
70+
71+
static void DrawNode(SerializedProxyNodeFeedback node)
72+
{
73+
var keys = node.keys;
74+
var values = node.values;
75+
for (var i = 0; i < keys.Length; i++)
76+
{
77+
var data = values[i];
78+
data.presentations = EditorGUILayout.IntField(keys[i].ToString(), data.presentations);
79+
}
80+
}
81+
82+
void Refresh()
83+
{
84+
m_SerializedFeedback.Clear();
85+
var preferences = SerializedPreferencesModule.DeserializePreferences(Core.EditorVR.serializedPreferences);
86+
if (preferences == null)
87+
return;
88+
89+
foreach (var kvp in preferences.items)
90+
{
91+
var type = kvp.Key;
92+
if (typeof(TwoHandedProxyBase).IsAssignableFrom(type))
93+
{
94+
var item = kvp.Value;
95+
Type payloadType = null;
96+
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
97+
{
98+
payloadType = assembly.GetType(item.payloadType);
99+
if (payloadType != null)
100+
break;
101+
}
102+
103+
if (payloadType == null)
104+
continue;
105+
106+
var payload = (SerializedProxyFeedback)JsonUtility.FromJson(item.payload, payloadType);
107+
m_SerializedFeedback[kvp.Key] = payload;
108+
}
109+
}
110+
}
111+
112+
static void ClearData()
113+
{
114+
var preferences = SerializedPreferencesModule.DeserializePreferences(Core.EditorVR.serializedPreferences);
115+
if (preferences == null)
116+
return;
117+
118+
foreach (var kvp in new Dictionary<Type, SerializedPreferencesModule.SerializedPreferenceItem>(preferences.items))
119+
{
120+
var type = kvp.Key;
121+
if (typeof(TwoHandedProxyBase).IsAssignableFrom(type))
122+
preferences.Remove(type);
123+
}
124+
125+
Core.EditorVR.serializedPreferences = JsonUtility.ToJson(preferences);
126+
}
127+
128+
void SaveData()
129+
{
130+
var preferences = SerializedPreferencesModule.DeserializePreferences(Core.EditorVR.serializedPreferences);
131+
if (preferences == null)
132+
return;
133+
134+
var items = preferences.items;
135+
foreach (var kvp in m_SerializedFeedback)
136+
{
137+
items[kvp.Key].payload = JsonUtility.ToJson(kvp.Value);
138+
}
139+
140+
Core.EditorVR.serializedPreferences = JsonUtility.ToJson(preferences);
141+
}
142+
}
143+
}

Editor/ProxyFeedbackEditor.cs.meta

Lines changed: 12 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Scripts/Core/EditorVR.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ static bool preserveLayout
5858
set { EditorPrefs.SetBool(k_PreserveLayout, value); }
5959
}
6060

61-
static string serializedPreferences
61+
internal static string serializedPreferences
6262
{
6363
get { return EditorPrefs.GetString(k_SerializedPreferences, string.Empty); }
6464
set { EditorPrefs.SetString(k_SerializedPreferences, value); }
@@ -279,7 +279,7 @@ IEnumerator Start()
279279
while (!viewer.hmdReady)
280280
yield return null;
281281

282-
GetModule<SerializedPreferencesModule>().DeserializePreferences(serializedPreferences);
282+
GetModule<SerializedPreferencesModule>().SetupWithPreferences(serializedPreferences);
283283
m_HasDeserialized = true;
284284
}
285285

Scripts/Modules/SerializedPreferencesModule.cs

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ sealed class SerializedPreferencesModule : MonoBehaviour
1313
SerializedPreferences m_Preferences;
1414

1515
[Serializable]
16-
class SerializedPreferences : ISerializationCallbackReceiver
16+
internal class SerializedPreferences : ISerializationCallbackReceiver
1717
{
1818
[SerializeField]
1919
SerializedPreferenceItem[] m_Items;
@@ -41,10 +41,16 @@ public void OnAfterDeserialize()
4141
}
4242
}
4343
}
44+
45+
public void Remove(Type type)
46+
{
47+
m_ItemDictionary.Remove(type);
48+
m_Items = m_ItemDictionary.Values.ToArray();
49+
}
4450
}
4551

4652
[Serializable]
47-
class SerializedPreferenceItem
53+
internal class SerializedPreferenceItem
4854
{
4955
[SerializeField]
5056
string m_Name;
@@ -75,7 +81,7 @@ public string payload
7581
public void AddSerializer(ISerializePreferences serializer)
7682
{
7783
if (m_Preferences != null)
78-
Deserialize(serializer);
84+
Deserialize(m_Preferences, serializer);
7985

8086
m_Serializers.Add(serializer);
8187
}
@@ -87,18 +93,23 @@ public void RemoveSerializer(ISerializePreferences serializer)
8793
m_Serializers.Remove(serializer);
8894
}
8995

90-
internal void DeserializePreferences(string serializedPreferences)
96+
internal void SetupWithPreferences(string serializedPreferences)
97+
{
98+
m_Preferences = DeserializePreferences(serializedPreferences, m_Serializers);
99+
}
100+
101+
internal static SerializedPreferences DeserializePreferences(string serializedPreferences, List<ISerializePreferences> serializers = null)
91102
{
92103
var preferences = JsonUtility.FromJson<SerializedPreferences>(serializedPreferences);
93-
if (preferences != null)
104+
if (preferences != null && serializers != null)
94105
{
95-
m_Preferences = preferences;
96-
97-
foreach (var serializer in m_Serializers)
106+
foreach (var serializer in serializers)
98107
{
99-
Deserialize(serializer);
108+
Deserialize(preferences, serializer);
100109
}
101110
}
111+
112+
return preferences;
102113
}
103114

104115
internal string SerializePreferences()
@@ -131,12 +142,16 @@ internal string SerializePreferences()
131142
return JsonUtility.ToJson(m_Preferences);
132143
}
133144

134-
void Deserialize(ISerializePreferences serializer)
145+
static void Deserialize(SerializedPreferences preferences, ISerializePreferences serializer)
135146
{
136147
SerializedPreferenceItem item;
137-
if (m_Preferences.items.TryGetValue(serializer.GetType(), out item))
148+
if (preferences.items.TryGetValue(serializer.GetType(), out item))
138149
{
139-
var payload = JsonUtility.FromJson(item.payload, Type.GetType(item.payloadType));
150+
var type = Type.GetType(item.payloadType);
151+
if (type == null)
152+
return;
153+
154+
var payload = JsonUtility.FromJson(item.payload, type);
140155
serializer.OnDeserializePreferences(payload);
141156
}
142157
}
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
#if UNITY_EDITOR
2+
using System;
3+
using UnityEngine;
4+
using UnityEngine.InputNew;
5+
6+
namespace UnityEditor.Experimental.EditorVR.Proxies
7+
{
8+
[Serializable]
9+
class SerializedProxyFeedback
10+
{
11+
public SerializedProxyNodeFeedback leftNode;
12+
public SerializedProxyNodeFeedback rightNode;
13+
}
14+
15+
/// <summary>
16+
/// Used as globally unique identifiers for feedback requests
17+
/// They are used to relate feedback requests to the persistent count of visible presentations used to suppress feedback
18+
/// </summary>
19+
[Serializable]
20+
class RequestKey
21+
{
22+
/// <summary>
23+
/// The control index used to identify the related affordance
24+
/// </summary>
25+
[SerializeField]
26+
VRInputDevice.VRControl m_Control;
27+
28+
/// <summary>
29+
/// The tooltip text that was presented
30+
/// </summary>
31+
[SerializeField]
32+
string m_TooltipText;
33+
34+
public void UpdateValues(ProxyFeedbackRequest request)
35+
{
36+
m_Control = request.control;
37+
m_TooltipText = request.tooltipText;
38+
}
39+
40+
public bool HasTooltip()
41+
{
42+
return !string.IsNullOrEmpty(m_TooltipText);
43+
}
44+
45+
public override int GetHashCode()
46+
{
47+
var hashCode = (int)m_Control;
48+
49+
if (m_TooltipText != null)
50+
hashCode ^= m_TooltipText.GetHashCode();
51+
52+
return hashCode;
53+
}
54+
55+
public override bool Equals(object obj)
56+
{
57+
if (obj == null)
58+
return false;
59+
60+
if (!(obj is RequestKey))
61+
return false;
62+
63+
var key = (RequestKey)obj;
64+
return m_Control == key.m_Control && string.Equals(m_TooltipText, key.m_TooltipText);
65+
}
66+
67+
public override string ToString()
68+
{
69+
return string.Format("{0}: {1}", m_Control, m_TooltipText);
70+
}
71+
}
72+
73+
/// <summary>
74+
/// Contains per-request persistent data
75+
/// </summary>
76+
[Serializable]
77+
class RequestData
78+
{
79+
[SerializeField]
80+
int m_Presentations;
81+
82+
readonly Action m_OnBecameVisible;
83+
84+
/// <summary>
85+
/// How many times the user viewed the presentation of this type of request
86+
/// </summary>
87+
public int presentations
88+
{
89+
get { return m_Presentations; }
90+
set { m_Presentations = value; }
91+
}
92+
93+
public bool visibleThisPresentation { get; set; }
94+
95+
public Action onBecameVisible
96+
{
97+
get { return m_OnBecameVisible; }
98+
}
99+
100+
public RequestData()
101+
{
102+
m_OnBecameVisible = OnBecameVisible;
103+
}
104+
105+
void OnBecameVisible()
106+
{
107+
if (!visibleThisPresentation)
108+
presentations++;
109+
110+
visibleThisPresentation = true;
111+
}
112+
}
113+
114+
/// <summary>
115+
/// Used to store persistent data about feedback requests
116+
/// </summary>
117+
[Serializable]
118+
class SerializedProxyNodeFeedback
119+
{
120+
public RequestKey[] keys;
121+
public RequestData[] values;
122+
}
123+
}
124+
#endif

Scripts/Proxies/Data/SerializedProxyFeedback.cs.meta

Lines changed: 13 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)