CodeLiturgy.Dashboard/BlueWest/Core/System/Artefact.cs

257 lines
7.8 KiB
C#
Raw Normal View History

2021-12-06 02:49:27 +03:00
using System;
using System.Collections;
2022-08-13 08:34:20 +03:00
using System.Collections.Generic;
2021-12-06 02:49:27 +03:00
using System.Data;
using System.Threading;
using BlueWest.Coroutines;
using BlueWest.Tools;
2022-08-13 20:15:43 +03:00
using PerformanceSolution.Core.System;
2021-12-06 02:49:27 +03:00
namespace BlueWest.Core.ComponentSystem
{
public class Artefact
{
public Artefact()
{
_autoTickTimer = new TimerTick();
_autoTickTimer.Reset();
_maximumElapsedTime = TimeSpan.FromMilliseconds(500.0);
}
// Time Management
private readonly TimeSpan _maximumElapsedTime;
private TimeSpan _accumulatedElapsedGameTime;
private TimeSpan TargetElapsedTime = TimeSpan.FromTicks(TimeSpan.TicksPerSecond / 30); // target elapsed time is by default 250Hz
private readonly TimerTick _autoTickTimer;
private TimeSpan accumulatedElapsedGameTime;
2022-08-13 08:34:20 +03:00
private Dictionary<ArtefactFrequency, int> behaviorConfigType =
new Dictionary<ArtefactFrequency, int>(10);
2021-12-06 02:49:27 +03:00
2022-08-13 08:34:20 +03:00
private readonly List<IEnumerator> _coroutines = new List<IEnumerator>(10000);
2021-12-06 02:49:27 +03:00
private bool? _prevVisibility;
// Mini ECS
protected EventManager _eventManager;
private bool _startCalled;
internal VisibilityHandler _visibilityHandler = new VisibilityHandler();
2022-08-13 08:34:20 +03:00
internal List<Component> _components = new List<Component>(10);
2021-12-06 02:49:27 +03:00
private int _componentsCount = 0;
// OLD STUFF
protected internal ArtefactFrequency Frequency;
protected internal bool IsActive { get { return _visibilityHandler.IsVisible; } set { SetActive(value); } }
/// <summary>
/// Initial setup of the entity. Triggers Awake method if the node is visible
/// and triggers an visibility change event.
/// </summary>
public void SetupEntity(EventManager eventManager)
{
_eventManager = eventManager;
2022-08-13 20:15:43 +03:00
switch (Frequency)
2021-12-06 02:49:27 +03:00
{
case ArtefactFrequency.T1Hz:
TargetElapsedTime = TimeSpan.FromTicks(TimeSpan.TicksPerSecond / 1);
break;
case ArtefactFrequency.T2Hz:
TargetElapsedTime = TimeSpan.FromTicks(TimeSpan.TicksPerSecond / 2);
break;
case ArtefactFrequency.T3Hz:
TargetElapsedTime = TimeSpan.FromTicks(TimeSpan.TicksPerSecond / 3);
break;
case ArtefactFrequency.T4Hz:
TargetElapsedTime = TimeSpan.FromTicks(TimeSpan.TicksPerSecond / 4);
break;
case ArtefactFrequency.T10Hz:
TargetElapsedTime = TimeSpan.FromTicks(TimeSpan.TicksPerSecond / 10);
break;
case ArtefactFrequency.T20Hz:
TargetElapsedTime = TimeSpan.FromTicks(TimeSpan.TicksPerSecond / 20);
break;
case ArtefactFrequency.T30Hz:
TargetElapsedTime = TimeSpan.FromTicks(TimeSpan.TicksPerSecond / 30);
break;
case ArtefactFrequency.T60Hz:
TargetElapsedTime = TimeSpan.FromTicks(TimeSpan.TicksPerSecond / 60);
break;
case ArtefactFrequency.T120Hz:
TargetElapsedTime = TimeSpan.FromTicks(TimeSpan.TicksPerSecond / 120);
break;
default:
throw new EvaluateException(
$"BehaviorType of class can't be null. Please assign it in the Constructor.");
}
if (!_visibilityHandler.IsVisible) return;
Awake();
OnVisibilityChange();
if (!_visibilityHandler.IsVisible) return;
if (!_startCalled)
{
_startCalled = true;
Start();
}
}
public void AddComponent<T>() where T : Component
{
var component = Activator.CreateInstance(typeof(T), _eventManager) as Component;
_components.Add(component);
_componentsCount += 1;
component.Start();
}
protected virtual void Awake()
{
}
protected virtual void Start()
{
}
public void ProcessComponents(double delta)
{
2022-08-13 08:34:20 +03:00
for (int i = 0; i < _components.Count; i++)
2021-12-06 02:49:27 +03:00
{
2022-08-13 08:34:20 +03:00
var component = _components[i];
2021-12-06 02:49:27 +03:00
component.EveryFrame(delta);
component.HandleCoroutines();
}
}
public void StartCoroutine(IEnumerator routine)
{
_coroutines.Add(routine);
}
public bool LoopEnabled = true;
/// <summary>
/// Called every frame
/// </summary>
public void RunLoop()
{
RetryTick:
if (!LoopEnabled) return;
if (!_visibilityHandler.IsVisible) return;
_autoTickTimer.Tick();
var elapsedAdjustedTime = _autoTickTimer.ElapsedTimeWithPause;
int updateCount = 1;
// then make ElapsedAdjustedTime = TargetElapsedTime. We take the same internal rules as XNA
if (Math.Abs(elapsedAdjustedTime.Ticks - TargetElapsedTime.Ticks) < (TargetElapsedTime.Ticks >> 6))
{
elapsedAdjustedTime = TargetElapsedTime;
}
// Update the accumulated time
accumulatedElapsedGameTime += elapsedAdjustedTime;
if (accumulatedElapsedGameTime < TargetElapsedTime)
{
var sleepTime = (TargetElapsedTime - accumulatedElapsedGameTime).TotalMilliseconds;
if (sleepTime >= 2.0)
{
System.Threading.Thread.Sleep(1);
}
goto RetryTick;
}
// We are going to call Update updateCount times, so we can subtract this from accumulated elapsed game time
accumulatedElapsedGameTime =
new TimeSpan(accumulatedElapsedGameTime.Ticks - (updateCount * TargetElapsedTime.Ticks));
for (int i = 0; i < updateCount; i++)
{
double delta = TargetElapsedTime.TotalSeconds;
Update(delta);
ProcessComponents(delta);
}
if (!_visibilityHandler.IsVisible) return; // Added to avoid running after deactivating node
HandleCoroutines();
goto RetryTick;
}
protected virtual void Update(double delta)
{
}
public void HandleCoroutines()
{
2022-08-13 08:34:20 +03:00
for (var i = 0; i < _coroutines.Count; i++)
2021-12-06 02:49:27 +03:00
{
2022-08-13 08:34:20 +03:00
var yielded = _coroutines[i].Current is CustomYieldInstruction yielder && yielder.MoveNext();
2021-12-06 02:49:27 +03:00
2022-08-13 08:34:20 +03:00
if (yielded || _coroutines[i].MoveNext()) continue;
2021-12-06 02:49:27 +03:00
_coroutines.RemoveAt(i);
i--;
}
}
/// <summary>
/// Trigger OnEnable and OnDisable methods regarding the current and previous visibility.
/// </summary>
internal void OnVisibilityChange()
{
var curVisibility = _visibilityHandler.IsVisible;
if (curVisibility == _prevVisibility) return;
if (curVisibility) OnEnable();
if (!curVisibility) OnDisable();
_prevVisibility = curVisibility;
}
protected virtual void OnEnable()
{
}
protected virtual void OnDisable()
{
}
public void SetActive(bool status)
{
_visibilityHandler.SetVisibility(status);
OnVisibilityChange();
}
}
}