Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 4 additions & 5 deletions KludgeBox/Core/CmdArgsService.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
using Godot;
using KludgeBox.DI.Requests.LoggerInjection;
using KludgeBox.Logging;
using Serilog;

namespace KludgeBox.Core;
Expand All @@ -10,9 +9,9 @@ public class CmdArgsService

protected readonly string[] CmdArgs = OS.GetCmdlineArgs();

private bool _logIfEmpty; // Write message to log, then param doesn't exist in args
private bool _logIfException; // Write message to log, then we catch Exception while find/parsing param
private bool _logIfSuccessful; // Write message to log, then param successfully found
private bool _logIfEmpty; // Write message to log, if param doesn't exist in args
private bool _logIfException; // Write message to log, if we catch Exception while find/parsing param
private bool _logIfSuccessful; // Write message to log, if param successfully found

[Logger] private ILogger _log;

Expand All @@ -29,7 +28,7 @@ public void LogCmdArgs()
{
if (!CmdArgs.IsEmpty())
{
_log.Information("Cmd args: " + CmdArgs.Join());
_log.Information("Cmd args: {args}", CmdArgs.Join());
}
else
{
Expand Down
27 changes: 15 additions & 12 deletions KludgeBox/Core/Cooldown/AutoCooldown.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
namespace KludgeBox.Core.Cooldown;

/// <summary>
/// A looping timer that counts down and executes the specified action <c>actionWhenReady</c> at the end of each cycle.<br/>
/// Restarts automatically.
/// </summary>
public class AutoCooldown : Cooldown
{

/// <summary>
/// Initializes a new instance of the <see cref="AutoCooldown"/> class with the specified duration.
/// </summary>
/// <param name="duration">The duration of the cooldown in seconds.</param>
/// <param name="isActivated">If false, the cooldown starts only after manually calling <c>Start()</c>.</param>
/// <param name="actionWhenReady">Invoked when the counter completes.</param>
public AutoCooldown(double duration, bool isActivated = true, Action actionWhenReady = null) :
base(duration, isActivated, actionWhenReady) { }

Expand All @@ -16,12 +19,12 @@ public AutoCooldown(double duration, bool isActivated = true, Action actionWhenR
/// <param name="deltaTime">The time elapsed since the last update in seconds.</param>
public void Update(double deltaTime)
{
if (!_isActivated) return;
if (!IsActivated) return;

_timeLeft -= deltaTime;
while (_timeLeft <= 0)
TimeLeft -= deltaTime;
while (TimeLeft <= 0)
{
_timeLeft += Duration;
TimeLeft += Duration;
ActivateAction();
}
}
Expand All @@ -31,8 +34,8 @@ public void Update(double deltaTime)
/// </summary>
public void Reset()
{
_timeLeft = Duration;
_isActivated = false;
TimeLeft = Duration;
IsActivated = false;
}

/// <summary>
Expand All @@ -41,16 +44,16 @@ public void Reset()
public void Restart()
{
Reset();
_isActivated = true;
IsActivated = true;
}

public void Start()
{
_isActivated = true;
IsActivated = true;
}

public void Pause()
{
_isActivated = false;
IsActivated = false;
}
}
19 changes: 8 additions & 11 deletions KludgeBox/Core/Cooldown/Cooldown.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,19 @@ public abstract class Cooldown
public double Duration { get; } = 0;

//Gets elapsed time in seconds
public double ElapsedTime => Duration - _timeLeft;
public double ElapsedTime => Duration - TimeLeft;
//Gets time left in seconds
public double TimeLeft => _timeLeft;
public double TimeLeft { get; protected set; } = 0;
public bool IsActivated { get; protected set; } = false;

//Gets the fraction of the cooldown completed, ranging from 0 to 1.
public double FractionElapsedTime => ElapsedTime / Duration;

public event Action ActionWhenReady;

protected double _timeLeft = 0;
protected bool _isActivated = false;

/// <summary>
/// Initializes a new instance of the <see cref="Cooldown"/> class with the specified duration.
/// </summary>

/// <param name="duration">The duration of the cooldown in seconds.</param>
/// <param name="isActivated">If false, the cooldown starts only after manually calling <c>Start()</c>.</param>
/// <param name="actionWhenReady">Invoked when the counter completes.</param>
public Cooldown(double duration, bool isActivated = true, Action actionWhenReady = null)
{
if (duration <= 0)
Expand All @@ -30,8 +27,8 @@ public Cooldown(double duration, bool isActivated = true, Action actionWhenReady
}

Duration = duration;
_timeLeft = duration;
_isActivated = isActivated;
TimeLeft = duration;
IsActivated = isActivated;
ActionWhenReady = actionWhenReady;
}

Expand Down
44 changes: 25 additions & 19 deletions KludgeBox/Core/Cooldown/ManualCooldown.cs
Original file line number Diff line number Diff line change
@@ -1,25 +1,31 @@
namespace KludgeBox.Core.Cooldown;

/// <summary>
/// A timer that counts down once and executes the specified <c>actionWhenReady</c> upon completion.<br/>
/// To run it again, you must manually call <c>Restart()</c>.
/// </summary>
public class ManualCooldown : Cooldown
{

//Cooldown ended, time left and actions executed
public bool IsCompleted => _isCompleted;

private bool _isCompleted = false;
public bool IsCompleted { get; private set; } = false;

/// <summary>
/// Initializes a new instance of the <see cref="ManualCooldown"/> class with the specified duration.
/// </summary>
/// <param name="duration">The duration of the cooldown in seconds.</param>
/// <param name="isCompleted">If true, the cooldown is immediately set to the completed state upon creation.<br/>
/// If <c>isActivated</c> is also true, <c>actionWhenReady</c> will be executed on the first <c>Update()</c> call.</param>
/// <param name="isActivated">If false, the cooldown starts only after manually calling <c>Start()</c>.</param>
/// <param name="actionWhenReady">Invoked when the counter completes.</param>
public ManualCooldown(double duration, bool isCompleted = false, bool isActivated = true, Action actionWhenReady = null) :
base(duration, isActivated, actionWhenReady)
{
_isCompleted = isCompleted;
IsCompleted = isCompleted;

if (isCompleted)
{
_timeLeft = 0;
TimeLeft = 0;
}
}

Expand All @@ -29,14 +35,14 @@ public ManualCooldown(double duration, bool isCompleted = false, bool isActivate
/// <param name="deltaTime">The time elapsed since the last update in seconds.</param>
public void Update(double deltaTime)
{
if (!_isActivated) return;
if (!IsActivated) return;

_timeLeft -= deltaTime;
if (_timeLeft <= 0)
TimeLeft -= deltaTime;
if (TimeLeft <= 0)
{
_timeLeft = 0;
_isCompleted = true;
_isActivated = false;
TimeLeft = 0;
IsCompleted = true;
IsActivated = false;
ActivateAction();
}
}
Expand All @@ -46,9 +52,9 @@ public void Update(double deltaTime)
/// </summary>
public void Reset()
{
_timeLeft = Duration;
_isCompleted = false;
_isActivated = false;
TimeLeft = Duration;
IsCompleted = false;
IsActivated = false;
}

/// <summary>
Expand All @@ -57,18 +63,18 @@ public void Reset()
public void Restart()
{
Reset();
_isActivated = true;
IsActivated = true;
}

public void Start()
{
if (_isCompleted) return;
_isActivated = true;
if (IsCompleted) return;
IsActivated = true;
}

public void Pause()
{
if (_isCompleted) return;
_isActivated = false;
if (IsCompleted) return;
IsActivated = false;
}
}
27 changes: 27 additions & 0 deletions KludgeBox/Core/Stats/StatModifier.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
namespace KludgeBox.Core.Stats;

public class StatModifier<TStat>
{
public enum ModifierType { Additive, Multiplicative }

public readonly TStat Stat;
public readonly ModifierType Type;
public readonly double Value;

public StatModifier(TStat stat, ModifierType type, double value)
{
Stat = stat;
Type = type;
Value = value;
}

public static StatModifier<TStat> CreateAdditive(TStat stat, double value)
{
return new StatModifier<TStat>(stat, ModifierType.Additive, value);
}

public static StatModifier<TStat> CreateMultiplicative(TStat stat, double value)
{
return new StatModifier<TStat>(stat, ModifierType.Multiplicative, value);
}
}
69 changes: 69 additions & 0 deletions KludgeBox/Core/Stats/StatModifiersContainer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
namespace KludgeBox.Core.Stats;

public class StatModifiersContainer<TStat>
{
private readonly HashSet<StatModifier<TStat>> _statsModifiers = new();

private readonly Dictionary<TStat, double> _cacheAdditive = new();
private readonly Dictionary<TStat, double> _cacheMultiplicative = new();
private readonly HashSet<(TStat, StatModifier<TStat>.ModifierType)> _needToInvalidateCache = new();

public void AddStatModifier(StatModifier<TStat> statModifier)
{
AddTaskToInvalidateCache(statModifier);
_statsModifiers.Add(statModifier);
}

public bool RemoveStatModifier(StatModifier<TStat> statModifier)
{
AddTaskToInvalidateCache(statModifier);
return _statsModifiers.Remove(statModifier);
}

public double GetStat(TStat stat, double baseValue = 0)
{
double additiveValue = GetStatValue(stat, StatModifier<TStat>.ModifierType.Additive);
double multiplicativeValue = GetStatValue(stat, StatModifier<TStat>.ModifierType.Multiplicative);
return (baseValue + additiveValue) * multiplicativeValue;
}

public double GetStatValue(TStat stat, StatModifier<TStat>.ModifierType type)
{
if (_needToInvalidateCache.Contains((stat, type))) RecalculateCache(stat, type);
return GetCacheInfo(type).Dictionary.GetValueOrDefault(stat, GetCacheInfo(type).DefaultValue);
}

private void AddTaskToInvalidateCache(StatModifier<TStat> statModifier)
{
_needToInvalidateCache.Add((statModifier.Stat, statModifier.Type));
}

private void RecalculateCache(TStat stat, StatModifier<TStat>.ModifierType type)
{
GetCacheInfo(type).Dictionary[stat] = _statsModifiers
.Where(sm => sm.Stat.Equals(stat))
.Where(sm => sm.Type == type)
.Select(sm => sm.Value)
.Aggregate(GetCacheInfo(type).DefaultValue, GetCacheInfo(type).Operation);

_needToInvalidateCache.Remove((stat, type));
}

private record CacheInfo(
Dictionary<TStat, double> Dictionary,
Func<double, double, double> Operation,
double DefaultValue);

private CacheInfo GetCacheInfo(StatModifier<TStat>.ModifierType type)
{
return type switch
{
StatModifier<TStat>.ModifierType.Additive =>
new CacheInfo(_cacheAdditive, (d1, d2) => d1 + d2, 0),
StatModifier<TStat>.ModifierType.Multiplicative =>
new CacheInfo(_cacheMultiplicative, (d1, d2) => d1 * d2, 1),
_ => throw new ArgumentException("Unknown ModifierType: " + type)
};
}

}
60 changes: 60 additions & 0 deletions KludgeBox/Core/TypesStorageService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
using KludgeBox.DI.Requests.LoggerInjection;
using Serilog;

namespace KludgeBox.Core;

public class TypesStorageService
{
private readonly Dictionary<int, Type> _typeById = new();
private readonly Dictionary<Type, int> _idByType = new();

[Logger] private ILogger _log;

public TypesStorageService()
{
Di.Process(this);
}

public void AddTypes(List<Type> types)
{
// Find and sort all types (except abstract and interface)
List<Type> filteredTypes = types
.Where(t => !t.IsInterface)
.Where(t => !t.IsAbstract)
.OrderBy(t => t.FullName)
.ToList();

for (int i = 0; i < filteredTypes.Count; i++)
{
Type type = filteredTypes[i];

_typeById[i] = type;
_idByType[type] = i;
}

_log.Information("Add {count} types.", _typeById.Count);
}

public int GetId(Type type)
{
if (_idByType.TryGetValue(type, out int id))
{
return id;
}
throw new KeyNotFoundException($"Type {type.Name} is not found in {nameof(TypesStorageService)}");
}

public int GetId<T>()
{
return GetId(typeof(T));
}

public Type GetType(int id)
{
if (_typeById.TryGetValue(id, out Type type))
{
return type;
}
throw new KeyNotFoundException($"Id {id} is not found in {nameof(TypesStorageService)}.");
}
}
Loading