Decompiled source of DuplicateFix v1.0.5

plugins/DuplicateFix/DuplicateFix.dll

Decompiled 5 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using BepInEx.NET.Common;
using BepInExResoniteShim;
using Elements.Core;
using FrooxEngine;
using FrooxEngine.Undo;
using HarmonyLib;
using SkyFrost.Base;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(/*Could not decode attribute arguments.*/)]
[assembly: TargetFramework(".NETCoreApp,Version=v10.0", FrameworkDisplayName = ".NET 10.0")]
[assembly: AssemblyCompany("art0007i")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.5.0")]
[assembly: AssemblyInformationalVersion("1.0.5+33944bc83e7f3f769600605413ffe6e415852ad4")]
[assembly: AssemblyProduct("DuplicateFix")]
[assembly: AssemblyTitle("DuplicateFix")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/art0007i/DuplicateFix")]
[assembly: AssemblyVersion("1.0.5.0")]
[module: RefSafetyRules(11)]
namespace DuplicateFix;

public static class DuplicateExtensions
{
	private static readonly global::System.Type InternalReferences = typeof(Worker).GetNestedType("InternalReferences", AccessTools.all);

	private static readonly MethodInfo RunDuplicate = typeof(Component).GetMethod("RunDuplicate", AccessTools.all);

	public static void MultiDuplicate(this global::System.Collections.Generic.IEnumerable<Slot> toDuplicate, List<Slot> newSlots, Slot duplicateRoot = null, bool keepGlobalTransform = true, DuplicationSettings settings = null, bool duplicateAsLocal = false)
	{
		//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
		//IL_0152: Unknown result type (might be due to invalid IL or missing references)
		//IL_015c: Expected O, but got Unknown
		//IL_01fa: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ff: Unknown result type (might be due to invalid IL or missing references)
		//IL_026a: Unknown result type (might be due to invalid IL or missing references)
		//IL_026f: Unknown result type (might be due to invalid IL or missing references)
		if (Enumerable.Any<Slot>(toDuplicate, (Func<Slot, bool>)((Slot x) => x.IsRootSlot)))
		{
			throw new global::System.Exception("Cannot duplicate root slot");
		}
		if (duplicateRoot != null && Enumerable.Any<Slot>(toDuplicate, (Func<Slot, bool>)((Slot x) => duplicateRoot.IsChildOf(x, false))))
		{
			throw new global::System.Exception("Target for the duplicate hierarchy cannot be within the hierarchy of the source");
		}
		object internalReferences = InternalReferences.GetConstructor(new global::System.Type[0]).Invoke((object[])null);
		HashSet<ISyncRef> hashSet = Pool.BorrowHashSet<ISyncRef>();
		HashSet<Slot> hashSet2 = Pool.BorrowHashSet<Slot>();
		List<Action> postDuplication = Pool.BorrowList<Action>();
		CollectionExtensions.Do<Slot>(toDuplicate, (Action<Slot>)delegate(Slot x)
		{
			x.ForeachComponentInChildren<IDuplicationHandler>((Action<IDuplicationHandler>)delegate(IDuplicationHandler h)
			{
				Action val = default(Action);
				h.OnBeforeDuplicate(x, ref val);
				if (val != null)
				{
					postDuplication.Add(val);
				}
			}, false, true);
		});
		CollectionExtensions.Do<Slot>(toDuplicate, (Action<Slot>)delegate(Slot x)
		{
			x.GenerateHierarchy(hashSet2, false);
		});
		CollectionExtensions.Do<Slot>(toDuplicate, (Action<Slot>)delegate(Slot x)
		{
			Traverse.Create((object)x).Method("CollectInternalReferences", new object[4] { x, internalReferences, hashSet, hashSet2 }).GetValue();
		});
		global::System.Collections.Generic.IEnumerator<Slot> enumerator = toDuplicate.GetEnumerator();
		try
		{
			while (((global::System.Collections.IEnumerator)enumerator).MoveNext())
			{
				Slot current = enumerator.Current;
				newSlots.Add((Slot)((MethodBase)typeof(Slot).GetMethod("InternalDuplicate", AccessTools.all)).Invoke((object)current, new object[5]
				{
					duplicateRoot ?? current.Parent ?? ((Worker)current).World.RootSlot,
					internalReferences,
					hashSet,
					settings,
					duplicateAsLocal
				}));
			}
		}
		finally
		{
			((global::System.IDisposable)enumerator)?.Dispose();
		}
		if (keepGlobalTransform)
		{
			global::System.Collections.Generic.IEnumerator<Slot> enumerator2 = toDuplicate.GetEnumerator();
			for (int num = 0; num < newSlots.Count; num++)
			{
				if (!((global::System.Collections.IEnumerator)enumerator2).MoveNext())
				{
					break;
				}
				newSlots[num].CopyTransform(enumerator2.Current);
			}
		}
		Traverse.Create(internalReferences).Method("TransferReferences", new object[1] { false }).GetValue();
		List<Component> list = Pool.BorrowList<Component>();
		CollectionExtensions.Do<Slot>((global::System.Collections.Generic.IEnumerable<Slot>)newSlots, (Action<Slot>)delegate(Slot x)
		{
			x.GetComponentsInChildren<Component>(list, (Predicate<Component>)null, false, false, (Predicate<Slot>)null);
		});
		Enumerator<Component> enumerator3 = list.GetEnumerator();
		try
		{
			while (enumerator3.MoveNext())
			{
				Component current2 = enumerator3.Current;
				((MethodBase)RunDuplicate).Invoke((object)current2, (object[])null);
			}
		}
		finally
		{
			((global::System.IDisposable)enumerator3/*cast due to .constrained prefix*/).Dispose();
		}
		Pool.Return<Component>(ref list);
		Pool.Return<ISyncRef>(ref hashSet);
		Traverse.Create(internalReferences).Method("Dispose", global::System.Array.Empty<object>());
		Enumerator<Action> enumerator4 = postDuplication.GetEnumerator();
		try
		{
			while (enumerator4.MoveNext())
			{
				enumerator4.Current.Invoke();
			}
		}
		finally
		{
			((global::System.IDisposable)enumerator4/*cast due to .constrained prefix*/).Dispose();
		}
		Pool.Return<Action>(ref postDuplication);
	}
}
[ResonitePlugin("art0007i.DuplicateFix", "DuplicateFix", "1.0.5", "art0007i", "https://github.com/art0007i/DuplicateFix")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public class Plugin : BasePlugin
{
	[HarmonyPatch(typeof(Grabber), "OnFocusChanged")]
	private class UserspaceTransferPatch
	{
		public static bool Prefix(Grabber __instance, WorldFocus focus)
		{
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			if (!Enabled.Value)
			{
				return true;
			}
			if (!WorldPermissionsExtensoins.CanTransferObjectsOut(((Worker)__instance).World))
			{
				return false;
			}
			Action beforeUserspaceTransfer = __instance.BeforeUserspaceTransfer;
			if (beforeUserspaceTransfer != null)
			{
				beforeUserspaceTransfer.Invoke();
			}
			Traverse.Create((object)__instance).Method("CleanupGrabbed", global::System.Array.Empty<object>()).GetValue();
			if ((int)focus != 0 || !__instance.IsHoldingObjects)
			{
				return false;
			}
			global::System.Collections.Generic.IEnumerator<IGrabbable> enumerator = ((global::System.Collections.Generic.IEnumerable<IGrabbable>)__instance.GrabbedObjects).GetEnumerator();
			try
			{
				while (((global::System.Collections.IEnumerator)enumerator).MoveNext())
				{
					if (((IComponent)enumerator.Current).Slot.GetComponentInChildren<IItemPermissions>((Predicate<IItemPermissions>)((IItemPermissions p) => !p.CanSave), false, false) != null)
					{
						return false;
					}
				}
			}
			finally
			{
				((global::System.IDisposable)enumerator)?.Dispose();
			}
			float3 localPosition = __instance.HolderSlot.LocalPosition;
			float3 zero = float3.Zero;
			if ((ref localPosition) != (ref zero))
			{
				float3 localPosition2 = __instance.HolderSlot.LocalPosition;
				__instance.HolderSlot.LocalPosition = float3.Zero;
				Enumerator<Slot> enumerator2 = __instance.HolderSlot.Children.GetEnumerator();
				try
				{
					while (enumerator2.MoveNext())
					{
						Slot current = enumerator2.Current;
						localPosition = current.LocalPosition;
						current.LocalPosition = (ref localPosition) + (ref localPosition2);
					}
				}
				finally
				{
					((global::System.IDisposable)enumerator2/*cast due to .constrained prefix*/).Dispose();
				}
			}
			if (Userspace.TryTransferToUserspaceGrabber(__instance.HolderSlot, __instance.LinkingKey))
			{
				__instance.DestroyGrabbed(true);
			}
			return false;
		}
	}

	[HarmonyPatch(typeof(Userspace), "Paste")]
	private class UserspacePastePatch
	{
		public static bool Prefix(Userspace __instance, ref Job<Slot> __result, SavedGraph data, Slot source, float3 userspacePos, floatQ userspaceRot, float3 userspaceScale, World targetWorld)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Expected O, but got Unknown
			if (!Enabled.Value)
			{
				return true;
			}
			Job<Slot> task = new Job<Slot>();
			World world = targetWorld ?? Engine.Current.WorldManager.FocusedWorld;
			world.RunSynchronously((Action)delegate
			{
				//IL_0013: Unknown result type (might be due to invalid IL or missing references)
				//IL_0028: Unknown result type (might be due to invalid IL or missing references)
				//IL_002d: Unknown result type (might be due to invalid IL or missing references)
				//IL_002f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0044: Unknown result type (might be due to invalid IL or missing references)
				//IL_0049: Unknown result type (might be due to invalid IL or missing references)
				//IL_004b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0060: Unknown result type (might be due to invalid IL or missing references)
				//IL_0065: Unknown result type (might be due to invalid IL or missing references)
				//IL_0174: Unknown result type (might be due to invalid IL or missing references)
				//IL_0181: Expected O, but got Unknown
				//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
				//IL_0100: Unknown result type (might be due to invalid IL or missing references)
				//IL_0107: Unknown result type (might be due to invalid IL or missing references)
				//IL_009f: Unknown result type (might be due to invalid IL or missing references)
				//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
				//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
				Slot val = null;
				if (WorldPermissionsExtensoins.CanSpawnObjects(world))
				{
					float3 globalPosition = WorldManager.TransferPoint(userspacePos, ((Worker)Userspace.Current).World, world);
					floatQ globalRotation = WorldManager.TransferRotation(userspaceRot, ((Worker)Userspace.Current).World, world);
					float3 globalScale = WorldManager.TransferScale(userspaceScale, ((Worker)Userspace.Current).World, world);
					Slot obj = source;
					if (((obj != null) ? ((Worker)obj).World : null) == world && !((ContainerWorker<Component>)(object)source).IsDestroyed)
					{
						source.ActiveSelf = true;
						source.GlobalPosition = globalPosition;
						source.GlobalRotation = globalRotation;
						source.GlobalScale = globalScale;
						task.SetResultAndFinish(source);
					}
					else
					{
						val = world.AddSlot("Paste", true);
						val.LoadObject(data.Root, (IRecord)null, (Slot)null, (Predicate<global::System.Type>)null, (ReferenceTranslator)null, (Func<DataTreeNode, DataTreeNode>)null);
						val.GlobalPosition = globalPosition;
						val.GlobalRotation = globalRotation;
						val.GlobalScale = globalScale;
						Traverse.Create((object)val).Method("RunOnPaste", global::System.Array.Empty<object>()).GetValue();
						if (val.Name == "Holder")
						{
							val.Destroy(val.Parent, false);
						}
					}
				}
				if (source != null && !((ContainerWorker<Component>)(object)source).IsDestroyed)
				{
					World world2 = ((Worker)source).World;
					Slot obj2 = source;
					world2.RunSynchronously(new Action(obj2.Destroy), false, (IUpdatable)null, false);
				}
				task.SetResultAndFinish(val);
			}, false, (IUpdatable)null, false);
			__result = task;
			return false;
		}
	}

	[HarmonyPatch(typeof(InteractionHandler), "DuplicateGrabbed", new global::System.Type[] { })]
	private class DuplicateFixPatch
	{
		public static bool Prefix(InteractionHandler __instance)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			if (!Enabled.Value)
			{
				return true;
			}
			UndoManagerExtensions.BeginUndoBatch(((Worker)__instance).World, LocaleHelper.AsLocaleKey("Undo.DuplicateGrabbed", (string)null, true, (Dictionary<string, object>)null));
			List<Slot> val = Pool.BorrowList<Slot>();
			List<Slot> val2 = Pool.BorrowList<Slot>();
			try
			{
				global::System.Collections.Generic.IEnumerator<IGrabbable> enumerator = ((global::System.Collections.Generic.IEnumerable<IGrabbable>)__instance.Grabber.GrabbedObjects).GetEnumerator();
				try
				{
					while (((global::System.Collections.IEnumerator)enumerator).MoveNext())
					{
						IGrabbable current = enumerator.Current;
						if (__instance.Grabber.GrabbableGetComponentInParents<IDuplicateBlock>(((IComponent)current).Slot, (Predicate<IDuplicateBlock>)null, true) == null)
						{
							val.Add(ObjectRootExtensions.GetObjectRoot(((IComponent)current).Slot, ((Component)__instance.Grabber).Slot, false));
						}
					}
				}
				finally
				{
					((global::System.IDisposable)enumerator)?.Dispose();
				}
				((global::System.Collections.Generic.IEnumerable<Slot>)val).MultiDuplicate(val2);
				CollectionExtensions.Do<Slot>((global::System.Collections.Generic.IEnumerable<Slot>)val2, (Action<Slot>)delegate(Slot x)
				{
					SpawnOrDestroyExtensions.CreateSpawnUndoPoint(x, (string)null, (Action<Worker>)null);
				});
				CollectionExtensions.Do<IGrabbable>(Enumerable.SelectMany<Slot, IGrabbable>((global::System.Collections.Generic.IEnumerable<Slot>)val2, (Func<Slot, global::System.Collections.Generic.IEnumerable<IGrabbable>>)((Slot x) => (global::System.Collections.Generic.IEnumerable<IGrabbable>)x.GetComponentsInChildren<IGrabbable>((Predicate<IGrabbable>)null, false, false, (Predicate<Slot>)null))), (Action<IGrabbable>)delegate(IGrabbable x)
				{
					if (x.IsGrabbed)
					{
						x.Release(x.Grabber, false);
					}
				});
			}
			catch (global::System.Exception ex)
			{
				((Worker)__instance).Debug.Error((object)("Exception duplicating items!\n" + (object)ex), true);
			}
			Pool.Return<Slot>(ref val2);
			Pool.Return<Slot>(ref val);
			UndoManagerExtensions.EndUndoBatch(((Worker)__instance).World);
			return false;
		}
	}

	internal static ManualLogSource Log;

	internal static ConfigEntry<bool> Enabled;

	public override void Load()
	{
		Log = ((BasePlugin)this).Log;
		Enabled = ((BasePlugin)this).Config.Bind<bool>("General", "Enabled", true, "When true the mod will be enabled.");
		((BasePlugin)this).HarmonyInstance.PatchAll();
	}
}
public static class PluginMetadata
{
	public const string GUID = "art0007i.DuplicateFix";

	public const string NAME = "DuplicateFix";

	public const string VERSION = "1.0.5";

	public const string AUTHORS = "art0007i";

	public const string REPOSITORY_URL = "https://github.com/art0007i/DuplicateFix";
}