Skip to content

Commit

Permalink
Finish porting from the Resonite integration
Browse files Browse the repository at this point in the history
  • Loading branch information
Banane9 committed Oct 3, 2024
1 parent 5906213 commit afa0fbd
Show file tree
Hide file tree
Showing 6 changed files with 128 additions and 114 deletions.
17 changes: 10 additions & 7 deletions ArrayEditing/ArrayEditing.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@
<Version>1.0.0</Version>
<Description>Adds proxy list UI for editing arrays in inspectors. Also improves the look of list UI a bit.</Description>
<PackageLicenseExpression>LGPL-3.0-or-later</PackageLicenseExpression>
<PackageProjectUrl>https://github.com/Nytra/ResoniteArrayEditing</PackageProjectUrl>
<PackageTags>mod; mods; monkeyloader; resonite</PackageTags>
<PackageProjectUrl>https://github.com/ResoniteModdingGroup/ArrayEditing</PackageProjectUrl>
<RepositoryUrl>$(PackageProjectUrl).git</RepositoryUrl>
<PackageTags>mod; mods; monkeyloader; resonite; inspector; inspectors; array; arrays; editing; member; editor</PackageTags>
<TargetsForTfmSpecificContentInPackage>$(TargetsForTfmSpecificContentInPackage)</TargetsForTfmSpecificContentInPackage>
</PropertyGroup>

Expand All @@ -35,15 +36,17 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="MonkeyLoader" Version="0.22.12-beta" />
<PackageReference Include="MonkeyLoader.GamePacks.Unity" Version="0.6.0-beta" />
<PackageReference Include="MonkeyLoader.GamePacks.Resonite" Version="0.19.2-beta" GeneratePathProperty="true" />
<PackageReference Include="MicroUtils.HarmonyAnalyzers" Version="1.3.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="MonkeyLoader.GamePacks.Resonite" Version="0.20.0-beta" GeneratePathProperty="true" />
<PackageReference Include="PolySharp" Version="1.14.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Resonite.Elements.Core" Version="1.2.1" />
<PackageReference Include="Resonite.FrooxEngine" Version="2024.8.6.1341" />
<PackageReference Include="Resonite.Elements.Core" Version="1.3.1" />
<PackageReference Include="Resonite.FrooxEngine" Version="2024.9.31.1216" />
<PackageReference Include="System.Text.Json" Version="8.0.4">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
Expand Down
164 changes: 66 additions & 98 deletions ArrayEditing/ArrayEditing.cs → ArrayEditing/ArrayEditor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,55 @@
using System.Reflection;
using EnumerableToolkit;
using MonkeyLoader.Resonite;
using MonkeyLoader.Resonite.UI.Inspectors;

namespace ArrayEditing
{
[HarmonyPatchCategory(nameof(SyncArrayEditor))]
[HarmonyPatch(typeof(SyncMemberEditorBuilder), nameof(SyncMemberEditorBuilder.BuildArray))]
internal sealed class SyncArrayEditor : ResoniteMonkey<SyncArrayEditor>
internal sealed class ArrayEditor : ResoniteCancelableEventHandlerMonkey<ArrayEditor, BuildArrayEditorEvent>
{
private static readonly MethodInfo _addLinearValueProxying = AccessTools.Method(typeof(SyncArrayEditor), nameof(AddLinearValueProxying));
private static readonly MethodInfo _addListReferenceProxying = AccessTools.Method(typeof(SyncArrayEditor), nameof(AddListReferenceProxying));
private static readonly MethodInfo _addListValueProxying = AccessTools.Method(typeof(SyncArrayEditor), nameof(AddListValueProxying));
private static readonly MethodInfo _addCurveValueProxying = AccessTools.Method(typeof(SyncArrayEditor), nameof(AddCurveValueProxying));
private static readonly MethodInfo _addCurveValueProxying = AccessTools.Method(typeof(ArrayEditor), nameof(AddCurveValueProxying));
private static readonly MethodInfo _addLinearValueProxying = AccessTools.Method(typeof(ArrayEditor), nameof(AddLinearValueProxying));
private static readonly MethodInfo _addListReferenceProxying = AccessTools.Method(typeof(ArrayEditor), nameof(AddListReferenceProxying));
private static readonly MethodInfo _addListValueProxying = AccessTools.Method(typeof(ArrayEditor), nameof(AddListValueProxying));
private static readonly Type _iWorldElementType = typeof(IWorldElement);
private static readonly Type _particleBurstType = typeof(ParticleBurst);

public override bool CanBeDisabled => true;

protected override IEnumerable<IFeaturePatch> GetFeaturePatches() => Enumerable.Empty<IFeaturePatch>();
public override int Priority => HarmonyLib.Priority.High;

public override bool SkipCanceled => true;

protected override bool AppliesTo(BuildArrayEditorEvent eventData) => Enabled;

protected override IEnumerable<IFeaturePatch> GetFeaturePatches() => [];

protected override void Handle(BuildArrayEditorEvent eventData)
=> eventData.Canceled = BuildArray(eventData.Member, eventData.Name, eventData.FieldInfo, eventData.UI, eventData.LabelSize!.Value);

private static void AddCurveValueProxying<T>(SyncArray<CurveKey<T>> array, SyncElementList<ValueGradientDriver<T>.Point> list)
where T : IEquatable<T>
{
foreach (var key in array)
{
var point = list.Add();
point.Position.Value = key.time;
point.Value.Value = key.value;
}

AddUpdateProxies(array, list, list.Elements);

list.ElementsAdded += (list, startIndex, count) =>
{
var addedElements = list.Elements.Skip(startIndex).Take(count).ToArray();
var buffer = addedElements.Select(point => new CurveKey<T>(point.Position, point.Value)).ToArray();

array.Insert(buffer, startIndex);
AddUpdateProxies(array, list, addedElements);
};

list.ElementsRemoved += (list, startIndex, count) => array.Remove(startIndex, count);
}

private static void AddLinearValueProxying<T>(SyncArray<LinearKey<T>> array, SyncElementList<ValueGradientDriver<T>.Point> list)
where T : IEquatable<T>
Expand Down Expand Up @@ -144,30 +176,6 @@ private static void AddTubePointProxying(SyncArray<TubePoint> array, SyncElement
list.ElementsRemoved += (list, startIndex, count) => array.Remove(startIndex, count);
}

private static void AddCurveValueProxying<T>(SyncArray<CurveKey<T>> array, SyncElementList<ValueGradientDriver<T>.Point> list)
where T : IEquatable<T>
{
foreach (var key in array)
{
var point = list.Add();
point.Position.Value = key.time;
point.Value.Value = key.value;
}

AddUpdateProxies(array, list, list.Elements);

list.ElementsAdded += (list, startIndex, count) =>
{
var addedElements = list.Elements.Skip(startIndex).Take(count).ToArray();
var buffer = addedElements.Select(point => new CurveKey<T>(point.Position, point.Value)).ToArray();

array.Insert(buffer, startIndex);
AddUpdateProxies(array, list, addedElements);
};

list.ElementsRemoved += (list, startIndex, count) => array.Remove(startIndex, count);
}

private static void AddUpdateProxies<T>(SyncArray<LinearKey<T>> array,
SyncElementList<ValueGradientDriver<T>.Point> list, IEnumerable<ValueGradientDriver<T>.Point> elements)
where T : IEquatable<T>
Expand Down Expand Up @@ -249,23 +257,10 @@ private static void AddUpdateProxies<T>(SyncArray<CurveKey<T>> array,
}
}

private static Component GetOrAttachComponent(Slot targetSlot, Type type, out bool attachedNew)
private static bool BuildArray(ISyncArray array, string name, FieldInfo fieldInfo, UIBuilder ui, float labelSize)
{
attachedNew = false;
if (targetSlot.GetComponent(type) is not Component comp)
{
comp = targetSlot.AttachComponent(type);
attachedNew = true;
}
return comp;
}

private static bool Prefix(ISyncArray array, string name, FieldInfo fieldInfo, UIBuilder ui, float labelSize)
{
if (!Enabled) return true;

if (!TryGetGenericParameters(typeof(SyncArray<>), array.GetType(), out var genericParameters))
return true;
return false;

var isSyncLinear = TryGetGenericParameters(typeof(SyncLinear<>), array.GetType(), out var syncLinearGenericParameters);

Expand Down Expand Up @@ -295,7 +290,7 @@ private static bool Prefix(ISyncArray array, string name, FieldInfo fieldInfo, U
if (isSyncLinear && SupportsLerp(syncLinearType!))
{
var gradientType = typeof(ValueGradientDriver<>).MakeGenericType(syncLinearType);
var gradient = GetOrAttachComponent(proxySlot, gradientType, out bool attachedNew);
var gradient = GetOrAttachComponent(proxySlot, gradientType, out var attachedNew);

list = (ISyncList)gradient.GetSyncMember(nameof(ValueGradientDriver<float>.Points));
listField = gradient.GetSyncMemberFieldInfo(nameof(ValueGradientDriver<float>.Points));
Expand All @@ -305,27 +300,27 @@ private static bool Prefix(ISyncArray array, string name, FieldInfo fieldInfo, U
if (isParticleBurst)
AddParticleBurstListProxying((SyncArray<LinearKey<ParticleBurst>>)array, (SyncElementList<ValueGradientDriver<int2>.Point>)list);
else
_addLinearValueProxying.MakeGenericMethod(syncLinearType).Invoke(null, new object[] { array, list });
_addLinearValueProxying.MakeGenericMethod(syncLinearType).Invoke(null, [array, list]);
}
}
else if (isSyncCurve && SupportsLerp(syncCurveType!))
{
var gradientType = typeof(ValueGradientDriver<>).MakeGenericType(syncCurveType);
var gradient = GetOrAttachComponent(proxySlot, gradientType, out bool attachedNew);
var gradient = GetOrAttachComponent(proxySlot, gradientType, out var attachedNew);

list = (ISyncList)gradient.GetSyncMember(nameof(ValueGradientDriver<float>.Points));
listField = gradient.GetSyncMemberFieldInfo(nameof(ValueGradientDriver<float>.Points));

if (attachedNew)
{
_addCurveValueProxying.MakeGenericMethod(syncCurveType).Invoke(null, new object[] { array, list });
_addCurveValueProxying.MakeGenericMethod(syncCurveType).Invoke(null, [array, list]);
}
}
else
{
if (arrayType == typeof(TubePoint))
{
var gradient = GetOrAttachComponent(proxySlot, typeof(ValueGradientDriver<float3>), out bool attachedNew);
var gradient = GetOrAttachComponent(proxySlot, typeof(ValueGradientDriver<float3>), out var attachedNew);

list = (ISyncList)gradient.GetSyncMember(nameof(ValueGradientDriver<float3>.Points));
listField = gradient.GetSyncMemberFieldInfo(nameof(ValueGradientDriver<float3>.Points));
Expand All @@ -338,27 +333,27 @@ private static bool Prefix(ISyncArray array, string name, FieldInfo fieldInfo, U
else if (Coder.IsEnginePrimitive(arrayType))
{
var multiplexerType = typeof(ValueMultiplexer<>).MakeGenericType(arrayType);
var multiplexer = GetOrAttachComponent(proxySlot, multiplexerType, out bool attachedNew);
var multiplexer = GetOrAttachComponent(proxySlot, multiplexerType, out var attachedNew);
list = (ISyncList)multiplexer.GetSyncMember(nameof(ValueMultiplexer<float>.Values));
listField = multiplexer.GetSyncMemberFieldInfo(nameof(ValueMultiplexer<float>.Values));

if (attachedNew)
_addListValueProxying.MakeGenericMethod(arrayType).Invoke(null, new object[] { array, list });
_addListValueProxying.MakeGenericMethod(arrayType).Invoke(null, [array, list]);
}
else if (_iWorldElementType.IsAssignableFrom(arrayType))
{
var multiplexerType = typeof(ReferenceMultiplexer<>).MakeGenericType(arrayType);
var multiplexer = GetOrAttachComponent(proxySlot, multiplexerType, out bool attachedNew);
var multiplexer = GetOrAttachComponent(proxySlot, multiplexerType, out var attachedNew);
list = (ISyncList)multiplexer.GetSyncMember(nameof(ReferenceMultiplexer<Slot>.References));
listField = multiplexer.GetSyncMemberFieldInfo(nameof(ReferenceMultiplexer<Slot>.References));

if (attachedNew)
_addListReferenceProxying.MakeGenericMethod(arrayType).Invoke(null, new object[] { array, list });
_addListReferenceProxying.MakeGenericMethod(arrayType).Invoke(null, [array, list]);
}
else
{
proxySlot.Destroy();
return true;
return false;
}
}

Expand Down Expand Up @@ -392,7 +387,20 @@ void ArrayChanged(IChangeable changeable)
ui.Text(in text);
}

return false;
return true;
}

private static Component GetOrAttachComponent(Slot targetSlot, Type type, out bool attachedNew)
{
attachedNew = false;

if (targetSlot.GetComponent(type) is not Component comp)
{
comp = targetSlot.AttachComponent(type);
attachedNew = true;
}

return comp;
}

private static bool SupportsLerp(Type type)
Expand All @@ -417,44 +425,4 @@ private static bool TryGetGenericParameters(Type baseType, Type concreteType, [N
return TryGetGenericParameters(baseType, concreteType.BaseType, out genericParameters);
}
}

internal sealed class ListUI_Improvements : ResoniteMonkey<ListUI_Improvements>
{
public override bool CanBeDisabled => true;

protected override IEnumerable<IFeaturePatch> GetFeaturePatches() => Enumerable.Empty<IFeaturePatch>();

[HarmonyPatchCategory(nameof(ListUI_Improvements))]
[HarmonyPatch(typeof(SyncMemberEditorBuilder), "GenerateMemberField")]
class SyncMemberEditorBuilder_GenerateMemberField_Patch
{
private static bool Prefix(ISyncMember member, string name, UIBuilder ui, float labelSize)
{
if (Enabled && member.Parent is ISyncList && member is SyncObject)
{
ui.CurrentRect.Slot.AttachComponent<HorizontalLayout>();
if (ui.CurrentRect.Slot.GetComponent<LayoutElement>() is LayoutElement layoutElement)
{
layoutElement.MinWidth.Value = 48f;
layoutElement.FlexibleWidth.Value = -1f;
}
}
return true;
}
}

[HarmonyPatchCategory(nameof(ListUI_Improvements))]
[HarmonyPatch(typeof(ListEditor), "BuildListElement")]
class ListEditor_BuildListElement_Patch
{
private static bool Prefix(ISyncList list, ISyncMember member, string name, UIBuilder ui)
{
if (Enabled)
{
ui.Style.MinHeight = 24f;
}
return true;
}
}
}
}
44 changes: 44 additions & 0 deletions ArrayEditing/ListUIImprovements.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
using FrooxEngine.UIX;
using FrooxEngine;
using HarmonyLib;
using MonkeyLoader.Patching;
using System.Collections.Generic;
using System.Linq;
using MonkeyLoader.Resonite;

namespace ArrayEditing
{
[HarmonyPatch]
[HarmonyPatchCategory(nameof(ListUIImprovements))]
internal sealed class ListUIImprovements : ResoniteMonkey<ListUIImprovements>
{
public override bool CanBeDisabled => true;

protected override IEnumerable<IFeaturePatch> GetFeaturePatches() => [];

[HarmonyPatch(typeof(ListEditor), "BuildListElement")]
private static bool Prefix(UIBuilder ui)
{
if (Enabled)
ui.Style.MinHeight = 24f;

return true;
}

[HarmonyPatch(typeof(SyncMemberEditorBuilder), "GenerateMemberField")]
private static bool Prefix(ISyncMember member, UIBuilder ui)
{
if (!Enabled || member.Parent is not ISyncList || member is not SyncObject)
return true;

ui.CurrentRect.Slot.AttachComponent<HorizontalLayout>();
if (ui.CurrentRect.Slot.GetComponent<LayoutElement>() is LayoutElement layoutElement)
{
layoutElement.MinWidth.Value = 48f;
layoutElement.FlexibleWidth.Value = -1f;
}

return true;
}
}
}
4 changes: 2 additions & 2 deletions ArrayEditing/Locale/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"localeCode": "de",
"authors": [ "Banane9" ],
"messages": {
"ModTemplate.KeyA": "Lokalisierungsschlüssel A",
"ModTemplate.KeyB": "Noch eine Lokalisierung"
"ArrayEditing.ArrayEditor.Description": "Erstellt eine Liste als Proxy für Arrays, um diese in Inspektoren editieren zu können.",
"ArrayEditing.ListUIImprovements.Description": "Verbessert das UI der Editoren für Listen."
}
}
4 changes: 2 additions & 2 deletions ArrayEditing/Locale/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"localeCode": "en",
"authors": [ "Banane9" ],
"messages": {
"ModTemplate.KeyA": "Localization key A",
"ModTemplate.KeyB": "Another localization"
"ArrayEditing.ArrayEditor.Description": "Proxies Arrays to Lists to allow editing them in inspectors.",
"ArrayEditing.ListUIImprovements.Description": "Improves the UI of List Editors."
}
}
Loading

0 comments on commit afa0fbd

Please sign in to comment.