Decompiled source of PEAK MX v1.1.1
PEAK-MX.dll
Decompiled 3 days ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Net; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Serialization; using System.Runtime.Serialization.Json; using System.Runtime.Versioning; using System.Security; using System.Security.Cryptography; using System.Security.Permissions; using System.Text; using System.Threading.Tasks; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using ExitGames.Client.Photon; using HarmonyLib; using Microsoft.CodeAnalysis; using MxAhg.Shared; using Peak.Network; using Photon.Pun; using Photon.Realtime; using Steamworks; using UnityEngine; using Zorro.Core; using Zorro.Core.Serizalization; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace MxAhg.Shared { internal static class Protocol { public const byte EventCode = 172; public const string Magic = "MX_AHG"; public const int Version = 1; public const int CommandChallenge = 1; public const int CommandReport = 2; public const string AgentVersionKey = "mxahg_v"; public const string ProtocolKey = "mxahg_p"; public const string FileSignatureKey = "mxahg_s"; public const string FileCountKey = "mxahg_c"; public const string LoadedSignatureKey = "mxahg_l"; public const string LoadedCountKey = "mxahg_lc"; public const string HeartbeatKey = "mxahg_h"; public const string SelfHashKey = "mxahg_i"; public const int MaxFiles = 512; public const int MaxPlugins = 256; public const int MaxHarmonyOwners = 256; public static string Short(string value, int length = 16) { if (string.IsNullOrWhiteSpace(value)) { return "?"; } if (value.Length > length) { return value.Substring(0, length); } return value; } public static string HashFile(string path) { using SHA256 sHA = SHA256.Create(); using FileStream inputStream = File.OpenRead(path); return ToHex(sHA.ComputeHash(inputStream)); } public static string HashText(string value) { using SHA256 sHA = SHA256.Create(); return ToHex(sHA.ComputeHash(Encoding.UTF8.GetBytes(value ?? ""))); } public static string ComputeProof(string nonce, Snapshot snapshot) { if (snapshot == null) { return ""; } return HashText(nonce + "|" + snapshot.FileSignature + "|" + snapshot.LoadedSignature + "|" + snapshot.SelfHash + "|" + (snapshot.Truncated ? "1" : "0") + "|" + snapshot.Error + "|" + snapshot.BuildCanonical()); } public static string[] ToFlatFiles(IReadOnlyList<FileEntry> entries) { if (entries == null || entries.Count == 0) { return Array.Empty<string>(); } string[] array = new string[entries.Count * 4]; for (int i = 0; i < entries.Count; i++) { int num = i * 4; array[num] = entries[i].RelativePath ?? ""; array[num + 1] = entries[i].Sha256 ?? ""; array[num + 2] = entries[i].AssemblyName ?? ""; array[num + 3] = entries[i].AssemblyVersion ?? ""; } return array; } public static string[] ToFlatPlugins(IReadOnlyList<PluginEntry> entries) { if (entries == null || entries.Count == 0) { return Array.Empty<string>(); } string[] array = new string[entries.Count * 5]; for (int i = 0; i < entries.Count; i++) { int num = i * 5; array[num] = entries[i].Guid ?? ""; array[num + 1] = entries[i].Name ?? ""; array[num + 2] = entries[i].Version ?? ""; array[num + 3] = entries[i].RelativePath ?? ""; array[num + 4] = entries[i].Sha256 ?? ""; } return array; } public static List<FileEntry> ParseFiles(object value) { string[] array = ReadStringArray(value); List<FileEntry> list = new List<FileEntry>(); int num = Math.Min(array.Length / 4, 512); for (int i = 0; i < num; i++) { int num2 = i * 4; list.Add(new FileEntry { RelativePath = Limit(array[num2], 320), Sha256 = Limit(array[num2 + 1], 64), AssemblyName = Limit(array[num2 + 2], 160), AssemblyVersion = Limit(array[num2 + 3], 80) }); } return list; } public static List<PluginEntry> ParsePlugins(object value) { string[] array = ReadStringArray(value); List<PluginEntry> list = new List<PluginEntry>(); int num = Math.Min(array.Length / 5, 256); for (int i = 0; i < num; i++) { int num2 = i * 5; list.Add(new PluginEntry { Guid = Limit(array[num2], 180), Name = Limit(array[num2 + 1], 180), Version = Limit(array[num2 + 2], 80), RelativePath = Limit(array[num2 + 3], 320), Sha256 = Limit(array[num2 + 4], 64) }); } return list; } public static string[] ReadStringArray(object value) { if (value is string[] result) { return result; } if (value is object[] array) { int num = Math.Min(array.Length, 2560); string[] array2 = new string[num]; for (int i = 0; i < num; i++) { array2[i] = array[i]?.ToString() ?? ""; } return array2; } return Array.Empty<string>(); } public static string Limit(string value, int maxLength) { if (string.IsNullOrEmpty(value)) { return ""; } if (value.Length > maxLength) { return value.Substring(0, maxLength); } return value; } private static string ToHex(byte[] bytes) { StringBuilder stringBuilder = new StringBuilder(bytes.Length * 2); for (int i = 0; i < bytes.Length; i++) { stringBuilder.Append(bytes[i].ToString("x2")); } return stringBuilder.ToString(); } } internal sealed class FileEntry { public string RelativePath = ""; public string Sha256 = ""; public string AssemblyName = ""; public string AssemblyVersion = ""; } internal sealed class PluginEntry { public string Guid = ""; public string Name = ""; public string Version = ""; public string RelativePath = ""; public string Sha256 = ""; } internal sealed class Snapshot { public readonly List<FileEntry> Files = new List<FileEntry>(); public readonly List<PluginEntry> Plugins = new List<PluginEntry>(); public readonly List<string> HarmonyOwners = new List<string>(); public string FileSignature = ""; public string LoadedSignature = ""; public string SelfHash = ""; public string Error = ""; public bool Truncated; public void Recalculate() { Files.Sort((FileEntry a, FileEntry b) => string.Compare(a.RelativePath, b.RelativePath, StringComparison.OrdinalIgnoreCase)); Plugins.Sort((PluginEntry a, PluginEntry b) => string.Compare(a.Guid, b.Guid, StringComparison.OrdinalIgnoreCase)); HarmonyOwners.Sort(StringComparer.OrdinalIgnoreCase); FileSignature = Protocol.HashText(BuildFileCanonical()); LoadedSignature = Protocol.HashText(BuildLoadedCanonical()); } public string BuildCanonical() { return BuildFileCanonical() + "\n--loaded--\n" + BuildLoadedCanonical(); } private string BuildFileCanonical() { StringBuilder stringBuilder = new StringBuilder(); for (int i = 0; i < Files.Count; i++) { AppendField(stringBuilder, Files[i].RelativePath.ToLowerInvariant()); AppendField(stringBuilder, Files[i].Sha256.ToLowerInvariant()); AppendField(stringBuilder, Files[i].AssemblyName.ToLowerInvariant()); AppendField(stringBuilder, Files[i].AssemblyVersion); stringBuilder.Append('\n'); } return stringBuilder.ToString(); } private string BuildLoadedCanonical() { StringBuilder stringBuilder = new StringBuilder(); for (int i = 0; i < Plugins.Count; i++) { AppendField(stringBuilder, Plugins[i].Guid.ToLowerInvariant()); AppendField(stringBuilder, Plugins[i].Name.ToLowerInvariant()); AppendField(stringBuilder, Plugins[i].Version); AppendField(stringBuilder, Plugins[i].RelativePath.ToLowerInvariant()); AppendField(stringBuilder, Plugins[i].Sha256.ToLowerInvariant()); stringBuilder.Append('\n'); } stringBuilder.Append("owners\n"); for (int j = 0; j < HarmonyOwners.Count; j++) { AppendField(stringBuilder, HarmonyOwners[j].ToLowerInvariant()); } return stringBuilder.ToString(); } private static void AppendField(StringBuilder sb, string value) { value = value ?? ""; sb.Append(value.Length).Append(':').Append(value) .Append('|'); } } internal static class Scanner { public const string AgentGuid = "com.maxkir041.mxahg"; public const string PeakMxGuid = "com.maxkir041.peakmx"; public static Snapshot Scan(string selfAssemblyPath, bool excludePeakMx = false) { Snapshot snapshot = new Snapshot(); List<string> list = new List<string>(); string text = Paths.PluginPath; if (string.IsNullOrWhiteSpace(text) || !Directory.Exists(text)) { text = Path.GetDirectoryName(selfAssemblyPath) ?? ""; } try { if (!string.IsNullOrWhiteSpace(selfAssemblyPath) && File.Exists(selfAssemblyPath)) { snapshot.SelfHash = Protocol.HashFile(selfAssemblyPath); } } catch (Exception ex) { list.Add("self: " + ex.Message); } try { string[] array = (Directory.Exists(text) ? Directory.GetFiles(text, "*.dll", SearchOption.AllDirectories) : Array.Empty<string>()); Array.Sort(array, (IComparer<string>?)StringComparer.OrdinalIgnoreCase); for (int i = 0; i < array.Length; i++) { if (snapshot.Files.Count >= 512) { snapshot.Truncated = true; break; } if (ShouldExcludeFile(Path.GetFileName(array[i]), excludePeakMx)) { continue; } try { AssemblyName assemblyName = null; try { assemblyName = AssemblyName.GetAssemblyName(array[i]); } catch { } snapshot.Files.Add(new FileEntry { RelativePath = RelativePath(text, array[i]), Sha256 = Protocol.HashFile(array[i]), AssemblyName = (assemblyName?.Name ?? Path.GetFileNameWithoutExtension(array[i])), AssemblyVersion = (assemblyName?.Version?.ToString() ?? "") }); } catch (Exception ex2) { list.Add(Path.GetFileName(array[i]) + ": " + ex2.Message); } } } catch (Exception ex3) { list.Add("files: " + ex3.Message); } try { foreach (KeyValuePair<string, PluginInfo> pluginInfo in Chainloader.PluginInfos) { if (snapshot.Plugins.Count >= 256) { snapshot.Truncated = true; break; } PluginInfo value = pluginInfo.Value; object obj2; if (value == null) { obj2 = null; } else { BepInPlugin metadata = value.Metadata; obj2 = ((metadata != null) ? metadata.GUID : null); } if (obj2 == null) { obj2 = pluginInfo.Key ?? ""; } string guid = (string)obj2; if (ShouldExcludePlugin(guid, excludePeakMx)) { continue; } string text2 = ((value != null) ? value.Location : null) ?? ""; string sha = ""; try { if (File.Exists(text2)) { sha = Protocol.HashFile(text2); } } catch { } List<PluginEntry> plugins = snapshot.Plugins; PluginEntry obj4 = new PluginEntry { Guid = guid }; object obj5; if (value == null) { obj5 = null; } else { BepInPlugin metadata2 = value.Metadata; obj5 = ((metadata2 != null) ? metadata2.Name : null); } if (obj5 == null) { obj5 = ""; } obj4.Name = (string)obj5; object obj6; if (value == null) { obj6 = null; } else { BepInPlugin metadata3 = value.Metadata; obj6 = ((metadata3 == null) ? null : metadata3.Version?.ToString()); } if (obj6 == null) { obj6 = ""; } obj4.Version = (string)obj6; obj4.RelativePath = RelativePath(text, text2); obj4.Sha256 = sha; plugins.Add(obj4); } } catch (Exception ex4) { list.Add("plugins: " + ex4.Message); } try { HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase); foreach (MethodBase allPatchedMethod in Harmony.GetAllPatchedMethods()) { Patches patchInfo = Harmony.GetPatchInfo(allPatchedMethod); if (((patchInfo != null) ? patchInfo.Owners : null) == null) { continue; } foreach (string owner in patchInfo.Owners) { if (!string.IsNullOrWhiteSpace(owner) && !ShouldExcludePlugin(owner, excludePeakMx) && !IsUnstableHarmonyOwner(owner)) { hashSet.Add(owner); } } } foreach (string item in hashSet) { if (snapshot.HarmonyOwners.Count >= 256) { snapshot.Truncated = true; break; } snapshot.HarmonyOwners.Add(item); } } catch (Exception ex5) { list.Add("harmony: " + ex5.Message); } snapshot.Error = string.Join("; ", list.ToArray()); snapshot.Recalculate(); return snapshot; } public static bool IsTechnicalFile(string path) { string fileName = Path.GetFileName(path ?? ""); if (!string.Equals(fileName, "MX-AHG.dll", StringComparison.OrdinalIgnoreCase)) { return string.Equals(fileName, "PEAK-MX.dll", StringComparison.OrdinalIgnoreCase); } return true; } public static bool IsTechnicalPlugin(string guid) { if (!string.Equals(guid, "com.maxkir041.mxahg", StringComparison.OrdinalIgnoreCase)) { return string.Equals(guid, "com.maxkir041.peakmx", StringComparison.OrdinalIgnoreCase); } return true; } public static bool IsUnstableHarmonyOwner(string owner) { if (!string.IsNullOrWhiteSpace(owner)) { return owner.StartsWith("harmony-auto-", StringComparison.OrdinalIgnoreCase); } return false; } private static bool ShouldExcludeFile(string fileName, bool excludePeakMx) { if (string.Equals(fileName, "MX-AHG.dll", StringComparison.OrdinalIgnoreCase)) { return true; } if (excludePeakMx) { return string.Equals(fileName, "PEAK-MX.dll", StringComparison.OrdinalIgnoreCase); } return false; } private static bool ShouldExcludePlugin(string guid, bool excludePeakMx) { if (string.Equals(guid, "com.maxkir041.mxahg", StringComparison.OrdinalIgnoreCase)) { return true; } if (excludePeakMx) { return string.Equals(guid, "com.maxkir041.peakmx", StringComparison.OrdinalIgnoreCase); } return false; } private static string RelativePath(string root, string file) { if (string.IsNullOrWhiteSpace(file)) { return ""; } try { Uri uri = new Uri(AppendSlash(Path.GetFullPath(root))); Uri uri2 = new Uri(Path.GetFullPath(file)); return Uri.UnescapeDataString(uri.MakeRelativeUri(uri2).ToString()).Replace('/', Path.DirectorySeparatorChar); } catch { return Path.GetFileName(file); } } private static string AppendSlash(string value) { char directorySeparatorChar = Path.DirectorySeparatorChar; if (!value.EndsWith(directorySeparatorChar.ToString(), StringComparison.Ordinal)) { directorySeparatorChar = Path.AltDirectorySeparatorChar; if (!value.EndsWith(directorySeparatorChar.ToString(), StringComparison.Ordinal)) { directorySeparatorChar = Path.DirectorySeparatorChar; return value + directorySeparatorChar; } } return value; } } } namespace PeakMX { internal static class AntiCheat { private const string EnabledKey = "pmx_ac"; private const string LockClientsKey = "pmx_ac_lock"; private const string HostActorKey = "pmx_ac_host"; private const string HostVersionKey = "pmx_ac_ver"; private static float _nextPublish; private static bool _lastPublishedEnabled; private static bool _hostEnabled; private static bool _hostLocksClients; private static int _hostActor; private static string _hostVersion = ""; private static int _lastLockNoticeHostActor = int.MinValue; private static bool _wasMasterClient; public static bool HostEnabled => _hostEnabled; public static bool HostLocksClients => _hostLocksClients; public static int HostActor => _hostActor; public static string HostVersion => _hostVersion; public static bool ClientToolsLocked { get { try { return PhotonNetwork.InRoom && _hostEnabled && _hostLocksClients && !PhotonNetwork.IsMasterClient; } catch { return false; } } } public static void Tick() { try { if (!PhotonNetwork.InRoom) { _hostEnabled = false; _hostLocksClients = false; _hostActor = 0; _hostVersion = ""; _nextPublish = 0f; _lastPublishedEnabled = false; _lastLockNoticeHostActor = int.MinValue; _wasMasterClient = false; return; } ReadRoomState(); bool isMasterClient = PhotonNetwork.IsMasterClient; bool flag = isMasterClient && !_wasMasterClient; _wasMasterClient = isMasterClient; if (isMasterClient) { if (flag) { AdoptInheritedRoomPolicy(); } ApplyHostMasterSwitch(); PublishHostState(); } if (ClientToolsLocked) { DisableRestrictedLocalTools(); } else { _lastLockNoticeHostActor = int.MinValue; } } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogDebug((object)("[AntiCheat] " + ex.Message)); } } } public static void SetHostEnabled(bool enabled) { ModConfig.AntiCheatEnabled = enabled; ModConfig.AdminProtectionEnabled = enabled; ApplyHostMasterSwitch(); _nextPublish = 0f; PublishHostState(); } public static string StatusText(Lang lang) { if (!PhotonNetwork.InRoom) { return Localization.Pick(lang, "Античит активируется в комнате.", "Anti-cheat becomes active inside a room.", "反作弊会在房间内启用。", "反作弊會在房間內啟用。"); } if (PhotonNetwork.IsMasterClient) { if (!ModConfig.AntiCheatEnabled) { return Localization.Pick(lang, "Античит хоста выключен.", "Host anti-cheat is disabled.", "房主反作弊已关闭。", "房主反作弊已關閉。"); } return Localization.Pick(lang, "Античит хоста включён.", "Host anti-cheat is enabled.", "房主反作弊已启用。", "房主反作弊已啟用。"); } if (_hostEnabled) { if (!_hostLocksClients) { return Localization.Pick(lang, "Хост включил античит без блокировки клиентских инструментов.", "The host enabled anti-cheat without locking client tools.", "房主启用了反作弊,但未锁定客户端工具。", "房主啟用了反作弊,但未鎖定用戶端工具。"); } return Localization.Pick(lang, "Хост включил античит. Инструменты PEAK-MX на клиентах заблокированы.", "The host enabled anti-cheat. PEAK-MX tools are locked on clients.", "房主启用了反作弊。客户端 PEAK-MX 工具已锁定。", "房主啟用了反作弊。用戶端 PEAK-MX 工具已鎖定。"); } return Localization.Pick(lang, "Хост не включал античит.", "The host has not enabled anti-cheat.", "房主未启用反作弊。", "房主未啟用反作弊。"); } public static void DisableRestrictedLocalTools() { ModConfig.SpeedMod = false; ModConfig.JumpMod = false; ModConfig.InfiniteJumps = false; ModConfig.ClimbMod = false; ModConfig.VineClimbMod = false; ModConfig.RopeClimbMod = false; ModConfig.GodMode = false; ModConfig.InfiniteStamina = false; ModConfig.NoFallDamage = false; ModConfig.NoFallingRagdoll = false; ModConfig.NoWeight = false; ModConfig.LockStatus = false; ModConfig.NoStatusEffects = false; ModConfig.NoInjury = false; ModConfig.NoHunger = false; ModConfig.NoCold = false; ModConfig.NoPoison = false; ModConfig.NoCurse = false; ModConfig.NoDrowsy = false; ModConfig.NoHot = false; ModConfig.NoCrab = false; ModConfig.NoThorns = false; ModConfig.NoSpores = false; ModConfig.NoWeb = false; ModConfig.NoArrows = false; ModConfig.NoPetrify = false; ModConfig.NoFlyTrap = false; ModConfig.TeleportToPing = false; ModConfig.NoSlipperySurfaces = false; ModConfig.LongInteraction = false; ModConfig.CinematicCamera = false; ModConfig.GlobalVoice = false; ModConfig.PlayerEsp = false; ModConfig.ItemEsp = false; if (ModConfig.WorldEsp != null) { ModConfig.WorldEsp.Value = false; } ModConfig.GameSpeedMod = false; ModConfig.PingHandSizeMultiplier = 1f; ModConfig.OverrideExpeditionTime = false; ModConfig.Fly = false; ModConfig.Noclip = false; ModConfig.InfiniteItems = false; ModConfig.UnlimitedLanternFuel = false; ModConfig.UnlimitedItemUses = false; ModConfig.RapidRandomOutfitColor = false; int num = ((_hostActor > 0) ? _hostActor : (-1)); if (_lastLockNoticeHostActor != num) { _lastLockNoticeHostActor = num; GameApi.AddAdminLog((Localization.Current == Lang.Russian) ? "anti-cheat: клиентские инструменты заблокированы хостом" : "anti-cheat: client tools locked by host", showNotice: false); } } private static void ApplyHostMasterSwitch() { if (ModConfig.AntiCheatEnabled) { if (ModConfig.ManyPlayersPluginAudit != null) { ModConfig.ManyPlayersPluginAudit.Value = false; } if (ModConfig.ManyPlayersPluginAuditKick != null) { ModConfig.ManyPlayersPluginAuditKick.Value = false; } } ModConfig.AdminProtectionEnabled = ModConfig.AntiCheatEnabled; } private static void AdoptInheritedRoomPolicy() { if (_hostEnabled && !ModConfig.AntiCheatEnabled) { ModConfig.AntiCheatEnabled = true; ModConfig.AdminProtectionEnabled = true; if (ModConfig.AntiCheatLockClients != null) { ModConfig.AntiCheatLockClients.Value = _hostLocksClients; } GameApi.AddAdminLog((Localization.Current == Lang.Russian) ? "anti-cheat: политика комнаты унаследована новым хостом" : "anti-cheat: room policy inherited by the new host"); } } private static void PublishHostState() { //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Expected O, but got Unknown if (PhotonNetwork.InRoom && PhotonNetwork.IsMasterClient && PhotonNetwork.CurrentRoom != null) { bool antiCheatEnabled = ModConfig.AntiCheatEnabled; if (antiCheatEnabled != _lastPublishedEnabled || !(Time.realtimeSinceStartup < _nextPublish)) { _nextPublish = Time.realtimeSinceStartup + 2f; _lastPublishedEnabled = antiCheatEnabled; Hashtable val = new Hashtable { [(object)"pmx_ac"] = antiCheatEnabled, [(object)"pmx_ac_lock"] = ModConfig.AntiCheatLockClients == null || ModConfig.AntiCheatLockClients.Value, [(object)"pmx_ac_host"] = ((PhotonNetwork.LocalPlayer != null) ? PhotonNetwork.LocalPlayer.ActorNumber : 0), [(object)"pmx_ac_ver"] = "1.1.1" }; PhotonNetwork.CurrentRoom.SetCustomProperties(val, (Hashtable)null, (WebFlags)null); _hostEnabled = antiCheatEnabled; _hostLocksClients = ModConfig.AntiCheatLockClients == null || ModConfig.AntiCheatLockClients.Value; _hostActor = ((PhotonNetwork.LocalPlayer != null) ? PhotonNetwork.LocalPlayer.ActorNumber : 0); _hostVersion = "1.1.1"; } } } private static void ReadRoomState() { try { Room currentRoom = PhotonNetwork.CurrentRoom; if (((currentRoom != null) ? ((RoomInfo)currentRoom).CustomProperties : null) == null) { return; } Hashtable customProperties = ((RoomInfo)PhotonNetwork.CurrentRoom).CustomProperties; bool flag = default(bool); int num; if (((Dictionary<object, object>)(object)customProperties).TryGetValue((object)"pmx_ac", out object value)) { if (value is bool) { flag = (bool)value; num = 1; } else { num = 0; } } else { num = 0; } _hostEnabled = (byte)((uint)num & (flag ? 1u : 0u)) != 0; bool flag2 = default(bool); int num2; if (((Dictionary<object, object>)(object)customProperties).TryGetValue((object)"pmx_ac_lock", out object value2)) { if (value2 is bool) { flag2 = (bool)value2; num2 = ((1 == 0) ? 1 : 0); } else { num2 = 1; } } else { num2 = 1; } _hostLocksClients = (byte)((uint)num2 | (flag2 ? 1u : 0u)) != 0; _hostActor = ((((Dictionary<object, object>)(object)customProperties).TryGetValue((object)"pmx_ac_host", out object value3) && int.TryParse(value3?.ToString(), out var result)) ? result : 0); _hostVersion = ((!((Dictionary<object, object>)(object)customProperties).TryGetValue((object)"pmx_ac_ver", out object value4)) ? "" : (value4?.ToString() ?? "")); } catch { _hostEnabled = false; _hostLocksClients = false; _hostActor = 0; _hostVersion = ""; } } } public static class CheatTracker { public static void Tick() { } } internal static class CompatibilityDiagnostics { public struct Row { public readonly string Name; public readonly bool Ok; public readonly string Detail; public Row(string name, bool ok, string detail) { Name = name; Ok = ok; Detail = detail; } } private const BindingFlags AnyInstance = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; public static List<Row> Rows(bool russian) { List<Row> list = new List<Row>(); list.Add(new Row(russian ? "PEAK-MX" : "PEAK-MX", ok: true, "v1.1.1")); list.Add(new Row(russian ? "Версия игры" : "Game version", ok: true, Safe(() => Application.version, "?"))); list.Add(new Row(russian ? "Photon" : "Photon", Safe(() => PhotonNetwork.NetworkingClient != null, fallback: false), Safe(() => (!PhotonNetwork.InRoom) ? ((!russian) ? "not in room" : "не в комнате") : string.Format("{0}: {1}", russian ? "комната" : "room", PhotonNetwork.PlayerList.Length), "?"))); list.Add(CheckMethod(typeof(CharacterMovement), "RocketExplodeRPC", russian ? "Взрыв игрока" : "Player explosion", russian ? "RPC взрыва найден" : "Explosion RPC found")); list.Add(CheckMethod(typeof(CharacterMovement), "FallFactor", russian ? "Урон от падения" : "Fall damage", russian ? "метод найден" : "method found")); list.Add(CheckMethod(typeof(CharacterMovement), "MaxVelDmg", russian ? "Скорость падения" : "Fall velocity", russian ? "метод найден" : "method found")); list.Add(CheckMethod(typeof(CharacterMovement), "AcceptableAngle", new Type[1] { typeof(float) }, russian ? "Угол падения" : "Fall angle", russian ? "метод найден" : "method found")); list.Add(CheckMethod(typeof(CharacterInput), "ResetInput", russian ? "Блокировка ввода" : "Input blocker", russian ? "метод найден" : "method found")); list.Add(CheckField(typeof(Player), "itemSlots", russian ? "Основные слоты" : "Main slots")); list.Add(CheckField(typeof(Player), "backpackSlot", russian ? "Слот на спине" : "Back slot")); list.Add(CheckField(typeof(Player), "tempFullSlot", russian ? "Амулет/временный слот" : "Amulet/temp slot")); list.Add(CheckMember(typeof(ItemSlot), "prefab", russian ? "Предмет в слоте" : "Slot item")); list.Add(CheckMember(typeof(CharacterData), "dead", russian ? "Состояние смерти" : "Dead state")); list.Add(CheckMember(typeof(CharacterData), "currentItem", russian ? "Текущий предмет" : "Current item")); list.Add(CheckMember(typeof(CharacterData), "currentStamina", russian ? "Стамина" : "Stamina")); list.Add(CheckMethod(typeof(NetworkingUtilities), "HostRoomOptions", russian ? "Большие лобби" : "Large lobbies", russian ? "метод комнаты найден" : "room method found")); list.Add(CheckMethod(typeof(AirportCheckInKiosk), "StartGame", new Type[1] { typeof(int) }, russian ? "Старт экспедиции" : "Expedition start", russian ? "метод киоска найден" : "kiosk method found")); list.Add(CheckMethod(typeof(AirportCheckInKiosk), "LoadIslandMaster", new Type[2] { typeof(int), typeof(byte[]) }, russian ? "Загрузка острова" : "Island loading", russian ? "метод загрузки найден" : "load method found")); list.Add(CheckMethod(typeof(PlayerHandler), "AssignMixerGroup", new Type[1] { typeof(Character) }, russian ? "Голосовые группы" : "Voice groups", russian ? "метод найден" : "method found")); list.Add(CheckMethod(typeof(UIPlayerNames), "DisableName", new Type[1] { typeof(int) }, russian ? "UI имен игроков" : "Player names UI", russian ? "метод найден" : "method found")); list.Add(CheckMethod(typeof(PointPinger), "ReceivePoint_Rpc", new Type[2] { typeof(Vector3), typeof(Vector3) }, russian ? "Пинги карты" : "Map pings", russian ? "RPC найден" : "RPC found")); list.Add(CheckEnum<STATUSTYPE>("Arrow", russian ? "Стрелы" : "Arrows")); list.Add(CheckEnum<STATUSTYPE>("Petrify", russian ? "Окаменение" : "Petrify")); list.Add(CheckEnum<STATUSTYPE>("FlyTrap", russian ? "Мухоловка" : "Flytrap")); list.Add(CheckField(typeof(CharacterVoiceHandler), "m_source", russian ? "Голосовой источник" : "Voice source")); list.Add(CheckField(typeof(VoiceObscuranceFilter), "_voiceHandler", russian ? "Фильтр эха голоса" : "Voice echo filter")); list.Add(CheckField(typeof(MapHandler), "respawnThePeak", russian ? "Телепорт на пик" : "Peak teleport")); bool flag = Safe(delegate { GameApi.EnsureItemsLoaded(); return GameApi.ItemNames.Count > 0; }, fallback: false); list.Add(new Row(russian ? "База предметов" : "Item database", flag, flag ? GameApi.ItemNames.Count.ToString() : (russian ? "предметы не загружены" : "items not loaded"))); int num = 0; List<string> list2 = new List<string>(); foreach (GameApi.CosmeticCategory category in Enum.GetValues(typeof(GameApi.CosmeticCategory))) { int num2 = Safe(() => GameApi.GetCosmeticOptions(category).Length, 0); num += num2; list2.Add(category.ToString() + "=" + num2); } list.Add(new Row(russian ? "База косметики" : "Cosmetic database", num > 0, (num > 0) ? string.Join(", ", list2) : (russian ? "косметика не найдена" : "cosmetics not found"))); list.Add(new Row(russian ? "Ачивки" : "Achievements", Safe(() => SteamAch.AllTypes.Length != 0, fallback: false), Safe<string>(() => SteamAch.AllTypes.Length.ToString(), "?"))); return list; } public static string BuildReport(bool russian) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("PEAK-MX compatibility report"); stringBuilder.AppendLine("Mod: 1.1.1"); stringBuilder.AppendLine("Game: " + Safe(() => Application.version, "?")); stringBuilder.AppendLine("Time: " + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")); stringBuilder.AppendLine(); List<Row> list = Rows(russian); for (int num = 0; num < list.Count; num++) { Row row = list[num]; stringBuilder.Append(row.Ok ? "[OK] " : "[WARN] "); stringBuilder.Append(row.Name); if (!string.IsNullOrWhiteSpace(row.Detail)) { stringBuilder.Append(": ").Append(row.Detail); } stringBuilder.AppendLine(); } stringBuilder.AppendLine(); stringBuilder.AppendLine(MxAhgHost.BuildReport(Localization.Current)); return stringBuilder.ToString(); } private static Row CheckMethod(Type type, string method, string name, string okDetail) { bool flag = Safe(() => type.GetMethod(method, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic) != null, fallback: false); return new Row(name, flag, flag ? okDetail : ("missing: " + type.Name + "." + method)); } private static Row CheckMethod(Type type, string method, Type[] args, string name, string okDetail) { bool flag = Safe(() => type.GetMethod(method, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, args, null) != null, fallback: false); return new Row(name, flag, flag ? okDetail : ("missing: " + type.Name + "." + method)); } private static Row CheckField(Type type, string field, string name) { bool flag = Safe(() => type.GetField(field, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic) != null, fallback: false); return new Row(name, flag, flag ? "ok" : ("missing: " + type.Name + "." + field)); } private static Row CheckMember(Type type, string member, string name) { bool flag = Safe(() => type.GetField(member, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic) != null || type.GetProperty(member, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic) != null || type.GetMethod("get_" + member, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic) != null, fallback: false); return new Row(name, flag, flag ? "ok" : ("missing: " + type.Name + "." + member)); } private static Row CheckEnum<T>(string value, string name) where T : struct { bool flag = Safe(() => Enum.IsDefined(typeof(T), value), fallback: false); return new Row(name, flag, flag ? value : ("missing: " + value)); } private static T Safe<T>(Func<T> func, T fallback) { try { return func(); } catch { return fallback; } } } public static class Features { private static readonly FieldRef<CharacterData, bool> InvincibleRef = AccessTools.FieldRefAccess<CharacterData, bool>("isInvincible"); private static readonly FieldInfo ClimbSpeedF = AccessTools.Field(typeof(CharacterClimbing), "climbSpeedMod"); private static readonly FieldInfo VineSpeedF = AccessTools.Field(typeof(CharacterVineClimbing), "climbSpeedMod"); private static readonly FieldInfo RopeSpeedF = AccessTools.Field(typeof(CharacterRopeHandling), "climbSpeedMod"); private static float _baseJumpImpulse = float.NaN; private static float[] _lockedStatuses; private static bool _godApplied; private static bool _speedApplied; private static bool _jumpApplied; private static bool _climbApplied; private static bool _vineApplied; private static bool _ropeApplied; private static float _itemTimer; private static float _timeOverrideTimer; private static float _adminTimer; private static float _cosmeticShuffleTimer; private static float _baseInteractionDistance = -1f; private static float _baseInteractionArea = -1f; private static bool _timeScaleApplied; private static readonly Dictionary<PointPing, float> PingBaseFrustumSizes = new Dictionary<PointPing, float>(); private static GameObject _cinematicObject; private static CameraOverride _cinematicOverride; private static Vector2 _cinematicLook; public static void Tick() { Character localCharacter = Character.localCharacter; if ((Object)(object)localCharacter == (Object)null || (Object)(object)localCharacter.data == (Object)null) { return; } if (NeedsMovementTick()) { try { ApplyMovement(localCharacter); } catch (Exception e) { Warn("movement", e); } } if (NeedsCheatTick()) { try { ApplyCheats(localCharacter); } catch (Exception e2) { Warn("cheats", e2); } } try { ApplyInfiniteItems(); } catch (Exception e3) { Warn("items", e3); } try { ApplyWorldOverrides(); } catch (Exception e4) { Warn("world", e4); } if (NeedsUtilityTick()) { try { ApplyUtilityModifiers(localCharacter); } catch (Exception e5) { Warn("utility", e5); } } try { ApplyAdminProtection(); } catch (Exception e6) { Warn("admin", e6); } try { ApplyCosmeticShuffle(); } catch (Exception e7) { Warn("cosmetics", e7); } try { GameApi.ApplyFrozenPlayers(Time.deltaTime); } catch (Exception e8) { Warn("freeze", e8); } try { GameApi.ApplyInventoryLocks(Time.deltaTime); } catch (Exception e9) { Warn("inventory-lock", e9); } } private static bool NeedsMovementTick() { if (!ModConfig.SpeedMod && !_speedApplied && !ModConfig.JumpMod && !_jumpApplied && !ModConfig.InfiniteJumps && !ModConfig.ClimbMod && !_climbApplied && !ModConfig.VineClimbMod && !_vineApplied && !ModConfig.RopeClimbMod) { return _ropeApplied; } return true; } private static bool NeedsCheatTick() { if (!ModConfig.GodMode && !_godApplied && !ModConfig.InfiniteStamina && !ModConfig.NoFallDamage && !ModConfig.NoFallingRagdoll && !ModConfig.NoSlipperySurfaces && !ModConfig.NoWeight && !ModConfig.NoStatusEffects && !ModConfig.NoInjury && !ModConfig.NoHunger && !ModConfig.NoCold && !ModConfig.NoPoison && !ModConfig.NoCurse && !ModConfig.NoDrowsy && !ModConfig.NoHot && !ModConfig.NoCrab && !ModConfig.NoThorns && !ModConfig.NoSpores && !ModConfig.NoWeb && !ModConfig.NoArrows && !ModConfig.NoPetrify && !ModConfig.NoFlyTrap && !ModConfig.LockStatus) { return _lockedStatuses != null; } return true; } private static bool NeedsUtilityTick() { if (!ModConfig.LongInteraction && !(_baseInteractionDistance >= 0f) && !ModConfig.GameSpeedMod && !_timeScaleApplied && !ModConfig.CinematicCamera && !((Object)(object)_cinematicObject != (Object)null) && !(Mathf.Abs(ModConfig.PingHandSizeMultiplier - 1f) >= 0.01f)) { return PingBaseFrustumSizes.Count > 0; } return true; } private static void ApplyInfiniteItems() { if (!ModConfig.InfiniteItems) { return; } _itemTimer += Time.deltaTime; if (!(_itemTimer < 0.5f)) { _itemTimer = 0f; float value = ((ModConfig.RechargeValue > 0f) ? ModConfig.RechargeValue : 999f); int num = GameApi.SlotCount(); for (int i = 0; i < num; i++) { GameApi.RechargeSlot(i, value); } } } private static void ApplyWorldOverrides() { if (!ModConfig.OverrideExpeditionTime) { _timeOverrideTimer = 0f; return; } _timeOverrideTimer += Time.deltaTime; if (_timeOverrideTimer < 0.5f) { return; } _timeOverrideTimer = 0f; if (ModConfig.ExpeditionTimeSeconds <= 0.01f) { float num = GameApi.ExpeditionTimeSeconds(); if (!(num > 0.01f)) { return; } ModConfig.ExpeditionTimeSeconds = num; } GameApi.SetExpeditionTime(ModConfig.ExpeditionTimeSeconds); } private static void ApplyAdminProtection() { if (!ModConfig.AdminProtectionEnabled) { _adminTimer = 0f; return; } _adminTimer += Time.deltaTime; if (!(_adminTimer < 2f)) { _adminTimer = 0f; GameApi.EnforceAdminProtection(); } } private static void ApplyCosmeticShuffle() { if (!ModConfig.RapidRandomOutfitColor) { _cosmeticShuffleTimer = 0f; return; } _cosmeticShuffleTimer += Time.unscaledDeltaTime; float num = Mathf.Clamp(ModConfig.RapidRandomOutfitColorInterval, 0.08f, 2f); if (!(_cosmeticShuffleTimer < num)) { _cosmeticShuffleTimer = 0f; GameApi.RandomizeOutfitAndColor(track: false); } } private static void ApplyMovement(Character c) { CharacterMovement val = c.refs?.movement; if ((Object)(object)val == (Object)null) { return; } if (ModConfig.SpeedMod) { val.movementModifier = ModConfig.SpeedAmount; _speedApplied = true; } else if (_speedApplied) { val.movementModifier = 1f; _speedApplied = false; } if (ModConfig.JumpMod) { if (float.IsNaN(_baseJumpImpulse) || _baseJumpImpulse <= 0f) { _baseJumpImpulse = ((val.jumpImpulse > 0f) ? val.jumpImpulse : 4f); } val.jumpImpulse = _baseJumpImpulse * ModConfig.JumpAmount; _jumpApplied = true; } else if (_jumpApplied) { if (!float.IsNaN(_baseJumpImpulse) && _baseJumpImpulse > 0f) { val.jumpImpulse = _baseJumpImpulse; } _jumpApplied = false; } if (ModConfig.InfiniteJumps) { c.data.jumpsRemaining = Mathf.Max(c.data.jumpsRemaining, 1); if (c.data.sinceJump > 0.28f) { c.data.sinceGrounded = Mathf.Min(c.data.sinceGrounded, 0.18f); } } ApplyClimbField<CharacterClimbing>(c, ClimbSpeedF, ModConfig.ClimbMod, ModConfig.ClimbAmount, ref _climbApplied); ApplyClimbField<CharacterVineClimbing>(c, VineSpeedF, ModConfig.VineClimbMod, ModConfig.VineClimbAmount, ref _vineApplied); ApplyClimbField<CharacterRopeHandling>(c, RopeSpeedF, ModConfig.RopeClimbMod, ModConfig.RopeClimbAmount, ref _ropeApplied); } private static void ApplyClimbField<T>(Character c, FieldInfo f, bool on, float amount, ref bool applied) where T : Component { if (f == null) { return; } T component = ((Component)c).GetComponent<T>(); if (!((Object)(object)component == (Object)null)) { if (on) { f.SetValue(component, amount); applied = true; } else if (applied) { f.SetValue(component, 1f); applied = false; } } } private static void ApplyCheats(Character c) { CharacterData data = c.data; CharacterAfflictions val = ((c.refs != null) ? c.refs.afflictions : null); if (ModConfig.GodMode) { InvincibleRef.Invoke(data) = true; _godApplied = true; } else if (_godApplied) { InvincibleRef.Invoke(data) = false; data.RecalculateInvincibility(); _godApplied = false; } if (ModConfig.InfiniteStamina) { data.currentStamina = 1f; data.extraStamina = Mathf.Max(data.extraStamina, 0f); } if (ModConfig.NoFallDamage) { data.fallSeconds = 0f; } if (ModConfig.NoFallingRagdoll) { data.fallSeconds = 0f; } if (ModConfig.NoSlipperySurfaces) { data.slippy = 0f; data.sinceFallSlide = Mathf.Max(data.sinceFallSlide, 2f); } if (!((Object)(object)val != (Object)null)) { return; } if (ModConfig.NoStatusEffects) { for (int i = 0; i < CharacterAfflictions.NumStatusTypes; i++) { val.SetStatus((STATUSTYPE)i, 0f, false); } try { val.RemoveAllThorns(); } catch { } } else { ClearBlockedStatus(val, (STATUSTYPE)0, ModConfig.NoInjury); ClearBlockedStatus(val, (STATUSTYPE)1, ModConfig.NoHunger); ClearBlockedStatus(val, (STATUSTYPE)2, ModConfig.NoCold); ClearBlockedStatus(val, (STATUSTYPE)3, ModConfig.NoPoison); ClearBlockedStatus(val, (STATUSTYPE)5, ModConfig.NoCurse); ClearBlockedStatus(val, (STATUSTYPE)6, ModConfig.NoDrowsy); ClearBlockedStatus(val, (STATUSTYPE)8, ModConfig.NoHot); ClearBlockedStatus(val, (STATUSTYPE)4, ModConfig.NoCrab); ClearBlockedStatus(val, (STATUSTYPE)9, ModConfig.NoThorns); ClearBlockedStatus(val, (STATUSTYPE)10, ModConfig.NoSpores); ClearBlockedStatus(val, (STATUSTYPE)11, ModConfig.NoWeb); ClearBlockedStatus(val, (STATUSTYPE)12, ModConfig.NoArrows); ClearBlockedStatus(val, (STATUSTYPE)13, ModConfig.NoPetrify); ClearBlockedStatus(val, (STATUSTYPE)14, ModConfig.NoFlyTrap); } if (ModConfig.NoWeight) { val.SetStatus((STATUSTYPE)7, 0f, true); } if (ModConfig.NoThorns) { GameApi.ClearThorns(c, track: false); } if (ModConfig.NoArrows) { GameApi.ClearArrows(c, track: false); } if (ModConfig.LockStatus) { if (_lockedStatuses == null && val.currentStatuses != null) { _lockedStatuses = (float[])val.currentStatuses.Clone(); } if (_lockedStatuses != null && val.currentStatuses != null) { Array.Copy(_lockedStatuses, val.currentStatuses, Mathf.Min(_lockedStatuses.Length, val.currentStatuses.Length)); } } else { _lockedStatuses = null; } } private static void ClearBlockedStatus(CharacterAfflictions affl, STATUSTYPE type, bool blocked) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) if (blocked) { affl.SetStatus(type, 0f, false); } } private static void ApplyUtilityModifiers(Character c) { ApplyInteractionRange(); ApplyGameSpeed(); ApplyCinematicCamera(c); ApplyPingHandScale(); } private static void ApplyInteractionRange() { Interaction instance = Interaction.instance; if (!((Object)(object)instance == (Object)null)) { if (_baseInteractionDistance < 0f) { _baseInteractionDistance = instance.distance; _baseInteractionArea = instance.area; } if (ModConfig.LongInteraction) { instance.distance = Mathf.Max(_baseInteractionDistance, ModConfig.InteractionDistance); instance.area = Mathf.Max(_baseInteractionArea, 1.25f); } else if (_baseInteractionDistance >= 0f) { instance.distance = _baseInteractionDistance; instance.area = _baseInteractionArea; } } } private static void ApplyGameSpeed() { if (ModConfig.GameSpeedMod) { Time.timeScale = Mathf.Clamp(ModConfig.GameSpeed, 0.05f, 5f); _timeScaleApplied = true; } else if (_timeScaleApplied) { Time.timeScale = 1f; _timeScaleApplied = false; } } private static void ApplyCinematicCamera(Character c) { //IL_016b: Unknown result type (might be due to invalid IL or missing references) //IL_0175: Unknown result type (might be due to invalid IL or missing references) //IL_017a: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Expected O, but got Unknown //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0085: 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_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: 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_025a: Unknown result type (might be due to invalid IL or missing references) //IL_026b: Unknown result type (might be due to invalid IL or missing references) //IL_0270: Unknown result type (might be due to invalid IL or missing references) //IL_0276: Unknown result type (might be due to invalid IL or missing references) //IL_027c: Unknown result type (might be due to invalid IL or missing references) //IL_0281: Unknown result type (might be due to invalid IL or missing references) if (!ModConfig.CinematicCamera) { DisableCinematicCamera(); return; } if ((Object)(object)_cinematicObject == (Object)null) { _cinematicObject = new GameObject("PEAK-MX Cinematic Camera"); Object.DontDestroyOnLoad((Object)(object)_cinematicObject); _cinematicOverride = _cinematicObject.AddComponent<CameraOverride>(); Transform val = (((Object)(object)MainCamera.instance != (Object)null) ? ((Component)MainCamera.instance).transform : ((Component)c).transform); _cinematicObject.transform.position = val.position; _cinematicObject.transform.rotation = val.rotation; Quaternion rotation = _cinematicObject.transform.rotation; Vector3 eulerAngles = ((Quaternion)(ref rotation)).eulerAngles; _cinematicLook = new Vector2(eulerAngles.y, eulerAngles.x); } _cinematicOverride.fov = Mathf.Clamp(ModConfig.CinematicCameraFov, 1f, 120f); float unscaledDeltaTime = Time.unscaledDeltaTime; _cinematicLook.x += Input.GetAxis("Mouse X") * 140f * unscaledDeltaTime; _cinematicLook.y -= Input.GetAxis("Mouse Y") * 140f * unscaledDeltaTime; _cinematicLook.y = Mathf.Clamp(_cinematicLook.y, -89f, 89f); _cinematicObject.transform.rotation = Quaternion.Euler(_cinematicLook.y, _cinematicLook.x, 0f); Vector3 zero = Vector3.zero; if (Input.GetKey((KeyCode)119)) { zero.z += 1f; } if (Input.GetKey((KeyCode)115)) { zero.z -= 1f; } if (Input.GetKey((KeyCode)100)) { zero.x += 1f; } if (Input.GetKey((KeyCode)97)) { zero.x -= 1f; } if (Input.GetKey((KeyCode)32) || Input.GetKey((KeyCode)101)) { zero.y += 1f; } if (Input.GetKey((KeyCode)306) || Input.GetKey((KeyCode)113)) { zero.y -= 1f; } float num = Mathf.Max(0.1f, ModConfig.CinematicCameraSpeed) * (Input.GetKey((KeyCode)304) ? 4f : 1f); Transform transform = _cinematicObject.transform; transform.position += _cinematicObject.transform.TransformDirection(((Vector3)(ref zero)).normalized) * num * unscaledDeltaTime; if ((Object)(object)MainCamera.instance != (Object)null) { MainCamera.instance.SetCameraOverride(_cinematicOverride); } } private static void DisableCinematicCamera() { if ((Object)(object)_cinematicObject == (Object)null) { return; } try { if ((Object)(object)MainCamera.instance != (Object)null) { MainCamera.instance.SetCameraOverride((CameraOverride)null); } } catch { } Object.Destroy((Object)(object)_cinematicObject); _cinematicObject = null; _cinematicOverride = null; } private static void ApplyPingHandScale() { float num = Mathf.Clamp(ModConfig.PingHandSizeMultiplier, 0.1f, 10f); if (Mathf.Abs(num - 1f) < 0.01f && PingBaseFrustumSizes.Count == 0) { return; } PointPing[] array = Object.FindObjectsByType<PointPing>((FindObjectsSortMode)0); foreach (PointPing val in array) { if (!((Object)(object)val == (Object)null)) { if (!PingBaseFrustumSizes.ContainsKey(val)) { PingBaseFrustumSizes[val] = Mathf.Max(0.001f, val.sizeOfFrustum); } val.sizeOfFrustum = PingBaseFrustumSizes[val] * num; } } if (!(Mathf.Abs(num - 1f) < 0.01f) || PingBaseFrustumSizes.Count <= 0) { return; } foreach (KeyValuePair<PointPing, float> pingBaseFrustumSize in PingBaseFrustumSizes) { if ((Object)(object)pingBaseFrustumSize.Key != (Object)null) { pingBaseFrustumSize.Key.sizeOfFrustum = pingBaseFrustumSize.Value; } } PingBaseFrustumSizes.Clear(); } private static void Warn(string where, Exception e) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Features:" + where + "] " + e.Message)); } } } public static class GameApi { public enum CosmeticCategory { Skin, Accessory, Eyes, Mouth, Outfit, Hat, Sash, Medal } public struct AdminListEntry { public string Key; public string Label; public AdminListEntry(string key, string label) { Key = key; Label = label; } } private struct AdminMotionSample { public Vector3 Position; public float Time; } private struct WorldObjectScanHit { public string Label; public Vector3 Position; public float Distance; } private struct SlotPrefabAccessor { public MethodInfo Getter; public FieldInfo Field; } public static readonly List<Item> Items = new List<Item>(); public static readonly List<string> ItemNames = new List<string>(); public static readonly List<Character> PlayerChars = new List<Character>(); public static readonly List<string> PlayerNames = new List<string>(); private static readonly HashSet<int> LocalCosmeticUnlocks = new HashSet<int>(); private static readonly HashSet<string> SessionBans = new HashSet<string>(); private static readonly Dictionary<string, string> SessionBanNames = new Dictionary<string, string>(); private static readonly HashSet<string> InventoryLocks = new HashSet<string>(); private static readonly Dictionary<string, string> InventoryLockNames = new Dictionary<string, string>(); private static readonly Dictionary<string, Vector3> FrozenPlayers = new Dictionary<string, Vector3>(); private static readonly List<string> FrozenKeysScratch = new List<string>(); private static readonly List<string> InventoryLockKeysScratch = new List<string>(); private static readonly Dictionary<string, AdminMotionSample> AdminMotion = new Dictionary<string, AdminMotionSample>(); private static readonly Dictionary<string, float> AdminMotionSuppressedUntil = new Dictionary<string, float>(); private static readonly Dictionary<string, int> AdminStrikes = new Dictionary<string, int>(); private static readonly Dictionary<string, string> AdminRareSlotState = new Dictionary<string, string>(); private static readonly Dictionary<string, string> AdminRareInventorySnapshot = new Dictionary<string, string>(); private static readonly Dictionary<string, List<float>> AdminRareItemEvents = new Dictionary<string, List<float>>(); private static readonly HashSet<string> AdminRareTouchedScratch = new HashSet<string>(); private static readonly List<string> AdminRareCurrentScratch = new List<string>(); private static readonly Dictionary<string, int> AdminRareCountsScratch = new Dictionary<string, int>(StringComparer.Ordinal); private static readonly Dictionary<string, string> AdminAmuletFirstOwnerScratch = new Dictionary<string, string>(StringComparer.Ordinal); private static readonly Dictionary<string, Character> AdminAmuletDuplicateTargetScratch = new Dictionary<string, Character>(StringComparer.Ordinal); private static readonly HashSet<string> AdminAmuletDuplicateSnapshot = new HashSet<string>(StringComparer.Ordinal); private static readonly List<string> AdminRareRemoveScratch = new List<string>(); public static readonly List<string> AdminProtectionLog = new List<string>(); private static float _freezeRpcTimer; private static float _inventoryLockTimer; private static float _knifeFightAt = -1f; private static int _knifeFightCountdownSecond = -1; private static bool _itemsEverLoaded; private const float AdminRareItemWindowSeconds = 10f; private const int AdminRareItemBurstThreshold = 3; private static readonly string[] AdminRareKeywords = new string[28] { "cursed", "curse", "skull", "pandora", "effigy", "faerie", "bugle", "warp compass", "amulet", "medallion", "talisman", "charm", "panacea", "cure-all", "cure all", "mystic", "mystical", "arcane", "healing gem", "прокля", "череп", "амулет", "медальон", "талисман", "панаце", "лекар", "исцел", "мист" }; private static Customization _customizationDb; private static readonly MethodInfo CustomGetData = typeof(CharacterCustomization).GetMethod("GetCustomizationData", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); private static readonly MethodInfo CustomSetData = typeof(CharacterCustomization).GetMethod("SetCustomizationData", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); private static readonly MethodInfo CustomSetSkin = typeof(CharacterCustomization).GetMethod("SetCharacterSkinColor", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); private static readonly MethodInfo CustomSetAccessory = typeof(CharacterCustomization).GetMethod("SetCharacterAccessory", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); private static readonly MethodInfo CustomSetEyes = typeof(CharacterCustomization).GetMethod("SetCharacterEyes", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); private static readonly MethodInfo CustomSetMouth = typeof(CharacterCustomization).GetMethod("SetCharacterMouth", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); private static readonly MethodInfo CustomSetOutfit = typeof(CharacterCustomization).GetMethod("SetCharacterOutfit", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); private static readonly MethodInfo CustomSetHat = typeof(CharacterCustomization).GetMethod("SetCharacterHat", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); private static readonly MethodInfo CustomSetSash = typeof(CharacterCustomization).GetMethod("SetCharacterSash", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); private static readonly MethodInfo CustomSetMedal = typeof(CharacterCustomization).GetMethod("SetCharacterMedal", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); private static readonly FieldInfo RunTimeField = typeof(RunManager).GetField("timeSinceRunStarted", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); private static readonly FieldInfo CharacterViewField = typeof(Character).GetField("view", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); private static readonly MethodInfo RocketExplodeRpcMethod = typeof(CharacterMovement).GetMethod("RocketExplodeRPC", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); private static readonly object SlotPrefabAccessorLock = new object(); private static readonly Dictionary<Type, SlotPrefabAccessor> SlotPrefabAccessors = new Dictionary<Type, SlotPrefabAccessor>(); private static readonly Segment[] WarpSegments; private static readonly string[] SegmentNamesEn; private static readonly string[] SegmentNamesRu; private const ItemTags ScoutAmuletTag = (ItemTags)512; public static readonly List<string> LuggageLabels; public static readonly List<Luggage> LuggageObjects; public static readonly List<string> WorldObjectLabels; private static readonly List<Vector3> WorldObjectPositions; public static readonly string[] StatusEn; public static readonly string[] StatusRu; private const int ArrowStatusIndex = 12; private const int PetrifyStatusIndex = 13; public static string AdminNoticeText { get; private set; } public static float AdminNoticeUntil { get; private set; } public static int SegmentCount => WarpSegments.Length; private static Item SlotPrefab(ItemSlot slot) { if (slot == null) { return null; } try { SlotPrefabAccessor slotPrefabAccessor = SlotPrefabAccessorFor(((object)slot).GetType()); if (slotPrefabAccessor.Getter != null) { object? obj = slotPrefabAccessor.Getter.Invoke(slot, null); return (Item)((obj is Item) ? obj : null); } if (slotPrefabAccessor.Field != null) { object? value = slotPrefabAccessor.Field.GetValue(slot); return (Item)((value is Item) ? value : null); } } catch (Exception ex) when (ex is MissingFieldException || ex is MissingMethodException || ex is TargetInvocationException || ex is ArgumentException || ex is InvalidOperationException) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogDebug((object)("[GameApi] ItemSlot prefab lookup failed: " + ex.Message)); } } return null; } private static SlotPrefabAccessor SlotPrefabAccessorFor(Type type) { if (type == null) { return default(SlotPrefabAccessor); } lock (SlotPrefabAccessorLock) { if (SlotPrefabAccessors.TryGetValue(type, out var value)) { return value; } SlotPrefabAccessor slotPrefabAccessor = new SlotPrefabAccessor { Getter = (type.GetProperty("prefab", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetGetMethod(nonPublic: true) ?? type.GetMethod("get_prefab", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)), Field = (type.GetField("prefab", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) ?? type.GetField("_prefab", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)) }; SlotPrefabAccessors[type] = slotPrefabAccessor; return slotPrefabAccessor; } } public static void LoadItems() { try { Items.Clear(); ItemNames.Clear(); Object obj = Resources.Load("ItemDatabase", typeof(ItemDatabase)); ItemDatabase val = (ItemDatabase)(object)((obj is ItemDatabase) ? obj : null); if ((Object)(object)val != (Object)null) { try { if (val.itemLookup != null) { foreach (Item value in val.itemLookup.Values) { Add(value); } } } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogDebug((object)("[GameApi] LoadItems itemLookup: " + ex.Message)); } } try { foreach (Item @object in ((DatabaseAsset<ItemDatabase, Item>)(object)(ObjectDatabaseAsset<ItemDatabase, Item>)(object)val).Objects) { Add(@object); } } catch (Exception ex2) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogDebug((object)("[GameApi] LoadItems ObjectDatabaseAsset: " + ex2.Message)); } } try { foreach (Item object2 in ((DatabaseAsset<ItemDatabase, Item>)(object)val).Objects) { Add(object2); } } catch (Exception ex3) { ManualLogSource log3 = Plugin.Log; if (log3 != null) { log3.LogDebug((object)("[GameApi] LoadItems DatabaseAsset: " + ex3.Message)); } } } try { Object[] array = Resources.LoadAll("0_Items", typeof(Item)); foreach (Object obj2 in array) { Add((Item)(object)((obj2 is Item) ? obj2 : null)); } } catch (Exception ex4) { ManualLogSource log4 = Plugin.Log; if (log4 != null) { log4.LogDebug((object)("[GameApi] LoadItems 0_Items: " + ex4.Message)); } } try { Object[] array = Resources.FindObjectsOfTypeAll(typeof(Item)); foreach (Object obj3 in array) { Add((Item)(object)((obj3 is Item) ? obj3 : null)); } } catch (Exception ex5) { ManualLogSource log5 = Plugin.Log; if (log5 != null) { log5.LogDebug((object)("[GameApi] LoadItems all objects: " + ex5.Message)); } } _itemsEverLoaded = ItemNames.Count > 0; ManualLogSource log6 = Plugin.Log; if (log6 != null) { log6.LogInfo((object)$"[GameApi] items loaded: {ItemNames.Count}"); } } catch (Exception ex6) { ManualLogSource log7 = Plugin.Log; if (log7 != null) { log7.LogWarning((object)("[GameApi] LoadItems: " + ex6.Message)); } } } public static bool EnsureItemsLoaded() { if (_itemsEverLoaded && ItemNames.Count > 0) { return false; } LoadItems(); return ItemNames.Count > 0; } private static void Add(Item it) { if ((Object)(object)it == (Object)null) { return; } try { if (IsInventorySpawnableItem(it)) { string name = it.GetName(); if (!string.IsNullOrEmpty(name) && !HasItemAlready(it, name)) { Items.Add(it); ItemNames.Add(name); } } } catch { } } private static bool HasItemAlready(Item item, string displayName) { for (int i = 0; i < Items.Count; i++) { Item val = Items[i]; if ((Object)(object)val == (Object)null) { continue; } try { if ((Object)(object)val == (Object)(object)item) { return true; } if (val.itemID == item.itemID && (Object)(object)((Component)val).gameObject != (Object)null && (Object)(object)((Component)item).gameObject != (Object)null && string.Equals(((Object)((Component)val).gameObject).name, ((Object)((Component)item).gameObject).name, StringComparison.Ordinal)) { return true; } } catch { } } return ItemNames.Contains(displayName); } private static bool IsInventorySpawnableItem(Item item) { try { if ((Object)(object)item == (Object)null || item.UIData == null || (Object)(object)((Component)item).gameObject == (Object)null) { return false; } if ((((Object)((Component)item).gameObject).name ?? "").IndexOf("BaseConstructable", StringComparison.OrdinalIgnoreCase) >= 0) { return false; } if (!HasResourcePrefab(item)) { return false; } if (!item.UIData.canPocket && !item.UIData.canBackpack) { return false; } return true; } catch { return false; } } private static bool CanPocketItem(int itemIndex) { try { return itemIndex >= 0 && itemIndex < Items.Count && (Object)(object)Items[itemIndex] != (Object)null && Items[itemIndex].UIData != null && Items[itemIndex].UIData.canPocket && HasResourcePrefab(Items[itemIndex]); } catch { return false; } } private static bool CanBackpackItem(int itemIndex) { try { return itemIndex >= 0 && itemIndex < Items.Count && (Object)(object)Items[itemIndex] != (Object)null && Items[itemIndex].UIData != null && Items[itemIndex].UIData.canBackpack && HasResourcePrefab(Items[itemIndex]); } catch { return false; } } private static bool CanBackSlotItem(int itemIndex) { try { return itemIndex >= 0 && itemIndex < Items.Count && Items[itemIndex] is Backpack && HasResourcePrefab(Items[itemIndex]); } catch { return false; } } private static bool IsScoutAmuletItem(Item item) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) try { if ((Object)(object)item == (Object)null) { return false; } if ((item.itemTags & 0x200) != 0) { return true; } string text = (item.GetName() + " " + ((Object)item).name + " " + (((Object)(object)((Component)item).gameObject != (Object)null) ? ((Object)((Component)item).gameObject).name : "")).ToLowerInvariant(); return text.IndexOf("amulet", StringComparison.Ordinal) >= 0 || text.IndexOf("medallion", StringComparison.Ordinal) >= 0 || text.IndexOf("talisman", StringComparison.Ordinal) >= 0 || text.IndexOf("charm", StringComparison.Ordinal) >= 0 || text.IndexOf("амулет", StringComparison.Ordinal) >= 0 || text.IndexOf("медальон", StringComparison.Ordinal) >= 0 || text.IndexOf("талисман", StringComparison.Ordinal) >= 0; } catch { return false; } } private static bool CanTempSlotItem(int itemIndex) { try { return itemIndex >= 0 && itemIndex < Items.Count && (Object)(object)Items[itemIndex] != (Object)null && (CanPocketItem(itemIndex) || IsScoutAmuletItem(Items[itemIndex])) && HasResourcePrefab(Items[itemIndex]); } catch { return false; } } private static bool HasResourcePrefab(Item item) { try { if ((Object)(object)item == (Object)null || (Object)(object)((Component)item).gameObject == (Object)null) { return false; } return HasResourcePrefabName(((Object)((Component)item).gameObject).name); } catch { return false; } } private static bool HasResourcePrefabName(string prefabName) { try { if (string.IsNullOrWhiteSpace(prefabName)) { return false; } return Resources.Load("0_Items/" + prefabName, typeof(GameObject)) != (Object)null; } catch { return false; } } private static int RandomItemIndexForSlot(bool backpack) { EnsureItemsLoaded(); List<int> list = new List<int>(); for (int i = 0; i < Items.Count; i++) { if (backpack ? CanBackpackItem(i) : CanPocketItem(i)) { list.Add(i); } } if (list.Count == 0) { return -1; } return list[Random.Range(0, list.Count)]; } public static Texture2D ItemIcon(int index) { try { Item val = ((index >= 0 && index < Items.Count) ? Items[index] : null); if ((Object)(object)val == (Object)null || val.UIData == null) { return null; } Texture2D icon = val.UIData.icon; if ((Object)(object)icon != (Object)null) { return icon; } return TryTextureMember(val.UIData, "altIcon", "colorBlindIcon", "sprite", "smallIcon", "inventoryIcon"); } catch { return null; } } public static ushort ItemIdAt(int index) { try { return (index >= 0 && index < Items.Count && (Object)(object)Items[index] != (Object)null) ? Items[index].itemID : ushort.MaxValue; } catch { return ushort.MaxValue; } } private static Texture2D TryTextureMember(object source, params string[] names) { if (source == null || names == null) { return null; } Type type = source.GetType(); foreach (string name in names) { try { FieldInfo field = type.GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field != null) { object value = field.GetValue(source); Texture2D val = (Texture2D)((value is Texture2D) ? value : null); if (val != null) { return val; } Sprite val2 = (Sprite)((value is Sprite) ? value : null); if (val2 != null && (Object)(object)val2.texture != (Object)null) { return val2.texture; } } } catch { } try { PropertyInfo property = type.GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (property != null) { object value2 = property.GetValue(source, null); Texture2D val3 = (Texture2D)((value2 is Texture2D) ? value2 : null); if (val3 != null) { return val3; } Sprite val4 = (Sprite)((value2 is Sprite) ? value2 : null); if (val4 != null && (Object)(object)val4.texture != (Object)null) { return val4.texture; } } } catch { } } return null; } public static bool SpawnToSlot(int itemIndex, int slot) { try { Player localPlayer = Player.localPlayer; if ((Object)(object)localPlayer == (Object)null || localPlayer.itemSlots == null) { return false; } if (slot < 0 || slot >= localPlayer.itemSlots.Length) { return false; } if (itemIndex < 0 || itemIndex >= Items.Count) { return false; } if (!CanPocketItem(itemIndex)) { return false; } SetSlotItem(localPlayer.itemSlots[slot], Items[itemIndex]); SyncInventory(localPlayer); return true; } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[GameApi] SpawnToSlot: " + ex.Message)); } return false; } } public static bool ClearSlot(int slot) { try { Player localPlayer = Player.localPlayer; if ((Object)(object)localPlayer == (Object)null || localPlayer.itemSlots == null || slot < 0 || slot >= localPlayer.itemSlots.Length) { return false; } ClearItemSlot(localPlayer.itemSlots[slot]); SyncInventory(localPlayer); return true; } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[GameApi] ClearSlot: " + ex.Message)); } return false; } } private static void SyncInventory(Player p) { SyncInventory(p, (RpcTarget)1); } private static void SetSlotItem(ItemSlot slot, Item prefab) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Expected O, but got Unknown //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) if (slot != null && !((Object)(object)prefab == (Object)null)) { ItemInstanceData val = new ItemInstanceData(Guid.NewGuid()); BackpackSlot val2 = (BackpackSlot)(object)((slot is BackpackSlot) ? slot : null); if (val2 != null) { Backpack val3 = (Backpack)(object)((prefab is Backpack) ? prefab : null); val2.backpackType = (BackpackType)((val3 != null) ? ((int)val3.backpackType) : 0); } slot.SetItem(prefab, val); ItemInstanceDataHandler.AddInstanceData(val); } } private static bool BackpackSlotSupportsStorage(BackpackSlot slot) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Invalid comparison between Unknown and I4 //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Invalid comparison between Unknown and I4 try { if (slot == null || ((ItemSlot)slot).IsEmpty()) { return false; } Item obj = SlotPrefab((ItemSlot)(object)slot); Backpack val = (Backpack)(object)((obj is Backpack) ? obj : null); if (val == null) { return false; } if ((int)slot.backpackType == 3 || (int)slot.backpackType == 4) { return false; } return val.slotCount > 0; } catch { return false; } } private static void ClearItemSlot(ItemSlot slot) { if (slot != null) { slot.EmptyOut(); } } private static void SyncInventory(Player p, RpcTarget target) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) byte[] array = IBinarySerializable.ToManagedArray<InventorySyncData>(new InventorySyncData(p.itemSlots, p.backpackSlot, p.tempFullSlot)); ((MonoBehaviourPun)p).photonView.RPC("SyncInventoryRPC", target, new object[2] { array, true }); } private static Player PlayerOf(Character c) { try { return ((Object)(object)c != (Object)null) ? c.player : null; } catch { return null; } } private static bool IsLocal(Character c) { try { return (Object)(object)c == (Object)null || c.IsLocal || (Object)(object)c == (Object)(object)Character.localCharacter; } catch { return (Object)(object)c == (Object)null || (Object)(object)c == (Object)(object)Character.localCharacter; } } public static bool IsHost() { try { return PhotonNetwork.IsMasterClient; } catch { return PhotonNetwork.IsMasterClient; } } private static bool RequireHostForRemote(Character target, string action) { return true; } private static bool RequireHostAction(string action) { return true; } private static void LogHostOnly(string action, Character target) { string text = (((Object)(object)target != (Object)null) ? SafeCharacterName(target) : ""); string text2 = (string.IsNullOrWhiteSpace(text) ? (action + ": host only") : (action + ": host only for " + text)); AddAdminLog(text2); ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[GameApi] " + text2)); } } private static CharacterCustomization LocalCustomization() { try { return (!((Object)(object)Character.localCharacter != (Object)null)) ? null : Character.localCharacter.refs?.customization; } catch { return null; } } private static Customization CustomizationDb() { try { if ((Object)(object)_customizationDb != (Object)null && HasAnyCosmeticOptions(_customizationDb)) { return _customizationDb; } try { Customization instance = Singleton<Customization>.Instance; if ((Object)(object)instance != (Object)null && HasAnyCosmeticOptions(instance)) { _customizationDb = instance; return _customizationDb; } } catch { } Customization[] source = Resources.FindObjectsOfTypeAll<Customization>(); _customizationDb = source.Where(HasAnyCosmeticOptions).OrderByDescending(TotalCosmeticOptionCount).FirstOrDefault() ?? source.FirstOrDefault(); return _customizationDb; } catch { return null; } } private static bool HasAnyCosmeticOptions(Customization db) { return TotalCosmeticOptionCount(db) > 0; } private static int TotalCosmeticOptionCount(Customization db) { if ((Object)(object)db == (Object)null) { return 0; } int num = 0; try { int num2 = num; CustomizationOption[] skins = db.skins; num = num2 + ((skins != null) ? skins.Length : 0); } catch { } try { int num3 = num; CustomizationOption[] accessories = db.accessories; num = num3 + ((accessories != null) ? accessories.Length : 0); } catch { } try { int num4 = num; CustomizationOption[] eyes = db.eyes; num = num4 + ((eyes != null) ? eyes.Length : 0); } catch { } try { int num5 = num; CustomizationOption[] mouths = db.mouths; num = num5 + ((mouths != null) ? mouths.Length : 0); } catch { } try { int num6 = num; CustomizationOption[] fits = db.fits; num = num6 + ((fits != null) ? fits.Length : 0); } catch { } try { int num7 = num; CustomizationOption[] hats = db.hats; num = num7 + ((hats != null) ? hats.Length : 0); } catch { } try { int num8 = num; CustomizationOption[] sashes = db.sashes; num = num8 + ((sashes != null) ? sashes.Length : 0); } catch { } try { int num9 = num; CustomizationOption[] medals = db.medals; num = num9 + ((medals != null) ? medals.Length : 0); } catch { } return num; } public static bool SpawnToSlotFor(Character target, int itemIndex, int slot) { try { if (IsLocal(target)) { return SpawnToSlot(itemIndex, slot); } if (!RequireHostForRemote(target, "inventory spawn")) { return false; } Player val = PlayerOf(target); if ((Object)(object)val == (Object)null || val.itemSlots == null) { return false; } if (slot < 0 || slot >= val.itemSlots.Length) { return false; } if (itemIndex < 0 || itemIndex >= Items.Count) { return false; } if (!CanPocketItem(itemIndex)) { return false; } SetSlotItem(val.itemSlots[slot], Items[itemIndex]); SyncInventory(val, (RpcTarget)0); return true; } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[GameApi] SpawnToSlotFor: " + ex.Message)); } return false; } } public static string SmartSpawnItem(Character target, int itemIndex) { //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_0110: 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_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) try { EnsureItemsLoaded(); Character val = target ?? Character.localCharacter; Player val2 = TargetPlayer(val); if ((Object)(object)val2 == (Object)null || itemIndex < 0 || itemIndex >= Items.Count || (Object)(object)Items[itemIndex] == (Object)null) { return "failed"; } if (!RequireHostForRemote(val, "smart inventory spawn")) { return "failed"; } if (CanPocketItem(itemIndex) && val2.itemSlots != null) { for (int i = 0; i < val2.itemSlots.Length; i++) { if (val2.itemSlots[i] != null && val2.itemSlots[i].IsEmpty() && SpawnToSlotFor(val, itemIndex, i)) { return "slot:" + (i + 1); } } } Vector3 val3 = SafePosition(val) + Vector3.up * 0.7f; try { val3 += ((Component)val).transform.forward * 1.1f; } catch { } if (SpawnWorldItem(itemIndex, val3, Quaternion.identity)) { return "ground"; } } catch (Exception e) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[GameApi] SmartSpawnItem: " + RootExceptionMessage(e))); } } return "failed"; } public static bool ClearSlotFor(Character target, int slot) { try { if (IsLocal(target)) { return ClearSlot(slot); } if (!RequireHostForRemote(target, "inventory clear")) { return false; } Player val = PlayerOf(target); if ((Object)(object)val == (Object)null || val.itemSlots == null || slot < 0 || slot >= val.itemSlots.Length) { return false; } ClearItemSlot(val.itemSlots[slot]); SyncInventory(val, (RpcTarget)0); return true; } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[GameApi] ClearSlotFor: " + ex.Message)); } return false; } } public static int SlotCount() { return SlotCountFor(Player.localPlayer); } public static int SlotCountFor(Character c) { return SlotCountFor(PlayerOf(c)); } private static int SlotCountFor(Player p) { try { return ((Object)(object)p != (Object)null && p.itemSlots != null) ? p.itemSlots.Length : 0; } catch { return 0; } } private static Player TargetPlayer(Character c) { return PlayerOf(c) ?? Player.localPlayer; } public static string DescribeSlot(Character c, int slot) { try { Player val = TargetPlayer(c); if ((Object)(object)val == (Object)null || val.itemSlots == null || slot < 0 || slot >= val.itemSlots.Length) { return ""; } Item val2 = SlotPrefab(val.itemSlots[slot]); if ((Object)(object)val2 == (Object)null) { return "-"; } string name = val2.GetName(); return string.IsNullOrWhiteSpace(name) ? ((Object)val2).name : name; } catch { return ""; } } public static string DescribeBackSlot(Character c) { try { Player val = TargetPlayer(c); BackpackSlot val2 = (((Object)(object)val != (Object)null) ? val.backpackSlot : null); if (val2 == null || ((ItemSlot)val2).IsEmpty()) { return "-"; } Item val3 = SlotPrefab((ItemSlot)(object)val2); string text = (((Object)(object)val3 != (Object)null) ? val3.GetName() : ""); if (string.IsNullOrWhiteSpace(text) && (Object)(object)val3 != (Object)null) { text = ((Object)val3).name; } if (string.IsNullOrWhiteSpace(text)) { text = ((ItemSlot)val2).GetPrefabName(); } return text; } catch { return ""; } } public static string DescribeTempSlot(Character c) { try { Player val = TargetPlayer(c); ItemSlot val2 = (((Object)(object)val != (Object)null) ? val.tempFullSlot : null); if (val2 == null || val2.IsEmpty()) { return "-"; } Item val3 = SlotPrefab(val2); if ((Object)(object)val3 == (Object)null) { return "-"; } string name = val3.GetName(); return string.IsNullOrWhiteSpace(name) ? ((Object)val3).name : name; } catch { return ""; } } public static bool SpawnToBackSlotFor(Character target, int itemIndex) { try { if (!RequireHostForRemote(target, "back slot spawn")) { return false; } if (!CanBackSlotItem(itemIndex)) { return false; } Player val = TargetPlayer(target); if ((Object)(object)val == (Object)null || val.backpackSlot == null) { return false; } SetSlotItem((ItemSlot)(object)val.backpackSlot, Items[itemIndex]); SyncTargetInventory(target); return true; } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[GameApi] SpawnToBackSlotFor: " + ex.Message)); } return false; } } public static bool ClearBackSlotFor(Character target) { try { if (!RequireHostForRemote(target, "back slot clear")) { return false; } Player val = TargetPlayer(target); if ((Object)(object)val == (Object)null || val.backpackSlot == null) { return false; } ClearItemSlot((ItemSlot)(object)val.backpackSlot); SyncTargetInventory(target); return true; } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[GameApi] ClearBackSlotFor: " + ex.Message)); } return false; } } public static void RechargeBackSlotFor(Character target, float value) { try { if (RequireHostForRemote(target, "back slot recharge")) { Player val = TargetPlayer(target); if (!((Object)(object)val == (Object)null) && val.backpackSlot != null && !((ItemSlot)val.backpackSlot).IsEmpty()) { RechargeItemSlotData((ItemSlot)(object)val.backpackSlot, value); SyncTargetInventory(target); } } } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[GameApi] RechargeBackSlotFor: " + ex.Message)); } } } public static bool SpawnToTempSlotFor(Character target, int itemIndex) { try { if (!RequireHostForRemote(target, "temporary slot spawn")) { return false; } if (!CanTempSlotItem(itemIndex)) { return false; } Player val = TargetPlayer(target); if ((Object)(object)val == (Object)null || val.tempFullSlot == null) { return false; } SetSlotItem(val.tempFullSlot, Items[itemIndex]); SyncTargetInventory(target); return true; } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[GameApi] SpawnToTempSlotFor: " + ex.Message)); } return false; } } public static bool ClearTempSlotFor(Character target) { try { if (!RequireHostForRemote(target, "temporary slot clear")) { return false; } Player val = TargetPlayer(target); if ((Object)(object)val == (Object)null || val.tempFullSlot == null) { return false; } ClearItemSlot(val.tempFullSlot); SyncTargetInventory(target); return true; } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[GameApi] ClearTempSlotFor: " + ex.Message)); } return false; } } public static void RechargeTempSlotFor(Character target, float value) { try { if (RequireHostForRemote(target, "temporary slot recharge")) { Player val = TargetPlayer(target); if (!((Object)(object)val == (Object)null) && val.tempFullSlot != null && !val.tempFullSlot.IsEmpty()) { RechargeItemSlotData(val.tempFullSlot, value); SyncTargetInventory(target); } } } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[GameApi] RechargeTempSlotFor: " + ex.Message)); } } } public static bool HasBackpack(Character c) { try { Player val = TargetPlayer(c); return (Object)(object)val != (Object)null && val.backpackSlot != null && !((ItemSlot)val.backpackSlot).IsEmpty() && ((ItemSlot)val.backpackSlot).data != null; } catch { return false; } } public static int BackpackSlotCount(Character c) { BackpackData val = BackpackDataFor(c, create: false); if (val == null || val.itemSlots == null) { return 0; } return val.itemSlots.Length; } public static string DescribeBackpackSlot(Character c, int slot) { try { BackpackData val = BackpackDataFor(c, create: false); if (val == null || val.itemSlots == null || slot < 0 || slot >= val.itemSlots.Length) { return ""; } Item val2 = SlotPrefab(val.itemSlots[slot]); if ((Object)(object)val2 == (Object)null) { return "-"; } string name = val2.GetName(); return string.IsNullOrWhiteSpace(name) ? ((Object)val2).name : name; } catch { return ""; } } public static bool SpawnToBackpackSlotFor(Character target, int itemIndex, int slot) { try { if (!RequireHostForRemote(target, "backpack spawn")) { return false; } if (itemIndex < 0 || itemIndex >= Items.Count) { return false; } if (!CanBackpackItem(itemIndex)) { return false; } BackpackData val = BackpackDataFor(target, create: true); if (val == null || val.itemSlots == null || slot < 0 || slot >= val.itemSlots.Length) { return false; } SetSlotItem(val.itemSlots[slot], Items[itemIndex]); SyncTargetInventory(target); return true; } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[GameApi] SpawnToBackpackSlotFor: " + ex.Message)); } return false; } } public static bool ClearBackpackSlotFor(Character target, int slot) { try { if (!RequireHostForRemote(target, "backpack clear")) { return false; } BackpackData val = BackpackDataFor(target, create: false); if (val == null || val.itemSlots == null || slot < 0 || slot >= val.itemSlots.Length) { return false; } ClearItemSlot(val.itemSlots[slot]); SyncTargetInventory(target); return true; } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[GameApi] ClearBackpackSlotFor: " + ex.Message)); } return false; } } public static void RechargeBackpackSlotFor(Character target, int slot, float value) { try { if (RequireHostForRemote(target, "backpack recharge")) { BackpackData val = BackpackDataFor(target, create: false); if (val != null && val.itemSlots != null && slot >= 0 && slot < val.itemSlots.Length) { RechargeItemSlotData(val.itemSlots[slot], value); SyncTargetInventory(target); } } } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[GameApi] RechargeBackpackSlotFor: " + ex.Message)); } } } private static BackpackData BackpackDataFor(Character c, bool create) { try { Player val = TargetPlayer(c); if ((Object)(object)val == (Object)null || val.backpackSlot == null || ((ItemSlot)val.backpackSlot).IsEmpty() || ((ItemSlot)val.backpackSlot).data == null) { return null; } if (!BackpackSlotSupportsStorage(val.backpackSlot)) { return null; } BackpackData result = default(BackpackData); if (((ItemSlot)val.backpackSlot).data.TryGetDataEntry<BackpackData>((DataEntryKey)7, ref result)) { return result; } return create ? ((ItemSlot)val.backpackSlot).data.RegisterNewEntry<BackpackData>((DataEntryKey)7) : null; } catch { return null; } } private static void SyncTargetInventory(Character c) { Player val = TargetPlayer(c); if (!((Object)(object)val == (Object)null)) { SyncInventory(val, (RpcTarget)(IsLocal(c) ? 1 : 0)); } } public static CustomizationOption[] GetCosmeticOptions(CosmeticCategory category) { try { Customization val = CustomizationDb(); if ((Object)(object)val == (Object)null) { return Array.Empty<CustomizationOption>(); } return category switch { CosmeticCategory.Skin => val.skins ?? Array.Empty<CustomizationOption>(), CosmeticCategory.Accessory => val.accessories ?? Array.Empty<CustomizationOption>(), CosmeticCategory.Eyes => val.eyes ?? Array.Empty<CustomizationOption>(), CosmeticCategory.Mouth => val.mouths ?? Array.Empty<CustomizationOption>(), CosmeticCategory.Outfit => val.fits ?? Array.Empty<CustomizationOption>(), CosmeticCategory.Hat => val.hats ?? Array.Empty<CustomizationOption>(), CosmeticCategory.Sash => val.sashes ?? Array.Empty<CustomizationOption>(), CosmeticCategory.Medal => val.medals ?? Array.Empty<CustomizationOption>(), _ => Array.Empty<CustomizationOption>(), }; } catch { return Array.Empty<CustomizationOption>(); } } public static int GetCurrentCosmeticIndex(CosmeticCategory category) { try { CharacterCustomization val = LocalCustomization(); if ((Object)(object)val == (Object)null) { return -1; } CharacterCustomizationData customizationData = GetCustomizationData(val); return category switch { CosmeticCategory.Skin => customizationData.currentSkin, CosmeticCategory.Accessory => customizationData.currentAccessory, CosmeticCategory.Eyes => customizationData.currentEyes, CosmeticCategory.Mouth => customizationData.currentMouth, CosmeticCategory.Outfit => customizationData.currentOutfit, CosmeticCategory.Hat => customizationData.currentHat, CosmeticCategory.Sash => customizationData.currentSash, CosmeticCategory.Medal => customizationData.currentMedal, _ => -1, }; } catch { return -1; } } public static int FindBlankCosmeticIndex(CosmeticCategory category) { CustomizationOption[] cosmeticOptions = GetCosmeticOptions(category); for (int i = 0; i < cosmeticOptions.Length; i++) { try { if ((Object)(object)cosmeticOptions[i] != (Object)null && cosmeticOptions[i].isBlank) { return i; } } catch { } } return -1; } public static bool IsCosmeticOptionGrantable(CosmeticCategory category, int index) { CustomizationOption[] cosmeticOptions = GetCosmeticOptions(category); if (index >= 0 && index < cosmeticOptions.Length) { return IsCosmeticOptionGrantable(category, cosmeticOptions[index]); } return false; } public static bool IsCosmeticOptionSelectable(CosmeticCategory category, int index) { CustomizationOption[] cosmeticOptions = GetCosmeticOptions(category); if (index >= 0 && index < cosmeticOptions.Length) { return IsCosmeticOptionSelectable(category, cosmeticOptions[index]); } return false; } public static bool IsCosmeticOptionSelectable(CosmeticCategory category, CustomizationOption option) { return (Object)(object)option != (Object)null; } public static bool IsCosmeticOptionGrantable(CosmeticCategory category, CustomizationOption option) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)option == (Object)null) { return false; } try { if (option.isBlank) { return true; } if (option.type != ExpectedCosmeticType(category)) { return false; } if (!HasKnownCosmeticRequirement(option)) { return false; } if (!HasCosmeticUnlockRequirement(option)) { return false; } return HasCosmeticVisual(category, option); } catch { return false; } } private static Type ExpectedCosmeticType(CosmeticCategory category) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0051: 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) return (Type)(category switch { CosmeticCategory.Skin => 0, CosmeticCategory.Accessory => 10, CosmeticCategory.Eyes => 20, CosmeticCategory.Mouth => 30, CosmeticCategory.Outfit => 40, CosmeticCategory.Hat => 50, CosmeticCategory.Sash => 60, CosmeticCategory.Medal => 70, _ => 0, }); } private static bool HasCosmeticVisual(CosmeticCategory category, CustomizationOption option) { //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_006f: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)option == (Object)null) { return false; } if ((Object)(object)option.texture != (Object)null) { return true; } if ((Object)(object)option.fitMesh != (Object)null || (Object)(object)option.fitMaterial != (Object)null || (Object)(object)option.fitMaterialShoes != (Object)null) { return true; } if ((Object)(object)option.fitMaterialOverridePants != (Object)null || (Object)(object)option.fitMaterialOverrideHat != (Object)null) { return true; } if (category == CosmeticCategory.Skin) { Color color = option.color; if (!(color.a > 0.01f) && !(color.r > 0.01f) && !(color.g > 0.01f)) { return color.b > 0.01f; } return true; } return false; } private static bool HasKnownCosmeticRequirement(CustomizationOption option) { string a = ((object)Unsafe.As<CUSTOMREQUIREMENT, CUSTOMREQUIREMENT>(ref option.customRequirement)/*cast due to .constrained prefix*/).ToString(); if (!string.Equals(a, "None", StringComparison.OrdinalIgnoreCase) && !string.Equals(a, "Goat", StringComparison.OrdinalIgnoreCase)) { return string.Equals(a, "Crown", StringComparison.OrdinalIgnoreCase); } return true; } private static bool HasCosmeticUnlockRequirement(CustomizationOption option) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)option == (Object)null || option.isBlank) { return false; } if (option.requiresAscent) { return true; } if (option.requiresSteamStat) { return true; } if ((int)option.requiredAchievement != 0) { return true; } string a = ((object)Unsafe.As<CUSTOMREQUIREMENT, CUSTOMREQUIREMENT>(ref option.customRequirement)/*cast due to .constrained prefix*/).ToString(); if (!string.Equals(a, "Goat", StringComparison.OrdinalIgnoreCase)) { return string.Equals(a, "Crown", StringComparison.OrdinalIgnoreCase); } return true; } public static bool SetCosmetic(CosmeticCategory category, int index) { try { CharacterCustomization val = LocalCustomization(); CustomizationOption[] cosmeticOptions = GetCosmeticOptions(category); if ((Object)(object)val == (Object)null || index < 0 || index >= cosmeticOptions.Length) { return false; } if (!IsCosmeticOptionSelectable(category, cosmeticOptions[index])) { return false; } CharacterCustomizationData customizationData = GetCustomizationData(val); switch (category) { case CosmeticCategory.Skin: customizationData.currentSkin = index; InvokeCustomizationSetter(val, CustomSetSkin, index); break; case CosmeticCategory.Accessory: customizationData.currentAccessory = index; InvokeCustomizationSetter(val, CustomSetAccessory, index); break; case CosmeticCategory.