remove time dilation priority system in favor of averaging

pull/5/head
thatcosmonaut 2019-11-22 13:14:36 -08:00
parent 71846a9a09
commit f05b7f725d
8 changed files with 93 additions and 176 deletions

View File

@ -1,15 +0,0 @@
using System;
namespace Encompass
{
[AttributeUsage(AttributeTargets.Class)]
public class TimeDilationPriority : Attribute
{
public int timeDilationPriority;
public TimeDilationPriority(int timeDilationPriority)
{
this.timeDilationPriority = timeDilationPriority;
}
}
}

View File

@ -27,7 +27,6 @@ namespace Encompass
/// <summary>
/// Used when activating time dilation. Lower priority overrides higher priority.
/// </summary>
internal int? timeDilationPriority = null;
private EntityManager entityManager;
private MessageManager messageManager;
@ -139,9 +138,9 @@ namespace Encompass
/// <summary>
/// Returns true if an Entity with the specified ID exists.
/// </summary>
internal bool EntityExists(Guid entityID)
protected bool EntityExists(Entity entity)
{
return entityManager.EntityExists(entityID);
return entityManager.EntityExists(entity.ID);
}
/// <summary>
@ -699,15 +698,10 @@ namespace Encompass
componentManager.MarkForRemoval(componentID);
}
private void CheckTimeDilationPriorityExists()
{
if (!timeDilationPriority.HasValue) { throw new TimeDilationPriorityUndefinedException("Engines that activate time dilation must use the TimeDilationPriority attribute."); }
}
/// <summary>
/// Activates the Encompass time dilation system.
/// If activating time dilation, make sure the TimeDilationPriority attribute is set or an exception will be thrown.
/// Engines that have the IgnoresTimeDilation property will ignore all time dilation.
/// If multiple time dilations are active they will be averaged.
/// </summary>
/// <param name="factor">The time dilation factor, which is multiplied by real delta time.</param>
/// <param name="easeInTime">The time that will elapse before time is fully dilated, in real time.</param>
@ -715,14 +709,13 @@ namespace Encompass
/// <param name="easeOutTime">The time that will elapse before time is fully undilated.</param>
public void ActivateTimeDilation(double factor, double easeInTime, double activeTime, double easeOutTime)
{
CheckTimeDilationPriorityExists();
timeManager.ActivateTimeDilation(factor, easeInTime, activeTime, easeOutTime, timeDilationPriority.Value);
timeManager.ActivateTimeDilation(factor, easeInTime, activeTime, easeOutTime);
}
/// <summary>
/// Activates the Encompass time dilation system.
/// If activating time dilation, make sure the TimeDilationPriority attribute is set or an exception will be thrown.
/// Engines that have the IgnoresTimeDilation property will ignore all time dilation.
/// If multiple time dilations are active they will be averaged.
/// </summary>
/// <param name="factor">The time dilation factor, which is multiplied by real delta time.</param>
/// <param name="easeInTime">The time that will elapse before time is fully dilated, in real time.</param>
@ -731,14 +724,13 @@ namespace Encompass
/// <param name="easeOutTime">The time that will elapse before time is fully undilated.</param>
public void ActivateTimeDilation(double factor, double easeInTime, System.Func<double, double, double, double, double> easeInFunction, double activeTime, double easeOutTime)
{
CheckTimeDilationPriorityExists();
timeManager.ActivateTimeDilation(factor, easeInTime, easeInFunction, activeTime, easeOutTime, timeDilationPriority.Value);
timeManager.ActivateTimeDilation(factor, easeInTime, easeInFunction, activeTime, easeOutTime);
}
/// <summary>
/// Activates the Encompass time dilation system.
/// If activating time dilation, make sure the TimeDilationPriority attribute is set or an exception will be thrown.
/// Engines that have the IgnoresTimeDilation property will ignore all time dilation.
/// If multiple time dilations are active they will be averaged.
/// </summary>
/// <param name="factor">The time dilation factor, which is multiplied by real delta time.</param>
/// <param name="easeInTime">The time that will elapse before time is fully dilated, in real time.</param>
@ -747,14 +739,13 @@ namespace Encompass
/// <param name="easeOutFunction">An easing function for the easing out of time dilation.</param>
public void ActivateTimeDilation(double factor, double easeInTime, double activeTime, double easeOutTime, System.Func<double, double, double, double, double> easeOutFunction)
{
CheckTimeDilationPriorityExists();
timeManager.ActivateTimeDilation(factor, easeInTime, activeTime, easeOutTime, easeOutFunction, timeDilationPriority.Value);
timeManager.ActivateTimeDilation(factor, easeInTime, activeTime, easeOutTime, easeOutFunction);
}
/// <summary>
/// Activates the Encompass time dilation system.
/// If activating time dilation, make sure the TimeDilationPriority attribute is set or an exception will be thrown.
/// Engines that have the IgnoresTimeDilation property will ignore all time dilation.
/// If multiple time dilations are active they will be averaged.
/// </summary>
/// <param name="factor">The time dilation factor, which is multiplied by real delta time.</param>
/// <param name="easeInTime">The time that will elapse before time is fully dilated, in real time.</param>
@ -764,8 +755,7 @@ namespace Encompass
/// <param name="easeOutFunction">An easing function for the easing out of time dilation.</param>
public void ActivateTimeDilation(double factor, double easeInTime, System.Func<double, double, double, double, double> easeInFunction, double activeTime, double easeOutTime, System.Func<double, double, double, double, double> easeOutFunction)
{
CheckTimeDilationPriorityExists();
timeManager.ActivateTimeDilation(factor, easeInTime, easeInFunction, activeTime, easeOutTime, easeOutFunction, timeDilationPriority.Value);
timeManager.ActivateTimeDilation(factor, easeInTime, easeInFunction, activeTime, easeOutTime, easeOutFunction);
}
}
}

View File

@ -1,12 +0,0 @@
using System;
namespace Encompass.Exceptions
{
public class TimeDilationPriorityConflictException : Exception
{
public TimeDilationPriorityConflictException(
string format,
params object[] args
) : base(string.Format(format, args)) { }
}
}

View File

@ -1,12 +0,0 @@
using System;
namespace Encompass.Exceptions
{
public class TimeDilationPriorityUndefinedException : Exception
{
public TimeDilationPriorityUndefinedException(
string format,
params object[] args
) : base(string.Format(format, args)) { }
}
}

View File

@ -29,6 +29,16 @@ namespace Encompass
return entityManager.GetEntity(entityID);
}
protected IEnumerable<Entity> ReadEntities<TComponent>() where TComponent : struct, IComponent
{
return ReadComponentsIncludingEntity<TComponent>().Select(tuple => tuple.Item2);
}
protected Entity ReadEntity<TComponent>() where TComponent : struct, IComponent
{
return ReadComponentIncludingEntity<TComponent>().Item2;
}
protected IEnumerable<TComponent> ReadComponents<TComponent>() where TComponent : struct, IComponent
{
return componentManager.GetComponentsByType<TComponent>().Select(tuple => tuple.Item2);

View File

@ -1,73 +1,76 @@
using System.Collections.Generic;
using System.Linq;
namespace Encompass
{
internal class TimeManager
{
private TimeDilationData timeDilationData = new TimeDilationData { factor = 1 };
private bool newTimeDilationData = false;
private TimeDilationData nextFrameTimeDilationData = new TimeDilationData { factor = 1 };
private List<TimeDilationData> timeDilationDatas = new List<TimeDilationData>();
private double Linear(double t, double b, double c, double d)
{
return c * t / d + b;
}
private int minPriority = int.MaxValue;
public double TimeDilationFactor
{
get
{
return timeDilationData.Factor;
return timeDilationDatas.Count == 0 ? 1 : timeDilationDatas.Select(data => data.Factor).Average();
}
}
public bool TimeDilationActive
{
get => TimeDilationFactor != 1;
get => timeDilationDatas.Count != 0;
}
public void Update(double dt)
{
if (newTimeDilationData)
for (var i = timeDilationDatas.Count - 1; i >= 0; i--)
{
timeDilationData = nextFrameTimeDilationData;
}
var data = timeDilationDatas[i];
timeDilationData.elapsedTime += dt;
newTimeDilationData = false;
minPriority = int.MaxValue;
}
data.elapsedTime += dt;
public void ActivateTimeDilation(double factor, double easeInTime, double activeTime, double easeOutTime, int priority)
{
ActivateTimeDilation(factor, easeInTime, Linear, activeTime, easeOutTime, Linear, priority);
}
public void ActivateTimeDilation(double factor, double easeInTime, System.Func<double, double, double, double, double> easeInFunction, double activeTime, double easeOutTime, int priority)
{
ActivateTimeDilation(factor, easeInTime, easeInFunction, activeTime, easeOutTime, Linear, priority);
}
public void ActivateTimeDilation(double factor, double easeInTime, double activeTime, double easeOutTime, System.Func<double, double, double, double, double> easeOutFunction, int priority)
{
ActivateTimeDilation(factor, easeInTime, Linear, activeTime, easeOutTime, easeOutFunction, priority);
}
public void ActivateTimeDilation(double factor, double easeInTime, System.Func<double, double, double, double, double> easeInFunction, double activeTime, double easeOutTime, System.Func<double, double, double, double, double> easeOutFunction, int priority)
{
if (priority <= minPriority)
{
newTimeDilationData = true;
nextFrameTimeDilationData = new TimeDilationData
if (data.elapsedTime > data.easeInTime + data.activeTime + data.easeOutTime)
{
elapsedTime = 0,
easeInTime = easeInTime,
easeInFunction = easeInFunction,
activeTime = activeTime,
easeOutTime = easeOutTime,
easeOutFunction = easeOutFunction,
factor = factor
};
timeDilationDatas.RemoveAt(i);
}
else
{
timeDilationDatas[i] = data;
}
}
}
public void ActivateTimeDilation(double factor, double easeInTime, double activeTime, double easeOutTime)
{
ActivateTimeDilation(factor, easeInTime, Linear, activeTime, easeOutTime, Linear);
}
public void ActivateTimeDilation(double factor, double easeInTime, System.Func<double, double, double, double, double> easeInFunction, double activeTime, double easeOutTime)
{
ActivateTimeDilation(factor, easeInTime, easeInFunction, activeTime, easeOutTime, Linear);
}
public void ActivateTimeDilation(double factor, double easeInTime, double activeTime, double easeOutTime, System.Func<double, double, double, double, double> easeOutFunction)
{
ActivateTimeDilation(factor, easeInTime, Linear, activeTime, easeOutTime, easeOutFunction);
}
public void ActivateTimeDilation(double factor, double easeInTime, System.Func<double, double, double, double, double> easeInFunction, double activeTime, double easeOutTime, System.Func<double, double, double, double, double> easeOutFunction)
{
timeDilationDatas.Add(new TimeDilationData
{
elapsedTime = 0,
easeInTime = easeInTime,
easeInFunction = easeInFunction,
activeTime = activeTime,
easeOutTime = easeOutTime,
easeOutFunction = easeOutFunction,
factor = factor
});
}
}
}

View File

@ -234,22 +234,8 @@ namespace Encompass
var writePriorities = new Dictionary<Type, HashSet<int>>();
var writeMessageToEngines = new Dictionary<Type, List<Engine>>();
var timeDilationPriorities = new Dictionary<int, HashSet<Engine>>();
foreach (var engine in engines)
{
var timeDilationPriorityAttribute = engine.GetType().GetCustomAttribute<TimeDilationPriority>();
if (timeDilationPriorityAttribute != null)
{
engine.timeDilationPriority = timeDilationPriorityAttribute.timeDilationPriority;
if (!timeDilationPriorities.ContainsKey(timeDilationPriorityAttribute.timeDilationPriority))
{
timeDilationPriorities.Add(timeDilationPriorityAttribute.timeDilationPriority, new HashSet<Engine>());
}
timeDilationPriorities[timeDilationPriorityAttribute.timeDilationPriority].Add(engine);
}
if (engine.GetType().GetCustomAttribute<IgnoresTimeDilation>() != null)
{
engine.usesTimeDilation = false;
@ -344,18 +330,6 @@ namespace Encompass
throw new EngineWriteConflictException(errorString);
}
foreach (var timeDilationEngines in timeDilationPriorities)
{
var priority = timeDilationEngines.Key;
var engines = timeDilationEngines.Value;
if (engines.Count > 1)
{
var errorString = "Multiple Engines have the same Time Dilation Priority value: ";
errorString += string.Join(", ", engines);
throw new TimeDilationPriorityConflictException(errorString);
}
}
var engineOrder = new List<Engine>();
foreach (var engine in engineGraph.TopologicalSort())
{

View File

@ -960,7 +960,6 @@ namespace Tests
static double dilatedDeltaTime;
[TimeDilationPriority(0)]
class ActivateTimeDilationEngine : Engine
{
public override void Update(double dt)
@ -1001,54 +1000,39 @@ namespace Tests
dilatedDeltaTime.Should().BeApproximately(0.3, 0.01);
}
class ActivateTimeDilationWithoutPriorityEngine : Engine
class ActivateTimeDilationLowerFactorEngine : Engine
{
private bool activated = false;
public override void Update(double dt)
{
ActivateTimeDilation(0.2, 1, 1, 1);
}
}
[Test]
public void ActivateTimeDilationWithoutPriorityThrows()
{
var worldBuilder = new WorldBuilder();
worldBuilder.AddEngine(new ActivateTimeDilationWithoutPriorityEngine());
var world = worldBuilder.Build();
Assert.Throws<TimeDilationPriorityUndefinedException>(() => world.Update(0.01));
}
[TimeDilationPriority(0)]
class ActivateTimeDilationLowerPriorityEngine : Engine
{
public override void Update(double dt)
{
if (!TimeDilationActive)
if (!activated)
{
ActivateTimeDilation(0.2, 1, 1, 1);
}
else
{
dilatedDeltaTime = dt;
activated = true;
}
}
}
[TimeDilationPriority(1)]
class ActivateTimeDilationHigherPriorityEngine : Engine
class ActivateTimeDilationHigherFactorEngine : Engine
{
private bool activated = false;
public override void Update(double dt)
{
if (!activated)
{
ActivateTimeDilation(0.5, 1, 1, 1);
activated = true;
}
}
}
class ReadDilatedDeltaTimeEngine : Engine
{
public override void Update(double dt)
{
if (!TimeDilationActive)
{
ActivateTimeDilation(0.5, 1, 1, 1);
}
else
{
dilatedDeltaTime = dt;
}
dilatedDeltaTime = dt;
}
}
@ -1056,26 +1040,21 @@ namespace Tests
public void MultipleActivateTimeDilation()
{
var worldBuilder = new WorldBuilder();
worldBuilder.AddEngine(new ActivateTimeDilationLowerPriorityEngine());
worldBuilder.AddEngine(new ActivateTimeDilationHigherPriorityEngine());
worldBuilder.AddEngine(new ReadDilatedDeltaTimeEngine());
worldBuilder.AddEngine(new ActivateTimeDilationLowerFactorEngine());
worldBuilder.AddEngine(new ActivateTimeDilationHigherFactorEngine());
var world = worldBuilder.Build();
world.Update(0.01); // activate time dilation
world.Update(0.5);
world.Update(0.5); // 0.3 and 0.375
dilatedDeltaTime.Should().BeApproximately(0.3, 0.01);
}
dilatedDeltaTime.Should().BeApproximately(0.3375, 0.01);
[Test]
public void MultipleActivateTimeDilationWithDuplicatePriority()
{
var worldBuilder = new WorldBuilder();
worldBuilder.AddEngine(new ActivateTimeDilationEngine());
worldBuilder.AddEngine(new ActivateTimeDilationLowerPriorityEngine());
world.Update(5);
Assert.Throws<TimeDilationPriorityConflictException>(() => worldBuilder.Build());
dilatedDeltaTime.Should().BeApproximately(5, 0.01);
}
static double undilatedDeltaTime;