// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. using Microsoft.MixedReality.Toolkit.Utilities; using Microsoft.MixedReality.Toolkit.Utilities.Editor; using System; using System.Collections.Generic; using System.Linq; using UnityEngine; using UnityEngine.Events; namespace Microsoft.MixedReality.Toolkit.UI { /// /// Event base class for events attached to Interactables. /// [System.Serializable] public class InteractableEvent { /// /// Base Event used to initialize EventReceiver class /// public UnityEvent Event = new UnityEvent(); /// /// ReceiverBase instantiation for this InteractableEvent. Used at runtime by Interactable class /// [NonSerialized] public ReceiverBase Receiver; /// /// Defines the type of Receiver to associate. Type must be a class that extends ReceiverBase /// public Type ReceiverType { get { if (receiverType == null) { if (string.IsNullOrEmpty(AssemblyQualifiedName)) { return null; } receiverType = Type.GetType(AssemblyQualifiedName); } return receiverType; } set { if (!value.IsSubclassOf(typeof(ReceiverBase))) { Debug.LogWarning($"Cannot assign type {value} that does not extend {typeof(ReceiverBase)} to ThemeDefinition"); return; } if (receiverType != value) { receiverType = value; ClassName = receiverType.Name; AssemblyQualifiedName = receiverType.AssemblyQualifiedName; } } } // Unity cannot serialize System.Type, thus must save AssemblyQualifiedName // Field here for Runtime use [NonSerialized] private Type receiverType; [SerializeField] private string ClassName; [SerializeField] private string AssemblyQualifiedName; [SerializeField] private List Settings = new List(); /// /// Create the event and setup the values from the inspector. If the asset is invalid, /// returns null. /// public static ReceiverBase CreateReceiver(InteractableEvent iEvent) { if (string.IsNullOrEmpty(iEvent.ClassName)) { // If the class name of this event is empty, the asset is invalid and loading types will throw errors. Return null. return null; } // Temporary workaround // This is to fix a bug in GA where the AssemblyQualifiedName was never actually saved. Functionality would work in editor...but never on device player if (iEvent.ReceiverType == null) { var correctType = TypeCacheUtility.GetSubClasses().Where(s => s?.Name == iEvent.ClassName).First(); iEvent.ReceiverType = correctType; } ReceiverBase newEvent = (ReceiverBase)Activator.CreateInstance(iEvent.ReceiverType, iEvent.Event); InspectorGenericFields.LoadSettings(newEvent, iEvent.Settings); return newEvent; } } }