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 BenchLink v0.1.0
BenchLink.dll
Decompiled 6 hours agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Jotunn.Entities; using Jotunn.Managers; using Jotunn.Utils; using Microsoft.CodeAnalysis; using UnityEngine; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: IgnoresAccessChecksTo("")] [assembly: AssemblyCompany("BenchLink")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("Link nearby crafting stations into clusters so any bench's range counts for every bench type in the cluster.")] [assembly: AssemblyFileVersion("0.1.0.0")] [assembly: AssemblyInformationalVersion("0.1.0+be295baf63ed35d85924693d03e1b16ab5cae297")] [assembly: AssemblyProduct("BenchLink")] [assembly: AssemblyTitle("BenchLink")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.1.0.0")] [module: UnverifiableCode] [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 BenchLink { internal sealed class BenchLinkCommand : ConsoleCommand { private const float NearbyDistance = 100f; private const int MaxAreaCells = 100000; public override string Name => "benchlink"; public override string Help => "Lists the linked crafting station clusters near you: members, ranges, link distances, and the area covered with and without linking."; public override void Run(string[] args) { ((ConsoleCommand)this).Run(args, (Terminal)(object)Console.instance); } public override void Run(string[] args, Terminal context) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { context.AddString("benchlink: no player in the world."); return; } StationGraph graph = StationClusters.Graph; IReadOnlyList<CraftingStation> stations = StationClusters.Stations; Vector3 position = ((Component)localPlayer).transform.position; context.AddString("BenchLink: LinkSlack " + BenchLinkConfig.LinkSlack.Value.ToString("0.#", CultureInfo.InvariantCulture) + ", " + graph.Count + " stations loaded"); int num = 0; for (int i = 0; i < graph.ClusterCount; i++) { if (IsNear(graph, i, position)) { num++; Describe(context, graph, stations, i, position); } } if (num == 0) { context.AddString("No stations within " + 100f + " m of you."); } } private static bool IsNear(StationGraph graph, int cluster, Vector3 origin) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) for (int i = 0; i < graph.Count; i++) { if (graph.ClusterOf(i) == cluster && StationGraph.Distance(graph[i], new StationNode(origin.x, origin.z, 0f, -1, 0L)) < 100f) { return true; } } return false; } private static void Describe(Terminal context, StationGraph graph, IReadOnlyList<CraftingStation> stations, int cluster, Vector3 origin) { //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) context.AddString("Cluster " + cluster + " (" + graph.ClusterSize(cluster) + " stations)"); StationNode b = new StationNode(origin.x, origin.z, 0f, -1, 0L); for (int i = 0; i < graph.Count; i++) { if (graph.ClusterOf(i) == cluster) { StationNode a = graph[i]; string text = (graph.Covers(i, origin.x, origin.z) ? ", you are in range" : string.Empty); string text2 = (graph.IsDuplicate(i) ? ", duplicate type: not linked" : string.Empty); context.AddString(" [" + i + "] " + Localization.instance.Localize(stations[i].m_name) + " level " + stations[i].GetLevel(true) + ", range " + a.Range.ToString("0.#", CultureInfo.InvariantCulture) + " m, " + StationGraph.Distance(in a, in b).ToString("0.#", CultureInfo.InvariantCulture) + " m from you" + text + text2); } } StringBuilder stringBuilder = new StringBuilder(); for (int j = 0; j < graph.Count; j++) { for (int k = j + 1; k < graph.Count; k++) { if (graph.ClusterOf(j) == cluster && graph.ClusterOf(k) == cluster && StationGraph.AreLinked(graph[j], graph[k], BenchLinkConfig.LinkSlack.Value)) { stringBuilder.Append(" [").Append(j).Append("]-[") .Append(k) .Append("] ") .Append(StationGraph.Distance(graph[j], graph[k]).ToString("0.#", CultureInfo.InvariantCulture)) .Append(" m\n"); } } } if (stringBuilder.Length > 0) { context.AddString(" links:\n" + stringBuilder.ToString().TrimEnd(new char[1] { '\n' })); } var (num, num2) = graph.EstimateAreas(cluster, 100000); context.AddString(" area with every type in range: vanilla " + num.ToString("N0", CultureInfo.InvariantCulture) + " m2, linked " + num2.ToString("N0", CultureInfo.InvariantCulture) + " m2 (any bench in range)"); } } internal static class PlacementNotice { private const float PlacementWindow = 1f; private const float HoldSeconds = 3f; private const float FadeSeconds = 1.5f; private static float _placedAt = float.NegativeInfinity; private static CraftingStation _justPlaced; private static float _fadeAt = float.PositiveInfinity; private static string _shownText; public static void Tick() { FadeWhenDue(); StationClusters.Poll(); if (StationClusters.TryTakeChanged(out var names)) { Show("Cluster " + Localization.instance.Localize(names) + " changed!"); } if (!((Object)(object)_justPlaced == (Object)null)) { CraftingStation justPlaced = _justPlaced; _justPlaced = null; int num = StationClusters.IndexOf(justPlaced); Player localPlayer = Player.m_localPlayer; if (num >= 0 && !((Object)(object)localPlayer == (Object)null) && StationClusters.Graph.IsDuplicate(num)) { Show("Duplicate " + Localization.instance.Localize(justPlaced.m_name) + ": it won't extend the cluster"); } } } private static void Show(string text) { MessageHud instance = MessageHud.instance; if (!((Object)(object)instance == (Object)null)) { int count = instance._crossFadeTextBuffer.Count; instance.ShowMessage((MessageType)2, text, 0, (Sprite)null, false, true); if (instance._crossFadeTextBuffer.Count == count + 2) { instance._crossFadeTextBuffer.RemoveAt(count + 1); _shownText = instance.m_messageCenterText.text; _fadeAt = Time.unscaledTime + 3f; } } } private static void FadeWhenDue() { if (!(Time.unscaledTime < _fadeAt)) { _fadeAt = float.PositiveInfinity; MessageHud instance = MessageHud.instance; if ((Object)(object)instance != (Object)null && instance.m_messageCenterText.text == _shownText) { ((Graphic)instance.m_messageCenterText).CrossFadeAlpha(0f, 1.5f, true); } } } internal static void Placed(Piece piece) { if ((Object)(object)((Component)piece).GetComponentInChildren<CraftingStation>() != (Object)null) { _placedAt = Time.time; } } internal static void Started(CraftingStation station) { if (Time.time - _placedAt < 1f) { _placedAt = float.NegativeInfinity; _justPlaced = station; } } } [HarmonyPatch(typeof(Player), "PlacePiece")] internal static class PlacePiecePatch { private static void Postfix(Piece piece) { PlacementNotice.Placed(piece); } } [BepInPlugin("javidahmed64592.benchlink", "Bench Link", "0.1.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] [NetworkCompatibility(/*Could not decode attribute arguments.*/)] public class BenchLinkPlugin : BaseUnityPlugin { public const string PluginGUID = "javidahmed64592.benchlink"; public const string PluginName = "Bench Link"; public const string PluginVersion = "0.1.0"; private readonly RangeIndicator _indicator = new RangeIndicator(); private Harmony _harmony; internal static ManualLogSource Log { get; private set; } private void Awake() { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; BenchLinkConfig.Bind(((BaseUnityPlugin)this).Config); _harmony = new Harmony("javidahmed64592.benchlink"); _harmony.PatchAll(); CommandManager.Instance.AddConsoleCommand((ConsoleCommand)(object)new BenchLinkCommand()); } private void Update() { _indicator.Tick(Time.deltaTime); PlacementNotice.Tick(); } private void OnDestroy() { _indicator.Hide(); Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } } internal enum IndicatorMode { Off, WhileBuilding } internal static class BenchLinkConfig { public static ConfigEntry<float> LinkSlack; public static ConfigEntry<IndicatorMode> Indicator; public static void Bind(ConfigFile config) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Expected O, but got Unknown LinkSlack = config.Bind<float>("General", "LinkSlack", 0f, new ConfigDescription("Extra metres added when deciding whether two stations are linked. Stations are linked when they are closer than the larger of their two build ranges plus this.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 20f), Array.Empty<object>())); Indicator = config.Bind<IndicatorMode>("Look", "Indicator", IndicatorMode.WhileBuilding, "Show the build range of every linked station while the hammer is out. Off removes it."); } } internal sealed class RangeIndicator { private readonly struct MarkerRenderers { public Renderer[] Items { get; } public int ChildCount { get; } public MarkerRenderers(Renderer[] items, int childCount) { Items = items; ChildCount = childCount; } } private const float TickInterval = 0.25f; private static readonly Color LinkedTint = new Color(0.941f, 0.69f, 0.29f); private static readonly Color HoverTint = new Color(0.6f, 0.8f, 1f); private static readonly string[] ColorProperties = new string[3] { "_Color", "_TintColor", "_BaseColor" }; private readonly List<CraftingStation> _shown = new List<CraftingStation>(); private readonly List<CraftingStation> _next = new List<CraftingStation>(); private readonly HashSet<CraftingStation> _tinted = new HashSet<CraftingStation>(); private readonly Dictionary<CraftingStation, MarkerRenderers> _cache = new Dictionary<CraftingStation, MarkerRenderers>(); private readonly MaterialPropertyBlock _block = new MaterialPropertyBlock(); private int[] _colorIds; private bool[] _clusterActive = Array.Empty<bool>(); private float _timer; private int _cacheVersion; public void Tick(float deltaTime) { _timer += deltaTime; if (_timer < 0.25f) { return; } _timer = 0f; Player localPlayer = Player.m_localPlayer; if (BenchLinkConfig.Indicator.Value == IndicatorMode.Off || (Object)(object)localPlayer == (Object)null || !((Character)localPlayer).InPlaceMode()) { Hide(); return; } if (_cacheVersion != StationClusters.Version) { _cache.Clear(); _cacheVersion = StationClusters.Version; } Update(localPlayer); } public void Hide() { foreach (CraftingStation item in _shown) { Hide(item); } _shown.Clear(); _tinted.Clear(); } private void Update(Player player) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0067: 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) Vector3 position = ((Component)player).transform.position; CraftingStation val = HoveredStation(player); StationGraph graph = StationClusters.Graph; IReadOnlyList<CraftingStation> stations = StationClusters.Stations; if (_clusterActive.Length < graph.ClusterCount) { _clusterActive = new bool[graph.ClusterCount]; } for (int i = 0; i < graph.ClusterCount; i++) { _clusterActive[i] = false; } for (int j = 0; j < graph.Count; j++) { if (graph.Covers(j, position.x, position.z)) { _clusterActive[graph.ClusterOf(j)] = true; } } _next.Clear(); for (int k = 0; k < graph.Count; k++) { int num = graph.ClusterOf(k); if (_clusterActive[num] && (Object)(object)stations[k].m_areaMarker != (Object)null) { _next.Add(stations[k]); Show(stations[k], graph.ClusterSize(num) > 1, (Object)(object)stations[k] == (Object)(object)val); } } if ((Object)(object)val != (Object)null && (Object)(object)val.m_areaMarker != (Object)null && !_next.Contains(val)) { val.GetStationBuildRange(); _next.Add(val); Show(val, linked: false, hovered: true); } foreach (CraftingStation item in _shown) { if (!_next.Contains(item)) { Hide(item); } } _shown.Clear(); _shown.AddRange(_next); } private static CraftingStation HoveredStation(Player player) { Piece hoveringPiece = player.GetHoveringPiece(); if (!((Object)(object)hoveringPiece == (Object)null)) { return ((Component)hoveringPiece).GetComponentInChildren<CraftingStation>(); } return null; } private void Show(CraftingStation station, bool linked, bool hovered) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) station.m_areaMarker.SetActive(true); ((MonoBehaviour)station).CancelInvoke("HideMarker"); if (hovered) { Tint(station, HoverTint); } else if (linked) { Tint(station, LinkedTint); } else { Untint(station); } } private void Hide(CraftingStation station) { if (!((Object)(object)station == (Object)null)) { Untint(station); if ((Object)(object)station.m_areaMarker != (Object)null) { station.m_areaMarker.SetActive(false); } } } private void Tint(CraftingStation station, Color tint) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) Renderer[] array = RenderersOf(station); foreach (Renderer val in array) { int num = ColorId(val); if (num >= 0) { float a = val.sharedMaterial.GetColor(num).a; _block.Clear(); _block.SetColor(num, new Color(tint.r, tint.g, tint.b, a)); val.SetPropertyBlock(_block); } } _tinted.Add(station); } private void Untint(CraftingStation station) { if (_tinted.Remove(station)) { Renderer[] array = RenderersOf(station); for (int i = 0; i < array.Length; i++) { array[i].SetPropertyBlock((MaterialPropertyBlock)null); } } } private int ColorId(Renderer renderer) { Material sharedMaterial = renderer.sharedMaterial; if ((Object)(object)sharedMaterial == (Object)null) { return -1; } if (_colorIds == null) { _colorIds = new int[ColorProperties.Length]; for (int i = 0; i < ColorProperties.Length; i++) { _colorIds[i] = Shader.PropertyToID(ColorProperties[i]); } } int[] colorIds = _colorIds; foreach (int num in colorIds) { if (sharedMaterial.HasProperty(num)) { return num; } } return -1; } private Renderer[] RenderersOf(CraftingStation station) { Transform transform = station.m_areaMarker.transform; if (!_cache.TryGetValue(station, out var value) || value.ChildCount != transform.childCount) { value = new MarkerRenderers(((Component)transform).GetComponentsInChildren<Renderer>(true), transform.childCount); _cache[station] = value; } return value.Items; } } internal static class StationClusters { private const float RefreshInterval = 1f; private static readonly Dictionary<string, int> TypeIds = new Dictionary<string, int>(); private static readonly List<CraftingStation> StationList = new List<CraftingStation>(); private static readonly Dictionary<int, bool> WasDuplicate = new Dictionary<int, bool>(); private static readonly List<string> ChangedNames = new List<string>(); private static StationGraph _graph; private static float _builtAt; private static float _builtSlack; private static int _builtVersion = -1; public static int Version { get; private set; } public static IReadOnlyList<CraftingStation> Stations { get { Refresh(); return StationList; } } public static StationGraph Graph { get { Refresh(); return _graph; } } public static void Poll() { Refresh(); } public static void Invalidate() { Version++; } public static CraftingStation FindLinked(string name, Vector3 point) { //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) Refresh(); if (!TypeIds.TryGetValue(name, out var value)) { return null; } int num = _graph.FindLinked(point.x, point.z, value); if (num >= 0) { return StationList[num]; } return null; } public static CraftingStation PreferLinked(CraftingStation found, Vector3 point) { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) Refresh(); if (!_graph.HasDuplicates) { return found; } int num = StationList.IndexOf(found); if (num < 0 || !_graph.IsDuplicate(num)) { return found; } int num2 = _graph.FindPrimaryCovering(point.x, point.z, _graph[num].Type); if (num2 >= 0) { return StationList[num2]; } return found; } public static int IndexOf(CraftingStation station) { Refresh(); return StationList.IndexOf(station); } public static bool TryTakeChanged(out string names) { names = string.Join(", ", ChangedNames); ChangedNames.Clear(); return names.Length > 0; } public static string NameOf(int type) { foreach (KeyValuePair<string, int> typeId in TypeIds) { if (typeId.Value == type) { return typeId.Key; } } return string.Empty; } private static void Refresh() { float num = Time.time - _builtAt; if (_graph == null || _builtVersion != Version || _builtSlack != BenchLinkConfig.LinkSlack.Value || !(num >= 0f) || !(num < 1f)) { Rebuild(); } } private static void Rebuild() { //IL_0074: 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) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) StationList.Clear(); foreach (CraftingStation allStation in CraftingStation.m_allStations) { if ((Object)(object)allStation != (Object)null) { StationList.Add(allStation); } } StationNode[] array = new StationNode[StationList.Count]; for (int i = 0; i < array.Length; i++) { CraftingStation val = StationList[i]; Vector3 position = ((Component)val).transform.position; array[i] = new StationNode(position.x, position.z, val.GetStationBuildRange(), TypeOf(val.m_name), BuiltOrder(val)); } _builtSlack = BenchLinkConfig.LinkSlack.Value; _graph = new StationGraph(array, _builtSlack); RecordChanges(); _builtAt = Time.time; _builtVersion = Version; } private static void RecordChanges() { //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; for (int i = 0; i < StationList.Count; i++) { bool flag = _graph.IsDuplicate(i); if ((Object)(object)localPlayer != (Object)null && WasDuplicate.TryGetValue(((Object)StationList[i]).GetInstanceID(), out var value) && value != flag) { Vector3 position = ((Component)localPlayer).transform.position; string name = StationList[i].m_name; if (_graph.Covers(i, position.x, position.z) && !ChangedNames.Contains(name)) { ChangedNames.Add(name); } } } WasDuplicate.Clear(); for (int j = 0; j < StationList.Count; j++) { WasDuplicate[((Object)StationList[j]).GetInstanceID()] = _graph.IsDuplicate(j); } } private static long BuiltOrder(CraftingStation station) { ZNetView component = ((Component)station).GetComponent<ZNetView>(); if (!((Object)(object)component != (Object)null) || !component.IsValid()) { return long.MaxValue; } return ((ZDOID)(ref component.GetZDO().m_uid)).ID; } private static int TypeOf(string name) { if (!TypeIds.TryGetValue(name, out var value)) { value = TypeIds.Count; TypeIds[name] = value; } return value; } } internal readonly struct StationNode { public float X { get; } public float Z { get; } public float Range { get; } public int Type { get; } public long Order { get; } public StationNode(float x, float z, float range, int type, long order = 0L) { X = x; Z = z; Range = range; Type = type; Order = order; } } internal sealed class StationGraph { private readonly StationNode[] _nodes; private readonly int[] _cluster; private readonly int[] _stamp; private readonly bool[] _duplicate; private int _stampId; public int Count => _nodes.Length; public int ClusterCount { get; } public StationNode this[int index] => _nodes[index]; public bool HasDuplicates { get { bool[] duplicate = _duplicate; for (int i = 0; i < duplicate.Length; i++) { if (duplicate[i]) { return true; } } return false; } } public StationGraph(StationNode[] nodes, float linkSlack) { _nodes = nodes; _cluster = new int[nodes.Length]; _stamp = new int[nodes.Length]; _duplicate = new bool[nodes.Length]; ClusterCount = BuildClusters(linkSlack); } public int ClusterOf(int index) { return _cluster[index]; } public bool IsDuplicate(int index) { return _duplicate[index]; } public int FindPrimaryCovering(float x, float z, int type) { int result = -1; float num = float.MaxValue; for (int i = 0; i < _nodes.Length; i++) { if (_nodes[i].Type == type && !_duplicate[i] && Covers(i, x, z)) { float num2 = Distance(_nodes[i].X, _nodes[i].Z, x, z); if (num2 < num) { result = i; num = num2; } } } return result; } public int ClusterSize(int cluster) { int num = 0; for (int i = 0; i < _cluster.Length; i++) { if (_cluster[i] == cluster) { num++; } } return num; } public static float Distance(in StationNode a, in StationNode b) { return Distance(a.X, a.Z, b.X, b.Z); } public static bool AreLinked(in StationNode a, in StationNode b, float linkSlack) { return Distance(in a, in b) < Math.Max(a.Range, b.Range) + linkSlack; } public bool Covers(int index, float x, float z) { return Distance(_nodes[index].X, _nodes[index].Z, x, z) < _nodes[index].Range; } public int FindLinked(float x, float z, int type) { _stampId++; bool flag = false; for (int i = 0; i < _nodes.Length; i++) { if (Covers(i, x, z)) { _stamp[_cluster[i]] = _stampId; flag = true; } } if (!flag) { return -1; } int result = -1; float num = float.MaxValue; for (int j = 0; j < _nodes.Length; j++) { if (_nodes[j].Type == type && _stamp[_cluster[j]] == _stampId) { float num2 = Distance(_nodes[j].X, _nodes[j].Z, x, z); if (num2 < num) { result = j; num = num2; } } } return result; } public bool TypeCoversVanilla(int cluster, int type, float x, float z) { for (int i = 0; i < _nodes.Length; i++) { if (_cluster[i] == cluster && _nodes[i].Type == type && Covers(i, x, z)) { return true; } } return false; } public bool ClusterCovers(int cluster, float x, float z) { for (int i = 0; i < _nodes.Length; i++) { if (_cluster[i] == cluster && Covers(i, x, z)) { return true; } } return false; } public (double vanilla, double linked) EstimateAreas(int cluster, int maxCells) { float num = float.MaxValue; float num2 = float.MinValue; float num3 = float.MaxValue; float num4 = float.MinValue; for (int i = 0; i < _nodes.Length; i++) { if (_cluster[i] == cluster) { num = Math.Min(num, _nodes[i].X - _nodes[i].Range); num2 = Math.Max(num2, _nodes[i].X + _nodes[i].Range); num3 = Math.Min(num3, _nodes[i].Z - _nodes[i].Range); num4 = Math.Max(num4, _nodes[i].Z + _nodes[i].Range); } } float num5 = 1f; while ((num2 - num) / num5 * ((num4 - num3) / num5) > (float)maxCells) { num5 *= 2f; } int[] types = TypesIn(cluster); long num6 = 0L; long num7 = 0L; for (float num8 = num + num5 / 2f; num8 < num2; num8 += num5) { for (float num9 = num3 + num5 / 2f; num9 < num4; num9 += num5) { if (ClusterCovers(cluster, num8, num9)) { num7++; if (CoversEveryType(cluster, types, num8, num9)) { num6++; } } } } double num10 = (double)num5 * (double)num5; return (vanilla: (double)num6 * num10, linked: (double)num7 * num10); } public static double LensArea(double r1, double r2, double d) { if (d >= r1 + r2) { return 0.0; } if (d <= Math.Abs(r1 - r2)) { double num = Math.Min(r1, r2); return Math.PI * num * num; } double num2 = r1 * r1 * Math.Acos((d * d + r1 * r1 - r2 * r2) / (2.0 * d * r1)); double num3 = r2 * r2 * Math.Acos((d * d + r2 * r2 - r1 * r1) / (2.0 * d * r2)); double num4 = 0.5 * Math.Sqrt((0.0 - d + r1 + r2) * (d + r1 - r2) * (d - r1 + r2) * (d + r1 + r2)); return num2 + num3 - num4; } public static double UnionArea(double r1, double r2, double d) { return Math.PI * r1 * r1 + Math.PI * r2 * r2 - LensArea(r1, r2, d); } private static float Distance(float ax, float az, float bx, float bz) { float num = ax - bx; float num2 = az - bz; return (float)Math.Sqrt(num * num + num2 * num2); } private bool CoversEveryType(int cluster, int[] types, float x, float z) { foreach (int type in types) { if (!TypeCoversVanilla(cluster, type, x, z)) { return false; } } return true; } private int[] TypesIn(int cluster) { int[] array = new int[_nodes.Length]; int num = 0; for (int i = 0; i < _nodes.Length; i++) { if (_cluster[i] == cluster && Array.IndexOf(array, _nodes[i].Type, 0, num) < 0) { array[num++] = _nodes[i].Type; } } Array.Resize(ref array, num); return array; } private int BuildClusters(float linkSlack) { int[] array = new int[_nodes.Length]; for (int i = 0; i < array.Length; i++) { array[i] = i; } int[] array2 = new int[_nodes.Length]; for (int j = 0; j < array2.Length; j++) { array2[j] = j; } Array.Sort(array2, ComparePriority); bool[] array3 = new bool[_nodes.Length]; int[] array4 = new int[_nodes.Length]; float[] rootDistance = new float[_nodes.Length]; int[] array5 = array2; foreach (int num in array5) { int num2 = CollectLinkedRoots(num, linkSlack, array, array3, array4, rootDistance); int num3 = AcceptRoots(num, array, array3, array4, num2); if (num2 > 0 && num3 == 0) { _duplicate[num] = true; continue; } array3[num] = true; for (int l = 0; l < num3; l++) { array[array4[l]] = num; } } int[] array6 = new int[_nodes.Length]; for (int m = 0; m < array6.Length; m++) { array6[m] = -1; } int result = 0; for (int n = 0; n < _nodes.Length; n++) { int num4 = Find(array, n); if (array6[num4] < 0) { array6[num4] = result++; } _cluster[n] = array6[num4]; } return result; } private int CollectLinkedRoots(int s, float linkSlack, int[] parent, bool[] admitted, int[] roots, float[] rootDistance) { int num = 0; for (int i = 0; i < _nodes.Length; i++) { if (admitted[i] && AreLinked(in _nodes[s], in _nodes[i], linkSlack)) { int num2 = Find(parent, i); float num3 = Distance(in _nodes[s], in _nodes[i]); int num4 = Array.IndexOf(roots, num2, 0, num); if (num4 >= 0) { rootDistance[num4] = Math.Min(rootDistance[num4], num3); continue; } roots[num] = num2; rootDistance[num] = num3; num++; } } Array.Sort(rootDistance, roots, 0, num); return num; } private int AcceptRoots(int s, int[] parent, bool[] admitted, int[] roots, int rootCount) { int[] array = new int[_nodes.Length + 1]; array[0] = _nodes[s].Type; int seenCount = 1; int result = 0; for (int i = 0; i < rootCount; i++) { if (TypesConflict(roots[i], parent, admitted, array, seenCount)) { continue; } for (int j = 0; j < _nodes.Length; j++) { if (admitted[j] && Find(parent, j) == roots[i]) { array[seenCount++] = _nodes[j].Type; } } roots[result++] = roots[i]; } return result; } private bool TypesConflict(int root, int[] parent, bool[] admitted, int[] seen, int seenCount) { for (int i = 0; i < _nodes.Length; i++) { if (admitted[i] && Find(parent, i) == root && Array.IndexOf(seen, _nodes[i].Type, 0, seenCount) >= 0) { return true; } } return false; } private int ComparePriority(int a, int b) { int num = _nodes[b].Range.CompareTo(_nodes[a].Range); if (num != 0) { return num; } int num2 = _nodes[a].Order.CompareTo(_nodes[b].Order); if (num2 != 0) { return num2; } int num3 = _nodes[a].X.CompareTo(_nodes[b].X); if (num3 != 0) { return num3; } int num4 = _nodes[a].Z.CompareTo(_nodes[b].Z); if (num4 == 0) { return a.CompareTo(b); } return num4; } private static int Find(int[] parent, int i) { while (parent[i] != i) { parent[i] = parent[parent[i]]; i = parent[i]; } return i; } } [HarmonyPatch(typeof(CraftingStation), "HaveBuildStationInRange")] internal static class HaveBuildStationInRangePatch { private static void Postfix(string name, Vector3 point, ref CraftingStation __result) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)__result != (Object)null) { __result = StationClusters.PreferLinked(__result, point); } else { __result = StationClusters.FindLinked(name, point); } } } [HarmonyPatch(typeof(CraftingStation), "Start")] internal static class StationStartPatch { private static void Postfix(CraftingStation __instance) { StationClusters.Invalidate(); PlacementNotice.Started(__instance); } } [HarmonyPatch(typeof(CraftingStation), "OnDestroy")] internal static class StationDestroyPatch { private static void Postfix() { StationClusters.Invalidate(); } } } namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] internal sealed class IgnoresAccessChecksToAttribute : Attribute { internal IgnoresAccessChecksToAttribute(string assemblyName) { } } }