Skip to content

Instantly share code, notes, and snippets.

@V0odo0
Last active November 29, 2022 12:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save V0odo0/ad19a504c563f8dcbf054b8b328f805a to your computer and use it in GitHub Desktop.
Save V0odo0/ad19a504c563f8dcbf054b8b328f805a to your computer and use it in GitHub Desktop.
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.Playables;
using UnityEngine.Timeline;
using Object = UnityEngine.Object;
#if UNITY_EDITOR
using UnityEditor;
#endif
#if ODIN_INSPECTOR
using Sirenix.OdinInspector;
#endif
namespace VD3V.Utils
{
public class PlayableDirectorBindingsRestorer : MonoBehaviour
{
public PlayableDirector PlayableDirector =>
_playableDirector ?? (_playableDirector = GetComponent<PlayableDirector>());
[SerializeField] private PlayableDirector _playableDirector;
public List<Binding> Bindings => _bindings;
[SerializeField] private List<Binding> _bindings = new List<Binding>();
[SerializeField, HideInInspector] private TimelineAsset _sourceTimeLineAsset;
[ContextMenu("Save Bindings")]
#if ODIN_INSPECTOR
[Button(name: "Save Bindings", buttonSize: ButtonSizes.Large)]
#endif
public void SaveBindings()
{
#if UNITY_EDITOR
if (PlayableDirector == null)
return;
_bindings.Clear();
var timeline = PlayableDirector.playableAsset as TimelineAsset;
if (timeline == null)
return;
_sourceTimeLineAsset = timeline;
foreach (var o in timeline.outputs)
{
var srcObj = o.sourceObject;
var tarObj = PlayableDirector.GetGenericBinding(o.sourceObject);
_bindings.Add(new Binding(srcObj, GlobalObjectId.GetGlobalObjectIdSlow(tarObj), tarObj == null));
}
EditorUtility.SetDirty(this);
#endif
}
[ContextMenu("Restore Bindings")]
#if ODIN_INSPECTOR
[Button(name: "Restore Bindings", buttonSize: ButtonSizes.Large)]
#endif
public void RestoreBindings()
{
#if UNITY_EDITOR
if (PlayableDirector == null || _sourceTimeLineAsset == null)
return;
Undo.RegisterCompleteObjectUndo(this, "Load Bindings");
var timeline = PlayableDirector.playableAsset as TimelineAsset;
if (timeline == null)
return;
if (timeline != _sourceTimeLineAsset)
{
var oldOutputs = _sourceTimeLineAsset.outputs.ToArray();
var newOutputs = timeline.outputs.ToArray();
for (int i = 0; i < Mathf.Min(_bindings.Count, newOutputs.Length, oldOutputs.Length); i++)
{
if (_bindings[i].TargetObjectIsEmpty)
continue;
if (newOutputs[i].streamName != oldOutputs[i].streamName || newOutputs[i].outputTargetType != oldOutputs[i].outputTargetType)
continue;
var value = GlobalObjectId.GlobalObjectIdentifierToObjectSlow(_bindings[i].TargetObjectId);
if (value == null)
continue;
var key = newOutputs[i].sourceObject;
PlayableDirector.SetGenericBinding(key, value);
}
}
else
{
foreach (var b in _bindings)
{
var value = GlobalObjectId.GlobalObjectIdentifierToObjectSlow(b.TargetObjectId);
if (value == null)
continue;
var key = b.SourceObject;
PlayableDirector.SetGenericBinding(key, value);
}
}
EditorUtility.SetDirty(this);
#endif
}
[Serializable]
public class Binding
{
protected static GlobalObjectId EmptyObjectId;
public GlobalObjectId TargetObjectId
{
get => GlobalObjectId.TryParse(_globalObjectIdString, out var g) ? g : EmptyObjectId;
set => _globalObjectIdString = value.ToString();
}
public bool TargetObjectIsEmpty;
public Object SourceObject;
[SerializeField, HideInInspector] private string _globalObjectIdString;
public Binding() { }
public Binding(Object sourceObject, GlobalObjectId targetObjectId, bool isEmpty)
{
SourceObject = sourceObject;
TargetObjectId = targetObjectId;
TargetObjectIsEmpty = isEmpty;
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment