Decompiled source of gtfo selectable scopes v1.3.0
SelectableScopes.dll
Decompiled 2 days ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using System.Text.Json; using System.Text.Json.Nodes; using Agents; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using BepInEx.Unity.IL2CPP; using CellMenu; using GTFO.API; using GameData; using Gear; using HarmonyLib; using Il2CppInterop.Runtime; using Il2CppInterop.Runtime.InteropTypes; using Il2CppInterop.Runtime.InteropTypes.Arrays; using Il2CppSystem; using Il2CppSystem.Collections.Generic; using Localization; using Player; using SNetwork; using SelectableScopes.Patches; using TMPro; using UnityEngine; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")] [assembly: AssemblyCompany("SelectableScopes")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+d83cc9581002173f38dcd2e549c37aed5c200581")] [assembly: AssemblyProduct("SelectableScopes")] [assembly: AssemblyTitle("SelectableScopes")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] namespace SelectableScopes { internal enum SightEditResult { Unchanged, Updated, Failed } internal static class GearJsonEditor { internal const int SightComponentId = 21; internal const int CategoryComponentId = 2; internal const string DefaultSight = "Default"; internal static bool TryGetComponentValue(string gearJson, int componentId, out long value) { value = 0L; if (!TryParse(gearJson, out var root)) { return false; } JsonObject jsonObject = Components(root); if (jsonObject == null) { return false; } foreach (JsonObject item in ComponentObjects(jsonObject)) { if (ReadInt(item["c"]) == componentId) { long? num = ReadLong(item["v"]); if (!num.HasValue) { return false; } value = num.Value; return true; } } return false; } internal static string GetDisplayName(string gearJson) { if (!TryParse(gearJson, out var root)) { return null; } if (!(root["Name"] is JsonValue jsonValue) || !jsonValue.TryGetValue<string>(out string value)) { return null; } if (!string.IsNullOrWhiteSpace(value)) { return value; } return null; } internal static SightEditResult TrySetSight(string gearJson, long sightId, out string updated) { updated = gearJson; if (!TryParse(gearJson, out var root)) { return SightEditResult.Failed; } JsonObject jsonObject = Components(root); if (jsonObject == null) { return SightEditResult.Failed; } foreach (JsonObject item in ComponentObjects(jsonObject)) { if (ReadInt(item["c"]) == 21) { if (ReadLong(item["v"]) == sightId) { return SightEditResult.Unchanged; } item["v"] = JsonValue.Create(sightId); updated = root.ToJsonString(); return SightEditResult.Updated; } } int num = ReadInt(jsonObject["Length"]) ?? CountComponents(jsonObject); if (num < 0 || num > 25) { return SightEditResult.Failed; } string propertyName = ((char)(97 + num)).ToString(); if (jsonObject[propertyName] != null) { return SightEditResult.Failed; } jsonObject[propertyName] = new JsonObject { ["c"] = JsonValue.Create(21), ["v"] = JsonValue.Create(sightId) }; jsonObject["Length"] = JsonValue.Create(num + 1); updated = root.ToJsonString(); return SightEditResult.Updated; } private static bool TryParse(string gearJson, out JsonObject root) { root = null; if (string.IsNullOrEmpty(gearJson)) { return false; } try { root = JsonNode.Parse(gearJson) as JsonObject; return root != null; } catch (JsonException) { return false; } } private static JsonObject Components(JsonObject root) { return root["Packet"]?["Comps"] as JsonObject; } private static IEnumerable<JsonObject> ComponentObjects(JsonObject comps) { foreach (KeyValuePair<string, JsonNode> comp in comps) { if (comp.Value is JsonObject jsonObject) { yield return jsonObject; } } } private static int CountComponents(JsonObject comps) { int num = 0; foreach (JsonObject item in ComponentObjects(comps)) { _ = item; num++; } return num; } private static int? ReadInt(JsonNode node) { long? num = ReadLong(node); if (!num.HasValue || num.Value < int.MinValue || num.Value > int.MaxValue) { return null; } return (int)num.Value; } private static long? ReadLong(JsonNode node) { if (!(node is JsonValue jsonValue)) { return null; } if (jsonValue.TryGetValue<long>(out var value)) { return value; } if (jsonValue.TryGetValue<int>(out var value2)) { return value2; } if (jsonValue.TryGetValue<bool>(out var value3)) { return value3 ? 1 : 0; } return null; } internal static string ComponentSignature(string gearJson) { if (!TryParse(gearJson, out var root)) { return null; } JsonObject jsonObject = Components(root); if (jsonObject == null) { return null; } Dictionary<int, long> dictionary = new Dictionary<int, long>(); foreach (JsonObject item in ComponentObjects(jsonObject)) { int? num = ReadInt(item["c"]); long? num2 = ReadLong(item["v"]); if (num.HasValue && num2.HasValue && num.Value != 21 && num2.Value != 0L) { dictionary[num.Value] = num2.Value; } } return FormatSignature(dictionary); } internal static string FormatSignature(Dictionary<int, long> values) { if (values == null || values.Count == 0) { return null; } List<int> list = new List<int>(values.Keys); list.Sort(); StringBuilder stringBuilder = new StringBuilder(list.Count * 8); for (int i = 0; i < list.Count; i++) { if (i != 0) { stringBuilder.Append(';'); } int key = list[i]; stringBuilder.Append(key.ToString(CultureInfo.InvariantCulture)); stringBuilder.Append(':'); stringBuilder.Append(values[key].ToString(CultureInfo.InvariantCulture)); } return stringBuilder.ToString(); } } [BepInPlugin("SelectableScopes", "Selectable Scopes", "1.0.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] public sealed class Plugin : BasePlugin { public const string Guid = "SelectableScopes"; public const string Version = "1.0.0"; internal static Plugin Instance { get; private set; } internal static ManualLogSource LogSource { get; private set; } internal static ConfigEntry<bool> Enabled { get; private set; } internal static bool Ready { get; set; } public override void Load() { //IL_0036: 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) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_007b: 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_009b: 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_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_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_010b: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Unknown result type (might be due to invalid IL or missing references) //IL_017b: Unknown result type (might be due to invalid IL or missing references) Instance = this; LogSource = ((BasePlugin)this).Log; Enabled = ((BasePlugin)this).Config.Bind<bool>("General", "Enabled", true, "When true, each weapon section below can replace that weapon's sight. Default leaves the weapon unchanged."); Harmony val = new Harmony("SelectableScopes"); val.PatchAll(typeof(LoadoutPagePatch)); val.PatchAll(typeof(LobbyBarPatch)); val.PatchAll(typeof(LobbyBarIntroPatch)); val.PatchAll(typeof(LobbyBarSpawnPatch)); val.PatchAll(typeof(WeaponPickedPatch)); val.PatchAll(typeof(LobbyBarLifetimePatch)); val.PatchAll(typeof(MenuTogglePatch)); val.PatchAll(typeof(MenuEnterPatch)); val.PatchAll(typeof(MenuExitPatch)); val.PatchAll(typeof(GearSpawnPatch)); val.PatchAll(typeof(ClipKeepPatch)); val.PatchAll(typeof(ClipWieldPatch)); val.PatchAll(typeof(ClipSpawnedPatch)); val.PatchAll(typeof(ClipUpdatePatch)); val.PatchAll(typeof(ClipStorePatch)); val.PatchAll(typeof(GearIconPatch)); val.PatchAll(typeof(ScopeModelAlignPatch)); val.PatchAll(typeof(ScopeModelSpawnPatch)); val.PatchAll(typeof(ScopeModelForgetPatch)); val.PatchAll(typeof(ScopeCrosshairPreparePatch)); val.PatchAll(typeof(ScopeCrosshairKeepPatch)); val.PatchAll(typeof(ScopeCrosshairLayerPatch)); EventAPI.OnAssetsLoaded += ScopeCatalog.BuildAndApply; ((BasePlugin)this).Log.LogInfo((object)"Selectable Scopes loaded. Weapon entries are written after game data loads."); } } internal static class ScopeAlignment { private sealed class ReloadWatch { public bool SawReload; public float BestScore; public string BestName = "none"; public Vector3 SightPosition; public Quaternion SightRotation; public readonly List<Transform> Nodes = new List<Transform>(); public readonly List<Vector3> LocalPositions = new List<Vector3>(); public readonly List<Quaternion> LocalRotations = new List<Quaternion>(); public readonly List<Vector3> WorldPositions = new List<Vector3>(); public readonly List<Quaternion> WorldRotations = new List<Quaternion>(); } private struct Pair { public ConfigEntry<float> Scope; public ConfigEntry<float> Forward; } private struct PlaceState { public Vector3 Written; public float Vertical; public float Depth; } private struct HeldAlign { public long SightId; public long CarrierId; public bool HasCarrier; } internal const float Step = 0.005f; private const float Max = 0.25f; private const string Section = "Alignment"; private const string ScopeSuffix = " Scope Vertical"; private const string ForwardSuffix = " Scope Forward"; private const string RetiredHandsSuffix = " Aim Hands Vertical"; private const string CarrierName = "ScopeAlignCarrier"; private const float VisualSign = -1f; private const float ForwardSign = 1f; private static readonly Dictionary<string, float> SightForwardShift = new Dictionary<string, float>(StringComparer.OrdinalIgnoreCase) { { "Sight_5", 0.1f } }; private static readonly Dictionary<string, string> Stems = new Dictionary<string, string>(StringComparer.Ordinal); private static readonly Dictionary<string, string> SightsByStem = new Dictionary<string, string>(StringComparer.Ordinal); private static readonly Dictionary<(InventorySlot Slot, string Weapon, string Sight), Pair> Saved = new Dictionary<(InventorySlot, string, string), Pair>(); private static readonly Dictionary<(InventorySlot Slot, string Weapon, string Sight), Vector2> Session = new Dictionary<(InventorySlot, string, string), Vector2>(); private static readonly Dictionary<uint, string> NamesById = new Dictionary<uint, string>(); private static readonly Dictionary<long, PlaceState> Places = new Dictionary<long, PlaceState>(); private static readonly Dictionary<string, string> BarrelPaths = new Dictionary<string, string>(StringComparer.Ordinal); private static readonly Dictionary<long, ReloadWatch> Watches = new Dictionary<long, ReloadWatch>(); private static readonly HashSet<string> BarrelLogged = new HashSet<string>(StringComparer.Ordinal); private static readonly Dictionary<long, Transform> FrontCarriers = new Dictionary<long, Transform>(); private static readonly HashSet<string> LinkedIrons = new HashSet<string>(StringComparer.OrdinalIgnoreCase); private static readonly Dictionary<IntPtr, bool> LocalCache = new Dictionary<IntPtr, bool>(); private static readonly Dictionary<IntPtr, HeldAlign> HeldAligns = new Dictionary<IntPtr, HeldAlign>(); private static readonly Dictionary<string, Vector2> Logged = new Dictionary<string, Vector2>(StringComparer.Ordinal); private static bool Bound; private const int BarrelNodeCap = 512; private const float BarrelMoveThreshold = 1.5f; internal static void Bind(string[] sightNames) { if (sightNames == null || Bound) { return; } Bound = true; HashSet<string> used = new HashSet<string>(StringComparer.OrdinalIgnoreCase); foreach (string text in sightNames) { if (!IsDefault(text) && !Stems.ContainsKey(text) && ScopeCatalog.Sights != null && ScopeCatalog.Sights.TryGetValue(text, out var value)) { string text2 = Stem(text, value, used); Stems.Add(text, text2); SightsByStem[text2] = text; NamesById[value] = text; } } LoadSaved(); } internal static bool Nudge(InventorySlot slot, string sightName, int kind, int direction) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) if (!TryTarget(slot, sightName, out (InventorySlot, string, string) key, out string _)) { return false; } ReadCurrent(key, out var scope, out var forward); float num = ((kind == 0) ? scope : forward); float num2 = Mathf.Clamp(Mathf.Round((num + (float)direction * 0.005f) * 1000f) / 1000f, -0.25f, 0.25f); if (Mathf.Abs(num2 - num) < 1E-07f) { return false; } if (kind == 0) { scope = num2; } else { forward = num2; } Session[key] = new Vector2(scope, forward); Reapply(); return true; } internal static bool Save(InventorySlot slot, string sightName) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) if (!TryTarget(slot, sightName, out (InventorySlot, string, string) key, out string weaponTitle)) { return false; } ReadCurrent(key, out var scope, out var forward); Write(key, scope, forward); Session.Remove(key); ((BasePlugin)Plugin.Instance).Config.Save(); Plugin.LogSource.LogInfo((object)("Saved alignment for " + SlotName(slot) + " " + weaponTitle + " / " + Label(sightName) + ": scope vertical " + Signed(scope) + ", scope forward " + Signed(forward) + ".")); Reapply(); return true; } internal static bool Reset(InventorySlot slot, string sightName) { //IL_0000: 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) if (!TryTarget(slot, sightName, out (InventorySlot, string, string) key, out string weaponTitle)) { return false; } BuiltIn(key.Item2, key.Item3, out var scope, out var forward); bool num = Session.Remove(key); ReadSaved(key, out var scope2, out var forward2); if (!num && Mathf.Abs(scope2 - scope) < 1E-05f && Mathf.Abs(forward2 - forward) < 1E-05f) { return false; } Write(key, scope, forward); ((BasePlugin)Plugin.Instance).Config.Save(); Plugin.LogSource.LogInfo((object)("Reset alignment for " + SlotName(slot) + " " + weaponTitle + " / " + Label(sightName) + ".")); Reapply(); return true; } internal static string RowLabel(int kind, int direction, InventorySlot slot, string sightName) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) string text = ((kind != 0) ? ((direction > 0) ? "Scope forward" : "Scope backward") : ((direction > 0) ? "Scope up" : "Scope down")); if (!TryValues(slot, sightName, out var scope, out var forward, out var _, out var _)) { return text; } return text + " " + Signed((kind == 0) ? scope : forward); } internal static string SaveLabel(InventorySlot slot, string sightName) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) if (TryValues(slot, sightName, out var _, out var _, out var _, out var pending) && pending) { return "Save alignment UNSAVED"; } return "Save alignment"; } internal static string ResetLabel() { return "Reset alignment"; } internal static string Summary(InventorySlot slot, string sightName, bool selected) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) string text = SlotName(slot); if (IsDefault(sightName)) { return "Pick a sight to align it on the equipped " + text.ToLowerInvariant() + " weapon. Each weapon keeps its own alignment."; } if (!TryValues(slot, sightName, out var scope, out var forward, out var weaponTitle, out var pending)) { return "Equip a " + text.ToLowerInvariant() + " weapon, then use the rows at the top. Each click moves the sight " + 0.005f.ToString("0.000", CultureInfo.InvariantCulture) + " m."; } StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("Scope height ").Append(Signed(scope)).Append(" m"); stringBuilder.Append('\n').Append("Scope forward ").Append(Signed(forward)) .Append(" m"); stringBuilder.Append('\n').Append(text).Append(" weapon: ") .Append(weaponTitle); stringBuilder.Append('\n').Append(Status(slot, sightName, pending)); stringBuilder.Append('\n').Append(selected ? "Top rows nudge this sight. Save stores it for this weapon. Reset restores the default alignment." : "Top rows change the selected sight."); return stringBuilder.ToString(); } internal static void ApplyScope(GearPartHolder holder) { //IL_00c4: Unknown result type (might be due to invalid IL or missing references) if (!Plugin.Ready || (Object)(object)holder == (Object)null || (Object)(object)holder.SightPart == (Object)null || IsIconCapture(holder) || !IsLocalHolder(holder)) { return; } Transform transform = holder.SightPart.transform; try { if (!TryPlacement(holder, out var scope, out var forward, out var slot, out var weaponKey, out var sightName)) { Transform target = TrackedIronTarget(transform); if (IsTracked(target)) { ApplyLocal(target, 0f, 0f); } return; } Transform target2 = IronTarget(holder, transform, sightName); float num = -1f * scope; float num2 = 1f * forward; if (!(Mathf.Abs(num) < 1E-07f) || !(Mathf.Abs(num2) < 1E-07f) || IsTracked(target2)) { ApplyLocal(target2, num, num2); LogIfChanged(slot, weaponKey, sightName, scope, forward); } if (ScopeCatalog.FollowsBarrel(weaponKey)) { FollowBarrel(holder, target2, weaponKey); } } finally { RememberAlign(holder, transform); } } internal static void Forget(GearPartHolder holder) { if ((Object)(object)holder == (Object)null) { return; } DropBarrel(holder); LocalCache.Remove(((Il2CppObjectBase)holder).Pointer); long key = 0L; bool flag = false; long key2 = 0L; bool flag2 = false; if (HeldAligns.TryGetValue(((Il2CppObjectBase)holder).Pointer, out var value)) { HeldAligns.Remove(((Il2CppObjectBase)holder).Pointer); key = value.SightId; flag = true; key2 = value.CarrierId; flag2 = value.HasCarrier; } if ((Object)(object)holder.SightPart != (Object)null) { Transform transform = holder.SightPart.transform; if ((Object)(object)transform != (Object)null) { key = ((Object)transform).GetInstanceID(); flag = true; } } if (!flag) { return; } Places.Remove(key); Transform value2 = null; if (FrontCarriers.TryGetValue(key, out value2)) { FrontCarriers.Remove(key); } if ((Object)(object)value2 != (Object)null) { Places.Remove(((Object)value2).GetInstanceID()); if ((Object)(object)value2.parent == (Object)null) { Object.Destroy((Object)(object)((Component)value2).gameObject); } } else if (flag2) { Places.Remove(key2); } } private static void RememberAlign(GearPartHolder holder, Transform sight) { if (!((Object)(object)holder == (Object)null) && !((Object)(object)sight == (Object)null)) { long num = ((Object)sight).GetInstanceID(); HeldAlign value = new HeldAlign { SightId = num }; if (FrontCarriers.TryGetValue(num, out var value2) && (Object)(object)value2 != (Object)null) { value.CarrierId = ((Object)value2).GetInstanceID(); value.HasCarrier = true; } HeldAligns[((Il2CppObjectBase)holder).Pointer] = value; } } private static Transform TrackedIronTarget(Transform sight) { if ((Object)(object)sight != (Object)null && FrontCarriers.TryGetValue(((Object)sight).GetInstanceID(), out var value) && (Object)(object)value != (Object)null) { return value; } return sight; } private static Transform IronTarget(GearPartHolder holder, Transform sight, string sightName) { if (!TryIronMate(sightName, out var mateName, out var front)) { return sight; } if (!front) { AttachMate(sight, sight, mateName); return sight; } return FrontCarrier(holder, sight, sightName, mateName); } private static Transform FrontCarrier(GearPartHolder holder, Transform sight, string sightName, string mateName) { //IL_00ad: 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_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) long key = ((Object)sight).GetInstanceID(); if (!FrontCarriers.TryGetValue(key, out var value) || (Object)(object)value == (Object)null) { value = (((Object)(object)sight.parent != (Object)null && ((Object)sight.parent).name == "ScopeAlignCarrier") ? sight.parent : null); } if ((Object)(object)value == (Object)null) { if (Places.TryGetValue(key, out var value2)) { Vector3 localPosition = sight.localPosition; localPosition.y -= value2.Vertical; localPosition.z -= value2.Depth; sight.localPosition = localPosition; Places.Remove(key); } value = new GameObject("ScopeAlignCarrier").transform; Transform parent = sight.parent; int siblingIndex = sight.GetSiblingIndex(); value.SetParent(parent, false); value.localPosition = sight.localPosition; value.localRotation = sight.localRotation; value.localScale = sight.localScale; if ((Object)(object)parent != (Object)null) { value.SetSiblingIndex(siblingIndex); } sight.SetParent(value, true); if (LinkedIrons.Add(sightName)) { Plugin.LogSource.LogInfo((object)("Front iron " + sightName + " is moved with " + mateName + ". The front mesh was not parented to the rear sight.")); } } else if ((Object)(object)sight.parent != (Object)(object)value) { sight.SetParent(value, true); } FrontCarriers[key] = value; AttachMate(value, sight, mateName); EnsureSightAlign(holder, value, sight); return value; } private static void AttachMate(Transform keepOn, Transform sight, string mateName) { if (!((Object)(object)keepOn == (Object)null) && !((Object)(object)sight == (Object)null) && !string.IsNullOrEmpty(mateName)) { Transform val = FindMate(sight, mateName); if (!((Object)(object)val == (Object)null) && !((Object)(object)val == (Object)(object)keepOn) && !((Object)(object)val == (Object)(object)sight) && !sight.IsChildOf(val) && !((Object)(object)val.parent == (Object)(object)keepOn)) { val.SetParent(keepOn, true); } } } private static Transform FindMate(Transform sight, string mateName) { Transform parent = sight.parent; Transform val = FindDirect(parent, sight, mateName); if ((Object)(object)val != (Object)null) { return val; } if ((Object)(object)parent != (Object)null && ((Object)parent).name == "ScopeAlignCarrier") { return FindDirect(parent.parent, parent, mateName); } return null; } private static Transform FindDirect(Transform parent, Transform skip, string partName) { if ((Object)(object)parent == (Object)null) { return null; } for (int i = 0; i < parent.childCount; i++) { Transform child = parent.GetChild(i); if ((Object)(object)child != (Object)(object)skip && NamesMatch(((Object)child).name, partName)) { return child; } } return null; } private static void EnsureSightAlign(GearPartHolder holder, Transform carrier, Transform sight) { //IL_001a: 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_004f: Unknown result type (might be due to invalid IL or missing references) Transform val = FindNamed(carrier, "Sight_Align"); if ((Object)(object)val == (Object)null) { val = new GameObject("Sight_Align").transform; val.SetParent(carrier, false); Renderer component = ((Component)sight).GetComponent<Renderer>(); if ((Object)(object)component != (Object)null && component.enabled) { Transform obj = val; Bounds bounds = component.bounds; obj.position = ((Bounds)(ref bounds)).center; } } if ((Object)(object)holder.m_aSightLook == (Object)null || !holder.m_aSightLook.IsChildOf(carrier)) { holder.m_aSightLook = val; } ItemEquippable componentInParent = ((Component)holder).GetComponentInParent<ItemEquippable>(); if ((Object)(object)componentInParent != (Object)null && ((Object)(object)componentInParent.SightLookAlign == (Object)null || !componentInParent.SightLookAlign.IsChildOf(carrier))) { componentInParent.SightLookAlign = val; } } private static Transform FindNamed(Transform root, string partName) { if ((Object)(object)root == (Object)null) { return null; } if (NamesMatch(((Object)root).name, partName)) { return root; } for (int i = 0; i < root.childCount; i++) { Transform val = FindNamed(root.GetChild(i), partName); if ((Object)(object)val != (Object)null) { return val; } } return null; } private static bool NamesMatch(string transformName, string partName) { if (string.Equals(transformName, partName, StringComparison.OrdinalIgnoreCase)) { return true; } if (string.IsNullOrEmpty(transformName) || string.IsNullOrEmpty(partName) || transformName.Length <= partName.Length) { return false; } if (!transformName.StartsWith(partName, StringComparison.OrdinalIgnoreCase)) { return false; } char c = transformName[partName.Length]; if (c != '(') { return c == ' '; } return true; } private static bool TryIronMate(string sightName, out string mateName, out bool front) { mateName = null; front = false; if (string.IsNullOrEmpty(sightName) || sightName.Length <= "IronSights_".Length || !sightName.StartsWith("IronSights_", StringComparison.OrdinalIgnoreCase)) { return false; } string text = sightName.Substring("IronSights_".Length); if (text.EndsWith("_Copy_Copy", StringComparison.OrdinalIgnoreCase)) { text = text.Substring(0, text.Length - "_Copy_Copy".Length); } else if (text.EndsWith("_Copy", StringComparison.OrdinalIgnoreCase)) { text = text.Substring(0, text.Length - "_Copy".Length); } bool flag = text.EndsWith("_B", StringComparison.OrdinalIgnoreCase); front = text.EndsWith("_F", StringComparison.OrdinalIgnoreCase); if (!front && !flag) { return false; } string text2 = text.Substring(0, text.Length - 2); if (text2.Length == 0) { return false; } mateName = sightName.Substring(0, "IronSights_".Length) + text2 + (front ? "_B" : "_F"); return true; } private static void Reapply() { try { Il2CppArrayBase<GearPartHolder> val = Object.FindObjectsOfType<GearPartHolder>(); if (val != null) { for (int i = 0; i < val.Count; i++) { ApplyScope(val[i]); } } } catch (Exception ex) { Plugin.LogSource.LogDebug((object)("Alignment refresh: " + ex.Message)); } } private static void ApplyLocal(Transform target, float vertical, float depth) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)target == (Object)null)) { Vector3 val = OffsetAxes(((Object)target).GetInstanceID(), target.localPosition, vertical, depth); Vector3 val2 = val - target.localPosition; if (((Vector3)(ref val2)).sqrMagnitude > 1E-08f) { target.localPosition = val; } } } private static Vector3 OffsetAxes(long id, Vector3 position, float vertical, float depth) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) if (Places.TryGetValue(id, out var value)) { Vector3 val = position - value.Written; if (((Vector3)(ref val)).sqrMagnitude <= 1E-08f) { if (Mathf.Abs(value.Vertical - vertical) <= 1E-07f && Mathf.Abs(value.Depth - depth) <= 1E-07f) { return position; } position.y += vertical - value.Vertical; position.z += depth - value.Depth; goto IL_0094; } } position.y += vertical; position.z += depth; goto IL_0094; IL_0094: Places[id] = new PlaceState { Written = position, Vertical = vertical, Depth = depth }; return position; } private static bool IsTracked(Transform target) { if ((Object)(object)target != (Object)null) { return Places.ContainsKey(((Object)target).GetInstanceID()); } return false; } private static void ForgetTransform(Transform target) { if ((Object)(object)target != (Object)null) { Places.Remove(((Object)target).GetInstanceID()); } } private static void FollowBarrel(GearPartHolder holder, Transform target, string weaponKey) { if ((Object)(object)holder == (Object)null || (Object)(object)target == (Object)null || string.IsNullOrEmpty(weaponKey)) { return; } Transform transform = ((Component)holder).transform; if ((Object)(object)transform == (Object)null) { return; } if (BarrelPaths.TryGetValue(weaponKey, out var value)) { Transform val = Walk(transform, value); if ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)target && !val.IsChildOf(target)) { ItemEquippable componentInParent = ((Component)holder).GetComponentInParent<ItemEquippable>(); if ((Object)(object)target.parent == (Object)(object)val || (Object)(object)componentInParent == (Object)null || !componentInParent.IsReloading) { Adopt(target, val, null); } } return; } long key = ((Object)transform).GetInstanceID(); ItemEquippable componentInParent2 = ((Component)holder).GetComponentInParent<ItemEquippable>(); bool num = (Object)(object)componentInParent2 != (Object)null && componentInParent2.IsReloading; if (!Watches.TryGetValue(key, out var value2)) { value2 = new ReloadWatch(); Watches[key] = value2; } if (!num) { if (value2.SawReload && BarrelLogged.Add(weaponKey)) { Plugin.LogSource.LogInfo((object)(ScopeCatalog.WeaponTitleFor(weaponKey, null) + " reload did not move a separate barrel bone. Largest change was " + value2.BestName + " at " + value2.BestScore.ToString("0.0", CultureInfo.InvariantCulture) + ". " + DescribeFront(holder))); } Capture(transform, target, value2); value2.SawReload = false; value2.BestScore = 0f; value2.BestName = "none"; return; } if (value2.Nodes.Count == 0) { Capture(transform, target, value2); value2.SawReload = true; return; } value2.SawReload = true; Transform val2 = Pick(value2, target, holder.m_aMuzzle); if ((Object)(object)val2 == (Object)null || (Object)(object)val2 == (Object)(object)target || (Object)(object)val2 == (Object)(object)transform || val2.IsChildOf(target)) { return; } string text = PathFrom(val2, transform); if (!string.IsNullOrEmpty(text)) { BarrelPaths[weaponKey] = text; Adopt(target, val2, value2); if (BarrelLogged.Add(weaponKey)) { Plugin.LogSource.LogInfo((object)(ScopeCatalog.WeaponTitleFor(weaponKey, null) + " sight follows " + text + " during reload.")); } } } private static void DropBarrel(GearPartHolder holder) { if ((Object)(object)holder != (Object)null) { Watches.Remove(((Object)((Component)holder).transform).GetInstanceID()); } } private static void Adopt(Transform target, Transform bone, ReloadWatch watch) { //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0050: 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_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0070: 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_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)target.parent == (Object)(object)bone) { return; } long key = ((Object)target).GetInstanceID(); PlaceState value; bool flag = Places.TryGetValue(key, out value); target.SetParent(bone, true); if (watch != null) { int num = watch.Nodes.IndexOf(bone); if (num >= 0) { Quaternion val = watch.WorldRotations[num]; target.localRotation = Quaternion.Inverse(val) * watch.SightRotation; target.localPosition = Quaternion.Inverse(val) * (watch.SightPosition - watch.WorldPositions[num]); } } Places[key] = new PlaceState { Written = target.localPosition, Vertical = (flag ? value.Vertical : 0f), Depth = (flag ? value.Depth : 0f) }; } private static void Capture(Transform root, Transform sight, ReloadWatch watch) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000e: 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) watch.SightPosition = sight.position; watch.SightRotation = sight.rotation; watch.Nodes.Clear(); watch.LocalPositions.Clear(); watch.LocalRotations.Clear(); watch.WorldPositions.Clear(); watch.WorldRotations.Clear(); AddNodes(root, sight, watch); } private static void AddNodes(Transform node, Transform sight, ReloadWatch watch) { //IL_0041: 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_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)node == (Object)null) && watch.Nodes.Count < 512 && !((Object)(object)node == (Object)(object)sight) && !node.IsChildOf(sight)) { watch.Nodes.Add(node); watch.LocalPositions.Add(node.localPosition); watch.LocalRotations.Add(node.localRotation); watch.WorldPositions.Add(node.position); watch.WorldRotations.Add(node.rotation); for (int i = 0; i < node.childCount; i++) { AddNodes(node.GetChild(i), sight, watch); } } } private static Transform Pick(ReloadWatch watch, Transform sight, Transform muzzle) { //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) Transform val = null; float num = 0f; bool flag = false; Transform val2 = null; float num2 = 0f; int num3 = int.MaxValue; Transform val3 = null; float num4 = 0f; Transform val4 = ((watch.Nodes.Count > 0) ? watch.Nodes[0] : null); bool flag2 = (Object)(object)muzzle != (Object)null && (Object)(object)val4 != (Object)null && ((Object)(object)muzzle == (Object)(object)val4 || muzzle.IsChildOf(val4)); for (int i = 0; i < watch.Nodes.Count; i++) { Transform val5 = watch.Nodes[i]; if ((Object)(object)val5 == (Object)null || (Object)(object)val5 == (Object)(object)val4 || (Object)(object)val5 == (Object)(object)sight || val5.IsChildOf(sight)) { continue; } float num5 = Quaternion.Angle(watch.LocalRotations[i], val5.localRotation); Vector3 val6 = val5.localPosition - watch.LocalPositions[i]; float num6 = ((Vector3)(ref val6)).magnitude * 200f; float num7 = num5 + num6; if (num7 > watch.BestScore) { watch.BestScore = num7; watch.BestName = PathFrom(val5, val4); } if (IsBarrelName(((Object)val5).name)) { flag = true; if (num7 >= 1.5f) { int num8 = DepthUnder(val5, val4); if (num7 > num2 + 0.01f || (Mathf.Abs(num7 - num2) <= 0.01f && num8 < num3)) { val2 = val5; num2 = num7; num3 = num8; } } } else { if (num7 < 1.5f || IsIgnoredMover(((Object)val5).name)) { continue; } if (flag2 && ((Object)(object)val5 == (Object)(object)muzzle || muzzle.IsChildOf(val5))) { if (num7 > num) { val = val5; num = num7; } } else if (num7 > num4) { val3 = val5; num4 = num7; } } } if ((Object)(object)val2 != (Object)null) { return val2; } if (flag) { return null; } Transform result = val3; float num9 = num4; if ((Object)(object)val != (Object)null && num > num9) { result = val; num9 = num; } return result; } private static Transform Walk(Transform root, string path) { if ((Object)(object)root == (Object)null || string.IsNullOrEmpty(path)) { return null; } string[] array = path.Split('/'); Transform val = root; for (int i = 0; i < array.Length; i++) { Transform val2 = null; for (int j = 0; j < val.childCount; j++) { Transform child = val.GetChild(j); if (string.Equals(((Object)child).name, array[i], StringComparison.Ordinal)) { val2 = child; break; } } if ((Object)(object)val2 == (Object)null) { return null; } val = val2; } return val; } private static string PathFrom(Transform node, Transform root) { if ((Object)(object)node == (Object)null || (Object)(object)node == (Object)(object)root) { return null; } List<string> list = new List<string>(); Transform val = node; int num = 0; while ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)root && num++ < 32) { list.Add(((Object)val).name); val = val.parent; } if ((Object)(object)val != (Object)(object)root) { return null; } list.Reverse(); return string.Join("/", list); } private static int DepthUnder(Transform node, Transform root) { int num = 0; Transform val = node; while ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)root && num < 32) { num++; val = val.parent; } return num; } private static string DescribeFront(GearPartHolder holder) { Transform val = (((Object)(object)holder.FrontPart != (Object)null) ? holder.FrontPart.transform : null); if ((Object)(object)val == (Object)null) { return "No front part."; } StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append(((Object)val).name).Append(" children:"); int num = Math.Min(val.childCount, 12); for (int i = 0; i < num; i++) { stringBuilder.Append(' ').Append(((Object)val.GetChild(i)).name); } Animator frontPartAnimator = holder.FrontPartAnimator; if ((Object)(object)frontPartAnimator != (Object)null && (Object)(object)frontPartAnimator.runtimeAnimatorController != (Object)null && frontPartAnimator.runtimeAnimatorController.animationClips != null) { stringBuilder.Append(". Clips:"); AnimationClip[] array = Il2CppArrayBase<AnimationClip>.op_Implicit((Il2CppArrayBase<AnimationClip>)(object)frontPartAnimator.runtimeAnimatorController.animationClips); int num2 = 0; for (int j = 0; j < array.Length; j++) { if (num2 >= 6) { break; } if (!((Object)(object)array[j] == (Object)null)) { stringBuilder.Append(' ').Append(((Object)array[j]).name); num2++; } } } return stringBuilder.ToString(); } private static bool IsBarrelName(string name) { if (string.IsNullOrEmpty(name) || name.IndexOf("align", StringComparison.OrdinalIgnoreCase) >= 0) { return false; } if (!ContainsToken(name, "barrel")) { return ContainsToken(name, "fold"); } return true; } private static bool IsIgnoredMover(string name) { if (string.IsNullOrEmpty(name)) { return true; } if (!ContainsToken(name, "cylinder") && !ContainsToken(name, "drum") && !ContainsToken(name, "hammer") && !ContainsToken(name, "trigger") && !ContainsToken(name, "bullet") && !ContainsToken(name, "shell") && !ContainsToken(name, "casing") && !ContainsToken(name, "cartridge") && !ContainsToken(name, "mag") && !ContainsToken(name, "speedloader") && !ContainsToken(name, "ejector") && !ContainsToken(name, "sight") && !ContainsToken(name, "align") && !ContainsToken(name, "hand") && !ContainsToken(name, "flash")) { return string.Equals(name, "ScopeAlignCarrier", StringComparison.Ordinal); } return true; } private static bool ContainsToken(string name, string token) { return name.IndexOf(token, StringComparison.OrdinalIgnoreCase) >= 0; } private static bool IsIconCapture(GearPartHolder holder) { GearIconRendering current = GearIconRendering.Current; IconRenderJob val = (((Object)(object)current != (Object)null) ? current.m_currentJob : null); GameObject val2 = ((val != null) ? val.loadedGearGO : null); if ((Object)(object)val2 == (Object)null) { return false; } Transform transform = val2.transform; Transform transform2 = ((Component)holder).transform; if (!((Object)(object)transform2 == (Object)(object)transform)) { return transform2.IsChildOf(transform); } return true; } private static bool IsLocalHolder(GearPartHolder holder) { if (LocalCache.TryGetValue(((Il2CppObjectBase)holder).Pointer, out var value)) { return value; } value = true; Transform val = ((Component)holder).transform; while ((Object)(object)val != (Object)null) { CM_PlayerLobbyBar component = ((Component)val).GetComponent<CM_PlayerLobbyBar>(); if ((Object)(object)component != (Object)null && (Object)(object)component.m_player != (Object)null) { value = component.m_player.IsLocal; break; } PlayerAgent component2 = ((Component)val).GetComponent<PlayerAgent>(); if ((Object)(object)component2 != (Object)null) { value = ((Agent)component2).IsLocallyOwned; break; } val = val.parent; } LocalCache[((Il2CppObjectBase)holder).Pointer] = value; return value; } private static bool TryPlacement(GearPartHolder holder, out float scope, out float forward, out InventorySlot slot, out string weaponKey, out string sightName) { scope = 0f; forward = 0f; slot = (InventorySlot)0; weaponKey = null; sightName = null; if (!TryContext(holder, out slot, out weaponKey, out sightName)) { return false; } ReadCurrent((Slot: slot, Weapon: weaponKey, Sight: sightName), out scope, out forward); return true; } private static bool TryContext(GearPartHolder holder, out InventorySlot slot, out string weaponKey, out string sightName) { slot = (InventorySlot)0; weaponKey = null; sightName = NameOf(((Object)(object)holder != (Object)null) ? holder.SightData : null); if (IsDefault(sightName)) { return false; } GearIDRange val = holder.GearIDRange; if (val == null) { ItemEquippable componentInParent = ((Component)holder).GetComponentInParent<ItemEquippable>(); val = (((Object)(object)componentInParent != (Object)null) ? componentInParent.GearIDRange : null); } if (val != null) { weaponKey = ScopeCatalog.WeaponKeyFor(val); if (weaponKey != null && TrySlot(weaponKey, sightName, out slot)) { return true; } } if (!ScopeLoadoutCategory.TryEditing(out slot) || !TryEquipped(slot, out weaponKey, out var _, out var _)) { weaponKey = null; return false; } return true; } private static bool TrySlot(string weaponKey, string sightName, out InventorySlot slot) { bool flag = string.Equals(EquippedKey((InventorySlot)1), weaponKey, StringComparison.Ordinal); bool flag2 = string.Equals(EquippedKey((InventorySlot)2), weaponKey, StringComparison.Ordinal); if (flag && !flag2) { slot = (InventorySlot)1; return true; } if (flag2 && !flag) { slot = (InventorySlot)2; return true; } if (flag && flag2) { bool flag3 = string.Equals(ScopeChoices.Display((InventorySlot)2), sightName, StringComparison.Ordinal); bool flag4 = string.Equals(ScopeChoices.Display((InventorySlot)1), sightName, StringComparison.Ordinal); slot = (InventorySlot)((!flag3 || flag4) ? 1 : 2); return true; } slot = (InventorySlot)0; return false; } private static string EquippedKey(InventorySlot slot) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) if (!TryEquipped(slot, out var weaponKey, out var _, out var _)) { return null; } return weaponKey; } private static bool TryEquipped(InventorySlot slot, out string weaponKey, out string weaponTitle, out GearIDRange range) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) weaponKey = null; weaponTitle = null; range = null; BackpackItem localItem = PlayerBackpackManager.GetLocalItem(slot); range = ((localItem != null) ? localItem.GearIDRange : null); if (range == null) { return false; } weaponKey = ScopeCatalog.WeaponKeyFor(range); if (weaponKey == null) { return false; } weaponTitle = ScopeCatalog.WeaponTitleFor(weaponKey, range); return true; } private static bool TryTarget(InventorySlot slot, string sightName, out (InventorySlot Slot, string Weapon, string Sight) key, out string weaponTitle) { //IL_000a: 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) key = default((InventorySlot, string, string)); weaponTitle = null; if (!TryEquipped(slot, out var weaponKey, out weaponTitle, out var _) || !Stems.ContainsKey(sightName)) { return false; } key = (Slot: slot, Weapon: weaponKey, Sight: sightName); return true; } private static bool TryValues(InventorySlot slot, string sightName, out float scope, out float forward, out string weaponTitle, out bool pending) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) scope = 0f; forward = 0f; weaponTitle = null; pending = false; if (!TryTarget(slot, sightName, out (InventorySlot, string, string) key, out weaponTitle)) { return false; } ReadCurrent(key, out scope, out forward); ReadSaved(key, out var scope2, out var forward2); pending = Session.ContainsKey(key) && (Mathf.Abs(scope2 - scope) > 1E-05f || Mathf.Abs(forward2 - forward) > 1E-05f); return true; } private static void ReadCurrent((InventorySlot Slot, string Weapon, string Sight) key, out float scope, out float forward) { //IL_0010: 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 (Session.TryGetValue(key, out var value)) { scope = Mathf.Clamp(value.x, -0.25f, 0.25f); forward = Mathf.Clamp(value.y, -0.25f, 0.25f); } else { ReadSaved(key, out scope, out forward); } } private static void ReadSaved((InventorySlot Slot, string Weapon, string Sight) key, out float scope, out float forward) { if (!Saved.TryGetValue(key, out var value)) { BuiltIn(key.Weapon, key.Sight, out scope, out forward); return; } scope = Mathf.Clamp(value.Scope.Value, -0.25f, 0.25f); forward = Mathf.Clamp(value.Forward.Value, -0.25f, 0.25f); } private static void BuiltIn(string weaponKey, string sightName, out float scope, out float forward) { if (weaponKey == null || !ScopeCatalog.TryAlignmentDefault(weaponKey, out scope, out forward)) { scope = 0f; forward = 0f; } if (sightName != null && SightForwardShift.TryGetValue(sightName, out var value)) { forward += value; } scope = Snap(scope); forward = Snap(forward); } private static float Snap(float value) { return Mathf.Clamp(Mathf.Round(value * 1000f) / 1000f, -0.25f, 0.25f); } private static string Status(InventorySlot slot, string sightName, bool pending) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) if (pending) { return "Not saved yet."; } if (TryTarget(slot, sightName, out (InventorySlot, string, string) key, out string _) && Saved.ContainsKey(key)) { return "Saved for this weapon and sight."; } return "Default alignment for this weapon."; } private static void Write((InventorySlot Slot, string Weapon, string Sight) key, float scope, float forward) { if (Ensure(key)) { Pair pair = Saved[key]; pair.Scope.Value = Mathf.Clamp(scope, -0.25f, 0.25f); pair.Forward.Value = Mathf.Clamp(forward, -0.25f, 0.25f); } } private static bool Ensure((InventorySlot Slot, string Weapon, string Sight) key) { //IL_002e: 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_00d8: Unknown result type (might be due to invalid IL or missing references) if (Saved.ContainsKey(key)) { return true; } if (!Stems.TryGetValue(key.Sight, out var value)) { return false; } string text = SlotName(key.Slot) + " weapon " + key.Weapon + ", sight " + key.Sight + ". Meters. Stored for this weapon and sight only."; BuiltIn(key.Weapon, key.Sight, out var scope, out var forward); Saved[key] = new Pair { Scope = ((BasePlugin)Plugin.Instance).Config.Bind<float>("Alignment", ConfigKey(key.Slot, key.Weapon, value, 0), scope, text + " Positive moves up."), Forward = ((BasePlugin)Plugin.Instance).Config.Bind<float>("Alignment", ConfigKey(key.Slot, key.Weapon, value, 1), forward, text + " Positive moves the sight forward, toward the muzzle.") }; return true; } private static void LoadSaved() { //IL_011d: Unknown result type (might be due to invalid IL or missing references) string path = Path.Combine(Paths.ConfigPath, "SelectableScopes.cfg"); if (!File.Exists(path)) { return; } bool flag = false; bool flag2 = false; HashSet<(InventorySlot, string, string)> hashSet = new HashSet<(InventorySlot, string, string)>(); string[] array = File.ReadAllLines(path); for (int i = 0; i < array.Length; i++) { string text = array[i].Trim(); if (text.Length >= 2 && text[0] == '[' && text[text.Length - 1] == ']') { flag = string.Equals(text.Substring(1, text.Length - 2), "Alignment", StringComparison.Ordinal); } else { if (!flag || text.Length == 0 || text[0] == '#') { continue; } int num = text.IndexOf('='); if (num <= 0) { continue; } string text2 = text.Substring(0, num).Trim(); InventorySlot slot; string weaponKey; string stem; int kind; float result; if (text2.EndsWith(" Aim Hands Vertical", StringComparison.Ordinal)) { if (!flag2) { flag2 = true; Plugin.LogSource.LogInfo((object)"Aim hands alignment entries are ignored. Forward and backward alignment replaces them."); } } else if (TryParseConfigKey(text2, out slot, out weaponKey, out stem, out kind)) { if (SightsByStem.TryGetValue(stem, out var value)) { hashSet.Add((slot, weaponKey, value)); } else { Plugin.LogSource.LogWarning((object)("Unknown alignment entry '" + text2 + "'. It was not loaded.")); } } else if ((text2.EndsWith(" Scope Vertical", StringComparison.Ordinal) || text2.EndsWith(" Scope Forward", StringComparison.Ordinal)) && float.TryParse(text.Substring(num + 1).Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out result) && Mathf.Abs(result) > 1E-05f) { Plugin.LogSource.LogInfo((object)("Ignored shared alignment '" + text2 + "' = " + Signed(result) + ". Save it again for each weapon.")); } } } foreach (var item in hashSet) { Ensure(item); } } private static bool TryParseConfigKey(string key, out InventorySlot slot, out string weaponKey, out string stem, out int kind) { slot = (InventorySlot)0; weaponKey = null; stem = null; kind = 0; string text = null; if (key.EndsWith(" Scope Vertical", StringComparison.Ordinal)) { text = " Scope Vertical"; } else if (key.EndsWith(" Scope Forward", StringComparison.Ordinal)) { kind = 1; text = " Scope Forward"; } if (text == null) { return false; } string text2 = key.Substring(0, key.Length - text.Length); int num = text2.IndexOf(' '); if (num <= 0) { return false; } string a = text2.Substring(0, num); if (string.Equals(a, "Primary", StringComparison.Ordinal)) { slot = (InventorySlot)1; } else { if (!string.Equals(a, "Special", StringComparison.Ordinal)) { return false; } slot = (InventorySlot)2; } string text3 = text2.Substring(num + 1); int num2 = text3.IndexOf(' '); if (num2 <= 0) { return false; } weaponKey = text3.Substring(0, num2); stem = text3.Substring(num2 + 1); if (weaponKey.Length > 0) { return stem.Length > 0; } return false; } private static string ConfigKey(InventorySlot slot, string weaponKey, string stem, int kind) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) return SlotName(slot) + " " + weaponKey + " " + stem + ((kind == 0) ? " Scope Vertical" : " Scope Forward"); } private static void LogIfChanged(InventorySlot slot, string weaponKey, string sightName, float scope, float forward) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) string key = SlotName(slot) + "|" + weaponKey + "|" + sightName; if (!Logged.TryGetValue(key, out var value) || !(Mathf.Abs(value.x - scope) < 1E-05f) || !(Mathf.Abs(value.y - forward) < 1E-05f)) { bool num = !Logged.ContainsKey(key); Logged[key] = new Vector2(scope, forward); if (!num || !(Mathf.Abs(scope) < 1E-05f) || !(Mathf.Abs(forward) < 1E-05f)) { Plugin.LogSource.LogInfo((object)("Alignment " + SlotName(slot) + " " + weaponKey + " / " + Label(sightName) + ": scope vertical " + Signed(scope) + ", scope forward " + Signed(forward) + ".")); } } } private static string NameOf(GearSightPartDataBlock block) { if (block == null) { return null; } if (NamesById.TryGetValue(((GameDataBlockBase<GearSightPartDataBlock>)(object)block).persistentID, out var value)) { return value; } if (!string.IsNullOrWhiteSpace(((GameDataBlockBase<GearSightPartDataBlock>)(object)block).name)) { return ((GameDataBlockBase<GearSightPartDataBlock>)(object)block).name; } return null; } private static string Stem(string sightName, uint sightId, HashSet<string> used) { StringBuilder stringBuilder = new StringBuilder(sightName.Length); foreach (char c in sightName) { bool flag; switch (c) { case '\t': case '\n': case '\r': case ' ': case '#': case '=': case '[': case ']': flag = true; break; default: flag = false; break; } bool flag2 = flag; stringBuilder.Append(flag2 ? '_' : c); } string text = stringBuilder.ToString().Trim('_'); if (text.Length == 0) { text = "Sight"; } if (!used.Add(text)) { text = text + "_" + sightId.ToString(CultureInfo.InvariantCulture); used.Add(text); } return text; } private static string Label(string sightName) { string text = ScopeCatalog.Title(sightName); if (string.IsNullOrWhiteSpace(text) || string.Equals(text, sightName, StringComparison.Ordinal)) { return sightName; } return sightName + " (" + text + ")"; } private static string SlotName(InventorySlot slot) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Invalid comparison between Unknown and I4 if ((int)slot != 2) { return "Primary"; } return "Special"; } private static string Signed(float value) { return value.ToString("+0.0000;-0.0000", CultureInfo.InvariantCulture); } private static bool IsDefault(string sightName) { if (!string.IsNullOrEmpty(sightName)) { return string.Equals(sightName, "Default", StringComparison.Ordinal); } return true; } } internal static class ScopeApplier { private static readonly HashSet<string> ReportedChoices = new HashSet<string>(StringComparer.Ordinal); private static readonly HashSet<uint> ReportedFailures = new HashSet<uint>(); internal static bool IsWriting { get; private set; } internal static void ApplyConfigured() { if (IsWriting || !Plugin.Ready || !Plugin.Enabled.Value || ScopeCatalog.Weapons == null) { return; } foreach (KeyValuePair<uint, ConfigEntry<string>> weapon in ScopeCatalog.Weapons) { if (TryRewrite(weapon.Key, null, out var block, out var updated, out var choice)) { IsWriting = true; try { block.GearJSON = updated; } finally { IsWriting = false; } Plugin.LogSource.LogInfo((object)(((GameDataBlockBase<PlayerOfflineGearDataBlock>)(object)block).name + " sight set to " + choice + ".")); } } } private static bool TryRewrite(uint persistentId, string gearJson, out PlayerOfflineGearDataBlock block, out string updated, out string choice) { block = null; updated = gearJson; choice = null; if (ScopeCatalog.Weapons == null || !ScopeCatalog.Weapons.TryGetValue(persistentId, out var value)) { return false; } choice = value.Value; if (string.IsNullOrEmpty(choice) || string.Equals(choice, "Default", StringComparison.Ordinal)) { return false; } if (!ScopeCatalog.Sights.TryGetValue(choice, out var value2)) { if (ReportedChoices.Add(persistentId + ":" + choice)) { Plugin.LogSource.LogWarning((object)("Unknown sight '" + choice + "' for gear " + persistentId + ". Leaving that weapon unchanged.")); } return false; } if (gearJson == null) { try { block = GameDataBlockBase<PlayerOfflineGearDataBlock>.GetBlock(persistentId); } catch (Exception ex) { Plugin.LogSource.LogDebug((object)("Gear " + persistentId + " was not readable: " + ex.Message)); return false; } if (block == null) { return false; } gearJson = block.GearJSON; } SightEditResult num = GearJsonEditor.TrySetSight(gearJson, value2, out updated); if (num == SightEditResult.Failed && ReportedFailures.Add(persistentId)) { Plugin.LogSource.LogWarning((object)("Could not write a sight component on gear " + persistentId + ".")); } return num == SightEditResult.Updated; } } internal static class ScopeCatalog { private struct AuthoredSight { public bool HadSight; public uint SightId; } private struct AlignmentDefault { public float Vertical; public float Forward; } private static readonly Dictionary<string, string> WeaponKeys = new Dictionary<string, string>(StringComparer.Ordinal); private static readonly Dictionary<string, string> WeaponTitles = new Dictionary<string, string>(StringComparer.Ordinal); private static readonly Dictionary<string, AuthoredSight> AuthoredSights = new Dictionary<string, AuthoredSight>(StringComparer.Ordinal); private static readonly Dictionary<uint, List<string>> SightUsers = new Dictionary<uint, List<string>>(); private static readonly Dictionary<string, AlignmentDefault> AlignmentDefaults = new Dictionary<string, AlignmentDefault>(StringComparer.Ordinal); private static readonly HashSet<string> BarrelDatablocks = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "RevolverHEL", "RevolverSemi" }; private static readonly HashSet<string> BarrelKeys = new HashSet<string>(StringComparer.Ordinal); private static readonly Dictionary<string, AlignmentDefault> AlignmentPresets = new Dictionary<string, AlignmentDefault>(StringComparer.OrdinalIgnoreCase) { { "HighCalPistol", new AlignmentDefault { Vertical = -0.035f, Forward = -0.085f } }, { "PistolSemi", new AlignmentDefault { Vertical = -0.035f, Forward = -0.07f } }, { "PistolBurst", new AlignmentDefault { Vertical = -0.02f, Forward = -0.072f } }, { "PistolAuto", new AlignmentDefault { Vertical = 0.005f, Forward = 0.048f } }, { "Autopistol staggering", new AlignmentDefault { Vertical = 0.005f, Forward = 0.02f } }, { "RevolverHEL", new AlignmentDefault { Vertical = -0.05f, Forward = 0.065f } }, { "RevolverSemi", new AlignmentDefault { Vertical = -0.05f, Forward = 0.16f } }, { "ShotgunSemi", new AlignmentDefault { Vertical = 0f, Forward = -0.06f } }, { "BullpupAuto", new AlignmentDefault { Vertical = 0.05f, Forward = -0.02f } }, { "ShotgunAuto", new AlignmentDefault { Vertical = 0.02f, Forward = 0.17f } }, { "SMGAuto", new AlignmentDefault { Vertical = 0.015f, Forward = 0.111f } }, { "PDWAuto", new AlignmentDefault { Vertical = -0.015f, Forward = -0.135f } }, { "ShotgunRanged", new AlignmentDefault { Vertical = 0.02f, Forward = 0.115f } }, { "SMGHeavyAuto", new AlignmentDefault { Vertical = 0.02f, Forward = 0.111f } }, { "SMGBurst", new AlignmentDefault { Vertical = 0f, Forward = -0.07f } }, { "HELGun", new AlignmentDefault { Vertical = 0f, Forward = -0.1f } }, { "DMRSemi", new AlignmentDefault { Vertical = 0f, Forward = 0f } }, { "DMRBurst", new AlignmentDefault { Vertical = 0f, Forward = -0.05f } }, { "HELRifleSemi", new AlignmentDefault { Vertical = 0f, Forward = -0.1f } }, { "MachinegunAuto", new AlignmentDefault { Vertical = 0.015f, Forward = 0.17f } }, { "ShotgunShort", new AlignmentDefault { Vertical = 0.005f, Forward = 0.035f } } }; private static readonly HashSet<string> HiddenNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase); private static eGearComponent[] Components; internal static Dictionary<string, uint> Sights { get; private set; } internal static string[] SightNames { get; private set; } internal static Dictionary<uint, ConfigEntry<string>> Weapons { get; private set; } internal static void BuildAndApply() { if (!Plugin.Ready) { if (!TryBuild()) { return; } Plugin.Ready = true; } ScopeApplier.ApplyConfigured(); } private static bool TryBuild() { //IL_0300: Unknown result type (might be due to invalid IL or missing references) //IL_030a: Expected O, but got Unknown Il2CppArrayBase<GearSightPartDataBlock> allBlocks = GameDataBlockBase<GearSightPartDataBlock>.GetAllBlocks(); Il2CppArrayBase<PlayerOfflineGearDataBlock> allBlocks2 = GameDataBlockBase<PlayerOfflineGearDataBlock>.GetAllBlocks(); if (allBlocks == null || allBlocks.Count == 0 || allBlocks2 == null) { Plugin.LogSource.LogWarning((object)"Sight datablocks are not loaded yet."); return false; } Sights = new Dictionary<string, uint>(StringComparer.Ordinal); HiddenNames.Clear(); List<string> list = new List<string> { "Default" }; int num = 0; int num2 = 0; foreach (GearSightPartDataBlock item in allBlocks) { if (item == null) { continue; } if (IsFrontIronSight(((GameDataBlockBase<GearSightPartDataBlock>)(object)item).name)) { num++; continue; } if (IsHiddenScope(item)) { num2++; continue; } string text = ((GameDataBlockBase<GearSightPartDataBlock>)(object)item).name; if (string.IsNullOrWhiteSpace(text)) { text = "ID_" + ((GameDataBlockBase<GearSightPartDataBlock>)(object)item).persistentID; } if (string.Equals(text, "Default", StringComparison.Ordinal) || Sights.ContainsKey(text)) { text = text + "#" + ((GameDataBlockBase<GearSightPartDataBlock>)(object)item).persistentID; } if (!Sights.ContainsKey(text)) { Sights.Add(text, ((GameDataBlockBase<GearSightPartDataBlock>)(object)item).persistentID); list.Add(text); } } list.Sort(1, list.Count - 1, StringComparer.OrdinalIgnoreCase); SightNames = list.ToArray(); AcceptableValueList<string> val = new AcceptableValueList<string>(SightNames); ScopeChoices.Bind(val); Weapons = new Dictionary<uint, ConfigEntry<string>>(); SightUsers.Clear(); HashSet<string> usedSections = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "General", "Lobby", "Alignment" }; Dictionary<string, string> dictionary = ReadExistingSights(); int num3 = 0; foreach (PlayerOfflineGearDataBlock item2 in allBlocks2) { if (item2 != null && !string.IsNullOrEmpty(item2.GearJSON) && !Weapons.ContainsKey(((GameDataBlockBase<PlayerOfflineGearDataBlock>)(object)item2).persistentID) && ShouldConfigure(item2.GearJSON)) { string text2 = SectionName(item2, usedSections); if (dictionary.TryGetValue(text2, out var value) && !string.Equals(value, "Default", StringComparison.Ordinal) && !Sights.ContainsKey(value)) { Plugin.LogSource.LogWarning((object)("Unknown sight '" + value + "' for " + text2 + ". Leaving that weapon unchanged.")); } string text3 = GearJsonEditor.GetDisplayName(item2.GearJSON) ?? ((GameDataBlockBase<PlayerOfflineGearDataBlock>)(object)item2).name; ConfigEntry<string> value2 = ((BasePlugin)Plugin.Instance).Config.Bind<string>(text2, "Sight", "Default", new ConfigDescription("In-game name: " + text3 + ". Persistent ID: " + ((GameDataBlockBase<PlayerOfflineGearDataBlock>)(object)item2).persistentID + ". Default keeps the current sight. Any other value is a GearSightPart datablock name.", (AcceptableValueBase)(object)val, Array.Empty<object>())); Weapons.Add(((GameDataBlockBase<PlayerOfflineGearDataBlock>)(object)item2).persistentID, value2); IndexWeapon(item2, text3); num3++; } } foreach (List<string> value3 in SightUsers.Values) { value3.Sort(StringComparer.OrdinalIgnoreCase); } ScopeAlignment.Bind(SightNames); ((BasePlugin)Plugin.Instance).Config.Save(); Plugin.LogSource.LogInfo((object)("Selectable Scopes catalog: " + Sights.Count + " sights, " + num3 + " weapons.")); if (num > 0) { Plugin.LogSource.LogInfo((object)("Left out " + num + " front iron sights. The rear sight is the one that aims.")); } if (num2 > 0) { Plugin.LogSource.LogInfo((object)("Left out " + num2 + " unusable sights (Sight 11, IRON_SIGHTS 2B, IRON_SIGHTS 11).")); } return true; } internal static string WeaponKeyFor(GearIDRange range) { if (range == null) { return null; } string text = null; try { text = Signature(range); } catch (Exception ex) { Plugin.LogSource.LogDebug((object)("Weapon signature: " + ex.Message)); } if (text != null && WeaponKeys.TryGetValue(text, out var value)) { return value; } uint compID = range.GetCompID((eGearComponent)2); uint compID2 = range.GetCompID((eGearComponent)16); if (compID == 0 && compID2 == 0) { string publicGearName = range.PublicGearName; if (!string.IsNullOrWhiteSpace(publicGearName)) { return "name-" + SanitizeKey(publicGearName); } return null; } return "cat-" + compID.ToString(CultureInfo.InvariantCulture) + "-rec-" + compID2.ToString(CultureInfo.InvariantCulture); } internal static string WeaponTitleFor(string weaponKey, GearIDRange range) { if (weaponKey != null && WeaponTitles.TryGetValue(weaponKey, out var value) && !string.IsNullOrWhiteSpace(value)) { return value; } if (range != null && !string.IsNullOrWhiteSpace(range.PublicGearName)) { return range.PublicGearName; } return "Weapon"; } internal static bool TryGetAuthoredSight(GearIDRange range, out bool hadSight, out uint sightId) { hadSight = false; sightId = 0u; if (range == null) { return false; } string text; try { text = Signature(range); } catch (Exception ex) { Plugin.LogSource.LogDebug((object)("Weapon signature: " + ex.Message)); return false; } if (text == null || !AuthoredSights.TryGetValue(text, out var value)) { return false; } hadSight = value.HadSight; sightId = value.SightId; return true; } internal static bool TryAlignmentDefault(string weaponKey, out float vertical, out float forward) { vertical = 0f; forward = 0f; if (weaponKey == null || !AlignmentDefaults.TryGetValue(weaponKey, out var value)) { return false; } vertical = value.Vertical; forward = value.Forward; return true; } private static void IndexWeapon(PlayerOfflineGearDataBlock block, string display) { string text = ((GameDataBlockBase<PlayerOfflineGearDataBlock>)(object)block).persistentID.ToString(CultureInfo.InvariantCulture); if (!WeaponTitles.ContainsKey(text)) { WeaponTitles.Add(text, string.IsNullOrWhiteSpace(display) ? ((GameDataBlockBase<PlayerOfflineGearDataBlock>)(object)block).name : display); } string text2 = GearJsonEditor.ComponentSignature(block.GearJSON); if (text2 != null) { if (!WeaponKeys.ContainsKey(text2)) { WeaponKeys.Add(text2, text); } if (!AuthoredSights.ContainsKey(text2)) { long value; bool flag = GearJsonEditor.TryGetComponentValue(block.GearJSON, 21, out value) && value >= 0 && value <= uint.MaxValue; AuthoredSights.Add(text2, new AuthoredSight { HadSight = flag, SightId = (uint)(flag ? value : 0u) }); } } string display2 = (string.IsNullOrWhiteSpace(display) ? ((GameDataBlockBase<PlayerOfflineGearDataBlock>)(object)block).name : display); if (GearJsonEditor.TryGetComponentValue(block.GearJSON, 21, out var value2)) { RememberSightUser(value2, display2); } RememberAlignmentDefault(text, ((GameDataBlockBase<PlayerOfflineGearDataBlock>)(object)block).name, display); if (((GameDataBlockBase<PlayerOfflineGearDataBlock>)(object)block).name != null && BarrelDatablocks.Contains(((GameDataBlockBase<PlayerOfflineGearDataBlock>)(object)block).name)) { BarrelKeys.Add(text); } } internal static bool FollowsBarrel(string weaponKey) { if (weaponKey != null) { return BarrelKeys.Contains(weaponKey); } return false; } private static void RememberAlignmentDefault(string weaponKey, string datablockName, string display) { if (!AlignmentDefaults.ContainsKey(weaponKey) && TryAlignmentPreset(datablockName, out var preset)) { AlignmentDefaults.Add(weaponKey, preset); string text = (string.IsNullOrWhiteSpace(display) ? datablockName : display); Plugin.LogSource.LogInfo((object)("Default alignment for " + text + ": scope vertical " + preset.Vertical.ToString("+0.0000;-0.0000", CultureInfo.InvariantCulture) + ", scope forward " + preset.Forward.ToString("+0.0000;-0.0000", CultureInfo.InvariantCulture) + ".")); } } private static bool TryAlignmentPreset(string datablockName, out AlignmentDefault preset) { if (datablockName != null && AlignmentPresets.TryGetValue(datablockName, out preset)) { return true; } preset = default(AlignmentDefault); return false; } private static string Signature(GearIDRange range) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0032: 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_0038: Invalid comparison between Unknown and I4 //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Expected I4, but got Unknown if (Components == null) { Components = (eGearComponent[])Enum.GetValues(typeof(eGearComponent)); } Dictionary<int, long> dictionary = new Dictionary<int, long>(); for (int i = 0; i < Components.Length; i++) { eGearComponent val = Components[i]; if ((int)val != 0 && (int)val != 21) { uint compID = range.GetCompID(val); if (compID != 0) { dictionary[(int)val] = compID; } } } return GearJsonEditor.FormatSignature(dictionary); } private static string SanitizeKey(string name) { StringBuilder stringBuilder = new StringBuilder(name.Length); foreach (char c in name) { bool flag; switch (c) { case '\t': case '\n': case '\r': case ' ': case '#': case '=': case '[': case ']': flag = true; break; default: flag = false; break; } bool flag2 = flag; stringBuilder.Append(flag2 ? '_' : c); } string text = stringBuilder.ToString().Trim('_'); if (text.Length != 0) { return text; } return "weapon"; } private static bool IsFrontIronSight(string name) { if (string.IsNullOrEmpty(name) || name.Length <= "IronSights_".Length || !name.StartsWith("IronSights_", StringComparison.OrdinalIgnoreCase)) { return false; } string text = name.Substring("IronSights_".Length); while (text.EndsWith("_Copy", StringComparison.OrdinalIgnoreCase)) { text = text.Substring(0, text.Length - "_Copy".Length); } return text.EndsWith("_F", StringComparison.OrdinalIgnoreCase); } internal static bool IsUnusableScope(string name) { if (string.IsNullOrEmpty(name)) { return false; } if (HiddenNames.Contains(name)) { return true; } int num = name.IndexOf('#'); if (num >= 0) { name = name.Substring(0, num); } while (name.EndsWith("_Copy", StringComparison.OrdinalIgnoreCase)) { name = name.Substring(0, name.Length - "_Copy".Length); } if (HiddenNames.Contains(name) || string.Equals(name, "Sight_11", StringComparison.OrdinalIgnoreCase)) { return true; } string text = CompactLabel(name); if (!(text == "IRONSIGHTS2B")) { return text == "IRONSIGHTS11"; } return true; } private static bool IsHiddenScope(GearSightPartDataBlock block) { if (!IsUnusableScope(((GameDataBlockBase<GearSightPartDataBlock>)(object)block).name) && !IsUnusableScope(TitleOf(block, ((GameDataBlockBase<GearSightPartDataBlock>)(object)block).name))) { return false; } if (!string.IsNullOrEmpty(((GameDataBlockBase<GearSightPartDataBlock>)(object)block).name)) { HiddenNames.Add(((GameDataBlockBase<GearSightPartDataBlock>)(object)block).name); } return true; } private static string CompactLabel(string name) { StringBuilder stringBuilder = new StringBuilder(name.Length); foreach (char c in name) { if (c != ' ' && c != '_' && c != '#') { stringBuilder.Append(char.ToUpperInvariant(c)); } } return stringBuilder.ToString(); } private static bool ShouldConfigure(string gearJson) { if (GearJsonEditor.TryGetComponentValue(gearJson, 21, out var _)) { return true; } return IsFirearm(gearJson); } private static bool IsFirearm(string gearJson) { //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_009c: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Invalid comparison between Unknown and I4 //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Invalid comparison between Unknown and I4 if (!GearJsonEditor.TryGetComponentValue(gearJson, 2, out var value)) { return false; } GearCategoryDataBlock block; try { block = GameDataBlockBase<GearCategoryDataBlock>.GetBlock((uint)value); } catch (Exception ex) { Plugin.LogSource.LogDebug((object)("Category " + value + " was not readable: " + ex.Message)); return false; } if (block == null) { return false; } ItemDataBlock block2; try { block2 = GameDataBlockBase<ItemDataBlock>.GetBlock(block.BaseItem); } catch (Exception ex2) { Plugin.LogSource.LogDebug((object)("Item " + block.BaseItem + " was not readable: " + ex2.Message)); return false; } if (block2 == null) { return false; } InventorySlot inventorySlot = block2.inventorySlot; if ((int)inventorySlot != 1) { return (int)inventorySlot == 2; } return true; } private static Dictionary<string, string> ReadExistingSights() { Dictionary<string, string> dictionary = new Dictionary<string, string>(StringComparer.Ordinal); string path = Path.Combine(Paths.ConfigPath, "SelectableScopes.cfg"); if (!File.Exists(path)) { return dictionary; } string text = null; string[] array = File.ReadAllLines(path); for (int i = 0; i < array.Length; i++) { string text2 = array[i].Trim(); if (text2.Length >= 2 && text2[0] == '[' && text2[text2.Length - 1] == ']') { text = text2.Substring(1, text2.Length - 2); } else if (text != null && text2.Length != 0 && text2[0] != '#') { int num = text2.IndexOf('='); if (num > 0 && string.Equals(text2.Substring(0, num).Trim(), "Sight", StringComparison.Ordinal)) { dictionary[text] = text2.Substring(num + 1).Trim(); } } } return dictionary; } internal static string Title(string sightName) { if (IsDefault(sightName)) { return "Default"; } return TitleOf(Find(sightName), sightName); } private static string TitleOf(GearSightPartDataBlock block, string fallback) { object obj; if (block == null) { obj = null; } else { GearPartGeneralData general = block.General; obj = ((general != null) ? general.PublicName : null); } string text = (string)obj; if (!string.IsNullOrWhiteSpace(text)) { string text2 = Localize(text.Trim()); if (HasLetter(text2)) { if (text2.IndexOf('_') < 0 || text2.IndexOf(' ') >= 0) { return text2; } return Prettify(text2); } } return Prettify((block != null && !string.IsNullOrWhiteSpace(((GameDataBlockBase<GearSightPartDataBlock>)(object)block).name)) ? ((GameDataBlockBase<GearSightPartDataBlock>)(object)block).name : fallback); } internal static string MenuLabel(string sightName) { string text = Title(sightName); if (IsDefault(sightName)) { return text; } string text2 = BriefUsers(sightName); if (text2 != null) { return text + " — " + text2; } return text; } internal static string Detail(string sightName) { if (IsDefault(sightName)) { return "Keeps the sight on the weapon"; } GearSightPartDataBlock obj = Find(sightName); GearSightPartProperties val = ((obj != null) ? obj.SightProperties : null); if (val == null || val.WorldFovZoom <= 0) { return "No zoom"; } return "FOV " + val.WorldFovZoom.ToString(CultureInfo.InvariantCulture); } internal static string Describe(string sightName, InventorySlot slot, bool selected) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Invalid comparison between Unknown and I4 string value = (((int)slot == 2) ? "special" : "primary"); StringBuilder stringBuilder = new StringBuilder(); if (selected) { stringBuilder.Append("Selected for your ").Append(value).Append('.') .Append('\n') .Append('\n'); } if (IsDefault(sightName)) { stringBuilder.Append("Keeps the sight already attached to the weapon."); } else { AppendStats(stringBuilder, sightName); stringBuilder.Append("Replaces the sight on your equipped ").Append(value).Append('.'); } stringBuilder.Append('\n').Append("Updates the equipped weapon and its icon."); return stringBuilder.ToString(); } private static void AppendStats(StringBuilder builder, string sightName) { AppendUsers(builder, sightName); GearSightPartDataBlock val = Find(sightName); GearSightPartProperties val2 = ((val != null) ? val.SightProperties : null); if (val2 == null || val2.WorldFovZoom <= 0) { builder.Append("Does not zoom.").Append('\n'); } else { builder.Append("FOV ").Append(val2.WorldFovZoom.ToString(CultureInfo.InvariantCulture)).Append(". A lower number magnifies more.") .Append('\n'); } if (val2 != null && val2.GearFovZoom > 0) { builder.Append("Sight model framing: FOV ").Append(val2.GearFovZoom.ToString(CultureInfo.InvariantCulture)).Append('\n'); } string value = ((val != null && !string.IsNullOrWhiteSpace(((GameDataBlockBase<GearSightPartDataBlock>)(object)val).name)) ? ((GameDataBlockBase<GearSightPartDataBlock>)(object)val).name : sightName); builder.Append("Datablock: ").Append(value).Append('\n'); } private static void AppendUsers(StringBuilder builder, string sightName) { List<string> list = UsersOf(sightName); if (list == null) { builder.Append("Not the stock sight on any weapon.").Append('\n'); return; } builder.Append("Stock sight on: "); for (int i = 0; i < list.Count; i++) { if (i > 0) { builder.Append(", "); } builder.Append(list[i]); } builder.Append('\n'); } private static string BriefUsers(string sightName) { List<string> list = UsersOf(sightName); if (list == null) { return null; } if (list.Count == 1) { return list[0]; } string text = list[0] + ", " + list[1]; int num = list.Count - 2; if (num > 0) { text = text + " +" + num.ToString(CultureInfo.InvariantCulture); } return text; } private static List<string> UsersOf(string sightName) { if (Sights == null || string.IsNullOrEmpty(sightName) || !Sights.TryGetValue(sightName, out var value)) { return null; } if (!SightUsers.TryGetValue(value, out var value2) || value2.Count == 0) { return null; } return value2; } private static void RememberSightUser(long sightValue, string display) { if (sightValue <= 0 || sightValue > uint.MaxValue || string.IsNullOrWhiteSpace(display)) { return; } uint key = (uint)sightValue; if (!SightUsers.TryGetValue(key, out var value)) { value = new List<string>(); SightUsers.Add(key, value); } for (int i = 0; i < value.Count; i++) { if (string.Equals(value[i], display, StringComparison.OrdinalIgnoreCase)) { return; } } value.Add(display); } private static bool HasLetter(string value) { if (string.IsNullOrWhiteSpace(value)) { return false; } for (int i = 0; i < value.Length; i++) { if (char.IsLetter(value[i])) { return true; } } return false; } private static bool IsDefault(string sightName) { if (!string.IsNullOrEmpty(sightName)) { return string.Equals(sightName, "Default", StringComparison.Ordinal); } return true; } private static GearSightPartDataBlock Find(string sightName) { if (Sights == null || string.IsNullOrEmpty(sightName) || !Sights.TryGetValue(sightName, out var value)) { return null; } try { return GameDataBlockBase<GearSightPartDataBlock>.GetBlock(value); } catch (Exception ex) { Plugin.LogSource.LogDebug((object)("Sight " + sightName + " was not readable: " + ex.Message)); return null; } } private static string Localize(string value) { if (!uint.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result)) { return value; } try { string text = Text.Get(result); return string.IsNullOrWhiteSpace(text) ? value : text; } catch (Exception ex) { Plugin.LogSource.LogDebug((object)("Sight name " + result + " was not localized: " + ex.Message)); return value; } } private static string Prettify(string name) { if (string.IsNullOrWhiteSpace(name)) { return "Sight"; } string text = name.Replace('_', ' ').Replace('#', ' ').Trim(); while (text.Contains(" ", StringComparison.Ordinal)) { text = text.Replace(" ", " ", StringComparison.Ordinal); } if (text.StartsWith("Sight ", StringComparison.OrdinalIgnoreCase)) { string text2 = text.Substring("Sight ".Length).Trim(); if (text2.Length > 0 && char.IsLetter(text2[0])) { text = text2; } } if (text.Length != 0) { return text; } return name; } private static string SectionName(PlayerOfflineGearDataBlock gear, HashSet<string> usedSections) { string text = ((GameDataBlockBase<PlayerOfflineGearDataBlock>)(object)gear).name; if (string.IsNullOrWhiteSpace(text)) { text = "Gear" + ((GameDataBlockBase<PlayerOfflineGearDataBlock>)(object)gear).persistentID; } StringBuilder stringBuilder = new StringBuilder(text.Length); string text2 = text; foreach (char c in text2) { bool flag; switch (c) { case '\t': case '\n': case '\r': case '[': case ']': flag = true; break; default: flag = false; break; } bool flag2 = flag; stringBuilder.Append(flag2 ? '_' : c); } string text3 = stringBuilder.ToString().Trim(); if (text3.Length == 0) { text3 = "Gear" + ((GameDataBlockBase<PlayerOfflineGearDataBlock>)(object)gear).persistentID; } if (!usedSections.Add(text3)) { text3 = text3 + "_" + ((GameDataBlockBase<PlayerOfflineGearDataBlock>)(object)gear).persistentID; usedSections.Add(text3); } return text3; } } internal static class ScopeChoices { internal static ConfigEntry<string> Primary { get; private set; } internal static ConfigEntry<string> Special { get; private set; } internal static void Bind(AcceptableValueList<string> acceptable) { Primary = BindEntry("Primary Sight", "Sight used on your equipped primary. Default keeps the weapon's current sight.", acceptable); Special = BindEntry("Special Sight", "Sight used on your equipped special. Default keeps the weapon's current sight.", acceptable); } internal static string Display(InventorySlot slot) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) ConfigEntry<string> val = Entry(slot); if (val == null || string.IsNullOrEmpty(val.Value)) { return "Default"; } return val.Value; } internal static void Set(InventorySlot slot, string sightName) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) ConfigEntry<string> val = Entry(slot); if (val != null) { val.Value = sightName; ((BasePlugin)Plugin.Instance).Config.Save(); } } internal static bool TryGetSightId(InventorySlot slot, out uint sightId) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) sightId = 0u; ConfigEntry<string> val = Entry(slot); if (val == null || ScopeCatalog.Sights == null) { return false; } string value = val.Value; if (string.IsNullOrEmpty(value) || string.Equals(value, "Default", StringComparison.Ordinal)) { return false; } return ScopeCatalog.Sights.TryGetValue(value, out sightId); } private static ConfigEntry<string> BindEntry(string key, string description, AcceptableValueList<string> acceptable) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Expected O, but got Unknown ConfigEntry<string> val = ((BasePlugin)Plugin.Instance).Config.Bind<string>("Lobby", key, "Default", new ConfigDescription(description, (AcceptableValueBase)(object)acceptable, Array.Empty<object>())); if (ScopeCatalog.IsUnusableScope(val.Value)) { Plugin.LogSource.LogInfo((object)("Lobby " + key + " was " + val.Value + ". That scope is no longer in the menu, so the slot is back on Default.")); val.Value = "Default"; } if (!string.IsNullOrEmpty(val.Value) && !string.Equals(val.Value, "Default", StringComparison.Ordinal) && (ScopeCatalog.Sights == null || !ScopeCatalog.Sights.ContainsKey(val.Value))) { Plugin.LogSource.LogWarning((object)("Unknown sight '" + val.Value + "' for Lobby " + key + ". That slot will keep the weapon's current sight.")); } return val; } private static ConfigEntry<string> Entry(InventorySlot slot) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Invalid comparison between Unknown and I4 //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Invalid comparison between Unknown and I4 if ((int)slot == 1) { return Primary; } if ((int)slot == 2) { return Special; } return null; } } internal static class ScopeCrosshair { private const string SightName = "Sight_11"; private static ItemDataBlock Forced; private static bool OriginalValue; private static bool Holding; private static bool Logged; internal static void Prepare(FirstPersonItemHolder holder) { if (!Enabled()) { Release(); } else { if (!IsLocal(holder)) { return; } ItemEquippable wieldedItem = holder.WieldedItem; if ((Object)(object)wieldedItem == (Object)null || !IsSight11(wieldedItem)) { Release(); return; } ItemDataBlock itemDataBlock = ((Item)wieldedItem).ItemDataBlock; if (itemDataBlock == null) { Release(); return; } if (!Holding || Forced == null || ((GameDataBlockBase<ItemDataBlock>)(object)Forced).persistentID != ((GameDataBlockBase<ItemDataBlock>)(object)itemDataBlock).persistentID) { Release(); OriginalValue = itemDataBlock.ShowCrosshairWhenAiming; Forced = itemDataBlock; Holding = true; } if (!itemDataBlock.ShowCrosshairWhenAiming) { itemDataBlock.ShowCrosshairWhenAiming = true; } } } internal static void Keep(FirstPersonItemHolder holder) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Invalid comparison between Unknown and I4 if (!Enabled() || (Object)(object)holder == (Object)null || (int)holder.m_currentState != 3 || !IsLocal(holder)) { return; } ItemEquippable wieldedItem = holder.WieldedItem; if (!((Object)(object)wieldedItem == (Object)null) && IsSight11(wieldedItem)) { LerpingPairFloat crosshairAlpha = holder.CrosshairAlpha; if (crosshairAlpha != null && (((LerpingPair<float>)(object)crosshairAlpha).Target < 0.999f || ((LerpingPair<float>)(object)crosshairAlpha).Start < 0.999f)) { ((LerpingPair<float>)(object)crosshairAlpha).Start = 1f; ((LerpingPair<float>)(object)crosshairAlpha).Target = 1f; } Show(wieldedItem); } } private static void Show(ItemEquippable weapon) { //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) if (!InFirstPerson() || (Object)(object)GuiManager.Current == (Object)null) { return; } CrosshairGuiLayer crosshairLayer = GuiManager.CrosshairLayer; ItemDataBlock itemDataBlock = ((Item)weapon).ItemDataBlock; if (crosshairLayer == null || itemDataBlock == null) { return; } float num; try { num = CellSettingsApply.ApplyHUDCrosshairOpacity(1f); } catch (Exception ex) { Plugin.LogSource.LogDebug((object)("Crosshair opacity: " + ex.Message)); num = 1f; } if (!(num <= 0.001f)) { Crosshair val = itemDataBlock.crosshair; if ((int)val == 0) { val = (Crosshair)1; } if (crosshairLayer.m_currentCrosshair != val) { crosshairLayer.ShowCrosshair(val); } if (crosshairLayer.GetCrosshairAlpha() < num * 0.9f) { crosshairLayer.SetCrosshairAlpha(num); } if (!Logged) { Logged = true; Plugin.LogSource.LogInfo((object)"Sight 11 keeps the crosshair while aiming."); } } } private static bool InFirstPerson() { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Invalid comparison between Unknown and I4 //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Invalid comparison between Unknown and I4 if ((Object)(object)FocusStateManager.Current == (Object)null) { return false; } eFocusState currentState = FocusStateManager.CurrentState; if ((int)currentState != 4) { return (int)currentState == 9; } return true; } private static void Release() { if (Holding) { Holding = false; ItemDataBlock forced = Forced; Forced = null; if (forced != null) { forced.ShowCrosshairWhenAiming = OriginalValue; } } } private static bool IsSight11(ItemEquippable weapon) { GearPartHolder gearPartHolder = weapon.GearPartHolder; GearSightPartDataBlock val = (((Object)(object)gearPartHolder != (Object)null) ? gearPartHolder.SightData : null); if (val != null) { return string.Equals(((GameDataBlockBase<GearSightPartDataBlock>)(object)val).name, "Sight_11", StringComparison.OrdinalIgnoreCase); } return false; } private static bool IsLocal(FirstPersonItemHolder holder) { if ((Object)(object)holder == (Object)null) { return false; } PlayerAgent owner = holder.m_owner; if ((Object)(object)owner != (Object)null) { return ((Agent)owner).IsLocallyOwned; } PlayerAgent val = default(PlayerAgent); if (PlayerManager.TryGetLocalPlayerAgent(ref val) && (Object)(object)val != (Object)null) { return (Object)(object)val.FPItemHolder == (Object)(object)holder; } return false; } private static bool Enabled() { if (Plugin.Enabled != null) { return Plugin.Enabled.Value; } return false; } } internal static class ScopeLoadoutCategory { private const string ButtonName = "SelectableScopes.Button"; private const string CardName = "SelectableScopes.Sight"; private const string ScopeUpId = "\u0001scope-up"; private const string ScopeDownId = "\u0001scope-down"; private const string ForwardId = "\u0001scope-forward"; private const string BackId = "\u0001scope-back"; private const string SaveId = "\u0001align-save"; private const string ResetId = "\u0001align-reset"; private static readonly Color SaveColor = new Color(0.62f, 1f, 0.62f, 1f); private static readonly Color ResetColor = new Color(1f, 0.78f, 0.45f, 1f); private static readonly Color Accent = new Color(0.54f, 0.71f, 0.98f, 1f); private static readonly Dictionary<IntPtr, CM_LobbyScrollItem> Buttons = new Dictionary<IntPtr, CM_LobbyScrollItem>(); private static readonly Dictionary<IntPtr, CM_PlayerLobbyBar> ButtonBars = new Dictionary<IntPtr, CM_PlayerLobbyBar>(); private static int ReleasedFrame = -1; private static readonly List<GameObject> Cards = new List<GameObject>(); private static readonly List<string> RowNames = new List<st