Skip to content

Commit 6231f04

Browse files
authored
Merge pull request #15 from AbroGames/2.2.0
2.2.0
2 parents b998357 + 4f7d32e commit 6231f04

30 files changed

Lines changed: 723 additions & 229 deletions

KludgeBox/Core/CmdArgsService.cs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
using Godot;
22
using KludgeBox.DI.Requests.LoggerInjection;
3-
using KludgeBox.Logging;
43
using Serilog;
54

65
namespace KludgeBox.Core;
@@ -10,9 +9,9 @@ public class CmdArgsService
109

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

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

1716
[Logger] private ILogger _log;
1817

@@ -29,7 +28,7 @@ public void LogCmdArgs()
2928
{
3029
if (!CmdArgs.IsEmpty())
3130
{
32-
_log.Information("Cmd args: " + CmdArgs.Join());
31+
_log.Information("Cmd args: {args}", CmdArgs.Join());
3332
}
3433
else
3534
{
Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
namespace KludgeBox.Core.Cooldown;
22

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

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

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

21-
_timeLeft -= deltaTime;
22-
while (_timeLeft <= 0)
24+
TimeLeft -= deltaTime;
25+
while (TimeLeft <= 0)
2326
{
24-
_timeLeft += Duration;
27+
TimeLeft += Duration;
2528
ActivateAction();
2629
}
2730
}
@@ -31,8 +34,8 @@ public void Update(double deltaTime)
3134
/// </summary>
3235
public void Reset()
3336
{
34-
_timeLeft = Duration;
35-
_isActivated = false;
37+
TimeLeft = Duration;
38+
IsActivated = false;
3639
}
3740

3841
/// <summary>
@@ -41,16 +44,16 @@ public void Reset()
4144
public void Restart()
4245
{
4346
Reset();
44-
_isActivated = true;
47+
IsActivated = true;
4548
}
4649

4750
public void Start()
4851
{
49-
_isActivated = true;
52+
IsActivated = true;
5053
}
5154

5255
public void Pause()
5356
{
54-
_isActivated = false;
57+
IsActivated = false;
5558
}
5659
}

KludgeBox/Core/Cooldown/Cooldown.cs

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,19 @@ public abstract class Cooldown
66
public double Duration { get; } = 0;
77

88
//Gets elapsed time in seconds
9-
public double ElapsedTime => Duration - _timeLeft;
9+
public double ElapsedTime => Duration - TimeLeft;
1010
//Gets time left in seconds
11-
public double TimeLeft => _timeLeft;
11+
public double TimeLeft { get; protected set; } = 0;
12+
public bool IsActivated { get; protected set; } = false;
1213

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

1617
public event Action ActionWhenReady;
17-
18-
protected double _timeLeft = 0;
19-
protected bool _isActivated = false;
20-
21-
/// <summary>
22-
/// Initializes a new instance of the <see cref="Cooldown"/> class with the specified duration.
23-
/// </summary>
18+
2419
/// <param name="duration">The duration of the cooldown in seconds.</param>
20+
/// <param name="isActivated">If false, the cooldown starts only after manually calling <c>Start()</c>.</param>
21+
/// <param name="actionWhenReady">Invoked when the counter completes.</param>
2522
public Cooldown(double duration, bool isActivated = true, Action actionWhenReady = null)
2623
{
2724
if (duration <= 0)
@@ -30,8 +27,8 @@ public Cooldown(double duration, bool isActivated = true, Action actionWhenReady
3027
}
3128

3229
Duration = duration;
33-
_timeLeft = duration;
34-
_isActivated = isActivated;
30+
TimeLeft = duration;
31+
IsActivated = isActivated;
3532
ActionWhenReady = actionWhenReady;
3633
}
3734

Lines changed: 25 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,31 @@
11
namespace KludgeBox.Core.Cooldown;
22

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

610
//Cooldown ended, time left and actions executed
7-
public bool IsCompleted => _isCompleted;
8-
9-
private bool _isCompleted = false;
11+
public bool IsCompleted { get; private set; } = false;
1012

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

2026
if (isCompleted)
2127
{
22-
_timeLeft = 0;
28+
TimeLeft = 0;
2329
}
2430
}
2531

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

34-
_timeLeft -= deltaTime;
35-
if (_timeLeft <= 0)
40+
TimeLeft -= deltaTime;
41+
if (TimeLeft <= 0)
3642
{
37-
_timeLeft = 0;
38-
_isCompleted = true;
39-
_isActivated = false;
43+
TimeLeft = 0;
44+
IsCompleted = true;
45+
IsActivated = false;
4046
ActivateAction();
4147
}
4248
}
@@ -46,9 +52,9 @@ public void Update(double deltaTime)
4652
/// </summary>
4753
public void Reset()
4854
{
49-
_timeLeft = Duration;
50-
_isCompleted = false;
51-
_isActivated = false;
55+
TimeLeft = Duration;
56+
IsCompleted = false;
57+
IsActivated = false;
5258
}
5359

5460
/// <summary>
@@ -57,18 +63,18 @@ public void Reset()
5763
public void Restart()
5864
{
5965
Reset();
60-
_isActivated = true;
66+
IsActivated = true;
6167
}
6268

6369
public void Start()
6470
{
65-
if (_isCompleted) return;
66-
_isActivated = true;
71+
if (IsCompleted) return;
72+
IsActivated = true;
6773
}
6874

6975
public void Pause()
7076
{
71-
if (_isCompleted) return;
72-
_isActivated = false;
77+
if (IsCompleted) return;
78+
IsActivated = false;
7379
}
7480
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
namespace KludgeBox.Core.Stats;
2+
3+
public class StatModifier<TStat>
4+
{
5+
public enum ModifierType { Additive, Multiplicative }
6+
7+
public readonly TStat Stat;
8+
public readonly ModifierType Type;
9+
public readonly double Value;
10+
11+
public StatModifier(TStat stat, ModifierType type, double value)
12+
{
13+
Stat = stat;
14+
Type = type;
15+
Value = value;
16+
}
17+
18+
public static StatModifier<TStat> CreateAdditive(TStat stat, double value)
19+
{
20+
return new StatModifier<TStat>(stat, ModifierType.Additive, value);
21+
}
22+
23+
public static StatModifier<TStat> CreateMultiplicative(TStat stat, double value)
24+
{
25+
return new StatModifier<TStat>(stat, ModifierType.Multiplicative, value);
26+
}
27+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
namespace KludgeBox.Core.Stats;
2+
3+
public class StatModifiersContainer<TStat>
4+
{
5+
private readonly HashSet<StatModifier<TStat>> _statsModifiers = new();
6+
7+
private readonly Dictionary<TStat, double> _cacheAdditive = new();
8+
private readonly Dictionary<TStat, double> _cacheMultiplicative = new();
9+
private readonly HashSet<(TStat, StatModifier<TStat>.ModifierType)> _needToInvalidateCache = new();
10+
11+
public void AddStatModifier(StatModifier<TStat> statModifier)
12+
{
13+
AddTaskToInvalidateCache(statModifier);
14+
_statsModifiers.Add(statModifier);
15+
}
16+
17+
public bool RemoveStatModifier(StatModifier<TStat> statModifier)
18+
{
19+
AddTaskToInvalidateCache(statModifier);
20+
return _statsModifiers.Remove(statModifier);
21+
}
22+
23+
public double GetStat(TStat stat, double baseValue = 0)
24+
{
25+
double additiveValue = GetStatValue(stat, StatModifier<TStat>.ModifierType.Additive);
26+
double multiplicativeValue = GetStatValue(stat, StatModifier<TStat>.ModifierType.Multiplicative);
27+
return (baseValue + additiveValue) * multiplicativeValue;
28+
}
29+
30+
public double GetStatValue(TStat stat, StatModifier<TStat>.ModifierType type)
31+
{
32+
if (_needToInvalidateCache.Contains((stat, type))) RecalculateCache(stat, type);
33+
return GetCacheInfo(type).Dictionary.GetValueOrDefault(stat, GetCacheInfo(type).DefaultValue);
34+
}
35+
36+
private void AddTaskToInvalidateCache(StatModifier<TStat> statModifier)
37+
{
38+
_needToInvalidateCache.Add((statModifier.Stat, statModifier.Type));
39+
}
40+
41+
private void RecalculateCache(TStat stat, StatModifier<TStat>.ModifierType type)
42+
{
43+
GetCacheInfo(type).Dictionary[stat] = _statsModifiers
44+
.Where(sm => sm.Stat.Equals(stat))
45+
.Where(sm => sm.Type == type)
46+
.Select(sm => sm.Value)
47+
.Aggregate(GetCacheInfo(type).DefaultValue, GetCacheInfo(type).Operation);
48+
49+
_needToInvalidateCache.Remove((stat, type));
50+
}
51+
52+
private record CacheInfo(
53+
Dictionary<TStat, double> Dictionary,
54+
Func<double, double, double> Operation,
55+
double DefaultValue);
56+
57+
private CacheInfo GetCacheInfo(StatModifier<TStat>.ModifierType type)
58+
{
59+
return type switch
60+
{
61+
StatModifier<TStat>.ModifierType.Additive =>
62+
new CacheInfo(_cacheAdditive, (d1, d2) => d1 + d2, 0),
63+
StatModifier<TStat>.ModifierType.Multiplicative =>
64+
new CacheInfo(_cacheMultiplicative, (d1, d2) => d1 * d2, 1),
65+
_ => throw new ArgumentException("Unknown ModifierType: " + type)
66+
};
67+
}
68+
69+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
using KludgeBox.DI.Requests.LoggerInjection;
2+
using Serilog;
3+
4+
namespace KludgeBox.Core;
5+
6+
public class TypesStorageService
7+
{
8+
private readonly Dictionary<int, Type> _typeById = new();
9+
private readonly Dictionary<Type, int> _idByType = new();
10+
11+
[Logger] private ILogger _log;
12+
13+
public TypesStorageService()
14+
{
15+
Di.Process(this);
16+
}
17+
18+
public void AddTypes(List<Type> types)
19+
{
20+
// Find and sort all types (except abstract and interface)
21+
List<Type> filteredTypes = types
22+
.Where(t => !t.IsInterface)
23+
.Where(t => !t.IsAbstract)
24+
.OrderBy(t => t.FullName)
25+
.ToList();
26+
27+
for (int i = 0; i < filteredTypes.Count; i++)
28+
{
29+
Type type = filteredTypes[i];
30+
31+
_typeById[i] = type;
32+
_idByType[type] = i;
33+
}
34+
35+
_log.Information("Add {count} types.", _typeById.Count);
36+
}
37+
38+
public int GetId(Type type)
39+
{
40+
if (_idByType.TryGetValue(type, out int id))
41+
{
42+
return id;
43+
}
44+
throw new KeyNotFoundException($"Type {type.Name} is not found in {nameof(TypesStorageService)}");
45+
}
46+
47+
public int GetId<T>()
48+
{
49+
return GetId(typeof(T));
50+
}
51+
52+
public Type GetType(int id)
53+
{
54+
if (_typeById.TryGetValue(id, out Type type))
55+
{
56+
return type;
57+
}
58+
throw new KeyNotFoundException($"Id {id} is not found in {nameof(TypesStorageService)}.");
59+
}
60+
}

0 commit comments

Comments
 (0)