Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add DynamicVariableIdentity struct and more extensions #97

Merged
merged 1 commit into from
Feb 6, 2025
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
151 changes: 151 additions & 0 deletions MonkeyLoader.Resonite.Integration/DynamicVariableExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,107 @@ public static DynamicVariableSpace CreateSpace(this Slot slot, string? spaceName
public static DynamicVariableSpace FindOrCreateSpace(this Slot slot, string? spaceName, bool onlyDirectBinding = false)
=> slot.FindSpace(spaceName!) ?? CreateSpace(slot, spaceName, onlyDirectBinding);

/// <summary>
/// Gets all <see cref="DynamicVariableSpace"/>s that apply to this <see cref="Slot"/>.<br/>
/// Optionally includes only those that pass through the <paramref name="filter"/>.
/// </summary>
/// <remarks>
/// This function is different from a regular
/// <c><see cref="Slot"/>.<see cref="Slot.GetComponentInParents{T}(Predicate{T}, bool, bool)">GetComponentsInParents</see>&lt;<see cref="DynamicVariableSpace"/>&gt;()</c>
/// call,<br/> as it considers that <see cref="DynamicVariableSpace"/>s deeper in the hierarchy
/// hide ones higher up with the same <see cref="DynamicVariableSpace.SpaceName">name</see>.<br/>
/// If a <see cref="DynamicVariableSpace"/> deeper in the hierarchy doesn't pass the <paramref name="filter"/>,<br/>
/// it will still hide any higher up ones with the same <see cref="DynamicVariableSpace.SpaceName">name</see>
/// that might pass it, because they don't apply to this <see cref="Slot"/>.
/// </remarks>
/// <param name="slot">The <see cref="Slot"/> to find all applicable <see cref="DynamicVariableSpace"/>s for.</param>
/// <param name="filter">The optional predicate to apply to the returned </param>
/// <returns>All <see cref="DynamicVariableSpace"/> that apply to this <see cref="Slot"/> and optionally pass the <paramref name="filter"/>.</returns>
public static IEnumerable<DynamicVariableSpace> GetAvailableSpaces(this Slot slot, Predicate<DynamicVariableSpace>? filter = null)
{
filter ??= Filter;
var result = new List<DynamicVariableSpace>();
var presentNames = Pool.BorrowHashSet<string>();

while (slot is not null)
{
var currentSpaces = slot.GetComponents<DynamicVariableSpace>();

foreach (var currentSpace in currentSpaces)
{
if (!filter(currentSpace))
{
presentNames.Add(currentSpace.SpaceName);
continue;
}

if (presentNames.Contains(currentSpace.SpaceName))
continue;

result.Add(currentSpace);
presentNames.Add(currentSpace.SpaceName.Value);
}

slot = slot.Parent;
Nytra marked this conversation as resolved.
Show resolved Hide resolved
}

Pool.Return(ref presentNames);

return [.. result];
}

/// <summary>
/// Gets all <see cref="DynamicVariableIdentity">full Dynamic Variable
/// identities</see> that apply to this <see cref="Slot"/>,
/// which can be assigned a value of the given <see cref="Type"/>.
/// </summary>
/// <param name="slot">The <see cref="Slot"/> to find all applicable full Dynamic Variable identities for.</param>
/// <param name="type">The type that must be assignable to the variables.</param>
/// <returns>All full Dynamic Variable identities that apply to this <see cref="Slot"/> that the given <see cref="Type"/> can be assigned to.</returns>
/// <inheritdoc cref="GetAvailableVariableIdentities(Slot)"/>
public static IEnumerable<DynamicVariableIdentity> GetAvailableVariableIdentities(this Slot slot, Type type)
=> slot.GetAvailableSpaces().SelectMany(space => space.GetVariableIdentities(type)).ToArray();

/// <summary>
/// Gets all <see cref="DynamicVariableIdentity">full Dynamic Variable
/// identities</see> that apply to this <see cref="Slot"/>,
/// which match the given <paramref name="name"/>.
/// </summary>
/// <param name="slot">The <see cref="Slot"/> to find all applicable full Dynamic Variable identities for.</param>
/// <param name="name">The name that the variable identities must have.</param>
/// <returns>All full Dynamic Variable identities that apply to this <see cref="Slot"/> that have the given <paramref name="name"/>.</returns>
/// <inheritdoc cref="GetAvailableVariableIdentities(Slot)"/>
public static IEnumerable<DynamicVariableIdentity> GetAvailableVariableIdentities(this Slot slot, string name)
=> slot.GetAvailableSpaces().SelectMany(space => space.GetVariableIdentities(name)).ToArray();

/// <summary>
/// Gets all <see cref="DynamicVariableIdentity">full Dynamic Variable
/// identities</see> that apply to this <see cref="Slot"/>,
/// which can be assigned a value of type <typeparamref name="T"/>.
/// </summary>
/// <typeparam name="T">The type that must be assignable to the variables.</typeparam>
/// <returns>All full Dynamic Variable identities that apply to this <see cref="Slot"/> that <typeparamref name="T"/> can be assigned to.</returns>
/// <inheritdoc cref="GetAvailableVariableIdentities(Slot)"/>
public static IEnumerable<DynamicVariableIdentity> GetAvailableVariableIdentities<T>(this Slot slot)
=> slot.GetAvailableSpaces().SelectMany(GetVariableIdentities<T>).ToArray();

/// <summary>
/// Gets all <see cref="DynamicVariableIdentity">full Dynamic Variable
/// identities</see> that apply to this <see cref="Slot"/>
/// </summary>
/// <remarks>
/// This function uses
/// <c><see cref="DynamicVariableSpace"/>.<see cref="GetAvailableSpaces(Slot, Predicate{DynamicVariableSpace}?)">GetAvailableSpaces</see>()</c>,<br/>
/// which is different from a regular
/// <c><see cref="Slot"/>.<see cref="Slot.GetComponentInParents{T}(Predicate{T}, bool, bool)">GetComponentsInParents</see>&lt;<see cref="DynamicVariableSpace"/>&gt;()</c>
/// call,<br/> as it considers that <see cref="DynamicVariableSpace"/>s deeper in the hierarchy
/// hide ones higher up with the same <see cref="DynamicVariableSpace.SpaceName">name</see>.
/// </remarks>
/// <param name="slot">The <see cref="Slot"/> to find all applicable full Dynamic Variable identities for.</param>
/// <returns>All full Dynamic Variable identities that apply to this <see cref="Slot"/>.</returns>
public static IEnumerable<DynamicVariableIdentity> GetAvailableVariableIdentities(this Slot slot)
=> slot.GetAvailableSpaces().SelectMany(GetVariableIdentities).ToArray();

/// <summary>
/// Gets the <see cref="DynamicVariableHandler{T}"/> of this
/// <see cref="IDynamicVariable{T}">dynamic variable</see>.
Expand Down Expand Up @@ -199,6 +300,56 @@ public static DynamicTypeField GetSyncWithVariable(this SyncType typeField, stri
return typeField.SyncWithVariable(variable, setupReset, forceCurrentValue);
}

/// <summary>
/// Gets all <see cref="DynamicVariableIdentity">full Dynamic Variable identities</see>
/// that are associated with this <see cref="DynamicVariableSpace"/>.
/// </summary>
/// <param name="space">The <see cref="DynamicVariableSpace"/> to get all the variable identities of.</param>
/// <returns>All full Dynamic Variable identities associated with this <paramref name="space"/>.</returns>
public static IEnumerable<DynamicVariableIdentity> GetVariableIdentities(this DynamicVariableSpace space)
{
var i = 0;
var identities = new DynamicVariableIdentity[space._dynamicValues.Keys.Count];

foreach (var identity in space._dynamicValues.Keys)
identities[i++] = new(space, identity);

return identities;
}

/// <summary>
/// Gets all <see cref="DynamicVariableIdentity">full Dynamic Variable identities</see>
/// that are associated with this <see cref="DynamicVariableSpace"/>,
/// which can be assigned a value of type <typeparamref name="T"/>.
/// </summary>
/// <typeparam name="T">The type that must be assignable to the variables.</typeparam>
/// <param name="space">The <see cref="DynamicVariableSpace"/> to get all the variable identities of.</param>
/// <returns>All full Dynamic Variable identities associated with this <paramref name="space"/> that <typeparamref name="T"/> can be assigned to.</returns>
public static IEnumerable<DynamicVariableIdentity> GetVariableIdentities<T>(this DynamicVariableSpace space)
=> space.GetVariableIdentities(typeof(T));

/// <summary>
/// Gets all <see cref="DynamicVariableIdentity">full Dynamic Variable identities</see>
/// that are associated with this <see cref="DynamicVariableSpace"/>,
/// which can be assigned a value of the given <see cref="Type"/>.
/// </summary>
/// <param name="space">The <see cref="DynamicVariableSpace"/> to get all the variable identities of.</param>
/// <param name="type">The type that must be assignable to the variables.</param>
/// <returns>All full Dynamic Variable identities associated with this <paramref name="space"/> that the given <see cref="Type"/> can be assigned to.</returns>
public static IEnumerable<DynamicVariableIdentity> GetVariableIdentities(this DynamicVariableSpace space, Type type)
=> space.GetVariableIdentities().Where(id => id.Type.IsAssignableFrom(type)).ToArray();

/// <summary>
/// Gets all <see cref="DynamicVariableIdentity">full Dynamic Variable identities</see>
/// that are associated with this <see cref="DynamicVariableSpace"/>,
/// which match the given <paramref name="name"/>.
/// </summary>
/// <param name="space">The <see cref="DynamicVariableSpace"/> to get all the variable identities of.</param>
/// <param name="name">The name that the variable identities must have.</param>
/// <returns>All full Dynamic Variable identities associated with this <paramref name="space"/> that have the given <paramref name="name"/>.</returns>
public static IEnumerable<DynamicVariableIdentity> GetVariableIdentities(this DynamicVariableSpace space, string name)
=> space.GetVariableIdentities().Where(id => id.Name == name).ToArray();

//public static DynamicField<T>? CreateVariable<T>(this IField<T> field, string name, bool overrideOnLink = false, bool persistent = true)
//{
// var variable = field.FindNearestParent<Slot>().AttachComponent<DynamicField<T>>();
Expand Down
88 changes: 88 additions & 0 deletions MonkeyLoader.Resonite.Integration/DynamicVariableIdentity.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
using FrooxEngine;
using System;
using System.Collections.Generic;
using System.Text;

namespace MonkeyLoader.Resonite
{
/// <summary>
/// Fully describes the identity of a Dynamic Variable based on itsn <see cref="Type">Type</see>,
/// <see cref="Name">Name</see>, and the <see cref="Space">Space</see> it's a part of.
/// </summary>
public readonly struct DynamicVariableIdentity : IEquatable<DynamicVariableIdentity>
{
/// <summary>
/// Gets the <see cref="IDynamicVariable.VariableName">name</see> of this Dynamic Variable.
/// </summary>
public readonly string Name { get; }

/// <summary>
/// Gets the <see cref="DynamicVariableSpace"/> that this Dynamic Variable is a part of.
/// </summary>
public readonly DynamicVariableSpace Space { get; }

/// <summary>
/// Gets the <see cref="System.Type"/> of this Dynamic Variable.
/// </summary>
public readonly Type Type { get; }

/// <summary>
/// Creates a new Dynamic Variable identity with the given details.
/// </summary>
/// <param name="space">The <see cref="DynamicVariableSpace"/> that this Dynamic Variable is a part of.</param>
/// <param name="type">The <see cref="System.Type"/> of this Dynamic Variable.</param>
/// <param name="name">The <see cref="IDynamicVariable.VariableName">name</see> of this Dynamic Variable.</param>
public DynamicVariableIdentity(DynamicVariableSpace space, Type type, string name)
{
Space = space;
Type = type;
Name = name;
}

/// <summary>
/// Creates a new full Dynamic Variable identity for the given space.
/// </summary>
/// <param name="space">The <see cref="DynamicVariableSpace"/> that this Dynamic Variable is a part of.</param>
/// <param name="variableIdentity">The Dynamic Variable's identity within the given <paramref name="space"/>.</param>
public DynamicVariableIdentity(DynamicVariableSpace space, DynamicVariableSpace.VariableIdentity variableIdentity)
{
Space = space;
Type = variableIdentity.type;
Name = variableIdentity.name;
}

/// <summary>
/// Determines whether two Dynamic Variable identities refer to different ones.
/// </summary>
/// <param name="left">The first Dynamic Variable identity.</param>
/// <param name="right">The second Dynamic Varible identity.</param>
/// <returns><c>true</c> if the identities are different; otherwise, <c>false</c>.</returns>
public static bool operator !=(DynamicVariableIdentity left, DynamicVariableIdentity right)
=> !left.Equals(right);

/// <summary>
/// Determines whether two Dynamic Variable identities refer to the same exact one.
/// </summary>
/// <param name="left">The first Dynamic Variable identity.</param>
/// <param name="right">The second Dynamic Varible identity.</param>
/// <returns><c>true</c> if the identities are the same; otherwise, <c>false</c>.</returns>
public static bool operator ==(DynamicVariableIdentity left, DynamicVariableIdentity right)
=> left.Equals(right);

/// <inheritdoc/>
public readonly bool Equals(DynamicVariableIdentity other)
=> ReferenceEquals(Space, other.Space) && Type == other.Type && Name == other.Name;

/// <inheritdoc/>
public override readonly bool Equals(object obj)
=> obj is DynamicVariableIdentity other && Equals(other);

/// <inheritdoc/>
public override readonly int GetHashCode()
=> HashCode.Combine(Space, Type, Name);

/// <inheritdoc/>
public override readonly string ToString()
=> $"Dynamic Variable {Name} of Type {Type.CompactDescription()} on {Space.GetReferenceLabel()}";
}
}
Loading