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 WardZone v1.1.0
WardZone.dll
Decompiled a day agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Jotunn.Entities; using Jotunn.Managers; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyCompany("WardZone")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.1.0.0")] [assembly: AssemblyInformationalVersion("1.1.0")] [assembly: AssemblyProduct("WardZone")] [assembly: AssemblyTitle("WardZone")] [assembly: AssemblyVersion("1.1.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 WardZone { [HarmonyPatch] internal static class CfcBridge { public const string Guid = "aedenthorn.CraftFromContainers"; private const string PluginType = "CraftFromContainers.BepInExPlugin"; private static FieldInfo s_containerList; private static FieldInfo s_lastPosition; private static FieldInfo s_pullByDistance; private static Func<Container, bool> s_allowType; private static Func<Container, long, bool> s_checkAccess; private static List<Container> s_lastExtended; private static bool s_failed; public static bool Attached { get; private set; } private static bool PullByDistance { get { if (s_pullByDistance?.GetValue(null) is ConfigEntry<bool> val) { return val.Value; } return false; } } private static bool Prepare() { Type type = AccessTools.TypeByName("CraftFromContainers.BepInExPlugin"); if (type == null) { return false; } MethodInfo methodInfo = Target(type); s_containerList = AccessTools.Field(type, "containerList"); s_lastPosition = AccessTools.Field(type, "lastPosition"); s_pullByDistance = AccessTools.Field(type, "pullByDistance"); MethodInfo methodInfo2 = AccessTools.Method(type, "AllowContainerType", new Type[1] { typeof(Container) }, (Type[])null); MethodInfo methodInfo3 = AccessTools.Method(typeof(Container), "CheckAccess", new Type[1] { typeof(long) }, (Type[])null); if (methodInfo == null || methodInfo.ReturnType != typeof(List<Container>) || s_containerList == null || !s_containerList.IsStatic || !typeof(List<Container>).IsAssignableFrom(s_containerList.FieldType) || methodInfo3 == null) { ManualLogSource log = WardZonePlugin.Log; if (log != null) { log.LogWarning((object)"CraftFromContainers has no GetNearbyContainers(Vector3)/containerList of the known shape: chests stay within its range"); } return false; } if (s_lastPosition != null && (!s_lastPosition.IsStatic || s_lastPosition.FieldType != typeof(Vector3))) { s_lastPosition = null; } if (s_pullByDistance != null && (!s_pullByDistance.IsStatic || s_pullByDistance.FieldType != typeof(ConfigEntry<bool>))) { s_pullByDistance = null; } s_allowType = ((methodInfo2 != null && methodInfo2.IsStatic && methodInfo2.ReturnType == typeof(bool)) ? AccessTools.MethodDelegate<Func<Container, bool>>(methodInfo2, (object)null, true) : ((Func<Container, bool>)((Container container) => true))); s_checkAccess = AccessTools.MethodDelegate<Func<Container, long, bool>>(methodInfo3, (object)null, true); Attached = true; return true; } private static MethodBase TargetMethod() { return Target(AccessTools.TypeByName("CraftFromContainers.BepInExPlugin")); } private static MethodInfo Target(Type plugin) { if (!(plugin == null)) { return AccessTools.Method(plugin, "GetNearbyContainers", new Type[1] { typeof(Vector3) }, (Type[])null); } return null; } public static void InvalidateCache() { //IL_0019: Unknown result type (might be due to invalid IL or missing references) if (Attached) { s_lastExtended = null; s_lastPosition?.SetValue(null, Vector3.positiveInfinity); } } private static void Postfix(Vector3 center, ref List<Container> __result) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) if (s_failed || __result == null || __result == s_lastExtended || !WardZonePlugin.ContainersFromZone.Value) { return; } s_lastExtended = __result; try { Extend(center, __result); } catch (Exception ex) { s_failed = true; WardZonePlugin.Log.LogError((object)("Chests from the zone are disabled after an error: " + ex)); } } private static void Extend(Vector3 center, List<Container> result) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: 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) //IL_00a7: 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) //IL_00af: 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) Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return; } Zone zone = ZoneMap.ZoneAt(center); if (zone == null || (WardZonePlugin.ContainersNeedAccess.Value && WardApi.Ready && !zone.Chain.HasLocalAccess()) || !(s_containerList.GetValue(null) is List<Container> list)) { return; } HashSet<Container> hashSet = new HashSet<Container>(result); long playerID = localPlayer.GetPlayerID(); int num = 0; for (int i = 0; i < list.Count; i++) { Container val = list[i]; if (!((Object)(object)val == (Object)null) && !hashSet.Contains(val)) { Vector3 position = ((Component)val).transform.position; if (zone.Contains(position) && s_allowType(val) && s_checkAccess(val, playerID) && !val.IsInUse() && val.GetInventory() != null && !((Object)(object)((Component)val).GetComponentInParent<Piece>() == (Object)null) && (!val.m_checkGuardStone || PrivateArea.CheckAccess(position, 0f, false, false))) { result.Add(val); num++; } } } if (num > 0 && PullByDistance) { result.Sort((Container a, Container b) => Vector3.Distance(center, ((Component)a).transform.position).CompareTo(Vector3.Distance(center, ((Component)b).transform.position))); } } } [HarmonyPatch(typeof(PrivateArea), "Interact")] internal static class PrivateArea_Interact_Patch { private static void Prefix(PrivateArea __instance, Humanoid human, bool hold) { try { ChainSync.OnInteract(__instance, human, hold); } catch (Exception ex) { WardZonePlugin.Log.LogError((object)("Chain sync failed: " + ex)); } } } internal static class ChainSync { public static void OnInteract(PrivateArea area, Humanoid human, bool hold) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) if (hold || (int)area.m_ownerFaction != 0 || !WardApi.Ready) { return; } Player val = (Player)(object)((human is Player) ? human : null); if ((Object)(object)val == (Object)null || (Object)(object)val != (Object)(object)Player.m_localPlayer) { return; } ZNetView val2 = WardApi.View(area); if ((Object)(object)val2 == (Object)null || !val2.IsValid()) { return; } Ward ward = ZoneMap.WardOf(area); if (ward != null && ward.Chain != null && ward.Chain.Wards.Count >= 2) { Piece val3 = WardApi.PieceOf(area); if ((Object)(object)val3 != (Object)null && val3.IsCreator()) { SyncEnabled(ward, !WardApi.IsEnabled(area)); } else if (!WardApi.IsEnabled(area)) { SyncPermitted(ward, val, !WardApi.IsPermitted(area, val.GetPlayerID())); } } } private static void SyncEnabled(Ward ward, bool enabled) { if (!WardZonePlugin.SyncEnabled.Value) { return; } int num = 0; foreach (Ward ward2 in ward.Chain.Wards) { if (ward2 != ward && !((Object)(object)ward2.Area == (Object)null) && WardApi.IsEnabled(ward2.Area) != enabled && Claim(ward2)) { WardApi.SetEnabled(ward2.Area, enabled); num++; } } if (num > 0) { ZoneText.Message(enabled ? "$q8wz_chain_on" : "$q8wz_chain_off", ward.Chain.Wards.Count); } } private static void SyncPermitted(Ward ward, Player player, bool add) { if (!WardZonePlugin.SyncPermitted.Value) { return; } long playerID = player.GetPlayerID(); int num = 0; foreach (Ward ward2 in ward.Chain.Wards) { if (ward2 != ward && !((Object)(object)ward2.Area == (Object)null) && WardApi.IsPermitted(ward2.Area, playerID) != add && Claim(ward2)) { if (add) { WardApi.AddPermitted(ward2.Area, playerID, player.GetPlayerName()); } else { WardApi.RemovePermitted(ward2.Area, playerID); } num++; } } if (num > 0) { ZoneText.Message(add ? "$q8wz_chain_added" : "$q8wz_chain_removed", ward.Chain.Wards.Count); } ZoneMap.MarkDirty(); } private static bool Claim(Ward other) { ZNetView view = other.View; if ((Object)(object)view == (Object)null || !view.IsValid()) { return false; } if (!view.IsOwner()) { view.ClaimOwnership(); } return view.IsOwner(); } } [HarmonyPatch(typeof(PrivateArea), "Awake")] internal static class PrivateArea_Awake_Patch { private static void Postfix(PrivateArea __instance) { ZoneMap.MarkDirty(); Placement.OnWardAwake(__instance); } } [HarmonyPatch(typeof(PrivateArea), "OnDestroy")] internal static class PrivateArea_OnDestroy_Patch { private static void Postfix() { ZoneMap.MarkDirty(); } } [HarmonyPatch(typeof(PrivateArea), "GetHoverText")] internal static class PrivateArea_GetHoverText_Patch { private static void Postfix(PrivateArea __instance, ref string __result) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) if (string.IsNullOrEmpty(__result) || (int)__instance.m_ownerFaction != 0) { return; } Ward ward = ZoneMap.WardOf(__instance); if (ward == null) { return; } if (ward.Zone != null && WardZonePlugin.ShowZoneOnHover.Value) { foreach (Ward ward2 in ward.Zone.Wards) { if (ward2 != ward && (Object)(object)ward2.Area != (Object)null) { ward2.Area.ShowAreaMarker(); } } } if (WardZonePlugin.HoverText.Value) { __result = __result + "\n" + ZoneText.Hover(ward); } } } [HarmonyPatch(typeof(Piece), "GetAllComfortPiecesInRadius")] internal static class Piece_GetAllComfortPiecesInRadius_Patch { private static HashSet<Piece> s_allComfortPieces; private static int s_ghostLayer = -1; private static bool Prefix(Vector3 p, float radius, List<Piece> pieces) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: 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) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) if (!WardZonePlugin.ComfortFromZone.Value) { return true; } Zone zone = ZoneMap.ZoneAt(p); if (zone == null) { return true; } if (s_allComfortPieces == null) { s_allComfortPieces = AccessTools.Field(typeof(Piece), "s_allComfortPieces")?.GetValue(null) as HashSet<Piece>; if (s_allComfortPieces == null) { WardZonePlugin.Log.LogWarning((object)"Piece.s_allComfortPieces not found: comfort stays within 10 m"); return true; } } if (s_ghostLayer < 0) { s_ghostLayer = LayerMask.NameToLayer("ghost"); } foreach (Piece s_allComfortPiece in s_allComfortPieces) { if (!((Object)(object)s_allComfortPiece == (Object)null) && ((Component)s_allComfortPiece).gameObject.layer != s_ghostLayer) { Vector3 position = ((Component)s_allComfortPiece).transform.position; if (Vector3.Distance(p, position) < radius || zone.Contains(position)) { pieces.Add(s_allComfortPiece); } } } return false; } } internal static class Placement { public static void OnWardAwake(PrivateArea area) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) if (WardZonePlugin.PlacementMessage.Value && (int)area.m_ownerFaction == 0) { ZNetView component = ((Component)area).GetComponent<ZNetView>(); if (!((Object)(object)component == (Object)null) && component.IsValid() && component.IsOwner() && component.GetZDO().GetLong(ZDOVars.s_creator, 0L) == 0L) { ((MonoBehaviour)WardZonePlugin.Instance).StartCoroutine(Announce(area)); } } } private static IEnumerator Announce(PrivateArea area) { yield return null; if (!((Object)(object)area == (Object)null) && !((Object)(object)Player.m_localPlayer == (Object)null)) { ZoneMap.MarkDirty(); Ward ward = ZoneMap.WardOf(area); if (ward != null) { ((Character)Player.m_localPlayer).Message((MessageType)1, ZoneText.Placed(ward), 0, (Sprite)null, false); } } } } internal static class ZoneText { public static string Hover(Ward ward) { int value = WardZonePlugin.MaxWards.Value; if (ward.Zone == null) { return "<color=orange>" + Format("$q8wz_outside", value, Wards(value)) + "</color>"; } int count = ward.Zone.Wards.Count; string text = ((value > 0) ? (count + " " + L("$q8wz_of") + " " + value) : (count + " " + Wards(count))); string text2 = "<color=#8fd3ff>" + L("$q8wz_zone") + ": " + text + " · " + L("$q8wz_coverage") + " ~" + Thousands(RoundArea(ward.Zone.AreaM2)) + " " + L("$q8wz_m2") + "</color>"; bool flag = CfcBridge.Attached && WardZonePlugin.ContainersFromZone.Value && WardZonePlugin.ContainersNeedAccess.Value; bool value2 = WardZonePlugin.StationsFromZone.Value; if ((flag || value2) && WardApi.Ready && !ward.Chain.HasLocalAccess()) { string token = ((flag && value2) ? "$q8wz_noaccess_both" : (value2 ? "$q8wz_noaccess_stations" : "$q8wz_noaccess")); text2 = text2 + "\n<color=orange>" + L(token) + "</color>"; } return text2; } public static void Message(string token, int count) { if ((Object)(object)Player.m_localPlayer != (Object)null) { ((Character)Player.m_localPlayer).Message((MessageType)1, Format(token, count), 0, (Sprite)null, false); } } public static string Placed(Ward ward) { int value = WardZonePlugin.MaxWards.Value; if (ward.Zone == null) { return Format("$q8wz_full", value, Wards(value)); } int count = ward.Zone.Wards.Count; if (value <= 0) { return Format("$q8wz_joined_count", count, Wards(count)); } return Format("$q8wz_joined", count, L("$q8wz_of"), value); } private static string L(string token) { return Localization.instance.Localize(token); } private static string Format(string token, params object[] args) { return string.Format(L(token), args); } private static string Wards(int count) { bool num = Localization.instance.GetSelectedLanguage() == "Russian"; int num2 = count % 10; int num3 = count % 100; if (num) { if (num2 == 1 && num3 != 11) { return L("$q8wz_ward_1"); } if (num2 >= 2 && num2 <= 4 && (num3 < 12 || num3 > 14)) { return L("$q8wz_ward_2"); } return L("$q8wz_ward_5"); } return L((count == 1) ? "$q8wz_ward_1" : "$q8wz_ward_2"); } private static int RoundArea(double area) { int num = ((area >= 1000.0) ? 100 : 10); return (int)Math.Round(area / (double)num) * num; } private static string Thousands(int value) { string text = value.ToString(); if (text.Length <= 3) { return text; } StringBuilder stringBuilder = new StringBuilder(); int num = text.Length % 3; if (num > 0) { stringBuilder.Append(text, 0, num); } for (int i = num; i < text.Length; i += 3) { if (stringBuilder.Length > 0) { stringBuilder.Append(' '); } stringBuilder.Append(text, i, 3); } return stringBuilder.ToString(); } } [BepInPlugin("qua8ion.valheim.wardzone", "WardZone", "1.1.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] public class WardZonePlugin : BaseUnityPlugin { public const string PluginGuid = "qua8ion.valheim.wardzone"; public const string PluginName = "WardZone"; public const string PluginVersion = "1.1.0"; internal static WardZonePlugin Instance; internal static ManualLogSource Log; internal static ConfigEntry<int> MaxWards; internal static ConfigEntry<bool> ComfortFromZone; internal static ConfigEntry<bool> ContainersFromZone; internal static ConfigEntry<bool> ContainersNeedAccess; internal static ConfigEntry<bool> StationsFromZone; internal static ConfigEntry<bool> SyncEnabled; internal static ConfigEntry<bool> SyncPermitted; internal static ConfigEntry<bool> ShowZoneOnHover; internal static ConfigEntry<bool> HoverText; internal static ConfigEntry<bool> PlacementMessage; private void Awake() { //IL_0211: Unknown result type (might be due to invalid IL or missing references) Instance = this; Log = ((BaseUnityPlugin)this).Logger; MaxWards = Rule("Zone", "MaxWards", 8, "How many wards one zone can hold. Wards whose circles touch form a chain; the zone grows from the oldest ward of the chain and stops at this many. The rest stay ordinary wards outside the zone. 0: no limit.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 1000)); ComfortFromZone = Rule("Zone", "ComfortFromZone", value: true, "Inside a zone the comfort level counts every comfort piece in the zone, not only those within 10 m."); ContainersFromZone = Rule("Zone", "ContainersFromZone", value: true, "Inside a zone CraftFromContainers pulls from every chest in the zone, not only those within its range. Needs CraftFromContainers (aedenthorn / UnderHeiz)."); ContainersNeedAccess = Rule("Zone", "ContainersNeedAccess", value: true, "Chests of the zone are pulled only for players written into a ward of the chain, or its builder. Comfort is for everyone regardless."); StationsFromZone = Rule("Zone", "StationsFromZone", value: true, "A workbench, forge or any other crafting station inside a zone counts as near everywhere in the zone: you can build, repair and remove pieces that need it anywhere in the zone. Only for players written into a ward of the chain, or its builder."); SyncEnabled = Rule("Zone", "SyncEnabled", value: true, "Enabling or disabling a ward does the same to every ward of its chain, whoever built them. As in the game, only the ward's builder can switch it."); SyncPermitted = Rule("Zone", "SyncPermitted", value: true, "Writing yourself into a ward, or out of it, does the same in every ward of its chain. As in the game, this is done on a disabled ward."); ShowZoneOnHover = ((BaseUnityPlugin)this).Config.Bind<bool>("Display", "ShowZoneOnHover", true, "Looking at a ward shows the circles of every ward in its zone, not only its own."); HoverText = ((BaseUnityPlugin)this).Config.Bind<bool>("Display", "HoverText", true, "Add a line about the zone to the ward's hover text: how many wards, coverage in m2."); PlacementMessage = ((BaseUnityPlugin)this).Config.Bind<bool>("Display", "PlacementMessage", true, "After placing a ward, say whether it joined the zone or the zone is already full."); MaxWards.SettingChanged += delegate { ZoneMap.MarkDirty(); }; StationsFromZone.SettingChanged += delegate { ZoneMap.MarkDirty(); }; ComfortFromZone.SettingChanged += delegate { ZoneMap.MarkDirty(); }; ContainersFromZone.SettingChanged += delegate { ZoneMap.MarkDirty(); }; SynchronizationManager.OnConfigurationSynchronized += delegate { ZoneMap.MarkDirty(); }; AddLocalization(); new Harmony("qua8ion.valheim.wardzone").PatchAll(Assembly.GetExecutingAssembly()); if (!WardApi.Ready) { Log.LogWarning((object)"PrivateArea has changed: chain switching, chain permissions and the access check are off"); } Log.LogInfo((object)(CfcBridge.Attached ? "Wards whose circles touch share one zone: comfort and CraftFromContainers reach the whole zone" : "Wards whose circles touch share one zone: comfort reaches the whole zone (CraftFromContainers not found, chests unchanged)")); } private void Update() { ZoneMap.Tick(); } private ConfigEntry<T> Rule<T>(string section, string key, T value, string description, AcceptableValueBase range = null) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Expected O, but got Unknown //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Expected O, but got Unknown return ((BaseUnityPlugin)this).Config.Bind<T>(section, key, value, new ConfigDescription(description, range, new object[1] { (object)new ConfigurationManagerAttributes { IsAdminOnly = true } })); } private static void AddLocalization() { CustomLocalization localization = LocalizationManager.Instance.GetLocalization(); string text = "English"; localization.AddTranslation(ref text, new Dictionary<string, string> { { "q8wz_zone", "Ward zone" }, { "q8wz_of", "of" }, { "q8wz_coverage", "coverage" }, { "q8wz_m2", "m²" }, { "q8wz_ward_1", "ward" }, { "q8wz_ward_2", "wards" }, { "q8wz_ward_5", "wards" }, { "q8wz_outside", "Outside the ward zone: it already holds its limit of {0} {1}" }, { "q8wz_noaccess", "Chests of the zone: only for players written into a ward" }, { "q8wz_noaccess_stations", "Workbenches of the zone: only for players written into a ward" }, { "q8wz_noaccess_both", "Chests and workbenches of the zone: only for players written into a ward" }, { "q8wz_joined", "The ward joined the zone: {0} {1} {2}" }, { "q8wz_joined_count", "The ward joined the zone: now {0} {1}" }, { "q8wz_full", "The zone is full ({0} {1}): this ward stays outside it" }, { "q8wz_chain_on", "All wards of the chain are on: {0}" }, { "q8wz_chain_off", "All wards of the chain are off: {0}" }, { "q8wz_chain_added", "Written into every ward of the chain: {0}" }, { "q8wz_chain_removed", "Removed from every ward of the chain: {0}" } }); text = "Russian"; localization.AddTranslation(ref text, new Dictionary<string, string> { { "q8wz_zone", "Зона тотемов" }, { "q8wz_of", "из" }, { "q8wz_coverage", "покрытие" }, { "q8wz_m2", "м²" }, { "q8wz_ward_1", "тотем" }, { "q8wz_ward_2", "тотема" }, { "q8wz_ward_5", "тотемов" }, { "q8wz_outside", "Вне зоны тотемов: в ней уже {0} {1}, это потолок" }, { "q8wz_noaccess", "Сундуки зоны — только вписанным в тотем" }, { "q8wz_noaccess_stations", "Верстаки зоны — только вписанным в тотем" }, { "q8wz_noaccess_both", "Сундуки и верстаки зоны — только вписанным в тотем" }, { "q8wz_joined", "Тотем вошёл в зону: {0} {1} {2}" }, { "q8wz_joined_count", "Тотем вошёл в зону: теперь {0} {1}" }, { "q8wz_full", "Зона уже полная ({0} {1}): этот тотем остался вне зоны" }, { "q8wz_chain_on", "Включены все тотемы цепи: {0}" }, { "q8wz_chain_off", "Выключены все тотемы цепи: {0}" }, { "q8wz_chain_added", "Вписан во все тотемы цепи: {0}" }, { "q8wz_chain_removed", "Выписан из всех тотемов цепи: {0}" } }); } } [HarmonyPatch(typeof(CraftingStation), "HaveBuildStationInRange")] internal static class CraftingStation_HaveBuildStationInRange_Patch { private static List<CraftingStation> s_allStations; private static bool s_failed; private static bool Prepare() { s_allStations = AccessTools.Field(typeof(CraftingStation), "m_allStations")?.GetValue(null) as List<CraftingStation>; if (s_allStations == null) { ManualLogSource log = WardZonePlugin.Log; if (log != null) { log.LogWarning((object)"CraftingStation.m_allStations not found: workbenches keep their own range"); } } return s_allStations != null; } [HarmonyPriority(200)] private static void Postfix(string name, Vector3 point, ref CraftingStation __result) { //IL_0035: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)__result != (Object)null || s_failed || !WardZonePlugin.StationsFromZone.Value || (Object)(object)Player.m_localPlayer == (Object)null || !WardApi.Ready) { return; } try { __result = Find(name, point); } catch (Exception ex) { s_failed = true; WardZonePlugin.Log.LogError((object)("Workbenches from the zone are disabled after an error: " + ex)); } } private static CraftingStation Find(string name, Vector3 point) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) Zone zone = ZoneMap.ZoneAt(point); if (zone == null || !zone.Chain.HasLocalAccess()) { return null; } CraftingStation result = null; float num = float.MaxValue; foreach (CraftingStation s_allStation in s_allStations) { if ((Object)(object)s_allStation == (Object)null || s_allStation.m_name != name) { continue; } Vector3 position = ((Component)s_allStation).transform.position; if (zone.Contains(position)) { float num2 = Ward.DistanceXZ(position, point); if (num2 < num) { result = s_allStation; num = num2; } } } return result; } } internal static class WardApi { private static readonly Func<PrivateArea, bool> s_isEnabled = Method<Func<PrivateArea, bool>>("IsEnabled"); private static readonly Action<PrivateArea, bool> s_setEnabled = Method<Action<PrivateArea, bool>>("SetEnabled"); private static readonly Func<PrivateArea, long, bool> s_isPermitted = Method<Func<PrivateArea, long, bool>>("IsPermitted"); private static readonly Action<PrivateArea, long, string> s_addPermitted = Method<Action<PrivateArea, long, string>>("AddPermitted"); private static readonly Action<PrivateArea, long> s_removePermitted = Method<Action<PrivateArea, long>>("RemovePermitted"); private static readonly Func<PrivateArea, bool> s_haveLocalAccess = Method<Func<PrivateArea, bool>>("HaveLocalAccess"); private static readonly FieldRef<PrivateArea, ZNetView> s_nview = AccessTools.FieldRefAccess<PrivateArea, ZNetView>("m_nview"); private static readonly FieldRef<PrivateArea, Piece> s_piece = AccessTools.FieldRefAccess<PrivateArea, Piece>("m_piece"); public static bool Ready { get { if (s_isEnabled != null && s_setEnabled != null && s_isPermitted != null && s_addPermitted != null && s_removePermitted != null) { return s_haveLocalAccess != null; } return false; } } public static bool IsEnabled(PrivateArea area) { return s_isEnabled(area); } public static void SetEnabled(PrivateArea area, bool enabled) { s_setEnabled(area, enabled); } public static bool IsPermitted(PrivateArea area, long playerId) { return s_isPermitted(area, playerId); } public static void AddPermitted(PrivateArea area, long playerId, string name) { s_addPermitted(area, playerId, name); } public static void RemovePermitted(PrivateArea area, long playerId) { s_removePermitted(area, playerId); } public static ZNetView View(PrivateArea area) { return s_nview.Invoke(area); } public static Piece PieceOf(PrivateArea area) { return s_piece.Invoke(area); } public static bool HaveLocalAccess(PrivateArea area) { if (s_haveLocalAccess != null && (Object)(object)Player.m_localPlayer != (Object)null) { return s_haveLocalAccess(area); } return false; } private static T Method<T>(string name) where T : Delegate { MethodInfo methodInfo = AccessTools.Method(typeof(PrivateArea), name, (Type[])null, (Type[])null); if (!(methodInfo == null)) { return AccessTools.MethodDelegate<T>(methodInfo, (object)null, true); } return null; } } public sealed class Ward { public PrivateArea Area; public ZNetView View; public Vector3 Pos; public float Radius; public long Stamp; public ZDOID Id; public Chain Chain; public Zone Zone; public int ChainSize { get { if (Chain == null) { return 1; } return Chain.Wards.Count; } } public bool Covers(Vector3 point) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) return DistanceXZ(Pos, point) < Radius; } public bool Touches(Ward other) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) return DistanceXZ(Pos, other.Pos) <= Radius + other.Radius; } public static float DistanceXZ(Vector3 a, Vector3 b) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: 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) //IL_0013: Unknown result type (might be due to invalid IL or missing references) float num = b.x - a.x; float num2 = b.z - a.z; return (float)Math.Sqrt(num * num + num2 * num2); } } public sealed class Chain { public readonly List<Ward> Wards = new List<Ward>(); public Zone Zone; private float m_accessCheckedAt = float.MinValue; private bool m_access; public bool HasLocalAccess() { float time = Time.time; if (time - m_accessCheckedAt < 0.5f) { return m_access; } m_accessCheckedAt = time; m_access = false; foreach (Ward ward in Wards) { if ((Object)(object)ward.Area != (Object)null && WardApi.HaveLocalAccess(ward.Area)) { m_access = true; break; } } return m_access; } } public sealed class Zone { public Chain Chain; public readonly List<Ward> Wards = new List<Ward>(); private double m_area = -1.0; public int ChainSize { get { if (Chain == null) { return Wards.Count; } return Chain.Wards.Count; } } public double AreaM2 { get { if (m_area < 0.0) { m_area = EstimateArea(); } return m_area; } } public bool Contains(Vector3 point) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) for (int i = 0; i < Wards.Count; i++) { if (Wards[i].Covers(point)) { return true; } } return false; } private double EstimateArea() { //IL_010e: Unknown result type (might be due to invalid IL or missing references) float num = float.MaxValue; float num2 = float.MinValue; float num3 = float.MaxValue; float num4 = float.MinValue; foreach (Ward ward in Wards) { num = Mathf.Min(num, ward.Pos.x - ward.Radius); num2 = Mathf.Max(num2, ward.Pos.x + ward.Radius); num3 = Mathf.Min(num3, ward.Pos.z - ward.Radius); num4 = Mathf.Max(num4, ward.Pos.z + ward.Radius); } int num5 = Mathf.CeilToInt((num2 - num) / 2f); int num6 = Mathf.CeilToInt((num4 - num3) / 2f); int num7 = 0; for (int i = 0; i < num5; i++) { float num8 = num + ((float)i + 0.5f) * 2f; for (int j = 0; j < num6; j++) { if (Contains(new Vector3(num8, 0f, num3 + ((float)j + 0.5f) * 2f))) { num7++; } } } return (double)num7 * 2.0 * 2.0; } } public static class ZoneMap { private const float RebuildInterval = 2f; private static readonly int StampHash = StringExtensionMethods.GetStableHashCode("q8wz_t"); private static readonly FieldInfo s_allAreasField = AccessTools.Field(typeof(PrivateArea), "m_allAreas"); private static readonly FieldRef<PrivateArea, ZNetView> s_nview = AccessTools.FieldRefAccess<PrivateArea, ZNetView>("m_nview"); private static readonly Dictionary<PrivateArea, Ward> s_byArea = new Dictionary<PrivateArea, Ward>(); private static readonly List<Chain> s_chains = new List<Chain>(); private static readonly List<Zone> s_zones = new List<Zone>(); private static bool s_dirty = true; private static float s_nextRebuild; public static int Version { get; private set; } public static IReadOnlyList<Zone> Zones { get { if (s_dirty) { Rebuild(); } return s_zones; } } public static IReadOnlyList<Chain> Chains { get { if (s_dirty) { Rebuild(); } return s_chains; } } public static void MarkDirty() { s_dirty = true; } public static void Tick() { if (s_dirty || Time.time >= s_nextRebuild) { Rebuild(); } } public static Zone ZoneAt(Vector3 point) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) if (s_dirty) { Rebuild(); } for (int i = 0; i < s_zones.Count; i++) { if (s_zones[i].Contains(point)) { return s_zones[i]; } } return null; } public static Ward WardOf(PrivateArea area) { if (s_dirty) { Rebuild(); } if (!((Object)(object)area != (Object)null) || !s_byArea.TryGetValue(area, out var value)) { return null; } return value; } public static void Rebuild() { s_dirty = false; s_nextRebuild = Time.time + 2f; s_chains.Clear(); s_zones.Clear(); s_byArea.Clear(); Version++; List<Ward> list = CollectWards(); s_chains.AddRange(Build(list, WardZonePlugin.MaxWards.Value)); foreach (Chain s_chain in s_chains) { s_zones.Add(s_chain.Zone); } foreach (Ward item in list) { s_byArea[item.Area] = item; } CfcBridge.InvalidateCache(); } public static List<Chain> Build(List<Ward> wards, int maxWards) { List<Chain> list = new List<Chain>(); int cap = Math.Max(0, maxWards); foreach (List<Ward> item in Groups(wards)) { item.Sort(ByAge); Chain chain = new Chain(); chain.Wards.AddRange(item); foreach (Ward item2 in item) { item2.Chain = chain; item2.Zone = null; } chain.Zone = Grow(chain, cap); list.Add(chain); } return list; } private static List<Ward> CollectWards() { //IL_004a: 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_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) List<Ward> list = new List<Ward>(); if (!(s_allAreasField?.GetValue(null) is List<PrivateArea> list2)) { return list; } long num = 0L; foreach (PrivateArea item in list2) { if ((Object)(object)item == (Object)null || (int)item.m_ownerFaction != 0) { continue; } ZNetView val = s_nview.Invoke(item); if ((Object)(object)val == (Object)null || !val.IsValid()) { continue; } ZDO zDO = val.GetZDO(); long num2 = zDO.GetLong(StampHash, 0L); if (num2 == 0L && val.IsOwner()) { if (num == 0L) { num = Now(); } num2 = num; zDO.Set(StampHash, num2); } list.Add(new Ward { Area = item, View = val, Pos = ((Component)item).transform.position, Radius = item.m_radius, Stamp = num2, Id = zDO.m_uid }); } return list; } private static long Now() { double num = (((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetTimeSeconds() : 0.0); return Math.Max(1L, (long)num); } private static List<List<Ward>> Groups(List<Ward> wards) { List<List<Ward>> list = new List<List<Ward>>(); int[] array = new int[wards.Count]; for (int i = 0; i < array.Length; i++) { array[i] = -1; } Queue<int> queue = new Queue<int>(); for (int j = 0; j < wards.Count; j++) { if (array[j] >= 0) { continue; } List<Ward> list2 = new List<Ward>(); array[j] = list.Count; queue.Enqueue(j); while (queue.Count > 0) { int index = queue.Dequeue(); list2.Add(wards[index]); for (int k = 0; k < wards.Count; k++) { if (array[k] < 0 && wards[index].Touches(wards[k])) { array[k] = list.Count; queue.Enqueue(k); } } } list.Add(list2); } return list; } private static Zone Grow(Chain chain, int cap) { Zone zone = new Zone { Chain = chain }; List<Ward> list = new List<Ward>(chain.Wards); Join(zone, list[0]); list.RemoveAt(0); while (list.Count > 0 && (cap == 0 || zone.Wards.Count < cap)) { int num = -1; for (int i = 0; i < list.Count; i++) { if (num >= 0) { break; } foreach (Ward ward in zone.Wards) { if (list[i].Touches(ward)) { num = i; break; } } } if (num < 0) { break; } Join(zone, list[num]); list.RemoveAt(num); } return zone; } private static void Join(Zone zone, Ward ward) { ward.Zone = zone; zone.Wards.Add(ward); } private static int ByAge(Ward a, Ward b) { //IL_0047: Unknown result type (might be due to invalid IL or missing references) long num = ((a.Stamp == 0L) ? long.MaxValue : a.Stamp); long value = ((b.Stamp == 0L) ? long.MaxValue : b.Stamp); int num2 = num.CompareTo(value); if (num2 == 0) { return ((ZDOID)(ref a.Id)).CompareTo(b.Id); } return num2; } } }