Decompiled source of ECHOX v3.8.0
GearVision.dll
Decompiled 15 hours 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.Reflection; using System.Resources; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using BoneLib; using BoneLib.BoneMenu; using Il2CppInterop.Runtime.InteropTypes.Arrays; using Il2CppSLZ.Marrow; using Il2CppSLZ.Marrow.AI; using MelonLoader; using MelonLoader.Preferences; using Microsoft.CodeAnalysis; using UnityEngine; using UnityEngine.Rendering; using UnityEngine.XR; using WeaponInspector; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: MelonInfo(typeof(WeaponInspectorMod), "ECHOX", "3.8.0", "Cr4shers_inc", null)] [assembly: MelonGame("Stress Level Zero", "BONELAB")] [assembly: MelonOptionalDependencies(new string[] { "BoneLib" })] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")] [assembly: AssemblyCompany("GearVision")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("GearVision")] [assembly: AssemblyTitle("GearVision")] [assembly: NeutralResourcesLanguage("en-US")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace WeaponInspector { public class WeaponInspectorMod : MelonMod { private class ReplayTransform { public Vector3 Position; public Quaternion Rotation = Quaternion.identity; } private class ReplayFrame { public float Time; public ReplayTransform Head = new ReplayTransform(); public ReplayTransform LeftHand = new ReplayTransform(); public ReplayTransform RightHand = new ReplayTransform(); public ReplayTransform Weapon = new ReplayTransform(); public bool HasHead; public bool HasLeftHand; public bool HasRightHand; public bool HasWeapon; public string WeaponName; } private class NPCReplayFrame { public float Time; public Vector3 Position; public Quaternion Rotation = Quaternion.identity; } private enum GearTag { None, Sidearm, Primary, Melee, Utility, Heavy, Experimental } private enum WeaponKind { Firearm, Melee, Unknown } private class WeaponInfo { public GameObject Anchor; public string Name; public WeaponKind Kind; public float Mass; public float Speed; public float Impact; public List<string> ExtraStats = new List<string>(); public List<string> Components = new List<string>(); } private GameObject inspectorRoot; private TextMesh inspectorText; private TextMesh hologramGlowText; private GameObject currentTarget; private WeaponInfo currentWeaponInfo; private string currentWeaponName; private float showUntil; private float currentAlpha; private bool visible; private GameObject lastScannedWeapon; private Material weaponOutlineMaterial; private bool outlineActive; private float outlineStartTime; private float outlineEndTime; private readonly List<Renderer> outlineRenderers = new List<Renderer>(); private readonly List<GameObject> outlineObjects = new List<GameObject>(); private readonly Dictionary<Mesh, Mesh> invertedOutlineMeshCache = new Dictionary<Mesh, Mesh>(); private bool manualInfoVisible; private bool supportSecondaryWasPressed; private GameObject trackedTwoHandWeapon; private bool primaryHandKnown; private bool primaryHandIsLeft; private bool quickLeftWasPressed; private bool quickRightWasPressed; private bool quickScanVisible; private GameObject quickScannedWeapon; private GameObject circleDeckRoot; private LineRenderer outerCircle; private LineRenderer innerCircle; private LineRenderer circlePointer; private Material hologramLineMaterial; private float circleRotation; private GameObject coneRoot; private MeshFilter coneMeshFilter; private MeshRenderer coneRenderer; private bool swooshActive; private float swooshStartTime; private const float SwooshDuration = 0.28f; private AudioSource scanAudioSource; private AudioClip scanAudioClip; private float hologramPulseTimer; private float flickerCountdown; private float flickerEndTime; private float flickerMultiplier = 1f; private Quaternion lockedLocalRotation; private bool hasLockedRotation; private string fullInspectorText = ""; private bool scanActive; private float scanStartTime; private float nextScanUpdate; private int lastScanCharacterCount = -1; private const float ScanDuration = 0.7f; private const float ScanRefreshRate = 1f / 30f; private readonly List<ReplayFrame> replayBuffer = new List<ReplayFrame>(); private readonly List<ReplayFrame> lastKillReplay = new List<ReplayFrame>(); private float nextReplaySampleTime; private readonly Dictionary<int, List<NPCReplayFrame>> npcReplayBuffers = new Dictionary<int, List<NPCReplayFrame>>(); private readonly List<NPCReplayFrame> lastKillNPCReplay = new List<NPCReplayFrame>(); private readonly List<AIBrain> trackedNPCs = new List<AIBrain>(); private float nextNPCRefreshTime; private int killedNPCInstanceId = -1; private bool combatReplayPlaying; private float combatReplayStartTime; private float combatReplayOriginalTimeScale = 1f; private bool replayIntroActive; private bool replayOutroActive; private float replayIntroStart; private float replayOutroStart; private const float ReplayIntroDuration = 1.1f; private const float ReplayOutroDuration = 1.3f; private bool replayKillPulseTriggered; private float replayKillPulse; private GameObject replayRoot; private GameObject replayHeadGhost; private GameObject replayLeftGhost; private GameObject replayRightGhost; private GameObject replayWeaponGhost; private GameObject replayNPCGhost; private GameObject replayNPCHeadGhost; private GameObject replayImpactMarker; private TextMesh replayStatsText; private TextMesh replayIntroText; private TextMesh replayOutroText; private LineRenderer replayHeadPath; private LineRenderer replayLeftPath; private LineRenderer replayRightPath; private LineRenderer replayWeaponPath; private LineRenderer replayBulletPath; private Material replayMaterial; private string replayWeaponName = "UNKNOWN"; private float replayKillDistance; private float replayHitVelocity; private Vector3 replayImpactPoint; private bool replayHasImpactPoint; private Vector3 lastShotOrigin; private Vector3 lastShotDirection; private float lastShotTime; private bool hasLastShot; private MelonPreferences_Category settingsCategory; private MelonPreferences_Entry<bool> enabled; private MelonPreferences_Entry<float> displayDuration; private MelonPreferences_Entry<float> fadeDuration; private MelonPreferences_Entry<bool> fadeEnabled; private MelonPreferences_Entry<float> textSize; private MelonPreferences_Entry<float> offsetX; private MelonPreferences_Entry<float> offsetY; private MelonPreferences_Entry<float> offsetZ; private MelonPreferences_Entry<float> textRed; private MelonPreferences_Entry<float> textGreen; private MelonPreferences_Entry<float> textBlue; private MelonPreferences_Entry<bool> showSpeed; private MelonPreferences_Entry<bool> showImpact; private MelonPreferences_Entry<bool> showComponents; private MelonPreferences_Entry<float> fontIndex; private MelonPreferences_Entry<bool> panelLock; private MelonPreferences_Entry<bool> scanAnimation; private MelonPreferences_Entry<int> flickerStrength; private MelonPreferences_Entry<bool> circleDeckEnabled; private MelonPreferences_Entry<float> circleSpinSpeed; private MelonPreferences_Entry<bool> swooshAnimation; private MelonPreferences_Entry<bool> scanSound; private MelonPreferences_Entry<float> scanSoundVolume; private MelonPreferences_Entry<bool> twoHandInfoToggle; private MelonPreferences_Entry<bool> quickScanEnabled; private MelonPreferences_Entry<float> quickScanRange; private MelonPreferences_Entry<bool> weaponOutlineEnabled; private MelonPreferences_Entry<float> weaponOutlineThickness; private MelonPreferences_Entry<float> weaponOutlineDuration; private MelonPreferences_Entry<bool> showFavoriteMarker; private MelonPreferences_Entry<bool> showTags; private MelonPreferences_Entry<string> favoritesData; private MelonPreferences_Entry<string> tagsData; private MelonPreferences_Entry<bool> combatReplayEnabled; private MelonPreferences_Entry<float> combatReplayLength; private MelonPreferences_Entry<float> combatReplaySpeed; private MelonPreferences_Entry<bool> combatReplayFreezeWorld; private MelonPreferences_Entry<bool> combatReplaySlowMotion; private MelonPreferences_Entry<bool> replayShowHeadPath; private MelonPreferences_Entry<bool> replayShowHandPaths; private MelonPreferences_Entry<bool> replayShowWeaponPath; private MelonPreferences_Entry<bool> replayShowBulletPath; private MelonPreferences_Entry<bool> replayShowImpactMarker; private MelonPreferences_Entry<bool> replayShowKillStats; private MelonPreferences_Entry<bool> replayShowNPC; private MelonPreferences_Entry<bool> replayIntroEnabled; private MelonPreferences_Entry<bool> replayOutroEnabled; private MelonPreferences_Entry<bool> replayKillPulseEnabled; private MelonPreferences_Entry<int> replayHologramStyle; private Font currentFont; private int loadedFontIndex = -1; private readonly string[][] availableFonts = new string[5][] { new string[3] { "Arial", "Liberation Sans", "Roboto" }, new string[3] { "Roboto", "Arial", "Liberation Sans" }, new string[3] { "Times New Roman", "Liberation Serif", "serif" }, new string[3] { "Courier New", "Liberation Mono", "monospace" }, new string[3] { "Verdana", "Arial", "Roboto" } }; private readonly HashSet<string> favoriteWeapons = new HashSet<string>(StringComparer.OrdinalIgnoreCase); private readonly Dictionary<string, GearTag> weaponTags = new Dictionary<string, GearTag>(StringComparer.OrdinalIgnoreCase); private readonly string[] firearmWords = new string[10] { "gun", "pistol", "rifle", "shotgun", "revolver", "smg", "carbine", "firearm", "blaster", "launcher" }; private readonly string[] meleeWords = new string[14] { "knife", "blade", "sword", "katana", "axe", "hatchet", "machete", "bat", "club", "hammer", "crowbar", "spear", "dagger", "melee" }; public override void OnInitializeMelon() { CreatePreferences(); LoadFavorites(); LoadTags(); Hooking.OnGrabObject += OnGrabObject; Hooking.OnReleaseObject += OnReleaseObject; Hooking.OnUIRigCreated += OnUIRigCreated; Hooking.OnLevelLoaded += OnLevelLoaded; Hooking.OnNPCBrainDie += OnNPCBrainDie; Hooking.OnPostFireGun += OnPostFireGun; TryCreateBoneMenu(); ((MelonBase)this).LoggerInstance.Msg("ECHOX OS 0.9.2 loaded."); } public override void OnUpdate() { UpdateTwoHandInfoToggle(); UpdateQuickScan(); UpdateInspector(); UpdateWeaponOutline(); UpdateCombatReplayRecording(); UpdateReplayIntroOutro(); UpdateCombatReplayPlayback(); } private void CreatePreferences() { settingsCategory = MelonPreferences.CreateCategory("ECHOX", "ECHOX"); enabled = settingsCategory.CreateEntry<bool>("Enabled", true, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); displayDuration = settingsCategory.CreateEntry<float>("DisplayDuration", 3f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); fadeDuration = settingsCategory.CreateEntry<float>("FadeDuration", 0.45f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); fadeEnabled = settingsCategory.CreateEntry<bool>("FadeEnabled", true, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); textSize = settingsCategory.CreateEntry<float>("TextSize", 0.006f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); offsetX = settingsCategory.CreateEntry<float>("OffsetX", 0.12f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); offsetY = settingsCategory.CreateEntry<float>("OffsetY", 0.08f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); offsetZ = settingsCategory.CreateEntry<float>("OffsetZ", 0.04f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); textRed = settingsCategory.CreateEntry<float>("TextRed", 0.65f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); textGreen = settingsCategory.CreateEntry<float>("TextGreen", 0.2f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); textBlue = settingsCategory.CreateEntry<float>("TextBlue", 1f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); showSpeed = settingsCategory.CreateEntry<bool>("ShowSpeed", true, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); showImpact = settingsCategory.CreateEntry<bool>("ShowImpact", true, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); showComponents = settingsCategory.CreateEntry<bool>("ShowComponents", false, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); fontIndex = settingsCategory.CreateEntry<float>("FontIndex", 0f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); panelLock = settingsCategory.CreateEntry<bool>("PanelLock", false, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); scanAnimation = settingsCategory.CreateEntry<bool>("ScanAnimation", true, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); flickerStrength = settingsCategory.CreateEntry<int>("FlickerStrength", 1, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); circleDeckEnabled = settingsCategory.CreateEntry<bool>("CircleDeck", true, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); circleSpinSpeed = settingsCategory.CreateEntry<float>("CircleSpinSpeed", 90f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); swooshAnimation = settingsCategory.CreateEntry<bool>("SwooshAnimation", true, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); scanSound = settingsCategory.CreateEntry<bool>("ScanSound", true, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); scanSoundVolume = settingsCategory.CreateEntry<float>("ScanSoundVolume", 0.45f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); twoHandInfoToggle = settingsCategory.CreateEntry<bool>("TwoHandInfoToggle", false, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); quickScanEnabled = settingsCategory.CreateEntry<bool>("QuickScan", true, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); quickScanRange = settingsCategory.CreateEntry<float>("QuickScanRange", 8f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); weaponOutlineEnabled = settingsCategory.CreateEntry<bool>("WeaponOutline", true, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); weaponOutlineThickness = settingsCategory.CreateEntry<float>("OutlineThickness", 0.005f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); weaponOutlineDuration = settingsCategory.CreateEntry<float>("OutlineDuration", 0.85f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); showFavoriteMarker = settingsCategory.CreateEntry<bool>("ShowFavoriteMarker", true, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); showTags = settingsCategory.CreateEntry<bool>("ShowTags", true, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); favoritesData = settingsCategory.CreateEntry<string>("Favorites", "", (string)null, (string)null, false, false, (ValueValidator)null, (string)null); tagsData = settingsCategory.CreateEntry<string>("Tags", "", (string)null, (string)null, false, false, (ValueValidator)null, (string)null); combatReplayEnabled = settingsCategory.CreateEntry<bool>("CombatReplayEnabled", true, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); combatReplayLength = settingsCategory.CreateEntry<float>("CombatReplayLength", 5f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); combatReplaySpeed = settingsCategory.CreateEntry<float>("CombatReplaySpeed", 1f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); combatReplayFreezeWorld = settingsCategory.CreateEntry<bool>("CombatReplayFreezeWorld", true, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); combatReplaySlowMotion = settingsCategory.CreateEntry<bool>("CombatReplaySlowMotion", false, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); replayShowHeadPath = settingsCategory.CreateEntry<bool>("ReplayShowHeadPath", false, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); replayShowHandPaths = settingsCategory.CreateEntry<bool>("ReplayShowHandPaths", true, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); replayShowWeaponPath = settingsCategory.CreateEntry<bool>("ReplayShowWeaponPath", true, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); replayShowBulletPath = settingsCategory.CreateEntry<bool>("ReplayShowBulletPath", true, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); replayShowImpactMarker = settingsCategory.CreateEntry<bool>("ReplayShowImpactMarker", true, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); replayShowKillStats = settingsCategory.CreateEntry<bool>("ReplayShowKillStats", true, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); replayShowNPC = settingsCategory.CreateEntry<bool>("ReplayShowNPC", true, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); replayIntroEnabled = settingsCategory.CreateEntry<bool>("ReplayIntroEnabled", true, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); replayOutroEnabled = settingsCategory.CreateEntry<bool>("ReplayOutroEnabled", true, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); replayKillPulseEnabled = settingsCategory.CreateEntry<bool>("ReplayKillPulse", true, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); replayHologramStyle = settingsCategory.CreateEntry<int>("ReplayHologramStyle", 0, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); } private void OnUIRigCreated() { TryCreateBoneMenu(); } private void OnLevelLoaded(LevelInfo levelInfo) { TryCreateBoneMenu(); StopCombatReplay(); ClearWeaponOutline(); replayBuffer.Clear(); lastKillReplay.Clear(); npcReplayBuffers.Clear(); lastKillNPCReplay.Clear(); trackedNPCs.Clear(); nextReplaySampleTime = 0f; nextNPCRefreshTime = 0f; hasLastShot = false; killedNPCInstanceId = -1; lastScannedWeapon = null; trackedTwoHandWeapon = null; primaryHandKnown = false; } private void TryCreateBoneMenu() { //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0165: Unknown result type (might be due to invalid IL or missing references) //IL_0173: Unknown result type (might be due to invalid IL or missing references) //IL_0197: Unknown result type (might be due to invalid IL or missing references) //IL_01ba: Unknown result type (might be due to invalid IL or missing references) //IL_01ed: Unknown result type (might be due to invalid IL or missing references) //IL_01fb: Unknown result type (might be due to invalid IL or missing references) //IL_021f: Unknown result type (might be due to invalid IL or missing references) //IL_0243: Unknown result type (might be due to invalid IL or missing references) //IL_026a: Unknown result type (might be due to invalid IL or missing references) //IL_028e: Unknown result type (might be due to invalid IL or missing references) //IL_02c1: Unknown result type (might be due to invalid IL or missing references) //IL_02e5: Unknown result type (might be due to invalid IL or missing references) //IL_0308: Unknown result type (might be due to invalid IL or missing references) //IL_033b: Unknown result type (might be due to invalid IL or missing references) //IL_0349: Unknown result type (might be due to invalid IL or missing references) //IL_036d: Unknown result type (might be due to invalid IL or missing references) //IL_039f: Unknown result type (might be due to invalid IL or missing references) //IL_03d2: Unknown result type (might be due to invalid IL or missing references) //IL_03e1: Unknown result type (might be due to invalid IL or missing references) //IL_0405: Unknown result type (might be due to invalid IL or missing references) //IL_041e: Unknown result type (might be due to invalid IL or missing references) //IL_0451: Unknown result type (might be due to invalid IL or missing references) //IL_0484: Unknown result type (might be due to invalid IL or missing references) //IL_04a8: Unknown result type (might be due to invalid IL or missing references) //IL_04cc: Unknown result type (might be due to invalid IL or missing references) //IL_04f0: Unknown result type (might be due to invalid IL or missing references) //IL_0514: Unknown result type (might be due to invalid IL or missing references) //IL_0538: Unknown result type (might be due to invalid IL or missing references) //IL_055c: Unknown result type (might be due to invalid IL or missing references) //IL_0580: Unknown result type (might be due to invalid IL or missing references) //IL_05a4: Unknown result type (might be due to invalid IL or missing references) //IL_05c8: Unknown result type (might be due to invalid IL or missing references) //IL_05ec: Unknown result type (might be due to invalid IL or missing references) //IL_0610: Unknown result type (might be due to invalid IL or missing references) //IL_0633: Unknown result type (might be due to invalid IL or missing references) //IL_065a: Unknown result type (might be due to invalid IL or missing references) //IL_0668: Unknown result type (might be due to invalid IL or missing references) //IL_0681: Unknown result type (might be due to invalid IL or missing references) //IL_06a5: Unknown result type (might be due to invalid IL or missing references) //IL_06c9: Unknown result type (might be due to invalid IL or missing references) //IL_06e2: Unknown result type (might be due to invalid IL or missing references) //IL_06fb: Unknown result type (might be due to invalid IL or missing references) //IL_0714: Unknown result type (might be due to invalid IL or missing references) //IL_072d: Unknown result type (might be due to invalid IL or missing references) //IL_0746: Unknown result type (might be due to invalid IL or missing references) //IL_075f: Unknown result type (might be due to invalid IL or missing references) //IL_0778: Unknown result type (might be due to invalid IL or missing references) //IL_0790: Unknown result type (might be due to invalid IL or missing references) //IL_07a9: Unknown result type (might be due to invalid IL or missing references) //IL_07b7: Unknown result type (might be due to invalid IL or missing references) //IL_07ea: Unknown result type (might be due to invalid IL or missing references) //IL_081c: Unknown result type (might be due to invalid IL or missing references) //IL_084f: Unknown result type (might be due to invalid IL or missing references) //IL_085d: Unknown result type (might be due to invalid IL or missing references) //IL_0890: Unknown result type (might be due to invalid IL or missing references) //IL_08c2: Unknown result type (might be due to invalid IL or missing references) //IL_08f4: Unknown result type (might be due to invalid IL or missing references) //IL_0902: Unknown result type (might be due to invalid IL or missing references) //IL_0926: Unknown result type (might be due to invalid IL or missing references) //IL_0949: Unknown result type (might be due to invalid IL or missing references) try { if (Page.Root == null || Page.Root.GetChildPage("ECHOX") != null) { return; } Color val = default(Color); ((Color)(ref val))..ctor(0.55f, 0.15f, 1f); Page obj = Page.Root.CreatePage("ECHOX", val, 9, true); obj.CreateBool("Enabled", val, enabled.Value, (Action<bool>)delegate(bool value) { enabled.Value = value; if (!value) { HideInspector(immediate: true); ClearWeaponOutline(); StopCombatReplay(); lastScannedWeapon = null; } }); obj.CreateFloat("Display Time", val, displayDuration.Value, 0.25f, 0.5f, 10f, (Action<float>)delegate(float value) { displayDuration.Value = value; }); obj.CreateBool("Fade Out", val, fadeEnabled.Value, (Action<bool>)delegate(bool value) { fadeEnabled.Value = value; if (!value && visible) { currentAlpha = 1f; } }); obj.CreateFloat("Fade Time", val, fadeDuration.Value, 0.05f, 0.05f, 3f, (Action<float>)delegate(float value) { fadeDuration.Value = value; }); obj.CreateFloat("Text Size", val, textSize.Value, 0.001f, 0.002f, 0.03f, (Action<float>)delegate(float value) { textSize.Value = value; UpdateHoloDeckLayout(); }); obj.CreateFloat("Font 0-4", val, fontIndex.Value, 1f, 0f, 4f, (Action<float>)delegate(float value) { fontIndex.Value = Mathf.Round(value); LoadSelectedFont(); }); Page obj2 = obj.CreatePage("Controls", val, 0, true); obj2.CreateBool("Two-Hand Info Toggle", val, twoHandInfoToggle.Value, (Action<bool>)delegate(bool value) { twoHandInfoToggle.Value = value; supportSecondaryWasPressed = false; if (!value) { manualInfoVisible = false; RestoreAutomaticInspector(); } }); obj2.CreateBool("Quick Scan", val, quickScanEnabled.Value, (Action<bool>)delegate(bool value) { quickScanEnabled.Value = value; quickLeftWasPressed = false; quickRightWasPressed = false; if (!value && quickScanVisible) { quickScanVisible = false; quickScannedWeapon = null; HideInspector(immediate: true); } }); obj2.CreateFloat("Quick Scan Range", val, quickScanRange.Value, 0.5f, 1f, 20f, (Action<float>)delegate(float value) { quickScanRange.Value = value; }); Page obj3 = obj.CreatePage("Hologram", val, 8, true); obj3.CreateBool("Panel Lock", val, panelLock.Value, (Action<bool>)delegate(bool value) { panelLock.Value = value; OnPanelLockChanged(); }); obj3.CreateBool("Scan Animation", val, scanAnimation.Value, (Action<bool>)delegate(bool value) { scanAnimation.Value = value; }); obj3.CreateInt("Flicker 0-3", val, flickerStrength.Value, 1, 0, 3, (Action<int>)delegate(int value) { flickerStrength.Value = value; ResetFlicker(); }); obj3.CreateBool("Circle Deck", val, circleDeckEnabled.Value, (Action<bool>)delegate(bool value) { circleDeckEnabled.Value = value; UpdateCircleVisibility(); }); obj3.CreateFloat("Circle Spin Speed", val, circleSpinSpeed.Value, 15f, -360f, 360f, (Action<float>)delegate(float value) { circleSpinSpeed.Value = value; }); obj3.CreateBool("Swoosh Animation", val, swooshAnimation.Value, (Action<bool>)delegate(bool value) { swooshAnimation.Value = value; }); obj3.CreateBool("Scan Sound", val, scanSound.Value, (Action<bool>)delegate(bool value) { scanSound.Value = value; }); obj3.CreateFloat("Scan Volume", val, scanSoundVolume.Value, 0.05f, 0f, 1f, (Action<float>)delegate(float value) { scanSoundVolume.Value = value; if ((Object)(object)scanAudioSource != (Object)null) { scanAudioSource.volume = value; } }); Page obj4 = obj.CreatePage("Weapon Outline", val, 0, true); obj4.CreateBool("Enabled", val, weaponOutlineEnabled.Value, (Action<bool>)delegate(bool value) { weaponOutlineEnabled.Value = value; if (!value) { ClearWeaponOutline(); } }); obj4.CreateFloat("Thickness", val, weaponOutlineThickness.Value, 0.001f, 0.001f, 0.015f, (Action<float>)delegate(float value) { weaponOutlineThickness.Value = value; }); obj4.CreateFloat("Duration", val, weaponOutlineDuration.Value, 0.1f, 0.2f, 3f, (Action<float>)delegate(float value) { weaponOutlineDuration.Value = value; }); Page obj5 = obj.CreatePage("Combat Replay", val, 12, true); obj5.CreateBool("Enabled", val, combatReplayEnabled.Value, (Action<bool>)delegate(bool value) { combatReplayEnabled.Value = value; if (!value) { StopCombatReplay(); replayBuffer.Clear(); lastKillReplay.Clear(); npcReplayBuffers.Clear(); lastKillNPCReplay.Clear(); } }); obj5.CreateFunction("Replay Last Kill", val, (Action)PlayLastCombatReplay); obj5.CreateFloat("Record Length", val, combatReplayLength.Value, 0.5f, 1f, 10f, (Action<float>)delegate(float value) { combatReplayLength.Value = value; }); obj5.CreateFloat("Replay Speed", val, combatReplaySpeed.Value, 0.1f, 0.1f, 2f, (Action<float>)delegate(float value) { combatReplaySpeed.Value = value; }); obj5.CreateBool("Freeze World", val, combatReplayFreezeWorld.Value, (Action<bool>)delegate(bool value) { combatReplayFreezeWorld.Value = value; }); obj5.CreateBool("Slow Motion", val, combatReplaySlowMotion.Value, (Action<bool>)delegate(bool value) { combatReplaySlowMotion.Value = value; }); obj5.CreateBool("Show NPC", val, replayShowNPC.Value, (Action<bool>)delegate(bool value) { replayShowNPC.Value = value; }); obj5.CreateBool("Kill Stats", val, replayShowKillStats.Value, (Action<bool>)delegate(bool value) { replayShowKillStats.Value = value; }); obj5.CreateBool("Intro", val, replayIntroEnabled.Value, (Action<bool>)delegate(bool value) { replayIntroEnabled.Value = value; }); obj5.CreateBool("Outro", val, replayOutroEnabled.Value, (Action<bool>)delegate(bool value) { replayOutroEnabled.Value = value; }); obj5.CreateBool("Kill Pulse", val, replayKillPulseEnabled.Value, (Action<bool>)delegate(bool value) { replayKillPulseEnabled.Value = value; }); obj5.CreateBool("Head Path", val, replayShowHeadPath.Value, (Action<bool>)delegate(bool value) { replayShowHeadPath.Value = value; }); obj5.CreateBool("Hand Paths", val, replayShowHandPaths.Value, (Action<bool>)delegate(bool value) { replayShowHandPaths.Value = value; }); obj5.CreateBool("Weapon Path", val, replayShowWeaponPath.Value, (Action<bool>)delegate(bool value) { replayShowWeaponPath.Value = value; }); obj5.CreateBool("Bullet Path", val, replayShowBulletPath.Value, (Action<bool>)delegate(bool value) { replayShowBulletPath.Value = value; }); obj5.CreateBool("Impact Marker", val, replayShowImpactMarker.Value, (Action<bool>)delegate(bool value) { replayShowImpactMarker.Value = value; }); obj5.CreateInt("Hologram Style 0-2", val, replayHologramStyle.Value, 1, 0, 2, (Action<int>)delegate(int value) { replayHologramStyle.Value = value; UpdateReplayMaterialColor(); }); Page obj6 = obj.CreatePage("Favorites & Tags", val, 7, true); obj6.CreateFunction("Toggle Favorite Held", val, (Action)ToggleFavoriteHeld); obj6.CreateBool("Show Favorite", val, showFavoriteMarker.Value, (Action<bool>)delegate(bool value) { showFavoriteMarker.Value = value; RefreshCurrentDisplay(); }); obj6.CreateBool("Show Tags", val, showTags.Value, (Action<bool>)delegate(bool value) { showTags.Value = value; RefreshCurrentDisplay(); }); obj6.CreateFunction("Tag: Sidearm", val, (Action)delegate { SetCurrentTag(GearTag.Sidearm); }); obj6.CreateFunction("Tag: Primary", val, (Action)delegate { SetCurrentTag(GearTag.Primary); }); obj6.CreateFunction("Tag: Melee", val, (Action)delegate { SetCurrentTag(GearTag.Melee); }); obj6.CreateFunction("Tag: Utility", val, (Action)delegate { SetCurrentTag(GearTag.Utility); }); obj6.CreateFunction("Tag: Heavy", val, (Action)delegate { SetCurrentTag(GearTag.Heavy); }); obj6.CreateFunction("Tag: Experimental", val, (Action)delegate { SetCurrentTag(GearTag.Experimental); }); obj6.CreateFunction("Clear Held Tag", val, (Action)delegate { SetCurrentTag(GearTag.None); }); obj6.CreateFunction("Clear All Favorites", val, (Action)ClearAllFavorites); obj6.CreateFunction("Clear All Tags", val, (Action)ClearAllTags); Page obj7 = obj.CreatePage("Offset", val, 0, true); obj7.CreateFloat("X", val, offsetX.Value, 0.01f, -1f, 1f, (Action<float>)delegate(float value) { offsetX.Value = value; }); obj7.CreateFloat("Y", val, offsetY.Value, 0.01f, -1f, 1f, (Action<float>)delegate(float value) { offsetY.Value = value; }); obj7.CreateFloat("Z", val, offsetZ.Value, 0.01f, -1f, 1f, (Action<float>)delegate(float value) { offsetZ.Value = value; }); Page obj8 = obj.CreatePage("Text Color", val, 0, true); obj8.CreateFloat("Red", val, textRed.Value, 0.05f, 0f, 1f, (Action<float>)delegate(float value) { textRed.Value = value; ApplyInspectorVisuals(); UpdateReplayMaterialColor(); }); obj8.CreateFloat("Green", val, textGreen.Value, 0.05f, 0f, 1f, (Action<float>)delegate(float value) { textGreen.Value = value; ApplyInspectorVisuals(); UpdateReplayMaterialColor(); }); obj8.CreateFloat("Blue", val, textBlue.Value, 0.05f, 0f, 1f, (Action<float>)delegate(float value) { textBlue.Value = value; ApplyInspectorVisuals(); UpdateReplayMaterialColor(); }); Page obj9 = obj.CreatePage("Information", val, 0, true); obj9.CreateBool("Show Speed", val, showSpeed.Value, (Action<bool>)delegate(bool value) { showSpeed.Value = value; RefreshCurrentDisplay(); }); obj9.CreateBool("Show Impact", val, showImpact.Value, (Action<bool>)delegate(bool value) { showImpact.Value = value; RefreshCurrentDisplay(); }); obj9.CreateBool("Show Components", val, showComponents.Value, (Action<bool>)delegate(bool value) { showComponents.Value = value; RefreshCurrentDisplay(); }); } catch (Exception ex) { ((MelonBase)this).LoggerInstance.Warning("ECHOX BoneMenu setup failed: " + ex.Message); } } private void OnNPCBrainDie(AIBrain brain) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) if (!combatReplayEnabled.Value || (Object)(object)brain == (Object)null) { return; } try { Transform transform = ((Component)brain).transform; if ((Object)(object)transform != (Object)null) { replayImpactPoint = transform.position; replayHasImpactPoint = true; if ((Object)(object)Player.Head != (Object)null) { replayKillDistance = Vector3.Distance(Player.Head.position, replayImpactPoint); } } killedNPCInstanceId = ((Object)brain).GetInstanceID(); lastKillNPCReplay.Clear(); if (npcReplayBuffers.TryGetValue(killedNPCInstanceId, out var value)) { for (int i = 0; i < value.Count; i++) { NPCReplayFrame nPCReplayFrame = value[i]; NPCReplayFrame nPCReplayFrame2 = new NPCReplayFrame(); nPCReplayFrame2.Time = nPCReplayFrame.Time; nPCReplayFrame2.Position = nPCReplayFrame.Position; nPCReplayFrame2.Rotation = nPCReplayFrame.Rotation; lastKillNPCReplay.Add(nPCReplayFrame2); } } replayHitVelocity = GetCurrentWeaponVelocity(); CaptureCombatReplay(); } catch (Exception ex) { ((MelonBase)this).LoggerInstance.Warning("ECHOX combat capture failed: " + ex.Message); } } private void OnPostFireGun(Gun gun) { //IL_0014: 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_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)gun == (Object)null) { return; } try { Transform transform = ((Component)gun).transform; lastShotOrigin = transform.position; lastShotDirection = transform.forward; lastShotTime = Time.unscaledTime; hasLastShot = true; } catch { } } private void UpdateCombatReplayRecording() { //IL_0170: Unknown result type (might be due to invalid IL or missing references) //IL_0175: Unknown result type (might be due to invalid IL or missing references) //IL_0187: Unknown result type (might be due to invalid IL or missing references) //IL_018c: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) if (!combatReplayEnabled.Value || combatReplayPlaying || replayIntroActive || replayOutroActive) { return; } float unscaledTime = Time.unscaledTime; if (unscaledTime < nextReplaySampleTime) { return; } nextReplaySampleTime = unscaledTime + 1f / 30f; ReplayFrame replayFrame = new ReplayFrame(); replayFrame.Time = unscaledTime; if ((Object)(object)Player.Head != (Object)null) { replayFrame.HasHead = true; replayFrame.Head.Position = Player.Head.position; replayFrame.Head.Rotation = Player.Head.rotation; } try { Hand leftHand = Player.LeftHand; if ((Object)(object)leftHand != (Object)null) { Transform transform = ((Component)leftHand).transform; replayFrame.HasLeftHand = true; replayFrame.LeftHand.Position = transform.position; replayFrame.LeftHand.Rotation = transform.rotation; } Hand rightHand = Player.RightHand; if ((Object)(object)rightHand != (Object)null) { Transform transform2 = ((Component)rightHand).transform; replayFrame.HasRightHand = true; replayFrame.RightHand.Position = transform2.position; replayFrame.RightHand.Rotation = transform2.rotation; } } catch { } try { GameObject objectInHand = Player.GetObjectInHand(Player.RightHand); if ((Object)(object)objectInHand == (Object)null) { objectInHand = Player.GetObjectInHand(Player.LeftHand); } if ((Object)(object)objectInHand != (Object)null) { GameObject val = FindWeaponRoot(objectInHand); if ((Object)(object)val != (Object)null) { replayFrame.HasWeapon = true; replayFrame.Weapon.Position = val.transform.position; replayFrame.Weapon.Rotation = val.transform.rotation; replayFrame.WeaponName = CleanName(((Object)val).name); } } } catch { } replayBuffer.Add(replayFrame); float num = unscaledTime - Mathf.Clamp(combatReplayLength.Value, 1f, 10f); while (replayBuffer.Count > 0 && replayBuffer[0].Time < num) { replayBuffer.RemoveAt(0); } while (replayBuffer.Count > 320) { replayBuffer.RemoveAt(0); } RecordNearbyNPCs(unscaledTime); } private void RecordNearbyNPCs(float now) { //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Unknown result type (might be due to invalid IL or missing references) if (now >= nextNPCRefreshTime) { nextNPCRefreshTime = now + 1f; RefreshTrackedNPCs(); } if (trackedNPCs.Count == 0) { return; } Vector3 val = (((Object)(object)Player.Head != (Object)null) ? Player.Head.position : Vector3.zero); int num = 0; for (int num2 = trackedNPCs.Count - 1; num2 >= 0 && num < 8; num2--) { AIBrain val2 = trackedNPCs[num2]; if ((Object)(object)val2 == (Object)null) { trackedNPCs.RemoveAt(num2); continue; } Transform transform; try { transform = ((Component)val2).transform; } catch { continue; } if (!((Object)(object)transform == (Object)null) && !(Vector3.Distance(val, transform.position) > 35f)) { int instanceID = ((Object)val2).GetInstanceID(); if (!npcReplayBuffers.TryGetValue(instanceID, out var value)) { value = new List<NPCReplayFrame>(); npcReplayBuffers[instanceID] = value; } NPCReplayFrame nPCReplayFrame = new NPCReplayFrame(); nPCReplayFrame.Time = now; nPCReplayFrame.Position = transform.position; nPCReplayFrame.Rotation = transform.rotation; value.Add(nPCReplayFrame); float num3 = now - Mathf.Clamp(combatReplayLength.Value, 1f, 10f); while (value.Count > 0 && value[0].Time < num3) { value.RemoveAt(0); } while (value.Count > 320) { value.RemoveAt(0); } num++; } } } private void RefreshTrackedNPCs() { try { trackedNPCs.Clear(); AIBrain[] array = Il2CppArrayBase<AIBrain>.op_Implicit(Object.FindObjectsOfType<AIBrain>()); if (array == null) { return; } int num = Mathf.Min(array.Length, 16); for (int i = 0; i < num; i++) { if ((Object)(object)array[i] != (Object)null) { trackedNPCs.Add(array[i]); } } } catch { } } private void CaptureCombatReplay() { //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) if (!combatReplayEnabled.Value || replayBuffer.Count < 2) { return; } lastKillReplay.Clear(); for (int i = 0; i < replayBuffer.Count; i++) { ReplayFrame replayFrame = replayBuffer[i]; ReplayFrame replayFrame2 = new ReplayFrame(); replayFrame2.Time = replayFrame.Time; replayFrame2.HasHead = replayFrame.HasHead; replayFrame2.HasLeftHand = replayFrame.HasLeftHand; replayFrame2.HasRightHand = replayFrame.HasRightHand; replayFrame2.HasWeapon = replayFrame.HasWeapon; replayFrame2.Head.Position = replayFrame.Head.Position; replayFrame2.Head.Rotation = replayFrame.Head.Rotation; replayFrame2.LeftHand.Position = replayFrame.LeftHand.Position; replayFrame2.LeftHand.Rotation = replayFrame.LeftHand.Rotation; replayFrame2.RightHand.Position = replayFrame.RightHand.Position; replayFrame2.RightHand.Rotation = replayFrame.RightHand.Rotation; replayFrame2.Weapon.Position = replayFrame.Weapon.Position; replayFrame2.Weapon.Rotation = replayFrame.Weapon.Rotation; replayFrame2.WeaponName = replayFrame.WeaponName; lastKillReplay.Add(replayFrame2); } replayWeaponName = "UNKNOWN"; for (int num = lastKillReplay.Count - 1; num >= 0; num--) { if (lastKillReplay[num].HasWeapon && !string.IsNullOrWhiteSpace(lastKillReplay[num].WeaponName)) { replayWeaponName = lastKillReplay[num].WeaponName; break; } } ((MelonBase)this).LoggerInstance.Msg("ECHOX OS // COMBAT ECHO CAPTURED // " + lastKillReplay.Count + " frames // " + replayWeaponName); } private void PlayLastCombatReplay() { if (!combatReplayEnabled.Value || combatReplayPlaying || replayIntroActive || replayOutroActive || lastKillReplay.Count < 2) { return; } CreateReplayObjects(); if (!((Object)(object)replayRoot == (Object)null)) { combatReplayOriginalTimeScale = Time.timeScale; if (combatReplayFreezeWorld.Value) { Time.timeScale = 0f; } replayKillPulse = 0f; replayKillPulseTriggered = false; if (replayIntroEnabled.Value) { replayIntroActive = true; replayOutroActive = false; replayIntroStart = Time.unscaledTime; combatReplayPlaying = false; ShowReplayIntro(); } else { BeginActualReplay(); } } } private void BeginActualReplay() { replayIntroActive = false; combatReplayPlaying = true; combatReplayStartTime = Time.unscaledTime; if (replayShowKillStats.Value) { CreateReplayStatsPanel(); } } private void ShowReplayIntro() { replayIntroText = CreateReplayText("ECHOX_ReplayIntro", "ECHOX OS\nRECONSTRUCTING COMBAT ECHO...", centered: true); } private void BeginReplayOutro() { if (!replayOutroActive) { combatReplayPlaying = false; if ((Object)(object)replayStatsText != (Object)null) { Object.Destroy((Object)(object)((Component)replayStatsText).gameObject); replayStatsText = null; } if (!replayOutroEnabled.Value) { FinishCombatReplay(); return; } replayOutroActive = true; replayOutroStart = Time.unscaledTime; replayOutroText = CreateReplayText("ECHOX_ReplayOutro", "ECHO COMPLETE\n" + GetLastReplayDuration().ToString("0.00") + " SEC ANALYZED", centered: true); } } private void UpdateReplayIntroOutro() { float unscaledTime = Time.unscaledTime; if (replayIntroActive) { FaceReplayTextToPlayer(replayIntroText); if (unscaledTime - replayIntroStart >= 1.1f) { replayIntroActive = false; if ((Object)(object)replayIntroText != (Object)null) { Object.Destroy((Object)(object)((Component)replayIntroText).gameObject); replayIntroText = null; } BeginActualReplay(); } } else if (replayOutroActive) { FaceReplayTextToPlayer(replayOutroText); if (unscaledTime - replayOutroStart >= 1.3f) { replayOutroActive = false; FinishCombatReplay(); } } } private float GetLastReplayDuration() { if (lastKillReplay.Count < 2) { return 0f; } return lastKillReplay[lastKillReplay.Count - 1].Time - lastKillReplay[0].Time; } private void UpdateCombatReplayPlayback() { if (!combatReplayPlaying || lastKillReplay.Count < 2) { return; } float num = Mathf.Max(0.1f, combatReplaySpeed.Value); if (combatReplaySlowMotion.Value) { num *= 0.35f; } float num2 = (Time.unscaledTime - combatReplayStartTime) * num; ReplayFrame replayFrame = lastKillReplay[0]; float num3 = lastKillReplay[lastKillReplay.Count - 1].Time - replayFrame.Time; if (num3 <= 0.001f) { BeginReplayOutro(); return; } if (num2 >= num3) { BeginReplayOutro(); return; } float num4 = replayFrame.Time + num2; int num5 = FindReplayFrameIndex(num4); ReplayFrame replayFrame2 = lastKillReplay[num5]; ReplayFrame replayFrame3 = lastKillReplay[Mathf.Min(num5 + 1, lastKillReplay.Count - 1)]; float num6 = Mathf.Max(0.0001f, replayFrame3.Time - replayFrame2.Time); float t = Mathf.Clamp01((num4 - replayFrame2.Time) / num6); SetReplayObjectState(replayHeadGhost, replayFrame2.HasHead && replayFrame3.HasHead); if (replayFrame2.HasHead && replayFrame3.HasHead) { ApplyReplayTransform(replayHeadGhost, replayFrame2.Head, replayFrame3.Head, t); } SetReplayObjectState(replayLeftGhost, replayFrame2.HasLeftHand && replayFrame3.HasLeftHand); if (replayFrame2.HasLeftHand && replayFrame3.HasLeftHand) { ApplyReplayTransform(replayLeftGhost, replayFrame2.LeftHand, replayFrame3.LeftHand, t); } SetReplayObjectState(replayRightGhost, replayFrame2.HasRightHand && replayFrame3.HasRightHand); if (replayFrame2.HasRightHand && replayFrame3.HasRightHand) { ApplyReplayTransform(replayRightGhost, replayFrame2.RightHand, replayFrame3.RightHand, t); } SetReplayObjectState(replayWeaponGhost, replayFrame2.HasWeapon && replayFrame3.HasWeapon); if (replayFrame2.HasWeapon && replayFrame3.HasWeapon) { ApplyReplayTransform(replayWeaponGhost, replayFrame2.Weapon, replayFrame3.Weapon, t); } UpdateNPCReplay(num4); UpdateReplayStatsPanel(num2, num3); if (replayKillPulseEnabled.Value) { UpdateKillMomentPulse(num2, num3); } UpdateReplayMaterialColor(); } private int FindReplayFrameIndex(float targetTime) { for (int i = 0; i < lastKillReplay.Count - 1; i++) { if (lastKillReplay[i + 1].Time >= targetTime) { return i; } } return Mathf.Max(0, lastKillReplay.Count - 2); } private void UpdateNPCReplay(float targetTime) { //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0105: 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_0112: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_0148: Unknown result type (might be due to invalid IL or missing references) //IL_014a: 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_0160: Unknown result type (might be due to invalid IL or missing references) //IL_0165: Unknown result type (might be due to invalid IL or missing references) //IL_017a: Unknown result type (might be due to invalid IL or missing references) if (!replayShowNPC.Value || (Object)(object)replayNPCGhost == (Object)null || lastKillNPCReplay.Count < 2) { SetReplayObjectState(replayNPCGhost, state: false); SetReplayObjectState(replayNPCHeadGhost, state: false); return; } SetReplayObjectState(replayNPCGhost, state: true); SetReplayObjectState(replayNPCHeadGhost, state: true); int num = 0; for (int i = 0; i < lastKillNPCReplay.Count - 1; i++) { if (lastKillNPCReplay[i + 1].Time >= targetTime) { num = i; break; } } NPCReplayFrame nPCReplayFrame = lastKillNPCReplay[num]; NPCReplayFrame nPCReplayFrame2 = lastKillNPCReplay[Mathf.Min(num + 1, lastKillNPCReplay.Count - 1)]; float num2 = Mathf.Max(0.0001f, nPCReplayFrame2.Time - nPCReplayFrame.Time); float num3 = Mathf.Clamp01((targetTime - nPCReplayFrame.Time) / num2); Vector3 val = Vector3.Lerp(nPCReplayFrame.Position, nPCReplayFrame2.Position, num3); Quaternion val2 = Quaternion.Slerp(nPCReplayFrame.Rotation, nPCReplayFrame2.Rotation, num3); replayNPCGhost.transform.position = val; replayNPCGhost.transform.rotation = val2; replayNPCHeadGhost.transform.position = val + val2 * new Vector3(0f, 0.9f, 0f); replayNPCHeadGhost.transform.rotation = val2; } private void CreateReplayStatsPanel() { string text = BuildReplayStatsText(0f, GetLastReplayDuration()); replayStatsText = CreateReplayText("ECHOX_KillStats", text, centered: false); PositionReplayStatsPanel(); } private string BuildReplayStatsText(float elapsed, float replayLength) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("ECHOX OS // KILL DATA"); stringBuilder.AppendLine("--------------------"); stringBuilder.Append("WEAPON: "); stringBuilder.AppendLine(replayWeaponName.ToUpperInvariant()); stringBuilder.Append("DISTANCE: "); stringBuilder.Append(replayKillDistance.ToString("0.00")); stringBuilder.AppendLine(" M"); stringBuilder.Append("HIT VELOCITY: "); stringBuilder.Append(replayHitVelocity.ToString("0.0")); stringBuilder.AppendLine(" M/S"); stringBuilder.Append("REPLAY TIME: "); stringBuilder.Append(elapsed.ToString("0.00")); stringBuilder.Append(" / "); stringBuilder.Append(replayLength.ToString("0.00")); stringBuilder.AppendLine(" SEC"); stringBuilder.Append("STATUS: "); if (replayLength - elapsed <= 0.15f) { stringBuilder.AppendLine("KILL FRAME"); } else { stringBuilder.AppendLine("RECONSTRUCTING"); } return stringBuilder.ToString().TrimEnd(); } private void UpdateReplayStatsPanel(float elapsed, float replayLength) { if (!replayShowKillStats.Value) { if ((Object)(object)replayStatsText != (Object)null) { ((Component)replayStatsText).gameObject.SetActive(false); } return; } if ((Object)(object)replayStatsText == (Object)null) { CreateReplayStatsPanel(); } if (!((Object)(object)replayStatsText == (Object)null)) { ((Component)replayStatsText).gameObject.SetActive(true); replayStatsText.text = BuildReplayStatsText(elapsed, replayLength); PositionReplayStatsPanel(); } } private void PositionReplayStatsPanel() { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005e: 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_006d: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)replayStatsText == (Object)null) && !((Object)(object)Player.Head == (Object)null)) { Transform head = Player.Head; ((Component)replayStatsText).transform.position = head.position + head.forward * 1.05f + head.right * 0.42f - head.up * 0.05f; FaceReplayTextToPlayer(replayStatsText); } } private TextMesh CreateReplayText(string name, string text, bool centered) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Expected O, but got Unknown //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject(name); if ((Object)(object)replayRoot != (Object)null) { val.transform.SetParent(replayRoot.transform, true); } TextMesh val2 = val.AddComponent<TextMesh>(); val2.text = text; val2.fontSize = 40; val2.characterSize = 0.006f; val2.richText = false; val2.anchor = (TextAnchor)(centered ? 4 : 0); val2.alignment = (TextAlignment)(centered ? 1 : 0); val2.color = GetReplayColor(0.9f); if ((Object)(object)currentFont != (Object)null) { val2.font = currentFont; Renderer component = ((Component)val2).GetComponent<Renderer>(); if ((Object)(object)component != (Object)null && (Object)(object)currentFont.material != (Object)null) { component.sharedMaterial = currentFont.material; } } if ((Object)(object)Player.Head != (Object)null) { Transform head = Player.Head; val.transform.position = head.position + head.forward * 1.1f; FaceReplayTextToPlayer(val2); } return val2; } private void FaceReplayTextToPlayer(TextMesh text) { //IL_001d: 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) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_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_0052: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)text == (Object)null) && !((Object)(object)Player.Head == (Object)null)) { Vector3 val = ((Component)text).transform.position - Player.Head.position; if (((Vector3)(ref val)).sqrMagnitude > 0.0001f) { ((Component)text).transform.rotation = Quaternion.LookRotation(((Vector3)(ref val)).normalized, Vector3.up); } } } private void UpdateKillMomentPulse(float elapsed, float replayLength) { float num = replayLength - elapsed; if (!replayKillPulseTriggered && num <= 0.15f) { replayKillPulseTriggered = true; replayKillPulse = 1f; } if (replayKillPulseTriggered) { replayKillPulse = Mathf.MoveTowards(replayKillPulse, 0f, Time.unscaledDeltaTime * 4.5f); ApplyReplayPulse(); } } private void ApplyReplayPulse() { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) float num = Mathf.Clamp01(replayKillPulse); if ((Object)(object)replayMaterial != (Object)null) { Color replayColor = GetReplayColor(0.32f); Color val = default(Color); ((Color)(ref val))..ctor(Mathf.Clamp01(replayColor.r + num * 0.35f), Mathf.Clamp01(replayColor.g + num * 0.35f), Mathf.Clamp01(replayColor.b + num * 0.35f), Mathf.Clamp01(replayColor.a + num * 0.55f)); if (replayMaterial.HasProperty("_Color")) { replayMaterial.SetColor("_Color", val); } if (replayMaterial.HasProperty("_TintColor")) { replayMaterial.SetColor("_TintColor", val); } } if ((Object)(object)replayImpactMarker != (Object)null) { float num2 = Mathf.Lerp(0.06f, 0.14f, num); replayImpactMarker.transform.localScale = Vector3.one * num2; } } private void CreateReplayObjects() { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Expected O, but got Unknown //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: 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) ClearReplayObjects(); replayRoot = new GameObject("ECHOX_CombatReplay"); replayHeadGhost = CreateReplayMarker("Head", (PrimitiveType)0, new Vector3(0.17f, 0.17f, 0.17f)); replayLeftGhost = CreateReplayMarker("LeftHand", (PrimitiveType)0, new Vector3(0.075f, 0.075f, 0.075f)); replayRightGhost = CreateReplayMarker("RightHand", (PrimitiveType)0, new Vector3(0.075f, 0.075f, 0.075f)); replayWeaponGhost = CreateReplayMarker("Weapon", (PrimitiveType)3, new Vector3(0.045f, 0.045f, 0.24f)); replayNPCGhost = CreateReplayMarker("NPC_Body", (PrimitiveType)1, new Vector3(0.32f, 0.65f, 0.32f)); replayNPCHeadGhost = CreateReplayMarker("NPC_Head", (PrimitiveType)0, new Vector3(0.18f, 0.18f, 0.18f)); if (!replayShowNPC.Value) { replayNPCGhost.SetActive(false); replayNPCHeadGhost.SetActive(false); } CreateReplayPaths(); CreateBulletTrajectory(); CreateImpactMarker(); } private GameObject CreateReplayMarker(string name, PrimitiveType primitive, Vector3 scale) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) GameObject val = GameObject.CreatePrimitive(primitive); ((Object)val).name = "ECHOX_Replay_" + name; if ((Object)(object)replayRoot != (Object)null) { val.transform.SetParent(replayRoot.transform, true); } val.transform.localScale = scale; Collider component = val.GetComponent<Collider>(); if ((Object)(object)component != (Object)null) { Object.Destroy((Object)(object)component); } Renderer component2 = val.GetComponent<Renderer>(); if ((Object)(object)component2 != (Object)null) { component2.shadowCastingMode = (ShadowCastingMode)0; component2.receiveShadows = false; component2.lightProbeUsage = (LightProbeUsage)0; component2.reflectionProbeUsage = (ReflectionProbeUsage)0; component2.sharedMaterial = GetReplayMaterial(); } return val; } private void SetReplayObjectState(GameObject obj, bool state) { if ((Object)(object)obj != (Object)null && obj.activeSelf != state) { obj.SetActive(state); } } private void ApplyReplayTransform(GameObject obj, ReplayTransform a, ReplayTransform b, float t) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0035: 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) if (!((Object)(object)obj == (Object)null)) { obj.transform.position = Vector3.Lerp(a.Position, b.Position, t); obj.transform.rotation = Quaternion.Slerp(a.Rotation, b.Rotation, t); } } private void CreateReplayPaths() { if (replayShowHeadPath.Value) { replayHeadPath = CreateReplayPath("HeadPath", 0); } if (replayShowHandPaths.Value) { replayLeftPath = CreateReplayPath("LeftHandPath", 1); replayRightPath = CreateReplayPath("RightHandPath", 2); } if (replayShowWeaponPath.Value) { replayWeaponPath = CreateReplayPath("WeaponPath", 3); } } private LineRenderer CreateReplayPath(string name, int pathType) { //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: 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_0130: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0165: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) List<Vector3> list = new List<Vector3>(); for (int i = 0; i < lastKillReplay.Count; i++) { ReplayFrame replayFrame = lastKillReplay[i]; if (pathType == 0 && replayFrame.HasHead) { list.Add(replayFrame.Head.Position); } else if (pathType == 1 && replayFrame.HasLeftHand) { list.Add(replayFrame.LeftHand.Position); } else if (pathType == 2 && replayFrame.HasRightHand) { list.Add(replayFrame.RightHand.Position); } else if (pathType == 3 && replayFrame.HasWeapon) { list.Add(replayFrame.Weapon.Position); } } if (list.Count < 2) { return null; } GameObject val = new GameObject("ECHOX_" + name); val.transform.SetParent(replayRoot.transform, true); LineRenderer val2 = val.AddComponent<LineRenderer>(); val2.useWorldSpace = true; val2.loop = false; val2.positionCount = list.Count; val2.startWidth = 0.008f; val2.endWidth = 0.003f; ((Renderer)val2).sharedMaterial = GetReplayMaterial(); Color val3 = (val2.startColor = GetReplayColor(0.5f)); val2.endColor = new Color(val3.r, val3.g, val3.b, 0.08f); for (int j = 0; j < list.Count; j++) { val2.SetPosition(j, list[j]); } return val2; } private void CreateBulletTrajectory() { //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Expected O, but got Unknown //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) if (replayShowBulletPath.Value && hasLastShot && replayHasImpactPoint && lastKillReplay.Count != 0 && !(Mathf.Abs(lastKillReplay[lastKillReplay.Count - 1].Time - lastShotTime) > 2f)) { GameObject val = new GameObject("ECHOX_BulletTrajectory"); val.transform.SetParent(replayRoot.transform, true); replayBulletPath = val.AddComponent<LineRenderer>(); replayBulletPath.useWorldSpace = true; replayBulletPath.positionCount = 2; replayBulletPath.startWidth = 0.006f; replayBulletPath.endWidth = 0.002f; ((Renderer)replayBulletPath).sharedMaterial = GetReplayMaterial(); Color replayColor = GetReplayColor(0.8f); replayBulletPath.startColor = replayColor; replayBulletPath.endColor = new Color(replayColor.r, replayColor.g, replayColor.b, 0.15f); replayBulletPath.SetPosition(0, lastShotOrigin); replayBulletPath.SetPosition(1, replayImpactPoint); } } private void CreateImpactMarker() { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) if (replayShowImpactMarker.Value && replayHasImpactPoint) { replayImpactMarker = CreateReplayMarker("Impact", (PrimitiveType)0, new Vector3(0.06f, 0.06f, 0.06f)); if ((Object)(object)replayImpactMarker != (Object)null) { replayImpactMarker.transform.position = replayImpactPoint; } } } private Material GetReplayMaterial() { //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Expected O, but got Unknown if ((Object)(object)replayMaterial != (Object)null) { UpdateReplayMaterialColor(); return replayMaterial; } Shader val = Shader.Find("Sprites/Default"); if ((Object)(object)val == (Object)null) { val = Shader.Find("Unlit/Color"); } if ((Object)(object)val == (Object)null) { return null; } replayMaterial = new Material(val); ((Object)replayMaterial).name = "ECHOX_ReplayMaterial"; if (replayMaterial.HasProperty("_ZWrite")) { replayMaterial.SetInt("_ZWrite", 0); } replayMaterial.renderQueue = 3000; UpdateReplayMaterialColor(); return replayMaterial; } private Color GetReplayColor(float alpha) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: 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) return (Color)(Mathf.Clamp(replayHologramStyle.Value, 0, 2) switch { 1 => new Color(textRed.Value, textGreen.Value, textBlue.Value, Mathf.Clamp01(alpha * 1.25f)), 2 => new Color(Mathf.Clamp01(textRed.Value + 0.2f), Mathf.Clamp01(textGreen.Value + 0.2f), Mathf.Clamp01(textBlue.Value + 0.2f), Mathf.Clamp01(alpha * 0.55f)), _ => new Color(textRed.Value, textGreen.Value, textBlue.Value, Mathf.Clamp01(alpha)), }); } private void UpdateReplayMaterialColor() { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)replayMaterial == (Object)null) && !(replayKillPulse > 0.001f)) { Color replayColor = GetReplayColor(0.32f); if (replayMaterial.HasProperty("_Color")) { replayMaterial.SetColor("_Color", replayColor); } if (replayMaterial.HasProperty("_TintColor")) { replayMaterial.SetColor("_TintColor", replayColor); } } } private void StopCombatReplay() { combatReplayPlaying = false; replayIntroActive = false; replayOutroActive = false; replayKillPulse = 0f; replayKillPulseTriggered = false; if (combatReplayFreezeWorld != null && combatReplayFreezeWorld.Value) { Time.timeScale = combatReplayOriginalTimeScale; } ClearReplayObjects(); } private void FinishCombatReplay() { combatReplayPlaying = false; replayIntroActive = false; replayOutroActive = false; replayKillPulse = 0f; replayKillPulseTriggered = false; if (combatReplayFreezeWorld.Value) { Time.timeScale = combatReplayOriginalTimeScale; } ClearReplayObjects(); } private void ClearReplayObjects() { if ((Object)(object)replayRoot != (Object)null) { Object.Destroy((Object)(object)replayRoot); replayRoot = null; } replayHeadGhost = null; replayLeftGhost = null; replayRightGhost = null; replayWeaponGhost = null; replayNPCGhost = null; replayNPCHeadGhost = null; replayImpactMarker = null; replayHeadPath = null; replayLeftPath = null; replayRightPath = null; replayWeaponPath = null; replayBulletPath = null; replayStatsText = null; replayIntroText = null; replayOutroText = null; } private float GetCurrentWeaponVelocity() { //IL_0076: 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) try { GameObject objectInHand = Player.GetObjectInHand(Player.RightHand); if ((Object)(object)objectInHand == (Object)null) { objectInHand = Player.GetObjectInHand(Player.LeftHand); } if ((Object)(object)objectInHand == (Object)null) { return 0f; } GameObject val = FindWeaponRoot(objectInHand); if ((Object)(object)val == (Object)null) { return 0f; } Rigidbody[] array = Il2CppArrayBase<Rigidbody>.op_Implicit(val.GetComponentsInChildren<Rigidbody>(true)); float num = 0f; foreach (Rigidbody val2 in array) { if ((Object)(object)val2 != (Object)null) { float num2 = num; Vector3 velocity = val2.velocity; num = Mathf.Max(num2, ((Vector3)(ref velocity)).magnitude); } } return num; } catch { return 0f; } } private Mesh GetInvertedOutlineMesh(Mesh source) { if ((Object)(object)source == (Object)null) { return null; } if (invertedOutlineMeshCache.TryGetValue(source, out var value) && (Object)(object)value != (Object)null) { return value; } try { Mesh val = Object.Instantiate<Mesh>(source); ((Object)val).name = ((Object)source).name + "_ECHOX_Inverted"; for (int i = 0; i < val.subMeshCount; i++) { int[] array = Il2CppArrayBase<int>.op_Implicit((Il2CppArrayBase<int>)(object)val.GetTriangles(i)); for (int j = 0; j + 2 < array.Length; j += 3) { int num = array[j + 1]; array[j + 1] = array[j + 2]; array[j + 2] = num; } val.SetTriangles(Il2CppStructArray<int>.op_Implicit(array), i); } val.RecalculateBounds(); invertedOutlineMeshCache[source] = val; return val; } catch (Exception ex) { ((MelonBase)this).LoggerInstance.Warning("ECHOX inverted mesh failed: " + ex.Message); return source; } } private void ShowWeaponOutline(GameObject weapon) { //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Expected O, but got Unknown //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_0229: Unknown result type (might be due to invalid IL or missing references) //IL_0230: Expected O, but got Unknown //IL_024b: Unknown result type (might be due to invalid IL or missing references) //IL_025c: Unknown result type (might be due to invalid IL or missing references) //IL_0270: Unknown result type (might be due to invalid IL or missing references) //IL_02ac: Unknown result type (might be due to invalid IL or missing references) if (!weaponOutlineEnabled.Value || (Object)(object)weapon == (Object)null) { return; } ClearWeaponOutline(); try { CreateOutlineMaterial(); if ((Object)(object)weaponOutlineMaterial == (Object)null) { return; } float num = Mathf.Clamp(weaponOutlineThickness.Value, 0.001f, 0.015f); float num2 = 1f + num; MeshRenderer[] array = Il2CppArrayBase<MeshRenderer>.op_Implicit(weapon.GetComponentsInChildren<MeshRenderer>(true)); foreach (MeshRenderer val in array) { if ((Object)(object)val == (Object)null || !((Renderer)val).enabled) { continue; } MeshFilter component = ((Component)val).GetComponent<MeshFilter>(); if (!((Object)(object)component == (Object)null) && !((Object)(object)component.sharedMesh == (Object)null) && !ShouldSkipOutlineMesh(component.sharedMesh, ((Component)val).gameObject)) { Mesh invertedOutlineMesh = GetInvertedOutlineMesh(component.sharedMesh); if (!((Object)(object)invertedOutlineMesh == (Object)null)) { GameObject val2 = new GameObject("ECHOX_OutlineMesh"); val2.transform.SetParent(((Component)val).transform, false); val2.transform.localPosition = Vector3.zero; val2.transform.localRotation = Quaternion.identity; val2.transform.localScale = new Vector3(num2, num2, num2); val2.AddComponent<MeshFilter>().sharedMesh = invertedOutlineMesh; MeshRenderer val3 = val2.AddComponent<MeshRenderer>(); ((Renderer)val3).sharedMaterial = weaponOutlineMaterial; ((Renderer)val3).shadowCastingMode = (ShadowCastingMode)0; ((Renderer)val3).receiveShadows = false; ((Renderer)val3).lightProbeUsage = (LightProbeUsage)0; ((Renderer)val3).reflectionProbeUsage = (ReflectionProbeUsage)0; outlineObjects.Add(val2); outlineRenderers.Add((Renderer)(object)val3); } } } SkinnedMeshRenderer[] array2 = Il2CppArrayBase<SkinnedMeshRenderer>.op_Implicit(weapon.GetComponentsInChildren<SkinnedMeshRenderer>(true)); foreach (SkinnedMeshRenderer val4 in array2) { if (!((Object)(object)val4 == (Object)null) && ((Renderer)val4).enabled && !((Object)(object)val4.sharedMesh == (Object)null) && !ShouldSkipOutlineMesh(val4.sharedMesh, ((Component)val4).gameObject)) { Mesh invertedOutlineMesh2 = GetInvertedOutlineMesh(val4.sharedMesh); if (!((Object)(object)invertedOutlineMesh2 == (Object)null)) { GameObject val5 = new GameObject("ECHOX_OutlineSkinned"); val5.transform.SetParent(((Component)val4).transform, false); val5.transform.localPosition = Vector3.zero; val5.transform.localRotation = Quaternion.identity; val5.transform.localScale = new Vector3(num2, num2, num2); SkinnedMeshRenderer val6 = val5.AddComponent<SkinnedMeshRenderer>(); val6.sharedMesh = invertedOutlineMesh2; val6.bones = val4.bones; val6.rootBone = val4.rootBone; ((Renderer)val6).localBounds = ((Renderer)val4).localBounds; val6.updateWhenOffscreen = false; ((Renderer)val6).sharedMaterial = weaponOutlineMaterial; ((Renderer)val6).shadowCastingMode = (ShadowCastingMode)0; ((Renderer)val6).receiveShadows = false; ((Renderer)val6).lightProbeUsage = (LightProbeUsage)0; ((Renderer)val6).reflectionProbeUsage = (ReflectionProbeUsage)0; outlineObjects.Add(val5); outlineRenderers.Add((Renderer)(object)val6); } } } outlineStartTime = Time.unscaledTime; outlineEndTime = outlineStartTime + Mathf.Max(0.2f, weaponOutlineDuration.Value); outlineActive = outlineObjects.Count > 0; ApplyOutlineColor(0.7f); } catch (Exception ex) { ((MelonBase)this).LoggerInstance.Warning("ECHOX outline failed: " + ex.Message); ClearWeaponOutline(); } } private bool ShouldSkipOutlineMesh(Mesh mesh, GameObject sourceObject) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0038: 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_005e: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)mesh == (Object)null || (Object)(object)sourceObject == (Object)null) { return true; } string text = ((Object)sourceObject).name.ToLowerInvariant(); if (text.Contains("echox_outline")) { return true; } Bounds bounds = mesh.bounds; if (((Bounds)(ref bounds)).size.x > 5f || ((Bounds)(ref bounds)).size.y > 5f || ((Bounds)(ref bounds)).size.z > 5f) { return true; } if (text.Contains("collider") || text.Contains("collision") || text.Contains("trigger") || text.Contains("bounds") || text.Contains("bounding") || text.Contains("helper") || text.Contains("proxy")) { return true; } return false; } private void CreateOutlineMaterial() { //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Expected O, but got Unknown if ((Object)(object)weaponOutlineMaterial != (Object)null) { return; } Shader val = Shader.Find("Unlit/Color"); if ((Object)(object)val == (Object)null) { val = Shader.Find("Sprites/Default"); } if ((Object)(object)val == (Object)null) { ((MelonBase)this).LoggerInstance.Warning("ECHOX could not find outline shader."); return; } weaponOutlineMaterial = new Material(val); ((Object)weaponOutlineMaterial).name = "ECHOX_InvertedHullOutline"; if (weaponOutlineMaterial.HasProperty("_Cull")) { weaponOutlineMaterial.SetInt("_Cull", 2); } if (weaponOutlineMaterial.HasProperty("_ZWrite")) { weaponOutlineMaterial.SetInt("_ZWrite", 1); } if (weaponOutlineMaterial.HasProperty("_ZTest")) { weaponOutlineMaterial.SetInt("_ZTest", 4); } weaponOutlineMaterial.renderQueue = 2001; } private void UpdateWeaponOutline() { if (!outlineActive) { return; } if (outlineObjects.Count == 0) { ClearWeaponOutline(); return; } float unscaledTime = Time.unscaledTime; if (unscaledTime >= outlineEndTime) { ClearWeaponOutline(); return; } float num = Mathf.Max(0.2f, weaponOutlineDuration.Value); float num2 = outlineEndTime - unscaledTime; float num3 = Mathf.Min(0.35f, num * 0.45f); float num4 = 0.7f; if (num2 < num3) { num4 *= Mathf.Clamp01(num2 / num3); } float num5 = 0.88f + Mathf.Sin(unscaledTime * 16f) * 0.12f; ApplyOutlineColor(num4 * num5); } private void ApplyOutlineColor(float alpha) { //IL_005a: 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) if (!((Object)(object)weaponOutlineMaterial == (Object)null)) { Color val = default(Color); ((Color)(ref val))..ctor(textRed.Value, textGreen.Value, textBlue.Value, Mathf.Clamp01(alpha)); if (weaponOutlineMaterial.HasProperty("_Color")) { weaponOutlineMaterial.SetColor("_Color", val); } if (weaponOutlineMaterial.HasProperty("_TintColor")) { weaponOutlineMaterial.SetColor("_TintColor", val); } } } private void ClearWeaponOutline() { outlineActive = false; for (int i = 0; i < outlineObjects.Count; i++) { GameObject val = outlineObjects[i]; if ((Object)(object)val != (Object)null) { Object.Destroy((Object)(object)val); } } outlineObjects.Clear(); outlineRenderers.Clear(); } private void RestoreAutomaticInspector() { try { GameObject objectInHand = Player.GetObjectInHand(Player.LeftHand); GameObject objectInHand2 = Player.GetObjectInHand(Player.RightHand); GameObject val = (((Object)(object)objectInHand2 != (Object)null) ? objectInHand2 : objectInHand); if ((Object)(object)val == (Object)null) { HideInspector(immediate: true); return; } WeaponInfo weaponInfo = InspectWeapon(val); if (weaponInfo.Kind == WeaponKind.Unknown && weaponInfo.Mass <= 0.01f) { HideInspector(immediate: true); return; } manualInfoVisible = false; quickScanVisible = false; quickScannedWeapon = null; ShowInspector(weaponInfo.Anchor, weaponInfo); showUntil = Time.unscaledTime + displayDuration.Value; } catch (Exception ex) { ((MelonBase)this).LoggerInstance.Warning("ECHOX automatic restore failed: " + ex.Message); } } private void UpdateTwoHandInfoToggle() { if (!enabled.Value || !twoHandInfoToggle.Value) { supportSecondaryWasPressed = false; return; } GameObject objectInHand; GameObject objectInHand2; try { objectInHand = Player.GetObjectInHand(Player.LeftHand); objectInHand2 = Player.GetObjectInHand(Player.RightHand); } catch { return; } if ((Object)(object)objectInHand == (Object)null || (Object)(object)objectInHand2 == (Object)null) { supportSecondaryWasPressed = false; return; } GameObject val = FindWeaponRoot(objectInHand); GameObject val2 = FindWeaponRoot(objectInHand2); if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null || (Object)(object)val != (Object)(object)val2) { supportSecondaryWasPressed = false; } else { if (!primaryHandKnown) { return; } bool leftHand = !primaryHandIsLeft; bool secondaryFaceButton = GetSecondaryFaceButton(leftHand); if (secondaryFaceButton && !supportSecondaryWasPressed) { if (manualInfoVisible) { manualInfoVisible = false; HideInspector(immediate: true); } else { WeaponInfo weaponInfo = InspectWeapon(val); quickScanVisible = false; quickScannedWeapon = null; ShowInspector(weaponInfo.Anchor, weaponInfo); manualInfoVisible = true; } } supportSecondaryWasPressed = secondaryFaceButton; } } private void UpdateQuickScan() { if (!enabled.Value || !quickScanEnabled.Value) { quickLeftWasPressed = false; quickRightWasPressed = false; return; } bool secondaryFaceButton = GetSecondaryFaceButton(leftHand: true); bool secondaryFaceButton2 = GetSecondaryFaceButton(leftHand: false); if (twoHandInfoToggle.Value && IsHoldingSameWeaponTwoHanded()) { quickLeftWasPressed = secondaryFaceButton; quickRightWasPressed = secondaryFaceButton2; return; } if (secondaryFaceButton && !quickLeftWasPressed) { TryQuickScan(leftHand: true); } if (secondaryFaceButton2 && !quickRightWasPressed) { TryQuickScan(leftHand: false); } quickLeftWasPressed = secondaryFaceButton; quickRightWasPressed = secondaryFaceButton2; } private bool IsHoldingSameWeaponTwoHanded() { try { GameObject objectInHand = Player.GetObjectInHand(Player.LeftHand); GameObject objectInHand2 = Player.GetObjectInHand(Player.RightHand); if ((Object)(object)objectInHand == (Object)null || (Object)(object)objectInHand2 == (Object)null) { return false; } GameObject val = FindWeaponRoot(objectInHand); GameObject val2 = FindWeaponRoot(objectInHand2); if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null) { return false; } return (Object)(object)val == (Object)(object)val2; } catch { return false; } } private void TryQuickScan(bool leftHand) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_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_0040: Unknown result type (might be due to invalid IL or missing references) try { Hand val = (leftHand ? Player.LeftHand : Player.RightHand); if ((Object)(object)val == (Object)null) { return; } Transform transform = ((Component)val).transform; Vector3 forward = transform.forward; RaycastHit val2 = default(RaycastHit); if (!Physics.Raycast(transform.position + forward * 0.05f, forward, ref val2, quickScanRange.Value, -5, (QueryTriggerInteraction)1) || (Object)(object)((RaycastHit)(ref val2)).collider == (Object)null) { return; } WeaponInfo weaponInfo = InspectWeapon(((Component)((RaycastHit)(ref val2)).collider).gameObject); if (weaponInfo.Kind != WeaponKind.Unknown || !(weaponInfo.Mass <= 0.01f)) { if (quickScanVisible && (Object)(object)quickScannedWeapon == (Object)(object)weaponInfo.Anchor) { quickScanVisible = false; quickScannedWeapon = null; HideInspector(immediate: true); ClearWeaponOutline(); } else { manualInfoVisible = false; quickScanVisible = true; quickScannedWeapon = weaponInfo.Anchor; ShowInspector(weaponInfo.Anchor, weaponInfo); } } } catch (Exception ex) { ((MelonBase)this).LoggerInstance.Warning("ECHOX Quick Scan failed: " + ex.Message); } } private bool GetSecondaryFaceButton(bool leftHand) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) try { InputDevice deviceAtXRNode = InputDevices.GetDeviceAtXRNode((XRNode)(leftHand ? 4 : 5)); if (!((InputDevice)(ref deviceAtXRNode)).isValid) { return false; } bool result = default(bool); if (((InputDevice)(ref deviceAtXRNode)).TryGetFeatureValue(CommonUsages.secondaryButton, ref result)) { return result; } } catch { } return false; } private void OnGrabObject(GameObject grabbedObject, Hand hand) { if (!enabled.Value || (Object)(object)grabbedObject == (Object)null) { return; } try { WeaponInfo weaponInfo = InspectWeapon(grabbedObject); if ((Object)(object)weaponInfo.Anchor == (Object)null || (weaponInfo.Kind == WeaponKind.Unknown && weaponInfo.Mass <= 0.01f)) { return; } bool flag = hand == Player.LeftHand; if ((Object)(object)lastScannedWeapon != (Object)null && (Object)(object)lastScannedWeapon == (Object)(object)weaponInfo.Anchor) { if ((Object)(object)trackedTwoHandWeapon == (Object)null) { trackedTwoHandWeapon = weaponInfo.Anchor; } return; } if ((Object)(object)trackedTwoHandWeapon != (Object)(object)weaponInfo.Anchor) { trackedTwoHandWeapon = weaponInfo.Anchor; primaryHandIsLeft = flag; primaryHandKnown = true; } manualInfoVisible = false; quickScanVisible = false; quickScannedWeapon = null; ShowInspector(weaponInfo.Anchor, weaponInfo); } catch (Exception ex) { ((MelonBase)this).LoggerInstance.Warning("ECHOX inspection failed: " + ex.Message); } } private void OnReleaseObject(Hand hand) { try { GameObject objectInHand = Player.GetObjectInHand(Player.LeftHand); GameObject objectInHand2 = Player.GetObjectInHand(Player.RightHand); GameObject val = (((Object)(object)objectInHand != (Object)null) ? FindWeaponRoot(objectInHand) : null); GameObject val2 = (((Object)(object)objectInHand2 != (Object)null) ? FindWeaponRoot(objectInHand2) : null); if ((Object)(object)lastScannedWeapon != (Object)null && (Object)(object)val != (Object)(object)lastScannedWeapon && (Object)(object)val2 != (Object)(object)lastScannedWeapon) { lastScannedWeapon = null; } if ((Object)(object)trackedTwoHandWeapon != (Object)null && (Object)(object)val != (Object)(object)trackedTwoHandWeapon && (Object)(object)val2 != (Object)(object)trackedTwoHandWeapon) { trackedTwoHandWeapon = null; primaryHandKnown = false; supportSecondaryWasPressed = false; } if ((Object)(object)objectInHand == (Object)null && (Object)(object)objectInHand2 == (Object)null && !quickScanVisible) { manualInfoVisible = false; HideInspector(immediate: false); } } catch { } } private WeaponInfo InspectWeapon(GameObject grabbedObject) { //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) WeaponInfo weaponInfo = new WeaponInfo(); GameObject val = FindWeaponRoot(grabbedObject); if ((Object)(object)val == (Object)null) { val = grabbedObject; } weaponInfo.Anchor = val; weaponInfo.Name = CleanName(((Object)val).name); Rigidbody[] array = Il2CppArrayBase<Rigidbody>.op_Implicit(val.GetComponentsInChildren<Rigidbody>(true)); float num = 0f; float num2 = 0f; if (array != null) { Rigidbody[] array2 = array; foreach (Rigidbody val2 in array2) { if (!((Object)(object)val2 == (Object)null)) { num += Mathf.Max(0f, val2.mass); float num3 = num2; Vector3 velocity = val2.velocity; num2 = Mathf.Max(num3, ((Vector3)(ref velocity)).magnitude); } } } weaponInfo.Mass = num; weaponInfo.Speed = num2; weaponInfo.Impact = 0.5f * num * num2 * num2; bool flag = false; bool flag2 = ContainsWord(weaponInfo.Name, firearmWords); bool flag3 = ContainsWord(weaponInfo.Name, meleeWords); Component[] array3 = Il2CppArrayBase<Component>.op_Implicit(val.GetComponentsInChildren<Component>(true)); HashSet<string> hashSet = new HashSet<string>(); if (array3 != null) { int num4 = Mathf.Min(array3.Length, 48); for (int j = 0; j < num4; j++) { Component val3 = array3[j]; if (!((Object)(object)val3 == (Object)null)) { string name = ((object)val3).GetType().Name; if (val3 is Gun) { flag = true; } if (ContainsWord(name, firearmWords)) { flag2 = true; } if (ContainsWord(name, meleeWords)) { flag3 = true; } if (hashSet.Count < 8 && hashSet.Add(name)) { weaponInfo.Components.Add(name); } if (weaponInfo.ExtraStats.Count < 5) { ExtractInterestingStats(val3, weaponInfo.ExtraStats); } } } } if (flag || flag2) { weaponInfo.Kind = WeaponKind.Firearm; } else if (flag3) { weaponInfo.Kind = WeaponKind.Melee; } else { weaponInfo.Kind = WeaponKind.Unknown; } return weaponInfo; } private GameObject FindWeaponRoot(GameObject grabbedObject) { if ((Object)(object)grabbedObject == (Object)null) { return null; } Transform val = grabbedObject.transform; Transform val2 = null; for (int i = 0; i < 10; i++) { if (!((Object)(object)val != (Object)null)) { break; } if ((Object)(object)((Component)val).GetComponent<Gun>() != (Object)null) { return ((Component)val).gameObject; } if ((Object)(object)val2 == (Object)null && (Object)(object)((Component)val).GetComponent<Rigidbody>() != (Object)null) { val2 = val; } val = val.parent; } if ((Object)(object)val2 != (Object)null) { return ((Component)val2).gameObject; } return grabbedObject; } private void ExtractInterestingStats(Component component, List<string> output) { if ((Object)(object)component == (Object)null || output.Count >= 5) { return; } Type type = ((object)component).GetType(); BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Public; try { PropertyInfo[] properties = type.GetProperties(bindingAttr); int num = Math.Min(properties.Length, 40); for (int i = 0; i < num; i++) { if (output.Count >= 5) { break; } PropertyInfo propertyInfo = properties[i]; if (!propertyInfo.CanRead || propertyInfo.GetIndexParameters().Length != 0) { continue; } string name = propertyInfo.Name.ToLowerInvariant(); if (IsInterestingStat(name)) { Type propertyType = propertyInfo.PropertyType; if (propertyType.IsPrimitive || !(propertyType != typeof(string)) || propertyType.IsEnum) { object value = propertyInfo.GetValue(component, null); AddStat(output, propertyInfo.Name, value); } } } } catch { } if (output.Count >= 5) { return; } try { FieldInfo[] fields = type.GetFields(bindingAttr); int num2 = Math.Min(fields.Length, 40); for (int j = 0; j < num2; j++) { if (output.Count >= 5) { break; } FieldInfo fieldInfo = fields[j]; string name2 = fieldInfo.Name.ToLowerInvariant(); if (IsInterestingStat(name2)) { Type fieldType = fieldInfo.FieldType; if (fieldType.IsPrimitive || !(fieldType != typeof(string)) || fieldType.IsEnum) { AddStat(output, fieldInfo.Name, fieldInfo.GetValue(component)); } } } } catch { } } private bool IsInterestingStat(string name) { if (!name.Contains("ammo") && !name.Contains("round") && !name.Contains("capacity") && !name.Contains("rpm") && !name.Contains("firerate") && !name.Contains("fire_rate") && !name.Contains("velocity") && !name.Contains("muzzle") && !name.Contains("firemode") && !name.Contains("fire_mode")) { return name.Contains("caliber"); } return true; } private void AddStat(List<string> output, string name, object value) { if (value == null) { return; } string text = value.ToString(); if (!string.IsNullOrWhiteSpace(text) && text.Length <= 24) { string item = name.Replace("_", " ") + ": " + text; if (!output.Contains(item)) { output.Add(item); } } } private bool ContainsWord(string value, string[] words) { if (string.IsNullOrEmpty(value)) { return false; } string text = value.ToLowerInvariant(); foreach (string value2 in words) { if (text.Contains(value2)) { return true; } } return false; } private string CleanName(string name) { if (string.IsNullOrWhiteSpace(name)) { return "Unknown Item"; } return name.Replace("(Clone)", "").Tr