Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of ContinuousBuild v1.0.0
BepInEx/plugins/ContinuousBuild.dll
Decompiled a week agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("Dedryx")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyCopyright("Copyright © Dedryx 2026")] [assembly: AssemblyDescription("Hold the placement button while building to continuously place pieces as you move through Valheim's snap points.")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("ContinuousBuild")] [assembly: AssemblyTitle("ContinuousBuild")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace ContinuousBuild { internal struct Pose { internal double X; internal double Y; internal double Z; internal double Qx; internal double Qy; internal double Qz; internal double Qw; internal bool Matches(Pose other, double distance, double degrees) { double num = X - other.X; double num2 = Y - other.Y; double num3 = Z - other.Z; double num4 = Math.Abs(Qx * other.Qx + Qy * other.Qy + Qz * other.Qz + Qw * other.Qw); double num5 = Math.Sqrt((Qx * Qx + Qy * Qy + Qz * Qz + Qw * Qw) * (other.Qx * other.Qx + other.Qy * other.Qy + other.Qz * other.Qz + other.Qw * other.Qw)); if (num * num + num2 * num2 + num3 * num3 <= distance * distance && num5 > 0.0) { return Math.Min(1.0, num4 / num5) >= Math.Cos(degrees * Math.PI / 360.0); } return false; } } internal sealed class PlacementGate { private readonly List<Pose> placed = new List<Pose>(); private double nextAttempt; private Pose lastAim; private int lastRotation; internal bool Armed => placed.Count > 0; internal Pose LastSuccessful { get; private set; } internal void Reset() { placed.Clear(); nextAttempt = 0.0; } internal bool IsNew(Pose pose, double positionTolerance, double rotationTolerance) { foreach (Pose item in placed) { if (pose.Matches(item, positionTolerance, rotationTolerance)) { return false; } } return true; } internal bool CanAttempt(Pose pose, double now, double positionTolerance, double rotationTolerance) { if (Armed && now >= nextAttempt) { return IsNew(pose, positionTolerance, rotationTolerance); } return false; } internal bool AllowsCandidate(Pose pose, bool snapped, Pose aim, int rotation, double positionTolerance, double rotationTolerance) { if (Armed && snapped && IsNew(pose, positionTolerance, rotationTolerance)) { if (rotation == lastRotation) { return !aim.Matches(lastAim, 0.01, 0.1); } return true; } return false; } internal void Attempt(double now) { nextAttempt = now + 0.25; } internal void Success(Pose pose, double now, Pose aim = default(Pose), int rotation = 0) { LastSuccessful = pose; lastAim = aim; lastRotation = rotation; placed.Add(pose); nextAttempt = now + 0.1; } } [BepInPlugin("dedryx.continuousbuild", "ContinuousBuild", "1.0.0")] [BepInProcess("valheim.exe")] public sealed class Plugin : BaseUnityPlugin { private delegate bool FindNearestSnap(Player player, Vector3 position, List<Transform> targets, float range, out Transform target, out float distance); [HarmonyPatch(typeof(Player), "UpdatePlacementGhost", new Type[] { typeof(bool) })] private static class GhostPatch { private static void Prefix(Player __instance) { if (!((Object)(object)__instance != (Object)(object)Player.m_localPlayer)) { refreshing = __instance; acceptedSnap = false; } } private static void Postfix(Player __instance) { if ((Object)(object)refreshing == (Object)(object)__instance) { refreshing = null; } } private static Exception Finalizer(Exception __exception) { if (__exception != null) { refreshing = null; acceptedSnap = false; } return __exception; } } [HarmonyPatch(typeof(Player), "FindClosestSnapPoints")] private static class SnapRangePatch { private static void Prefix(Player __instance, ref float maxSnapDistance) { if (CanAssistSnap(__instance)) { maxSnapDistance = Mathf.Max(maxSnapDistance, heldSnapDistance.Value); } } private static void Postfix(Player __instance, Transform ghost, float maxSnapDistance, List<Piece> pieces, ref Transform a, ref Transform b, ref bool __result) { //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) if (!__result || !improveAutoSnapping.Value || !CanAssistSnap(__instance) || manualSnapPoint.Invoke(__instance) >= 0 || (Object)(object)a == (Object)null || (Object)(object)b == (Object)null) { return; } Piece piece = ((Component)ghost).GetComponent<Piece>(); if ((Object)(object)piece == (Object)null) { return; } Vector3 origin = ghost.position; Quaternion rotation = ghost.rotation; inspectingCandidates = true; try { if (!Accept(a, b)) { __result = SnapFallback.Find(sourceSnaps.Invoke(__instance), targetSnaps.Invoke(__instance), maxSnapDistance, Nearest, Accept, out var source, out var target); a = source; b = target; } } finally { inspectingCandidates = false; } bool Accept(Transform from, Transform to) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)from == (Object)null || (Object)(object)to == (Object)null) { return false; } Vector3 val = to.position - (from.position - origin); if (!overlaps(__instance, val, rotation, ((Object)ghost).name, pieces, piece.m_allowRotatedOverlap)) { if (gate.Armed) { return gate.IsNew(Snapshot(val, rotation), positionTolerance.Value, rotationTolerance.Value); } return true; } return false; } bool Nearest(Transform from, List<Transform> targets, float range, out Transform to, out float distance) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) return findNearestSnap(__instance, from.position, targets, range, out to, out distance); } } } [HarmonyPatch(typeof(Player), "IsOverlappingOtherPiece", new Type[] { typeof(Vector3), typeof(Quaternion), typeof(string), typeof(List<Piece>), typeof(bool) })] private static class SnapPatch { private static void Postfix(Player __instance, Vector3 p, Quaternion rotation, bool __result) { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) if (!inspectingCandidates && !((Object)(object)refreshing != (Object)(object)__instance) && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer)) { acceptedSnap = !__result; if (acceptedSnap) { snappedPose = Snapshot(p, rotation); } } } } [HarmonyPatch(typeof(Player), "UpdatePlacement", new Type[] { typeof(bool), typeof(float) })] private static class UpdatePatch { private static void Prefix(Player __instance, bool takeInput) { if (!((Object)(object)__instance != (Object)(object)Player.m_localPlayer)) { updating = __instance; automatic = (succeeded = false); Sync(__instance, takeInput); } } private static void Postfix(Player __instance, bool takeInput, ref float ___m_placePressedTime) { if (!((Object)(object)updating != (Object)(object)__instance)) { if (automatic) { ___m_placePressedTime = -9999f; } if (automatic && !succeeded) { Log("Automatic placement rejected by vanilla or duplicate guard."); } Sync(__instance, takeInput); updating = null; automatic = false; } } private static Exception Finalizer(Exception __exception) { if (__exception != null) { Reset(); updating = null; automatic = false; } return __exception; } private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions) { //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Expected O, but got Unknown List<CodeInstruction> list = new List<CodeInstruction>(instructions); int num = 0; for (int i = 1; i < list.Count; i++) { if (list[i - 1].opcode == OpCodes.Ldstr && object.Equals(list[i - 1].operand, "Attack") && CodeInstructionExtensions.Calls(list[i], AccessTools.Method(typeof(ZInput), "GetButtonDown", new Type[1] { typeof(string) }, (Type[])null))) { CodeInstruction val = new CodeInstruction(OpCodes.Ldarg_0, (object)null); val.labels.AddRange(list[i].labels); list[i].labels.Clear(); list.Insert(i++, val); list[i].opcode = OpCodes.Call; list[i].operand = AccessTools.Method(typeof(Plugin), "PlaceInput", (Type[])null, (Type[])null); num++; } } if (num != 1) { throw new InvalidOperationException("Expected one vanilla Attack edge in UpdatePlacement; found " + num); } return list; } } [HarmonyPatch(typeof(Player), "TryPlacePiece", new Type[] { typeof(Piece) })] private static class TryPatch { private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator) { //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Expected O, but got Unknown //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Expected O, but got Unknown //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Expected O, but got Unknown //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Expected O, but got Unknown //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Expected O, but got Unknown List<CodeInstruction> list = new List<CodeInstruction>(instructions); int num = 0; for (int i = 0; i < list.Count; i++) { if (CodeInstructionExtensions.Calls(list[i], AccessTools.Method(typeof(Player), "UpdatePlacementGhost", new Type[1] { typeof(bool) }, (Type[])null))) { Label label = generator.DefineLabel(); list[i + 1].labels.Add(label); list.InsertRange(i + 1, (IEnumerable<CodeInstruction>)(object)new CodeInstruction[5] { new CodeInstruction(OpCodes.Ldarg_0, (object)null), new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(Plugin), "AllowRefreshedPlacement", (Type[])null, (Type[])null)), new CodeInstruction(OpCodes.Brtrue, (object)label), new CodeInstruction(OpCodes.Ldc_I4_0, (object)null), new CodeInstruction(OpCodes.Ret, (object)null) }); i += 5; num++; } } if (num != 1) { throw new InvalidOperationException("Expected one ghost refresh in TryPlacePiece; found " + num); } return list; } } [HarmonyPatch(typeof(Player), "PlacePiece", new Type[] { typeof(Piece), typeof(Vector3), typeof(Quaternion), typeof(bool), typeof(bool) })] private static class PlacedPatch { private static void Postfix(Player __instance, Piece piece, Vector3 pos, Quaternion rot) { //IL_002e: 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) if (!((Object)(object)updating != (Object)(object)__instance) && active && !((Object)(object)piece != (Object)(object)selected) && Held()) { gate.Success(Snapshot(pos, rot), Time.time, Aim(__instance), placeRotation.Invoke(__instance)); succeeded = true; Log("Placement succeeded; transform recorded."); } } } private const string Id = "dedryx.continuousbuild"; private const string PluginVersion = "1.0.0"; private static Plugin instance; private static ConfigEntry<bool> featureEnabled; private static ConfigEntry<bool> debug; private static ConfigEntry<bool> requireModifier; private static ConfigEntry<bool> improveAutoSnapping; private static ConfigEntry<KeyCode> modifier; private static ConfigEntry<float> positionTolerance; private static ConfigEntry<float> rotationTolerance; private static ConfigEntry<float> heldSnapDistance; private static Action<Player, bool> refreshGhost; private static Func<Humanoid, ItemData> getRightItem; private static Func<Player, bool> takeInput; private static FieldRef<Player, GameObject> ghost; private static FieldRef<Player, float> lastToolUse; private static FieldRef<Player, float> placeDelay; private static FieldRef<Player, int> placeRotation; private static FieldRef<Player, int> manualSnapPoint; private static FieldRef<Player, List<Transform>> sourceSnaps; private static FieldRef<Player, List<Transform>> targetSnaps; private static FindNearestSnap findNearestSnap; private static Func<Player, Vector3, Quaternion, string, List<Piece>, bool, bool> overlaps; private static bool inspectingCandidates; private static Player refreshing; private static bool acceptedSnap; private static Pose snappedPose; private static readonly PlacementGate gate = new PlacementGate(); private static Player owner; private static Player updating; private static Piece selected; private static ItemData tool; private static bool active; private static bool automatic; private static bool succeeded; private Harmony harmony; private void Awake() { //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Expected O, but got Unknown //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Expected O, but got Unknown //IL_0152: Unknown result type (might be due to invalid IL or missing references) //IL_015c: Expected O, but got Unknown //IL_0167: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Expected O, but got Unknown instance = this; featureEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Enable continuous placement after a successful normal placement."); requireModifier = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "RequireModifier", false, "When false, hold only the configured placement button to build continuously at new snap positions. When true, also hold ModifierKey."); modifier = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("General", "ModifierKey", (KeyCode)308, "Optional key used only when RequireModifier is true. Choose a key that does not conflict with vanilla AltPlace (LeftShift by default) to retain snapping."); debug = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "DebugLogging", false, "Log continuous-build transitions and placement attempts."); improveAutoSnapping = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ImproveAutoSnapping", true, "While holding placement in Auto snap mode, try the next nearest snap when vanilla's first choice overlaps an existing piece or repeats a placement from this hold. Named snap modes are unchanged."); heldSnapDistance = ((BaseUnityPlugin)this).Config.Bind<float>("General", "HeldSnapDistance", 1f, new ConfigDescription("Snap capture distance in meters while holding placement input in build mode. Vanilla uses 0.5; 1 doubles the capture range. Set 0.5 for vanilla behavior. Does not increase building reach. Larger values may select unintended nearby snap points.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 2f), Array.Empty<object>())); positionTolerance = ((BaseUnityPlugin)this).Config.Bind<float>("Advanced", "PositionTolerance", 0.05f, new ConfigDescription("Positions within this distance (meters) count as the same location. Lower only for unusually small snap spacing.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.001f, 0.5f), Array.Empty<object>())); rotationTolerance = ((BaseUnityPlugin)this).Config.Bind<float>("Advanced", "RotationTolerance", 10f, new ConfigDescription("Rotations within this angle (degrees) at the same position count as duplicates. Vanilla normally rotates in 22.5 degree steps.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 20f), Array.Empty<object>())); harmony = new Harmony("dedryx.continuousbuild"); try { refreshGhost = AccessTools.MethodDelegate<Action<Player, bool>>(AccessTools.DeclaredMethod(typeof(Player), "UpdatePlacementGhost", new Type[1] { typeof(bool) }, (Type[])null), (object)null, true); getRightItem = AccessTools.MethodDelegate<Func<Humanoid, ItemData>>(AccessTools.Method(typeof(Humanoid), "GetRightItem", Type.EmptyTypes, (Type[])null), (object)null, true); takeInput = AccessTools.MethodDelegate<Func<Player, bool>>(AccessTools.DeclaredMethod(typeof(Player), "TakeInput", Type.EmptyTypes, (Type[])null), (object)null, true); ghost = AccessTools.FieldRefAccess<Player, GameObject>("m_placementGhost"); lastToolUse = AccessTools.FieldRefAccess<Player, float>("m_lastToolUseTime"); placeDelay = AccessTools.FieldRefAccess<Player, float>("m_placeDelay"); placeRotation = AccessTools.FieldRefAccess<Player, int>("m_placeRotation"); manualSnapPoint = AccessTools.FieldRefAccess<Player, int>("m_manualSnapPoint"); sourceSnaps = AccessTools.FieldRefAccess<Player, List<Transform>>("m_tempSnapPoints1"); targetSnaps = AccessTools.FieldRefAccess<Player, List<Transform>>("m_tempSnapPoints2"); findNearestSnap = AccessTools.MethodDelegate<FindNearestSnap>(AccessTools.DeclaredMethod(typeof(Player), "FindClosestSnappoint", (Type[])null, (Type[])null), (object)null, true); overlaps = AccessTools.MethodDelegate<Func<Player, Vector3, Quaternion, string, List<Piece>, bool, bool>>(AccessTools.DeclaredMethod(typeof(Player), "IsOverlappingOtherPiece", (Type[])null, (Type[])null), (object)null, true); harmony.PatchAll(typeof(Plugin).Assembly); ((BaseUnityPlugin)this).Logger.LogInfo((object)"ContinuousBuild 1.0.0 initialized."); } catch (Exception ex) { harmony.UnpatchSelf(); ((BaseUnityPlugin)this).Logger.LogError((object)("ContinuousBuild could not locate/patch the required vanilla placement path; disabled. " + ex)); } } private void OnDestroy() { Harmony obj = harmony; if (obj != null) { obj.UnpatchSelf(); } Reset(); instance = null; } private static void Log(string message) { if (debug.Value) { ((BaseUnityPlugin)instance).Logger.LogInfo((object)("[Debug] " + message)); } } private static void Reset() { if (active) { Log("Continuous-build input stopped."); } gate.Reset(); active = false; selected = null; tool = null; owner = null; acceptedSnap = false; } private static bool Held() { //IL_001d: Unknown result type (might be due to invalid IL or missing references) if (featureEnabled.Value && (!requireModifier.Value || ZInput.GetKey(modifier.Value, true))) { if (!ZInput.GetButton("Attack")) { return ZInput.GetButton("JoyPlace"); } return true; } return false; } private static bool CanAssistSnap(Player player) { if ((Object)(object)player == (Object)(object)Player.m_localPlayer && (Object)(object)refreshing == (Object)(object)player && active && (Object)(object)owner == (Object)(object)player && Held() && takeInput(player) && ((Character)player).InPlaceMode() && (Object)(object)player.GetSelectedPiece() == (Object)(object)selected && !Hud.IsPieceSelectionVisible() && !Hud.InRadial()) { return !ZInput.GetButton("JoyAltKeys"); } return false; } private static bool Sync(Player player, bool takeInput) { Piece val = (((Character)player).InPlaceMode() ? player.GetSelectedPiece() : null); ItemData val2 = getRightItem((Humanoid)(object)player); if ((Object)(object)player != (Object)(object)Player.m_localPlayer || !takeInput || !Held() || ((Character)player).IsDead() || Hud.IsPieceSelectionVisible() || Hud.InRadial() || ZInput.GetButton("JoyAltKeys") || (Object)(object)val == (Object)null || val.m_repairPiece || val.m_removePiece || val2 == null || (Object)(object)ghost.Invoke(player) == (Object)null) { Reset(); return false; } if ((Object)(object)owner != (Object)(object)player || (Object)(object)selected != (Object)(object)val || tool != val2) { Reset(); } if (!active) { Log("Continuous-build input started; waiting for a normal successful placement."); } owner = player; selected = val; tool = val2; active = true; return true; } private static Pose Snapshot(Vector3 p, Quaternion r) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) return new Pose { X = p.x, Y = p.y, Z = p.z, Qx = r.x, Qy = r.y, Qz = r.z, Qw = r.w }; } private static Pose GhostPose(Player player) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) return Snapshot(ghost.Invoke(player).transform.position, ghost.Invoke(player).transform.rotation); } private static Pose Aim(Player player) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: 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) return Snapshot(((Component)player).transform.position, Quaternion.LookRotation(((Character)player).GetLookDir())); } private static bool CandidateAllowed(Player player) { Pose pose = GhostPose(player); bool snapped = acceptedSnap && pose.Matches(snappedPose, 0.001, 0.1); return gate.AllowsCandidate(pose, snapped, Aim(player), placeRotation.Invoke(player), positionTolerance.Value, rotationTolerance.Value); } private static bool PlaceInput(string name, Player player) { //IL_0094: Unknown result type (might be due to invalid IL or missing references) bool buttonDown = ZInput.GetButtonDown(name); if ((Object)(object)player != (Object)(object)Player.m_localPlayer) { return buttonDown; } if (!Sync(player, takeInput: true) || buttonDown || ZInput.GetButtonDown("JoyPlace")) { return buttonDown; } if (!gate.Armed || Time.time - lastToolUse.Invoke(player) <= placeDelay.Invoke(player)) { return false; } refreshGhost(player, arg2: false); if ((Object)(object)ghost.Invoke(player) == (Object)null || !ghost.Invoke(player).activeInHierarchy || (int)player.GetPlacementStatus() != 0 || !CandidateAllowed(player) || !gate.CanAttempt(GhostPose(player), Time.time, positionTolerance.Value, rotationTolerance.Value)) { return false; } gate.Attempt(Time.time); automatic = true; Log("New confirmed snap after aim/movement/rotation change: automatic placement attempted."); return true; } private static bool AllowRefreshedPlacement(Player player) { //IL_003f: Unknown result type (might be due to invalid IL or missing references) if (!automatic || (Object)(object)updating != (Object)(object)player) { return true; } if (Sync(player, takeInput: true) && gate.Armed && ghost.Invoke(player).activeInHierarchy && (int)player.GetPlacementStatus() == 0) { return CandidateAllowed(player); } return false; } } internal static class SnapFallback { internal delegate bool Closest<T>(T source, List<T> targets, float range, out T target, out float distance); internal static bool Find<T>(IList<T> sources, List<T> targets, float range, Closest<T> closest, Func<T, T, bool> acceptable, out T source, out T target) { source = default(T); target = default(T); bool result = false; float num = float.PositiveInfinity; int num2 = 0; List<T> list = new List<T>(targets.Count); foreach (T source2 in sources) { list.Clear(); list.AddRange(targets); T target2; float distance; while (closest(source2, list, Math.Min(range, num), out target2, out distance)) { if (++num2 > 256) { source = default(T); target = default(T); return false; } if (acceptable(source2, target2)) { if (distance < num) { result = true; num = distance; source = source2; target = target2; } break; } if (!list.Remove(target2)) { break; } } } return result; } } }