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 BaseDefenseWard v0.1.2
plugins/BaseDefenseWard.dll
Decompiled a month agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.Linq; 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 Microsoft.CodeAnalysis; using SoftReferenceableAssets.SceneManagement; using Splatform; using TMPro; using UnityEngine; using UnityEngine.UI; [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("BaseDefenseWard")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.1.2.0")] [assembly: AssemblyInformationalVersion("0.1.2+81884e753045922b1f64b6ffa0b0268d3bd6b5ad")] [assembly: AssemblyProduct("BaseDefenseWard")] [assembly: AssemblyTitle("BaseDefenseWard")] [assembly: AssemblyVersion("0.1.2.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 BaseDefenseWard { [HarmonyPatch(typeof(BossStone), "SetActivated")] internal static class BossStone_SetActivated { private static readonly Dictionary<string, bool> Last = new Dictionary<string, bool>(); public static string KeyFor(BossStone stone) { string text = ((Object)((Component)stone).gameObject).name.Replace("(Clone)", "").Trim(); if (text.StartsWith("BossStone_")) { text = text.Substring("BossStone_".Length); } return "bdw_hung_" + text.ToLowerInvariant(); } private static void Postfix(BossStone __instance, bool active) { if ((Object)(object)ZoneSystem.instance == (Object)null || (Object)(object)__instance.m_itemStand == (Object)null) { return; } string text = KeyFor(__instance); if (Last.TryGetValue(text, out var value) && value == active) { return; } Last[text] = active; if (active) { if (!ZoneSystem.instance.GetGlobalKey(text)) { ZoneSystem.instance.SetGlobalKey(text); } } else if (ZoneSystem.instance.GetGlobalKey(text)) { ZoneSystem.instance.RemoveGlobalKey(text); } } } public static class Cfg { public static ConfigEntry<float> CountdownMinutes; public static ConfigEntry<float> WaveTimeLimitMinutes; public static ConfigEntry<float> SpawnRadius; public static ConfigEntry<int> BaseMobCount; public static ConfigEntry<int> MobsPerCompletedChallenge; public static ConfigEntry<int> MaxMobCount; public static ConfigEntry<float> SpawnIntervalSeconds; public static ConfigEntry<float> RestMinMinutes; public static ConfigEntry<float> RestMaxMinutes; public static ConfigEntry<bool> PausableWards; public static ConfigEntry<KeyboardShortcut> PauseKey; public static ConfigEntry<bool> StartNow; public static ConfigEntry<float> PlayerHuntRange; public static ConfigEntry<float> RewardMultiplier; public static ConfigEntry<bool> DeleteWorldOnLoss; public static ConfigEntry<float> BuildDeadlineMinutes; public static ConfigEntry<string> BossKeys; public static ConfigEntry<string> ExtraMobPools; public static void Bind(ConfigFile c) { //IL_0139: Unknown result type (might be due to invalid IL or missing references) CountdownMinutes = c.Bind<float>("Challenge", "CountdownMinutes", 10f, "Minutes between building the ward and the first wave."); WaveTimeLimitMinutes = c.Bind<float>("Challenge", "WaveTimeLimitMinutes", 5f, "If the ward still stands after this many minutes the challenge is won even if mobs remain."); SpawnRadius = c.Bind<float>("Challenge", "SpawnRadius", 55f, "Distance from the ward at which wave mobs spawn (the ward's protected radius is 32)."); BaseMobCount = c.Bind<int>("Challenge", "BaseMobCount", 4, "Mobs in the first wave."); MobsPerCompletedChallenge = c.Bind<int>("Challenge", "MobsPerCompletedChallenge", 2, "Extra mobs per previously completed challenge on this world."); MaxMobCount = c.Bind<int>("Challenge", "MaxMobCount", 30, "Hard cap on mobs per wave."); SpawnIntervalSeconds = c.Bind<float>("Challenge", "SpawnIntervalSeconds", 1.5f, "Delay between individual spawns."); RestMinMinutes = c.Bind<float>("Challenge", "RestMinMinutes", 30f, "After a successful defense the ward rests for a random time between RestMinMinutes and RestMaxMinutes before the next countdown starts."); RestMaxMinutes = c.Bind<float>("Challenge", "RestMaxMinutes", 120f, "Upper bound of the rest between challenges, in minutes."); PausableWards = c.Bind<bool>("Challenge", "PausableWards", false, "Allow pausing a ward (its countdown and rest timers stop) by pressing PauseKey while standing within interact range of it. Not possible during a wave."); PauseKey = c.Bind<KeyboardShortcut>("Challenge", "PauseKey", new KeyboardShortcut((KeyCode)112, Array.Empty<KeyCode>()), "Key that pauses or resumes the ward you stand next to (only when PausableWards is on)."); StartNow = c.Bind<bool>("Challenge", "StartNow", true, "Interacting with the ward (Use key) during the countdown starts the wave immediately instead of toggling the ward."); PlayerHuntRange = c.Bind<float>("Challenge", "PlayerHuntRange", 40f, "Mobs switch to hunting a player who is within this range of them and not sheltered (roofed and walled in). Otherwise they go for the ward."); RewardMultiplier = c.Bind<float>("Rewards", "RewardMultiplier", 1f, "Scales all reward amounts."); DeleteWorldOnLoss = c.Bind<bool>("Consequences", "DeleteWorldOnLoss", false, "If the ward is destroyed during a wave (or the build deadline is missed) the world save is deleted and the game exits. Dedicated servers exit so a wrapper script can restart them."); BuildDeadlineMinutes = c.Bind<float>("Consequences", "BuildDeadlineMinutes", 0f, "If > 0, a ward must be built within this many minutes of world creation or the challenge counts as lost. 0 = off."); BossKeys = c.Bind<string>("Progression", "BossKeys", "bdw_hung_eikthyr,bdw_hung_theelder,bdw_hung_bonemass,bdw_hung_dragonqueen,bdw_hung_yagluth,bdw_hung_thequeen,bdw_hung_fader", "Global keys in tier order; the highest tier whose key is set decides which mob pools are unlocked. The bdw_hung_* keys are set by this mod when a trophy is hung on the corresponding boss stone. To use boss kills instead: defeated_eikthyr,defeated_gdking,defeated_bonemass,defeated_dragon,defeated_goblinking,defeated_queen,defeated_fader"); ExtraMobPools = c.Bind<string>("Progression", "ExtraMobPools", "", "Optional override of the mob pools, one tier per ';', prefabs per ',' e.g. 'Greyling,Neck;Greydwarf,Skeleton'. Empty = built-in pools."); } } public static class Deadline { private static float _timer; public static void Tick(float dt) { _timer -= dt; if (_timer > 0f) { return; } _timer = 1f; if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer() || (Object)(object)ZoneSystem.instance == (Object)null) { return; } double timeSeconds = ZNet.instance.GetTimeSeconds(); string s = default(string); long result; if (!ZoneSystem.instance.GetGlobalKey("bdw_worldstart", ref s)) { Progress.SetValue("bdw_worldstart", ((long)timeSeconds).ToString(CultureInfo.InvariantCulture)); } else if (!(Cfg.BuildDeadlineMinutes.Value <= 0f) && !Progress.Has("bdw_built") && !Progress.Has("bdw_deadline_failed") && long.TryParse(s, NumberStyles.Any, CultureInfo.InvariantCulture, out result) && !(timeSeconds - (double)result < (double)Cfg.BuildDeadlineMinutes.Value * 60.0)) { ZoneSystem.instance.SetGlobalKey("bdw_deadline_failed"); Plugin.Log.LogWarning((object)"Build deadline missed: no Base Defense Ward was built in time"); WardChallenge.Say("No ward was built in time. Challenge lost."); if (Cfg.DeleteWorldOnLoss.Value) { WorldReset.Schedule("build deadline missed"); } } } public static string Status() { if ((Object)(object)ZNet.instance == (Object)null) { return "no znet"; } string text = default(string); ZoneSystem.instance.GetGlobalKey("bdw_worldstart", ref text); return string.Format("deadlineMin={0} worldStart={1} now={2:0} built={3} failed={4}", Cfg.BuildDeadlineMinutes.Value, text, ZNet.instance.GetTimeSeconds(), Progress.Has("bdw_built"), Progress.Has("bdw_deadline_failed")); } } public static class Interaction { public static WardChallenge NearestInReach(Player p) { float reach = p.m_maxInteractDistance; return (from w in WardChallenge.All where (Object)(object)w != (Object)null && (Object)(object)w.View != (Object)null && w.View.IsValid() select (w: w, d: Vector3.Distance(((Component)w).transform.position, ((Component)p).transform.position)) into t where t.d <= reach orderby t.d select t.w).FirstOrDefault(); } public static string TogglePause(Player p) { if (!Cfg.PausableWards.Value) { return "Pausing wards is disabled in the config."; } WardChallenge wardChallenge = NearestInReach(p); if ((Object)(object)wardChallenge == (Object)null) { return "No Base Defense Ward within reach."; } if (wardChallenge.State == ChallengeState.Active) { return "A wave is attacking. The ward cannot be paused now."; } wardChallenge.RequestTogglePause(); return null; } public static string StartNow(WardChallenge w) { if (!Cfg.StartNow.Value) { return "Starting the wave early is disabled in the config."; } if (w.State != ChallengeState.Countdown) { return null; } w.RequestStartNow(); return "The wave is called early!"; } public static void Tick() { //IL_0039: 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) if (!Cfg.PausableWards.Value || (Object)(object)Player.m_localPlayer == (Object)null || Console.IsVisible()) { return; } Chat instance = Chat.instance; if (instance != null && instance.HasFocus()) { return; } KeyboardShortcut value = Cfg.PauseKey.Value; if (((KeyboardShortcut)(ref value)).IsDown()) { string text = TogglePause(Player.m_localPlayer); if (text != null) { ((Character)Player.m_localPlayer).Message((MessageType)2, text, 0, (Sprite)null, false); } } } } [HarmonyPatch(typeof(PrivateArea), "Interact")] internal static class PrivateArea_Interact { private static bool Prefix(PrivateArea __instance, Humanoid human, bool hold, ref bool __result) { if (hold || !Cfg.StartNow.Value) { return true; } WardChallenge component = ((Component)__instance).GetComponent<WardChallenge>(); if ((Object)(object)component == (Object)null || (Object)(object)component.View == (Object)null || !component.View.IsValid() || component.State != ChallengeState.Countdown) { return true; } string text = Interaction.StartNow(component); if (text != null) { Player val = (Player)(object)((human is Player) ? human : null); if (val != null) { ((Character)val).Message((MessageType)2, text, 0, (Sprite)null, false); } } __result = true; return false; } } [HarmonyPatch(typeof(PrivateArea), "GetHoverText")] internal static class PrivateArea_GetHoverText { private static void Postfix(PrivateArea __instance, ref string __result) { //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) WardChallenge component = ((Component)__instance).GetComponent<WardChallenge>(); if ((Object)(object)component == (Object)null || (Object)(object)component.View == (Object)null || !component.View.IsValid()) { return; } List<string> list = new List<string>(); switch (component.State) { case ChallengeState.Countdown: list.Add("Wave in " + Fmt(Cfg.CountdownMinutes.Value * 60f - component.Elapsed) + (component.Paused ? " (paused)" : "")); if (Cfg.StartNow.Value) { list.Add("[<color=yellow><b>$KEY_Use</b></color>] Start the wave now"); } break; case ChallengeState.Active: list.Add("Wave! hold " + Fmt(Cfg.WaveTimeLimitMinutes.Value * 60f - component.WaveElapsed)); break; case ChallengeState.Resting: list.Add("Defended. Next wave in " + Fmt(component.RestFor - component.RestElapsed) + (component.Paused ? " (paused)" : "")); break; } if (Cfg.PausableWards.Value && component.State != ChallengeState.Active) { KeyboardShortcut value = Cfg.PauseKey.Value; list.Add(string.Format("[<color=yellow><b>{0}</b></color>] {1} the ward", ((KeyboardShortcut)(ref value)).MainKey, component.Paused ? "Resume" : "Pause")); } if (list.Count > 0) { __result = Localization.instance.Localize(__result + "\n" + string.Join("\n", list)); } } private static string Fmt(float s) { if (s < 0f) { s = 0f; } TimeSpan timeSpan = TimeSpan.FromSeconds(s); if (!(timeSpan.TotalHours >= 1.0)) { return $"{timeSpan.Minutes:00}:{timeSpan.Seconds:00}"; } return $"{(int)timeSpan.TotalHours}:{timeSpan.Minutes:00}:{timeSpan.Seconds:00}"; } } public static class MobPool { private static readonly string[][] Builtin = new string[8][] { new string[3] { "Greyling", "Neck", "Boar" }, new string[4] { "Greydwarf", "Greydwarf_Shaman", "Skeleton", "Greydwarf_Elite" }, new string[5] { "Draugr", "Draugr_Ranged", "Blob", "Skeleton_Poison", "Troll" }, new string[5] { "Wolf", "Draugr_Elite", "Fenring", "Ulv", "Wraith" }, new string[4] { "Goblin", "GoblinArcher", "GoblinShaman", "GoblinBrute" }, new string[4] { "Seeker", "SeekerBrute", "Tick", "Gjall" }, new string[4] { "Charred_Melee", "Charred_Archer", "Charred_Mage", "Charred_Twitcher" }, new string[4] { "Charred_Melee", "Charred_Archer", "Charred_Mage", "Morgen" } }; private static readonly (string, int)[][] Rewards = new(string, int)[8][] { new(string, int)[3] { ("Coins", 25), ("Flint", 10), ("LeatherScraps", 8) }, new(string, int)[4] { ("Coins", 50), ("Copper", 6), ("Tin", 4), ("SurtlingCore", 2) }, new(string, int)[4] { ("Coins", 80), ("Iron", 6), ("Bronze", 4), ("Chain", 1) }, new(string, int)[4] { ("Coins", 120), ("Silver", 6), ("WolfPelt", 3), ("Obsidian", 6) }, new(string, int)[4] { ("Coins", 160), ("BlackMetal", 6), ("LinenThread", 6), ("Needle", 2) }, new(string, int)[4] { ("Coins", 220), ("BlackMarble", 12), ("Eitr", 6), ("Sap", 6) }, new(string, int)[4] { ("Coins", 300), ("FlametalNew", 6), ("Grausten", 12), ("Blackwood", 12) }, new(string, int)[4] { ("Coins", 400), ("FlametalNew", 10), ("Grausten", 16), ("CharredBone", 8) } }; public static string[][] Pools() { string value = Cfg.ExtraMobPools.Value; if (string.IsNullOrWhiteSpace(value)) { return Builtin; } return (from t in value.Split(';') select (from x in t.Split(',') select x.Trim() into x where x.Length > 0 select x).ToArray()).ToArray(); } public static List<string> Sample(int count, int bossTier, int completed, Random rng) { string[][] array = Pools(); int num = Mathf.Clamp(bossTier, 0, array.Length - 1); float[] array2 = new float[num + 1]; for (int i = 0; i <= num; i++) { float num2 = 1f + ((i == num) ? 2f : 0f) + (float)i * 0.5f + (float)completed * 0.25f * (float)i; array2[i] = num2; } List<string> list = new List<string>(); for (int j = 0; j < count; j++) { int num3 = Weighted(array2, rng); string[] array3 = array[num3].Where(Exists).ToArray(); if (array3.Length == 0) { array3 = array[0].Where(Exists).ToArray(); } if (array3.Length == 0) { break; } list.Add(array3[rng.Next(array3.Length)]); } return list; } public static List<(string prefab, int amount)> RewardFor(int bossTier, int completed) { int num = Mathf.Clamp(bossTier, 0, Rewards.Length - 1); float scale = (1f + 0.25f * (float)completed) * Cfg.RewardMultiplier.Value; return (from r in Rewards[num] where Exists(r.Item1) select (r.Item1, Mathf.Max(1, Mathf.RoundToInt((float)r.Item2 * scale)))).ToList(); } private static bool Exists(string prefab) { if ((Object)(object)ZNetScene.instance != (Object)null) { return (Object)(object)ZNetScene.instance.GetPrefab(prefab) != (Object)null; } return false; } private static int Weighted(float[] w, Random rng) { float num = w.Sum(); float num2 = (float)rng.NextDouble() * num; for (int i = 0; i < w.Length; i++) { num2 -= w[i]; if (num2 <= 0f) { return i; } } return w.Length - 1; } } public static class OnePerPlayer { public static readonly int HState = StringExtensionMethods.GetStableHashCode("bdw_state"); public static int BlockedCount; public static int RemovedCount; public static bool IsWard(Piece piece) { if ((Object)(object)piece != (Object)null) { return ((Object)((Component)piece).gameObject).name.StartsWith("BaseDefenseWard"); } return false; } public static List<ZDO> WardsOf(long playerId) { List<ZDO> list = new List<ZDO>(); int num = 0; while (!ZDOMan.instance.GetAllZDOsWithPrefabIterative("BaseDefenseWard", list, ref num)) { } return list.FindAll((ZDO z) => z.GetLong(ZDOVars.s_creator, 0L) == playerId); } public static bool HasWaveInProgress(long playerId) { return WardsOf(playerId).Exists((ZDO z) => z.GetInt(HState, 0) == 2); } public static int RemoveOtherWards(long playerId, ZDOID keep) { //IL_0019: 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_002c: Unknown result type (might be due to invalid IL or missing references) int num = 0; foreach (ZDO item in WardsOf(playerId)) { if (!(item.m_uid == keep)) { GameObject val = ZNetScene.instance.FindInstance(item.m_uid); if ((Object)(object)val != (Object)null) { ZNetView component = val.GetComponent<ZNetView>(); component.ClaimOwnership(); component.Destroy(); } else { item.SetOwner(ZDOMan.GetSessionID()); ZDOMan.instance.DestroyZDO(item); } num++; } } RemovedCount += num; return num; } } [HarmonyPatch(typeof(Player), "TryPlacePiece")] internal static class Player_TryPlacePiece { private static bool Prefix(Player __instance, Piece piece, ref bool __result) { if (!OnePerPlayer.IsWard(piece) || !OnePerPlayer.HasWaveInProgress(__instance.GetPlayerID())) { return true; } ((Character)__instance).Message((MessageType)2, "A wave is attacking your ward. You cannot move it now.", 0, (Sprite)null, false); OnePerPlayer.BlockedCount++; Plugin.Log.LogInfo((object)"Ward placement blocked: wave in progress"); __result = false; return false; } } [HarmonyPatch(typeof(Player), "PlacePiece")] internal static class Player_PlacePiece { private static void Postfix(Player __instance, Piece piece, Vector3 pos) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000e: 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_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) if (!OnePerPlayer.IsWard(piece)) { return; } ZDOID keep = ZDOID.None; foreach (ZDO item in OnePerPlayer.WardsOf(__instance.GetPlayerID())) { if (Vector3.Distance(item.GetPosition(), pos) < 0.5f) { keep = item.m_uid; } } int num = OnePerPlayer.RemoveOtherWards(__instance.GetPlayerID(), keep); if (num > 0) { ((Character)__instance).Message((MessageType)1, "Previous ward removed. The countdown restarts here.", 0, (Sprite)null, false); Plugin.Log.LogInfo((object)$"Removed {num} previous ward(s) for player {__instance.GetPlayerID()}"); } } } [BepInPlugin("com.night.basedefenseward", "Base Defense Ward", "0.1.2")] public class Plugin : BaseUnityPlugin { public const string GUID = "com.night.basedefenseward"; public const string NAME = "Base Defense Ward"; public const string VERSION = "0.1.2"; public const string PrefabName = "BaseDefenseWard"; public const string SourcePrefab = "guard_stone"; public static readonly Color GlowColor = new Color(0.9f, 0.35f, 0.4f); public static ManualLogSource Log; public static GameObject WardPrefab; private static GameObject _holder; public static Plugin Instance; private void Awake() { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Expected O, but got Unknown //IL_0054: Unknown result type (might be due to invalid IL or missing references) Instance = this; Log = ((BaseUnityPlugin)this).Logger; Cfg.Bind(((BaseUnityPlugin)this).Config); Log.LogInfo((object)"Base Defense Ward 0.1.2 loading"); _holder = new GameObject("BaseDefenseWard_PrefabHolder"); _holder.SetActive(false); Object.DontDestroyOnLoad((Object)(object)_holder); new Harmony("com.night.basedefenseward").PatchAll(Assembly.GetExecutingAssembly()); } private void Update() { Deadline.Tick(Time.deltaTime); WardBoard.Tick(Time.deltaTime); WardPins.Tick(Time.deltaTime); Interaction.Tick(); } public static string DebugCommand(string line) { //IL_0882: Unknown result type (might be due to invalid IL or missing references) //IL_04c9: Unknown result type (might be due to invalid IL or missing references) //IL_0819: Unknown result type (might be due to invalid IL or missing references) //IL_03ba: Unknown result type (might be due to invalid IL or missing references) //IL_044c: Unknown result type (might be due to invalid IL or missing references) //IL_07d6: Unknown result type (might be due to invalid IL or missing references) //IL_035c: Unknown result type (might be due to invalid IL or missing references) //IL_079e: Unknown result type (might be due to invalid IL or missing references) //IL_0504: Unknown result type (might be due to invalid IL or missing references) //IL_050b: Expected O, but got Unknown //IL_0b5c: Unknown result type (might be due to invalid IL or missing references) //IL_0b61: Unknown result type (might be due to invalid IL or missing references) string[] parts = line.Split(new char[1] { ' ' }, StringSplitOptions.RemoveEmptyEntries); string text = ((parts.Length != 0) ? parts[0] : ""); Player localPlayer = Player.m_localPlayer; switch (text) { case "status": { WardChallenge wardChallenge2 = (((Object)(object)localPlayer != (Object)null) ? WardChallenge.Nearest(((Component)localPlayer).transform.position) : WardChallenge.All.FirstOrDefault()); return (((Object)(object)wardChallenge2 == (Object)null) ? "no ward nearby" : wardChallenge2.Status()) + "\n" + Progress.Summary() + "\n" + Deadline.Status(); } case "skip": { WardChallenge wardChallenge6 = WardChallenge.Nearest(((Component)localPlayer).transform.position); if ((Object)(object)wardChallenge6 == (Object)null) { return "no ward nearby"; } long num3 = long.Parse(parts[1]); ZDO zDO2 = ((Component)wardChallenge6).GetComponent<ZNetView>().GetZDO(); int num4 = ((wardChallenge6.State == ChallengeState.Active) ? WardChallenge.HWaveElapsed : WardChallenge.HElapsed); zDO2.Set(num4, zDO2.GetFloat(num4, 0f) + (float)num3); return "skipped " + num3; } case "mobs": { WardChallenge w = WardChallenge.Nearest(((Component)localPlayer).transform.position); if ((Object)(object)w == (Object)null) { return "no ward nearby"; } return string.Join("\n", w.AliveMobs().Select(delegate(Character c) { //IL_003d: 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) object[] obj2 = new object[5] { ((Object)((Component)c).gameObject).name, c.GetHealth(), c.GetMaxHealth(), Vector3.Distance(((Component)c).transform.position, ((Component)w).transform.position), null }; MonsterAI component2 = ((Component)c).GetComponent<MonsterAI>(); obj2[4] = ((component2 != null) ? new bool?(((BaseAI)component2).HuntPlayer()) : ((bool?)null)); return string.Format("{0}\t{1:0}/{2:0}\t{3:0}m hunt={4}", obj2); })) + $"\ncount={w.AliveMobs().Count}"; } case "kill": { WardChallenge wardChallenge5 = WardChallenge.Nearest(((Component)localPlayer).transform.position); if ((Object)(object)wardChallenge5 == (Object)null) { return "no ward nearby"; } int num2 = 0; foreach (Character item8 in wardChallenge5.AliveMobs()) { HitData val = new HitData(); val.m_damage.m_damage = 1E+10f; item8.Damage(val); num2++; } return "killed " + num2; } case "setcompleted": Progress.SetCompleted(int.Parse(parts[1])); return Progress.Summary(); case "setkey": ZoneSystem.instance.SetGlobalKey(parts[1]); return Progress.Summary(); case "removekey": ZoneSystem.instance.RemoveGlobalKey(parts[1]); return Progress.Summary(); case "sample": return string.Join(",", MobPool.Sample(int.Parse(parts[1]), int.Parse(parts[2]), int.Parse(parts[3]), new Random())); case "reward": return string.Join(",", from tuple2 in MobPool.RewardFor(int.Parse(parts[1]), int.Parse(parts[2])) select tuple2.prefab + "x" + tuple2.amount); case "cfg": if (parts.Length == 3) { ConfigEntryBase val2 = (from kv in (IEnumerable<KeyValuePair<ConfigDefinition, ConfigEntryBase>>)((BaseUnityPlugin)Instance).Config where kv.Key.Key == parts[1] select kv.Value).FirstOrDefault(); if (val2 == null) { return "no such key"; } val2.SetSerializedValue(parts[2]); } return string.Join("\n", ((IEnumerable<KeyValuePair<ConfigDefinition, ConfigEntryBase>>)((BaseUnityPlugin)Instance).Config).Select((KeyValuePair<ConfigDefinition, ConfigEntryBase> kv) => kv.Key.Key + "=" + kv.Value.GetSerializedValue())); case "hud": if (!((Object)(object)WardHud.Instance == (Object)null)) { return string.Format("visible={0} rows={1} tops={2} text={3}", WardHud.Instance.Visible, WardHud.Instance.RowCount, string.Join(",", WardHud.Instance.RowTops.Select((float t) => t.ToString("0"))), WardHud.Instance.CurrentText); } return "no hud"; case "pins": return string.Join("\n", WardPins.Describe()) + $"\ncount={WardPins.Count}"; case "board": return WardBoard.Describe(); case "pause": return Interaction.TogglePause(localPlayer) ?? "toggled"; case "startnow": { WardChallenge wardChallenge3 = WardChallenge.Nearest(((Component)localPlayer).transform.position); object obj; if (!((Object)(object)wardChallenge3 == (Object)null)) { obj = Interaction.StartNow(wardChallenge3); if (obj == null) { return "not in countdown"; } } else { obj = "no ward nearby"; } return (string)obj; } case "hover": { WardChallenge wardChallenge4 = WardChallenge.Nearest(((Component)localPlayer).transform.position); if (!((Object)(object)wardChallenge4 == (Object)null)) { return ((Component)wardChallenge4).GetComponent<PrivateArea>().GetHoverText().Replace("\n", " / "); } return "no ward nearby"; } case "interact": { WardChallenge wardChallenge7 = WardChallenge.Nearest(((Component)localPlayer).transform.position); if ((Object)(object)wardChallenge7 == (Object)null) { return "no ward nearby"; } PrivateArea component = ((Component)wardChallenge7).GetComponent<PrivateArea>(); return "result=" + component.Interact((Humanoid)(object)localPlayer, false, false) + " hover=" + component.GetHoverText().Replace("\n", " / "); } case "setcreator": { WardChallenge wardChallenge = WardChallenge.Nearest(((Component)localPlayer).transform.position); if ((Object)(object)wardChallenge == (Object)null) { return "no ward nearby"; } ZDO zDO = ((Component)wardChallenge).GetComponent<ZNetView>().GetZDO(); zDO.Set(ZDOVars.s_creator, long.Parse(parts[1])); zDO.Set(ZDOVars.s_creatorIndex, -1, false); return $"creator={zDO.GetLong(ZDOVars.s_creator, 0L)}"; } case "hudrects": { Hud instance = Hud.instance; MessageHud instance2 = MessageHud.instance; List<(string, RectTransform)> list = new List<(string, RectTransform)>(); Minimap instance3 = Minimap.instance; object item; if (instance3 == null) { item = null; } else { GameObject smallRoot = instance3.m_smallRoot; item = ((smallRoot != null) ? smallRoot.GetComponent<RectTransform>() : null); } list.Add(("minimap", (RectTransform)item)); list.Add(("statusEffects", instance?.m_statusEffectListRoot)); object item2; if (instance == null) { item2 = null; } else { GameObject eventBar = instance.m_eventBar; item2 = ((eventBar != null) ? eventBar.GetComponent<RectTransform>() : null); } list.Add(("eventBar", (RectTransform)item2)); object item3; if (instance2 == null) { item3 = null; } else { TMP_Text messageText = instance2.m_messageText; item3 = ((messageText != null) ? messageText.rectTransform : null); } list.Add(("messageTopLeft", (RectTransform)item3)); object item4; if (instance2 == null) { item4 = null; } else { TMP_Text messageCenterText = instance2.m_messageCenterText; item4 = ((messageCenterText != null) ? messageCenterText.rectTransform : null); } list.Add(("messageCenter", (RectTransform)item4)); list.Add(("healthPanel", instance?.m_healthPanel)); list.Add(("guardianPower", instance?.m_gpRoot)); object item5; if (instance == null) { item5 = null; } else { GameObject buildHud = instance.m_buildHud; item5 = ((buildHud != null) ? buildHud.GetComponent<RectTransform>() : null); } list.Add(("buildHud", (RectTransform)item5)); object item6; if (instance == null) { item6 = null; } else { GameObject saveIcon = instance.m_saveIcon; item6 = ((saveIcon != null) ? saveIcon.GetComponent<RectTransform>() : null); } list.Add(("saveIcon", (RectTransform)item6)); object item7; if (instance == null) { item7 = null; } else { GameObject betaText = instance.m_betaText; item7 = ((betaText != null) ? betaText.GetComponent<RectTransform>() : null); } list.Add(("betaText", (RectTransform)item7)); List<(string, RectTransform)> list2 = list; List<RectTransform> list3 = (((Object)(object)WardHud.Instance != (Object)null) ? WardHud.Instance.RowRects().ToList() : new List<RectTransform>()); for (int num = 0; num < list3.Count; num++) { list2.Add(("row" + num, list3[num])); } StringBuilder stringBuilder = new StringBuilder(); foreach (var item9 in list2) { var (text2, rt) = item9; if ((Object)(object)rt == (Object)null) { stringBuilder.AppendLine(text2 + "\tnull"); continue; } Rect r = R(rt); IEnumerable<string> values = from row in list3 where (Object)(object)row != (Object)(object)rt && ((Component)row).gameObject.activeInHierarchy && ((Rect)(ref r)).Overlaps(R(row)) select ((Object)row).name; stringBuilder.AppendLine(string.Format("{0}\tactive={1}\tx={2:0}-{3:0}\ty={4:0}-{5:0}\toverlapsRows={6}", text2, ((Component)rt).gameObject.activeInHierarchy, ((Rect)(ref r)).xMin, ((Rect)(ref r)).xMax, ((Rect)(ref r)).yMin, ((Rect)(ref r)).yMax, string.Join(",", values))); } return stringBuilder.ToString().TrimEnd(); } case "wards": return string.Join("\n", from z in OnePerPlayer.WardsOf(localPlayer.GetPlayerID()) select string.Format("{0} state={1} pos={2}", z.m_uid, (ChallengeState)z.GetInt(StringExtensionMethods.GetStableHashCode("bdw_state"), 0), z.GetPosition())) + $"\ncount={OnePerPlayer.WardsOf(localPlayer.GetPlayerID()).Count} removed={OnePerPlayer.RemovedCount} blocked={OnePerPlayer.BlockedCount}"; case "reset": WorldReset.Schedule("debug"); return "scheduled"; default: return "unknown: status skip <s> mobs setcompleted <n> setkey <k> removekey <k> sample <n> <tier> <completed> reward <tier> <completed> cfg [key value] reset"; } static Rect R(RectTransform val3) { //IL_003e: Unknown result type (might be due to invalid IL or missing references) Vector3[] array = (Vector3[])(object)new Vector3[4]; val3.GetWorldCorners(array); return Rect.MinMaxRect(array[0].x, array[0].y, array[2].x, array[2].y); } } public static void TryRegister() { //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0164: Unknown result type (might be due to invalid IL or missing references) //IL_0169: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Unknown result type (might be due to invalid IL or missing references) //IL_0172: Unknown result type (might be due to invalid IL or missing references) //IL_017c: Unknown result type (might be due to invalid IL or missing references) //IL_0181: Unknown result type (might be due to invalid IL or missing references) //IL_018e: Unknown result type (might be due to invalid IL or missing references) //IL_0193: Unknown result type (might be due to invalid IL or missing references) //IL_024d: Unknown result type (might be due to invalid IL or missing references) //IL_0252: 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_027f: Unknown result type (might be due to invalid IL or missing references) //IL_0296: Unknown result type (might be due to invalid IL or missing references) //IL_01f6: Unknown result type (might be due to invalid IL or missing references) //IL_0215: Unknown result type (might be due to invalid IL or missing references) //IL_021f: Unknown result type (might be due to invalid IL or missing references) ZNetScene instance = ZNetScene.instance; ObjectDB instance2 = ObjectDB.instance; if ((Object)(object)instance == (Object)null || (Object)(object)instance2 == (Object)null || instance2.m_items == null || instance2.m_items.Count == 0) { return; } if ((Object)(object)WardPrefab == (Object)null || (Object)(object)instance.GetPrefab("BaseDefenseWard") == (Object)null) { GameObject prefab = instance.GetPrefab("guard_stone"); if ((Object)(object)prefab == (Object)null) { Log.LogError((object)"Source prefab guard_stone not found"); return; } WardPrefab = Object.Instantiate<GameObject>(prefab, _holder.transform); ((Object)WardPrefab).name = "BaseDefenseWard"; Piece component = WardPrefab.GetComponent<Piece>(); component.m_name = "Base Defense Ward"; component.m_description = "Build it and a wave comes for it. Defend it to earn rewards."; WardPrefab.AddComponent<WardChallenge>(); StaticTarget obj = WardPrefab.AddComponent<StaticTarget>(); obj.m_primaryTarget = true; obj.m_randomTarget = true; PrivateArea component2 = WardPrefab.GetComponent<PrivateArea>(); if ((Object)(object)component2 != (Object)null) { component2.m_name = "Base Defense Ward"; if ((Object)(object)component2.m_enabledEffect != (Object)null) { Light[] componentsInChildren = component2.m_enabledEffect.GetComponentsInChildren<Light>(true); for (int i = 0; i < componentsInChildren.Length; i++) { componentsInChildren[i].color = GlowColor; } ParticleSystem[] componentsInChildren2 = component2.m_enabledEffect.GetComponentsInChildren<ParticleSystem>(true); foreach (ParticleSystem obj2 in componentsInChildren2) { MainModule main = obj2.main; ((MainModule)(ref main)).startColor = MinMaxGradient.op_Implicit(GlowColor); ColorOverLifetimeModule colorOverLifetime = obj2.colorOverLifetime; if (((ColorOverLifetimeModule)(ref colorOverLifetime)).enabled) { ((ColorOverLifetimeModule)(ref colorOverLifetime)).color = new MinMaxGradient(GlowColor); } } Renderer[] componentsInChildren3 = component2.m_enabledEffect.GetComponentsInChildren<Renderer>(true); for (int i = 0; i < componentsInChildren3.Length; i++) { Material[] materials = componentsInChildren3[i].materials; foreach (Material val in materials) { if (!((Object)(object)val == (Object)null)) { if (val.HasProperty("_Color")) { val.SetColor("_Color", GlowColor); } if (val.HasProperty("_EmissionColor")) { val.SetColor("_EmissionColor", GlowColor * 2f); } } } } GameObject val2 = new GameObject("BaseDefenseWardGlow"); val2.transform.SetParent(component2.m_enabledEffect.transform, false); val2.transform.localPosition = new Vector3(0f, 1.5f, 0f); Light obj3 = val2.AddComponent<Light>(); obj3.type = (LightType)2; obj3.color = GlowColor; obj3.intensity = 1.2f; obj3.range = 6f; obj3.shadows = (LightShadows)0; } } instance.m_prefabs.Add(WardPrefab); (AccessTools.Field(typeof(ZNetScene), "m_namedPrefabs").GetValue(instance) as Dictionary<int, GameObject>)[StringExtensionMethods.GetStableHashCode("BaseDefenseWard")] = WardPrefab; Log.LogInfo((object)"Registered prefab BaseDefenseWard (clone of guard_stone)"); } GameObject itemPrefab = instance2.GetItemPrefab("Hammer"); PieceTable val3 = ((itemPrefab == null) ? null : itemPrefab.GetComponent<ItemDrop>()?.m_itemData?.m_shared?.m_buildPieces); if ((Object)(object)val3 == (Object)null) { Log.LogError((object)"Hammer piece table not found"); } else if (!val3.m_pieces.Contains(WardPrefab)) { val3.m_pieces.Add(WardPrefab); Log.LogInfo((object)"Added Base Defense Ward to Hammer piece table"); } } } [HarmonyPatch(typeof(PrivateArea), "UpdateStatus")] internal static class PrivateArea_UpdateStatus { private static void Postfix(PrivateArea __instance) { //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) if (!((Object)__instance).name.StartsWith("BaseDefenseWard") || (Object)(object)__instance.m_model == (Object)null) { return; } Material[] materials = ((Renderer)__instance.m_model).materials; foreach (Material val in materials) { if (val.HasProperty("_EmissionColor")) { val.SetColor("_EmissionColor", Plugin.GlowColor * 2f); } } } } [HarmonyPatch(typeof(ZNetScene), "Awake")] internal static class ZNetScene_Awake { private static void Postfix() { Plugin.TryRegister(); } } [HarmonyPatch(typeof(ObjectDB), "Awake")] internal static class ObjectDB_Awake { private static void Postfix() { Plugin.TryRegister(); } } [HarmonyPatch(typeof(ObjectDB), "CopyOtherDB")] internal static class ObjectDB_CopyOtherDB { private static void Postfix() { Plugin.TryRegister(); } } public static class Progress { public const string CompletedKey = "bdw_completed"; public const string BuiltKey = "bdw_built"; public const string WorldStartKey = "bdw_worldstart"; public const string DeadlineFailedKey = "bdw_deadline_failed"; public static int Completed() { string s = default(string); if ((Object)(object)ZoneSystem.instance != (Object)null && ZoneSystem.instance.GetGlobalKey("bdw_completed", ref s) && int.TryParse(s, NumberStyles.Any, CultureInfo.InvariantCulture, out var result)) { return result; } return 0; } public static void SetCompleted(int n) { SetValue("bdw_completed", n.ToString(CultureInfo.InvariantCulture)); } public static void SetValue(string key, string value) { ZoneSystem.instance.RemoveGlobalKey(key); ZoneSystem.instance.SetGlobalKey(key + " " + value); } public static bool Has(string key) { if ((Object)(object)ZoneSystem.instance != (Object)null) { return ZoneSystem.instance.GetGlobalKey(key); } return false; } public static string[] BossKeys() { return (from s in Cfg.BossKeys.Value.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries) select s.Trim()).ToArray(); } public static int BossTier() { string[] array = BossKeys(); int result = 0; for (int i = 0; i < array.Length; i++) { if (Has(array[i])) { result = i + 1; } } return result; } public static string Summary() { return string.Format("completed={0} bossTier={1} keys=[{2}]", Completed(), BossTier(), string.Join(",", BossKeys().Where(Has))); } } public static class WardBoard { public class Entry { public ZDOID Id; public long Creator; public string Name; public ChallengeState State; public bool Paused; public bool Running; public float Remaining; public Vector3 Pos; public float ReceivedAt; public float RemainingNow { get { if (!Running) { return Remaining; } return Mathf.Max(0f, Remaining - (Time.time - ReceivedAt)); } } } public static readonly List<Entry> Entries = new List<Entry>(); public static HashSet<long> Online = new HashSet<long>(); public static float LastUpdate = -1f; private const string Rpc = "BDW_Wards"; private static bool _registered; private static float _clockTimer; private static float _sendTimer; private static readonly int HState = StringExtensionMethods.GetStableHashCode("bdw_state"); public static bool IsOnline(long playerId) { return Online.Contains(playerId); } public static void Tick(float dt) { if (ZRoutedRpc.instance == null || (Object)(object)ZNet.instance == (Object)null) { _registered = false; return; } if (!_registered) { ZRoutedRpc.instance.Register<ZPackage>("BDW_Wards", (Action<long, ZPackage>)RPC_Wards); _registered = true; } if (ZNet.instance.IsServer() && ZDOMan.instance != null) { _clockTimer += dt; _sendTimer += dt; if (_clockTimer >= 1f) { AdvanceUnloaded(_clockTimer); _clockTimer = 0f; } if (_sendTimer >= 2f) { Broadcast(); _sendTimer = 0f; } } } private static void AdvanceUnloaded(float dt) { //IL_0054: Unknown result type (might be due to invalid IL or missing references) HashSet<long> hashSet = OnlinePlayerIds(); foreach (ZDO item in AllWardZdos()) { ChallengeState challengeState = (ChallengeState)item.GetInt(HState, 0); if ((challengeState == ChallengeState.Countdown || challengeState == ChallengeState.Resting) && !item.GetBool(WardChallenge.HPaused, false) && hashSet.Contains(item.GetLong(ZDOVars.s_creator, 0L)) && !IsSimulated(item.GetPosition())) { int num = ((challengeState == ChallengeState.Countdown) ? WardChallenge.HElapsed : WardChallenge.HRestElapsed); item.Set(num, item.GetFloat(num, 0f) + dt); } } } private static bool IsSimulated(Vector3 pos) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0012: 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_0044: Unknown result type (might be due to invalid IL or missing references) if (!ZNet.instance.IsDedicated() && ZNetScene.InActiveArea(pos, ZNet.instance.GetReferencePosition())) { return true; } foreach (ZNetPeer peer in ZNet.instance.GetPeers()) { if (peer.IsReady() && ZNetScene.InActiveArea(pos, peer.GetRefPos())) { return true; } } return false; } private static HashSet<long> OnlinePlayerIds() { //IL_0038: 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) //IL_0043: 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) HashSet<long> hashSet = new HashSet<long>(); if ((Object)(object)Player.m_localPlayer != (Object)null) { hashSet.Add(Player.m_localPlayer.GetPlayerID()); } foreach (PlayerInfo player in ZNet.instance.GetPlayerList()) { ZDO zDO = ZDOMan.instance.GetZDO(player.m_characterID); long num = ((zDO != null) ? zDO.GetLong(ZDOVars.s_playerID, 0L) : 0); if (num != 0L) { hashSet.Add(num); } } return hashSet; } public static string NameOf(long playerId, ZDO ward) { //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: 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_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)Player.m_localPlayer != (Object)null && Player.m_localPlayer.GetPlayerID() == playerId) { return Player.m_localPlayer.GetPlayerName(); } foreach (Player allPlayer in Player.GetAllPlayers()) { if ((Object)(object)allPlayer != (Object)null && allPlayer.GetPlayerID() == playerId) { return allPlayer.GetPlayerName(); } } if ((Object)(object)ZNet.instance != (Object)null && ZDOMan.instance != null) { foreach (PlayerInfo player in ZNet.instance.GetPlayerList()) { ZDO zDO = ZDOMan.instance.GetZDO(player.m_characterID); if (zDO != null && zDO.GetLong(ZDOVars.s_playerID, 0L) == playerId && !string.IsNullOrEmpty(player.m_name)) { return player.m_name; } } } int num = ((ward != null) ? ward.GetInt(ZDOVars.s_creatorIndex, -1) : (-1)); List<CrossNetworkUserInfo> list = ZNet.World?.m_playerHistory; if (list != null && num >= 0 && num < list.Count && !string.IsNullOrEmpty(list[num].m_displayName)) { return list[num].m_displayName; } return "Viking"; } public static List<ZDO> AllWardZdos() { List<ZDO> list = new List<ZDO>(); int num = 0; while (!ZDOMan.instance.GetAllZDOsWithPrefabIterative("BaseDefenseWard", list, ref num)) { } return list; } private static void Broadcast() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected O, but got Unknown //IL_0168: Unknown result type (might be due to invalid IL or missing references) //IL_0177: Unknown result type (might be due to invalid IL or missing references) //IL_01c5: Unknown result type (might be due to invalid IL or missing references) HashSet<long> hashSet = OnlinePlayerIds(); ZPackage val = new ZPackage(); val.Write(hashSet.Count); foreach (long item in hashSet) { val.Write(item); } List<ZDO> list = AllWardZdos(); val.Write(list.Count); foreach (ZDO item2 in list) { ChallengeState challengeState = (ChallengeState)item2.GetInt(HState, 0); bool flag = item2.GetBool(WardChallenge.HPaused, false); long num = item2.GetLong(ZDOVars.s_creator, 0L); float num2 = 0f; bool flag2 = false; switch (challengeState) { case ChallengeState.Idle: case ChallengeState.Countdown: num2 = Cfg.CountdownMinutes.Value * 60f - item2.GetFloat(WardChallenge.HElapsed, 0f); flag2 = !flag && hashSet.Contains(num); break; case ChallengeState.Resting: num2 = item2.GetFloat(WardChallenge.HRestFor, 0f) - item2.GetFloat(WardChallenge.HRestElapsed, 0f); flag2 = !flag && hashSet.Contains(num); break; case ChallengeState.Active: num2 = Cfg.WaveTimeLimitMinutes.Value * 60f - item2.GetFloat(WardChallenge.HWaveElapsed, 0f); flag2 = IsSimulated(item2.GetPosition()); break; } val.Write(item2.m_uid); val.Write(num); val.Write(NameOf(num, item2)); val.Write((int)challengeState); val.Write(flag); val.Write(flag2); val.Write(Mathf.Max(0f, num2)); val.Write(item2.GetPosition()); } val.SetPos(0); RPC_Wards(0L, val); val.SetPos(0); ZRoutedRpc.instance.InvokeRoutedRPC(0L, "BDW_Wards", new object[1] { val }); } private static void RPC_Wards(long sender, ZPackage pkg) { //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) HashSet<long> hashSet = new HashSet<long>(); int num = pkg.ReadInt(); for (int i = 0; i < num; i++) { hashSet.Add(pkg.ReadLong()); } Online = hashSet; Entries.Clear(); int num2 = pkg.ReadInt(); for (int j = 0; j < num2; j++) { Entries.Add(new Entry { Id = pkg.ReadZDOID(), Creator = pkg.ReadLong(), Name = pkg.ReadString(), State = (ChallengeState)pkg.ReadInt(), Paused = pkg.ReadBool(), Running = pkg.ReadBool(), Remaining = pkg.ReadSingle(), Pos = pkg.ReadVector3(), ReceivedAt = Time.time }); } LastUpdate = Time.time; } public static bool IsRunning(ChallengeState s) { if (s != ChallengeState.Idle && s != ChallengeState.Countdown && s != ChallengeState.Active) { return s == ChallengeState.Resting; } return true; } public static string Describe() { return string.Join("\n", Entries.Select((Entry e) => $"{e.Id} creator={e.Creator} name={e.Name} state={e.State} paused={e.Paused} running={e.Running} remaining={e.RemainingNow:0} pos={e.Pos}")) + $"\ncount={Entries.Count} age={((LastUpdate < 0f) ? (-1f) : (Time.time - LastUpdate)):0.0}"; } } public enum ChallengeState { Idle, Countdown, Active, Won, Lost, Cancelled, Resting } public class WardChallenge : MonoBehaviour { private static readonly int HState = StringExtensionMethods.GetStableHashCode("bdw_state"); public static readonly int HElapsed = StringExtensionMethods.GetStableHashCode("bdw_elapsed"); public static readonly int HWaveElapsed = StringExtensionMethods.GetStableHashCode("bdw_waveelapsed"); public static readonly int HRestElapsed = StringExtensionMethods.GetStableHashCode("bdw_restelapsed"); public static readonly int HRestFor = StringExtensionMethods.GetStableHashCode("bdw_restfor"); public static readonly int HPaused = StringExtensionMethods.GetStableHashCode("bdw_paused"); private static readonly int HTier = StringExtensionMethods.GetStableHashCode("bdw_tier"); private static readonly int HMobCount = StringExtensionMethods.GetStableHashCode("bdw_mobcount"); public static readonly int HMobWard = StringExtensionMethods.GetStableHashCode("bdw_ward"); private static readonly Random Rng = new Random(); public static readonly List<WardChallenge> All = new List<WardChallenge>(); private ZNetView _nview; private WearNTear _wnt; private readonly Queue<string> _toSpawn = new Queue<string>(); private float _spawnTimer; private string _id; private double _lastTick = -1.0; public ChallengeState State => (ChallengeState)_nview.GetZDO().GetInt(HState, 0); private double Now => ZNet.instance.GetTimeSeconds(); public int Tier => _nview.GetZDO().GetInt(HTier, 0); public float Elapsed => _nview.GetZDO().GetFloat(HElapsed, 0f); public float WaveElapsed => _nview.GetZDO().GetFloat(HWaveElapsed, 0f); public float RestElapsed => _nview.GetZDO().GetFloat(HRestElapsed, 0f); public float RestFor => _nview.GetZDO().GetFloat(HRestFor, 0f); public bool Paused => _nview.GetZDO().GetBool(HPaused, false); public ZNetView View => _nview; private void Awake() { _nview = ((Component)this).GetComponent<ZNetView>(); if (!((Object)(object)_nview == (Object)null) && _nview.IsValid()) { _wnt = ((Component)this).GetComponent<WearNTear>(); if ((Object)(object)_wnt != (Object)null) { _wnt.m_onDestroyed = (Action)Delegate.Combine(_wnt.m_onDestroyed, new Action(OnDestroyed)); } _id = ((object)Unsafe.As<ZDOID, ZDOID>(ref _nview.GetZDO().m_uid)/*cast due to .constrained prefix*/).ToString(); _nview.Register("BDW_StartNow", (Action<long>)RPC_StartNow); _nview.Register("BDW_TogglePause", (Action<long>)RPC_TogglePause); All.Add(this); ((MonoBehaviour)this).InvokeRepeating("Tick", 1f, 1f); } } private void OnDestroy() { All.Remove(this); } private void SetState(ChallengeState s) { _nview.GetZDO().Set(HState, (int)s, false); } public string Status() { ZDO zDO = _nview.GetZDO(); return $"state={State} tier={Tier} owner={_nview.IsOwner()} paused={Paused} hp={(((Object)(object)_wnt != (Object)null) ? (_wnt.GetHealthPercentage() * 100f) : (-1f)):0}% elapsed={Elapsed:0}s " + $"waveElapsed={WaveElapsed:0}s rest={RestElapsed:0}/{RestFor:0}s alive={AliveMobs().Count} pending={_toSpawn.Count} planned={zDO.GetInt(HMobCount, 0)}"; } private void RPC_StartNow(long sender) { if (_nview.IsOwner() && State == ChallengeState.Countdown) { Plugin.Log.LogInfo((object)("Wave started early by request: ward=" + _id)); StartWave(); } } private void RPC_TogglePause(long sender) { if (_nview.IsOwner() && State != ChallengeState.Active) { bool flag = !Paused; _nview.GetZDO().Set(HPaused, flag); Plugin.Log.LogInfo((object)("Ward " + (flag ? "paused" : "resumed") + ": ward=" + _id)); Say(flag ? "Base Defense Ward paused." : "Base Defense Ward resumed."); } } public void RequestStartNow() { _nview.InvokeRPC("BDW_StartNow", Array.Empty<object>()); } public void RequestTogglePause() { _nview.InvokeRPC("BDW_TogglePause", Array.Empty<object>()); } private void Tick() { if (!_nview.IsValid() || !_nview.IsOwner() || (Object)(object)ZNet.instance == (Object)null) { _lastTick = -1.0; return; } ZDO zDO = _nview.GetZDO(); float num = ((_lastTick < 0.0) ? 0f : Mathf.Clamp((float)(Now - _lastTick), 0f, 2f)); _lastTick = Now; if (Paused && State != ChallengeState.Active) { num = 0f; } if ((State == ChallengeState.Countdown || State == ChallengeState.Resting) && !WardBoard.IsOnline(zDO.GetLong(ZDOVars.s_creator, 0L))) { num = 0f; } switch (State) { case ChallengeState.Won: StartRest(); break; case ChallengeState.Resting: zDO.Set(HRestElapsed, RestElapsed + num); if (RestElapsed >= RestFor) { zDO.Set(HElapsed, 0f); SetState(ChallengeState.Countdown); Say($"The ward stirs. The next wave arrives in {Cfg.CountdownMinutes.Value:0.#} minutes."); } break; case ChallengeState.Idle: zDO.Set(HElapsed, 0f); SetState(ChallengeState.Countdown); if (!Progress.Has("bdw_built")) { ZoneSystem.instance.SetGlobalKey("bdw_built"); } Say($"Base Defense Ward armed. The wave arrives in {Cfg.CountdownMinutes.Value:0.#} minutes."); break; case ChallengeState.Countdown: zDO.Set(HElapsed, Elapsed + num); if (Elapsed >= Cfg.CountdownMinutes.Value * 60f) { StartWave(); } break; case ChallengeState.Active: { zDO.Set(HWaveElapsed, WaveElapsed + num); PumpSpawns(); List<Character> list = AliveMobs(); DirectMobs(list); bool flag = WaveElapsed >= Cfg.WaveTimeLimitMinutes.Value * 60f; if (_toSpawn.Count == 0 && list.Count == 0) { Win("Wave destroyed"); } else if (flag) { Despawn(list); Win("Ward held until dawn"); } break; } case ChallengeState.Lost: case ChallengeState.Cancelled: break; } } private void StartWave() { ZDO zDO = _nview.GetZDO(); int num = Progress.BossTier(); int num2 = Progress.Completed(); int count = Mathf.Clamp(Cfg.BaseMobCount.Value + Cfg.MobsPerCompletedChallenge.Value * num2, 1, Cfg.MaxMobCount.Value); _toSpawn.Clear(); foreach (string item in MobPool.Sample(count, num, num2, Rng)) { _toSpawn.Enqueue(item); } zDO.Set(HTier, num, false); zDO.Set(HMobCount, _toSpawn.Count, false); zDO.Set(HWaveElapsed, 0f); SetState(ChallengeState.Active); Plugin.Log.LogInfo((object)string.Format("Wave start: ward={0} tier={1} completed={2} mobs={3}", _id, num, num2, string.Join(",", _toSpawn))); Say("The wave is here! Defend the ward!"); } private void PumpSpawns() { if (_toSpawn.Count != 0) { _spawnTimer -= 1f; if (!(_spawnTimer > 0f)) { _spawnTimer = Cfg.SpawnIntervalSeconds.Value; Spawn(_toSpawn.Dequeue()); } } } private void Spawn(string prefabName) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_007e: 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) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00db: 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_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_0167: Unknown result type (might be due to invalid IL or missing references) GameObject prefab = ZNetScene.instance.GetPrefab(prefabName); if ((Object)(object)prefab == (Object)null) { Plugin.Log.LogWarning((object)("Missing mob prefab " + prefabName)); return; } Vector3 val = ((Component)this).transform.position; float num2 = default(float); for (int i = 0; i < 10; i++) { float num = (float)(Rng.NextDouble() * Math.PI * 2.0); Vector3 val2 = ((Component)this).transform.position + new Vector3(Mathf.Cos(num), 0f, Mathf.Sin(num)) * Cfg.SpawnRadius.Value; if (ZoneSystem.instance.GetGroundHeight(val2, ref num2) && num2 > ZoneSystem.instance.m_waterLevel) { val2.y = num2 + 0.3f; val = val2; break; } } Vector3 val3 = val; Vector3 val4 = ((Component)this).transform.position - val; GameObject obj = Object.Instantiate<GameObject>(prefab, val3, Quaternion.LookRotation(((Vector3)(ref val4)).normalized)); ZNetView component = obj.GetComponent<ZNetView>(); if (component != null) { ZDO zDO = component.GetZDO(); if (zDO != null) { zDO.Set(HMobWard, _id); } } MonsterAI component2 = obj.GetComponent<MonsterAI>(); if ((Object)(object)component2 != (Object)null) { ((BaseAI)component2).SetHuntPlayer(true); ((BaseAI)component2).Alert(); if (component != null) { ZDO zDO2 = component.GetZDO(); if (zDO2 != null) { zDO2.Set(ZDOVars.s_despawnInDay, false); } } } Plugin.Log.LogInfo((object)$"Spawned {prefabName} at {val}"); } public List<Character> AliveMobs() { List<Character> list = new List<Character>(); foreach (Character allCharacter in Character.GetAllCharacters()) { if (!((Object)(object)allCharacter == (Object)null) && !allCharacter.IsDead() && !allCharacter.IsPlayer()) { ZNetView component = ((Component)allCharacter).GetComponent<ZNetView>(); if ((Object)(object)component != (Object)null && component.IsValid() && component.GetZDO().GetString(HMobWard, "") == _id) { list.Add(allCharacter); } } } return list; } private void DirectMobs(List<Character> mobs) { StaticTarget component = ((Component)this).GetComponent<StaticTarget>(); List<Player> allPlayers = Player.GetAllPlayers(); foreach (Character c in mobs) { MonsterAI component2 = ((Component)c).GetComponent<MonsterAI>(); if ((Object)(object)component2 == (Object)null) { continue; } bool flag = allPlayers.Any((Player p) => !((Character)p).IsDead() && !p.InShelter() && Vector3.Distance(((Component)p).transform.position, ((Component)c).transform.position) <= Cfg.PlayerHuntRange.Value); ((BaseAI)component2).SetHuntPlayer(flag); if (!flag && (Object)(object)component != (Object)null) { object? value = AccessTools.Field(typeof(MonsterAI), "m_targetStatic").GetValue(component2); object? obj = ((value is StaticTarget) ? value : null); object? value2 = AccessTools.Field(typeof(MonsterAI), "m_targetCreature").GetValue(component2); Character val = (Character)((value2 is Character) ? value2 : null); if ((Object)obj == (Object)null && (Object)(object)val == (Object)null) { AccessTools.Field(typeof(MonsterAI), "m_targetStatic").SetValue(component2, component); } if (!((BaseAI)component2).IsAlerted()) { ((BaseAI)component2).Alert(); } } } } private void Despawn(List<Character> mobs) { foreach (Character mob in mobs) { ZNetView component = ((Component)mob).GetComponent<ZNetView>(); if ((Object)(object)component != (Object)null && component.IsValid()) { component.Destroy(); } } } private void Win(string why) { int num = Progress.Completed(); List<(string, int)> list = MobPool.RewardFor(Tier, num); Progress.SetCompleted(num + 1); foreach (var (prefab, amount) in list) { DropReward(prefab, amount); } Plugin.Log.LogInfo((object)string.Format("Challenge won ({0}): ward={1} completed->{2} reward={3}", why, _id, num + 1, string.Join(",", list.Select<(string, int), string>(((string prefab, int amount) r) => r.prefab + "x" + r.amount)))); Say("Ward defended! " + why + ". Rewards have been dropped at the ward."); StartRest(); } private void StartRest() { float num = Mathf.Max(0f, Cfg.RestMinMinutes.Value); float num2 = Mathf.Max(num, Cfg.RestMaxMinutes.Value); float num3 = (num + (float)Rng.NextDouble() * (num2 - num)) * 60f; ZDO zDO = _nview.GetZDO(); zDO.Set(HRestFor, num3); zDO.Set(HRestElapsed, 0f); SetState(ChallengeState.Resting); Plugin.Log.LogInfo((object)$"Ward resting for {num3:0}s: ward={_id}"); } private void DropReward(string prefab, int amount) { //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) GameObject prefab2 = ZNetScene.instance.GetPrefab(prefab); ItemDrop val = ((prefab2 != null) ? prefab2.GetComponent<ItemDrop>() : null); if (!((Object)(object)val == (Object)null)) { val.m_itemData.m_dropPrefab = prefab2; int num = Mathf.Max(1, val.m_itemData.m_shared.m_maxStackSize); Vector3 val2 = default(Vector3); while (amount > 0) { int num2 = Mathf.Min(amount, num); amount -= num2; ((Vector3)(ref val2))..ctor((float)Rng.NextDouble() * 2f - 1f, 1.5f, (float)Rng.NextDouble() * 2f - 1f); ItemDrop.DropItem(val.m_itemData.Clone(), num2, ((Component)this).transform.position + val2, Quaternion.identity); } } } private void OnDestroyed() { if (!_nview.IsValid() || !_nview.IsOwner()) { return; } switch (State) { case ChallengeState.Active: SetState(ChallengeState.Lost); Despawn(AliveMobs()); Plugin.Log.LogInfo((object)("Challenge lost: ward=" + _id + " destroyed during wave")); Say("The ward has fallen. Challenge lost."); if (Cfg.DeleteWorldOnLoss.Value) { WorldReset.Schedule("ward destroyed"); } break; case ChallengeState.Countdown: Plugin.Log.LogInfo((object)("Challenge cancelled: ward=" + _id + " removed before the wave")); break; } } public static void Say(string text) { if ((Object)(object)MessageHud.instance != (Object)null) { MessageHud.instance.MessageAll((MessageType)2, text); } } public static WardChallenge Nearest(Vector3 pos, float r = 500f) { //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) return (from w in All where (Object)(object)w != (Object)null && Vector3.Distance(((Component)w).transform.position, pos) <= r orderby (w.State != ChallengeState.Countdown && w.State != ChallengeState.Active && w.State != ChallengeState.Idle) ? 1 : 0, Vector3.Distance(((Component)w).transform.position, pos) select w).FirstOrDefault(); } } public class WardHud : MonoBehaviour { private class Row { public GameObject Go; public RectTransform Rect; public Image Icon; public TMP_Text Text; } public static WardHud Instance; private const float RowWidth = 300f; private const float RowHeight = 36f; private const float RowGap = 4f; private RectTransform _holder; private readonly List<Row> _rows = new List<Row>(); private readonly List<string> _lines = new List<string>(); private Sprite _sprite; private Vector2 _anchor; private float _scanTimer; private TMP_Text _template; public string CurrentText => string.Join(" | ", _lines); public int RowCount => _lines.Count; public bool Visible => _lines.Count > 0; public IEnumerable<float> RowTops => from r in _rows.Take(_lines.Count) select r.Rect.anchoredPosition.y; public IEnumerable<RectTransform> RowRects() { return from r in _rows.Take(_lines.Count) select r.Rect; } public static void Create(Hud hud) { //IL_003d: 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_0088: Unknown result type (might be due to invalid IL or missing references) //IL_009a: 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_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)Instance != (Object)null) && !((Object)(object)hud == (Object)null) && !((Object)(object)hud.m_rootObject == (Object)null)) { GameObject val = new GameObject("BaseDefenseWardHud", new Type[1] { typeof(RectTransform) }); Minimap instance = Minimap.instance; object obj; if (instance == null) { obj = null; } else { GameObject smallRoot = instance.m_smallRoot; obj = ((smallRoot != null) ? smallRoot.GetComponent<RectTransform>() : null); } RectTransform val2 = (RectTransform)obj; val.transform.SetParent(((Object)(object)val2 != (Object)null) ? ((Transform)val2).parent : hud.m_rootObject.transform, false); RectTransform component = val.GetComponent<RectTransform>(); component.anchorMin = new Vector2(0f, 0f); component.anchorMax = new Vector2(1f, 1f); Vector2 offsetMin = (component.offsetMax = Vector2.zero); component.offsetMin = offsetMin; Instance = val.AddComponent<WardHud>(); Instance._holder = component; Instance._template = hud.m_healthText; Instance.Reposition(); } } private Row MakeRow() { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Expected O, but got Unknown //IL_0063: 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) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_0144: Unknown result type (might be due to invalid IL or missing references) //IL_0173: Unknown result type (might be due to invalid IL or missing references) //IL_0178: Unknown result type (might be due to invalid IL or missing references) //IL_0185: Unknown result type (might be due to invalid IL or missing references) //IL_0196: Unknown result type (might be due to invalid IL or missing references) //IL_01ab: Unknown result type (might be due to invalid IL or missing references) //IL_01c0: Unknown result type (might be due to invalid IL or missing references) //IL_01d4: Unknown result type (might be due to invalid IL or missing references) //IL_0220: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("Row" + _rows.Count, new Type[1] { typeof(RectTransform) }); val.transform.SetParent(((Component)this).transform, false); RectTransform component = val.GetComponent<RectTransform>(); Vector2 val2 = default(Vector2); ((Vector2)(ref val2))..ctor(0f, 0f); component.anchorMax = val2; component.anchorMin = val2; component.pivot = new Vector2(1f, 1f); component.sizeDelta = new Vector2(300f, 36f); ((Graphic)val.AddComponent<Image>()).color = new Color(0f, 0f, 0f, 0.45f); GameObject val3 = new GameObject("Icon", new Type[1] { typeof(RectTransform) }); val3.transform.SetParent((Transform)(object)component, false); RectTransform component2 = val3.GetComponent<RectTransform>(); ((Vector2)(ref val2))..ctor(0f, 0.5f); component2.anchorMax = val2; component2.anchorMin = val2; component2.pivot = new Vector2(0f, 0.5f); component2.sizeDelta = new Vector2(32f, 32f); component2.anchoredPosition = new Vector2(4f, 0f); Image val4 = val3.AddComponent<Image>(); val4.preserveAspect = true; GameObject val5 = new GameObject("Text", new Type[1] { typeof(RectTransform) }); val5.transform.SetParent((Transform)(object)component, false); RectTransform component3 = val5.GetComponent<RectTransform>(); component3.anchorMin = new Vector2(0f, 0f); component3.anchorMax = new Vector2(1f, 1f); component3.offsetMin = new Vector2(42f, 2f); component3.offsetMax = new Vector2(-6f, -2f); TextMeshProUGUI val6 = val5.AddComponent<TextMeshProUGUI>(); if ((Object)(object)_template != (Object)null) { ((TMP_Text)val6).font = _template.font; ((TMP_Text)val6).fontSharedMaterial = _template.fontSharedMaterial; } ((TMP_Text)val6).fontSize = 16f; ((Graphic)val6).color = Color.white; ((TMP_Text)val6).alignment = (TextAlignmentOptions)4097; ((TMP_Text)val6).enableWordWrapping = false; ((TMP_Text)val6).overflowMode = (TextOverflowModes)1; Row row = new Row { Go = val, Rect = component, Icon = val4, Text = (TMP_Text)(object)val6 }; _rows.Add(row); return row; } private void Reposition() { //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0094: 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_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: 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_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_002e: 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) //IL_0048: 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_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) Minimap instance = Minimap.instance; object obj; if (instance == null) { obj = null; } else { GameObject smallRoot = instance.m_smallRoot; obj = ((smallRoot != null) ? smallRoot.GetComponent<RectTransform>() : null); } RectTransform val = (RectTransform)obj; Rect rect; if ((Object)(object)val == (Object)null) { rect = _holder.rect; float num = ((Rect)(ref rect)).width - 20f; rect = _holder.rect; _anchor = new Vector2(num, ((Rect)(ref rect)).height - 160f); } else { Vector3[] array = (Vector3[])(object)new Vector3[4]; val.GetWorldCorners(array); Vector3 val2 = ((Transform)_holder).InverseTransformPoint(array[3]); Vector2 val3 = new Vector2(val2.x, val2.y); rect = _holder.rect; Vector2 val4 = val3 + ((Rect)(ref rect)).size * _holder.pivot; _anchor = val4 + new Vector2(0f, -8f); } } private void Update() { //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) _lines.Clear(); if ((Object)(object)Player.m_localPlayer != (Object)null && (Object)(object)ZNet.instance != (Object)null) { _scanTimer -= Time.deltaTime; if (_scanTimer <= 0f) { _scanTimer = 2f; Reposition(); if ((Object)(object)_sprite == (Object)null) { GameObject wardPrefab = Plugin.WardPrefab; _sprite = ((wardPrefab == null) ? null : wardPrefab.GetComponent<Piece>()?.m_icon); } } BuildLines(); } for (int i = 0; i < _lines.Count; i++) { Row row = ((i < _rows.Count) ? _rows[i] : MakeRow()); if (!row.Go.activeSelf) { row.Go.SetActive(true); } row.Rect.anchoredPosition = _anchor - new Vector2(0f, (float)i * 40f); if ((Object)(object)row.Icon.sprite == (Object)null) { row.Icon.sprite = _sprite; } row.Text.text = _lines[i]; } for (int j = _lines.Count; j < _rows.Count; j++) { if (_rows[j].Go.activeSelf) { _rows[j].Go.SetActive(false); } } } private void BuildLines() { long me = Player.m_localPlayer.GetPlayerID(); WardBoard.Entry entry = (from e in WardBoard.Entries where e.Creator == me orderby (!WardBoard.IsRunning(e.State)) ? 1 : 0 select e).FirstOrDefault(); if (entry != null) { _lines.Add(Line(entry, "Your ward")); } foreach (WardBoard.Entry item in from e in WardBoard.Entries where e.Creator != me && WardBoard.IsRunning(e.State) orderby ((ZDOID)(ref e.Id)).ID select e) { _lines.Add(Line(item, item.Name)); } string s = default(string); if (_lines.Count == 0 && Cfg.BuildDeadlineMinutes.Value > 0f && !Progress.Has("bdw_built") && !Progress.Has("bdw_deadline_failed") && (Object)(object)ZoneSystem.instance != (Object)null && ZoneSystem.instance.GetGlobalKey("bdw_worldstart", ref s) && long.TryParse(s, out var result)) { _lines.Add("Build ward in " + Fmt((double)Cfg.BuildDeadlineMinutes.Value * 60.0 - (ZNet.instance.GetTimeSeconds() - (double)result))); } } private static string Line(WardBoard.Entry e, string who) { string text = (e.Paused ? " (paused)" : ""); switch (e.State) { case ChallengeState.Idle: case ChallengeState.Countdown: return who + ": wave in " + Fmt(e.RemainingNow) + text; case ChallengeState.Active: return who + ": hold " + Fmt(e.RemainingNow); case ChallengeState.Won: case ChallengeState.Resting: return who + ": defended, next in " + Fmt(e.RemainingNow) + text; case ChallengeState.Lost: return who + ": lost"; default: return null; } } private static string Fmt(double seconds) { if (seconds < 0.0) { seconds = 0.0; } TimeSpan timeSpan = TimeSpan.FromSeconds(seconds); if (!(timeSpan.TotalHours >= 1.0)) { return $"{timeSpan.Minutes:00}:{timeSpan.Seconds:00}"; } return $"{(int)timeSpan.TotalHours}:{timeSpan.Minutes:00}:{timeSpan.Seconds:00}"; } } public static class WardPins { private static readonly Dictionary<ZDOID, PinData> _pins = new Dictionary<ZDOID, PinData>(); private static float _timer; public static int Count => _pins.Count; public static IEnumerable<string> Describe() { return _pins.Select((KeyValuePair<ZDOID, PinData> kv) => $"{kv.Key} {kv.Value.m_name} {kv.Value.m_pos}"); } public static void Tick(float dt) { //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: 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_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_01b4: Unknown result type (might be due to invalid IL or missing references) //IL_01b9: Unknown result type (might be due to invalid IL or missing references) //IL_01c1: Unknown result type (might be due to invalid IL or missing references) //IL_01d2: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) _timer -= dt; if (_timer > 0f) { return; } _timer = 2f; Minimap instance = Minimap.instance; if ((Object)(object)instance == (Object)null || (Object)(object)Player.m_localPlayer == (Object)null) { Clear(); return; } HashSet<ZDOID> running = new HashSet<ZDOID>(); foreach (WardBoard.Entry entry in WardBoard.Entries) { if (!WardBoard.IsRunning(entry.State)) { continue; } running.Add(entry.Id); string text = entry.Name + "'s ward"; if (_pins.TryGetValue(entry.Id, out var value) && value.m_name != text) { instance.RemovePin(value); _pins.Remove(entry.Id); value = null; } if (value == null) { value = instance.AddPin(entry.Pos, (PinType)3, text, false, false, 0L, default(PlatformUserID)); GameObject wardPrefab = Plugin.WardPrefab; Sprite val = ((wardPrefab == null) ? null : wardPrefab.GetComponent<Piece>()?.m_icon); if ((Object)(object)val != (Object)null) { value.m_icon = val; } _pins[entry.Id] = value; } else { value.m_pos = entry.Pos; } } foreach (ZDOID item in _pins.Keys.Where((ZDOID id) => !running.Contains(id)).ToList()) { instance.RemovePin(_pins[item]); _pins.Remove(item); } } public static void Clear() { if ((Object)(object)Minimap.instance != (Object)null) { foreach (PinData value in _pins.Values) { Minimap.instance.RemovePin(value); } } _pins.Clear(); } } [HarmonyPatch(typeof(Hud), "Awake")] internal static class Hud_Awake { private static void Postfix(Hud __instance) { WardHud.Create(__instance); } } public static class WorldReset { public const float DelaySeconds = 10f; public static bool Pending { get; private set; } public static void Schedule(string reason) { if (!Pending && !((Object)(object)ZNet.instance == (Object)null) && ZNet.instance.IsServer()) { Pending = true; Plugin.Log.LogWarning((object)$"World reset scheduled in {10f}s: {reason}"); WardChallenge.Say($"This world will be deleted in {10f:0} seconds."); ((MonoBehaviour)Plugin.Instance).StartCoroutine(Run()); } } private static IEnumerator Run() { yield return (object)new WaitForSeconds(10f); World world = ZNet.World; string text = world?.m_name; FileSource val = (FileSource)((world == null) ? 2 : ((int)world.m_fileSource)); bool dedicated = ZNet.instance.IsDedicated(); Plugin.Log.LogWarning((object)$"Deleting world '{text}' ({val}) and shutting down"); AccessTools.Method(typeof(Game), "Shutdown", (Type[])null, (Type[])null).Invoke(Game.instance, new object[1] { false }); if (!string.IsNullOrEmpty(text)) { World.RemoveWorld(text, val); } SaveSystem.InvalidateCache((SaveDataType)0); yield return null; if (dedicated) { Application.Quit(); } else { SystemResourceManager.FastLoadScene(Game.instance.m_startScene, (LoadSceneMode)0); } } } }