diff --git a/MonkeyLoader.Resonite.Integration/UI/SyncArrayEditor.cs b/MonkeyLoader.Resonite.Integration/UI/SyncArrayEditor.cs index b81cee7..ee07e21 100644 --- a/MonkeyLoader.Resonite.Integration/UI/SyncArrayEditor.cs +++ b/MonkeyLoader.Resonite.Integration/UI/SyncArrayEditor.cs @@ -21,6 +21,7 @@ internal sealed class SyncArrayEditor : ResoniteMonkey 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 Type _iWorldElementType = typeof(IWorldElement); private static readonly Type _particleBurstType = typeof(ParticleBurst); @@ -121,6 +122,53 @@ private static void AddParticleBurstListProxying(SyncArray array.Remove(startIndex, count); } + private static void AddTubePointProxying(SyncArray array, SyncElementList.Point> list) + { + foreach (var tubePoint in array) + { + var point = list.Add(); + point.Position.Value = tubePoint.radius; + point.Value.Value = tubePoint.position; + } + + 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 TubePoint(point.Value.Value, point.Position.Value)).ToArray(); + + array.Insert(buffer, startIndex); + AddUpdateProxies(array, list, addedElements); + }; + + list.ElementsRemoved += (list, startIndex, count) => array.Remove(startIndex, count); + } + + private static void AddCurveValueProxying(SyncArray> array, SyncElementList.Point> list) + where T : IEquatable + { + 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(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(SyncArray> array, SyncElementList.Point> list, IEnumerable.Point> elements) where T : IEquatable @@ -175,6 +223,33 @@ private static void AddUpdateProxies(SyncArray array, SyncElementList array, SyncElementList.Point> list, IEnumerable.Point> elements) + { + foreach (var point in elements) + { + point.Changed += field => + { + var index = list.IndexOfElement(point); + var tubePoint = new TubePoint(point.Value.Value, point.Position.Value); + array[index] = tubePoint; + }; + } + } + + private static void AddUpdateProxies(SyncArray> array, + SyncElementList.Point> list, IEnumerable.Point> elements) + where T : IEquatable + { + foreach (var point in elements) + { + point.Changed += syncObject => + { + var index = list.IndexOfElement(point); + array[index] = new CurveKey(point.Position, point.Value, array[index].leftTangent, array[index].rightTangent); + }; + } + } + private static Component GetOrAttachComponent(Slot targetSlot, Type type, out bool attachedNew) { attachedNew = false; @@ -186,7 +261,7 @@ private static Component GetOrAttachComponent(Slot targetSlot, Type type, out bo return comp; } - private static bool Prefix(ISyncArray array, string name, FieldInfo fieldInfo, UIBuilder ui) + private static bool Prefix(ISyncArray array, string name, FieldInfo fieldInfo, UIBuilder ui, float labelSize) { if (!Enabled) return true; @@ -195,8 +270,11 @@ private static bool Prefix(ISyncArray array, string name, FieldInfo fieldInfo, U var isSyncLinear = TryGetGenericParameters(typeof(SyncLinear<>), array.GetType(), out var syncLinearGenericParameters); + var isSyncCurve = TryGetGenericParameters(typeof(SyncCurve<>), array.GetType(), out var syncCurveGenericParameters); + var arrayType = genericParameters!.Value.First(); var syncLinearType = syncLinearGenericParameters?.First(); + var syncCurveType = syncCurveGenericParameters?.First(); var isParticleBurst = syncLinearType == _particleBurstType; @@ -231,9 +309,34 @@ private static bool Prefix(ISyncArray array, string name, FieldInfo fieldInfo, U _addLinearValueProxying.MakeGenericMethod(syncLinearType).Invoke(null, new object[] { array, list }); } } + else if (isSyncCurve && SupportsLerp(syncCurveType!)) + { + var gradientType = typeof(ValueGradientDriver<>).MakeGenericType(syncCurveType); + var gradient = GetOrAttachComponent(proxySlot, gradientType, out bool attachedNew); + + list = (ISyncList)gradient.GetSyncMember(nameof(ValueGradientDriver.Points)); + listField = gradient.GetSyncMemberFieldInfo(nameof(ValueGradientDriver.Points)); + + if (attachedNew) + { + _addCurveValueProxying.MakeGenericMethod(syncCurveType).Invoke(null, new object[] { array, list }); + } + } else { - if (Coder.IsEnginePrimitive(arrayType)) + if (arrayType == typeof(TubePoint)) + { + var gradient = GetOrAttachComponent(proxySlot, typeof(ValueGradientDriver), out bool attachedNew); + + list = (ISyncList)gradient.GetSyncMember(nameof(ValueGradientDriver.Points)); + listField = gradient.GetSyncMemberFieldInfo(nameof(ValueGradientDriver.Points)); + + if (attachedNew) + { + AddTubePointProxying((SyncArray)array, (SyncElementList.Point>)list); + } + } + else if (Coder.IsEnginePrimitive(arrayType)) { var multiplexerType = typeof(ValueMultiplexer<>).MakeGenericType(arrayType); var multiplexer = GetOrAttachComponent(proxySlot, multiplexerType, out bool attachedNew); @@ -260,8 +363,35 @@ private static bool Prefix(ISyncArray array, string name, FieldInfo fieldInfo, U } } - SyncMemberEditorBuilder.BuildList(list, name, listField, ui); - ui.Current[ui.Current.ChildrenCount - 1].DestroyWhenLocalUserLeaves(); + ui.Panel().Slot.GetComponent(); + var memberFieldSlot = SyncMemberEditorBuilder.GenerateMemberField(array, name, ui, labelSize); + ui.NestOut(); + if (!array.IsDriven) + { + SyncMemberEditorBuilder.BuildList(list, name, listField, ui); + var listSlot = ui.Current; + listSlot.DestroyWhenLocalUserLeaves(); + void ArrayChanged(IChangeable changeable) + { + if (((ISyncArray)changeable).IsDriven) + { + listSlot.DestroyChildren(); + listSlot.Components.ToArray().Do((Component c) => c.Destroy()); + listSlot.AttachComponent().MinHeight.Value = 24f; + var newUi = new UIBuilder(listSlot, listSlot); + RadiantUI_Constants.SetupEditorStyle(newUi); + newUi.Text("(array is driven)"); + proxySlot?.Destroy(); + array.Changed -= ArrayChanged; + } + } + array.Changed += ArrayChanged; + } + else + { + LocaleString text = "(array is driven)"; + ui.Text(in text); + } return false; }