Add example Unity Project

This commit is contained in:
Michał Gdula 2023-04-26 01:55:33 +01:00
parent fda7ff28dd
commit e3acdb9d6b
7122 changed files with 505543 additions and 2 deletions

View file

@ -0,0 +1,31 @@
namespace UnityEngine.Timeline
{
/// <summary>
/// Interface implemented by markers.
/// </summary>
/// <remarks>
/// A marker is a point in time.
/// </remarks>
/// <seealso cref="UnityEngine.Timeline.Marker"/>
public interface IMarker
{
/// <summary>
/// The time set for the marker, in seconds.
/// </summary>
double time { get; set; }
/// <summary>
/// The track that contains the marker.
/// </summary>
TrackAsset parent { get; }
/// <summary>
/// This method is called when the marker is initialized.
/// </summary>
/// <param name="parent">The track that contains the marker.</param>
/// <remarks>
/// This method is called after each deserialization of the Timeline Asset.
/// </remarks>
void Initialize(TrackAsset parent);
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4cb169caa67eddf4d83b39fd0917a945
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,15 @@
namespace UnityEngine.Timeline
{
/// <summary>
/// Implement this interface to change the behaviour of an INotification.
/// </summary>
/// This interface must be implemented along with <see cref="UnityEngine.Playables.INotification"/> to modify the default behaviour of a notification.
/// <seealso cref="UnityEngine.Timeline.NotificationFlags"/>
public interface INotificationOptionProvider
{
/// <summary>
/// The flags that change the triggering behaviour.
/// </summary>
NotificationFlags flags { get; }
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 5082cb99a8f99b84d84dd8b4c5233a9e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,53 @@
using System;
namespace UnityEngine.Timeline
{
/// <summary>
/// Use Marker as a base class when creating a custom marker.
/// </summary>
/// <remarks>
/// A marker is a point in time.
/// </remarks>
public abstract class Marker : ScriptableObject, IMarker
{
[SerializeField, TimeField, Tooltip("Time for the marker")] double m_Time;
/// <inheritdoc/>
public TrackAsset parent { get; private set; }
/// <inheritdoc/>
/// <remarks>
/// The marker time cannot be negative.
/// </remarks>
public double time
{
get { return m_Time; }
set { m_Time = Math.Max(value, 0); }
}
void IMarker.Initialize(TrackAsset parentTrack)
{
// We only really want to update the parent when the object is first deserialized
// If not a cloned track would "steal" the source's markers
if (parent == null)
{
parent = parentTrack;
try
{
OnInitialize(parentTrack);
}
catch (Exception e)
{
Debug.LogError(e.Message, this);
}
}
}
/// <summary>
/// Override this method to receive a callback when the marker is initialized.
/// </summary>
public virtual void OnInitialize(TrackAsset aPent)
{
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 89b48a03f6f43e94e87cc8d2104d3d4d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,168 @@
using System;
using System.Collections.Generic;
using UnityEngine.Playables;
namespace UnityEngine.Timeline
{
[Serializable]
struct MarkerList : ISerializationCallbackReceiver
{
[SerializeField, HideInInspector] List<ScriptableObject> m_Objects;
[HideInInspector, NonSerialized] List<IMarker> m_Cache;
bool m_CacheDirty;
bool m_HasNotifications;
public List<IMarker> markers
{
get
{
BuildCache();
return m_Cache;
}
}
public MarkerList(int capacity)
{
m_Objects = new List<ScriptableObject>(capacity);
m_Cache = new List<IMarker>(capacity);
m_CacheDirty = true;
m_HasNotifications = false;
}
public void Add(ScriptableObject item)
{
if (item == null)
return;
m_Objects.Add(item);
m_CacheDirty = true;
}
public bool Remove(IMarker item)
{
if (!(item is ScriptableObject))
throw new InvalidOperationException("Supplied type must be a ScriptableObject");
return Remove((ScriptableObject)item, item.parent.timelineAsset, item.parent);
}
public bool Remove(ScriptableObject item, TimelineAsset timelineAsset, PlayableAsset thingToDirty)
{
if (!m_Objects.Contains(item)) return false;
TimelineUndo.PushUndo(thingToDirty, "Delete Marker");
m_Objects.Remove(item);
m_CacheDirty = true;
TimelineUndo.PushDestroyUndo(timelineAsset, thingToDirty, item, "Delete Marker");
return true;
}
public void Clear()
{
m_Objects.Clear();
m_CacheDirty = true;
}
public bool Contains(ScriptableObject item)
{
return m_Objects.Contains(item);
}
public IEnumerable<IMarker> GetMarkers()
{
return markers;
}
public int Count
{
get { return markers.Count; }
}
public IMarker this[int idx]
{
get
{
return markers[idx];
}
}
public List<ScriptableObject> GetRawMarkerList()
{
return m_Objects;
}
public IMarker CreateMarker(Type type, double time, TrackAsset owner)
{
if (!typeof(ScriptableObject).IsAssignableFrom(type) || !typeof(IMarker).IsAssignableFrom(type))
{
throw new InvalidOperationException(
"The requested type needs to inherit from ScriptableObject and implement IMarker");
}
if (!owner.supportsNotifications && typeof(INotification).IsAssignableFrom(type))
{
throw new InvalidOperationException(
"Markers implementing the INotification interface cannot be added on tracks that do not support notifications");
}
var markerSO = ScriptableObject.CreateInstance(type);
var marker = (IMarker)markerSO;
marker.time = time;
TimelineCreateUtilities.SaveAssetIntoObject(markerSO, owner);
TimelineUndo.RegisterCreatedObjectUndo(markerSO, "Create " + type.Name);
TimelineUndo.PushUndo(owner, "Create " + type.Name);
Add(markerSO);
marker.Initialize(owner);
return marker;
}
public bool HasNotifications()
{
BuildCache();
return m_HasNotifications;
}
void ISerializationCallbackReceiver.OnBeforeSerialize()
{
}
void ISerializationCallbackReceiver.OnAfterDeserialize()
{
#if UNITY_EDITOR
for (int i = m_Objects.Count - 1; i >= 0; i--)
{
object o = m_Objects[i];
if (o == null)
{
Debug.LogWarning("Empty marker found while loading timeline. It will be removed.");
m_Objects.RemoveAt(i);
}
}
#endif
m_CacheDirty = true;
}
void BuildCache()
{
if (m_CacheDirty)
{
m_Cache = new List<IMarker>(m_Objects.Count);
m_HasNotifications = false;
foreach (var o in m_Objects)
{
if (o != null)
{
m_Cache.Add(o as IMarker);
if (o is INotification)
{
m_HasNotifications = true;
}
}
}
m_CacheDirty = false;
}
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4335a164bb763104c8805212c23d795f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using UnityEngine.Playables;
namespace UnityEngine.Timeline
{
/// <inheritdoc />
/// <summary>
/// Use this track to add Markers bound to a GameObject.
/// </summary>
[Serializable]
[TrackBindingType(typeof(GameObject))]
[HideInMenu]
[ExcludeFromPreset]
public class MarkerTrack : TrackAsset
{
/// <inheritdoc/>
public override IEnumerable<PlayableBinding> outputs
{
get
{
return this == timelineAsset.markerTrack ?
new List<PlayableBinding> {ScriptPlayableBinding.Create(name, null, typeof(GameObject))} :
base.outputs;
}
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2a16748d9461eae46a725db9776d5390
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,19 @@
using System;
namespace UnityEngine.Timeline
{
/// <summary>
/// Use this track to emit signals to a bound SignalReceiver.
/// </summary>
/// <remarks>
/// This track cannot contain clips.
/// </remarks>
/// <seealso cref="UnityEngine.Timeline.SignalEmitter"/>
/// <seealso cref="UnityEngine.Timeline.SignalReceiver"/>
/// <seealso cref="UnityEngine.Timeline.SignalAsset"/>
[Serializable]
[TrackBindingType(typeof(SignalReceiver))]
[TrackColor(0.25f, 0.25f, 0.25f)]
[ExcludeFromPreset]
public class SignalTrack : MarkerTrack {}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b46e36075dd1c124a8422c228e75e1fb
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 5b00473355622524394628f7ec51808d
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,5 @@
namespace UnityEngine.Timeline
{
//used to tell Signal Handler inspector to use a special drawer for UnityEvent
class CustomSignalEventDrawer : PropertyAttribute {}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a7ebd1239373d5f41af65ef32d67f445
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,22 @@
using System;
using UnityEngine;
namespace UnityEngine.Timeline
{
/// <summary>
/// An asset representing an emitted signal. A SignalAsset connects a SignalEmitter with a SignalReceiver.
/// </summary>
/// <seealso cref="UnityEngine.Timeline.SignalEmitter"/>
/// <seealso cref="UnityEngine.Timeline.SignalReceiver"/>
[AssetFileNameExtension("signal")]
public class SignalAsset : ScriptableObject
{
internal static event Action<SignalAsset> OnEnableCallback;
void OnEnable()
{
if (OnEnableCallback != null)
OnEnableCallback(this);
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d6fa2d92fc1b3f34da284357edf89c3b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,72 @@
using System;
using UnityEngine;
using UnityEngine.Playables;
namespace UnityEngine.Timeline
{
/// <inheritdoc cref="UnityEngine.Timeline.IMarker" />
/// <summary>
/// Marker that emits a signal to a SignalReceiver.
/// </summary>
/// A SignalEmitter emits a notification through the playable system. A SignalEmitter is used with a SignalReceiver and a SignalAsset.
/// <seealso cref="UnityEngine.Timeline.SignalAsset"/>
/// <seealso cref="UnityEngine.Timeline.SignalReceiver"/>
[Serializable]
[CustomStyle("SignalEmitter")]
[ExcludeFromPreset]
public class SignalEmitter : Marker, INotification, INotificationOptionProvider
{
[SerializeField] bool m_Retroactive;
[SerializeField] bool m_EmitOnce;
[SerializeField] SignalAsset m_Asset;
/// <summary>
/// Use retroactive to emit the signal if playback starts after the SignalEmitter time.
/// </summary>
public bool retroactive
{
get { return m_Retroactive; }
set { m_Retroactive = value; }
}
/// <summary>
/// Use emitOnce to emit this signal once during loops.
/// </summary>
public bool emitOnce
{
get { return m_EmitOnce; }
set { m_EmitOnce = value; }
}
/// <summary>
/// Asset representing the signal being emitted.
/// </summary>
public SignalAsset asset
{
get { return m_Asset; }
set { m_Asset = value; }
}
PropertyName INotification.id
{
get
{
if (m_Asset != null)
{
return new PropertyName(m_Asset.name);
}
return new PropertyName(string.Empty);
}
}
NotificationFlags INotificationOptionProvider.flags
{
get
{
return (retroactive ? NotificationFlags.Retroactive : default(NotificationFlags)) |
(emitOnce ? NotificationFlags.TriggerOnce : default(NotificationFlags)) |
NotificationFlags.TriggerInEditMode;
}
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 15c38f6fa1940124db1ab7f6fe7268d1
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,248 @@
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.Playables;
namespace UnityEngine.Timeline
{
/// <summary>
/// Listens for emitted signals and reacts depending on its defined reactions.
/// </summary>
/// A SignalReceiver contains a list of reactions. Each reaction is bound to a SignalAsset.
/// When a SignalEmitter emits a signal, the SignalReceiver invokes the corresponding reaction.
/// <seealso cref="UnityEngine.Timeline.SignalEmitter"/>
/// <seealso cref="UnityEngine.Timeline.SignalAsset"/>
public class SignalReceiver : MonoBehaviour, INotificationReceiver
{
[SerializeField]
EventKeyValue m_Events = new EventKeyValue();
/// <summary>
/// Called when a notification is sent.
/// </summary>
public void OnNotify(Playable origin, INotification notification, object context)
{
var signal = notification as SignalEmitter;
if (signal != null && signal.asset != null)
{
UnityEvent evt;
if (m_Events.TryGetValue(signal.asset, out evt) && evt != null)
{
evt.Invoke();
}
}
}
/// <summary>
/// Defines a new reaction for a SignalAsset.
/// </summary>
/// <param name="asset">The SignalAsset for which the reaction is being defined.</param>
/// <param name="reaction">The UnityEvent that describes the reaction.</param>
/// <exception cref="ArgumentNullException">Thrown when the asset is null.</exception>
/// <exception cref="ArgumentException">Thrown when the SignalAsset is already registered with this receiver.</exception>
public void AddReaction(SignalAsset asset, UnityEvent reaction)
{
if (asset == null)
throw new ArgumentNullException("asset");
if (m_Events.signals.Contains(asset))
throw new ArgumentException("SignalAsset already used.");
m_Events.Append(asset, reaction);
}
/// <summary>
/// Appends a null SignalAsset with a reaction specified by the UnityEvent.
/// </summary>
/// <param name="reaction">The new reaction to be appended.</param>
/// <returns>The index of the appended reaction.</returns>
/// <remarks>Multiple null assets are valid.</remarks>
public int AddEmptyReaction(UnityEvent reaction)
{
m_Events.Append(null, reaction);
return m_Events.events.Count - 1;
}
/// <summary>
/// Removes the first occurrence of a SignalAsset.
/// </summary>
/// <param name="asset">The SignalAsset to be removed.</param>
public void Remove(SignalAsset asset)
{
if (!m_Events.signals.Contains(asset))
{
throw new ArgumentException("The SignalAsset is not registered with this receiver.");
}
m_Events.Remove(asset);
}
/// <summary>
/// Gets a list of all registered SignalAssets.
/// </summary>
/// <returns>Returns a list of SignalAssets.</returns>
public IEnumerable<SignalAsset> GetRegisteredSignals()
{
return m_Events.signals;
}
/// <summary>
/// Gets the first UnityEvent associated with a SignalAsset.
/// </summary>
/// <param name="key">A SignalAsset defining the signal.</param>
/// <returns>Returns the reaction associated with a SignalAsset. Returns null if the signal asset does not exist.</returns>
public UnityEvent GetReaction(SignalAsset key)
{
UnityEvent ret;
if (m_Events.TryGetValue(key, out ret))
{
return ret;
}
return null;
}
/// <summary>
/// Returns the count of registered SignalAssets.
/// </summary>
/// <returns></returns>
public int Count()
{
return m_Events.signals.Count;
}
/// <summary>
/// Replaces the SignalAsset associated with a reaction at a specific index.
/// </summary>
/// <param name="idx">The index of the reaction.</param>
/// <param name="newKey">The replacement SignalAsset.</param>
/// <exception cref="ArgumentException">Thrown when the replacement SignalAsset is already registered to this SignalReceiver.</exception>
/// <remarks>The new SignalAsset can be null.</remarks>
public void ChangeSignalAtIndex(int idx, SignalAsset newKey)
{
if (idx < 0 || idx > m_Events.signals.Count - 1)
throw new IndexOutOfRangeException();
if (m_Events.signals[idx] == newKey)
return;
var alreadyUsed = m_Events.signals.Contains(newKey);
if (newKey == null || m_Events.signals[idx] == null || !alreadyUsed)
m_Events.signals[idx] = newKey;
if (newKey != null && alreadyUsed)
throw new ArgumentException("SignalAsset already used.");
}
/// <summary>
/// Removes the SignalAsset and reaction at a specific index.
/// </summary>
/// <param name="idx">The index of the SignalAsset to be removed.</param>
public void RemoveAtIndex(int idx)
{
if (idx < 0 || idx > m_Events.signals.Count - 1)
throw new IndexOutOfRangeException();
m_Events.Remove(idx);
}
/// <summary>
/// Replaces the reaction at a specific index with a new UnityEvent.
/// </summary>
/// <param name="idx">The index of the reaction to be replaced.</param>
/// <param name="reaction">The replacement reaction.</param>
/// <exception cref="ArgumentNullException">Thrown when the replacement reaction is null.</exception>
public void ChangeReactionAtIndex(int idx, UnityEvent reaction)
{
if (idx < 0 || idx > m_Events.events.Count - 1)
throw new IndexOutOfRangeException();
m_Events.events[idx] = reaction;
}
/// <summary>
/// Gets the reaction at a specific index.
/// </summary>
/// <param name="idx">The index of the reaction.</param>
/// <returns>Returns a reaction.</returns>
public UnityEvent GetReactionAtIndex(int idx)
{
if (idx < 0 || idx > m_Events.events.Count - 1)
throw new IndexOutOfRangeException();
return m_Events.events[idx];
}
/// <summary>
/// Gets the SignalAsset at a specific index
/// </summary>
/// <param name="idx">The index of the SignalAsset.</param>
/// <returns>Returns a SignalAsset.</returns>
public SignalAsset GetSignalAssetAtIndex(int idx)
{
if (idx < 0 || idx > m_Events.signals.Count - 1)
throw new IndexOutOfRangeException();
return m_Events.signals[idx];
}
// Required by Unity for the MonoBehaviour to have an enabled state
private void OnEnable()
{
}
[Serializable]
class EventKeyValue
{
[SerializeField]
List<SignalAsset> m_Signals = new List<SignalAsset>();
[SerializeField, CustomSignalEventDrawer]
List<UnityEvent> m_Events = new List<UnityEvent>();
public bool TryGetValue(SignalAsset key, out UnityEvent value)
{
var index = m_Signals.IndexOf(key);
if (index != -1)
{
value = m_Events[index];
return true;
}
value = null;
return false;
}
public void Append(SignalAsset key, UnityEvent value)
{
m_Signals.Add(key);
m_Events.Add(value);
}
public void Remove(int idx)
{
if (idx != -1)
{
m_Signals.RemoveAt(idx);
m_Events.RemoveAt(idx);
}
}
public void Remove(SignalAsset key)
{
var idx = m_Signals.IndexOf(key);
if (idx != -1)
{
m_Signals.RemoveAt(idx);
m_Events.RemoveAt(idx);
}
}
public List<SignalAsset> signals
{
get { return m_Signals; }
}
public List<UnityEvent> events
{
get { return m_Events; }
}
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e52de21a22b6dd44c9cc19f810c65059
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: