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();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|