Skip to content
Open
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
3 changes: 2 additions & 1 deletion Heck/Animation/PointDefinition/PointDefinition.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Heck.BaseProvider;
using ModestTree;

namespace Heck.Animation;
Expand Down Expand Up @@ -170,7 +171,7 @@ private static IEnumerable<IGrouping<GroupType, object>> Group(IEnumerable<objec
{
return n switch
{
string s when !s.StartsWith("base") => GroupType.Flag,
string s when !BaseProviderManager.Instance.IsProviderString(s) => GroupType.Flag,
List<object> => GroupType.Modifier,
_ => GroupType.Value
};
Expand Down
6 changes: 3 additions & 3 deletions Heck/Animation/PointDefinition/Values.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@

namespace Heck.Animation;

internal interface IValues
public interface IValues
{
public float[] Values { get; }
}

internal interface IRotationValues
public interface IRotationValues
{
public Quaternion Rotation { get; }
}
Expand All @@ -36,7 +36,7 @@ internal BaseProviderValues(float[] values)
public float[] Values { get; }
}

internal abstract record UpdateableValues : IValues
public abstract record UpdateableValues : IValues
{
public abstract float[] Values { get; }

Expand Down
183 changes: 142 additions & 41 deletions Heck/Services/BaseProvider/BaseProviderManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,23 @@

namespace Heck.BaseProvider;

internal class BaseProviderManager : ITickable
public class BaseProviderManager : ITickable
{
private readonly Dictionary<string, IValues> _baseProviders = new();
private readonly HashSet<UpdateableValues> _updateableBaseProviders = [];
private readonly Dictionary<string, UpdateableValues> _updateableProviders = new();
private readonly Dictionary<string, DynamicProvider> _dynamicProviders = new();
private readonly Dictionary<string, DynamicSeperator> _dynamicSeperators = new();
private readonly Dictionary<string, UpdateableValues> _updateableDynamicProviders = new();
private readonly List<DynamicModifier> _dynamicModifiers = new();

[UsedImplicitly]
private BaseProviderManager(
[Inject(Optional = true, Source = InjectSources.Local)]
IEnumerable<IBaseProvider> baseProviders)
{
Instance = this;
AddModifierHandler(DefaultModifier);
foreach (IBaseProvider baseProvider in baseProviders)
{
foreach (PropertyInfo propertyInfo in baseProvider.GetType().GetProperties(AccessTools.allDeclared))
Expand Down Expand Up @@ -50,6 +55,12 @@ private BaseProviderManager(
}
}

public delegate UpdateableValues? DynamicModifier(string key, IValues provider, out string rest);

public delegate IValues? DynamicProvider(string key);

public delegate string DynamicSeperator(string key, out string rest);

// I couldnt think of a way to di this thing
internal static BaseProviderManager Instance { get; private set; } = null!;

Expand All @@ -60,69 +71,159 @@ public void Tick()
updatableProvidersValue.Update();
}

foreach (UpdateableValues updatableDynamicProvidersValue in _updateableDynamicProviders.Values)
{
updatableDynamicProvidersValue.Update();
}

foreach (UpdateableValues updateableBaseProvider in _updateableBaseProviders)
{
updateableBaseProvider.Update();
}
}

// Clear cache when song ends to not keep updating unneeded values
public void Clear()
[PublicAPI]
public void AddModifierHandler(DynamicModifier modifier)
{
_updateableProviders.Clear();
_dynamicModifiers.Add(modifier);
}

internal IValues GetProviderValues(string key)
[PublicAPI]
public void AddDynamicProvider(string startsWith, DynamicProvider dynamicProvider)
{
string[] splits = key.Split('.');
IValues result = _baseProviders[splits[0]];
_dynamicProviders.Add(startsWith, dynamicProvider);
}

if (splits.Length == 1)
{
return result;
}
[PublicAPI]
public void AddDynamicSeperator(string startsWith, DynamicSeperator dynamicProvider)
{
_dynamicSeperators.Add(startsWith, dynamicProvider);
}

[PublicAPI]
public IValues GetProviderValues(string key)
{
string rest;
IValues result = GetProvider(key, out rest);

if (_updateableProviders.TryGetValue(key, out UpdateableValues cachedValues))
{
return cachedValues;
}

for (int i = 1; i < splits.Length; i++)

while (rest != String.Empty)
{
string split = splits[i];
string subKey = string.Join(".", splits.Take(i));
if (!_updateableProviders.TryGetValue(subKey, out UpdateableValues updateableValues))
UpdateableValues updateableValues = ApplyModifiers(rest, result, out rest);
string subkey = key.Substring(0, key.Length - rest.Length - 1);
if (!_updateableProviders.ContainsKey(subkey))
{
if (split.StartsWith("s"))
{
float mult = float.Parse(split.Substring(1).Replace('_', '.'));
updateableValues = result is IRotationValues rotationValues
? new SmoothRotationProvidersValues(rotationValues, mult)
: new SmoothProvidersValues(result.Values, mult);
}
else
{
int[] parts = split
.Select(
n => n switch
{
'x' => 0,
'y' => 1,
'z' => 2,
'w' => 3,
_ => throw new ArgumentOutOfRangeException(nameof(n), n, null)
})
.ToArray();

updateableValues = new PartialProviderValues(result.Values, parts);
}

_updateableProviders[subKey] = updateableValues;
_updateableProviders.Add(subkey, updateableValues);
}

result = updateableValues;
result = _updateableProviders[subkey];
}

return result;
}

internal bool IsProviderString(string key)
{
return key.StartsWith("base")
|| _dynamicProviders.Keys.Any(key.StartsWith);
}

// Clear cache when song ends to not keep updating unneeded values
internal void Clear()
{
_updateableProviders.Clear();
_updateableDynamicProviders.Clear();
}

private IValues GetProvider(string key, out string modifiers)
{
var splits = key.Split(['.'], 2);
var start = splits[0];
modifiers = splits.Length > 1 ? splits[1] : string.Empty;
if (_baseProviders.TryGetValue(splits[0], out var baseProvider))
{
return baseProvider;
}

foreach (var providerKey in _dynamicProviders.Keys.Where(key.StartsWith))
{
if (_dynamicSeperators.TryGetValue(providerKey, out var seperator))
{
start = seperator.Invoke(key, out modifiers);
}

if (_updateableDynamicProviders.TryGetValue(start, out var dynamicProvider))
{
return dynamicProvider;
}

var provider = _dynamicProviders[providerKey].Invoke(start);

if (provider is null)
{
continue;
}

if (provider is UpdateableValues updateableProvider)
{
_updateableDynamicProviders.Add(start, updateableProvider);
}

return provider;
}

throw new Exception($"No provider found for: \"{key}\"");
}

private UpdateableValues ApplyModifiers(string modifiers, IValues baseValue, out string rest)
{
foreach (var modifier in _dynamicModifiers)
{
var modifiersValue = modifier(modifiers, baseValue, out rest);
if (modifiersValue is not null)
{
return modifiersValue;
}
}

throw new Exception($"No modifier found for: \"{modifiers}\"");
}

private UpdateableValues? DefaultModifier(string modifiers, IValues baseValue, out string rest)
{
var splits = modifiers.Split(['.'], 2);
var modifier = splits[0];
rest = splits.Length > 1 ? splits[1] : string.Empty;

switch (modifier[0])
{
case 's':
float mult = float.Parse(modifier.Substring(1).Replace('_', '.'));
return baseValue is IRotationValues rotationValues
? new SmoothRotationProvidersValues(rotationValues, mult)
: new SmoothProvidersValues(baseValue.Values, mult);

case 'x' or 'y' or 'z' or 'w':
int[] parts = modifier
.Select(
n => n switch
{
'x' => 0,
'y' => 1,
'z' => 2,
'w' => 3,
_ => throw new ArgumentOutOfRangeException(nameof(n), n, null)
})
.ToArray();

return new PartialProviderValues(baseValue.Values, parts);
}

return null;
}
}