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

Release/v1.0.3 #30

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
1,714 changes: 1,714 additions & 0 deletions Assets/VIRTUOSO/Examples/EventBusScene.unity

Large diffs are not rendered by default.

7 changes: 7 additions & 0 deletions Assets/VIRTUOSO/Examples/EventBusScene.unity.meta

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

62 changes: 62 additions & 0 deletions Assets/VIRTUOSO/Scripts/Editor/Editors/EventBusEndpointEditor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEditorInternal;
using UnityEngine;

namespace CharlesRiverAnalytics.Virtuoso.Events
{
/// <summary>
/// Styles the EventBusEndpoint component to use a reorderable list for the reaction list.
///
/// TODO Make the hierarchy and event inputs become dropdown menus instead of strings
///
/// Written by: Nicolas Herrera (nherrera@cra.com), Apr 2020
/// </summary>
[CustomEditor(typeof(EventBusEndpoint))]
public class EventBusEndpointEditor : Editor
{
private SerializedProperty hierarchyString;
private SerializedProperty eventString;
private SerializedProperty reactionList;
private ReorderableList reorderableReactionList;

void OnEnable()
{
hierarchyString = serializedObject.FindProperty("hierarchyString");
eventString = serializedObject.FindProperty("eventString");
reactionList = serializedObject.FindProperty("reactionList");

reorderableReactionList = new ReorderableList(serializedObject, reactionList, true, true, true, true);

// Customize the reorderable list
reorderableReactionList.elementHeight = EditorGUIUtility.singleLineHeight * 2.5f;

reorderableReactionList.drawHeaderCallback = (Rect rect) =>
{
EditorGUI.LabelField(rect, "Reaction List");
};

reorderableReactionList.drawElementCallback = (Rect rect, int index, bool isActive, bool isFocused) =>
{
var element = reorderableReactionList.serializedProperty.GetArrayElementAtIndex(index);

EditorGUI.PropertyField(new Rect(rect.x, rect.y, rect.width / 2, EditorGUIUtility.singleLineHeight), element.FindPropertyRelative("reaction"), GUIContent.none);

EditorGUI.PropertyField(new Rect(rect.x + rect.width / 2, rect.y, rect.width / 2, EditorGUIUtility.singleLineHeight), element.FindPropertyRelative("fireMethod"), GUIContent.none);
};
}

public override void OnInspectorGUI()
{
serializedObject.Update();

hierarchyString.stringValue = EditorGUILayout.TextField("Hierarchy", hierarchyString.stringValue);
eventString.stringValue = EditorGUILayout.TextField("Event", eventString.stringValue);

reorderableReactionList.DoLayoutList();

serializedObject.ApplyModifiedProperties();
}
}
}

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

14 changes: 0 additions & 14 deletions Assets/VIRTUOSO/Scripts/Editor/Editors/ReactorEditor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -92,20 +92,6 @@ public override void OnInspectorGUI()

Component eventSenderComponent = eventSender.objectReferenceValue as Component;

// Get the list of all reactions in the scene to display in a list
GenericReaction[] reactionsInScene = FindObjectsOfType<GenericReaction>();

// Check to make sure there is at least 1 reaction in scene
if (reactionsInScene.Length == 0)
{
EditorGUILayout.HelpBox(NO_REACTION_WARNING_MESSAGE, MessageType.Error);

serializedObject.ApplyModifiedProperties();

// Since there are no reactions, don't processing the rest
return;
}

// See if the dictionary needs to be updated with new events
if (eventSenderComponent != null && eventSenderComponent != lastUsedComponent.objectReferenceValue)
{
Expand Down

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

132 changes: 132 additions & 0 deletions Assets/VIRTUOSO/Scripts/Events/EventBus/EventBus.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using CharlesRiverAnalytics.Virtuoso.Utilities;
using System.Text.RegularExpressions;

namespace CharlesRiverAnalytics.Virtuoso.Events
{
/// <summary>
/// The singleton class that manages the mapping between all the EventBus endpoints.
///
/// Written by: Nicolas Herrera (nherrera@cra.com), Apr 2020
/// </summary>
public class EventBus : Singleton<EventBus>
{
#region ProtectedVariables

protected Dictionary<ObjectEventMapping, HashSet<EventBusEndpoint>> endPointsWaitingOnEvents;
protected Tree<string> hierarchyTree = new Tree<string>("/");

#endregion

#region PrivateVariables

private Regex alphaNumericCharactersOnly = new Regex("^[a-zA-Z0-9 ]*$");

#endregion

protected struct ObjectEventMapping
{
public string hierarchyString;
public string eventString;
}

#region PublicAPI

public void ForwardEvent(string eventName, EventBusHierarchy eventObjectHierarchy, object sender, EventArgs args)
{
// Since the eventObjectHierarchy is a tree structure, we must check every combination of the built hierarchy
foreach(string currentHierarchyString in eventObjectHierarchy.GetHierarchyCombination())
{
ObjectEventMapping checkKey;
checkKey.hierarchyString = currentHierarchyString;
checkKey.eventString = eventName;

if (endPointsWaitingOnEvents.ContainsKey(checkKey))
{
foreach (EventBusEndpoint endpoint in endPointsWaitingOnEvents[checkKey])
{
endpoint.FireReactions(sender, args);
}
}
}
}

public void SubscribeToEvent(EventBusEndpoint endpoint, string hierarchyString, string eventString)
{
ObjectEventMapping newKey;
newKey.hierarchyString = hierarchyString;
newKey.eventString = eventString;

// The object/event pairing already exists, add the endpoint to the hashset for it
if (endPointsWaitingOnEvents.ContainsKey(newKey))
{
endPointsWaitingOnEvents[newKey].Add(endpoint);
}
// The object/event pairing is new, add to the dictionary and create a hashset with this endpoint to start
else
{
endPointsWaitingOnEvents[newKey] = new HashSet<EventBusEndpoint>() { endpoint };
}
}

public void UnsubscribeToEvent(EventBusEndpoint endpoint, string hierarchyString, string eventString)
{
ObjectEventMapping newKey;
newKey.hierarchyString = hierarchyString;
newKey.eventString = eventString;

// Can only unsubscribe from known object/event pairings with known endpoints
if (endPointsWaitingOnEvents.ContainsKey(newKey) &&
endPointsWaitingOnEvents[newKey].Contains(endpoint))
{
endPointsWaitingOnEvents[newKey].Remove(endpoint);
}
}

public void AddKnownObject(EventBusHierarchy hierarchyValue)
{
var splitHierarchy = hierarchyValue.GetSplitHierarchy();

Tree<string> currentNode;

for (int i = 0; i < splitHierarchy.Length; i++)
{
currentNode = hierarchyTree.InChildNode(splitHierarchy[i]);

// The node doesn't exist, so it needs to be added
if (currentNode == null)
{
// Only allow alphanumeric characters to define the hierarchy
if (alphaNumericCharactersOnly.IsMatch(splitHierarchy[i]))
{
currentNode = hierarchyTree.AddChild(splitHierarchy[i]);
}
}
// Else, it already exists, vist the children nodes in the next loop for the next hierarchy string
}
}

[ContextMenu("Print Tree")]
public void PrintTree()
{
hierarchyTree.Traverse((x) =>
{
Debug.Log(x);
});
}

#endregion

#region UnityFunctions

protected void Awake()
{
endPointsWaitingOnEvents = new Dictionary<ObjectEventMapping, HashSet<EventBusEndpoint>>();
}

#endregion
}
}
11 changes: 11 additions & 0 deletions Assets/VIRTUOSO/Scripts/Events/EventBus/EventBus.cs.meta

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

68 changes: 68 additions & 0 deletions Assets/VIRTUOSO/Scripts/Events/EventBus/EventBusEndpoint.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
using CharlesRiverAnalytics.Virtuoso.Reaction;
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace CharlesRiverAnalytics.Virtuoso.Events
{
/// <summary>
/// The component that holds the logic between the object that needs to be fired, the event to fire
/// the reaction on, and the list of reactions to be fired.
///
/// Written by: Nicolas Herrera (nherrera@cra.com), Apr 2020
/// </summary>
public class EventBusEndpoint : MonoBehaviour
{
#region PublicVariables

public string hierarchyString;
public string eventString;
public List<ReactionFireInfo> reactionList;

#endregion

#region PublicAPI

public void FireReactions(object sender, EventArgs eventArgs)
{
if(isActiveAndEnabled)
{
for(int i = 0; i < reactionList.Count; i++)
{
if(reactionList[i].fireMethod == Utilities.Constants.ReactionFireMethods.StartReaction)
{
reactionList[i].reaction.StartReaction(sender, eventArgs);
}
else
{
reactionList[i].reaction.StopReaction(sender, eventArgs);
}
}
}
}

#endregion

#region UnityFunctions

protected void OnEnable()
{
EventBus.Instance.SubscribeToEvent(this, hierarchyString, eventString);
}

protected void OnDisable()
{
EventBus.Instance?.UnsubscribeToEvent(this, hierarchyString, eventString);
}

#endregion
}

[Serializable]
public struct ReactionFireInfo
{
public GenericReaction reaction;
public Utilities.Constants.ReactionFireMethods fireMethod;
}
}

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