diff --git a/ArrayEditing/ArrayEditor.cs b/ArrayEditing/ArrayEditor.cs index a1d71e9..a424623 100644 --- a/ArrayEditing/ArrayEditor.cs +++ b/ArrayEditing/ArrayEditor.cs @@ -23,6 +23,11 @@ internal sealed class ArrayEditor : ResoniteCancelableEventHandlerMonkey true; public override int Priority => HarmonyLib.Priority.High; @@ -53,11 +58,24 @@ private static void AddCurveValueProxying(SyncArray> array, SyncE 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); + if (!_skipListChanges) + { + array.Changed -= ArrayChanged; + array.Insert(buffer, startIndex); + array.Changed += ArrayChanged; + } + AddUpdateProxies(array, list, addedElements); }; - list.ElementsRemoved += (list, startIndex, count) => array.Remove(startIndex, count); + list.ElementsRemoved += (list, startIndex, count) => + { + if (_skipListChanges) return; + if (array.Count < startIndex + count) return; + array.Changed -= ArrayChanged; + array.Remove(startIndex, count); + array.Changed += ArrayChanged; + }; } private static void AddLinearValueProxying(SyncArray> array, SyncElementList.Point> list) @@ -77,11 +95,23 @@ private static void AddLinearValueProxying(SyncArray> array, Syn var addedElements = list.Elements.Skip(startIndex).Take(count).ToArray(); var buffer = addedElements.Select(point => new LinearKey(point.Position, point.Value)).ToArray(); - array.Insert(buffer, startIndex); + if (!_skipListChanges) + { + array.Changed -= ArrayChanged; + array.Insert(buffer, startIndex); + array.Changed += ArrayChanged; + } AddUpdateProxies(array, list, addedElements); }; - list.ElementsRemoved += (list, startIndex, count) => array.Remove(startIndex, count); + list.ElementsRemoved += (list, startIndex, count) => + { + if (_skipListChanges) return; + if (array.Count < startIndex + count) return; + array.Changed -= ArrayChanged; + array.Remove(startIndex, count); + array.Changed += ArrayChanged; + }; } private static void AddListReferenceProxying(SyncArray array, SyncElementList> list) @@ -100,11 +130,23 @@ private static void AddListReferenceProxying(SyncArray array, SyncElementL var addedElements = list.Elements.Skip(startIndex).Take(count).ToArray(); var buffer = addedElements.Select(syncRef => syncRef.Target).ToArray(); - array.Insert(buffer, startIndex); + if (!_skipListChanges) + { + array.Changed -= ArrayChanged; + array.Insert(buffer, startIndex); + array.Changed += ArrayChanged; + } AddUpdateProxies(array, list, addedElements); }; - list.ElementsRemoved += (list, startIndex, count) => array.Remove(startIndex, count); + list.ElementsRemoved += (list, startIndex, count) => + { + if (_skipListChanges) return; + if (array.Count < startIndex + count) return; + array.Changed -= ArrayChanged; + array.Remove(startIndex, count); + array.Changed += ArrayChanged; + }; } private static void AddListValueProxying(SyncArray array, SyncElementList> list) @@ -123,11 +165,23 @@ private static void AddListValueProxying(SyncArray array, SyncElementList< var addedElements = list.Elements.Skip(startIndex).Take(count).ToArray(); var buffer = addedElements.Select(sync => sync.Value).ToArray(); - array.Insert(buffer, startIndex); + if (!_skipListChanges) + { + array.Changed -= ArrayChanged; + array.Insert(buffer, startIndex); + array.Changed += ArrayChanged; + } AddUpdateProxies(array, list, addedElements); }; - list.ElementsRemoved += (list, startIndex, count) => array.Remove(startIndex, count); + list.ElementsRemoved += (list, startIndex, count) => + { + if (_skipListChanges) return; + if (array.Count < startIndex + count) return; + array.Changed -= ArrayChanged; + array.Remove(startIndex, count); + array.Changed += ArrayChanged; + }; } private static void AddParticleBurstListProxying(SyncArray> array, SyncElementList.Point> list) @@ -146,11 +200,23 @@ private static void AddParticleBurstListProxying(SyncArray new LinearKey(point.Position, new ParticleBurst() { minCount = point.Value.Value.x, maxCount = point.Value.Value.y })).ToArray(); - array.Insert(buffer, startIndex); + if (!_skipListChanges) + { + array.Changed -= ArrayChanged; + array.Insert(buffer, startIndex); + array.Changed += ArrayChanged; + } AddUpdateProxies(array, list, addedElements); }; - list.ElementsRemoved += (list, startIndex, count) => array.Remove(startIndex, count); + list.ElementsRemoved += (list, startIndex, count) => + { + if (_skipListChanges) return; + if (array.Count < startIndex + count) return; + array.Changed -= ArrayChanged; + array.Remove(startIndex, count); + array.Changed += ArrayChanged; + }; } private static void AddTubePointProxying(SyncArray array, SyncElementList.Point> list) @@ -169,11 +235,23 @@ private static void AddTubePointProxying(SyncArray array, SyncElement 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); + if (!_skipListChanges) + { + array.Changed -= ArrayChanged; + array.Insert(buffer, startIndex); + array.Changed += ArrayChanged; + } AddUpdateProxies(array, list, addedElements); }; - list.ElementsRemoved += (list, startIndex, count) => array.Remove(startIndex, count); + list.ElementsRemoved += (list, startIndex, count) => + { + if (_skipListChanges) return; + if (array.Count < startIndex + count) return; + array.Changed -= ArrayChanged; + array.Remove(startIndex, count); + array.Changed += ArrayChanged; + }; } private static void AddUpdateProxies(SyncArray> array, @@ -184,8 +262,11 @@ private static void AddUpdateProxies(SyncArray> array, { point.Changed += syncObject => { + if (_skipListChanges) return; var index = list.IndexOfElement(point); + array.Changed -= ArrayChanged; array[index] = new LinearKey(point.Position, point.Value); + array.Changed += ArrayChanged; }; } } @@ -197,9 +278,12 @@ private static void AddUpdateProxies(SyncArray> array, { point.Changed += field => { + if (_skipListChanges) return; var index = list.IndexOfElement(point); var key = new LinearKey(point.Position, new ParticleBurst() { minCount = point.Value.Value.x, maxCount = point.Value.Value.y }); + array.Changed -= ArrayChanged; array[index] = key; + array.Changed += ArrayChanged; }; } } @@ -211,8 +295,11 @@ private static void AddUpdateProxies(SyncArray array, SyncElementList { + if (_skipListChanges) return; var index = list.IndexOfElement(sync); + array.Changed -= ArrayChanged; array[index] = sync.Value; + array.Changed += ArrayChanged; }; } } @@ -224,8 +311,11 @@ private static void AddUpdateProxies(SyncArray array, SyncElementList { + if (_skipListChanges) return; var index = list.IndexOfElement(sync); + array.Changed -= ArrayChanged; array[index] = sync.Target; + array.Changed += ArrayChanged; }; } } @@ -236,9 +326,12 @@ private static void AddUpdateProxies(SyncArray array, SyncElementList { point.Changed += field => { + if (_skipListChanges) return; var index = list.IndexOfElement(point); var tubePoint = new TubePoint(point.Value.Value, point.Position.Value); + array.Changed -= ArrayChanged; array[index] = tubePoint; + array.Changed += ArrayChanged; }; } } @@ -251,8 +344,11 @@ private static void AddUpdateProxies(SyncArray> array, { point.Changed += syncObject => { + if (_skipListChanges) return; var index = list.IndexOfElement(point); + array.Changed -= ArrayChanged; array[index] = new CurveKey(point.Position, point.Value, array[index].leftTangent, array[index].rightTangent); + array.Changed += ArrayChanged; }; } } @@ -277,10 +373,12 @@ private static bool BuildArray(ISyncArray array, string name, FieldInfo fieldInf var proxySlotName = $"{name}-{array.ReferenceID}-Proxy"; var proxiesSlot = ui.World.AssetsSlot; + var newProxy = false; if (proxiesSlot.FindChild(proxySlotName) is not Slot proxySlot) { proxySlot = proxiesSlot.AddSlot(proxySlotName); array.FindNearestParent().Destroyed += (IDestroyable _) => proxySlot.Destroy(); + newProxy = true; } proxySlot.DestroyWhenLocalUserLeaves(); @@ -357,15 +455,16 @@ private static bool BuildArray(ISyncArray array, string name, FieldInfo fieldInf } } - ui.Panel().Slot.GetComponent(); + 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) + void ArrayDriveCheck(IChangeable changeable) { if (((ISyncArray)changeable).IsDriven) { @@ -376,10 +475,10 @@ void ArrayChanged(IChangeable changeable) RadiantUI_Constants.SetupEditorStyle(newUi); newUi.Text("(array is driven)"); proxySlot?.Destroy(); - array.Changed -= ArrayChanged; + array.Changed -= ArrayDriveCheck; } } - array.Changed += ArrayChanged; + array.Changed += ArrayDriveCheck; } else { @@ -387,9 +486,124 @@ void ArrayChanged(IChangeable changeable) ui.Text(in text); } + if (newProxy) + { + array.Changed += ArrayChanged; + } + return true; } + // doesn't work? + static void SetParticlePoint(ValueGradientDriver.Point point, LinearKey arrayElem) + { + point.Position.Value = arrayElem.time; + point.Value.Value = new int2(arrayElem.value.minCount, arrayElem.value.maxCount); + } + + static void SetLinearPoint(ValueGradientDriver.Point point, LinearKey arrayElem) where T : IEquatable + { + point.Position.Value = arrayElem.time; + point.Value.Value = arrayElem.value; + } + + static void SetCurvePoint(ValueGradientDriver.Point point, CurveKey arrayElem) where T : IEquatable + { + point.Position.Value = arrayElem.time; + point.Value.Value = arrayElem.value; + } + + static void SetTubePoint(ValueGradientDriver.Point point, TubePoint arrayElem) + { + point.Position.Value = arrayElem.radius; + point.Value.Value = arrayElem.position; + } + + static void ArrayChanged(IChangeable changeable) + { + var array = (ISyncArray)changeable; + + if (array.IsDriven) + { + array.Changed -= ArrayChanged; + return; + } + + var proxySlotName = $"{array.Name}-{array.ReferenceID}-Proxy"; + var proxiesSlot = array.World.AssetsSlot; + if (proxiesSlot.FindChild(proxySlotName) is Slot proxySlot) + { + ISyncList? list = null; + foreach (var comp in proxySlot.Components) + { + if (comp.GetType().IsGenericType && comp.GetType().GetGenericTypeDefinition() == typeof(ValueMultiplexer<>)) + { + list = comp.GetSyncMember("Values") as ISyncList; + _skipListChanges = true; + list.World.RunSynchronously(() => _skipListChanges = false); + list.EnsureExactElementCount(array.Count); + for (int i = 0; i < array.Count; i++) + { + ((IField)list.GetElement(i)).BoxedValue = array.GetElement(i); + } + } + else if (comp.GetType().IsGenericType && comp.GetType().GetGenericTypeDefinition() == typeof(ReferenceMultiplexer<>)) + { + list = comp.GetSyncMember("References") as ISyncList; + _skipListChanges = true; + list.World.RunSynchronously(() => _skipListChanges = false); + list.EnsureExactElementCount(array.Count); + for (int i = 0; i < array.Count; i++) + { + ((ISyncRef)list.GetElement(i)).Target = (IWorldElement)array.GetElement(i); + } + } + else if (comp.GetType().IsGenericType && comp.GetType().GetGenericTypeDefinition() == typeof(ValueGradientDriver<>)) + { + list = comp.GetSyncMember("Points") as ISyncList; + _skipListChanges = true; + list.World.RunSynchronously(() => _skipListChanges = false); + list.EnsureExactElementCount(array.Count); + + var isSyncLinear = TryGetGenericParameters(typeof(SyncLinear<>), array.GetType(), out var syncLinearGenericParameters); + var isSyncCurve = TryGetGenericParameters(typeof(SyncCurve<>), array.GetType(), out var syncCurveGenericParameters); + var syncLinearType = syncLinearGenericParameters?.First(); + var syncCurveType = syncCurveGenericParameters?.First(); + var isParticleBurst = syncLinearType == _particleBurstType; + + if (!TryGetGenericParameters(typeof(SyncArray<>), array.GetType(), out var genericParameters)) + return; + + var arrayType = genericParameters!.Value.First(); + + for (int i = 0; i < array.Count; i++) + { + var elem = list.GetElement(i); + + if (isSyncLinear && SupportsLerp(syncLinearType!)) + { + if (isParticleBurst) + SetParticlePoint((ValueGradientDriver.Point)elem!, (LinearKey)array.GetElement(i)); + else + _setLinearPoint.MakeGenericMethod(syncLinearType).Invoke(null, [elem, array.GetElement(i)]); + } + else if (isSyncCurve && SupportsLerp(syncCurveType!)) + { + _setCurvePoint.MakeGenericMethod(syncCurveType).Invoke(null, [elem, array.GetElement(i)]); + } + else + { + if (arrayType == typeof(TubePoint)) + { + SetTubePoint((ValueGradientDriver.Point)elem!, (TubePoint)array.GetElement(i)); + } + } + } + } + } + } + } + private static Component GetOrAttachComponent(Slot targetSlot, Type type, out bool attachedNew) { attachedNew = false;