I am creating TimelineClips in code via TimelineTrack.CreateDefaultClip(). I’d like to set the extrapolation modes on those clips but I cannot do that, because the setters for those are internal.
It seems you can set it via the Inspector only because the corresponding private fields are marked with [SerializeField].
Is there any way to set theses values that’s not reflection?
if anyone needs it, here are some extension methods that will work with 2018.2 (tested in Editor and iOS):
/// <summary>
/// Private field name of <see cref="TimelineClip.postExtrapolationMode"/>
/// </summary>
private static readonly string POST_EXTRAP_MODE_INTERNAL_FIELD = "m_PostExtrapolationMode";
/// <summary>
/// Private field name of <see cref="TimelineClip.preExtrapolationMode"/>
/// </summary>
private static readonly string PRE_EXTRAP_MODE_INTERNAL_FIELD = "m_PreExtrapolationMode";
/// <summary>
/// Private field name of the "Animation Extrapolation" duration beyond the end of the clip
/// </summary>
private static readonly string POST_EXTRAP_TIME_INTERNAL_FIELD = "m_PostExtrapolationTime";
/// <summary>
/// Private field name of the "Animation Extrapolation" duration before the start of the clip
/// </summary>
private static readonly string PRE_EXTRAP_TIME_INTERNAL_FIELD = "m_PreExtrapolationTime";
/// <summary>
/// Sets the pre-extrapolation mode for a clip
/// (uses Unity 2018.2.0f2 internal methods that may break in future versions)
/// </summary>
/// <param name="clip">Clip to set the extrapolation for</param>
/// <param name="extrapolationMode">Extrapolation behaviour</param>
public static void SetPreExtrapolationMode(this TimelineClip clip, TimelineClip.ClipExtrapolation extrapolationMode)
{
clip.SetPrivateFieldValue<TimelineClip.ClipExtrapolation>(PRE_EXTRAP_MODE_INTERNAL_FIELD, extrapolationMode);
}
/// <summary>
/// Sets the pre-extrapolation time for a clip (duration of the extrapolated portion)
/// (uses Unity 2018.2.0f2 internal methods that may break in future versions)
/// </summary>
/// <param name="clip">Clip to set the extrapolation for</param>
/// <param name="time">How long to extrapolate into the past before the clip starts</param>
public static void SetPreExtrapolationTime(this TimelineClip clip, double time)
{
clip.SetPrivateFieldValue<double>(PRE_EXTRAP_TIME_INTERNAL_FIELD, time);
}
/// <summary>
/// Gets the pre-extrapolation time for a clip (duration of the extrapolated portion)
/// (uses Unity 2018.2.0f2 internal methods that may break in future versions)
/// </summary>
/// <param name="clip">Clip to get the extrapolation for</param>
/// <param name="time">Duration of the extrapolation into the past before the clip starts</param>
public static double GetPreExtrapolationTime(this TimelineClip clip)
{
return clip.GetPrivateFieldValue<double>(PRE_EXTRAP_TIME_INTERNAL_FIELD);
}
/// <summary>
/// Sets the post-extrapolation mode for a clip
/// (uses Unity 2018.2.0f2 internal methods that may break in future versions)
/// </summary>
/// <param name="clip">Clip to set the extrapolation for</param>
/// <param name="extrapolationMode">Extrapolation behaviour</param>
public static void SetPostExtrapolationMode(this TimelineClip clip, TimelineClip.ClipExtrapolation extrapolationMode)
{
clip.SetPrivateFieldValue<TimelineClip.ClipExtrapolation>(POST_EXTRAP_MODE_INTERNAL_FIELD, extrapolationMode);
}
/// <summary>
/// Sets the post-extrapolation time for a clip (duration of the extrapolated portion)
/// (uses Unity 2018.2.0f2 internal methods that may break in future versions)
/// </summary>
/// <param name="clip">Clip to set the extrapolation for</param>
/// <param name="time">How long to extrapolate into the future beyond the clip end</param>
public static void SetPostExtrapolationTime(this TimelineClip clip, double time)
{
clip.SetPrivateFieldValue<double>(POST_EXTRAP_TIME_INTERNAL_FIELD, time);
}
/// <summary>
/// Gets the post-extrapolation time for a clip (duration of the extrapolated portion)
/// (uses Unity 2018.2.0f2 internal methods that may break in future versions)
/// </summary>
/// <param name="clip">Clip to get the extrapolation for</param>
/// <param name="time">Duration of the extrapolation into the future beyond the clip end</param>
public static double GetPostExtrapolationTime(this TimelineClip clip)
{
return clip.GetPrivateFieldValue<double>(POST_EXTRAP_TIME_INTERNAL_FIELD);
}
/// <summary>
/// Returns a private Property Value from a given Object. Uses Reflection.
/// Throws a ArgumentOutOfRangeException if the Property is not found.
/// </summary>
/// <typeparam name="T">Type of the Property</typeparam>
/// <param name="obj">Object from where the Property Value is returned</param>
/// <param name="propName">Propertyname as string.</param>
/// <returns>PropertyValue</returns>
public static T GetPrivateFieldValue<T>(this object obj, string propName)
{
if (obj == null) throw new ArgumentNullException("obj");
Type t = obj.GetType();
FieldInfo fi = null;
while (fi == null && t != null)
{
fi = t.GetField(propName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
t = t.BaseType;
}
if (fi == null) throw new ArgumentOutOfRangeException("propName", string.Format("Field {0} was not found in Type {1}", propName, obj.GetType().FullName));
return (T)fi.GetValue(obj);
}
/// <summary>
/// Set a private Property Value on a given Object. Uses Reflection.
/// </summary>
/// <typeparam name="T">Type of the Property</typeparam>
/// <param name="obj">Object from where the Property Value is returned</param>
/// <param name="propName">Propertyname as string.</param>
/// <param name="val">the value to set</param>
/// <exception cref="ArgumentOutOfRangeException">if the Property is not found</exception>
public static void SetPrivateFieldValue<T>(this object obj, string propName, T val)
{
if (obj == null) throw new ArgumentNullException("obj");
Type t = obj.GetType();
FieldInfo fi = null;
while (fi == null && t != null)
{
fi = t.GetField(propName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
t = t.BaseType;
}
if (fi == null) throw new ArgumentOutOfRangeException("propName", string.Format("Field {0} was not found in Type {1}", propName, obj.GetType().FullName));
fi.SetValue(obj, val);
}
Hey @seant_unity do you have an ETA for this? I would really need to be able to set these parameters in order to automate the setup of Timeline the way I need. Will it be in release 2019.3f?
It won’t be released in the version that ships with 2019.3, but it may make it into a future compatible version.
In 2019.3, timeline has moved to being a complete package, meaning that new versions can be released independent of the editor version.
In the meantime, you can use the solution from @panta , or just move the timeline package from the package cache into the project and make the necessary API changes. Extrapolation.CalculateExtrapolationTimes is the method we use internally.
In case anyone else struggles to get this to work, here’s how I did it using @panta 's extension methods above.
Create a new C# script amongst your project assets, call it TimelineExtensions.cs or something like that.
Make the class static and remove the inheritance from MonoBehaviour.
Add (with using) System, System.Reflection and UnityEngine.Timeline.
Copy-paste all the code from panta’s post (see above) in the body of your class.
The file TimelineExtensions.cs shoul look like this:
using System;
using System.Reflection;
using UnityEngine.Timeline;
public static class TimelineExtensions
{
// paste all the code from @panta in here
}
Now these extension methods should be available from your TimelineClip in your code, use it something like this:
// create a new clip on a timeline track (stored in the variable 'track' in this example)
var clip = track.CreateClip<MyCustomTimelineClip>();
// Set the post-extrapolation mode to 'Hold'
clip.SetPostExtrapolationMode(TimelineClip.ClipExtrapolation.Hold);
I just encountered the same issue. I need to set the Pre- and Post-Extrapolate values when creating a Clip. Please provide functionality to do this, so we don’t have to use reflection.