using System.Diagnostics;
using System.Collections;
using System.Collections.Generic;
using System;
using Godot;
using Rokojori.Extensions;
namespace Rokojori;
/**
Manages time lines for events, callbacks tweens.
Most time-based SequenceActions use a Timeline to define the clock it belongs to.
*/
[Tool]
[GlobalClass, Icon("res://addons/rokojori_action_library/Icons/TimelineManager.svg") ]
public partial class TimelineManager:NetworkNode
{
[Export]
public Timeline[] timelines = new Timeline[ 0 ];
[Export]
public Timeline timeScaleTimeline;
[Export]
public Timeline realtimeTimeline;
[Export]
public bool computeRealtimeWithEngineDelta;
List _runners = new List();
int _idCounter = 0;
bool _initialized = false;
public override void _Ready()
{
if ( _runners == null )
{
GD.Print( "is null" );
}
_runners = null;
Initialize();
}
public static TimelineManager Get()
{
return Unique.Get();
}
float _lastUpdate = 0;
//DateTime lastUpdated = DateTime.Now;
float lastUpdated = TimeTool.Now();
float _estimatedDelta = 0;
float _estimatedDeltaFilter = 0.9f;
float _unscaledDelta = 0;
double _lastRealtimePosition = 0;
double _realtimePosition = 0;
float _lastTimeScale = 1;
QueueList _processCallbacks = new QueueList();
bool _inProcess = false;
public bool inProcess => _inProcess;
bool _paused = false;
public bool paused => _paused;
public override void _Process( double delta )
{
_inProcess = true;
_paused = GetTree().Paused;
UpdateRealTime( delta );
if ( ! Engine.IsEditorHint() && timeScaleTimeline != null )
{
Engine.TimeScale = GetRunnerByTimeline( timeScaleTimeline ).modulatedSpeed;
}
_runners.ForEach(
r =>
{
if ( r == null )
{
return;
}
r.UpdateTimeLine( unscaledTimeDelta );
}
);
_processCallbacks.IterateAndResolve( t => t() );
_inProcess = false;
}
public void AddProcessCallback( System.Action a )
{
_processCallbacks.QueueInsert( a );
}
public void RemoveProcessCallback( System.Action a )
{
_processCallbacks.QueueRemoval( a );
}
public int GetTimeLineIndex( Timeline timeLine )
{
return timelines == null ? -1 : Arrays.IndexOf( timelines, timeLine );
}
public void Modulate( Timeline timeline, AnimationCurve c, Action onReady )
{
var runner = GetRunner( GetTimeLineIndex( timeline ) );
runner.Modulate( c, onReady );
}
void UpdateRealTime( double engineDelta )
{
var now = TimeTool.Now();
var unscaled = ( now - lastUpdated );
lastUpdated = now;
if ( unscaled < 1f/20f )
{
_estimatedDelta += _estimatedDeltaFilter * ( unscaled - _estimatedDelta );
}
if ( computeRealtimeWithEngineDelta )
{
_unscaledDelta = (float)( Engine.TimeScale == 0 ? _estimatedDelta : ( engineDelta / Engine.TimeScale ) );
}
else
{
_unscaledDelta = _estimatedDelta;
}
_lastRealtimePosition = _realtimePosition;
_realtimePosition += _unscaledDelta;
}
public float unscaledTimeDelta => _unscaledDelta;
public double realtime => _realtimePosition;
void Initialize()
{
if ( _initialized )
{
return;
}
_initialized = true;
_runners = ListExtensions.Map( timelines, tl => new TimelineRunner( tl, this ) );
// this.LogInfo( "Created runners:", _runners.Count );
}
public static Timeline Ensure( Timeline timeline )
{
if ( timeline != null )
{
return timeline;
}
var tm = Get();
if ( tm == null )
{
return new Timeline();
}
return tm.timeScaleTimeline;
}
public TimelineRunner GetRunnerByTimeline( Timeline timeline )
{
return GetRunner( _runners.FindIndex( r => r.timeLine == timeline ) );
}
public TimelineRunner GetRunner( int index )
{
if ( index < 0 || index >= _runners.Count )
{
return null ;
}
return _runners[ index ];
}
int _CreateID()
{
_idCounter ++;
return _idCounter;
}
public static int CreateID()
{
var tm = Get();
return tm._CreateID();
}
}