rokojori_action_library/Runtime/Time/TimeLineRunner.cs

332 lines
7.3 KiB
C#
Raw Normal View History

2024-05-19 15:59:41 +00:00
using System.Diagnostics;
using System.Collections;
using System.Collections.Generic;
using System;
using Godot;
2026-05-22 12:25:02 +00:00
using Rokojori.Extensions;
namespace Rokojori;
public class TimelineRunner
{
public Timeline timeLine;
public TimelineManager manager;
public float lastPosition = 0;
public float position = 0;
public bool playing = false;
public float deltaScale = 1;
public float speed = 1;
List<TimelineEvent> events = new List<TimelineEvent>();
List<TimelineSpan> spans = new List<TimelineSpan>();
List<TimelineCallback> callbacks = new List<TimelineCallback>();
AnimationCurve modulatorCurve;
float modulatorTime;
Vector3 modulatorRandomization;
Action<bool> modulatorOnReady = null;
float _lastModulation = 1;
float _currentDelta = 1;
public float modulatedSpeed => (float)( speed * _lastModulation * deltaScale );
public float currentDelta => _currentDelta;
public TimelineRunner( Timeline timeLine, TimelineManager manager )
2024-05-19 15:59:41 +00:00
{
2026-05-22 12:25:02 +00:00
this.timeLine = timeLine;
this.manager = manager;
this.speed = timeLine.startSpeed;
2025-01-03 12:09:23 +00:00
2026-05-22 12:25:02 +00:00
playing = timeLine.autoStart;
}
2024-05-19 15:59:41 +00:00
2026-05-22 12:25:02 +00:00
public void Modulate( AnimationCurve curve, Action<bool> onReady )
{
if ( modulatorOnReady != null )
{
modulatorOnReady( false );
2024-05-19 15:59:41 +00:00
}
2026-05-22 12:25:02 +00:00
modulatorCurve = curve;
modulatorTime = 0;
modulatorRandomization = curve.Randomize();
modulatorOnReady = onReady;
}
2025-01-03 12:09:23 +00:00
2026-05-22 12:25:02 +00:00
public void UpdateTimeLine( float realtimeDelta )
{
if ( ! playing || ( manager.paused && ! timeLine.executesInPause ))
{
return;
2025-01-03 12:09:23 +00:00
}
2026-05-22 12:25:02 +00:00
var modulation = 1f;
2024-05-19 15:59:41 +00:00
2026-05-22 12:25:02 +00:00
if ( modulatorCurve != null )
{
modulation = modulatorCurve.SampleRandomized( modulatorTime, modulatorRandomization );
2025-01-03 12:09:23 +00:00
2026-05-22 12:25:02 +00:00
_lastModulation = modulation;
modulatorTime += realtimeDelta;
2025-01-03 12:09:23 +00:00
2026-05-22 12:25:02 +00:00
if ( modulatorTime >= modulatorCurve.GetRandomizedEndTime( modulatorRandomization ) )
{
var mr = modulatorOnReady;
modulatorOnReady = null;
modulatorCurve = null;
modulatorTime = 0;
modulatorRandomization = Vector3.Zero;
2025-01-03 12:09:23 +00:00
2026-05-22 12:25:02 +00:00
if ( mr != null )
2025-01-03 12:09:23 +00:00
{
2026-05-22 12:25:02 +00:00
mr( true );
2025-01-03 12:09:23 +00:00
}
2026-05-22 12:25:02 +00:00
2025-01-03 12:09:23 +00:00
}
2026-05-22 12:25:02 +00:00
}
else
{
_lastModulation = 1;
}
2025-01-03 12:09:23 +00:00
2026-05-22 12:25:02 +00:00
_currentDelta = realtimeDelta * deltaScale * speed * modulation;
lastPosition = position;
position += _currentDelta;
2024-05-19 15:59:41 +00:00
2026-05-22 12:25:02 +00:00
var isForward = speed >= 0;
2024-05-19 15:59:41 +00:00
2026-05-22 12:25:02 +00:00
if ( isForward )
{
ProcessForward();
2024-05-19 15:59:41 +00:00
}
2026-05-22 12:25:02 +00:00
}
2024-05-19 15:59:41 +00:00
2025-01-03 12:09:23 +00:00
2026-05-22 12:25:02 +00:00
void ProcessForward()
{
ProcessEvents();
ProcessSpans();
ProcessCallbacks();
}
2025-01-21 20:58:56 +00:00
2026-05-22 12:25:02 +00:00
List<TimelineCallback> _callbackAdditions = new List<TimelineCallback>();
2025-01-21 20:58:56 +00:00
2026-05-22 12:25:02 +00:00
void ProcessCallbacks()
{
if ( _callbackAdditions.Count > 0 )
{
callbacks.AddRange( _callbackAdditions );
_callbackAdditions.Clear();
}
2025-01-21 20:58:56 +00:00
2026-05-22 12:25:02 +00:00
callbacks.ForEach( c => c.callback( c ) );
2025-01-03 12:09:23 +00:00
2026-05-22 12:25:02 +00:00
}
2025-01-03 12:09:23 +00:00
2026-05-22 12:25:02 +00:00
void ProcessEvents()
{
if ( requestedRemovalIDs.Count > 0 )
2024-05-19 15:59:41 +00:00
{
2026-05-22 12:25:02 +00:00
requestedRemovalIDs.Sort();
2025-07-25 08:13:35 +00:00
2026-05-22 12:25:02 +00:00
RJLog.Log( "Removing:", requestedRemovalIDs, "From:", events );
//Lists.RemoveIncreasingSortedIndices( events, requestedRemovalIDs );
events = events.Filter( e => ! requestedRemovalIDs.Contains( e.id ) );
requestedRemovalIDs.Clear();
}
2025-01-16 07:20:32 +00:00
2026-05-22 12:25:02 +00:00
List<int> eventRemovals = null;
2024-05-19 15:59:41 +00:00
2026-05-22 12:25:02 +00:00
for ( int i = 0; i < events.Count; i++ )
{
var eventPosition = events[ i ].position;
if ( events[ i ].looping )
2024-05-19 15:59:41 +00:00
{
2026-05-22 12:25:02 +00:00
var next = events[ i ].GetNextLoopPosition( lastPosition );
var previous = events[ i ].GetPreviousLoopPosition( position );
2025-01-16 07:20:32 +00:00
2026-05-22 12:25:02 +00:00
if ( next != previous )
2024-05-19 15:59:41 +00:00
{
continue;
}
2026-05-22 12:25:02 +00:00
eventPosition = next;
}
if ( ! RangeDouble.ContainsExclusiveMax( lastPosition, position, eventPosition ) )
{
if ( events[ i ].wasInside )
{
eventRemovals = AddRemoval( events[ i ].persistent, i, eventRemovals );
}
2024-05-19 15:59:41 +00:00
2026-05-22 12:25:02 +00:00
continue;
2024-05-19 15:59:41 +00:00
}
2026-05-22 12:25:02 +00:00
events[ i ].callback( events[ i ] );
events[ i ].wasInside = true;
2024-05-19 15:59:41 +00:00
2025-01-19 20:35:51 +00:00
}
2026-05-22 12:25:02 +00:00
if ( eventRemovals != null )
{
ListExtensions.RemoveIncreasingSortedIndices( events, eventRemovals );
}
2024-05-19 15:59:41 +00:00
2026-05-22 12:25:02 +00:00
}
2024-05-19 15:59:41 +00:00
2026-05-22 12:25:02 +00:00
void ProcessSpans()
{
if ( spans.Count == 0 )
{
return;
}
2025-01-03 12:09:23 +00:00
2026-05-22 12:25:02 +00:00
List<int> spanRemovals = null;
2025-01-03 12:09:23 +00:00
2026-05-22 12:25:02 +00:00
var timelineSpan = RangeDouble.Create( lastPosition, position );
var span = RangeDouble.Create( 0, 1 );
var isForward = lastPosition < position;
2024-05-19 15:59:41 +00:00
2026-05-22 12:25:02 +00:00
for ( int i = 0; i < spans.Count; i++ )
{
span.min = spans[ i ].start;
span.max = spans[ i ].end;
2024-05-19 15:59:41 +00:00
2026-05-22 12:25:02 +00:00
var overlaps = timelineSpan.Overlaps( span );
2024-05-19 15:59:41 +00:00
2026-05-22 12:25:02 +00:00
if ( ! overlaps )
{
if ( spans[ i ].wasInside )
2024-05-19 15:59:41 +00:00
{
2026-05-22 12:25:02 +00:00
spanRemovals = AddRemoval( spans[ i ].persistent, i, spanRemovals );
2024-05-19 15:59:41 +00:00
}
2026-05-22 12:25:02 +00:00
continue;
}
2025-01-08 18:46:17 +00:00
2026-05-22 12:25:02 +00:00
var isStart = timelineSpan.ContainsValue( spans[ i ].start );
var isEnd = timelineSpan.ContainsValue( spans[ i ].end );
2024-05-19 15:59:41 +00:00
2026-05-22 12:25:02 +00:00
var spanType = TimelineSpanUpdateType.InSpan;
2024-05-19 15:59:41 +00:00
2026-05-22 12:25:02 +00:00
if ( isStart && isEnd )
2025-01-03 12:09:23 +00:00
{
2026-05-22 12:25:02 +00:00
spanType = TimelineSpanUpdateType.CompletelyInside;
2024-05-19 15:59:41 +00:00
}
2026-05-22 12:25:02 +00:00
else if ( isStart )
2025-01-19 20:35:51 +00:00
{
2026-05-22 12:25:02 +00:00
spanType = TimelineSpanUpdateType.Start;
2025-01-19 20:35:51 +00:00
}
2026-05-22 12:25:02 +00:00
else if ( isEnd )
2025-01-19 20:35:51 +00:00
{
2026-05-22 12:25:02 +00:00
spanType = TimelineSpanUpdateType.End;
2025-01-19 20:35:51 +00:00
}
2026-05-22 12:25:02 +00:00
spans[ i ].wasInside = true;
2025-01-19 20:35:51 +00:00
2026-05-22 12:25:02 +00:00
spans[ i ].callback( spans[ i ], spanType );
2025-01-19 20:35:51 +00:00
2026-05-22 12:25:02 +00:00
}
2025-01-16 07:20:32 +00:00
2026-05-22 12:25:02 +00:00
if ( spanRemovals != null )
2025-01-16 07:20:32 +00:00
{
2026-05-22 12:25:02 +00:00
ListExtensions.RemoveIncreasingSortedIndices( spans, spanRemovals );
}
}
2025-07-25 08:13:35 +00:00
2026-05-22 12:25:02 +00:00
List<int> AddRemoval( bool isPersistent, int index, List<int> list )
{
if ( isPersistent )
{
return list;
2025-01-16 07:20:32 +00:00
}
2026-05-22 12:25:02 +00:00
if ( list == null )
2025-01-21 20:58:56 +00:00
{
2026-05-22 12:25:02 +00:00
list = new List<int>();
}
2025-01-21 20:58:56 +00:00
2026-05-22 12:25:02 +00:00
list.Add( index );
2025-01-21 20:58:56 +00:00
2026-05-22 12:25:02 +00:00
return list;
}
2025-01-21 20:58:56 +00:00
2026-05-22 12:25:02 +00:00
List<int> requestedRemovalIDs = new List<int>();
2024-05-19 15:59:41 +00:00
2026-05-22 12:25:02 +00:00
public void RemoveEvent( int eventID )
{
requestedRemovalIDs.Add( eventID );
2025-01-19 20:35:51 +00:00
2026-05-22 12:25:02 +00:00
RJLog.Log( "requestedRemovals add:", eventID );
}
2024-05-19 15:59:41 +00:00
2026-05-22 12:25:02 +00:00
public TimelineCallback _ScheduleCallback( Action<TimelineCallback> callback, int eventID )
{
var tle = new TimelineCallback();
tle.id = eventID;
tle.callback = callback;
tle.timeLine = timeLine;
2025-01-16 07:20:32 +00:00
2026-05-22 12:25:02 +00:00
_callbackAdditions.Add( tle );
2025-01-19 20:35:51 +00:00
2026-05-22 12:25:02 +00:00
return tle;
}
public TimelineEvent _ScheduleEvent( float position, int eventID, bool isPersistent, Action<TimelineEvent> callback )
{
var tle = new TimelineEvent();
tle.position = position;
tle.id = eventID;
tle.persistent = isPersistent;
tle.callback = callback;
tle.timeLine = timeLine;
events.Add( tle );
return tle;
}
public TimelineEvent _ScheduleLoopEvent( float loopDuration, float loopOffset, int eventID, bool isPersistent, Action<TimelineEvent> callback )
{
var tle = new TimelineEvent();
tle.position = loopOffset;
tle.looping = true;
tle.loopDuration = loopDuration;
tle.id = eventID;
tle.persistent = isPersistent;
tle.callback = callback;
tle.timeLine = timeLine;
events.Add( tle );
return tle;
}
public TimelineSpan _ScheduleSpan( float start, float end, int eventID, bool isPersistent, Action<TimelineSpan, TimelineSpanUpdateType> callback )
{
var tse = new TimelineSpan();
tse.start = start;
tse.end = end;
tse.id = eventID;
tse.persistent = isPersistent;
tse.wasInside = false;
tse.callback = callback;
tse.timeLine = timeLine;
spans.Add( tse );
return tse;
2024-05-19 15:59:41 +00:00
}
2026-05-22 12:25:02 +00:00
}