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 Troll Nuke v0.6.6
plugins/TrollNuke/TrollNuke.dll
Decompiled 4 days ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Jotunn.Configs; using Jotunn.Entities; using Jotunn.Managers; using Jotunn.Utils; using UnityEngine; using UnityEngine.PostProcessing; using UnityEngine.Rendering; using UnityEngine.SceneManagement; [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("TrollNuke")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.6.6.0")] [assembly: AssemblyInformationalVersion("0.6.6")] [assembly: AssemblyProduct("TrollNuke")] [assembly: AssemblyTitle("TrollNuke")] [assembly: AssemblyVersion("0.6.6.0")] namespace WeaponsOfMassDestruction; [Flags] public enum BlastParts { None = 0, Looks = 1, Sweep = 2, Crater = 4, All = 7 } public struct BlastPlan { public Vector3 Center; public float Radius; public float ShockSpeed; public double ImpactTime; public long Id; public long Shooter; public BlastParts Parts; } public static class Blast { private readonly struct Identity { private readonly double m_start; private readonly long m_shooter; private readonly float m_x; private readonly float m_y; private readonly float m_z; public Identity(double start, long shooter, Vector3 target) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) m_start = start; m_shooter = shooter; m_x = target.x; m_y = target.y; m_z = target.z; } public bool Same(Identity other) { if (m_start == other.m_start && m_shooter == other.m_shooter && m_x == other.m_x && m_y == other.m_y) { return m_z == other.m_z; } return false; } } private sealed class Entry { public BlastPlan Plan; public bool Console; public double LiftOff; public float Flown; public bool Dud; public double LastWarned = double.NegativeInfinity; public int Warnings; public bool Begun; public bool Closed; public float Late; public bool Own; public string OwnWhy = ""; public string LooksNote = "not begun"; public string PlayerNote = "not begun"; public string WorldNote; public bool PlayerPending; public bool Far; public string FarNote = ""; public bool AreaWaiting; public double AreaWaitUntil; public float AreaReadyAfter = -1f; public bool CraterWarm; public bool SweepWarm; public bool WarmFailed; public int WarmFrames; public bool WorldRan; public bool WorldActive; public double WorldStarted; public double WorldLimit; public CraterTicket Ticket; public bool CraterTried; public bool InnerCleared; public bool SweepSeenRunning; public bool SweepEnded; public float CraterWaited = -1f; public BlastSweep Sweep; public Action OnInnerCleared; public string CraterCheck = ""; public string CraterDig = ""; public string SweepNote = ""; public string SweepGivenUp; public float InnerClearedAfter = -1f; public float SweepOverAfter = -1f; public string PlacesRemoved; public string RecordsNote; public bool RecordsBegun; public float FpsBefore; public float WorstFrame; public float Settled; public float AfterSeconds; public int AfterFrames; } private const double LateGrace = 3.0; private const double WorldGrace = 30.0; private const double SweepPatience = 30.0; private const double SweepStartGrace = 1.0; private const float SettleSeconds = 2f; private const float AfterWindow = 1f; internal const float MinArmingDistance = 10f; private const float MinWorldRadius = 10f; private const float MaxWorldRadius = 600f; private const double AreaPatience = 12.0; private const double WideAreaPatience = 30.0; private const float WideFrom = 150f; private const double WarmLead = 6.0; private const float KeepUnchanged = 3f; private const float KeepChanged = 120f; internal const float HeightReach = 1.5f; private const float BluntShare = 0.6f; private const float PushPerSpeed = 0.8f; private const float LiftForward = 0.6f; private const float LiftUp = 0.45f; private const float MaxLiftUp = 10f; private const float EdgeTolerance = 0.5f; private const float ZoneSize = 64f; private static readonly List<Entry> s_entries = new List<Entry>(); private static readonly Dictionary<long, Identity> s_seen = new Dictionary<long, Identity>(); private static readonly List<ProtectedDisc> s_discs = new List<ProtectedDisc>(); private static ZNet s_world; private static BlastRunner s_runner; private static Entry s_worldEntry; private static string s_lastLine; private static float s_frameSeconds; private static bool s_loggedStepError; private static bool s_warnedIdClash; private static bool s_loggedPlayerError; internal const float ShooterRoom = 12f; public static bool SweepRunning { get { Entry entry = s_worldEntry; if (entry == null) { return false; } try { ZNet instance = ZNet.instance; if ((Object)(object)instance != (Object)null && instance == s_world && (Object)(object)s_runner != (Object)null && entry.WorldActive && !entry.Closed && instance.GetTimeSeconds() - entry.WorldStarted <= entry.WorldLimit + 5.0) { return true; } } catch (Exception) { } s_worldEntry = null; return false; } } internal static int Pending { get { if ((Object)(object)ZNet.instance == (Object)null || ZNet.instance != s_world || (Object)(object)s_runner == (Object)null) { return 0; } int num = 0; for (int i = 0; i < s_entries.Count; i++) { if (!s_entries[i].Begun) { num++; } } return num; } } internal static string LastLine => s_lastLine; public static void Schedule(LaunchOrder order) { //IL_001f: 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_0095: 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) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_023e: Unknown result type (might be due to invalid IL or missing references) //IL_0244: Unknown result type (might be due to invalid IL or missing references) //IL_0249: Unknown result type (might be due to invalid IL or missing references) //IL_024e: Unknown result type (might be due to invalid IL or missing references) //IL_0276: Unknown result type (might be due to invalid IL or missing references) //IL_027b: Unknown result type (might be due to invalid IL or missing references) //IL_0352: Unknown result type (might be due to invalid IL or missing references) try { ZNet instance = ZNet.instance; if ((Object)(object)instance == (Object)null) { Warn("[Blast] launch order not scheduled: no world is running."); return; } if (!FxLocal.IsFinite(order.Target) || !FxLocal.IsFinite(order.Pad) || !IsFinite(order.StartTime) || !FxLocal.IsFinite(order.PadHold) || !FxLocal.IsFinite(order.FlightTime) || !FxLocal.IsFinite(order.BlastRadius) || !(order.BlastRadius > 0f)) { Warn(Text($"[Blast] launch order not scheduled: it holds a broken number (target {order.Target}, pad {order.Pad}, start {order.StartTime}, hold {order.PadHold}, flight {order.FlightTime}, blast {order.BlastRadius}).")); return; } EnterWorld(instance); double num = RocketFlight.NetSeconds(instance); long id = BlastRules.OrderId(order.StartTime, order.Shooter, order.Target.x, order.Target.y, order.Target.z); if (!Claim(ref id, new Identity(order.StartTime, order.Shooter, order.Target))) { Warn(Text($"[Blast] the launch order with id {id:X} was scheduled a second time; the second one was dropped (one blast per order).")); return; } if (order.StartTime - num > 30.0) { Warn(Text($"[Blast] launch order {id:X} not scheduled: it starts {order.StartTime - num:F1} s from now (start {order.StartTime:F2}, clock {num:F2}).")); return; } string why; bool flag = IsOwn(order.Shooter, instance, out why); double num2 = num - order.ImpactTime; if (num2 > (flag ? 30.0 : 3.0)) { Info(Text($"[Blast] launch order {id:X} arrived {num2:F1} s after its blast: nothing is shown or done on this peer.")); return; } Vector3 val = order.Target - order.Pad; val.y = 0f; float magnitude = ((Vector3)(ref val)).magnitude; Entry entry = new Entry { Plan = new BlastPlan { Center = order.Target, Radius = order.BlastRadius, ShockSpeed = ShockSpeedNow(), ImpactTime = order.ImpactTime, Id = id, Shooter = order.Shooter, Parts = BlastParts.All }, LiftOff = order.StartTime + (double)order.PadHold, Flown = magnitude, Dud = !Arms(magnitude, order.BlastRadius), Own = flag, OwnWhy = why }; s_entries.Add(entry); EnsureRunner(); if (flag && !entry.Dud) { HoldArea(entry); } Info(Text($"[Blast] scheduled id={id:X} at {FxLocal.Vec(order.Target)} R={order.BlastRadius:0.#}: ") + ((num2 >= 0.0) ? Text($"its time passed {num2:F2} s ago, it runs at once") : Text($"in {0.0 - num2:F2} s")) + "; this peer " + (flag ? "changes the world" : "does not change the world") + " (" + why + ")" + ((flag && !entry.Dud) ? ("; far zones: " + entry.FarNote) : "") + (entry.Dud ? Text($"; the rocket stands {magnitude:F1} m from its target and needs {ArmingDistance(order.BlastRadius):F1} m to arm: it will be a dud") : "")); } catch (Exception ex) { Error("[Blast] a launch order could not be scheduled: " + ex); } } private static void HoldArea(Entry entry) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) try { entry.Far = FarZones.Begin(entry.Plan.Id, entry.Plan.Center, LiveRadius(entry.Plan.Radius) + 16f, out entry.FarNote); } catch (Exception ex) { entry.Far = false; entry.FarNote = "the hold failed (" + ex.GetType().Name + ": " + ex.Message + ")"; Warn("[Blast] the zones of blast " + entry.Plan.Id.ToString("X") + " could not be held: " + ex); } } internal static float LiveRadius(float radius) { float num = 0f; try { num = Crater.GroundReach(radius); } catch (Exception) { num = 0f; } return BlastRules.LiveRadius(radius, num); } public static void Now(Vector3 point, float radius, BlastParts parts) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) TryNow(point, radius, parts, out var _); } internal static bool TryNow(Vector3 point, float radius, BlastParts parts, out string note) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_008b: 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) Entry entry = null; try { ZNet instance = ZNet.instance; if ((Object)(object)instance == (Object)null) { note = "no world is running"; return false; } if (!FxLocal.IsFinite(point) || !FxLocal.IsFinite(radius) || !(radius > 0f)) { note = "that is not a usable point or radius"; return false; } parts &= BlastParts.All; if (parts == BlastParts.None) { note = "no part of the blast was asked for"; return false; } EnterWorld(instance); double num = RocketFlight.NetSeconds(instance); long id = BlastRules.OrderId(num, 0L, point.x, point.y, point.z); if (!Claim(ref id, new Identity(num, 0L, point))) { note = "the same blast was asked for twice in the same instant"; return false; } entry = new Entry { Plan = new BlastPlan { Center = point, Radius = radius, ShockSpeed = ShockSpeedNow(), ImpactTime = num, Id = id, Shooter = 0L, Parts = parts }, Console = true, LiftOff = num, Flown = float.NaN, Own = true, OwnWhy = "typed into this console" }; s_entries.Add(entry); EnsureRunner(); if ((parts & (BlastParts.Sweep | BlastParts.Crater)) != BlastParts.None) { HoldArea(entry); } Begin(entry, num, instance); note = "looks " + entry.LooksNote + "; world " + WorldText(entry, withPlaces: false); return true; } catch (Exception ex) { Error("[Blast] a blast from the console failed: " + ex); if (entry != null) { Abandon(entry); s_entries.Remove(entry); } note = "it failed: " + ex.GetType().Name + ": " + ex.Message; return false; } } internal static float ArmingDistance(float blastRadius) { if (!(Value(Settings.MinSafeDistanceFactor, 1.5f) < 1f)) { return Mathf.Max(blastRadius, 10f); } return 0f; } internal static bool Arms(float flown, float blastRadius) { return flown >= ArmingDistance(blastRadius); } internal static bool AreaLoaded(Vector3 center, float radius) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) int zones; int missing; return DiscLoaded(center, radius, out zones, out missing); } internal static string Describe(Vector3 point, float radius) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_0194: Unknown result type (might be due to invalid IL or missing references) //IL_0199: Unknown result type (might be due to invalid IL or missing references) //IL_019a: Unknown result type (might be due to invalid IL or missing references) //IL_019f: Unknown result type (might be due to invalid IL or missing references) //IL_01a1: Unknown result type (might be due to invalid IL or missing references) try { float num = ShockSpeedNow(); BlastPlan plan = new BlastPlan { Center = point, Radius = radius, ShockSpeed = num, Parts = BlastParts.All }; string say; string text = Refusal(plan, 0f, out say); if (text == null && !AreaReady(plan, out var why)) { text = why + (FarZones.Available(out say) ? "; a launch would load it first" : ""); } StringBuilder stringBuilder = new StringBuilder(256); float num2 = BlastRules.ClearRadius(radius, Crater.GroundReach(radius)); stringBuilder.Append(Text($"blast: R={radius:0.#} m, fireball to {BlastRules.VaporiseRadius(radius):0.#} m, ")); if (num2 > BlastRules.VaporiseRadius(radius)) { stringBuilder.Append(Text($"everything goes whole out to {num2:0.#} m (the ground the crater moves), ")); } stringBuilder.Append(Text($"shove to {BlastRules.PushRadius(radius):0.#} m, the wave at {num:0.#} m/s reaches the edge after {ShockFront.Arrival(radius, radius, num):0.00} s; ")); stringBuilder.Append((text == null) ? "a blast here now would change the world" : ("a blast here now would be an explosion only: " + text)); stringBuilder.Append("; protected places in reach: ").Append(ProtectedPlaces(plan)); stringBuilder.Append("; places it would remove whole: ").Append(Protection.DoomedNames(point, radius)); Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer != (Object)null) { Vector3 val = ((Component)localPlayer).transform.position - point; float num3 = Mathf.Abs(val.y); val.y = 0f; float magnitude = ((Vector3)(ref val)).magnitude; float num4 = BlastRules.PushRadius(radius); float distance = ((magnitude > num4 && magnitude <= num4 + 0.5f) ? num4 : magnitude); BlastBand blastBand = ((!(num3 > 1.5f * radius)) ? BlastRules.BandAt(radius, distance) : BlastBand.None); stringBuilder.Append(Text($"; you: {magnitude:0.0} m away, {BandName(blastBand)}")); if (blastBand != BlastBand.None) { PlayerDamageMode playerDamageMode = ((Settings.PlayerDamage != null) ? Settings.PlayerDamage.Value : PlayerDamageMode.Full); float num5 = ((blastBand == BlastBand.Push || playerDamageMode == PlayerDamageMode.None) ? 0f : BlastRules.CreatureDamage(radius, distance, Value(Settings.CreatureDamage, 0f))); stringBuilder.Append(Text($", the wave after {ShockFront.Arrival(distance, radius, num):0.00} s: ")).Append((num5 > 0f) ? Text($"a hit of {num5:0} before armour and a throw") : "a stagger and a shove, no damage").Append(" (PlayerDamage=") .Append(playerDamageMode) .Append(')'); } } return stringBuilder.ToString(); } catch (Exception ex) { return "blast: could not be described (" + ex.GetType().Name + ": " + ex.Message + ")"; } } internal static string Status() { int num = 0; for (int i = 0; i < s_entries.Count; i++) { if (s_entries[i].Begun) { num++; } } return "blast: SweepRunning=" + SweepRunning + ", to come=" + Pending + ", being finished=" + (((Object)(object)ZNet.instance != (Object)null && ZNet.instance == s_world) ? num : 0); } private static bool IsOwn(long shooter, ZNet net, out string why) { if (net.IsDedicated()) { why = "a dedicated server changes nothing itself"; return false; } if (shooter == 0L) { bool flag = net.IsServer(); why = (flag ? "launched from this console" : "launched from the host's console"); return flag; } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer != (Object)null && localPlayer.GetPlayerID() == shooter) { why = "the shooter is this player"; return true; } if (ZNet.IsSinglePlayer) { why = "single player"; return true; } why = "the shooter is another player"; return false; } private static bool Claim(ref long id, Identity blast) { if (s_seen.Count > 4096) { s_seen.Clear(); } for (int i = 0; i < 256; i++) { if (!s_seen.TryGetValue(id, out var value)) { s_seen.Add(id, blast); return true; } if (value.Same(blast)) { return false; } if (!s_warnedIdClash) { s_warnedIdClash = true; Warn(Text($"[Blast] two different blasts were given the id {id:X}; the later one takes the next free number (said once).")); } id++; } return false; } private static void EnterWorld(ZNet net) { if (net != s_world) { if ((Object)(object)s_world != (Object)null || s_entries.Count > 0 || s_seen.Count > 0) { Close("another world was entered"); } s_world = net; } } private static void EnsureRunner() { //IL_0013: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)s_runner != (Object)null)) { s_runner = new GameObject("WMD_Blast").AddComponent<BlastRunner>(); } } private static void Close(string why) { int num = 0; for (int i = 0; i < s_entries.Count; i++) { Entry entry = s_entries[i]; entry.Closed = true; if (entry.Begun) { try { WriteLine(entry, (entry.PlayerPending || entry.WorldActive) ? why : null, withPlaces: false); } catch (Exception ex) { Warn("[Blast] the line of a blast could not be written: " + ex.Message); } } else { num++; } entry.Ticket = null; entry.Sweep = null; } if (num > 0) { Info("[Blast] " + why + ": " + num + " blast(s) whose time had not come were dropped. Nothing is left behind."); } s_entries.Clear(); s_seen.Clear(); s_worldEntry = null; s_world = null; s_frameSeconds = 0f; BlastRunner blastRunner = s_runner; s_runner = null; if ((Object)(object)blastRunner != (Object)null) { Object.Destroy((Object)(object)((Component)blastRunner).gameObject); } } internal static void RunnerGone(BlastRunner runner) { if (runner != s_runner) { return; } s_runner = null; try { Close("the world was closed"); } catch (Exception ex) { s_entries.Clear(); s_seen.Clear(); s_worldEntry = null; s_world = null; Warn("[Blast] the schedule could not be closed in order: " + ex.Message); } } internal static void Tick(BlastRunner runner) { if (runner != s_runner) { Object.Destroy((Object)(object)((Component)runner).gameObject); return; } try { Step(); } catch (Exception ex) { if (!s_loggedStepError) { s_loggedStepError = true; Error("[Blast] the schedule failed and was emptied (said once): " + ex); } try { Close("the schedule failed"); } catch (Exception) { s_entries.Clear(); s_worldEntry = null; } } } private static void Step() { ZNet instance = ZNet.instance; if ((Object)(object)instance == (Object)null || instance != s_world) { Close("the world was closed"); } else { if (Time.timeScale <= 0f) { return; } float unscaledDeltaTime = Time.unscaledDeltaTime; if (unscaledDeltaTime > 0f && unscaledDeltaTime < 1f) { s_frameSeconds = ((s_frameSeconds > 0f) ? Mathf.Lerp(s_frameSeconds, unscaledDeltaTime, Mathf.Min(1f, 2f * unscaledDeltaTime)) : unscaledDeltaTime); } if (s_entries.Count == 0) { return; } double now = RocketFlight.NetSeconds(instance); for (int num = s_entries.Count - 1; num >= 0; num--) { Entry entry = s_entries[num]; bool flag; try { flag = (entry.Begun ? Follow(entry, now, unscaledDeltaTime) : Wait(entry, now, instance)); } catch (Exception ex) { Error(Text($"[Blast] blast {entry.Plan.Id:X} failed and was ended: ") + ex); Abandon(entry); entry.WorldNote = entry.WorldNote + " (ended by an error: " + ex.GetType().Name + ")"; flag = true; } if (flag) { s_entries.RemoveAt(num); entry.Closed = true; if (entry.Far) { FarZones.Settle(entry.Plan.Id, entry.WorldRan ? Value(Settings.KeepBlastSite, 120f) : 3f); } if (entry.Begun) { try { WriteLine(entry, null, withPlaces: true); } catch (Exception ex2) { Warn("[Blast] the line of blast " + entry.Plan.Id.ToString("X") + " could not be written: " + ex2.Message); } } } } } } private static void Abandon(Entry entry) { entry.PlayerPending = false; entry.AreaWaiting = false; if (entry.Ticket != null && !entry.CraterTried) { entry.CraterDig = "crater never dug (the blast was ended first)"; } EndWorld(entry); } private static bool Wait(Entry entry, double now, ZNet net) { //IL_0093: Unknown result type (might be due to invalid IL or missing references) BlastPlan plan = entry.Plan; if (now >= plan.ImpactTime) { Begin(entry, now, net); return false; } if (entry.Own && !entry.Dud && !entry.WarmFailed && plan.ImpactTime - now <= 6.0) { WarmAhead(entry); } if (!entry.Dud && now >= entry.LiftOff && now - entry.LastWarned >= 1.0) { entry.LastWarned = now; Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer != (Object)null && !((Character)localPlayer).IsDead() && InReach(((Component)localPlayer).transform.position, plan, plan.Radius)) { entry.Warnings++; Tell("You are inside the blast radius"); } } return false; } private static void WarmAhead(Entry entry) { //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) try { BlastPlan plan = entry.Plan; bool flag = (plan.Parts & BlastParts.Crater) != BlastParts.None && !entry.CraterWarm; bool flag2 = (plan.Parts & BlastParts.Sweep) != BlastParts.None && !entry.SweepWarm; if ((flag || flag2) && FarZones.Ready(plan.Center, LiveRadius(plan.Radius), out var _, out var _, out var _)) { float budgetMs = 0.5f * Mathf.Clamp(Value(Settings.BlastBudgetMs, 4f), 1f, 16f); entry.WarmFrames++; if (flag) { entry.CraterWarm = Crater.Warm(plan.Center, plan.Radius, budgetMs); } if (flag2) { plan.ShockSpeed = ShockSpeedNow(); entry.SweepWarm = BlastSweep.Warm(plan, budgetMs); } } } catch (Exception ex) { entry.WarmFailed = true; Warn(Text($"[Blast] reading ahead for blast {entry.Plan.Id:X} failed and was given up (the blast itself is not affected): ") + ex); } } private static bool Follow(Entry entry, double now, float frame) { if (frame > entry.WorstFrame && frame < 10f) { entry.WorstFrame = frame; } if (entry.PlayerPending) { WatchPlayer(entry, now); } if (entry.WorldActive) { WatchWorld(entry, now); } if (entry.PlayerPending || entry.WorldActive) { return false; } entry.Settled += frame; if (entry.Settled > 1f) { entry.AfterSeconds += frame; entry.AfterFrames++; } return entry.Settled >= 2f; } private static void Begin(Entry entry, double now, ZNet net) { //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Invalid comparison between Unknown and I4 //IL_0137: Unknown result type (might be due to invalid IL or missing references) entry.Begun = true; BlastPlan plan = entry.Plan; plan.ShockSpeed = ShockSpeedNow(); entry.Plan = plan; entry.Late = (float)Math.Max(0.0, now - plan.ImpactTime); entry.FpsBefore = ((s_frameSeconds > 0f) ? (1f / s_frameSeconds) : ((Time.smoothDeltaTime > 0f) ? (1f / Time.smoothDeltaTime) : 0f)); if (!entry.Console) { entry.Own = IsOwn(plan.Shooter, net, out entry.OwnWhy); } bool flag = !net.IsDedicated() && (int)SystemInfo.graphicsDeviceType != 4; bool flag2 = (double)entry.Late <= 3.0; if (entry.Dud) { BeginDud(entry, flag && flag2); return; } if ((plan.Parts & BlastParts.Looks) == 0) { entry.LooksNote = "not asked for"; } else if (!flag) { entry.LooksNote = "none (no display on this peer)"; } else if (!flag2) { entry.LooksNote = Text($"skipped ({entry.Late:F1} s late)"); } else { try { Impact.Detonate(plan.Center, plan.Radius); entry.LooksNote = "shown"; } catch (Exception ex) { entry.LooksNote = "failed (" + ex.GetType().Name + ")"; Error("[Blast] the explosion could not be shown: " + ex); } } if ((plan.Parts & BlastParts.Sweep) == 0) { entry.PlayerNote = "not asked for (it goes with the sweep)"; } else if (net.IsDedicated()) { entry.PlayerNote = "none on a dedicated server"; } else if (!flag2) { entry.PlayerNote = Text($"skipped ({entry.Late:F1} s late)"); } else { entry.PlayerPending = true; entry.PlayerNote = "the wave has not reached them"; } if ((plan.Parts & (BlastParts.Sweep | BlastParts.Crater)) == 0) { entry.WorldNote = "not asked for"; } else if (!entry.Own) { entry.WorldNote = "not this peer's to change (" + entry.OwnWhy + ")"; } else { string say; string text = Refusal(plan, entry.Late, out say); string why; if (text != null) { entry.WorldNote = "REFUSED: " + text; if (say != null) { Tell(say); } } else if (AreaReady(plan, out why)) { entry.AreaReadyAfter = 0f; StartWorld(entry, now); } else if (entry.Far) { entry.AreaWaiting = true; double num = ((entry.Plan.Radius > 150f) ? 30.0 : 12.0); entry.AreaWaitUntil = now + num; entry.WorldActive = true; entry.WorldStarted = now; entry.WorldLimit = num + 5.0; entry.WorldNote = "waiting for its area to load: " + why; s_worldEntry = entry; } else { entry.WorldNote = "REFUSED: " + why; Tell("Explosion only: the blast area is not fully loaded from where you are."); } } if (entry.PlayerPending) { WatchPlayer(entry, now); } } private static void BeginDud(Entry entry, bool show) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) BlastPlan plan = entry.Plan; string text = "not shown"; if (show) { try { RocketFlight.GroundBurst(plan.Center, RocketModel.PlannedLength(), out var dustShown, out var soundShown); text = "dust=" + dustShown + ", sound=" + soundShown; } catch (Exception ex) { text = "failed (" + ex.GetType().Name + ")"; } } entry.LooksNote = Text($"DUD, the rocket stood {entry.Flown:F1} m from its target and needs {ArmingDistance(plan.Radius):F1} m to arm: a puff only ({text})"); entry.PlayerNote = "untouched"; entry.WorldNote = "untouched"; if (entry.Own) { Tell(Text($"The rocket did not arm: it stood only {entry.Flown:0} m from its target.")); } } private static string Refusal(BlastPlan plan, float late, out string say) { //IL_00fc: Unknown result type (might be due to invalid IL or missing references) say = null; if ((double)late > 30.0) { return Text($"its time passed {late:F0} s ago"); } if (!(plan.Radius >= 10f) || !(plan.Radius <= 600f)) { say = Text($"A blast radius of {plan.Radius:0.#} m only shows the explosion (the world is changed from {10f:0} to {600f:0} m)."); return Text($"the radius {plan.Radius:0.#} m is outside {10f:0} to {600f:0} m"); } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return "this peer has no player in the world (dead or not spawned)"; } if ((Object)(object)ZNetScene.instance == (Object)null || (Object)(object)ZoneSystem.instance == (Object)null) { return "the world is not there (loading or closing)"; } if (Character.InInterior(plan.Center)) { say = "Explosion only: it went off inside a dungeon."; return "ground zero is inside a dungeon"; } if (((Character)localPlayer).InInterior()) { say = "Explosion only: you are inside a dungeon."; return "the player is inside a dungeon"; } if (SweepRunning) { say = "Explosion only: the last blast is still settling."; return "another blast is still being applied"; } return null; } private static bool AreaReady(BlastPlan plan, out string why) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) if (FarZones.Ready(plan.Center, LiveRadius(plan.Radius), out var zones, out var missing, out var objectsToCome)) { why = null; return true; } why = Text(FormattableStringFactory.Create("the blast disc is not fully loaded ({0} of its {1} zones {2} missing", missing, zones, (missing == 1) ? "is" : "are")) + ((objectsToCome > 0) ? Text($", {objectsToCome} objects still to come)") : ")"); return false; } private static void WatchArea(Entry entry, double now) { //IL_0057: Unknown result type (might be due to invalid IL or missing references) BlastPlan plan = entry.Plan; float num = (float)(now - plan.ImpactTime); if (AreaReady(plan, out var why)) { entry.AreaWaiting = false; entry.AreaReadyAfter = num; entry.WorldNote = null; StartWorld(entry, now); } else if (!(now < entry.AreaWaitUntil)) { entry.AreaWaiting = false; if ((Object)(object)Player.m_localPlayer != (Object)null && FarZones.GroundReady(plan.Center, LiveRadius(plan.Radius))) { entry.AreaReadyAfter = num; entry.FarNote = entry.FarNote + Text($"; begun {num:F1} s after the flash without waiting longer for: ") + why; entry.WorldNote = null; StartWorld(entry, now); } else { entry.WorldNote = Text($"REFUSED: its area had not loaded {num:F1} s after the flash: ") + why; Tell("Explosion only: the blast area did not load in time."); EndWorld(entry); } } } private static bool DiscLoaded(Vector3 center, float radius, out int zones, out int missing) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) zones = 0; missing = 0; ZoneSystem instance = ZoneSystem.instance; ZNet instance2 = ZNet.instance; if ((Object)(object)instance == (Object)null || (Object)(object)instance2 == (Object)null) { return false; } return DiscWithin(instance, ZoneSystem.GetZone(instance2.GetReferencePosition()), instance2.GetSyncedSimulationDistance(), center, radius, mustBeBuilt: true, out zones, out missing); } internal static bool AreaHolds(Vector3 center, float radius, Vector3 shooter) { //IL_0000: 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_0035: 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_0037: Unknown result type (might be due to invalid IL or missing references) //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_006b: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: 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_00b1: 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_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: 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_00c2: Unknown result type (might be due to invalid IL or missing references) if (!DiscLoaded(center, radius, out var zones, out var missing)) { return false; } ZoneSystem instance = ZoneSystem.instance; ZNet instance2 = ZNet.instance; if ((Object)(object)instance == (Object)null || (Object)(object)instance2 == (Object)null) { return false; } SimulationDistance syncedSimulationDistance = instance2.GetSyncedSimulationDistance(); Vector3 val = center - shooter; val.y = 0f; if (((Vector3)(ref val)).magnitude + radius <= 64f * (float)((SimulationDistance)(ref syncedSimulationDistance)).NearSimulationDistance + 0.01f) { return true; } Vector2s zone = ZoneSystem.GetZone(shooter); for (int i = 0; i < 4; i++) { Vector2s zone2 = ZoneSystem.GetZone(shooter + new Vector3(((i & 1) == 0) ? (-12f) : 12f, 0f, ((i & 2) == 0) ? (-12f) : 12f)); if (zone2 != zone && !DiscWithin(instance, zone2, syncedSimulationDistance, center, radius, mustBeBuilt: false, out missing, out zones)) { return false; } } return true; } internal static float SureRange(float radius) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) ZNet instance = ZNet.instance; if (!((Object)(object)instance != (Object)null)) { return 0f; } SimulationDistance syncedSimulationDistance = instance.GetSyncedSimulationDistance(); return Mathf.Max(0f, 64f * (float)((SimulationDistance)(ref syncedSimulationDistance)).NearSimulationDistance - radius); } private static bool DiscWithin(ZoneSystem system, Vector2s home, SimulationDistance reach, Vector3 center, float radius, bool mustBeBuilt, out int zones, out int missing) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0089: 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_00c7: 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_00d6: Unknown result type (might be due to invalid IL or missing references) zones = 0; missing = 0; int num = ZoneIndex(center.x - radius); int num2 = ZoneIndex(center.x + radius); int num3 = ZoneIndex(center.z - radius); int num4 = ZoneIndex(center.z + radius); Vector2s val = default(Vector2s); for (int i = num3; i <= num4; i++) { for (int j = num; j <= num2; j++) { float num5 = (float)j * 64f; float num6 = (float)i * 64f; float num7 = Mathf.Max(0f, Mathf.Abs(center.x - num5) - 32f); float num8 = Mathf.Max(0f, Mathf.Abs(center.z - num6) - 32f); if (!(num7 * num7 + num8 * num8 > radius * radius)) { zones++; ((Vector2s)(ref val))..ctor(j, i); if (!InNearArea(system, home, reach, val) || (mustBeBuilt && !system.IsZoneLoaded(val))) { missing++; } } } } if (zones > 0) { return missing == 0; } return false; } internal static bool InNearArea(ZoneSystem system, Vector2s home, SimulationDistance reach, Vector2s zone) { //IL_0008: 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_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0023: 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_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) int nearSimulationDistance = ((SimulationDistance)(ref reach)).NearSimulationDistance; if (Math.Abs(zone.x - home.x) > nearSimulationDistance || Math.Abs(zone.y - home.y) > nearSimulationDistance) { return false; } if (!((SimulationDistance)(ref reach)).IsClassic && !(zone == home)) { return system.ZonesWithinRadius(home, zone, nearSimulationDistance, false); } return true; } private static int ZoneIndex(float coordinate) { return Mathf.FloorToInt((coordinate + 32f) / 64f); } private static string ProtectedPlaces(BlastPlan plan) { //IL_000b: 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_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_008c: Unknown result type (might be due to invalid IL or missing references) try { s_discs.Clear(); Protection.ProtectedDiscs(plan.Center, plan.Radius, s_discs); if (s_discs.Count == 0) { return "none"; } StringBuilder stringBuilder = new StringBuilder(64); stringBuilder.Append(s_discs.Count).Append(" ("); for (int i = 0; i < s_discs.Count && i < 4; i++) { if (i > 0) { stringBuilder.Append(", "); } Vector3 val = s_discs[i].Center - plan.Center; val.y = 0f; stringBuilder.Append(string.IsNullOrEmpty(s_discs[i].Name) ? "a place" : s_discs[i].Name).Append(Text($" r={s_discs[i].Radius:0.#} m, {((Vector3)(ref val)).magnitude:0} m off")); } if (s_discs.Count > 4) { stringBuilder.Append(", ..."); } stringBuilder.Append(')'); s_discs.Clear(); return stringBuilder.ToString(); } catch (Exception ex) { s_discs.Clear(); return "not known (" + ex.GetType().Name + ")"; } } private static void StartWorld(Entry entry, double now) { //IL_00b6: Unknown result type (might be due to invalid IL or missing references) BlastPlan plan = entry.Plan; bool num = (plan.Parts & BlastParts.Crater) != 0; bool flag = (plan.Parts & BlastParts.Sweep) != 0; entry.WorldRan = true; entry.WorldActive = true; entry.WorldStarted = now; entry.WorldLimit = (double)ShockFront.Arrival(BlastRules.PushRadius(plan.Radius) + 8f, plan.Radius, plan.ShockSpeed) + 30.0; s_worldEntry = entry; if (!num) { entry.CraterCheck = "crater not asked for"; } else { try { entry.Ticket = Crater.Check(plan.Center, plan.Radius, out var note); entry.CraterCheck = Labelled((entry.Ticket != null) ? "crater ready" : "no crater", note); } catch (Exception ex) { entry.Ticket = null; entry.CraterCheck = "no crater (its check failed: " + ex.GetType().Name + ": " + ex.Message + ")"; Error("[Blast] the crater's check failed: " + ex); } } if (!flag) { entry.SweepNote = "not asked for"; } else if (!(Value(Settings.ObjectDamage, 0f) > 0f) && !(Value(Settings.CreatureDamage, 0f) > 0f)) { entry.SweepNote = "off (ObjectDamage and CreatureDamage are both 0)"; } else { try { entry.OnInnerCleared = delegate { InnerCleared(entry); }; entry.Sweep = BlastSweep.Run(plan, entry.OnInnerCleared); entry.SweepNote = (((Object)(object)entry.Sweep != (Object)null) ? "started" : "could not start (the sweep's own line says why)"); } catch (Exception ex2) { entry.Sweep = null; entry.SweepNote = "could not start (" + ex2.GetType().Name + ": " + ex2.Message + ")"; Error("[Blast] the sweep could not be started: " + ex2); } } if (flag && (Object)(object)entry.Sweep != (Object)null) { BeginRecords(entry); } if ((Object)(object)entry.Sweep == (Object)null) { if (entry.Ticket != null) { RemovePlaces(entry); } Dig(entry, null); if (!CraterBusy()) { EndWorld(entry); } } } private static void BeginRecords(Entry entry) { //IL_0059: Unknown result type (might be due to invalid IL or missing references) if (entry.RecordsNote != null) { return; } try { if (!RecordSweep.Applies(entry.Plan.Radius, out var why)) { entry.RecordsNote = ((entry.Plan.Radius > 200f) ? ("not worked on (" + why + ")") : ""); return; } entry.RecordsBegun = RecordSweep.Start(entry.Plan.Center, entry.Plan.Radius, entry.Plan.Id, out var note); entry.RecordsNote = Text($"beyond {LiveRadius(entry.Plan.Radius):0} m by the world's records, ") + (entry.RecordsBegun ? note : ("NOT begun (" + note + ")")); } catch (Exception ex) { entry.RecordsBegun = false; entry.RecordsNote = "NOT begun (" + ex.GetType().Name + ": " + ex.Message + ")"; Error("[Blast] the work on the records could not be started: " + ex); } } private static bool RecordsBusy(Entry entry) { try { return entry.RecordsBegun && RecordSweep.Running; } catch (Exception) { return false; } } private static bool CraterBusy() { try { return Crater.Busy; } catch (Exception) { return false; } } private static void InnerCleared(Entry entry) { try { if (!entry.Closed && !entry.InnerCleared) { entry.InnerCleared = true; ZNet instance = ZNet.instance; if ((Object)(object)instance != (Object)null) { entry.InnerClearedAfter = (float)(RocketFlight.NetSeconds(instance) - entry.Plan.ImpactTime); } RemovePlaces(entry); Dig(entry, null); } } catch (Exception ex) { Error("[Blast] the crater could not be dug when the middle was cleared: " + ex); } } private static void RemovePlaces(Entry entry) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) if (entry.PlacesRemoved != null || entry.Closed) { return; } entry.PlacesRemoved = "none"; try { entry.PlacesRemoved = Protection.RemoveDoomed(entry.Plan.Center, entry.Plan.Radius) ?? "none"; } catch (Exception ex) { entry.PlacesRemoved = "not known (" + ex.GetType().Name + ")"; Error("[Blast] the places in the fireball could not be removed: " + ex); } } private static void Dig(Entry entry, string why) { CraterTicket ticket = entry.Ticket; if (ticket == null || entry.CraterTried || entry.Closed) { return; } entry.CraterTried = true; entry.Ticket = null; try { string note; bool flag = Crater.Dig(ticket, out note); entry.CraterDig = Labelled(flag ? "crater under way" : "crater NOT dug", note) + ((why != null) ? (" " + why) : ""); } catch (Exception ex) { entry.CraterDig = "crater NOT dug (it failed: " + ex.GetType().Name + ": " + ex.Message + ")"; Error("[Blast] the crater could not be dug: " + ex); } } private static void WatchWorld(Entry entry, double now) { if (entry.AreaWaiting) { WatchArea(entry, now); return; } bool running = BlastSweep.Running; if (running) { entry.SweepSeenRunning = true; } double num = now - entry.WorldStarted; bool flag = (Object)(object)entry.Sweep == (Object)null || (!running && (entry.SweepSeenRunning || num > 1.0)); string sweepGivenUp = null; if (!flag && num > entry.WorldLimit) { flag = true; sweepGivenUp = Text($"it still said it was running {num:F0} s after it began and is no longer waited for"); Warn(Text($"[Blast] the sweep of blast {entry.Plan.Id:X} still says it is running {num:F0} s after it began; the blast is taken as over.")); } if (!flag) { return; } if (!entry.SweepEnded) { entry.SweepEnded = true; if (entry.Sweep != null) { entry.SweepOverAfter = (float)(now - entry.Plan.ImpactTime); entry.SweepGivenUp = sweepGivenUp; } if (entry.Ticket != null && !entry.CraterTried) { Dig(entry, "(the sweep ended without clearing the middle first)"); } } if (num <= entry.WorldLimit && (CraterBusy() || RecordsBusy(entry))) { if (entry.CraterWaited < 0f) { entry.CraterWaited = 0f; } return; } if (entry.CraterWaited >= 0f) { entry.CraterWaited = (float)(now - entry.WorldStarted) - Math.Max(0f, entry.SweepOverAfter - (float)(entry.WorldStarted - entry.Plan.ImpactTime)); } EndWorld(entry); } private static void EndWorld(Entry entry) { entry.WorldActive = false; entry.AreaWaiting = false; entry.Ticket = null; entry.Sweep = null; if (s_worldEntry == entry) { s_worldEntry = null; } } private static void WatchPlayer(Entry entry, double now) { //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Unknown result type (might be due to invalid IL or missing references) BlastPlan plan = entry.Plan; float num = (float)(now - plan.ImpactTime); float num2 = BlastRules.PushRadius(plan.Radius); bool flag = num > ShockFront.Arrival(num2, plan.Radius, plan.ShockSpeed); Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { if (flag) { entry.PlayerPending = false; entry.PlayerNote = "none in the world on this peer"; } return; } Vector3 val = ((Component)localPlayer).transform.position - plan.Center; float num3 = Mathf.Abs(val.y); val.y = 0f; float magnitude = ((Vector3)(ref val)).magnitude; if (num3 > 1.5f * plan.Radius || ((Character)localPlayer).InInterior() != Character.InInterior(plan.Center)) { entry.PlayerPending = false; entry.PlayerNote = Text($"{magnitude:0.0} m away but {num3:0} m above or below ground zero: out of reach"); return; } if (magnitude > num2 + 0.5f) { if (flag) { entry.PlayerPending = false; entry.PlayerNote = Text($"{magnitude:0.0} m away when the wave left the push radius ({num2:0.#} m): out of reach"); } return; } float num4 = Mathf.Min(magnitude, num2); if (num < ShockFront.Arrival(num4, plan.Radius, plan.ShockSpeed)) { return; } entry.PlayerPending = false; try { entry.PlayerNote = Strike(entry, localPlayer, val, num4, num); } catch (Exception ex) { entry.PlayerNote = Text($"{magnitude:0.0} m away: failed ({ex.GetType().Name}: {ex.Message})"); if (!s_loggedPlayerError) { s_loggedPlayerError = true; Error("[Blast] the blast's effect on the player failed (said once): " + ex); } } } private static string Strike(Entry entry, Player player, Vector3 offset, float away, float sinceFlash) { //IL_0164: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Unknown result type (might be due to invalid IL or missing references) //IL_0156: Unknown result type (might be due to invalid IL or missing references) //IL_015b: 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_0179: Unknown result type (might be due to invalid IL or missing references) //IL_017e: 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_0271: Expected O, but got Unknown //IL_0211: Unknown result type (might be due to invalid IL or missing references) //IL_0219: Unknown result type (might be due to invalid IL or missing references) //IL_02af: Unknown result type (might be due to invalid IL or missing references) //IL_02b4: Unknown result type (might be due to invalid IL or missing references) //IL_02bb: Unknown result type (might be due to invalid IL or missing references) //IL_02bd: Unknown result type (might be due to invalid IL or missing references) //IL_02e6: Unknown result type (might be due to invalid IL or missing references) //IL_0331: Unknown result type (might be due to invalid IL or missing references) //IL_0336: Unknown result type (might be due to invalid IL or missing references) //IL_0398: Unknown result type (might be due to invalid IL or missing references) //IL_03a2: Unknown result type (might be due to invalid IL or missing references) //IL_03a7: Unknown result type (might be due to invalid IL or missing references) //IL_03ae: Unknown result type (might be due to invalid IL or missing references) //IL_03b3: Unknown result type (might be due to invalid IL or missing references) BlastPlan plan = entry.Plan; BlastBand blastBand = BlastRules.BandAt(plan.Radius, away); string text = Text($"{away:0.0} m away, {BandName(blastBand)}, the wave after {sinceFlash:0.00} s: "); if (blastBand == BlastBand.None) { return text + "out of reach"; } if (((Character)player).IsDead()) { return text + "already dead"; } if (((Character)player).IsTeleporting()) { return text + "teleporting, left alone"; } if (((Character)player).InCutscene()) { return text + "asleep or in a cutscene, left alone"; } if (((Character)player).IsDebugFlying()) { return text + "debug fly is on, left alone"; } PlayerDamageMode playerDamageMode = ((Settings.PlayerDamage != null) ? Settings.PlayerDamage.Value : PlayerDamageMode.Full); string text2 = "PlayerDamage=" + playerDamageMode; if (!entry.Own && playerDamageMode != PlayerDamageMode.None) { HurtPlayersMode hurtPlayersMode = ((Settings.HurtOtherPlayers == null) ? HurtPlayersMode.PvpOnly : Settings.HurtOtherPlayers.Value); bool flag = hurtPlayersMode switch { HurtPlayersMode.PvpOnly => ((Character)player).IsPVPEnabled(), HurtPlayersMode.Always => true, _ => false, }; text2 = text2 + ", somebody else's blast with HurtOtherPlayers=" + hurtPlayersMode.ToString() + (flag ? "" : ": a shove only"); if (!flag) { playerDamageMode = PlayerDamageMode.None; } } Vector3 val = ((((Vector3)(ref offset)).sqrMagnitude > 0.01f) ? ((Vector3)(ref offset)).normalized : (-Flat(((Component)player).transform.forward))); if (((Vector3)(ref val)).sqrMagnitude < 0.01f) { val = Vector3.forward; } float num = Mathf.Max(0f, BlastRules.ThrowSpeed(plan.Radius, away)); bool flag2 = ((Character)player).IsAttached(); float num2 = (flag2 ? 0f : (0.8f * ((Character)player).GetMass() * num)); float num3 = ((blastBand == BlastBand.Push || playerDamageMode == PlayerDamageMode.None) ? 0f : BlastRules.CreatureDamage(plan.Radius, away, Value(Settings.CreatureDamage, 0f))); float health = ((Character)player).GetHealth(); if (!(num3 > 0f)) { if (flag2) { return text + "attached to something (sitting, steering, riding), not shoved; no damage (" + text2 + ")"; } ((Character)player).Stagger(val); ((Character)player).ApplyPushback(val, num2); return text + Text($"staggered and shoved about {0.5f * num2 / Mathf.Max(0.01f, ((Character)player).GetMass()):0.0} m, no damage ({text2})"); } bool flag3 = playerDamageMode == PlayerDamageMode.NeverKill; HitData val2 = new HitData(); val2.m_damage.m_blunt = (flag3 ? num3 : (0.6f * num3)); val2.m_damage.m_fire = (flag3 ? 0f : (0.39999998f * num3)); val2.m_point = ((Character)player).GetCenterPoint(); val2.m_dir = val; val2.m_pushForce = num2; val2.m_staggerMultiplier = (flag2 ? 1f : 100f); val2.m_hitType = (HitType)11; val2.m_dodgeable = false; val2.m_blockable = false; val2.m_ranged = true; val2.m_backstabBonus = 1f; val2.m_toolTier = 0; val2.m_itemWorldLevel = (byte)Mathf.Clamp(Game.m_worldLevel, 0, 255); val2.m_attacker = ZDOID.None; ((Character)player).Damage(val2); string text3 = ""; if (flag3) { if (!((Character)player).IsDead() && ((Character)player).GetHealth() < 1f) { ((Character)player).SetHealth(1f); } } else if (!flag2 && num > 0f) { float num4 = Mathf.Min(0.45f * num, 10f); ((Character)player).ForceJump(val * (0.6f * num) + Vector3.up * num4, false); text3 = Text($", thrown at {0.6f * num:0.0} m/s out and {num4:0.0} m/s up"); } return text + Text(FormattableStringFactory.Create("hit for {0:0} before armour ({1}), health {2:0.#} -> {3:0.#}", num3, flag3 ? "blunt only" : "blunt and fire", health, ((Character)player).GetHealth())) + text3 + " (" + text2 + ((((Character)player).InGodMode() || ((Character)player).InGhostMode()) ? ", god or ghost mode keeps 1 health" : "") + ")"; } private static void WriteLine(Entry entry, string closing, bool withPlaces) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) BlastPlan plan = entry.Plan; StringBuilder stringBuilder = new StringBuilder(640); stringBuilder.Append("[Blast] at ").Append(FxLocal.Vec(plan.Center)).Append(" R=") .Append(FxLocal.Num(plan.Radius)) .Append(" c=") .Append(FxLocal.Num(plan.ShockSpeed, 0)) .Append(" id=") .Append(plan.Id.ToString("X")) .Append(entry.Console ? " from the console" : " from a rocket") .Append(" (") .Append(PartsName(plan.Parts)) .Append(')'); if (entry.Late > 0.05f) { stringBuilder.Append(", begun ").Append(FxLocal.Num(entry.Late, 2)).Append(" s late"); } stringBuilder.Append(": looks ").Append(entry.LooksNote); if (entry.Warnings > 0) { stringBuilder.Append("; warned the player ").Append(entry.Warnings).Append(" time(s) in flight that they stood inside the blast radius"); } stringBuilder.Append("; player ").Append(entry.PlayerPending ? "not reached yet" : entry.PlayerNote); stringBuilder.Append("; world ").Append(WorldText(entry, withPlaces)); stringBuilder.Append("; fps ").Append(FxLocal.Num(entry.FpsBefore, 0)).Append(" before, ") .Append((entry.WorstFrame > 0f) ? FxLocal.Num(1f / entry.WorstFrame, 0) : "?") .Append(" lowest, ") .Append((entry.AfterFrames > 0 && entry.AfterSeconds > 0f) ? FxLocal.Num((float)entry.AfterFrames / entry.AfterSeconds, 0) : "?") .Append(" after"); if (closing != null) { stringBuilder.Append("; ended early: ").Append(closing); } Info(s_lastLine = stringBuilder.ToString()); } private static string WorldText(Entry entry, bool withPlaces) { if (!entry.WorldRan) { return (entry.WorldNote ?? "not begun") + (entry.Far ? ("; far zones: " + entry.FarNote) : ""); } StringBuilder stringBuilder = new StringBuilder(256); stringBuilder.Append("changed by this peer (").Append(entry.OwnWhy).Append("): ") .Append(entry.CraterCheck); if (entry.CraterDig.Length > 0) { stringBuilder.Append("; ").Append(entry.CraterDig); } else if (entry.Ticket != null) { stringBuilder.Append(entry.Closed ? "; never dug (the blast ended first)" : "; it is dug when the sweep has cleared the middle"); } stringBuilder.Append("; sweep ").Append(entry.SweepNote); if (entry.InnerClearedAfter >= 0f) { stringBuilder.Append(", middle cleared after ").Append(FxLocal.Num(entry.InnerClearedAfter, 2)).Append(" s"); } if (entry.SweepGivenUp != null) { stringBuilder.Append(", ").Append(entry.SweepGivenUp); } else if (entry.SweepOverAfter >= 0f) { stringBuilder.Append(", over after ").Append(FxLocal.Num(entry.SweepOverAfter, 2)).Append(" s"); } else if (entry.WorldActive) { stringBuilder.Append(", still running"); } if (entry.WarmFrames > 0) { stringBuilder.Append("; read ahead over ").Append(entry.WarmFrames).Append(" frame(s)") .Append(entry.WarmFailed ? " and then given up" : ((entry.CraterWarm && entry.SweepWarm) ? ", all of it" : ", not all of it")); } if (entry.Far) { stringBuilder.Append("; far zones: ").Append(entry.FarNote); if (entry.AreaReadyAfter > 0f) { stringBuilder.Append(", area ready ").Append(FxLocal.Num(entry.AreaReadyAfter, 2)).Append(" s after the flash"); } } if (withPlaces) { stringBuilder.Append("; protected places in reach: ").Append(ProtectedPlaces(entry.Plan)); } if (entry.PlacesRemoved != null && entry.PlacesRemoved != "none") { stringBuilder.Append("; places removed whole: ").Append(entry.PlacesRemoved); } if (!string.IsNullOrEmpty(entry.RecordsNote)) { stringBuilder.Append("; ").Append(entry.RecordsNote); } if (entry.WorldNote != null) { stringBuilder.Append(entry.WorldNote); } return stringBuilder.ToString(); } private static bool InReach(Vector3 point, BlastPlan plan, float radius) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: 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) //IL_000c: 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_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) Vector3 val = point - plan.Center; if (Mathf.Abs(val.y) > 1.5f * plan.Radius || Character.InInterior(point) != Character.InInterior(plan.Center)) { return false; } val.y = 0f; return ((Vector3)(ref val)).sqrMagnitude < radius * radius; } private static Vector3 Flat(Vector3 direction) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) direction.y = 0f; float magnitude = ((Vector3)(ref direction)).magnitude; if (!(magnitude > 0.01f)) { return Vector3.zero; } return direction / magnitude; } private static float ShockSpeedNow() { float num = Value(Settings.ShockSpeed, 30f); if (!(num >= 1f)) { return 30f; } return num; } private static float Value(ConfigEntry<float> entry, float fallback) { if (entry == null) { return fallback; } float value = entry.Value; if (!FxLocal.IsFinite(value)) { return fallback; } return value; } private static string BandName(BlastBand band) { return band switch { BlastBand.Vaporise => "inside the fireball", BlastBand.Damage => "inside the blast radius", BlastBand.Push => "in the push band", _ => "outside the blast", }; } internal static string PartsName(BlastParts parts) { parts &= BlastParts.All; switch (parts) { case BlastParts.All: return "all parts"; case BlastParts.None: return "no part"; default: { string text = ""; if ((parts & BlastParts.Looks) != BlastParts.None) { text = "looks"; } if ((parts & BlastParts.Sweep) != BlastParts.None) { text = text + ((text.Length > 0) ? " + " : "") + "sweep"; } if ((parts & BlastParts.Crater) != BlastParts.None) { text = text + ((text.Length > 0) ? " + " : "") + "crater"; } return text + " only"; } } } private static string Labelled(string state, string note) { if (string.IsNullOrEmpty(note)) { return state; } if (!note.StartsWith(state, StringComparison.OrdinalIgnoreCase)) { return state + " [" + note + "]"; } return note; } private static void Tell(string text) { try { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer != (Object)null) { ((Character)localPlayer).Message((MessageType)2, text, 0, (Sprite)null, false); } } catch (Exception ex) { Warn("[Blast] could not show the message \"" + text + "\": " + ex.Message); } } private static bool IsFinite(double value) { if (!double.IsNaN(value)) { return !double.IsInfinity(value); } return false; } private static string Text(FormattableString text) { return FormattableString.Invariant(text); } private static void Info(string line) { ManualLogSource log = WeaponsOfMassDestructionPlugin.Log; if (log != null) { log.LogInfo((object)line); } } private static void Warn(string line) { ManualLogSource log = WeaponsOfMassDestructionPlugin.Log; if (log != null) { log.LogWarning((object)line); } } private static void Error(string line) { ManualLogSource log = WeaponsOfMassDestructionPlugin.Log; if (log != null) { log.LogError((object)line); } } } public sealed class BlastRunner : MonoBehaviour { private void Update() { Blast.Tick(this); } private void OnDestroy() { Blast.RunnerGone(this); } } internal struct BlastTarget { public ZNetView View; public ZDOID Uid; public PrefabInfo Info; public BlastBand Band; public float Distance; public float Arrival; public bool WouldFall; public bool Burns; } internal sealed class BlastScanResult { public const int Kinds = 11; public const int Bands = 4; public const int Reasons = 9; public Vector3 Center; public float Radius; public float Speed; public BlastSettings Settings; public readonly List<BlastTarget> Targets = new List<BlastTarget>(1024); public readonly HashSet<ZDOID> Seen = new HashSet<ZDOID>(); public readonly List<Ward> Wards = new List<Ward>(); public readonly List<ProtectedDisc> Sacred = new List<ProtectedDisc>(); public readonly int[,] Counts = new int[11, 4]; public readonly int[] Spared = new int[9]; public readonly Dictionary<string, int> NeverNames = new Dictionary<string, int>(); public int Scanned; public int NoOwner; public int BeyondActiveArea; public int SparedBuiltBeyond; public double Milliseconds; public double AheadMs; public int AheadCalls; public int ReadLate; public bool FromTable; public int FallenTreeBudget; public int TreesThatWouldFall; public int TreesToBurn; public bool SparesBuilt => Spared[1] + Spared[2] + Spared[3] + Spared[4] + Spared[6] + SparedBuiltBeyond > 0; public int SparedTotal { get { int num = 0; for (int i = 1; i < 9; i++) { num += Spared[i]; } return num; } } public int CountOf(BlastKind kind) { return Counts[(uint)kind, 3] + Counts[(uint)kind, 2] + Counts[(uint)kind, 1]; } public int CountIn(BlastBand band) { int num = 0; for (int i = 0; i < 11; i++) { num += Counts[i, (int)band]; } return num; } } internal sealed class BlastScanJob { private const int Places = 0; private const int Listing = 1; private const int Reading = 2; private const int Resting = 3; private const int LookingAgain = 4; private const int ReadingNew = 5; private const int Ending = 6; private const int Finished = 7; private const int Chunk = 48; private const float AheadSeconds = 60f; private const float LookAgainEvery = 0.5f; private const int MostRestarts = 2; public readonly BlastScanResult Result; private static readonly List<ProtectedDisc> s_sacredNow = new List<ProtectedDisc>(); private static readonly List<Ward> s_wardsNow = new List<Ward>(); private readonly ZNetScene m_scene; private readonly List<ZNetView> m_views = new List<ZNetView>(); private readonly Vector3 m_center; private readonly float m_radius; private readonly float m_reach; private readonly float m_reachSqr; private readonly float m_vertical; private readonly float m_born; private readonly int m_fallenTrees; private readonly bool m_wardsCount; private BlastSettings m_settings; private int m_phase; private int m_next; private int m_wardStamp; private int m_locationStamp; private int m_listedIn = -1; private int m_restarts; private bool m_closing; private bool m_late; private bool m_lookedAtClose; private float m_speed; private float m_restedAt; public bool Done => m_phase == 7; public bool Rested => m_phase == 3; public bool Stale { get { if (!(Time.realtimeSinceStartup - m_born > 60f)) { return Time.realtimeSinceStartup < m_born; } return true; } } public string Progress { get { switch (m_phase) { case 0: return "it had not begun to read"; case 1: return "it had collected the protected places"; case 2: case 5: return "it had read " + m_next + " of " + m_views.Count + " objects"; case 7: return "it was made"; default: return "it had read everything there was when it was made ahead"; } } } private BlastScanJob(ZNetScene scene, Vector3 center, float radius, BlastSettings settings, int fallenTrees) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0093: 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) m_scene = scene; m_center = center; m_radius = radius; m_settings = settings; m_fallenTrees = fallenTrees; m_born = Time.realtimeSinceStartup; m_reach = BlastRules.PushRadius(radius) + 8f; m_reachSqr = m_reach * m_reach; m_vertical = 1.5f * radius; m_wardsCount = Protection.WardsCount(settings.Structures); Result = new BlastScanResult { Center = center, Radius = radius, Settings = settings, FallenTreeBudget = fallenTrees }; } public static BlastScanJob Begin(Vector3 center, float radius, BlastSettings settings, int fallenTrees, out string problem) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) ZNetScene instance = ZNetScene.instance; if ((Object)(object)instance == (Object)null || (Object)(object)ZNet.instance == (Object)null || ZDOMan.instance == null) { problem = "no world is loaded"; return null; } if (!IsNumber(center.x) || !IsNumber(center.y) || !IsNumber(center.z) || !(radius > 0f) || float.IsInfinity(radius)) { problem = "the place or the radius is not a usable number"; return null; } if (center.y > 3000f) { problem = "ground zero is inside a dungeon"; return null; } problem = null; return new BlastScanJob(instance, center, radius, settings, fallenTrees); } public bool IsFor(Vector3 center, float radius, ref BlastSettings settings, int fallenTrees) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) if (m_scene == ZNetScene.instance && m_center.x == center.x && m_center.y == center.y && m_center.z == center.z && m_radius == radius && m_fallenTrees == fallenTrees && m_settings.ObjectDamage == settings.ObjectDamage && m_settings.CreatureDamage == settings.CreatureDamage && m_settings.Structures == settings.Structures && m_settings.Drops == settings.Drops && m_settings.SpareTamed == settings.SpareTamed) { return m_settings.Clear == settings.Clear; } return false; } public void Close(float speed) { m_speed = speed; Result.Speed = speed; if (m_closing) { return; } m_closing = true; if (m_phase == 3) { if (m_listedIn == Time.frameCount) { m_phase = 6; return; } m_late = true; m_lookedAtClose = true; m_phase = 4; } } public bool Advance(double budgetMs) { if (m_phase == 7) { return true; } if (m_phase == 3 && !m_closing) { float realtimeSinceStartup = Time.realtimeSinceStartup; if (realtimeSinceStartup >= m_restedAt && realtimeSinceStartup - m_restedAt < 0.5f) { return true; } m_phase = 4; } long timestamp = Stopwatch.GetTimestamp(); double num; do { Step(); num = (double)(Stopwatch.GetTimestamp() - timestamp) * 1000.0 / (double)Stopwatch.Frequency; } while (m_phase != 7 && (m_phase != 3 || m_closing) && num < budgetMs); Result.Milliseconds += num; if (!m_closing) { Result.AheadMs += num; Result.AheadCalls++; } if (m_phase != 7) { if (m_phase == 3) { return !m_closing; } return false; } return true; } private void Step() { switch (m_phase) { case 0: CollectPlaces(); m_phase = 1; break; case 1: BlastScan.ForgetPrefabsOfAnotherWorld(m_scene); Result.FromTable = BlastScan.Views(m_views); m_listedIn = Time.frameCount; m_next = 0; m_phase = 2; break; case 2: case 5: { int num = Math.Min(m_views.Count, m_next + 48); while (m_next < num) { ReadOne(m_views[m_next]); m_next++; } if (m_next >= m_views.Count) { m_views.Clear(); m_next = 0; if (!m_closing) { m_phase = 3; m_restedAt = Time.realtimeSinceStartup; } else if (m_listedIn == Time.frameCount || m_lookedAtClose) { m_phase = 6; } else { m_late = true; m_lookedAtClose = true; m_phase = 4; } } break; } case 4: if ((!m_closing || m_restarts < 2) && !SamePlaces(!m_closing)) { Restart(); break; } BlastScan.Views(m_views); m_listedIn = Time.frameCount; m_next = 0; m_phase = 5; break; case 6: End(); m_phase = 7; break; case 3: break; } } private void CollectPlaces() { //IL_000d: Unknown result type (might be due to invalid IL or missing references) float num = BlastRules.PushRadius(m_radius); Protection.ProtectedDiscs(m_center, num + 8f, Result.Sacred); if (m_wardsCount) { Protection.CollectWards(Result.Wards); } m_wardStamp = GamePlaces.WardStamp(); m_locationStamp = GamePlaces.LocationStamp(); } private bool SamePlaces(bool byListsOnly) { //IL_006b: Unknown result type (might be due to invalid IL or missing references) int num = GamePlaces.WardStamp(); int num2 = GamePlaces.LocationStamp(); bool flag = num != 0 && num2 != 0 && m_wardStamp != 0 && m_locationStamp != 0; if (flag && (!m_wardsCount || num == m_wardStamp) && num2 == m_locationStamp) { return true; } if (!flag && byListsOnly) { return true; } List<ProtectedDisc> list = s_sacredNow; List<Ward> list2 = s_wardsNow; list.Clear(); list2.Clear(); try { Protection.ProtectedDiscs(m_center, m_reach, list); if (m_wardsCount) { Protection.CollectWards(list2); } if (!SameSacred(list, Result.Sacred) || !SameWardsInReach(list2, Result.Wards)) { return false; } m_wardStamp = num; m_locationStamp = num2; return true; } finally { list.Clear(); list2.Clear(); } } private static bool SameSacred(List<ProtectedDisc> now, List<ProtectedDisc> then) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) if (now.Count != then.Count) { return false; } for (int i = 0; i < now.Count; i++) { bool flag = false; for (int j = 0; j < then.Count; j++) { if (flag) { break; } flag = then[j].Center == now[i].Center && then[j].Radius == now[i].Radius; } if (!flag) { return false; } } return true; } private bool SameWardsInReach(List<Ward> now, List<Ward> then) { //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) int num = 0; int num2 = 0; for (int i = 0; i < then.Count; i++) { if (InReach(then[i])) { num2++; } } for (int j = 0; j < now.Count; j++) { if (!InReach(now[j])) { continue; } num++; bool flag = false; for (int k = 0; k < then.Count; k++) { if (flag) { break; } flag = then[k].Position == now[j].Position && then[k].Radius == now[j].Radius; } if (!flag) { return false; } } return num == num2; } private bool InReach(Ward ward) { //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 Protection.Flat(ward.Position, m_center) - ward.Radius <= m_reach; } private void Restart() { if (m_closing) { m_restarts++; } m_lookedAtClose = false; BlastScanResult result = Result; result.Targets.Clear(); result.Seen.Clear(); result.Wards.Clear(); result.Sacred.Clear(); Array.Clear(result.Counts, 0, result.Counts.Length); Array.Clear(result.Spared, 0, result.Spared.Length); result.NeverNames.Clear(); result.Scanned = 0; result.NoOwner = 0; result.BeyondActiveArea = 0; result.SparedBuiltBeyond = 0; result.ReadLate = 0; m_views.Clear(); m_late = false; m_phase = 0; } private void ReadOne(ZNetView view) { //IL_0027: 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_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_005d: 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) //IL_007d: 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_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: 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_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_018c: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Unknown result type (might be due to invalid IL or missing references) //IL_026c: Unknown result type (might be due to invalid IL or missing references) //IL_029c: Unknown result type (might be due to invalid IL or missing references) //IL_02a1: Unknown result type (might be due to invalid IL or missing references) ZDO val = ((view != null) ? view.GetZDO() : null); if (val == null || !val.IsValid()) { return; } BlastScanResult result = Result; if (!result.Seen.Add(val.m_uid)) { return; } result.Scanned++; Vector3 center = m_center; Vector3 position = val.GetPosition(); if (position.y > 3000f || Mathf.Abs(position.y - center.y) > m_vertical + 8f || Protection.FlatSqr(position, center) > m_reachSqr) { return; } int prefab = val.GetPrefab(); if (prefab == 0) { return; } PrefabInfo prefabInfo = BlastScan.Info(prefab, view); if (prefabInfo.Kind == BlastKind.None || !Object.op_Implicit((Object)(object)view) || !view.IsValid()) { return; } if (m_late) { result.ReadLate++; } Vector3 position2 = ((Component)view).transform.position; if (position2.y > 3000f || Mathf.Abs(position2.y - center.y) > m_vertical) { return; } float radius = m_radius; float distance = Protection.Flat(position2, center); BlastBand blastBand = BlastRules.BandAt(radius, distance, m_settings.Clear); bool flag = BlastScan.Concerns(prefabInfo.Kind, blastBand); bool flag2 = blastBand == BlastBand.Push && (prefabInfo.Kind == BlastKind.Piece || (prefabInfo.HasPiece && prefabInfo.Kind != BlastKind.Item)); if (!flag && !flag2) { return; } bool inWard = m_wardsCount && Protection.InsideWard(result.Wards, position2); bool inSacred = Protection.InsideDisc(result.Sacred, position2); SpareReason spareReason = Protection.Judge(prefabInfo, view, inWard, inSacred, ref m_settings); if (!flag) { if (spareReason != SpareReason.None) { result.SparedBuiltBeyond++; } return; } if (spareReason != SpareReason.None) { if (spareReason == SpareReason.Never) { if (prefabInfo.Never == "player") { return; } string key = prefabInfo.Never ?? prefabInfo.Name; result.NeverNames.TryGetValue(key, out var value); result.NeverNames[key] = value + 1; } result.Spared[(uint)spareReason]++; return; } result.Counts[(uint)prefabInfo.Kind, (int)blastBand]++; if (!val.HasOwner()) { result.NoOwner++; } if (m_scene.OutsideActiveArea(position2)) { result.BeyondActiveArea++; } result.Targets.Add(new BlastTarget { View = view, Uid = val.m_uid, Info = prefabInfo, Band = blastBand, Distance = distance, WouldFall = (prefabInfo.Kind == BlastKind.Tree && blastBand == BlastBand.Damage && Recipes.TreeWouldFall(view, val, radius, distance, m_settings.ObjectDamage)) }); } private void End() { BlastScanResult result = Result; List<BlastTarget> targets = result.Targets; targets.Sort(BlastScan.NearestFirst); int num = 0; for (int i = 0; i < targets.Count; i++) { if (targets[i].WouldFall) { num++; } } int num2 = 0; for (int j = 0; j < targets.Count; j++) { BlastTarget value = targets[j]; value.Arrival = ((value.Band == BlastBand.Vaporise) ? 0f : ShockFront.Arrival(value.Distance, m_radius, m_speed)); if (value.WouldFall) { value.Burns = !BlastRules.TreeFalls(num2++, num, m_fallenTrees); } targets[j] = value; } result.TreesThatWouldFall = num; result.TreesToBurn = BlastRules.TreesBurnt(num, m_fallenTrees); } private static bool IsNumber(float value) { if (!float.IsNaN(value)) { return !float.IsInfinity(value); } return false; } } public static class BlastScan { internal const float InteriorHeight = 3000f; internal const float ReachMargin = 8f; internal const float VerticalFactor = 1.5f; private static readonly Dictionary<int, PrefabInfo> s_prefabs = new Dictionary<int, PrefabInfo>(); private static ZNetScene s_prefabsOf; private static FieldInfo s_instancesField; private static bool s_bindTried; internal static readonly Comparison<BlastTarget> NearestFirst = (BlastTarget a, BlastTarget b) => a.Distance.CompareTo(b.Distance); public static string Describe(Vector3 center, float blastRadius) { //IL_003c: Unknown result type (might be due to invalid IL or missing references) try { if (!(blastRadius > 0f) || float.IsInfinity(blastRadius)) { return "Scan: the blast radius is not a usable number."; } BlastSettings settings = BlastSettings.Read(blastRadius); float speed = ((Settings.ShockSpeed != null) ? Settings.ShockSpeed.Value : 30f); string problem; BlastScanResult blastScanResult = Scan(center, blastRadius, speed, ref settings, out problem); if (blastScanResult == null) { return "Scan: " + problem + "."; } return Describe(blastScanResult); } catch (Exception ex) { WeaponsOfMassDestructionPlugin.Log.LogError((object)("[Blast] the scan failed: " + ex)); return "Scan failed: " + ex.GetType().Name + ": " + ex.Message + " (the log has the details)."; } } internal static BlastScanResult Scan(Vector3 center, float radius, float speed, ref BlastSettings settings, out string problem) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) BlastScanJob blastScanJob = BlastScanJob.Begin(center, radius, settings, FallenTreesNow(), out problem); if (blastScanJob == null) { return null; } blastScanJob.Close(speed); while (!blastScanJob.Advance(double.MaxValue)) { } return blastScanJob.Result; } internal static int FallenTreesNow() { return BlastRules.FallenTreeBudget((Settings.FallenTrees != null) ? Settings.FallenTrees.Value : 0f); } internal static bool Snapshot(List<KeyValuePair<ZDO, ZNetView>> into) { into.Clear(); ZNetScene instance = ZNetScene.instance; if ((Object)(object)instance == (Object)null) { return false; } Dictionary<ZDO, ZNetView> dictionary = Table(instance); if (dictionary != null) { foreach (KeyValuePair<ZDO, ZNetView> item in dictionary) { into.Add(item); } return true; } ZNetView[] array = Object.FindObjectsByType<ZNetView>((FindObjectsSortMode)0); foreach (ZNetView val in array) { ZDO val2 = (((Object)(object)val != (Object)null) ? val.GetZDO() : null); if (val2 != null) { into.Add(new KeyValuePair<ZDO, ZNetView>(val2, val)); } } return false; } internal static bool Views(List<ZNetView> into) { into.Clear(); ZNetScene instance = ZNetScene.instance; if ((Object)(object)instance == (Object)null) { return false; } Dictionary<ZDO, ZNetView> dictionary = Table(instance); if (dictionary != null) { foreach (KeyValuePair<ZDO, ZNetView> item in dictionary) { into.Add(item.Value); } return true; } into.AddRange(Object.FindObjectsByType<ZNetView>((FindObjectsSortMode)0)); return false; } internal static PrefabInfo Info(int prefab, ZNetView view) { if (s_prefabs.TryGetValue(prefab, out var value)) { return value; } if (!Object.op_Implicit((Object)(object)view)) { return PrefabInfo.Unlisted; } value = Protection.Classify(((Component)view).gameObject); s_prefabs[prefab] = value; return value; } internal static void ForgetPrefabsOfAnotherWorld(ZNetScene scene) { if (scene != s_prefabsOf) { s_prefabsOf = scene; s_prefabs.Clear(); } } internal static bool Concerns(BlastKind kind, BlastBand band) { switch (band) { case BlastBand.Vaporise: return true; case BlastBand.Damage: return kind != BlastKind.Pickable; case BlastBand.Push: if (kind != BlastKind.Creature && kind != BlastKind.Item && kind != BlastKind.Log) { return kind == BlastKind.Ragdoll; } return true; default: return false; } } private static Dictionary<ZDO, ZNetView> Table(ZNetScene scene) { if (!s_bindTried) { s_bindTried = true; string text = null; try { FieldInfo field = typeof(ZNetScene).GetField("m_instances", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field == null) { text = "the game's ZNetScene.m_instances was not found"; } else if (!typeof(Dictionary<ZDO, ZNetView>).IsAssignableFrom(field.FieldType)) { text = "the game's ZNetScene.m_instances is now a " + field.FieldType.Name; } else { s_instancesField = field; } } catch (Exception ex) { text = "the game's ZNetScene.m_instances could not be reached (" + ex.GetType().Name + ": " + ex.Message + ")"; } if (text != null) { WeaponsOfMassDestructionPlugin.Log.LogWarning((object)("[Blast] " + text + ": the blast finds its targets by asking for every network view in the scene instead (slower, same result).")); } } if (s_instancesField == null) { return null; } try { return s_instancesField.GetValue(scene) as Dictionary<ZDO, ZNetView>; } catch (Exception) { return null; } } private static string Describe(BlastScanResult scan) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_08b5: Unknown result type (might be due to invalid IL or missing references) //IL_08bb: Unknown result type (might be due to invalid IL or missing references) //IL_097b: Unknown result type (might be due to invalid IL or missing references) //IL_0981: Unknown result type (might be due to invalid IL or missing references) Recipes recipes = new Recipes(scan.Center, scan.Radius, scan.Settings); int[,,] tally = new int[4, 11, 14]; int num = 0; int num2 = 0; for (int i = 0; i < scan.Targets.Count; i++) { BlastTarget target = scan.Targets[i]; BlastDecision blastDecision; try { blastDecision = recipes.Decide(ref target); } catch (Exception) { blastDecision = new BlastDecision { Act = BlastAct.Nothing, Band = target.Band }; } if (blastDecision.Act == BlastAct.InUse) { num++; continue; } if (blastDecision.Burnt) { num2++; } tally[(int)((blastDecision.Band == BlastBand.None) ? target.Band : blastDecision.Band), (uint)target.Info.Kind, (uint)blastDecision.Act]++; } CultureInfo invariantCulture = CultureInfo.InvariantCulture; StringBuilder stringBuilder = new StringBuilder(1200); float radius = scan.Radius; float num3 = BlastRules.VaporiseRadius(radius); stringBuilder.AppendFormat(invariantCulture, "Scan at ({0:0}, {1:0}, {2:0}), blast radius {3:0.#} m: fireball to {4:0.#} m{9}, damage to {3:0.#} m, push to {5:0.#} m. Read {6} loaded objects in {7:0.0} ms{8}.", scan.Center.x, scan.Center.y, scan.Center.z, radius, num3, BlastRules.PushRadius(radius), scan.Scanned, scan.Milliseconds, scan.FromTable ? "" : " (the slow way: the game's object table was not reachable)", (scan.Settings.Clear > num3) ? string.Format(invariantCulture, " (everything goes whole out to {0:0.#} m: the ground the crater moves)", scan.Settings.Clear) : ""); stringBuilder.Append("\nFireball, removed: "); stringBuilder.Append(Count(Sum(BlastBand.Vaporise, BlastKind.Tree, new BlastAct[1] { BlastAct.Remove }), "tree")).Append(", "); stringBuilder.Append(Count(Sum(BlastBand.Vaporise, BlastKind.Log, new BlastAct[1] { BlastAct.Remove }), "log")).Append(", "); stringBuilder.Append(Count(Sum(BlastBand.Vaporise, BlastKind.Small, new BlastAct[2] { BlastAct.Remove, BlastAct.Spill }), "small thing")).Append(", "); stringBuilder.Append(Count(Sum(BlastBand.Vaporise, BlastKind.Rock, new BlastAct[1] { BlastAct.Remove }), "rock")).Append(", "); stringBuilder.Append(Count(Sum(BlastBand.Vaporise, BlastKind.Pickable, new BlastAct[1] { BlastAct.Remove }), "pickable")).Append(", "); stringBuilder.Append(Count(Sum(BlastBand.Vaporise, BlastKind.Piece, new BlastAct[1] { BlastAct.RemovePiece }), "building piece")).Append("; "); stringBuilder.Append(Count(Sum(BlastBand.Vaporise, BlastKind.Creature, new BlastAct[2] { BlastAct.Hit, BlastAct.Push }), "creature")).Append(" hit, "); stringBuilder.Append(Count(Loose(BlastBand.Vaporise), "loose thing")).Append(" thrown."); stringBuilder.Append("\nDamage band: "); stringBuilder.Append(Count(Sum(BlastBand.Damage, BlastKind.Tree, new BlastAct[4] { BlastAct.Fell, BlastAct.Remove, BlastAct.Weaken, BlastAct.Nothing }), "tree")); stringBuilder.AppendFormat(invariantCulture, " ({0} fall and leave their logs, {1} burn away, {2} weakened; FallenTrees {3}), ", Sum(BlastBand.Damage, BlastKind.Tree, new BlastAct[1] { BlastAct.Fell }), num2, Sum(BlastBand.Damage, BlastKind.Tree, new BlastAct[1] { BlastAct.Weaken }), scan.FallenTreeBudget); stringBuilder.Append(Count(Sum(BlastBand.Damage, BlastKind.Small, new BlastAct[4] { BlastAct.Break, BlastAct.Weaken, BlastAct.Nothing, BlastAct.LeaveRock }), "small thing")); stringBuilder.AppendFormat(invariantCulture, " ({0} break, {1} weakened), ", Sum(BlastBand.Damage, BlastKind.Small, new BlastAct[1] { BlastAct.Break }), Sum(BlastBand.Damage, BlastKind.Small, new BlastAct[1] { BlastAct.Weaken })); stringBuilder.Append(Count(Sum(BlastBand.Damage, BlastKind.Rock, new BlastAct[3] { BlastAct.Remove, BlastAct.LeaveRock, BlastAct.Nothing }), "rock")); stringBuilder.AppendFormat(invariantCulture, " ({0} burst, {1} left standing), ", Sum(BlastBand.Damage, BlastKind.Rock, new BlastAct[1] { BlastAct.Remove }), Sum(BlastBand.Damage, BlastKind.Rock, new BlastAct[2] { BlastAct.LeaveRock, BlastAct.Nothing })); stringBuilder.Append(Count(Sum(BlastBand.Damage, BlastKind.Piece, new BlastAct[3] { BlastAct.BreakPiece, BlastAct.WearPiece, BlastAct.Nothing }), "building piece")); stringBuilder.AppendFormat(invariantCulture, " ({0} break, {1} worn), ", Sum(BlastBand.Damage, BlastKind.Piece, new BlastAct[1] { BlastAct.BreakPiece }), Sum(BlastBand.Damage, BlastKind.Piece, new BlastAct[1] { BlastAct.WearPiece })); stringBuilder.Append(Count(Sum(BlastBand.Damage, BlastKind.Creature, new BlastAct[2] { BlastAct.Hit, BlastAct.Push }), "creature")).Append(" hit, "); stringBuilder.Append(Count(Loose(BlastBand.Damage), "loose thing")).Append(" thrown."); stringBuilder.Append("\nPush band: "); stringBuilder.Append(Count(Sum(BlastBand.Push, BlastKind.Creature, new BlastAct[2] { BlastAct.Push, BlastAct.Hit }), "creature")).Append(" shoved, "); stringBuilder.Append(Count(Loose(BlastBand.Push), "loose thing")).Append(" thrown."); stringBuilder.Append("\nSpared: "); stringBuilder.Append(Count(scan.Spared[1], "player-built piece")).Append(" and "); stringBuilder.Append(Count(scan.Spared[2], "world-built piece")); stringBuilder.Append(" by the StructureDamage setting (").Append(scan.Settings.Structures).Append("), "); stringBuilder.Append(Count(scan.Spared[3], "thing")).Append(" inside a ward, "); stringBuilder.Append(Count(scan.Spared[4], "thing")).Append(" at a protected place, "); stringBuilder.Append(Count(scan.Spared[5], "tamed animal")).Append(", "); stringBuilder.Append(Count(scan.Spared[6], "ward, portal or bed", "wards, portals and beds")).Append(", "); stringBuilder.Append(Count(num, "piece")).Append(" in use, "); stringBuilder.Append(scan.Spared[8].ToString(invariantCulture)).Append(" never touched"); if (scan.NeverNames.Count > 0) { stringBuilder.Append(" ("); bool flag = true; foreach (KeyValuePair<string, int> neverName in scan.NeverNames) { stringBuilder.Append(flag ? "" : ", ").Append(neverName.Value.ToString(invariantCulture)).Append(' ') .Append(neverName.Key); flag = false; } stringBuilder.Append(')'); } stringBuilder.Append('.'); stringBuilder.AppendFormat(invariantCulture, "\nOf the {0} targets {1} have no owner yet (the blast claims those) and {2} lie beyond the active area.", scan.Targets.Count, scan.NoOwner, scan.BeyondActiveArea); stringBuilder.Append("\nWards: "); if (!Protection.WardsCount(scan.Settings.Structures)) { stringBuilder.Append("do not count (StructureDamage = Everything)."); } else if (scan.Wards.Count == 0) { stringBuilder.Append("no active ward in the loaded world."); } else { float num4 = float.MaxValue; foreach (Ward ward in scan.Wards) { num4 = Mathf.Min(num4, Protection.Flat(ward.Position, scan.Center)); } stringBuilder.AppendFormat(invariantCulture, "{0} active, the nearest {1:0} m from ground zero.", scan.Wards.Count, num4); } stringBuilder.Append(" Protected places: "); if (scan.Sacred.Count == 0) { stringBuilder.Append("none in reach."); } else { for (int j = 0; j < scan.Sacred.Count; j++) { ProtectedDisc protectedDisc = scan.Sacred[j]; stringBuilder.AppendFormat(invariantCulture, "{0}{1} ({2:0} m away, {3:0} m wide)", (j == 0) ? "" : ", ", protectedDisc.Name, Protection.Flat(protectedDisc.Center, scan.Center), 2f * protectedDisc.Radius); } stringBuilder.Append('.'); } stringBuilder.AppendFormat(invariantCulture, "\nSettings: ObjectDamage {0:0}, CreatureDamage {1:0}, StructureDamage {2}, SpareTamed {3}, Drops {4}, FallenTrees {5}. The scan changed nothing.", scan.Settings.ObjectDamage, scan.Settings.CreatureDamage, scan.Settings.Structures, scan.Settings.SpareTamed ? "on" : "off", scan.Settings.Drops, scan.FallenTreeBudget); return stringBuilder.ToString(); int Loose(BlastBand band) { return Sum(band, BlastKind.Item, new BlastAct[1] { BlastAct.Throw }) + Sum(band, BlastKind.Ragdoll, new BlastAct[1] { BlastAct.Throw }) + Sum(band, BlastKind.Log, new BlastAct[1] { BlastAct.Throw }); } int Sum(BlastBand band, BlastKind kind, params BlastAct[] acts) { int num5 = 0; foreach (BlastAct blastAct in acts) { num5 += tally[(int)band, (uint)kind, (uint)blastAct]; } return num5; } } private static string Count(int number, string one, string many = null) { return number.ToString(CultureInfo.InvariantCulture) + " " + ((number == 1) ? one : (many ?? (one + "s"))); } } public sealed class BlastSweep : MonoBehaviour { private struct NewThing { public ZNetView View; public ZDOID Uid; public BlastKind Kind; } private const float NewThingMargin = 10f; private const float StoredSlack = 16f; private const int LogEffectEvery = 5; private const float GiveUpAfter = 180f; private const int NewestSlack = 16; private const int LogsATree = 4; private static readonly bool LogsKeepLandingDamage = true; private static BlastSweep s_live; private static BlastScanJob s_ahead; private static bool s_warmFailureLogged; private static readonly List<KeyValuePair<ZDO, ZNetView>> s_snapshot = new List<KeyValuePair<ZDO, ZNetView>>(4096); private BlastPlan m_plan; private Action m_innerCleared; private BlastScanJob m_job; private BlastScanResult m_scan; private Recipes m_recipes; private BlastSettings m_settings; private SweepProgress m_progress; private readonly Stopwatch m_watch = new Stopwatch(); private readonly List<NewThing> m_new = new List<NewThing>(); private double m_impact; private float m_pushRadius; private float m_seconds; private float m_awake; private bool m_over; private bool m_craterCalled; private bool m_scanAhead; private string m_leftBehind; private int m_vaporised; private int m_felled; private int m_burnt; private int m_broken; private int m_weakened; private int m_left; private int m_hit; private int m_pushed; private int m_thrown; private int m_inUse; private int m_untouched; private int m_gone; private int m_notOurs; private int m_errors; private int m_newLogs; private int m_newBodies; private int m_newItems; private int m_frames; private int m_scanFrames; private int m_satOut; private int m_framesSatOut; private double m_workMs; private double m_worstMs; private double m_scanMs; public static bool Running { get { if ((Object)(object)s_live != (Object)null) { return !s_live.m_over; } return false; } } public static string LastReport { get; private set; } public static bool Warm(BlastPlan plan, float budgetMs) { //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) try { if (Running) { return true; } if ((Object)(object)ZNet.instance == (Object)null || (Object)(object)ZNetScene.instance == (Object)null || ZDOMan.instance == null) { return true; } BlastSettings settings = BlastSettings.Read(plan.Radius); int fallenTrees = BlastScan.FallenTreesNow(); BlastScanJob blastScanJob = s_ahead; if (blastScanJob == null || !blastScanJob.IsFor(plan.Center, plan.Radius, ref settings, fallenTrees) || blastScanJob.Stale) { blastScanJob = (s_ahead = BlastScanJob.Begin(plan.Center, plan.Radius, settings, fallenTrees, out var _)); if (blastScanJob == null) { return true; } } return blastScanJob.Advance(budgetMs); } catch (Exception ex) { s_ahead = null; if (!s_warmFailureLogged) { s_warmFailureLogged = true; WeaponsOfMassDestructionPlugin.Log.LogWarning((object)("[Blast] the scan ahead failed and is made at the landing instead (said once): " + ex)); } return true; } } public static BlastSweep Run(BlastPlan plan, Action innerCleared) { //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Expected O, but got Unknown //IL_00e0: Unknown result type (might be due to invalid IL or missing references) GameObject val = null; try { if (Running) { return Refuse("another sweep is still running"); } ZNet instance = ZNet.instance; if ((Object)(object)instance == (Object)null || (Object)(object)ZNetScene.instance == (Object)null || ZDOMan.instance == null || ZRoutedRpc.instance == null) { return Refuse("no world is loaded"); } if ((Object)(object)Player.m_localPlayer == (Object)null) { return Refuse("there is no local player on this machine"); } if ((Object)(object)Game.instance == (Object)null) { return Refuse("the game is not running"); } BlastSettings settings = BlastSettings.Read(plan.Radius); int fallenTrees = BlastScan.FallenTreesNow(); BlastScanJob blastScanJob = s_ahead; s_ahead = null; bool flag = blastScanJob != null && blastScanJob.IsFor(plan.Center, plan.Radius, ref settings, fallenTrees) && !blastScanJob.Stale; if (!flag) { blastScanJob = BlastScanJob.Begin(plan.Center, plan.Radius, settings, fallenTrees, out var problem); if (blastScanJob == null) { return Refuse(problem); } } blastScanJob.Close(plan.ShockSpeed); val = new GameObject("WMD_BlastSweep"); BlastSweep blastSweep = val.AddComponent<BlastSweep>(); blastSweep.m_plan = plan; blastSweep.m_innerCleared = innerCleared; blastSweep.m_job = blastScanJob; blastSweep.m_scanAhead = flag; blastSweep.m_settings = settings; blastSweep.m_pushRadius = BlastRules.PushRadius(plan.Radius); double num = NetSeconds(instance); blastSweep.m_impact = ((plan.ImpactTime <= num) ? plan.ImpactTime : num); s_live = blastSweep; return blastSweep; } catch (Exception ex) { WeaponsOfMassDestructionPlugin.Log.LogError((object)("[Blast] sweep not started: " + ex)); if ((Object)(object)val != (Object)null) { Object.Destroy((Object)(object)val); } return null; } } private static BlastSweep Refuse(string why) { WeaponsOfMassDestructionPlugin.Log.LogWarning((object)("[Blast] sweep not started: " + why + ".")); return null; } private void Update() { if (m_over) { return; } Action action = null; try { action = Step(); } catch (Exception ex) { WeaponsOfMassDestructionPlugin.Log.LogError((object)("[Blast] the sweep failed and was stopped: " + ex)); Finish("an error in its update"); return; } if (action == null) { return; } m_craterCalled = true; try { action(); } catch (Exception ex2) { WeaponsOfMassDestructionPlugin.Log.LogError((object)("[Blast] the call that follows the emptied fireball (the crater) failed: " + ex2)); } } private void OnDestroy() { if (!m_over) { m_over