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 ValheimBattleRoyale v1.1.1
ValheimBattleRoyale.dll
Decompiled 2 weeks 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.Threading; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using TMPro; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("ValheimBattleRoyale")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("ValheimBattleRoyale")] [assembly: AssemblyCopyright("Copyright © 2026")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("75C3A508-4CBA-494A-B957-1B0C9E976E0B")] [assembly: AssemblyFileVersion("1.1.1.0")] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyVersion("1.1.1.0")] namespace ValheimBattleRoyale; [BepInPlugin("com.xtasy.ValheimBattleRoyale", "Valheim Battle Royale", "1.1.1")] public sealed class ValheimBattleRoyalePlugin : BaseUnityPlugin { internal sealed class ZonePresence { internal bool Known; internal bool Outside; internal double LastLog = double.NegativeInfinity; internal bool Observe(bool outside, bool diagnostics, double now, out bool entered) { entered = Known && Outside && !outside; bool num = !Known || Outside != outside; Known = true; Outside = outside; double num2 = ((!diagnostics) ? 30 : (outside ? 5 : 10)); if (!num && now - LastLog < num2) { return false; } LastLog = now; return true; } } private sealed class PeerDiagnostics { internal long AckRevision = -1L; internal long LastDamageSent; internal long LastDamageAck; internal double FirstUnackedAt = -1.0; internal double LastStateAckAt; internal double FirstSeenAt = LocalClock(); internal ZDOID Character; } public const string GUID = "com.xtasy.ValheimBattleRoyale"; public const string NAME = "Valheim Battle Royale"; public const string VERSION = "1.1.1"; internal static ValheimBattleRoyalePlugin Instance; internal static ManualLogSource Log; internal ConfigEntry<KeyboardShortcut> StartHotkey; internal ConfigEntry<KeyboardShortcut> PlaceZoneHotkey; internal ConfigEntry<KeyboardShortcut> CancelZoneHotkey; internal ConfigEntry<float> StartCountdown; internal ConfigEntry<float> InitialRadius; internal ConfigEntry<float> NextRadiusMultiplier; internal ConfigEntry<float> MinimumRadius; internal ConfigEntry<float> WaitBeforeShrink; internal ConfigEntry<float> ShrinkDuration; internal ConfigEntry<float> OutsideDamage; internal ConfigEntry<float> DamageInterval; internal ConfigEntry<bool> RequireNextInsideCurrent; internal ConfigEntry<bool> ShowHud; internal ConfigEntry<float> OutsideWarningTopPercent; internal ConfigEntry<float> OutsideWarningFontSize; private Harmony _harmony; private FileSystemWatcher _watcher; private int _reloadPending; private double _reloadAt = -1.0; private double _nextServerDamageAt; private double _nextVisualAt; private double _nextSyncAt; private double _nextSnapshotAt; private double _lastStateAt; private double _clockAtReceipt; private double _serverClockAtReceipt; private double _nextHudAttempt; private double _nextFontProbe; private ZNet _network; private ZRoutedRpc _registeredRouter; private long _serverPeerId; private long _revision; private long _snapshotSerial; private long _lastSnapshotSerial; private long _matchId; private long _damageSequence; private long _lastDamageSequence; private string _session; private bool _hasSnapshot; private bool _snapshotNeeded; private GameObject _hudRoot; private TextMeshProUGUI _hudTitle; private TextMeshProUGUI _hudTimer; private TextMeshProUGUI _hudDanger; private Player _pvpPlayer; private bool _pvpCaptured; private bool _previousPvp; private bool _pvpNoticeShown; private ConfigEntry<string> ExemptSteamIds; private string _exemptConfig; private readonly HashSet<string> _exemptIds = new HashSet<string>(StringComparer.Ordinal); private bool _localExempt; private string _lastHudStatus; private double _nextPresenceCheck; private readonly Dictionary<long, ZonePresence> _presence = new Dictionary<long, ZonePresence>(); private ConfigEntry<bool> DiagnosticLogging; private ConfigEntry<float> DiagnosticInterval; private readonly Dictionary<string, double> _logTimes = new Dictionary<string, double>(); private readonly Dictionary<string, double> _rpcTimes = new Dictionary<string, double>(); private readonly Dictionary<long, PeerDiagnostics> _peers = new Dictionary<long, PeerDiagnostics>(); private static TMP_FontAsset _valheimNorseBold; private static string _selectedLanguage; private static float _nextLanguageProbeAt; private static readonly FieldInfo AdminListField = AccessTools.Field(typeof(ZNet), "m_adminList"); private static readonly MethodInfo AdminContains = AccessTools.Method(typeof(ZNet), "ListContainsId", new Type[2] { typeof(SyncedList), typeof(string) }, (Type[])null); private static readonly MethodInfo CheckDeath = AccessTools.Method(typeof(Character), "CheckDeath", Type.EmptyTypes, (Type[])null); private static readonly FieldInfo LastHit = AccessTools.Field(typeof(Character), "m_lastHit"); private static readonly Type LocalizationType = Type.GetType("Localization, assembly_guiutils", throwOnError: false); private static readonly MethodInfo SelectedLanguage = ((LocalizationType == null) ? null : AccessTools.Method(LocalizationType, "GetSelectedLanguage", Type.EmptyTypes, (Type[])null)); private static readonly PropertyInfo LocalizationInstance = ((LocalizationType == null) ? null : AccessTools.Property(LocalizationType, "instance")); private const int Protocol = 111; private const string RpcRequest = "XBR111_Request"; private const string RpcState = "XBR111_State"; private const string RpcSnapshotRequest = "XBR111_SnapshotRequest"; private const string RpcStateAck = "XBR111_StateAck"; private const string RpcZoneDamage = "XBR111_ZoneDamage"; private const string RpcDamageAck = "XBR111_DamageAck"; internal bool _restoringPvp; private static StatusEffect _zoneFireVisual; private double DiagnosticSeconds => SafeNumber(DiagnosticInterval.Value, 30f, 5f, 300f); private static double LocalClock() { return Time.realtimeSinceStartupAsDouble; } internal void Diagnose(string key, string message, bool warning = false, double interval = -1.0) { bool flag = key.StartsWith("damage-tx-", StringComparison.Ordinal) || key.StartsWith("damage-rx-", StringComparison.Ordinal) || key.StartsWith("damage-ack-", StringComparison.Ordinal) || key == "damage-local"; if (flag && !warning) { interval = (DiagnosticLogging.Value ? 5 : 30); } if (!warning && !DiagnosticLogging.Value && !flag) { return; } if (interval < 0.0) { interval = (warning ? 10.0 : DiagnosticSeconds); } if (Allow(_logTimes, key, interval)) { string text = (((Object)(object)ZNet.instance == (Object)null) ? "offline" : (ZNet.instance.IsServer() ? "server" : "client")); string text2 = "[BR111 " + text + "] " + message; if (warning) { Log.LogWarning((object)text2); } else { Log.LogInfo((object)text2); } } } private static bool Allow(Dictionary<string, double> times, string key, double interval) { double num = LocalClock(); if (times.TryGetValue(key, out var value) && num < value) { return false; } if (times.Count >= 512 && !times.ContainsKey(key)) { return false; } times[key] = num + interval; return true; } internal static bool Finite(float v) { if (!float.IsNaN(v)) { return !float.IsInfinity(v); } return false; } internal static bool Finite(double v) { if (!double.IsNaN(v)) { return !double.IsInfinity(v); } return false; } internal static bool Finite(Vector3 v) { //IL_0000: 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_001a: Unknown result type (might be due to invalid IL or missing references) if (Finite(v.x) && Finite(v.y)) { return Finite(v.z); } return false; } private static float SafeNumber(float value, float fallback, float min, float max) { return Mathf.Clamp(Finite(value) ? value : fallback, min, max); } internal static bool SkipDamageForHealth(bool dead, bool hasHealth, float health) { if (!dead) { if (hasHealth) { if (Finite(health)) { return health <= 0f; } return true; } return false; } return true; } internal static bool IsBattleRoyaleMethod(int hash) { if (hash != StringExtensionMethods.GetStableHashCode("XBR111_Request") && hash != StringExtensionMethods.GetStableHashCode("XBR111_State") && hash != StringExtensionMethods.GetStableHashCode("XBR111_SnapshotRequest") && hash != StringExtensionMethods.GetStableHashCode("XBR111_StateAck") && hash != StringExtensionMethods.GetStableHashCode("XBR111_ZoneDamage")) { return hash == StringExtensionMethods.GetStableHashCode("XBR111_DamageAck"); } return true; } internal static bool AcceptIngress(bool server, bool ready, bool serverConnection, long actualPeer, long claimedPeer, long target, long local, bool globalTarget, int method) { if (!ready || actualPeer != claimedPeer || target != local || !globalTarget) { return false; } if (server) { if (method != StringExtensionMethods.GetStableHashCode("XBR111_Request") && method != StringExtensionMethods.GetStableHashCode("XBR111_SnapshotRequest") && method != StringExtensionMethods.GetStableHashCode("XBR111_StateAck")) { return method == StringExtensionMethods.GetStableHashCode("XBR111_DamageAck"); } return true; } if (serverConnection) { if (method != StringExtensionMethods.GetStableHashCode("XBR111_State")) { return method == StringExtensionMethods.GetStableHashCode("XBR111_ZoneDamage"); } return true; } return false; } internal bool ValidateIngress(ZRpc transport, ZPackage package) { //IL_0022: 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) if (package == null) { return false; } int pos = package.GetPos(); try { package.ReadLong(); long claimedPeer = package.ReadLong(); long target = package.ReadLong(); ZDOID val = package.ReadZDOID(); int num = package.ReadInt(); if (!IsBattleRoyaleMethod(num)) { return true; } ZNet instance = ZNet.instance; ZNetPeer val2 = null; if ((Object)(object)instance != (Object)null && transport != null) { foreach (ZNetPeer peer in instance.GetPeers()) { if (peer.m_rpc == transport) { val2 = peer; break; } } } int num2; if ((Object)(object)instance != (Object)null && val2 != null) { num2 = (AcceptIngress(instance.IsServer(), val2.IsReady(), !instance.IsServer() && val2 == instance.GetServerPeer(), val2.m_uid, claimedPeer, target, ZNet.GetUID(), ((ZDOID)(ref val)).IsNone(), num) ? 1 : 0); if (num2 != 0) { goto IL_0121; } } else { num2 = 0; } Diagnose("rpc-ingress-rejected", "Rejected BR RPC: transport identity, direction or target mismatch; claimed=" + claimedPeer + " method=" + num, warning: true, 10.0); goto IL_0121; IL_0121: return (byte)num2 != 0; } catch (Exception ex) { Diagnose("rpc-header-invalid", "Rejected malformed routed RPC header: " + ex.GetType().Name, warning: true, 10.0); return false; } finally { package.SetPos(pos); } } private bool IsServerSender(long sender) { if ((Object)(object)ZNet.instance == (Object)null) { return false; } if (ZNet.instance.IsServer()) { return sender == ZNet.GetUID(); } ZNetPeer serverPeer = ZNet.instance.GetServerPeer(); if (serverPeer != null && serverPeer.IsReady()) { return sender == serverPeer.m_uid; } return false; } private bool IsConnectedPeer(long sender) { ZNetPeer val = (((Object)(object)ZNet.instance == (Object)null) ? null : ZNet.instance.GetPeer(sender)); if (val != null) { return val.IsReady(); } return false; } private void Awake() { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Expected O, but got Unknown Instance = this; Log = ((BaseUnityPlugin)this).Logger; BindConfig(); SetupConfigWatcher(); _harmony = new Harmony("com.xtasy.ValheimBattleRoyale"); _harmony.PatchAll(); Log.LogInfo((object)"Valheim Battle Royale 1.1.1 loaded."); } private void OnDestroy() { if ((Object)(object)_hudRoot != (Object)null) { Object.Destroy((Object)(object)_hudRoot); _hudRoot = null; } RestorePvp(discardIfUnavailable: true); MinimapUpdatePatch.Cleanup(); if ((Object)(object)_zoneFireVisual != (Object)null) { Object.Destroy((Object)(object)_zoneFireVisual); } _zoneFireVisual = null; if (_watcher != null) { _watcher.Dispose(); _watcher = null; } if (_harmony != null) { _harmony.UnpatchSelf(); } Instance = null; } private void BindConfig() { //IL_001b: 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) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_025d: Unknown result type (might be due to invalid IL or missing references) //IL_0267: Expected O, but got Unknown //IL_029b: Unknown result type (might be due to invalid IL or missing references) //IL_02a5: Expected O, but got Unknown StartHotkey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Controls", "StartHotkey", new KeyboardShortcut((KeyCode)288, Array.Empty<KeyCode>()), "Start/stop match request from an admin client."); PlaceZoneHotkey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Controls", "PlaceZoneHotkey", new KeyboardShortcut((KeyCode)323, (KeyCode[])(object)new KeyCode[1] { (KeyCode)304 }), "Place or move a zone on the large map. Mouse0 = left mouse button; Mouse1 = right mouse button; Mouse2 = middle mouse button (wheel click). Example: LeftShift + Mouse0."); CancelZoneHotkey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Controls", "CancelZoneHotkey", new KeyboardShortcut((KeyCode)323, (KeyCode[])(object)new KeyCode[1] { (KeyCode)306 }), "Cancel the next/current zone on the large map. Mouse0 = left mouse button; Mouse1 = right mouse button; Mouse2 = middle mouse button (wheel click). Example: LeftControl + Mouse0."); StartCountdown = ((BaseUnityPlugin)this).Config.Bind<float>("Match", "StartCountdown", 10f, "Seconds between admin start and actual match start. Damage is disabled during this countdown."); InitialRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Zone", "InitialRadius", 3000f, "Initial safe-zone radius used by Shift+LeftClick / br zone when radius is omitted."); NextRadiusMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Zone", "NextRadiusMultiplier", 0.5f, "Next-zone radius as a multiplier of the current radius. 0.5 = 50%. Used when an explicit radius is not supplied."); MinimumRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Zone", "MinimumRadius", 25f, "Minimum automatically calculated next-zone radius."); WaitBeforeShrink = ((BaseUnityPlugin)this).Config.Bind<float>("Zone", "WaitBeforeShrink", 300f, "Seconds from assigning the next safe zone until shrinking starts."); ShrinkDuration = ((BaseUnityPlugin)this).Config.Bind<float>("Zone", "ShrinkDuration", 180f, "Seconds used to move/shrink from current zone to next zone."); RequireNextInsideCurrent = ((BaseUnityPlugin)this).Config.Bind<bool>("Zone", "RequireNextZoneInsideCurrent", true, "Reject a next circle that is not fully inside the current circle."); OutsideDamage = ((BaseUnityPlugin)this).Config.Bind<float>("Damage", "OutsideDamage", 10f, "Direct health removed per tick outside the current safe zone. Bypasses armor, blocking and elemental resistances."); DamageInterval = ((BaseUnityPlugin)this).Config.Bind<float>("Damage", "DamageInterval", 2f, "Seconds between damage ticks."); ExemptSteamIds = ((BaseUnityPlugin)this).Config.Bind<string>("Administration", "ExemptSteamIds", "", "Server-only comma-separated SteamID64 list. Listed players are exempt from zone damage, forced PvP and personal zone effects. Does not grant admin permissions."); ShowHud = ((BaseUnityPlugin)this).Config.Bind<bool>("UI", "ShowHud", true, "Show match/zone/timer information on screen."); OutsideWarningTopPercent = ((BaseUnityPlugin)this).Config.Bind<float>("UI", "OutsideWarningTopPercent", 20f, new ConfigDescription("Outside-zone warning center measured from the top as a percentage of screen height (0-100). Clamped to keep the text on screen. Client-local setting.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), Array.Empty<object>())); OutsideWarningFontSize = ((BaseUnityPlugin)this).Config.Bind<float>("UI", "OutsideWarningFontSize", 25f, new ConfigDescription("Outside-zone warning font size (12-100). Client-local setting.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(12f, 100f), Array.Empty<object>())); DiagnosticLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("Diagnostics", "Enabled", true, "Log RPC, zone, HUD and damage summaries. Warnings remain enabled."); DiagnosticInterval = ((BaseUnityPlugin)this).Config.Bind<float>("Diagnostics", "SummaryInterval", 30f, "Seconds between repeated diagnostic summaries (5..300). Warnings are limited separately."); } private void SetupConfigWatcher() { try { string configFilePath = ((BaseUnityPlugin)this).Config.ConfigFilePath; _watcher = new FileSystemWatcher(Path.GetDirectoryName(configFilePath) ?? Paths.ConfigPath, Path.GetFileName(configFilePath)); _watcher.NotifyFilter = NotifyFilters.Size | NotifyFilters.LastWrite | NotifyFilters.CreationTime; _watcher.Changed += delegate { Interlocked.Exchange(ref _reloadPending, 1); }; _watcher.Created += delegate { Interlocked.Exchange(ref _reloadPending, 1); }; _watcher.Renamed += delegate { Interlocked.Exchange(ref _reloadPending, 1); }; _watcher.EnableRaisingEvents = true; } catch (Exception ex) { Log.LogWarning((object)("Config watcher unavailable: " + ex)); } } private void Update() { //IL_0173: Unknown result type (might be due to invalid IL or missing references) //IL_0178: Unknown result type (might be due to invalid IL or missing references) //IL_018a: Unknown result type (might be due to invalid IL or missing references) //IL_0190: Unknown result type (might be due to invalid IL or missing references) if (Interlocked.Exchange(ref _reloadPending, 0) != 0) { _reloadAt = LocalClock() + 0.35; } if (_reloadAt > 0.0 && LocalClock() >= _reloadAt) { _reloadAt = -1.0; try { ((BaseUnityPlugin)this).Config.Reload(); if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer()) { SyncServerSettings(); BroadcastState(); } Diagnose("config", "Configuration reloaded."); } catch (Exception ex) { Diagnose("config-error", "Config reload failed: " + ex, warning: true); } } try { MaintainNetwork(); } catch (Exception ex2) { Diagnose("network-error", "Network update failed: " + ex2, warning: true); } if ((Object)(object)ZNet.instance != (Object)null && ZRoutedRpc.instance != null) { try { if (ZNet.instance.IsServer() && (Object)(object)Player.m_localPlayer != (Object)null) { SetLocalExemption(IsExempt(ZNet.GetUID())); } UpdatePvp(); UpdateZonePresence(); if ((Object)(object)Player.m_localPlayer != (Object)null && !IsTextInputActive()) { KeyboardShortcut value = StartHotkey.Value; if (((KeyboardShortcut)(ref value)).IsDown()) { SendRequest("toggle"); } } if (ZNet.instance.IsServer()) { ApplyServerDamage(); } ApplyLocalZoneVisual(); } catch (Exception ex3) { Diagnose("gameplay-error", "Gameplay update failed: " + ex3, warning: true); } } try { UpdateTmpHud(); } catch (Exception ex4) { Diagnose("hud-error", "HUD update failed; recreation scheduled: " + ex4, warning: true); DestroyHud(); _nextHudAttempt = LocalClock() + 1.0; } } private void ResetSession(bool resetRouter = true) { RestorePvp(discardIfUnavailable: true); ZoneState.Reset(); if (resetRouter) { _registeredRouter = null; } _serverPeerId = (_revision = (_snapshotSerial = (_lastSnapshotSerial = (_matchId = 0L)))); _damageSequence = (_lastDamageSequence = 0L); _localExempt = false; _hasSnapshot = false; _snapshotNeeded = true; _session = null; _nextSyncAt = (_nextSnapshotAt = (_nextServerDamageAt = (_nextVisualAt = (_lastStateAt = 0.0)))); _peers.Clear(); _rpcTimes.Clear(); _logTimes.Clear(); _presence.Clear(); _nextPresenceCheck = 0.0; _valheimNorseBold = null; _nextFontProbe = 0.0; _lastHudStatus = null; DestroyHud(); if ((Object)(object)_zoneFireVisual != (Object)null) { Object.Destroy((Object)(object)_zoneFireVisual); } _zoneFireVisual = null; } private unsafe void MaintainNetwork() { //IL_0242: Unknown result type (might be due to invalid IL or missing references) //IL_0247: Unknown result type (might be due to invalid IL or missing references) ZNet instance = ZNet.instance; ZRoutedRpc instance2 = ZRoutedRpc.instance; if (_network != instance || (_registeredRouter != null && _registeredRouter != instance2)) { ResetSession(_registeredRouter != instance2); _network = instance; if ((Object)(object)instance != (Object)null && instance.IsServer()) { _session = Guid.NewGuid().ToString("N"); _hasSnapshot = true; SyncServerSettings(); } } if ((Object)(object)instance == (Object)null || instance2 == null) { return; } if (_registeredRouter != instance2) { instance2.Register<ZPackage>("XBR111_Request", (Action<long, ZPackage>)RPC_Request); instance2.Register<ZPackage>("XBR111_State", (Action<long, ZPackage>)RPC_State); instance2.Register("XBR111_SnapshotRequest", (Action<long>)RPC_SnapshotRequest); instance2.Register<ZPackage>("XBR111_StateAck", (Action<long, ZPackage>)RPC_StateAck); instance2.Register<ZPackage>("XBR111_ZoneDamage", (Action<long, ZPackage>)RPC_ZoneDamage); instance2.Register<ZPackage>("XBR111_DamageAck", (Action<long, ZPackage>)RPC_DamageAck); _registeredRouter = instance2; Diagnose("registered", "RPC registered; protocol=111 uid=" + ZNet.GetUID(), warning: false, 0.0); } double num = LocalClock(); if (instance.IsServer()) { if (_session == null) { _session = Guid.NewGuid().ToString("N"); _hasSnapshot = true; SyncServerSettings(); } if (num < _nextSyncAt) { return; } _nextSyncAt = num + 5.0; HashSet<long> hashSet = new HashSet<long>(); foreach (ZNetPeer peer in instance.GetPeers()) { if (peer.IsReady()) { hashSet.Add(peer.m_uid); if (!_peers.TryGetValue(peer.m_uid, out var value)) { value = new PeerDiagnostics(); _peers[peer.m_uid] = value; string key = "join-" + peer.m_uid; string text = peer.m_uid.ToString(); ZDOID characterID = peer.m_characterID; Diagnose(key, "Ready peer=" + text + " character=" + ((object)(*(ZDOID*)(&characterID))/*cast due to .constrained prefix*/).ToString(), warning: false, 0.0); } SendState(peer.m_uid); if ((value.AckRevision < 0 && num - value.FirstSeenAt > 15.0) || (value.AckRevision >= 0 && num - value.LastStateAckAt > 15.0)) { Diagnose("sync-peer-" + peer.m_uid, "No recent state ACK peer=" + peer.m_uid + "; check that both sides run 1.1.1.", warning: true, 30.0); } } } foreach (long item in new List<long>(_peers.Keys)) { if (hashSet.Contains(item)) { continue; } _peers.Remove(item); foreach (string item2 in new List<string>(_rpcTimes.Keys)) { if (item2.EndsWith("-" + item, StringComparison.Ordinal)) { _rpcTimes.Remove(item2); } } foreach (string item3 in new List<string>(_logTimes.Keys)) { if (item3.EndsWith("-" + item, StringComparison.Ordinal)) { _logTimes.Remove(item3); } } } Diagnose("server-summary", "Zone rev=" + _revision + " peers=" + hashSet.Count + " " + ZoneState.Describe()); return; } ZNetPeer serverPeer = instance.GetServerPeer(); long num2 = ((serverPeer != null && serverPeer.IsReady()) ? serverPeer.m_uid : 0); if (_serverPeerId != num2) { ResetSession(resetRouter: false); _serverPeerId = num2; return; } if (num2 == 0L) { Diagnose("waiting-server", "Waiting for ready server peer."); return; } if (num >= _nextSnapshotAt && (!_hasSnapshot || _snapshotNeeded || num - _lastStateAt > 12.0)) { _nextSnapshotAt = num + 3.0; instance2.InvokeRoutedRPC(num2, "XBR111_SnapshotRequest", Array.Empty<object>()); Diagnose("snapshot-request", "Snapshot requested from=" + num2 + " received=" + _hasSnapshot); } if (_hasSnapshot && num - _lastStateAt > 15.0) { Diagnose("stale-state", "State heartbeat stale age=" + (num - _lastStateAt).ToString("F1") + "s; requesting resync.", warning: true, 15.0); } } private void SyncServerSettings() { ZoneState.DamageAmount = SafeNumber(OutsideDamage.Value, 10f, 0f, 100000f); ZoneState.DamageTick = SafeNumber(DamageInterval.Value, 2f, 0.1f, 3600f); if (ZoneState.Phase == ZonePhase.Waiting) { ZoneState.WaitSecondsAtAssignment = SafeNumber(WaitBeforeShrink.Value, 300f, 0f, 86400f); } } internal bool ForcePvp(Player player) { if ((Object)(object)player == (Object)(object)Player.m_localPlayer && ZoneState.Running && _hasSnapshot) { return !_localExempt; } return false; } private void CapturePvp(Player player) { if (!_pvpCaptured || !((Object)(object)_pvpPlayer == (Object)(object)player)) { if (!_pvpCaptured) { _previousPvp = ((Character)player).IsPVPEnabled(); _pvpCaptured = true; _pvpNoticeShown = false; } _pvpPlayer = player; } } internal void GuardPvp(Player player, ref bool pvp) { if (ForcePvp(player) && ((Character)player).IsOwner()) { CapturePvp(player); if (!pvp) { Diagnose("pvp-block", "Prevented disabling PvP during the match."); } pvp = true; } } private void UpdatePvp() { Player localPlayer = Player.m_localPlayer; if (_pvpCaptured && (!ZoneState.Running || _localExempt)) { RestorePvp(); } if (!((Object)(object)localPlayer == (Object)null) && ((Character)localPlayer).IsOwner() && ForcePvp(localPlayer)) { CapturePvp(localPlayer); if (!((Character)localPlayer).IsPVPEnabled()) { localPlayer.SetPVP(true); Diagnose("pvp-on", "PvP enabled for local player."); } } } private void RestorePvp(bool discardIfUnavailable = false) { if (!_pvpCaptured) { return; } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || !((Character)localPlayer).IsOwner() || ((Character)localPlayer).IsDead()) { if (discardIfUnavailable) { _pvpCaptured = false; _pvpPlayer = null; } return; } _restoringPvp = true; try { if (((Character)localPlayer).IsPVPEnabled() != _previousPvp) { localPlayer.SetPVP(_previousPvp); } _pvpCaptured = false; _pvpPlayer = null; } finally { _restoringPvp = false; } } internal bool AllowPvpNotice(Character character, string message) { if (_localExempt || _restoringPvp || (Object)(object)character != (Object)(object)Player.m_localPlayer || !ZoneState.Running || !_hasSnapshot) { return true; } if (message == "$msg_pvpoff") { return false; } if (message != "$msg_pvpon") { return true; } if (_pvpNoticeShown) { Diagnose("pvp-notice", "Suppressed repeated PvP notification."); return false; } _pvpNoticeShown = true; return true; } internal static bool IsTextInputActive() { if ((Object)(object)Console.instance != (Object)null && Console.IsVisible()) { return true; } if ((Object)(object)Chat.instance != (Object)null && Chat.instance.HasFocus()) { return true; } if (!TextInput.IsVisible() && !Minimap.InTextInput() && !Menu.IsActive() && !InventoryGui.IsVisible()) { return ZInput.VirtualKeyboardOpen; } return true; } internal void SendRequest(string action, Vector3 pos = default(Vector3), float radius = 0f) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Expected O, but got Unknown //IL_004e: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)ZNet.instance == (Object)null || ZRoutedRpc.instance == null) { return; } if (!Finite(pos) || !Finite(radius)) { Diagnose("bad-request", "Invalid control coordinates/radius.", warning: true); return; } ZPackage val = new ZPackage(); val.Write(action); val.Write(pos); val.Write(radius); if (ZNet.instance.IsServer()) { val.SetPos(0); RPC_Request(ZNet.GetUID(), val); return; } ZNetPeer serverPeer = ZNet.instance.GetServerPeer(); if (serverPeer == null || !serverPeer.IsReady()) { Diagnose("request-no-server", "Control request skipped: server not ready.", warning: true); return; } Diagnose("request-send", "Control TX action=" + action + " to=" + serverPeer.m_uid, warning: false, 0.25); ZRoutedRpc.instance.InvokeRoutedRPC(serverPeer.m_uid, "XBR111_Request", new object[1] { val }); } private unsafe void RPC_Request(long sender, ZPackage pkg) { //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: 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_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0271: Unknown result type (might be due to invalid IL or missing references) //IL_0267: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer()) { return; } if (!IsAuthorized(sender)) { Diagnose("unauthorized", "Rejected non-admin control RPC sender=" + sender, warning: true); } else { if (!Allow(_rpcTimes, "control-" + sender, 0.25)) { return; } try { if (pkg == null || pkg.Size() > 256) { throw new InvalidDataException("control size"); } string text = pkg.ReadString(); Vector3 val = pkg.ReadVector3(); float num = pkg.ReadSingle(); if (!Finite(val) || !Finite(num) || Mathf.Abs(val.x) > 100000f || Mathf.Abs(val.z) > 100000f || num > 100000f) { throw new InvalidDataException("invalid coordinates/radius"); } string[] obj = new string[8] { "Control RX sender=", sender.ToString(), " action=", text, " pos=", null, null, null }; Vector3 val2 = val; obj[5] = ((object)(*(Vector3*)(&val2))/*cast due to .constrained prefix*/).ToString(); obj[6] = " radius="; obj[7] = num.ToString(); Diagnose("control", string.Concat(obj), warning: false, 0.25); switch (text) { case "toggle": if (ZoneState.Running || ZoneState.Starting) { StopMatch(); } else { StartMatch(); } break; case "start": StartMatch(); break; case "stop": StopMatch(); break; case "zone": SetCurrentZone(val, num); break; case "next": SetNextZone(val, num); break; case "cancelnext": CancelNextZone(); break; case "cancelzone": CancelAssignedZone(); break; default: Diagnose("unknown-control", "Unknown control action.", warning: true); return; } BroadcastState(); } catch (Exception ex) { Diagnose("control-error", "Control RPC failed: " + ex, warning: true); } } } private void CancelNextZone() { if (ZoneState.Phase == ZonePhase.Shrinking) { Diagnose("cancel-shrinking", "Cannot cancel during shrinking.", warning: true); return; } ZoneState.HasNext = false; ZoneState.Phase = ZonePhase.Idle; } private void StartMatch() { //IL_0077: 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) if (ZoneState.Running || ZoneState.Starting) { return; } if (!ZoneState.HasCurrent) { Log.LogWarning((object)"Cannot start: current safe zone is not set."); return; } _matchId++; _damageSequence = 0L; foreach (PeerDiagnostics value in _peers.Values) { value.LastDamageSent = (value.LastDamageAck = 0L); value.FirstUnackedAt = -1.0; value.Character = ZDOID.None; } ZoneState.Starting = true; ZoneState.MatchStartAt = ServerTime() + (double)SafeNumber(StartCountdown.Value, 10f, 0f, 86400f); SyncServerSettings(); Log.LogInfo((object)("Battle Royale countdown started; match=" + _matchId)); } private void StopMatch() { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) ZoneState.CurrentCenter = GetEffectiveCurrentCenter(); ZoneState.CurrentRadius = GetEffectiveCurrentRadius(); ZoneState.Running = (ZoneState.Starting = false); ZoneState.Phase = ZonePhase.Idle; _matchId++; RestorePvp(); Log.LogInfo((object)"Battle Royale stopped."); } internal static string NormalizeSteamId(string value) { if (value == null) { return null; } value = value.Trim(); if (value.StartsWith("Steam_", StringComparison.OrdinalIgnoreCase)) { value = value.Substring(6); } if (value.Length != 17) { return null; } string text = value; foreach (char c in text) { if (c < '0' || c > '9') { return null; } } if (!ulong.TryParse(value, NumberStyles.None, CultureInfo.InvariantCulture, out var result) || result == 0L) { return null; } return value; } private bool IsExempt(long peerId) { if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer()) { return false; } string text = ExemptSteamIds.Value ?? ""; if (text != _exemptConfig) { _exemptIds.Clear(); _exemptConfig = text; string[] array = text.Split(new char[1] { ',' }); foreach (string value in array) { string text2 = NormalizeSteamId(value); if (text2 != null) { _exemptIds.Add(text2); } else if (!string.IsNullOrWhiteSpace(value)) { Diagnose("exempt-invalid", "Ignored invalid ExemptSteamIds entry; use comma-separated SteamID64 values.", warning: true, 30.0); } } } if (_exemptIds.Count == 0) { return false; } try { string value4; if (peerId == ZNet.GetUID()) { object value2 = Type.GetType("Splatform.PlatformManager, Splatform", throwOnError: true).GetProperty("DistributionPlatform").GetValue(null, null); object value3 = Type.GetType("Splatform.IDistributionPlatform, Splatform", throwOnError: true).GetProperty("LocalUser").GetValue(value2, null); value4 = Type.GetType("Splatform.IUser, Splatform", throwOnError: true).GetProperty("PlatformUserID").GetValue(value3, null)?.ToString(); } else { ZNetPeer peer = ZNet.instance.GetPeer(peerId); object obj; if (peer == null) { obj = null; } else { ZRpc rpc = peer.m_rpc; if (rpc == null) { obj = null; } else { ISocket socket = rpc.GetSocket(); obj = ((socket != null) ? socket.GetHostName() : null); } } value4 = (string)obj; } string text3 = NormalizeSteamId(value4); return text3 != null && _exemptIds.Contains(text3); } catch (Exception ex) { Diagnose("exempt-identity", "Could not verify exemption identity: " + ex.GetType().Name, warning: true, 30.0); return false; } } private void SetLocalExemption(bool exempt) { if (_localExempt == exempt) { return; } _localExempt = exempt; Log.LogInfo((object)("[BR111] Server-authorized local exemption=" + exempt)); if (exempt) { RestorePvp(); Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer != (Object)null && ((Character)localPlayer).GetSEMan() != null) { ((Character)localPlayer).GetSEMan().RemoveStatusEffect(StringExtensionMethods.GetStableHashCode("BR_ZoneFireVisual"), false); } } } private bool IsAuthorized(long sender) { if (sender == ZNet.GetUID()) { return true; } ZNetPeer peer = ZNet.instance.GetPeer(sender); if (peer == null || !peer.IsReady() || peer.m_rpc == null || peer.m_rpc.GetSocket() == null) { return false; } try { object obj = ((AdminListField == null) ? null : AdminListField.GetValue(ZNet.instance)); if (obj == null || AdminContains == null) { return false; } return (bool)AdminContains.Invoke(ZNet.instance, new object[2] { obj, peer.m_rpc.GetSocket().GetHostName() }); } catch (Exception ex) { Diagnose("admin-api", "Admin check failed: " + ex, warning: true); return false; } } private void CancelAssignedZone() { if (ZoneState.Phase == ZonePhase.Shrinking) { Log.LogWarning((object)"Cannot cancel a zone while shrinking is in progress."); } else if (ZoneState.HasNext) { ZoneState.HasNext = false; ZoneState.Phase = ZonePhase.Idle; Log.LogInfo((object)"Next zone cancelled."); } else if (ZoneState.HasCurrent) { ZoneState.HasCurrent = false; ZoneState.HasNext = false; ZoneState.Phase = ZonePhase.Idle; ZoneState.Running = false; ZoneState.Starting = false; Log.LogInfo((object)"Current/start zone cancelled."); } } private void SetCurrentZone(Vector3 pos, float radius) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0060: 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) if (radius <= 0f) { radius = SafeNumber(InitialRadius.Value, 3000f, 1f, 100000f); } ZoneState.CurrentCenter = Flat(pos); ZoneState.CurrentRadius = Mathf.Max(1f, radius); ZoneState.HasCurrent = true; ZoneState.HasNext = false; ZoneState.Phase = ZonePhase.Idle; Log.LogInfo((object)$"Current zone: X={pos.x:F0} Z={pos.z:F0} R={radius:F0}"); } private void SetNextZone(Vector3 pos, float radius) { //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: 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_0165: Unknown result type (might be due to invalid IL or missing references) //IL_0173: Unknown result type (might be due to invalid IL or missing references) if (!ZoneState.HasCurrent) { Log.LogWarning((object)"Set current zone first."); return; } if (ZoneState.Phase == ZonePhase.Shrinking) { Log.LogWarning((object)"Cannot assign or move the next zone while shrinking is in progress."); return; } bool hasNext = ZoneState.HasNext; if (radius <= 0f) { if (hasNext) { radius = ZoneState.NextRadius; } else { float num = SafeNumber(NextRadiusMultiplier.Value, 0.5f, 0.01f, 1f); radius = Mathf.Max(SafeNumber(MinimumRadius.Value, 25f, 1f, ZoneState.CurrentRadius), ZoneState.CurrentRadius * num); } } else { radius = Mathf.Max(1f, radius); } pos = Flat(pos); if (RequireNextInsideCurrent.Value) { float num2 = DistanceXZ(ZoneState.CurrentCenter, pos); if (num2 + radius > ZoneState.CurrentRadius) { Log.LogWarning((object)$"Next zone rejected: distance {num2:F0} + radius {radius:F0} > current radius {ZoneState.CurrentRadius:F0}."); return; } } ZoneState.NextCenter = pos; ZoneState.NextRadius = radius; ZoneState.HasNext = true; ZoneState.Phase = ZonePhase.Waiting; ZoneState.PhaseStartedAt = ServerTime(); ZoneState.WaitSecondsAtAssignment = SafeNumber(WaitBeforeShrink.Value, 300f, 0f, 86400f); Log.LogInfo((object)string.Format("Next zone {0}: X={1:F0} Z={2:F0} R={3:F0}; wait={4:F0}s", hasNext ? "moved" : "assigned", pos.x, pos.z, radius, ZoneState.WaitSecondsAtAssignment)); } private void FixedUpdate() { //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer() || !ZoneState.HasCurrent) { return; } try { double num = ServerTime(); if (ZoneState.Starting && num >= ZoneState.MatchStartAt) { ZoneState.Starting = false; ZoneState.Running = true; if (ZoneState.HasNext) { ZoneState.Phase = ZonePhase.Waiting; ZoneState.PhaseStartedAt = num; ZoneState.WaitSecondsAtAssignment = SafeNumber(WaitBeforeShrink.Value, 300f, 0f, 86400f); } _nextServerDamageAt = num; Log.LogInfo((object)("Battle Royale started; match=" + _matchId)); BroadcastState(); } if (ZoneState.Running) { if (ZoneState.Phase == ZonePhase.Waiting && ZoneState.HasNext && num - ZoneState.PhaseStartedAt >= (double)ZoneState.WaitSecondsAtAssignment) { ZoneState.Phase = ZonePhase.Shrinking; ZoneState.PhaseStartedAt = num; ZoneState.ShrinkFromCenter = ZoneState.CurrentCenter; ZoneState.ShrinkFromRadius = ZoneState.CurrentRadius; ZoneState.ShrinkSeconds = SafeNumber(ShrinkDuration.Value, 180f, 0.01f, 86400f); BroadcastState(); } else if (ZoneState.Phase == ZonePhase.Shrinking && ZoneState.HasNext && num - ZoneState.PhaseStartedAt >= (double)ZoneState.ShrinkSeconds) { ZoneState.CurrentCenter = ZoneState.NextCenter; ZoneState.CurrentRadius = ZoneState.NextRadius; ZoneState.HasNext = false; ZoneState.Phase = ZonePhase.Idle; BroadcastState(); } } } catch (Exception ex) { Diagnose("phase-error", "Zone phase update failed: " + ex, warning: true); } } private void UpdateZonePresence() { //IL_017f: Unknown result type (might be due to invalid IL or missing references) //IL_01a5: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) if (!_hasSnapshot || !ZoneState.Running || ZoneState.Starting || !ZoneState.HasCurrent) { _presence.Clear(); return; } double num = LocalClock(); if (num < _nextPresenceCheck) { return; } _nextPresenceCheck = num + 0.5; HashSet<long> hashSet = new HashSet<long>(); if (ZNet.instance.IsServer() && ZDOMan.instance != null) { float health = default(float); foreach (ZNetPeer peer in ZNet.instance.GetPeers()) { if (!peer.IsReady() || IsExempt(peer.m_uid)) { continue; } ZDO val = (((ZDOID)(ref peer.m_characterID)).IsNone() ? null : ZDOMan.instance.GetZDO(peer.m_characterID)); if (val != null && val.GetOwner() == peer.m_uid && Finite(val.GetPosition())) { bool hasHealth = val.GetFloat(ZDOVars.s_health, ref health); if (!SkipDamageForHealth(val.GetBool(ZDOVars.s_dead, false), hasHealth, health)) { hashSet.Add(peer.m_uid); LogZonePresence(peer.m_uid, val.GetPosition(), num); } } } } Player localPlayer = Player.m_localPlayer; if (!_localExempt && (Object)(object)localPlayer != (Object)null && ((Character)localPlayer).IsOwner() && !((Character)localPlayer).IsDead() && Finite(((Component)localPlayer).transform.position)) { long uID = ZNet.GetUID(); if (hashSet.Add(uID)) { LogZonePresence(uID, ((Component)localPlayer).transform.position, num); } } foreach (long item in new List<long>(_presence.Keys)) { if (!hashSet.Contains(item)) { _presence.Remove(item); } } } private void LogZonePresence(long id, Vector3 position, double now) { //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) float num = DistanceXZ(position, GetEffectiveCurrentCenter()); float effectiveCurrentRadius = GetEffectiveCurrentRadius(); if (!_presence.TryGetValue(id, out var value)) { value = new ZonePresence(); _presence[id] = value; } if (value.Observe(num > effectiveCurrentRadius, DiagnosticLogging.Value, now, out var entered)) { string text = (entered ? "Player entered safe zone" : (value.Outside ? "Player outside safe zone" : "Player in safe zone")); Log.LogInfo((object)("[BR111 " + (ZNet.instance.IsServer() ? "server" : "client") + "] " + text + " peer=" + id + " distance=" + num.ToString("F1") + " radius=" + effectiveCurrentRadius.ToString("F1"))); } } private unsafe void ApplyServerDamage() { //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_0591: Unknown result type (might be due to invalid IL or missing references) //IL_0597: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_01da: Unknown result type (might be due to invalid IL or missing references) //IL_01e0: Unknown result type (might be due to invalid IL or missing references) //IL_0370: Unknown result type (might be due to invalid IL or missing references) //IL_0375: 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_039f: Expected O, but got Unknown //IL_03d2: Unknown result type (might be due to invalid IL or missing references) //IL_0452: Unknown result type (might be due to invalid IL or missing references) //IL_0457: Unknown result type (might be due to invalid IL or missing references) if (!ZoneState.Running || ZoneState.Starting || !ZoneState.HasCurrent || ZDOMan.instance == null) { return; } double num = ServerTime(); if (num < _nextServerDamageAt) { return; } _nextServerDamageAt = num + (double)ZoneState.DamageTick; if (ZoneState.DamageAmount <= 0f) { return; } long num2 = ++_damageSequence; int num3 = 0; int num4 = 0; int num5 = 0; float health = default(float); foreach (ZNetPeer peer in ZNet.instance.GetPeers()) { if (!peer.IsReady()) { continue; } try { if (IsExempt(peer.m_uid)) { continue; } ZDO val = (((ZDOID)(ref peer.m_characterID)).IsNone() ? null : ZDOMan.instance.GetZDO(peer.m_characterID)); ZDOID characterID; if (val == null || val.GetOwner() != peer.m_uid || !Finite(val.GetPosition())) { num5++; string key = "missing-zdo-" + peer.m_uid; string[] obj = new string[5] { "Damage skipped peer=", peer.m_uid.ToString(), " char=", null, null }; characterID = peer.m_characterID; obj[3] = ((object)(*(ZDOID*)(&characterID))/*cast due to .constrained prefix*/).ToString(); obj[4] = "; character ZDO/owner not ready."; Diagnose(key, string.Concat(obj), warning: true, 30.0); continue; } num3++; bool flag = val.GetFloat(ZDOVars.s_health, ref health); if (SkipDamageForHealth(val.GetBool(ZDOVars.s_dead, false), flag, health)) { continue; } if (!flag) { Diagnose("health-default-" + peer.m_uid, "Character has no explicit health; using native alive/default-health semantics peer=" + peer.m_uid, warning: false, 30.0); } float num6 = DistanceXZ(val.GetPosition(), GetEffectiveCurrentCenter()); if (num6 <= GetEffectiveCurrentRadius()) { continue; } num4++; if (!_peers.TryGetValue(peer.m_uid, out var value)) { value = new PeerDiagnostics(); _peers[peer.m_uid] = value; } if (value.AckRevision < 0) { SendState(peer.m_uid); Diagnose("damage-handshake-" + peer.m_uid, "Damage deferred peer=" + peer.m_uid + "; waiting for 1.1.1 state ACK.", LocalClock() - value.FirstSeenAt > 15.0, 30.0); continue; } if (value.AckRevision != _revision) { SendState(peer.m_uid); } if (value.FirstUnackedAt >= 0.0 && LocalClock() - value.FirstUnackedAt > 10.0) { Diagnose("damage-no-ack-" + peer.m_uid, "Damage ACK missing peer=" + peer.m_uid + " lastSent=" + value.LastDamageSent + " lastAck=" + value.LastDamageAck, warning: true, 30.0); } value.LastDamageSent = num2; value.Character = peer.m_characterID; if (value.FirstUnackedAt < 0.0) { value.FirstUnackedAt = LocalClock(); } ZPackage val2 = new ZPackage(); val2.Write(_session); val2.Write(_matchId); val2.Write(_revision); val2.Write(num2); val2.Write(peer.m_characterID); val2.Write(num); val2.Write(ZoneState.DamageAmount); ZRoutedRpc.instance.InvokeRoutedRPC(peer.m_uid, "XBR111_ZoneDamage", new object[1] { val2 }); string key2 = "damage-tx-" + peer.m_uid; string[] obj2 = new string[14] { "Damage TX peer=", peer.m_uid.ToString(), " char=", null, null, null, null, null, null, null, null, null, null, null }; characterID = peer.m_characterID; obj2[3] = ((object)(*(ZDOID*)(&characterID))/*cast due to .constrained prefix*/).ToString(); obj2[4] = " seq="; obj2[5] = num2.ToString(); obj2[6] = " rev="; obj2[7] = _revision.ToString(); obj2[8] = " distance="; obj2[9] = num6.ToString("F1"); obj2[10] = " radius="; obj2[11] = GetEffectiveCurrentRadius().ToString("F1"); obj2[12] = " amount="; obj2[13] = ZoneState.DamageAmount.ToString(); Diagnose(key2, string.Concat(obj2)); } catch (Exception ex) { Diagnose("damage-peer-" + peer.m_uid, "Peer damage failed: " + ex, warning: true); } } Player localPlayer = Player.m_localPlayer; if (!_localExempt && (Object)(object)localPlayer != (Object)null && ((Character)localPlayer).IsOwner() && !((Character)localPlayer).IsDead() && DistanceXZ(((Component)localPlayer).transform.position, GetEffectiveCurrentCenter()) > GetEffectiveCurrentRadius()) { float before; float after; string text = ApplyAuthorizedZoneDamage(localPlayer, ZoneState.DamageAmount, out before, out after); Diagnose("damage-local", "Listen-server damage=" + text + " hp=" + before + "->" + after, text != "applied"); } Diagnose("damage-summary", "Damage tick=" + num2 + " inspected=" + num3 + " outside=" + num4 + " missing=" + num5); } private void RPC_ZoneDamage(long sender, ZPackage pkg) { //IL_0069: 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_0296: Unknown result type (might be due to invalid IL or missing references) //IL_029d: Expected O, but got Unknown //IL_02b7: Unknown result type (might be due to invalid IL or missing references) //IL_0154: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Unknown result type (might be due to invalid IL or missing references) if (!IsServerSender(sender)) { Diagnose("forged-damage", "Rejected damage sender=" + sender, warning: true); return; } try { if (pkg == null || pkg.Size() > 256) { throw new InvalidDataException("damage size"); } string text = pkg.ReadString(); long num = pkg.ReadLong(); long num2 = pkg.ReadLong(); long num3 = pkg.ReadLong(); ZDOID val = pkg.ReadZDOID(); double num4 = pkg.ReadDouble(); float num5 = pkg.ReadSingle(); if (!Finite(num4) || !Finite(num5) || num5 <= 0f || num5 > 100000f || num3 <= 0) { throw new InvalidDataException("damage values"); } string text2 = null; float before = -1f; float after = -1f; Player localPlayer = Player.m_localPlayer; if (!_hasSnapshot || text != _session || num != _matchId || num2 > _revision) { text2 = "state-mismatch"; } else if (!ZoneState.Running || ZoneState.Starting || !ZoneState.HasCurrent) { text2 = "match-inactive"; } else if (num2 < _revision) { text2 = "old-revision"; } else if (num3 <= _lastDamageSequence) { text2 = "duplicate"; } else if ((Object)(object)localPlayer == (Object)null || ((Character)localPlayer).GetZDOID() != val) { text2 = "character-not-ready"; } else if (Math.Abs(ServerTime() - num4) > (double)Math.Max(10f, ZoneState.DamageTick * 3f)) { text2 = "expired"; } else { _lastDamageSequence = num3; text2 = ApplyAuthorizedZoneDamage(localPlayer, num5, out before, out after); if (text2 == "applied") { EnsureZoneFireVisual(localPlayer); } } if (text2 == "state-mismatch") { _snapshotNeeded = true; _nextSnapshotAt = 0.0; } Diagnose("damage-rx-" + text2, "Damage RX sender=" + sender + " seq=" + num3 + " rev=" + num2 + " result=" + text2 + " hp=" + before + "->" + after, text2 != "applied" && text2 != "duplicate"); ZPackage val2 = new ZPackage(); val2.Write(text); val2.Write(num); val2.Write(num3); val2.Write(val); val2.Write(text2); val2.Write(before); val2.Write(after); ZRoutedRpc.instance.InvokeRoutedRPC(sender, "XBR111_DamageAck", new object[1] { val2 }); } catch (Exception ex) { Diagnose("damage-rpc-error", "Damage RPC failed: " + ex, warning: true); } } private static string ApplyAuthorizedZoneDamage(Player player, float damage, out float before, out float after) { //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Expected O, but got Unknown //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: 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) before = (after = -1f); if ((Object)(object)Instance != (Object)null && Instance._localExempt) { return "exempt"; } if ((Object)(object)player == (Object)null || !((Character)player).IsOwner()) { return "not-owner"; } if (((Character)player).IsDead()) { return "dead"; } before = ((Character)player).GetHealth(); if (!Finite(before) || before <= 0f) { return "invalid-health"; } if (damage >= before && (CheckDeath == null || LastHit == null)) { return "death-api-unavailable"; } if (damage >= before) { HitData val = new HitData(); val.m_hitType = (HitType)0; val.m_damage.m_damage = damage; val.m_point = ((Component)player).transform.position; LastHit.SetValue(player, val); } ((Character)player).SetHealth(Mathf.Max(0f, before - damage)); after = ((Character)player).GetHealth(); if (after >= before) { return "health-unchanged"; } if (after <= 0f) { try { CheckDeath.Invoke(player, null); } catch (Exception ex) { Instance?.Diagnose("death-error", "Health reached zero but death pipeline failed: " + ex, warning: true); return "death-error"; } } return "applied"; } private void RPC_DamageAck(long sender, ZPackage pkg) { //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: 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) if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer() || !IsConnectedPeer(sender) || !Allow(_rpcTimes, "damage-ack-" + sender, 0.05)) { return; } try { if (pkg == null || pkg.Size() > 256) { throw new InvalidDataException("ack size"); } string text = pkg.ReadString(); long num = pkg.ReadLong(); long num2 = pkg.ReadLong(); ZDOID val = pkg.ReadZDOID(); string text2 = pkg.ReadString(); float v = pkg.ReadSingle(); float v2 = pkg.ReadSingle(); if (!(text != _session) && num == _matchId && _peers.TryGetValue(sender, out var value) && num2 > value.LastDamageAck && num2 <= value.LastDamageSent && !(val != value.Character)) { if (!Finite(v) || !Finite(v2) || text2.Length > 64) { throw new InvalidDataException("ack values"); } value.LastDamageAck = num2; value.FirstUnackedAt = -1.0; Diagnose("damage-ack-" + sender, "Damage ACK peer=" + sender + " seq=" + num2 + " result=" + text2 + " hp=" + v + "->" + v2, text2 != "applied" && text2 != "dead", (text2 == "applied") ? DiagnosticSeconds : 10.0); if (text2 == "state-mismatch") { SendState(sender); } } } catch (Exception ex) { Diagnose("ack-error", "Malformed damage ACK: " + ex, warning: true); } } private void ApplyLocalZoneVisual() { //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; if (!_localExempt && ZoneState.Running && !ZoneState.Starting && ZoneState.HasCurrent && !((Object)(object)localPlayer == (Object)null) && !((Character)localPlayer).IsDead() && !(LocalClock() < _nextVisualAt)) { _nextVisualAt = LocalClock() + (double)ZoneState.DamageTick; if (DistanceXZ(((Component)localPlayer).transform.position, GetEffectiveCurrentCenter()) > GetEffectiveCurrentRadius()) { EnsureZoneFireVisual(localPlayer); } } } private static void EnsureZoneFireVisual(Player player) { if ((Object)(object)player == (Object)null || ((Character)player).GetSEMan() == null || (Object)(object)ObjectDB.instance == (Object)null) { return; } try { if ((Object)(object)_zoneFireVisual == (Object)null) { StatusEffect statusEffect = ObjectDB.instance.GetStatusEffect(StringExtensionMethods.GetStableHashCode("Burning")); if ((Object)(object)statusEffect == (Object)null) { Instance.Diagnose("fire-missing", "Burning visual unavailable.", warning: true); return; } _zoneFireVisual = ScriptableObject.CreateInstance<StatusEffect>(); ((Object)_zoneFireVisual).name = "BR_ZoneFireVisual"; _zoneFireVisual.m_name = ""; _zoneFireVisual.m_tooltip = ""; _zoneFireVisual.m_ttl = Mathf.Max(0.5f, ZoneState.DamageTick + 0.35f); _zoneFireVisual.m_startEffects = statusEffect.m_startEffects; _zoneFireVisual.m_stopEffects = statusEffect.m_stopEffects; } _zoneFireVisual.m_ttl = Mathf.Max(0.5f, ZoneState.DamageTick + 0.35f); ((Character)player).GetSEMan().AddStatusEffect(_zoneFireVisual, true, 0, 0f, (short)(-1)); } catch (Exception ex) { Instance.Diagnose("fire-error", "Cosmetic zone fire failed: " + ex.Message, warning: true); } } private void RPC_SnapshotRequest(long sender) { if (!((Object)(object)ZNet.instance == (Object)null) && ZNet.instance.IsServer() && IsConnectedPeer(sender) && Allow(_rpcTimes, "snapshot-" + sender, 2.0)) { Diagnose("snapshot-rx-" + sender, "Snapshot request RX peer=" + sender); SendState(sender); } } private void BroadcastState() { _revision++; Diagnose("transition", "State transition match=" + _matchId + " rev=" + _revision + " " + ZoneState.Describe(), warning: false, 0.0); if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer()) { return; } foreach (ZNetPeer peer in ZNet.instance.GetPeers()) { if (peer.IsReady()) { SendState(peer.m_uid); } } } private void SendState(long target) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Expected O, but got Unknown if (!((Object)(object)ZNet.instance == (Object)null) && ZNet.instance.IsServer() && ZRoutedRpc.instance != null && _session != null) { ZPackage val = new ZPackage(); val.Write(111); val.Write(_session); val.Write(_matchId); val.Write(_revision); val.Write(++_snapshotSerial); val.Write(ServerTime()); val.Write(IsExempt(target)); ZoneState.Write(val); ZRoutedRpc.instance.InvokeRoutedRPC(target, "XBR111_State", new object[1] { val }); Diagnose("state-tx-" + target, "State TX target=" + target + " rev=" + _revision + " serial=" + _snapshotSerial); } } private void RPC_State(long sender, ZPackage pkg) { //IL_022d: Unknown result type (might be due to invalid IL or missing references) //IL_0234: Expected O, but got Unknown if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer()) { return; } if (!IsServerSender(sender)) { Diagnose("forged-state", "Rejected state sender=" + sender, warning: true); return; } try { if (pkg == null || pkg.Size() > 1024 || pkg.ReadInt() != 111) { throw new InvalidDataException("state protocol/size"); } string text = pkg.ReadString(); long num = pkg.ReadLong(); long num2 = pkg.ReadLong(); long num3 = pkg.ReadLong(); double num4 = pkg.ReadDouble(); if (text.Length != 32 || num < 0 || num2 < 0 || num3 <= 0 || !Finite(num4) || num4 < 0.0) { throw new InvalidDataException("state header"); } if (_hasSnapshot && text != _session) { Diagnose("state-session", "Unexpected server session; reconnect required.", warning: true); } else if (!_hasSnapshot || (num3 > _lastSnapshotSerial && num2 >= _revision && num >= _matchId)) { bool localExemption = pkg.ReadBool(); ZoneState.Read(pkg); bool flag = !_hasSnapshot || num2 != _revision; if (!_hasSnapshot || num != _matchId) { _lastDamageSequence = 0L; } SetLocalExemption(localExemption); _session = text; _matchId = num; _revision = num2; _lastSnapshotSerial = num3; _lastStateAt = (_clockAtReceipt = LocalClock()); _serverClockAtReceipt = num4; _hasSnapshot = true; _snapshotNeeded = false; Diagnose("state-rx", "State RX sender=" + sender + " rev=" + num2 + " serial=" + num3 + " " + ZoneState.Describe(), warning: false, flag ? 0.0 : DiagnosticSeconds); ZPackage val = new ZPackage(); val.Write(text); val.Write(num2); val.Write("1.1.1"); ZRoutedRpc.instance.InvokeRoutedRPC(sender, "XBR111_StateAck", new object[1] { val }); } } catch (Exception ex) { Diagnose("state-error", "State rejected without modifying current snapshot: " + ex, warning: true); _snapshotNeeded = true; _nextSnapshotAt = 0.0; } } private void RPC_StateAck(long sender, ZPackage pkg) { if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer() || !IsConnectedPeer(sender) || !Allow(_rpcTimes, "state-ack-" + sender, 0.2)) { return; } try { if (pkg == null || pkg.Size() > 128) { throw new InvalidDataException("state ack size"); } string text = pkg.ReadString(); long num = pkg.ReadLong(); string text2 = pkg.ReadString(); if (!(text != _session) && num >= 0 && num <= _revision && !(text2 != "1.1.1")) { if (!_peers.TryGetValue(sender, out var value)) { value = new PeerDiagnostics(); _peers[sender] = value; } value.AckRevision = Math.Max(value.AckRevision, num); value.LastStateAckAt = LocalClock(); Diagnose("state-ack-" + sender, "State ACK peer=" + sender + " rev=" + num + " version=" + text2); } } catch (Exception ex) { Diagnose("state-ack-error", "State ACK failed: " + ex, warning: true); } } internal static double ServerTime() { ValheimBattleRoyalePlugin instance = Instance; if ((Object)(object)ZNet.instance != (Object)null && !ZNet.instance.IsServer() && (Object)(object)instance != (Object)null && instance._hasSnapshot) { return instance._serverClockAtReceipt + LocalClock() - instance._clockAtReceipt; } return LocalClock(); } internal static float DistanceXZ(Vector3 a, Vector3 b) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) float num = a.x - b.x; float num2 = a.z - b.z; return Mathf.Sqrt(num * num + num2 * num2); } internal static Vector3 Flat(Vector3 v) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) v.y = 0f; return v; } internal Vector3 GetEffectiveCurrentCenter() { //IL_000f: 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_003b: Unknown result type (might be due to invalid IL or missing references) if (ZoneState.Phase != ZonePhase.Shrinking || !ZoneState.HasNext) { return ZoneState.CurrentCenter; } float shrinkSeconds = ZoneState.ShrinkSeconds; float num = Mathf.Clamp01((float)((ServerTime() - ZoneState.PhaseStartedAt) / (double)shrinkSeconds)); return Vector3.Lerp(ZoneState.ShrinkFromCenter, ZoneState.NextCenter, num); } internal float GetEffectiveCurrentRadius() { if (ZoneState.Phase != ZonePhase.Shrinking || !ZoneState.HasNext) { return ZoneState.CurrentRadius; } float shrinkSeconds = ZoneState.ShrinkSeconds; float num = Mathf.Clamp01((float)((ServerTime() - ZoneState.PhaseStartedAt) / (double)shrinkSeconds)); return Mathf.Lerp(ZoneState.ShrinkFromRadius, ZoneState.NextRadius, num); } private static bool IsRussianLanguage() { string selectedGameLanguage = GetSelectedGameLanguage(); if (!string.IsNullOrEmpty(selectedGameLanguage)) { if (!selectedGameLanguage.Equals("Russian", StringComparison.OrdinalIgnoreCase) && !selectedGameLanguage.Equals("Русский", StringComparison.OrdinalIgnoreCase)) { return selectedGameLanguage.StartsWith("ru", StringComparison.OrdinalIgnoreCase); } return true; } return false; } private static string GetSelectedGameLanguage() { //IL_00eb: 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) if (!string.IsNullOrEmpty(_selectedLanguage) && Time.realtimeSinceStartup < _nextLanguageProbeAt) { return _selectedLanguage; } _nextLanguageProbeAt = Time.realtimeSinceStartup + 2f; try { object obj = ((LocalizationInstance == null) ? null : LocalizationInstance.GetValue(null, null)); if (obj != null && SelectedLanguage != null) { string text = SelectedLanguage.Invoke(obj, null) as string; if (!string.IsNullOrEmpty(text)) { return _selectedLanguage = text; } } } catch (Exception ex) { Instance?.Diagnose("language-error", "Language lookup failed: " + ex.Message, warning: true); } string text2 = PlayerPrefs.GetString("language", ""); if (string.IsNullOrEmpty(text2)) { text2 = PlayerPrefs.GetString("Language", ""); } return _selectedLanguage = (string.IsNullOrEmpty(text2) ? ((object)Application.systemLanguage/*cast due to .constrained prefix*/).ToString() : text2); } private static string Localize(string english, string russian) { if (!IsRussianLanguage()) { return english; } return russian; } private static TMP_FontAsset GetValheimNorseBold() { if ((Object)(object)_valheimNorseBold != (Object)null) { return _valheimNorseBold; } if ((Object)(object)Instance != (Object)null && LocalClock() < Instance._nextFontProbe) { return TMP_Settings.defaultFontAsset; } if ((Object)(object)Instance != (Object)null) { Instance._nextFontProbe = LocalClock() + 2.0; } TMP_FontAsset[] array = Resources.FindObjectsOfTypeAll<TMP_FontAsset>(); foreach (TMP_FontAsset val in array) { if ((Object)(object)val != (Object)null && ((Object)val).name.Equals("Valheim-Norsebold", StringComparison.OrdinalIgnoreCase)) { _valheimNorseBold = val; Instance.Diagnose("font-ready", "HUD font=" + ((Object)val).name, warning: false, 0.0); return val; } } Instance.Diagnose("font-pending", "Norsebold not yet loaded; default TMP font and retry are used.", warning: true, 30.0); return TMP_Settings.defaultFontAsset; } private void DestroyHud() { if ((Object)(object)_hudRoot != (Object)null) { Object.Destroy((Object)(object)_hudRoot); } _hudRoot = null; _hudTitle = (_hudTimer = (_hudDanger = null)); } private void EnsureTmpHud() { //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Expected O, but got Unknown //IL_0104: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_hudRoot != (Object)null) || !((Object)(object)_hudRoot.GetComponent<Canvas>() != (Object)null) || !((Object)(object)_hudTitle != (Object)null) || !((Object)(object)_hudTimer != (Object)null) || !((Object)(object)_hudDanger != (Object)null)) { DestroyHud(); GameObject val = new GameObject("XBR_TMP_HUD"); Object.DontDestroyOnLoad((Object)(object)val); Canvas obj = val.AddComponent<Canvas>(); obj.renderMode = (RenderMode)0; obj.sortingOrder = 200; val.AddComponent<CanvasScaler>().uiScaleMode = (ScaleMode)0; ((Behaviour)val.AddComponent<GraphicRaycaster>()).enabled = false; _hudRoot = val; _hudTitle = CreateTmpText("Title", val.transform, 18f); _hudTimer = CreateTmpText("Timer", val.transform, 18f); _hudDanger = CreateTmpText("Danger", val.transform, 25f); ((Graphic)_hudDanger).color = new Color(1f, 0.35f, 0.15f, 1f); } } private static TextMeshProUGUI CreateTmpText(string name, Transform parent, float size) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject(name); val.transform.SetParent(parent, false); TextMeshProUGUI val2 = val.AddComponent<TextMeshProUGUI>(); TMP_FontAsset valheimNorseBold = GetValheimNorseBold(); if ((Object)(object)valheimNorseBold != (Object)null) { ((TMP_Text)val2).font = valheimNorseBold; } ((TMP_Text)val2).fontSize = size; ((TMP_Text)val2).fontStyle = (FontStyles)1; ((TMP_Text)val2).alignment = (TextAlignmentOptions)514; ((Graphic)val2).color = Color.white; ((Graphic)val2).raycastTarget = false; ((TMP_Text)val2).textWrappingMode = (TextWrappingModes)0; return val2; } private static void SetScreenRect(RectTransform rt, Rect screenRect) { //IL_0001: 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_0017: 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_0050: Unknown result type (might be due to invalid IL or missing references) rt.anchorMin = Vector2.zero; rt.anchorMax = Vector2.zero; rt.pivot = Vector2.zero; rt.anchoredPosition = new Vector2(((Rect)(ref screenRect)).x, (float)Screen.height - ((Rect)(ref screenRect)).yMax); rt.sizeDelta = new Vector2(((Rect)(ref screenRect)).width, ((Rect)(ref screenRect)).height); } private void UpdateTmpHud() { //IL_03c8: Unknown result type (might be due to invalid IL or missing references) //IL_03ee: Unknown result type (might be due to invalid IL or missing references) //IL_0577: Unknown result type (might be due to invalid IL or missing references) //IL_057c: Unknown result type (might be due to invalid IL or missing references) //IL_0747: Unknown result type (might be due to invalid IL or missing references) //IL_063e: Unknown result type (might be due to invalid IL or missing references) //IL_0644: Unknown result type (might be due to invalid IL or missing references) if (!ShowHud.Value || (Object)(object)ZNet.instance == (Object)null || (Object)(object)Player.m_localPlayer == (Object)null) { if ((Object)(object)_hudRoot != (Object)null) { _hudRoot.SetActive(false); } if ((Object)(object)ZNet.instance != (Object)null) { Diagnose("hud-hidden", "HUD hidden: ShowHud=" + ShowHud.Value + " localPlayer=" + ((Object)(object)Player.m_localPlayer != (Object)null)); } } else { if (LocalClock() < _nextHudAttempt) { return; } EnsureTmpHud(); _hudRoot.SetActive(true); Canvas component = _hudRoot.GetComponent<Canvas>(); if (!((Behaviour)component).enabled || !((Behaviour)_hudTitle).enabled || !((Behaviour)_hudTimer).enabled || !((Behaviour)_hudDanger).enabled) { Diagnose("hud-components-disabled", "Restoring disabled BR HUD rendering components.", warning: true, 30.0); } ((Behaviour)component).enabled = true; TextMeshProUGUI hudTitle = _hudTitle; TextMeshProUGUI hudTimer = _hudTimer; bool flag = (((Behaviour)_hudDanger).enabled = true); bool enabled = (((Behaviour)hudTimer).enabled = flag); ((Behaviour)hudTitle).enabled = enabled; TMP_FontAsset valheimNorseBold = GetValheimNorseBold(); if ((Object)(object)valheimNorseBold != (Object)null) { if ((Object)(object)((TMP_Text)_hudTitle).font != (Object)(object)valheimNorseBold) { ((TMP_Text)_hudTitle).font = valheimNorseBold; } if ((Object)(object)((TMP_Text)_hudTimer).font != (Object)(object)valheimNorseBold) { ((TMP_Text)_hudTimer).font = valheimNorseBold; } if ((Object)(object)((TMP_Text)_hudDanger).font != (Object)(object)valheimNorseBold) { ((TMP_Text)_hudDanger).font = valheimNorseBold; } } double num = ServerTime(); string text = null; string text2 = null; if (!_hasSnapshot) { text = Localize("BATTLE ROYALE", "КОРОЛЕВСКАЯ БИТВА"); text2 = Localize("SYNCHRONIZING...", "СИНХРОНИЗАЦИЯ..."); } else if (ZoneState.Starting) { text = Localize("BATTLE ROYALE", "КОРОЛЕВСКАЯ БИТВА"); text2 = Localize("MATCH STARTS IN ", "МАТЧ НАЧНЁТСЯ ЧЕРЕЗ ") + FormatSeconds((float)Math.Max(0.0, ZoneState.MatchStartAt - num)); } else if (ZoneState.Running) { if (ZoneState.Phase == ZonePhase.Waiting && ZoneState.HasNext) { text = Localize("ZONE SHRINKS IN", "СУЖЕНИЕ ЗОНЫ ЧЕРЕЗ"); text2 = FormatSeconds(Mathf.Max(0f, ZoneState.WaitSecondsAtAssignment - (float)(num - ZoneState.PhaseStartedAt))); } else if (ZoneState.Phase == ZonePhase.Shrinking && ZoneState.HasNext) { text = Localize("ZONE IS SHRINKING", "ЗОНА СУЖАЕТСЯ"); text2 = FormatSeconds(Mathf.Max(0f, ZoneState.ShrinkSeconds - (float)(num - ZoneState.PhaseStartedAt))); } else { text = Localize("BATTLE ROYALE", "КОРОЛЕВСКАЯ БИТВА"); } } bool flag4 = !string.IsNullOrEmpty(text); ((Component)_hudTitle).gameObject.SetActive(flag4); ((Component)_hudTimer).gameObject.SetActive(flag4 && !string.IsNullOrEmpty(text2)); if (flag4) { if (!MinimapUpdatePatch.TryGetSmallMinimapScreenRect(Minimap.instance, out var screenRect)) { ((Rect)(ref screenRect))..ctor((float)Screen.width - 320f, 245f, 300f, 70f); } float num2 = Mathf.Min(Mathf.Max(300f, ((Rect)(ref screenRect)).width), (float)Screen.width); float num3 = Mathf.Clamp(((Rect)(ref screenRect)).xMax - num2, 0f, Mathf.Max(0f, (float)Screen.width - num2)); float num4 = Mathf.Clamp(((Rect)(ref screenRect)).yMax + 8f, 0f, Mathf.Max(0f, (float)Screen.height - 72f)); SetScreenRect(((TMP_Text)_hudTitle).rectTransform, new Rect(num3, num4, num2, 28f)); SetScreenRect(((TMP_Text)_hudTimer).rectTransform, new Rect(num3, num4 + 27f, num2, 34f)); ((TMP_Text)_hudTitle).text = text; ((TMP_Text)_hudTimer).text = text2 ?? ""; } string text3 = "snapshot=" + _hasSnapshot + " phase=" + ZoneState.Phase.ToString() + " title=" + flag4 + " timer=" + !string.IsNullOrEmpty(text2) + " font=" + (((Object)(object)((TMP_Text)_hudTimer).font == (Object)null) ? "missing" : ((Object)((TMP_Text)_hudTimer).font).name); Diagnose("hud-status", "HUD " + text3 + " screen=" + Screen.width + "x" + Screen.height + " rev=" + _revision + " rootActive=" + _hudRoot.activeInHierarchy + " timerEnabled=" + ((Behaviour)_hudTimer).isActiveAndEnabled + " timerRect=" + ((object)((TMP_Text)_hudTimer).rectTransform.rect/*cast due to .constrained prefix*/).ToString() + " canvasEnabled=" + ((Behaviour)_hudRoot.GetComponent<Canvas>()).enabled, warning: false, (text3 == _lastHudStatus) ? DiagnosticSeconds : 0.0); _lastHudStatus = text3; if ((Object)(object)((TMP_Text)_hudTimer).font == (Object)null) { Diagnose("hud-no-font", "HUD has no usable font; waiting for assets.", warning: true, 30.0); } bool flag5 = !_localExempt && ZoneState.Running && ZoneState.HasCurrent && !((Character)Player.m_localPlayer).IsDead() && DistanceXZ(((Component)Player.m_localPlayer).transform.position, GetEffectiveCurrentCenter()) > GetEffectiveCurrentRadius(); ((Component)_hudDanger).gameObject.SetActive(flag5); if (flag5) { float num5 = SafeNumber(OutsideWarningFontSize.Value, 25f, 12f, 100f); float num6 = SafeNumber(OutsideWarningTopPercent.Value, 20f, 0f, 100f); ((TMP_Text)_hudDanger).fontSize = num5; float num7 = Mathf.Min((float)Screen.height, num5 * 1.8f); float num8 = Mathf.Max(1f, (float)Screen.width - 20f); float num9 = Mathf.Clamp((float)Screen.height * num6 / 100f - num7 / 2f, 0f, Mathf.Max(0f, (float)Screen.height - num7)); SetScreenRect(((TMP_Text)_hudDanger).rectTransform, new Rect(((float)Screen.width - num8) / 2f, num9, num8, num7)); ((TMP_Text)_hudDanger).text = Localize("YOU ARE OUTSIDE THE SAFE ZONE!", "ВЫ ВНЕ БЕЗОПАСНОЙ ЗОНЫ!"); } } } private static string FormatSeconds(float value) { int num = Mathf.CeilToInt(value); return (num / 60).ToString("00") + ":" + (num % 60).ToString("00"); } private void OnGUI() { if ((Object)(object)Minimap.instance != (Object)null) { MinimapUpdatePatch.DrawZoneCircles(Minimap.instance); } } internal static bool HandleCommand(Terminal terminal, string line) { //IL_0177: Unknown result type (might be due to invalid IL or missing references) //IL_017d: Unknown result type (might be due to invalid IL or missing references) //IL_0208: Unknown result type (might be due to invalid IL or missing references) //IL_028f: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)Instance == (Object)null || string.IsNullOrWhiteSpace(line)) { return false; } string[] array = line.Trim().Split(new char[2] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries); if (array.Length == 0 || !array[0].Equals("br", StringComparison.OrdinalIgnoreCase)) { return false; } try { if (array.Length == 1 || array[1].Equals("help", StringComparison.OrdinalIgnoreCase)) { terminal.AddString("br start | stop | toggle | status | zone <x> <z> [r] | next <x> <z> [r] | here [r] | nexthere [r] | cancelnext"); return true; } string text = array[1].ToLowerInvariant(); switch (text) { case "status": terminal.AddString(ZoneState.Describe() + " snapshot=" + Instance._hasSnapshot + " rev=" + Instance._revision + " stateAge=" + (((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer()) ? "N/A(server)" : ((!Instance._hasSnapshot) ? "N/A(no snapshot)" : (LocalClock() - Instance._lastStateAt).ToString("F1")))); return true; case "start": case "stop": case "toggle": case "cancelnext": Instance.SendRequest(text); return true; case "here": case "nexthere": { if ((Object)(object)Player.m_localPlayer == (Object)null) { terminal.AddString("No local player."); return true; } float radius2 = ((array.Length >= 3) ? ParseFloat(array[2]) : 0f); Instance.SendRequest((text == "here") ? "zone" : "next", ((Component)Player.m_localPlayer).transform.position, radius2); return true; } case "zone": case "next": { if (array.Length < 4) { terminal.AddString("Usage: br " + text + " <x> <z> [radius]"); return true; } float num = ParseFloat(array[2]); float num2 = ParseFloat(array[3]); float radius = ((array.Length >= 5) ? ParseFloat(array[4]) : 0f); Instance.SendRequest(text, new Vector3(num, 0f, num2), radius); return true; } default: terminal.AddString("Unknown BR command. Type: br help"); break; } } catch (Exception ex) { terminal.AddString("BR error: " + ex.Message); } return true; } private static float ParseFloat(string s) { if (!float.TryParse(s.Replace(',', '.'), NumberStyles.Float, CultureInfo.InvariantCulture, out var result) || !Finite(result)) { throw new FormatException("Invalid number: " + s); } return result; } } internal enum ZonePhase { Idle, Waiting, Shrinking } internal static class ZoneState { internal static bool Running; internal static bool Starting; internal static bool HasCurrent; internal static bool HasNext; internal static Vector3 CurrentCenter; internal static Vector3 NextCenter; internal static Vector3 ShrinkFromCenter; internal static float CurrentRadius; internal static float NextRadius; internal static float ShrinkFromRadius; internal static float WaitSecondsAtAssignment; internal static float ShrinkSeconds = 180f; internal static float DamageTick = 2f; internal static float DamageAmount = 10f; internal static ZonePhase Phase; internal static double PhaseStartedAt; internal static double MatchStartAt; internal static void Reset() { //IL_0018: 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_001e: 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_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) Running = (Starting = (HasCurrent = (HasNext = false))); CurrentCenter = (NextCenter = (ShrinkFromCenter = Vector3.zero)); CurrentRadius = (NextRadius = (ShrinkFromRadius = (WaitSecondsAtAssignment = 0f))); ShrinkSeconds = 180f; DamageTick = 2f; DamageAmount = 10f; Phase = ZonePhase.Idle; PhaseStartedAt = (MatchStartAt = 0.0); } internal static void Write(ZPackage p) { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_004e: 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) p.Write(Running); p.Write(Starting); p.Write(MatchStartAt); p.Write(HasCurrent); p.Write(HasNext); p.Write(CurrentCenter); p.Write(CurrentRadius); p.Write(NextCenter); p.Write(NextRadius); p.Write((int)Phase); p.Write(PhaseStartedAt); p.Write(ShrinkFromCenter); p.Write(ShrinkFromRadius); p.Write(WaitSecondsAtAssignment); p.Write(ShrinkSeconds); p.Write(DamageTick); p.Write(DamageAmount); } internal static void Read(ZPackage p) { //IL_0025: 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) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0058: 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_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_01d9: Unknown result type (might be due to invalid IL or missing references) //IL_01e5: Unknown result type (might be due to invalid IL or missing references) //IL_01e7: Unknown result type (might be due to invalid IL or missing references) //IL_0201: Unknown result type (might be due to invalid IL or missing references) //IL_0203: Unknown result type (might be due to invalid IL or missing references) bool flag = p.ReadBool(); bool flag2 = p.ReadBool(); double num = p.ReadDouble(); bool flag3 = p.ReadBool(); bool flag4 = p.ReadBool(); Vector3 val = p.ReadVector3(); float num2 = p.ReadSingle(); Vector3 val2 = p.ReadVector3(); float num3 = p.ReadSingle(); int num4 = p.ReadInt(); double num5 = p.ReadDouble(); Vector3 val3 = p.ReadVector3(); float num6 = p.ReadSingle(); float num7 = p.ReadSingle(); float num8 = p.ReadSingle(); float num9 = p.ReadSingle(); float num10 = p.ReadSingle(); if (!ValheimBattleRoyalePlugin.Finite(val) || !ValheimBattleRoyalePlugin.Finite(val2) || !ValheimBattleRoyalePlugin.Finite(val3) || !Valid(num2, 0f, 100000f) || !Valid(num3, 0f, 100000f) || !Valid(num6, 0f, 100000f) || !Valid(num7, 0f, 86400f) || !Valid(num8, 0.01f, 86400f) || !Valid(num9, 0.1f, 3600f) || !Valid(num10, 0f, 100000f) || !ValheimBattleRoyalePlugin.Finite(num) || !ValheimBattleRoyalePlugin.Finite(num5) || num < 0.0 || num5 < 0.0 || num4 < 0 || num4 > 2 || (flag && flag2) || ((flag || flag2 || flag4) && !flag3) || (flag3 && num2 < 1f) || (flag4 && num3 < 1f) || (num4 != 0 && !flag4) || (num4 == 2 && num6 < 1f)) { throw new InvalidDataException("Invalid zone snapshot"); } Running = flag; Starting = flag2; MatchStartAt = num; HasCurrent = flag3; HasNext = flag4; CurrentCenter = val; CurrentRadius = num2; NextCenter = val2; NextRadius = num3; Phase = (ZonePhase)num4; PhaseStartedAt = num5; ShrinkFromCenter = val3; ShrinkFromRadius = num6; WaitSecondsAtAssignment = num7; ShrinkSeconds = num8; DamageTick = num9; DamageAmount = num10; } private static bool Valid(float value, float min, float max) { if (ValheimBattleRoyalePlugin.Finite(value) && value >= min) { return value <= max; } return false; } internal static string Describe() { return string.Format("BR running={0}, starting={1}, phase={2}, current=({3:F0},{4:F0}) R={5:F0}, next={6}, wait={7:F1}, shrink={8:F1}, damage={9:F1}/{10:F1}s", Running, Starting, Phase, CurrentCenter.x, CurrentCenter.z, CurrentRadius, HasNext ? $"({NextCenter.x:F0},{NextCenter.z:F0}) R={NextRadius:F0}" : "none", WaitSecondsAtAssignment, ShrinkSeconds, DamageAmount, DamageTick); } } [HarmonyPatch(typeof(ZRoutedRpc), "RPC_RoutedRPC", new Type[] { typeof(ZRpc), typeof(ZPackage) })] internal static class BattleRoyaleIngressPatch { private static bool Prefix(ZRpc __0, ZPackage __1) { ValheimBattleRoyalePlugin instance = ValheimBattleRoyalePlugin.Instance; if (!((Object)(object)instance == (Object)null)) { return instance.ValidateIngress(__0, __1); } return true; } } [HarmonyPatch(typeof(Player), "SetPVP")] internal static class PlayerSetPvpPatch { private static void Prefix(Player __instance, ref bool __0) { ValheimBattleRoyalePlugin instance = ValheimBattleRoyalePlugin.Instance; if ((Object)(object)instance != (Object)null && !instance._restoringPvp) { instance.GuardPvp(__instance, ref __0); } } } [HarmonyPatch(typeof(Player), "Message", new Type[] { typeof(MessageType), typeof(string), typeof(int), typeof(Sprite), typeof(bool) })] internal static class PvpNotificationPatch { private static bool Prefix(Character __instance, string msg) { ValheimBattleRoyalePlugin instance = ValheimBattleRoyalePlugin.Instance; if (!((Object)(object)instance == (Object)null)) { return instance.AllowPvpNotice(__instance, msg); } return true; } } [HarmonyPatch(typeof(Terminal), "TryRunCommand", new Type[] { typeof(string), typeof(bool), typeof(bool) })] internal static class TerminalTryRunCommandPatch { private static bool Prefix(Terminal __instance, string text) { return !ValheimBattleRoyalePlugin.HandleCommand(__instance, text); } } [HarmonyPatch(typeof(Minimap), "Update")] internal static class MinimapUpdatePatch { private static readonly MethodInfo ScreenToWorldPoint = FindMethod("ScreenToWorldPoint", typeof(Vector3)); private static readonly FieldInfo MapImageLargeField = AccessTools.Field(typeof(Minimap), "m_mapImageLarge"); private static readonly FieldInfo MapImageSmallField = AccessTools.Field(typeof(Minimap), "m_mapImageSmall"); private static readonly FieldInfo PixelSizeField = AccessTools.Field(typeof(Minimap), "m_pixelSize"); private static readonly FieldInfo TextureSizeField = AccessTools.Field(typeof(Minimap), "m_textureSize"); private static Texture2D _lineTex; private static MethodInfo FindMethod(string name, params Type[] parameterTypes) { MethodInfo[] methods = typeof(Minimap).GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); foreach (MethodInfo methodInfo in methods) { if (!string.Equals(methodInfo.Name, name, StringComparison.Ordinal)) { continue; } ParameterInfo[] parameters = methodInfo.GetParameters(); if (parameters.Length != parameterTypes.Length) { continue; } bool flag = true; for (int j = 0; j < parameters.Length; j++) { if (parameters[j].ParameterType != parameterTypes[j]) { flag = false; break; } } if (flag) { return methodInfo; } } return null; } private static void Postfix(Minimap __instance) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Invalid comparison between Unknown and I4 //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_004e: 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) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: 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_011f: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_01a8: Unknown result type (might be due to invalid IL or missing references) //IL_01b4: Unknown result type (might be due to invalid IL or missing references) //IL_0184: Unknown result type (might be due to invalid IL or missing references) //IL_0190: Unknown result type (might be due to invalid IL or missing references) //IL_01d7: Unknown result type (might be due to invalid IL or missing references) ValheimBattleRoyalePlugin instance = ValheimBattleRoyalePlugin.Instance; if ((Object)(object)instance == (Object)null || (Object)(object)Player.m_localPlayer == (Object)null || ScreenToWorldPoint == null || (int)__instance.m_mode != 2) { return; } KeyboardShortcut value = instance.PlaceZoneHotkey.Value; bool flag = ((KeyboardShortcut)(ref value)).IsDown(); value = instance.CancelZoneHotkey.Value; bool flag2 = ((KeyboardShortcut)(ref value)).IsDown(); if ((!flag && !flag2) || !CanUseMapInput(__instance)) { return; } if (flag2) { if (ZoneState.Phase == ZonePhase.Shrinking) { ValheimBattleRoyalePlugin.Log.LogInfo((object)"Map Ctrl+Click ignored: zone shrinking is already in progress."); return; } ValheimBattleRoyalePlugin.Log.LogInfo((object)(ZoneState.HasNext ? "Map Ctrl+Click: cancel next zone" : "Map Ctrl+Click: cancel current/start zone")); instance.SendRequest("cancelzone"); } else { if (!flag) { return; } if (ZoneState.Phase != ZonePhase.Shrinking) { try { Vector3 val = (Vector3)ScreenToWorldPoint.Invoke(__instance, new object[1] { Input.mousePosition }); val.y = 0f; if (!ZoneState.HasCurrent) { ValheimBattleRoyalePlugin.Log.LogInfo((object)$"Map Shift+Click: initial zone at X={val.x:F0} Z={val.z:F0}"); instance.SendRequest("zone", val, instance.InitialRadius.Value); } else { float num = (ZoneState.HasNext ? ZoneState.NextRadius : 0f); ValheimBattleRoyalePlugin.Log.LogInfo((object)(ZoneState.HasNext ? $"Map Shift+Click: move next zone to X={val.x:F0} Z={val.z:F0}, keep R={num:F0}" : $"Map Shift+Click: next zone at X={val.x:F0} Z={val.z:F0} (automatic radius)")); instance.SendRequest("next", val, num); } return; } catch (Exception ex) { ValheimBattleRoyalePlugin.Log.LogError((object)("Map click conversion failed: " + ex)); return; } } ValheimBattleRoyalePlugin.Log.LogInfo((object)"Map Shift+Click ignored: zone shrinking is already in progress."); } } private static bool CanUseMapInput(Minimap map) { //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: 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) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Expected O, but got Unknown //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) if (ValheimBattleRoyalePlugin.IsTextInputActive()) { return false; } if ((Object)(object)Hud.instance != (Object)null && (Object)(object)Hud.instance.m_buildUi != (Object)null && Hud.instance.m_buildUi.SearchFieldFocused) { return false; } object? obj = MapImageLargeField?.GetValue(map); Graphic val = (Graphic)((obj is Graphic) ? obj : null); if ((Object)(object)val == (Object)null || !((Behaviour)val).isActiveAndEnabled) { return false; } Canvas canvas = val.canvas; Camera val2 = (((Object)(object)canvas != (Object)null && (int)canvas.renderMode != 0) ? canvas.worldCamera : null); if (!RectTransformUtility.RectangleContainsScreenPoint(val.rectTransform, Vector2.op_Implicit(Input.mousePosition), val2)) { return false; } EventSystem current = EventSystem.current; if ((Object)(object)current == (Object)null) { return false; } List<RaycastResult> list = new List<RaycastResult>(); current.RaycastAll(new PointerEventData(current) { position = Vector2.op_Implicit(Input.mousePosition) }, list); if (list.Count == 0) { return false; } RaycastResult val3 = list[0]; Transform transform = ((RaycastResult)(ref val3)).gameObject.transform; if ((Object)(object)transform == (Object)(object)((Component)val).transform || transform.IsChildOf(((Component)val).transform)) { return (Object)(object)((Component)transform).GetComponentInParent<Selectable>() == (Object)null; } return false; } internal static void Cleanup() { if ((Object)(object)_lineTex != (Object)null) { Object.Destroy((Object)(object)_lineTex); } _lineTex = null; } internal static void DrawZoneCircles(Minimap map) { //IL_0090: 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_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) if (!ZoneState.HasCurrent || (Object)(object)map == (Object)null) { return; } try { object activeMapImage = GetActiveMapImage(map); if (activeMapImage == null || !TryGetImageGeometry(activeMapImage, out var uvRect, out var screenRect)) { return; } float numericField = GetNumericField(PixelSizeField, map, 1f); float numericField2 = GetNumericField(TextureSizeField, map, 2048f); float num = numericField * numericField2; if (!(num <= 0.001f) && !(Mathf.Abs(((Rect)(ref uvRect)).width) < 1E-05f) && !(Mathf.Abs(((Rect)(ref uvRect)).height) < 1E-05f)) { Vector3 effectiveCurrentCenter = ValheimBattleRoyalePlugin.Instance.GetEffectiveCurrentCenter(); float effectiveCurrentRadius = ValheimBattleRoyalePlugin.Instance.GetEffectiveCurrentRadius(); DrawCircle(effectiveCurrentCenter, effectiveCurrentRadius, new Color(0.2f, 1f, 0.25f, 0.95f), uvRect, screenRect, num, 3f); if (ZoneState.HasNext) { DrawCircle(ZoneState.NextCenter, ZoneState.NextRadius, new Color(1f, 0.85f, 0.15f, 0.95f), uvRect, screenRect, num, 3f); } } } catch (Exception ex) { ValheimBattleRoyalePlugin.Instance?.Diagnose("overlay-error", "Zone map overlay unavailable: " + ex, warning: true); } } private static object GetActiveMapImage(Minimap map) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Invalid comparison between Unknown and I4 if ((int)map.m_mode == 2) { return MapImageLargeField?.GetValue(map); } return MapImageSmallField?.GetValue(map); } internal static bool TryGetSmallMinimapScreenRect(Minimap map, out Rect screenRect) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) screenRect = default(Rect); if ((Object)(object)map == (Object)null) { return false; } try { object obj = MapImageSmallField?.GetValue(map); if (obj == null) { return false; } Rect uvRect; return TryGetImageGeometry(obj, out uvRect, out screenRect); } catch { return false; } } private static float GetNumericField(FieldInfo field, object instance, float fallback) { if (field == null) { return fallback; } object value = field.GetValue(instance); if (value == null) { return fallback; } try { return Convert.ToSingle(value, CultureInfo.InvariantCulture); } catch { return fallback; } } private static bool TryGetImageGeometry(object image, out Rect uvRect, out Rect screenRect) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0062: 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_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Unknown result type