Decompiled source of STREPLAY v1.1.2
BepInEx/plugins/streplay/streplay.dll
Decompiled 9 hours ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using System.Text.RegularExpressions; using System.Threading; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using ComputerysModdingUtilities; using FishNet; using FishNet.Component.Transforming; using FishNet.Managing; using FishNet.Managing.Client; using FishNet.Managing.Object; using FishNet.Object; using Goodgulf.Graphics; using HarmonyLib; using ICSharpCode.SharpZipLib; using ICSharpCode.SharpZipLib.Zip.Compression; using ICSharpCode.SharpZipLib.Zip.Compression.Streams; using Microsoft.CodeAnalysis; using Newtonsoft.Json; using StreplayFfmpeg; using TMPro; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.Experimental.Rendering; using UnityEngine.Rendering; using UnityEngine.Rendering.PostProcessing; using UnityEngine.SceneManagement; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: StraftatMod(true)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("streplay")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.1.2.0")] [assembly: AssemblyInformationalVersion("1.1.2+1b240207a82c4306dc9aedbfc8c08bc923cd65f6")] [assembly: AssemblyProduct("streplay")] [assembly: AssemblyTitle("streplay")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.1.2.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 Streplay { internal static class AudioCapture { [ThreadStatic] internal static int RpcDepth; internal static int ReplayPlays; internal static readonly List<string> ReplayClips = new List<string>(); internal static bool OwnPlay; public static void Install(Harmony harmony) { Type typeFromHandle = typeof(AudioSource); Patch(harmony, typeFromHandle.GetMethod("PlayOneShot", new Type[2] { typeof(AudioClip), typeof(float) }), "PlayOneShotPostfix"); Patch(harmony, typeFromHandle.GetMethod("Play", Type.EmptyTypes), "PlayPostfix"); Patch(harmony, typeFromHandle.GetMethod("Play", new Type[1] { typeof(ulong) }), "PlayPostfix"); Patch(harmony, typeFromHandle.GetMethod("PlayDelayed", new Type[1] { typeof(float) }), "PlayPostfix"); } private static void Patch(Harmony harmony, MethodInfo target, string postfix) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Expected O, but got Unknown try { if (target == null) { throw new MissingMethodException("AudioSource", postfix); } harmony.Patch((MethodBase)target, (HarmonyMethod)null, new HarmonyMethod(typeof(AudioCapture).GetMethod(postfix, BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } catch (Exception ex) { Plugin.Log.LogWarning((object)("Could not hook AudioSource for sound capture: " + ex.Message)); } } private static void PlayOneShotPostfix(AudioSource __instance, AudioClip clip, float volumeScale) { Observe(__instance, clip, volumeScale, fromPlay: false); } private static void PlayPostfix(AudioSource __instance) { Observe(__instance, ((Object)(object)__instance != (Object)null) ? __instance.clip : null, 1f, fromPlay: true); } private static void Observe(AudioSource src, AudioClip clip, float volumeScale, bool fromPlay) { try { if ((Object)(object)src == (Object)null || (Object)(object)clip == (Object)null) { return; } if (ReplayPlayer.Active) { if (!OwnPlay && ((Behaviour)src).isActiveAndEnabled) { ReplayPlays++; if (ReplayClips.Count < 64) { ReplayClips.Add(((Object)clip).name); } } } else { Recorder instance = Recorder.Instance; if ((Object)(object)instance != (Object)null && instance.IsRecording) { instance.OnSound(src, clip, volumeScale, fromPlay, RpcDepth > 0); } } } catch (Exception ex) { Plugin.Log.LogDebug((object)("Sound capture failed: " + ex.Message)); } } } internal sealed class AudioTap : MonoBehaviour { private readonly object _lock = new object(); private List<float> _samples = new List<float>(); private volatile bool _on; private int _channels = 2; public int SampleRate { get; private set; } public int Channels { get { lock (_lock) { return _channels; } } } public int Frames { get { lock (_lock) { return _samples.Count / Math.Max(1, _channels); } } } public void Begin() { SampleRate = AudioSettings.outputSampleRate; lock (_lock) { _samples = new List<float>(SampleRate * 2 * 30); } _on = true; } public void Stop() { _on = false; } private void OnAudioFilterRead(float[] data, int channels) { if (_on) { lock (_lock) { _channels = channels; _samples.AddRange(data); } if (Plugin.RenderMuteSoundPass.Value) { Array.Clear(data, 0, data.Length); } } } public void WriteWavMapped(string path, int frames, Func<int, double> srcFrame, float gain) { float[] array; int num; lock (_lock) { array = _samples.ToArray(); num = Math.Max(1, _channels); } int num2 = array.Length / num; using BinaryWriter binaryWriter = new BinaryWriter(File.Create(path)); WriteHeader(binaryWriter, frames, num); for (int i = 0; i < frames; i++) { double num3 = srcFrame(i); int num4 = (int)Math.Floor(num3); float num5 = (float)(num3 - (double)num4); for (int j = 0; j < num; j++) { float num6 = ((num4 >= 0 && num4 < num2) ? array[num4 * num + j] : 0f); float num7 = ((num4 + 1 >= 0 && num4 + 1 < num2) ? array[(num4 + 1) * num + j] : num6); binaryWriter.Write((short)Mathf.Clamp(Mathf.RoundToInt((num6 + (num7 - num6) * num5) * gain * 32767f), -32768, 32767)); } } } private void WriteHeader(BinaryWriter w, int frames, int ch) { int num = frames * ch * 2; w.Write(new char[4] { 'R', 'I', 'F', 'F' }); w.Write(36 + num); w.Write(new char[8] { 'W', 'A', 'V', 'E', 'f', 'm', 't', ' ' }); w.Write(16); w.Write((short)1); w.Write((short)ch); w.Write(SampleRate); w.Write(SampleRate * ch * 2); w.Write((short)(ch * 2)); w.Write((short)16); w.Write(new char[4] { 'd', 'a', 't', 'a' }); w.Write(num); } public void WriteWav(string path, int frames) { float[] array; int num; lock (_lock) { array = _samples.ToArray(); num = Math.Max(1, _channels); } using BinaryWriter binaryWriter = new BinaryWriter(File.Create(path)); int num2 = frames * num * 2; binaryWriter.Write(new char[4] { 'R', 'I', 'F', 'F' }); binaryWriter.Write(36 + num2); binaryWriter.Write(new char[8] { 'W', 'A', 'V', 'E', 'f', 'm', 't', ' ' }); binaryWriter.Write(16); binaryWriter.Write((short)1); binaryWriter.Write((short)num); binaryWriter.Write(SampleRate); binaryWriter.Write(SampleRate * num * 2); binaryWriter.Write((short)(num * 2)); binaryWriter.Write((short)16); binaryWriter.Write(new char[4] { 'd', 'a', 't', 'a' }); binaryWriter.Write(num2); for (int i = 0; i < frames * num; i++) { binaryWriter.Write((short)((i < array.Length) ? ((short)Mathf.Clamp(Mathf.RoundToInt(array[i] * 32767f), -32768, 32767)) : 0)); } } } internal sealed class DebugDump : MonoBehaviour { private void Update() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_02d6: Unknown result type (might be due to invalid IL or missing references) //IL_02db: 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) KeyboardShortcut value = Plugin.DumpKey.Value; if (!((KeyboardShortcut)(ref value)).IsDown()) { return; } try { StringBuilder stringBuilder = new StringBuilder(); Scene activeScene = SceneManager.GetActiveScene(); stringBuilder.AppendLine($"Scene: {((Scene)(ref activeScene)).name} replay={ReplayPlayer.Active} time={DateTime.Now}"); ClientManager clientManager = InstanceFinder.ClientManager; if (!ReplayPlayer.Active && (Object)(object)clientManager != (Object)null && clientManager.Started) { DumpCanvases(stringBuilder); FirstPersonController val = (((Object)(object)Settings.Instance != (Object)null) ? Settings.Instance.localPlayer : null); PlayerSetup val2 = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponent<PlayerSetup>() : null); if ((Object)(object)val2 != (Object)null && AccessTools.Field(typeof(PlayerSetup), "cameras")?.GetValue(val2) is Camera[] array) { for (int i = 0; i < array.Length; i++) { if ((Object)(object)array[i] != (Object)null) { stringBuilder.AppendLine($"player camera[{i}] {((Object)array[i]).name} enabled={((Behaviour)array[i]).enabled} fov={array[i].fieldOfView} depth={array[i].depth} " + $"clear={array[i].clearFlags} mask={array[i].cullingMask:X8} near={array[i].nearClipPlane} path={Recorder.ScenePath(((Component)array[i]).transform)}"); } } } foreach (NetworkObject item in from n in ((ManagedObjects)clientManager.Objects).Spawned.Values where (Object)(object)n != (Object)null && (Object)(object)n.ParentNetworkObject == (Object)null orderby n.ObjectId select n) { stringBuilder.AppendLine($"=== #{item.ObjectId} {((Object)item).name} prefab={item.SpawnableCollectionId}:{item.PrefabId} scene={Net.SceneId(item)} owner={item.IsOwner}"); Dump(stringBuilder, ((Component)item).transform, 1); } } else { activeScene = SceneManager.GetActiveScene(); GameObject[] rootGameObjects = ((Scene)(ref activeScene)).GetRootGameObjects(); foreach (GameObject val3 in rootGameObjects) { Dump(stringBuilder, val3.transform, 0); } } string text = Path.Combine(Plugin.ReplayFolder.Value, "dump_" + DateTime.Now.ToString("yyyyMMdd_HHmmss", CultureInfo.InvariantCulture) + ".txt"); File.WriteAllText(text, stringBuilder.ToString()); Plugin.Log.LogInfo((object)("Wrote " + text)); } catch (Exception arg) { Plugin.Log.LogError((object)$"Dump failed: {arg}"); } } private static void DumpCanvases(StringBuilder sb) { //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_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) Canvas[] array = Resources.FindObjectsOfTypeAll<Canvas>(); foreach (Canvas val in array) { if (!((Object)(object)val == (Object)null)) { Scene scene = ((Component)val).gameObject.scene; if (((Scene)(ref scene)).IsValid() && val.isRootCanvas) { int num = ((Component)val).GetComponentsInChildren<Graphic>(true).Length; int num2 = ((Component)val).GetComponentsInChildren<CanvasGroup>(true).Length; string arg = Recorder.ScenePath(((Component)val).transform); scene = ((Component)val).gameObject.scene; sb.AppendLine($"canvas {arg} scene={((Scene)(ref scene)).name} active={((Behaviour)val).isActiveAndEnabled} " + string.Format("mode={0} cam={1} order={2} graphics={3} groups={4}", val.renderMode, ((Object)(object)val.worldCamera != (Object)null) ? ((Object)val.worldCamera).name : "-", val.sortingOrder, num, num2)); } } } sb.AppendLine(); } private static void Dump(StringBuilder sb, Transform t, int depth) { if (depth <= 14) { IEnumerable<string> values = (from c in ((Component)t).GetComponents<Component>() where (Object)(object)c != (Object)null && !(c is Transform) select c).Select(delegate(Component c) { Behaviour val = (Behaviour)(object)((c is Behaviour) ? c : null); return (val == null || val.enabled) ? ((object)c).GetType().Name : (((object)c).GetType().Name + "(off)"); }); sb.Append(' ', depth * 2).Append(((Component)t).gameObject.activeSelf ? "" : "[inactive] ").Append(((Object)t).name) .Append(" layer=") .Append(((Component)t).gameObject.layer) .Append(" ") .AppendLine(string.Join(", ", values)); for (int num = 0; num < t.childCount; num++) { Dump(sb, t.GetChild(num), depth + 1); } } } } internal static class Disk { public const long Floor = 2147483648L; public const long Low = 5368709120L; internal static long TestFree = -1L; public static long Free(string dir) { if (TestFree >= 0) { return TestFree; } try { string pathRoot = Path.GetPathRoot(Path.GetFullPath(dir)); return string.IsNullOrEmpty(pathRoot) ? (-1) : new DriveInfo(pathRoot).AvailableFreeSpace; } catch { return -1L; } } public static string Drive(string dir) { try { return Path.GetPathRoot(Path.GetFullPath(dir)).TrimEnd('\\'); } catch { return "the drive"; } } public static string Gb(long bytes) { return ((double)bytes / 1073741824.0).ToString((bytes < 10737418240L) ? "0.0" : "0", CultureInfo.InvariantCulture) + " GB"; } } [HarmonyPatch] internal static class GameSuspend { [HarmonyPatch(typeof(PauseManager), "Update")] [HarmonyPrefix] private static bool PauseManagerUpdate() { return !ReplayPlayer.SuspendGame; } [HarmonyPatch(typeof(PauseManager), "Menu")] [HarmonyPrefix] private static bool PauseManagerMenu() { return !ReplayPlayer.SuspendGame; } } [HarmonyPatch] internal static class ReplayNoise { [HarmonyPatch(typeof(KillCam), "OnDisable")] [HarmonyFinalizer] private static Exception KillCamOnDisable(Exception __exception) { if (!ReplayPlayer.Active) { return __exception; } return null; } [HarmonyPatch(typeof(PlayerHealth), "Awake___UserLogic")] [HarmonyFinalizer] private static Exception PlayerHealthAwake(Exception __exception) { if (!ReplayPlayer.Active) { return __exception; } return null; } } internal static class Highlights { internal sealed class KillRec { public float T; public float ShotT; public string Victim = ""; public string Weapon = ""; public string Held = ""; public bool Headshot; public bool Airborne; public bool Scoped; public bool QuickScope; public float Distance; public float Speed; public int Health; public float FlickDeg; public float FlickPeak; public float Straight = 1f; public float FlickGap; public int Corrections; public int Shots = -1; private float _score = -1f; [JsonIgnore] public bool NoScope { get { if (!Scoped) { return IsScopeGun(Held); } return false; } } [JsonIgnore] public bool CleanFlick { get { if (FlickDeg >= 35f && FlickPeak >= 600f && Straight >= 0.85f && Corrections <= 1) { return FlickGap <= 0.3f; } return false; } } public float Score() { if (_score >= 0f) { return _score; } float num = WeaponWeight(Weapon); float num2 = 1f; if (FlickDeg >= 35f && FlickPeak >= 600f) { float num3 = Mathf.Clamp01((Straight - 0.6f) / 0.35f) * ((Corrections == 0) ? 1f : ((Corrections == 1) ? 0.7f : 0.35f)) * ((FlickGap <= 0.3f) ? 1f : ((FlickGap <= 0.6f) ? 0.5f : 0.2f)); num2 += num3 * (1.2f + Mathf.Clamp((FlickDeg - 35f) / 60f, 0f, 1.6f) + Mathf.Clamp((FlickPeak - 600f) / 1200f, 0f, 0.8f)); } else if (Corrections >= 3) { num2 -= 0.3f; } if (Shots == 1) { num2 += 0.6f; } else if (Shots >= 5) { num2 -= 0.6f; } if (Headshot) { num2 += 0.7f; } num2 += Mathf.Clamp((Distance - 20f) / 30f, 0f, 1f); if (QuickScope) { num2 += 1f; } if (NoScope) { num2 += 0.9f; } if (Health > 0 && Health <= 35) { num2 += 0.5f; } if (num >= 1f) { if (Airborne) { num2 += 0.4f; } num2 += Mathf.Clamp((Speed - 10f) / 15f, 0f, 0.6f); } return _score = num2 * num; } } private static class Tuning { public const float FlickMinDeg = 35f; public const float FlickMinPeak = 600f; } private sealed class Context { private readonly ReplayData _d; private readonly int _local; private readonly float _restFov; private readonly UiElementInfo _speedHud; private readonly UiElementInfo _healthHud; public readonly Dictionary<string, float> LocalZoom = new Dictionary<string, float>(StringComparer.OrdinalIgnoreCase); private static readonly Regex SpeedRx = new Regex("speed\\s*:?\\s*([0-9]+(?:[.,][0-9]+)?)", RegexOptions.IgnoreCase); private static readonly Regex HealthRx = new Regex("health\\s*:?\\s*([0-9]+)", RegexOptions.IgnoreCase); private List<float> _shots; public Context(ReplayData d, int local) { _d = d; _local = local; _restFov = Median(from x in d.Frames select x.CamFov into v where v > 1f select v); foreach (UiElementInfo value2 in d.Ui.Values) { if (value2.Kind == UiKind.Text && !value2.Dynamic) { if (_speedHud == null && value2.States.Any((UiState s) => s.Text != null && SpeedRx.IsMatch(s.Text))) { _speedHud = value2; } if (_healthHud == null && value2.Path.IndexOf("Enemy", StringComparison.OrdinalIgnoreCase) < 0 && value2.States.Any((UiState s) => s.Text != null && HealthRx.IsMatch(s.Text))) { _healthHud = value2; } } } foreach (Frame frame in d.Frames) { if (!Scoped(frame)) { continue; } string text = Held(frame); if (text != null) { float num = frame.CamFov / _restFov; if (!LocalZoom.TryGetValue(text, out var value) || num < value) { LocalZoom[text] = num; } } } MergeZoom(LocalZoom); } private bool Scoped(Frame f) { if (f.CamFov > 1f && _restFov > 1f) { return f.CamFov < _restFov * 0.8f; } return false; } private ObjState Me(Frame f) { ObjState[] objects = f.Objects; foreach (ObjState objState in objects) { ObjectInfo objectInfo = _d.Objects[objState.Obj]; if (objectInfo.Player != null && objectInfo.Player.PlayerId == _local && objState.Active) { return objState; } } return null; } private string Held(Frame f) { ObjState objState = Me(f); if (objState == null || objState.HeldRight < 0 || objState.HeldRight >= _d.Objects.Count) { return null; } string name = _d.Objects[objState.HeldRight].Name; int num = name.IndexOf("(Clone)", StringComparison.Ordinal); if (num <= 0) { return name; } return name.Substring(0, num).Trim(); } private void MeasureAim(KillRec k) { //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_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_00bf: 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_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Unknown result type (might be due to invalid IL or missing references) //IL_0190: Unknown result type (might be due to invalid IL or missing references) //IL_01b3: Unknown result type (might be due to invalid IL or missing references) //IL_01c4: Unknown result type (might be due to invalid IL or missing references) List<Frame> frames = _d.Frames; int num = FrameAt(frames, k.ShotT); int num2 = FrameAt(frames, k.ShotT - 0.8f); if (num - num2 < 4) { return; } int num3 = num - num2; float[] array = new float[num3]; float[] array2 = new float[num3]; for (int i = 0; i < num3; i++) { Frame frame = frames[num2 + i]; Frame frame2 = frames[num2 + i + 1]; float num4 = frame2.T - frame.T; if (!(num4 <= 0.0001f)) { float num5 = Quaternion.Angle(frame.CamRot, frame2.CamRot); if (num5 / num4 > 6000f) { return; } array[i] = num5 / num4; array2[i] = Mathf.DeltaAngle((frame.CamRot * Vector3.forward).Yaw(), (frame2.CamRot * Vector3.forward).Yaw()) / num4; } } int num6 = 0; for (int j = 1; j < num3; j++) { if (array[j] > array[num6]) { num6 = j; } } float num7 = array[num6]; int num8 = num6; int l = num6; while (num8 > 0 && array[num8 - 1] > 0.3f * num7) { num8--; } for (; l < num3 - 1 && array[l + 1] > 0.3f * num7; l++) { } float num9 = 0f; for (int m = num8; m <= l; m++) { num9 += Quaternion.Angle(frames[num2 + m].CamRot, frames[num2 + m + 1].CamRot); } float num10 = Quaternion.Angle(frames[num2 + num8].CamRot, frames[num2 + l + 1].CamRot); k.FlickPeak = num7; k.FlickDeg = num10; k.Straight = ((num9 > 0.001f) ? (num10 / num9) : 1f); k.FlickGap = Mathf.Max(0f, k.ShotT - frames[num2 + l + 1].T); int num11 = 0; for (int n = 0; n < num3; n++) { if (!(frames[num2 + n].T < k.ShotT - 0.4f)) { int num12 = ((array2[n] > 40f) ? 1 : ((array2[n] < -40f) ? (-1) : 0)); if (num12 != 0 && num11 != 0 && num12 != num11) { k.Corrections++; } if (num12 != 0) { num11 = num12; } } } } private float? Hud(UiElementInfo el, Regex rx, float t) { if (el == null) { return null; } int num = FrameAt(_d.Frames, t); int num2 = -1; for (int i = 0; i < el.Frames.Count && el.Frames[i] <= num; i++) { num2 = i; } if (num2 < 0 || el.States[num2].Text == null) { return null; } Match match = rx.Match(el.States[num2].Text); if (!match.Success || !float.TryParse(match.Groups[1].Value.Replace(',', '.'), NumberStyles.Float, CultureInfo.InvariantCulture, out var result)) { return null; } return result; } private List<float> Shots() { if (_shots != null) { return _shots; } _shots = new List<float>(); foreach (ReplayEvent @event in _d.Events) { if (@event.Method.StartsWith("Shoot", StringComparison.Ordinal)) { ObjState objState = Me(_d.Frames[FrameAt(_d.Frames, @event.T)]); if (objState != null && (@event.Obj == objState.HeldRight || @event.Obj == objState.HeldLeft)) { _shots.Add(@event.T); } } } return _shots; } public void Measure(KillRec k, int victimId) { //IL_0218: 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_0224: Unknown result type (might be due to invalid IL or missing references) //IL_022e: Unknown result type (might be due to invalid IL or missing references) //IL_0233: Unknown result type (might be due to invalid IL or missing references) //IL_0398: Unknown result type (might be due to invalid IL or missing references) //IL_039d: Unknown result type (might be due to invalid IL or missing references) List<Frame> frames = _d.Frames; List<float> list = Shots(); float num = list.Where((float x) => x <= k.T + 0.02f && x >= k.T - 0.6f).DefaultIfEmpty(-1f).Max(); k.ShotT = ((num >= 0f) ? num : (k.T - 0.03f)); k.Shots = ((list.Count > 0) ? list.Count((float x) => x <= k.T + 0.02f && x >= k.T - 1.2f) : (-1)); if (k.Shots == 0) { k.Shots = -1; } MeasureAim(k); int num2 = FrameAt(frames, k.T); Frame frame = frames[num2]; k.Scoped = Scoped(frame); if (k.Scoped) { bool quickScope = false; for (int num3 = FrameAt(frames, k.T - 0.45f); num3 < FrameAt(frames, k.T - 0.08f); num3++) { if (!Scoped(frames[num3])) { quickScope = true; break; } } k.QuickScope = quickScope; } k.Held = Held(frame) ?? Held(frames[FrameAt(frames, k.T - 0.1f)]) ?? ""; ObjState[] objects = frames[FrameAt(frames, k.T - 0.05f)].Objects; foreach (ObjState objState in objects) { ObjectInfo objectInfo = _d.Objects[objState.Obj]; if (objectInfo.Player != null && objState.Active && objectInfo.Player.PlayerId == victimId) { k.Distance = Mathf.Max(k.Distance, Vector3.Distance(frame.CamPos, objState.Pos + Vector3.up * 1.2f)); } } Frame frame2 = frames[FrameAt(frames, k.T - 0.15f)]; ObjState objState2 = Me(frame2); ObjState objState3 = Me(frame); if (objState2 != null && objState3 != null && frame.T - frame2.T > 0.05f) { float num5 = (objState3.Pos.y - objState2.Pos.y) / (frame.T - frame2.T); float num6 = float.MaxValue; for (int num7 = FrameAt(frames, k.T - 1.5f); num7 <= num2; num7++) { ObjState objState4 = Me(frames[num7]); if (objState4 != null) { num6 = Mathf.Min(num6, objState4.Pos.y); } } k.Airborne = Mathf.Abs(num5) > 2.5f || objState3.Pos.y - num6 > 1.5f; Vector2 val = new Vector2(objState3.Pos.x - objState2.Pos.x, objState3.Pos.z - objState2.Pos.z); float num8 = ((Vector2)(ref val)).magnitude / (frame.T - frame2.T); k.Speed = Hud(_speedHud, SpeedRx, k.T) ?? num8; } k.Health = Mathf.RoundToInt(Hud(_healthHud, HealthRx, k.T - 0.05f).GetValueOrDefault()); } } public const int Version = 6; public const int FeaturesVersion = 1; private static readonly Regex Tag = new Regex("<[^>]*>"); internal static readonly Regex Who = new Regex("\\{PLAYER_NAME\\}:\\{(\\d+)\\}"); private static Dictionary<string, float> _weights; private static string _weightsFrom; private static readonly Dictionary<string, float> Zoom = new Dictionary<string, float>(StringComparer.OrdinalIgnoreCase); private const float ScopeZoom = 0.35f; private static Thread _thread; private static volatile int _done; private static volatile int _total; internal static int Changes; public static bool Scanning { get { if (_thread != null) { return _thread.IsAlive; } return false; } } public static string Progress { get { if (!Scanning) { return null; } return $"Finding highlights {_done}/{_total}…"; } } public static List<ReplayMeta.MetaHighlight> Analyze(ReplayData data, ReplayMeta meta) { Measure(data, meta); return Score(meta); } private static void Measure(ReplayData data, ReplayMeta meta) { List<ObjectInfo> players = data.Objects.Where((ObjectInfo o) => o.Player != null).ToList(); int num = (players.FirstOrDefault((ObjectInfo o) => o.Player.IsLocal)?.Player)?.PlayerId ?? meta.Players.FirstOrDefault((ReplayMeta.MetaPlayer p) => p.IsLocal)?.PlayerId ?? (-1); Context context = new Context(data, num); List<KillRec> list = new List<KillRec>(); List<float> list2 = new List<float>(); if (num >= 0) { foreach (ReplayEvent @event in data.Events) { if (@event.Method != "RpcSendChatLineToAllObservers" || @event.Args.Length == 0 || !(@event.Args[0] is string input)) { continue; } string text = Tag.Replace(input, "").Trim(); List<int> list3 = (from Match x in Who.Matches(text) select int.Parse(x.Groups[1].Value)).ToList(); if (text.EndsWith(" won the take", StringComparison.Ordinal)) { if (list3.Contains(num)) { list2.Add(@event.T); } continue; } int num2 = text.LastIndexOf(" by ", StringComparison.Ordinal); if (list3.Count != 2 || num2 < 0 || !text.Contains(" was ") || list3[1] != num || list3[0] == num) { continue; } KillRec killRec = new KillRec { T = @event.T, Victim = Name(list3[0]), Headshot = text.Contains(" headshot ") }; int num3 = text.IndexOf(" with a", StringComparison.Ordinal); if (num3 >= 0) { int num4 = text.IndexOf(' ', num3 + 6) + 1; if (num4 > 0 && num4 < num2) { killRec.Weapon = text.Substring(num4, num2 - num4).Trim(); } } context.Measure(killRec, list3[0]); list.Add(killRec); } } meta.KillRecs = list; meta.TakeWins = list2; meta.WeaponZoom = context.LocalZoom; meta.FeaturesVersion = 1; string Name(int id) { string text2 = players.FirstOrDefault((ObjectInfo o) => o.Player.PlayerId == id)?.Player.Name; if (text2 == null || text2.Length <= 0) { string text3 = meta.Players.FirstOrDefault((ReplayMeta.MetaPlayer p) => p.PlayerId == id)?.Name; if (text3 == null) { return $"player {id}"; } return Tag.Replace(text3, ""); } return Tag.Replace(text2, ""); } } public static List<ReplayMeta.MetaHighlight> Score(ReplayMeta meta) { List<KillRec> list = meta.KillRecs ?? new List<KillRec>(); List<float> source = meta.TakeWins ?? new List<float>(); List<ReplayMeta.MetaHighlight> list2 = new List<ReplayMeta.MetaHighlight>(); List<ReplayMeta.MetaMarker> source2 = meta.Markers.Where((ReplayMeta.MetaMarker m) => !m.Auto).ToList(); HashSet<ReplayMeta.MetaMarker> usedFlags = new HashSet<ReplayMeta.MetaMarker>(); float value = Plugin.HighlightChain.Value; int num = 0; while (num < list.Count) { int num2; for (num2 = num + 1; num2 < list.Count && list[num2].T - list[num2 - 1].T <= value; num2++) { } List<KillRec> range = list.GetRange(num, num2 - num); num = num2; float t0 = range[0].T; float t1 = range[range.Count - 1].T; float num3 = t1 - t0; List<ReplayMeta.MetaMarker> list3 = source2.Where((ReplayMeta.MetaMarker f) => f.T >= t0 - 1.5f && f.T <= t1 + 1.5f).ToList(); foreach (ReplayMeta.MetaMarker item in list3) { usedFlags.Add(item); } bool num4 = source.Any((float w) => w >= t1 && w - t1 < 3f); List<float> list4 = (from k in range select k.Score() into x orderby x descending select x).ToList(); float num5 = list4[0] + 0.3f * list4.Skip(1).Sum(); if (range.Count > 1) { num5 += 0.35f * (float)(range.Count - 1) + 0.3f * Mathf.Clamp01((4f - num3) / 4f); } if (num4) { num5 += 0.3f; } if (list3.Count > 0) { num5 += 3f; } int num6 = range.Count((KillRec k) => k.Headshot); float num7 = range.Max((KillRec k) => k.Distance); float num8 = range.Max((KillRec k) => k.Speed); range.OrderByDescending((KillRec k) => k.Score()).First(); List<string> list5 = new List<string>(); if (range.Count > 1) { list5.Add($"{range.Count}K" + ((num3 < 2f) ? " fast" : "")); } KillRec killRec = (from k in range where k.CleanFlick orderby k.FlickDeg descending select k).FirstOrDefault(); if (killRec != null) { list5.Add($"flick {killRec.FlickDeg:0}°"); } if (num6 > 0) { list5.Add((num6 > 1) ? $"{num6} headshots" : "headshot"); } if (range.Any((KillRec k) => k.QuickScope)) { list5.Add("quickscope"); } if (range.Any((KillRec k) => k.NoScope)) { list5.Add("no-scope"); } if (range.All((KillRec k) => k.Shots == 1)) { list5.Add((range.Count > 1) ? "one-taps" : "one-tap"); } else if (range.Any((KillRec k) => k.Shots >= 5)) { list5.Add("spray"); } if (num7 >= 25f) { list5.Add($"{num7:0} m"); } if (range.Any((KillRec k) => k.Airborne)) { list5.Add("airborne"); } if (num8 >= 12f) { list5.Add($"fast {num8:0} m/s"); } int num9 = (from k in range where k.Health > 0 && k.Health <= 35 select k.Health).DefaultIfEmpty(0).Min(); if (num9 > 0) { list5.Add($"low hp {num9}"); } if (num4) { list5.Add("take winner"); } if (list3.Count > 0) { list5.Add("flagged"); } IEnumerable<string> enumerable = (from k in range select k.Weapon into w where w.Length > 0 select w).Distinct(); list2.Add(new ReplayMeta.MetaHighlight { T0 = t0, T1 = t1, Kills = range.Count, Score = (float)Math.Round(num5, 1), KillT = range.Select((KillRec k) => k.T).ToList(), Tags = list5, Detail = string.Join(", ", range.Select((KillRec k) => k.Victim).Distinct()) + (enumerable.Any() ? (" · " + string.Join(", ", enumerable)) : "") }); } foreach (ReplayMeta.MetaMarker item2 in source2.Where((ReplayMeta.MetaMarker f) => !usedFlags.Contains(f))) { list2.Add(new ReplayMeta.MetaHighlight { T0 = item2.T, T1 = item2.T, Kills = 0, Score = 3f, Tags = new List<string> { "flagged" }, Detail = item2.Label }); } return list2.OrderBy((ReplayMeta.MetaHighlight h) => h.T0).ToList(); } private static float WeaponWeight(string weapon) { string text = Plugin.HighlightWeaponWeights?.Value ?? ""; if (_weights == null || _weightsFrom != text) { Dictionary<string, float> dictionary = new Dictionary<string, float>(StringComparer.OrdinalIgnoreCase); string[] array = text.Split(','); foreach (string text2 in array) { int num = text2.IndexOf('='); if (num > 0 && float.TryParse(text2.Substring(num + 1).Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out var result)) { dictionary[text2.Substring(0, num).Trim()] = Mathf.Clamp(result, 0f, 5f); } } _weights = dictionary; _weightsFrom = text; } if (string.IsNullOrEmpty(weapon)) { return 1f; } foreach (KeyValuePair<string, float> weight in _weights) { if (weapon.IndexOf(weight.Key, StringComparison.OrdinalIgnoreCase) >= 0) { return weight.Value; } } return 1f; } private static bool IsScopeGun(string weapon) { lock (Zoom) { float value; return weapon != null && Zoom.TryGetValue(weapon, out value) && value < 0.35f; } } private static void MergeZoom(Dictionary<string, float> zoom) { if (zoom == null) { return; } lock (Zoom) { foreach (KeyValuePair<string, float> item in zoom) { if (!Zoom.TryGetValue(item.Key, out var value) || item.Value < value) { Zoom[item.Key] = item.Value; } } } } internal static string ZoomSummary() { lock (Zoom) { return string.Join(", ", from z in Zoom orderby z.Value select $"{z.Key} {z.Value:0.00}"); } } public static List<(float T, int Victim)> LocalKills(ReplayData data, ReplayMeta meta) { List<(float, int)> list = new List<(float, int)>(); int num = data.Objects.FirstOrDefault((ObjectInfo o) => o.Player != null && o.Player.IsLocal)?.Player.PlayerId ?? meta?.Players.FirstOrDefault((ReplayMeta.MetaPlayer p) => p.IsLocal)?.PlayerId ?? (-1); if (num < 0) { return list; } foreach (ReplayEvent @event in data.Events) { if (!(@event.Method != "RpcSendChatLineToAllObservers") && @event.Args.Length != 0 && @event.Args[0] is string input) { string text = Tag.Replace(input, ""); List<int> list2 = (from Match x in Who.Matches(text) select int.Parse(x.Groups[1].Value)).ToList(); if (list2.Count == 2 && text.Contains(" was ") && text.Contains(" by ") && list2[1] == num && list2[0] != num) { list.Add((@event.T, list2[0])); } } } return list; } private static float Yaw(this Vector3 f) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) return Mathf.Atan2(f.x, f.z) * 57.29578f; } private static int FrameAt(List<Frame> frames, float t) { int num = 0; int num2 = frames.Count - 1; while (num < num2) { int num3 = num + num2 + 1 >> 1; if (frames[num3].T <= t) { num = num3; } else { num2 = num3 - 1; } } return num; } private static float Median(IEnumerable<float> values) { List<float> list = values.OrderBy((float x) => x).ToList(); if (list.Count != 0) { return list[list.Count / 2]; } return 0f; } public static void Scan(List<ReplayMeta> metas) { if (Scanning) { return; } string recording = (((Object)(object)Recorder.Instance != (Object)null) ? Recorder.Instance.CurrentMetaPath : null); List<ReplayMeta> todo = metas.Where((ReplayMeta m) => m.HighlightsVersion < 6 && (m.Finished || !string.Equals(m.MetaPath, recording, StringComparison.OrdinalIgnoreCase))).ToList(); if (todo.Count == 0) { return; } foreach (ReplayMeta meta in metas) { MergeZoom(meta.WeaponZoom); } _done = 0; _total = todo.Count; _thread = new Thread((ThreadStart)delegate { int num = 0; Stopwatch stopwatch = Stopwatch.StartNew(); foreach (ReplayMeta item in todo) { try { ReplayMeta work = ReplayMeta.Load(item.MetaPath); if (work == null) { item.HighlightsVersion = 6; _done++; continue; } bool flag = work.FeaturesVersion == 1 && work.KillRecs != null; if (!flag || !work.Finished) { ReplayData replayData = ReplayIO.Read(work.ReplayPath); if (!flag) { Measure(replayData, work); num++; } if (!work.Finished) { work.Duration = replayData.Duration; work.Finished = true; } } List<ReplayMeta.MetaHighlight> found = Score(work); ReplayMeta.UpdateFile(item.MetaPath, delegate(ReplayMeta f) { f.Highlights = found; f.HighlightsVersion = 6; f.KillRecs = work.KillRecs; f.TakeWins = work.TakeWins; f.WeaponZoom = work.WeaponZoom; f.FeaturesVersion = work.FeaturesVersion; if (!f.Finished) { f.Duration = work.Duration; f.Finished = true; } }); item.Highlights = found; item.HighlightsVersion = 6; if (!item.Finished) { item.Duration = work.Duration; item.Finished = true; } } catch (ThreadAbortException) { throw; } catch (Exception ex2) { Plugin.Log.LogWarning((object)("Finding highlights in " + item.ReplayFile + " failed: " + ex2.Message)); item.HighlightsVersion = 6; } _done++; Interlocked.Increment(ref Changes); } Plugin.Log.LogInfo((object)$"Highlights: scored {_total} recordings in {stopwatch.Elapsed.TotalSeconds:0}s ({num} read from disk, the rest from stored measurements); weapon zoom: {ZoomSummary()}"); }) { IsBackground = true, Name = "Streplay highlights", Priority = ThreadPriority.BelowNormal }; _thread.Start(); } } internal enum UiKind : byte { Graphic, Text, Group } internal sealed class UiState { public bool Visible; public Color32 Color; public int Sprite = -1; public float Fill = 1f; public string Text; public Vector2 Pos; public Vector2 Size; public Vector3 Scale = Vector3.one; public float RotZ; public float Alpha = 1f; public bool SameAs(UiState o, bool dynamic = false) { //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: 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_0107: 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_0126: 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) //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) if (o != null && Visible == o.Visible) { if (Visible) { if (Color.r == o.Color.r && Color.g == o.Color.g && Color.b == o.Color.b && Color.a == o.Color.a && Sprite == o.Sprite && Mathf.Abs(Fill - o.Fill) < 0.001f && Text == o.Text) { Vector2 val = Pos - o.Pos; if (((Vector2)(ref val)).sqrMagnitude < (dynamic ? 2.5E-09f : 0.01f)) { val = Size - o.Size; if (((Vector2)(ref val)).sqrMagnitude < (dynamic ? 2.5E-09f : 0.01f)) { Vector3 val2 = Scale - o.Scale; if (((Vector3)(ref val2)).sqrMagnitude < 1E-06f && Mathf.Abs(RotZ - o.RotZ) < 0.05f) { return Mathf.Abs(Alpha - o.Alpha) < 0.002f; } } } } return false; } return true; } return false; } public void Write(BinaryWriter w, UiKind kind) { w.Write(Visible); if (!Visible) { return; } if (kind == UiKind.Group) { w.Write(Alpha); return; } w.Write(Color.r); w.Write(Color.g); w.Write(Color.b); w.Write(Color.a); w.Write(Sprite); w.Write(Fill); if (kind == UiKind.Text) { w.Write(Text ?? ""); } w.Write(Pos.x); w.Write(Pos.y); w.Write(Size.x); w.Write(Size.y); w.Write(Scale.x); w.Write(Scale.y); w.Write(Scale.z); w.Write(RotZ); } public static UiState Read(BinaryReader r, UiKind kind) { //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) UiState uiState = new UiState { Visible = r.ReadBoolean() }; if (!uiState.Visible) { return uiState; } if (kind == UiKind.Group) { uiState.Alpha = r.ReadSingle(); return uiState; } uiState.Color = new Color32(r.ReadByte(), r.ReadByte(), r.ReadByte(), r.ReadByte()); uiState.Sprite = r.ReadInt32(); uiState.Fill = r.ReadSingle(); if (kind == UiKind.Text) { uiState.Text = r.ReadString(); } uiState.Pos = new Vector2(r.ReadSingle(), r.ReadSingle()); uiState.Size = new Vector2(r.ReadSingle(), r.ReadSingle()); uiState.Scale = new Vector3(r.ReadSingle(), r.ReadSingle(), r.ReadSingle()); uiState.RotZ = r.ReadSingle(); return uiState; } } internal sealed class HudCapture { private sealed class Elem { public int Id; public UiKind Kind; public Component C; public UiState Last; public bool SeenThisFrame; public bool Dynamic; } private sealed class Root { public Transform T; public byte Anchor; public Transform AnchorRoot; } public const byte AnchorDdol = 0; public const byte AnchorLocalPlayer = 1; private readonly Dictionary<Component, Elem> _elems = new Dictionary<Component, Elem>(); private readonly List<Elem> _visibleLast = new List<Elem>(); private readonly Dictionary<Transform, Component[]> _comps = new Dictionary<Transform, Component[]>(); private readonly Dictionary<string, int> _strings = new Dictionary<string, int>(); private readonly List<Root> _roots = new List<Root>(); private readonly HashSet<GameObject> _excluded = new HashSet<GameObject>(); private readonly List<(Elem e, UiState s)> _changes = new List<(Elem, UiState)>(); private float _nextRootScan; private Transform _localRoot; private static readonly string[] ExcludedPauseFields = new string[6] { "mainMenu", "pauseMenu", "optionsMenu", "firstInterface", "secondInterface", "voiceChatText" }; private readonly MemoryStream _buf = new MemoryStream(4096); private BinaryWriter _bw; public void Reset() { _elems.Clear(); _visibleLast.Clear(); _comps.Clear(); _strings.Clear(); _roots.Clear(); _nextRootScan = 0f; _localRoot = null; } public void Sample(BinaryWriter output, NetworkObject localPlayer) { if (_bw == null) { _bw = new BinaryWriter(_buf); } _buf.SetLength(0L); SampleInto(_bw, localPlayer); _bw.Flush(); if (_buf.Length > 0) { output.Write(_buf.GetBuffer(), 0, (int)_buf.Length); } } private void SampleInto(BinaryWriter w, NetworkObject localPlayer) { Transform val = (((Object)(object)localPlayer != (Object)null) ? ((Component)localPlayer).transform : null); if (Time.unscaledTime >= _nextRootScan || (Object)(object)val != (Object)(object)_localRoot) { _nextRootScan = Time.unscaledTime + 1f; _localRoot = val; ScanRoots(val); } foreach (Elem item in _visibleLast) { item.SeenThisFrame = false; } _changes.Clear(); foreach (Root root in _roots) { if ((Object)(object)root.T != (Object)null && ((Component)root.T).gameObject.activeInHierarchy) { Walk(w, root, root.T); } } for (int num = _visibleLast.Count - 1; num >= 0; num--) { Elem elem = _visibleLast[num]; if (!elem.SeenThisFrame) { UiState uiState = new UiState { Visible = false }; if (!uiState.SameAs(elem.Last)) { elem.Last = uiState; _changes.Add((elem, uiState)); } _visibleLast.RemoveAt(num); } } if (_changes.Count != 0) { w.Write((byte)8); w.Write((ushort)Math.Min(_changes.Count, 65535)); for (int i = 0; i < _changes.Count && i < 65535; i++) { w.Write(_changes[i].e.Id); _changes[i].s.Write(w, _changes[i].e.Kind); } } } private void ScanRoots(Transform localRoot) { //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_014d: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Invalid comparison between Unknown and I4 //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Invalid comparison between Unknown and I4 _roots.Clear(); _excluded.Clear(); PauseManager instance = PauseManager.Instance; if ((Object)(object)instance != (Object)null) { string[] excludedPauseFields = ExcludedPauseFields; foreach (string text in excludedPauseFields) { object? obj = AccessTools.Field(typeof(PauseManager), text)?.GetValue(instance); GameObject val = (GameObject)((obj is GameObject) ? obj : null); if (val != null && (Object)(object)val != (Object)null) { _excluded.Add(val); } } } if ((Object)(object)VoiceChatUI.Instance != (Object)null) { _excluded.Add(((Component)VoiceChatUI.Instance).gameObject); } Scene val2 = Net.DdolScene(); Canvas[] componentsInChildren; if (((Scene)(ref val2)).IsValid()) { GameObject[] rootGameObjects = ((Scene)(ref val2)).GetRootGameObjects(); for (int i = 0; i < rootGameObjects.Length; i++) { componentsInChildren = rootGameObjects[i].GetComponentsInChildren<Canvas>(true); foreach (Canvas val3 in componentsInChildren) { if (val3.isRootCanvas && (int)val3.renderMode != 2) { _roots.Add(new Root { T = ((Component)val3).transform, Anchor = 0 }); } } } } if (!((Object)(object)localRoot != (Object)null)) { return; } componentsInChildren = ((Component)localRoot).GetComponentsInChildren<Canvas>(true); foreach (Canvas val4 in componentsInChildren) { if (val4.isRootCanvas && (int)val4.renderMode != 2) { _roots.Add(new Root { T = ((Component)val4).transform, Anchor = 1, AnchorRoot = localRoot }); } } } private void Walk(BinaryWriter w, Root root, Transform t) { //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) if (!((Component)t).gameObject.activeSelf || _excluded.Contains(((Component)t).gameObject)) { return; } if (!_comps.TryGetValue(t, out var value)) { value = (Component[])(object)new Component[3] { (Component)((Component)t).GetComponent<Canvas>(), (Component)((Component)t).GetComponent<CanvasGroup>(), (Component)((Component)t).GetComponent<Graphic>() }; _comps[t] = value; } Component obj = value[0]; Canvas val = (Canvas)(object)((obj is Canvas) ? obj : null); if (val != null && (Object)(object)val != (Object)null && !((Behaviour)val).enabled) { return; } Component obj2 = value[1]; CanvasGroup val2 = (CanvasGroup)(object)((obj2 is CanvasGroup) ? obj2 : null); if (val2 != null && (Object)(object)val2 != (Object)null) { Visit(w, root, (Component)(object)val2, UiKind.Group); if (val2.alpha <= 0.001f) { return; } } Component obj3 = value[2]; Graphic val3 = (Graphic)(object)((obj3 is Graphic) ? obj3 : null); if (val3 != null && (Object)(object)val3 != (Object)null && ((Behaviour)val3).enabled && !(val3 is TMP_SubMeshUI)) { Visit(w, root, (Component)(object)val3, (val3 is TMP_Text || val3 is Text) ? UiKind.Text : UiKind.Graphic); } Vector3 localScale = t.localScale; if (!((Object)(object)t != (Object)(object)root.T) || (!(Mathf.Abs(localScale.x) < 0.0001f) && !(Mathf.Abs(localScale.y) < 0.0001f))) { for (int i = 0; i < t.childCount; i++) { Walk(w, root, t.GetChild(i)); } } } private void Visit(BinaryWriter w, Root root, Component c, UiKind kind) { //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_0168: Unknown result type (might be due to invalid IL or missing references) //IL_0180: Unknown result type (might be due to invalid IL or missing references) if (!_elems.TryGetValue(c, out var value)) { value = new Elem { Id = _elems.Count, Kind = kind, C = c, Dynamic = (kind != UiKind.Group && IsSpawned(c.transform, root.T)) }; _elems[c] = value; w.Write((byte)7); w.Write(value.Id); w.Write(root.Anchor); w.Write((root.Anchor == 1) ? Recorder.RelPath(root.AnchorRoot, c.transform) : Recorder.ScenePath(c.transform)); w.Write((byte)kind); w.Write(value.Dynamic); if (value.Dynamic) { Image val = (Image)(object)((c is Image) ? c : null); TMP_Text val2 = (TMP_Text)(object)((c is TMP_Text) ? c : null); w.Write((byte)(((Object)(object)val != (Object)null) ? ((uint)(int)val.type) : 0u)); w.Write((Object)(object)val != (Object)null && val.preserveAspect); w.Write(((Object)(object)val2 != (Object)null && (Object)(object)val2.font != (Object)null) ? ((Object)val2.font).name : ""); w.Write(((Object)(object)val2 != (Object)null) ? val2.fontSize : 0f); w.Write(((Object)(object)val2 != (Object)null) ? ((int)val2.alignment) : 0); w.Write(((Object)(object)val2 != (Object)null) ? ((int)val2.fontStyle) : 0); } } UiState uiState = Capture(w, c, kind, value.Dynamic); if (!value.SeenThisFrame && (value.Last == null || !value.Last.Visible)) { _visibleLast.Add(value); } value.SeenThisFrame = true; if (!uiState.SameAs(value.Last, value.Dynamic)) { value.Last = uiState; _changes.Add((value, uiState)); } } private static bool IsSpawned(Transform t, Transform root) { Transform val = t; while ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)root) { if (((Object)val).name.EndsWith("(Clone)", StringComparison.Ordinal)) { return true; } val = val.parent; } return false; } private UiState Capture(BinaryWriter w, Component c, UiKind kind, bool dynamic) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Expected O, but got Unknown //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Invalid comparison between Unknown and I4 //IL_0190: Unknown result type (might be due to invalid IL or missing references) //IL_0195: Unknown result type (might be due to invalid IL or missing references) //IL_019d: Unknown result type (might be due to invalid IL or missing references) //IL_01a2: Unknown result type (might be due to invalid IL or missing references) //IL_01aa: Unknown result type (might be due to invalid IL or missing references) //IL_01af: Unknown result type (might be due to invalid IL or missing references) //IL_01b7: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_0119: 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) //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Unknown result type (might be due to invalid IL or missing references) //IL_0164: Unknown result type (might be due to invalid IL or missing references) //IL_0169: Unknown result type (might be due to invalid IL or missing references) //IL_016f: Unknown result type (might be due to invalid IL or missing references) //IL_0174: Unknown result type (might be due to invalid IL or missing references) //IL_017c: Unknown result type (might be due to invalid IL or missing references) UiState uiState = new UiState { Visible = true }; if (kind == UiKind.Group) { uiState.Alpha = ((CanvasGroup)c).alpha; return uiState; } Graphic val = (Graphic)c; uiState.Color = Color32.op_Implicit(val.color); Image val2 = (Image)(object)((val is Image) ? val : null); if (val2 != null) { uiState.Sprite = (((Object)(object)val2.sprite != (Object)null) ? StringId(w, ((Object)val2.sprite).name) : (-1)); uiState.Fill = (((int)val2.type == 3) ? val2.fillAmount : 1f); } TMP_Text val3 = (TMP_Text)(object)((val is TMP_Text) ? val : null); if (val3 != null) { uiState.Text = val3.text; } else { Text val4 = (Text)(object)((val is Text) ? val : null); if (val4 != null) { uiState.Text = val4.text; } } RectTransform rectTransform = val.rectTransform; if (dynamic) { Rect rect = rectTransform.rect; Vector3 val5 = ((Transform)rectTransform).TransformPoint(Vector2.op_Implicit(((Rect)(ref rect)).center)); Vector3 lossyScale = ((Transform)rectTransform).lossyScale; float num = Mathf.Max(1, Screen.width); float num2 = Mathf.Max(1, Screen.height); uiState.Pos = new Vector2(val5.x / num, val5.y / num2); rect = rectTransform.rect; float num3 = ((Rect)(ref rect)).width * lossyScale.x / num; rect = rectTransform.rect; uiState.Size = new Vector2(num3, ((Rect)(ref rect)).height * lossyScale.y / num); uiState.Scale = Vector3.one; uiState.RotZ = ((Transform)rectTransform).eulerAngles.z; return uiState; } uiState.Pos = rectTransform.anchoredPosition; uiState.Size = rectTransform.sizeDelta; uiState.Scale = ((Transform)rectTransform).localScale; uiState.RotZ = ((Transform)rectTransform).localEulerAngles.z; return uiState; } private int StringId(BinaryWriter w, string s) { if (_strings.TryGetValue(s, out var value)) { return value; } value = _strings.Count; _strings[s] = value; w.Write((byte)9); w.Write(value); w.Write(s); return value; } } internal sealed class HudReplay { private sealed class Bound { public int Part = -1; public UiElementInfo Info; public Component C; public Canvas RootCanvas; public string FitFor; public int LogBirth = -1; public Vector2 LogPos; public List<Transform> Collapsed; public List<UiElementInfo> Groups; } private sealed class Snap { public Component C; public bool Enabled; public float Alpha; public Color Color; public Sprite Sprite; public float Fill; public string Text; public TMP_SpriteAsset SpriteAsset; public Vector2 Pos; public Vector2 Size; public Vector3 Scale; public Quaternion Rot; } internal static readonly (string key, string label, string[] paths)[] Parts = new(string, string, string[])[9] { ("Crosshair", "Crosshair", new string[1] { "---USER INTERFACE---/Crosshair" }), ("Hitmarkers", "Hitmarkers", new string[1] { "HitMarker" }), ("KillFeed", "Kill feed", new string[1] { "/LogsPosition/" }), ("Ammo", "Ammo", new string[3] { "/GUN_RIGHT", "/GUN_LEFT", "Ammo" }), ("Health", "Health", new string[2] { "/HealthDisplay/text", "Health" }), ("Speed", "Speed", new string[1] { "/Speedometer" }), ("FpsPing", "FPS / ping", new string[2] { "/HealthDisplay/fps", "/HealthDisplay/ping" }), ("RoundText", "Round text", new string[3] { "--START ROUND", "--END ROUND", "/START ROUND TEXT" }), ("Chat", "Text chat", new string[1] { "/ChatText/" }) }; private const string LogPath = "/LogsPosition/LogPrefab(Clone)"; private const float LogLineStep = 35f; private readonly List<int> _logBirths = new List<int>(); private readonly List<Bound> _bound = new List<Bound>(); private readonly List<GameObject> _created = new List<GameObject>(); private Dictionary<string, TMP_FontAsset> _fonts; private readonly List<GameObject> _activated = new List<GameObject>(); private readonly List<Behaviour> _enabled = new List<Behaviour>(); private readonly List<Graphic> _suppressed = new List<Graphic>(); private readonly List<Snap> _snaps = new List<Snap>(); private readonly List<(CanvasGroup g, float a)> _groupAlpha = new List<(CanvasGroup, float)>(); private readonly List<(Transform t, Vector3 scale)> _expanded = new List<(Transform, Vector3)>(); private Dictionary<string, Sprite> _sprites; private ReplayData _data; private readonly List<Canvas> _roots = new List<Canvas>(); private readonly List<(Canvas c, RenderMode mode, Camera cam, float plane, CanvasScaler scaler, bool scalerOn, float scale)> _moved = new List<(Canvas, RenderMode, Camera, float, CanvasScaler, bool, float)>(); private Camera _renderCam; private readonly List<Renderer> _hiddenRenderers = new List<Renderer>(); private static Vector4? _logTextMargin; private static bool _materialsLogged; private static bool _renderersListed; internal static bool ProbeOnRender; private float _nextProbe; private static readonly Regex SpriteName = new Regex("<sprite\\s+name\\s*=\\s*\"?([^\">]+)\"?", RegexOptions.IgnoreCase); private readonly Dictionary<string, TMP_SpriteAsset> _spriteAssetFor = new Dictionary<string, TMP_SpriteAsset>(); private static bool _askedIconMods; private HashSet<Component> _keep; private float _nextStrayCheck; public bool Shown { get; private set; } public bool Available => _bound.Count > 0; internal static bool PartDefault(string key) { return key != "Chat"; } private static int PartOf(string path) { foreach (int item2 in from i in Enumerable.Range(0, Parts.Length) orderby (!(Parts[i].key == "RoundText")) ? ((Parts[i].key == "FpsPing") ? 1 : 2) : 0 select i) { string[] item = Parts[item2].paths; foreach (string value in item) { if (path.IndexOf(value, StringComparison.Ordinal) >= 0 && (item2 != 0 || !path.Contains("ScopeCrosshair"))) { return item2; } } } return -1; } private void TakeSnapshots() { //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0120: 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) //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) _snaps.Clear(); foreach (Bound item in _bound) { if ((Object)(object)item.C == (Object)null || item.Info.Dynamic) { continue; } Snap snap = new Snap { C = item.C }; Component c = item.C; CanvasGroup val = (CanvasGroup)(object)((c is CanvasGroup) ? c : null); if (val != null) { snap.Alpha = val.alpha; } else { Component c2 = item.C; Graphic val2 = (Graphic)(object)((c2 is Graphic) ? c2 : null); if (val2 == null) { continue; } snap.Enabled = ((Behaviour)val2).enabled; snap.Color = val2.color; Image val3 = (Image)(object)((val2 is Image) ? val2 : null); if (val3 != null) { snap.Sprite = val3.sprite; snap.Fill = val3.fillAmount; } TMP_Text val4 = (TMP_Text)(object)((val2 is TMP_Text) ? val2 : null); if (val4 != null) { snap.Text = val4.text; snap.SpriteAsset = val4.spriteAsset; } else { Text val5 = (Text)(object)((val2 is Text) ? val2 : null); if (val5 != null) { snap.Text = val5.text; } } RectTransform rectTransform = val2.rectTransform; snap.Pos = rectTransform.anchoredPosition; snap.Size = rectTransform.sizeDelta; snap.Scale = ((Transform)rectTransform).localScale; snap.Rot = ((Transform)rectTransform).localRotation; } _snaps.Add(snap); } } private void RestoreSnapshots() { //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Expected O, but got Unknown //IL_005a: 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_00f3: 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_010a: Unknown result type (might be due to invalid IL or missing references) foreach (Snap snap in _snaps) { try { if ((Object)(object)snap.C == (Object)null) { continue; } Component c = snap.C; CanvasGroup val = (CanvasGroup)(object)((c is CanvasGroup) ? c : null); if (val != null) { val.alpha = snap.Alpha; continue; } Graphic val2 = (Graphic)snap.C; val2.color = snap.Color; Image val3 = (Image)(object)((val2 is Image) ? val2 : null); if (val3 != null) { val3.sprite = snap.Sprite; val3.fillAmount = snap.Fill; } TMP_Text val4 = (TMP_Text)(object)((val2 is TMP_Text) ? val2 : null); if (val4 != null) { val4.spriteAsset = snap.SpriteAsset; if (val4.text != snap.Text) { val4.text = snap.Text; } } else { Text val5 = (Text)(object)((val2 is Text) ? val2 : null); if (val5 != null) { val5.text = snap.Text; } } RectTransform rectTransform = val2.rectTransform; rectTransform.anchoredPosition = snap.Pos; rectTransform.sizeDelta = snap.Size; ((Transform)rectTransform).localScale = snap.Scale; ((Transform)rectTransform).localRotation = snap.Rot; ((Behaviour)val2).enabled = snap.Enabled; } catch (Exception ex) { Plugin.Log.LogDebug((object)("HUD restore: " + ex.Message)); } } _snaps.Clear(); } public bool UsesCanvas(Canvas c) { if (Shown) { return _roots.Contains(c); } return false; } public void Bind(ReplayData data, Transform localPlayer) { //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_02e9: Unknown result type (might be due to invalid IL or missing references) //IL_02ee: Unknown result type (might be due to invalid IL or missing references) _spriteAssetFor.Clear(); Hide(); Unbind(); _data = data; if (data.Ui.Count == 0) { return; } Scene val = Net.DdolScene(); GameObject[] rootGameObjects = ((Scene)(ref val)).GetRootGameObjects(); int num = 0; int num2 = 0; List<string> list = new List<string>(); foreach (UiElementInfo value in data.Ui.Values) { if (IsTmpSubMesh(value.Path) || value.Path.IndexOf("/VoiceChatIndicator/", StringComparison.Ordinal) >= 0 || value.Path.IndexOf("--PopupWriting--/VoiceText", StringComparison.Ordinal) >= 0 || (value.Kind == UiKind.Group && value.Path.IndexOf("(Clone)", StringComparison.Ordinal) >= 0)) { continue; } if (value.Dynamic) { (Component, Canvas) tuple = Create(value, localPlayer, rootGameObjects); if ((Object)(object)tuple.Item1 != (Object)null) { List<Bound> bound = _bound; Bound obj = new Bound { Info = value }; (obj.C, obj.RootCanvas) = tuple; bound.Add(obj); num2++; } else { num++; } continue; } Transform val2 = Resolve(value.Anchor, value.Path, localPlayer, rootGameObjects); Component val3 = null; if ((Object)(object)val2 != (Object)null) { val3 = (Component)((value.Kind == UiKind.Group) ? ((object)((Component)val2).GetComponent<CanvasGroup>()) : ((object)((Component)val2).GetComponent<Graphic>())); } if ((Object)(object)val3 == (Object)null) { num++; if (list.Count < 60) { list.Add(value.Path); } } else { _bound.Add(new Bound { Info = value, C = val3 }); } } foreach (Bound item in _bound) { item.Part = PartOf(item.Info.Path); } LinkGroups(data); _logBirths.Clear(); if (data.Header.Version < 7) { foreach (Bound item2 in _bound) { if (!item2.Info.Dynamic || item2.Info.Path.IndexOf("/LogsPosition/LogPrefab(Clone)", StringComparison.Ordinal) < 0) { continue; } int num3 = item2.Info.States.FindIndex((UiState st) => st.Visible); if (num3 >= 0) { item2.LogBirth = item2.Info.Frames[num3]; item2.LogPos = item2.Info.States[num3].Pos; if (item2.Info.Kind == UiKind.Graphic && item2.Info.Path.EndsWith("/LogsPosition/LogPrefab(Clone)/Panel (1)", StringComparison.Ordinal)) { _logBirths.Add(item2.LogBirth); } } } _logBirths.Sort(); } Plugin.Log.LogDebug((object)($"HUD: {_bound.Count} elements bound ({num2} rebuilt)" + ((num > 0) ? $", {num} not found" : "") + ((_logBirths.Count > 0) ? $", {_logBirths.Count} kill feed lines restacked" : ""))); if (list.Count > 0) { Plugin.Log.LogDebug((object)("HUD not found: " + string.Join(" | ", list.Distinct()))); } } private static Transform Resolve(byte anchor, string path, Transform localPlayer, GameObject[] ddolRoots) { if (anchor == 1) { if (!((Object)(object)localPlayer != (Object)null)) { return null; } if (!string.IsNullOrEmpty(path)) { return localPlayer.Find(path); } return localPlayer; } int num = path.IndexOf('/'); string text = ((num < 0) ? path : path.Substring(0, num)); foreach (GameObject val in ddolRoots) { if (!(((Object)val).name != text)) { Transform val2 = ((num < 0) ? val.transform : val.transform.Find(path.Substring(num + 1))); if ((Object)(object)val2 != (Object)null) { return val2; } } } return null; } private static Vector4 LogTextMargin() { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: 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_00c7: Unknown result type (might be due to invalid IL or missing references) if (_logTextMargin.HasValue) { return _logTextMargin.Value; } GameObject val = (((Object)(object)MatchLogsOffline.Instance != (Object)null) ? MatchLogsOffline.Instance.chatLinePrefab : null); if ((Object)(object)val == (Object)null && (Object)(object)MatchLogs.Instance != (Object)null) { val = MatchLogs.Instance.chatLinePrefab; } if ((Object)(object)val == (Object)null) { val = (from l in Resources.FindObjectsOfTypeAll<MatchChatLine>() select ((Component)l).gameObject).FirstOrDefault((Func<GameObject, bool>)delegate(GameObject go) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) Scene scene = go.scene; return !((Scene)(ref scene)).IsValid(); }); } TMP_Text val2 = (((Object)(object)val != (Object)null) ? val.GetComponentInChildren<TMP_Text>(true) : null); if ((Object)(object)val2 == (Object)null) { return Vector4.zero; } _logTextMargin = val2.margin; Plugin.Log.LogDebug((object)$"Kill feed text margin {val2.margin}"); return val2.margin; } private (Component c, Canvas canvas) Create(UiElementInfo el, Transform localPlayer, GameObject[] ddolRoots) { //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Expected O, but got Unknown //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: 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_0109: 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_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_0195: Unknown result type (might be due to invalid IL or missing references) string text = el.Path; Transform val = null; while ((Object)(object)val == (Object)null && text.Length > 0) { int num = text.LastIndexOf('/'); text = ((num < 0) ? "" : text.Substring(0, num)); if (text.Length > 0 || el.Anchor == 1) { val = Resolve(el.Anchor, text, localPlayer, ddolRoots); } } Canvas val2 = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponentInParent<Canvas>(true) : null); if ((Object)(object)val2 == (Object)null) { return (c: null, canvas: null); } val2 = val2.rootCanvas; GameObject val3 = new GameObject("Streplay " + el.Path.Substring(el.Path.LastIndexOf('/') + 1), new Type[1] { typeof(RectTransform) }); val3.transform.SetParent(((Component)val2).transform, false); val3.transform.SetAsLastSibling(); RectTransform val4 = (RectTransform)val3.transform; Vector2 val5 = default(Vector2); ((Vector2)(ref val5))..ctor(0.5f, 0.5f); val4.pivot = val5; Vector2 anchorMin = (val4.anchorMax = val5); val4.anchorMin = anchorMin; _created.Add(val3); Graphic val9; if (el.Kind == UiKind.Text) { TextMeshProUGUI val7 = val3.AddComponent<TextMeshProUGUI>(); TMP_FontAsset val8 = FindFont(el.Font); if ((Object)(object)val8 != (Object)null) { ((TMP_Text)val7).font = val8; } ((TMP_Text)val7).fontSize = el.FontSize; ((TMP_Text)val7).alignment = (TextAlignmentOptions)el.Alignment; ((TMP_Text)val7).fontStyle = (FontStyles)el.FontStyle; if (el.Path.IndexOf("/LogsPosition/LogPrefab(Clone)", StringComparison.Ordinal) >= 0) { ((TMP_Text)val7).margin = LogTextMargin(); } val9 = (Graphic)(object)val7; } else { Image obj = val3.AddComponent<Image>(); obj.type = (Type)el.ImageType; obj.preserveAspect = el.PreserveAspect; val9 = (Graphic)(object)obj; } val9.raycastTarget = false; ((Behaviour)val9).enabled = false; return (c: (Component)(object)val9, canvas: val2); } private void Unbind() { foreach (GameObject item in _created) { if ((Object)(object)item != (Object)null) { Object.Destroy((Object)(object)item); } } _created.Clear(); _bound.Clear(); } public void Dispose() { Hide(); Unbind(); } public void Show() { if (Shown || _bound.Count == 0) { return; } Shown = true; TakeSnapshots(); HashSet<Component> hashSet = (_keep = new HashSet<Component>(from b in _bound where (Object)(object)b.C != (Object)null select b.C)); HashSet<Canvas> hashSet2 = new HashSet<Canvas>(); foreach (Bound item2 in _bound) { if ((Object)(object)item2.C == (Object)null) { continue; } Transform val = item2.C.transform; while ((Object)(object)val != (Object)null) { if (!((Component)val).gameObject.activeSelf) { ((Component)val).gameObject.SetActive(true); _activated.Add(((Component)val).gameObject); } Canvas component = ((Component)val).GetComponent<Canvas>(); if ((Object)(object)component != (Object)null) { if (!((Behaviour)component).enabled) { ((Behaviour)component).enabled = true; _enabled.Add((Behaviour)(object)component); } if (component.isRootCanvas) { hashSet2.Add(component); break; } } val = val.parent; } } _roots.Clear(); _roots.AddRange(hashSet2); FindCollapsedParents(hashSet); if ((Object)(object)_renderCam != (Object)null) { MoveToCamera(); } foreach (Canvas item3 in hashSet2) { Graphic[] componentsInChildren = ((Component)item3).GetComponentsInChildren<Graphic>(true); foreach (Graphic val2 in componentsInChildren) { if (((Behaviour)val2).enabled && !hashSet.Contains((Component)(object)val2) && !(val2 is TMP_SubMeshUI)) { ((Behaviour)val2).enabled = false; _suppressed.Add(val2); } } CanvasGroup[] componentsInChildren2 = ((Component)item3).GetComponentsInChildren<CanvasGroup>(true); foreach (CanvasGroup val3 in componentsInChildren2) { if (!hashSet.Contains((Component)(object)val3)) { _groupAlpha.Add((val3, val3.alpha)); } } } foreach (var item4 in _groupAlpha) { CanvasGroup item = item4.g; if ((Object)(object)item != (Object)null) { item.alpha = 1f; } } } public void Hide() { //IL_0044: 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_0054: Unknown result type (might be due to invalid IL or missing references) if (!Shown) { return; } Shown = false; _keep = null; RestoreFromCamera(); _roots.Clear(); foreach (var (val, localScale) in _expanded) { if ((Object)(object)val != (Object)null) { val.localScale = localScale; } } _expanded.Clear(); foreach (var (val2, alpha) in _groupAlpha) { if ((Object)(object)val2 != (Object)null) { val2.alpha = alpha; } } _groupAlpha.Clear(); foreach (Graphic item in _suppressed) { if ((Object)(object)item != (Object)null) { ((Behaviour)item).enabled = true; } } _suppressed.Clear(); RestoreSnapshots(); foreach (Behaviour item2 in _enabled) { if ((Object)(object)item2 != (Object)null) { item2.enabled = false; } } _enabled.Clear(); for (int num = _activated.Count - 1; num >= 0; num--) { if ((Object)(object)_activated[num] != (Object)null) { _activated[num].SetActive(false); } } _activated.Clear(); } private void FindCollapsedParents(HashSet<Component> keep) { //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) foreach (Bound item in _bound) { item.Collapsed = null; if ((Object)(object)item.C == (Object)null || item.Info.Dynamic) { continue; } Transform parent = item.C.transform.parent; while ((Object)(object)parent != (Object)null) { Canvas component = ((Component)parent).GetComponent<Canvas>(); if (component != null && component.isRootCanvas) { break; } Graphic component2 = ((Component)parent).GetComponent<Graphic>(); if (component2 == null || !keep.Contains((Component)(object)component2)) { Vector3 localScale = parent.localScale; if (Mathf.Abs(localScale.x) < 0.05f || Mathf.Abs(localScale.y) < 0.05f) { Bound bound = item; (bound.Collapsed ?? (bound.Collapsed = new List<Transform>())).Add(parent); } } parent = parent.parent; } } List<Bound> list = _bound.Where((Bound b) => b.Collapsed != null).ToList(); if (list.Count > 0) { Plugin.Log.LogDebug((object)($"HUD: {list.Count} recorded elements sit in collapsed containers (" + string.Join(", ", from t in list.SelectMany((Bound b) => b.Collapsed).Distinct().Take(4) select $"{((Object)t).name} scale {t.localScale.x:0.###}") + ")" + ((_data.Header.Version < 7) ? ", kept hidden" : ""))); } } public void SetRenderCamera(Camera cam) { if (!((Object)(object)cam == (Object)(object)_renderCam)) { RestoreFromCamera(); _renderCam = cam; if ((Object)(object)cam != (Object)null && Shown) { MoveToCamera(); } } } internal void ProbeCentre(string when) { //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: 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_00d7: 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_0135: 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_01c2: Unknown result type (might be due to invalid IL or missing references) //IL_01c7: Unknown result type (might be due to invalid IL or missing references) //IL_01cb: Unknown result type (might be due to invalid IL or missing references) //IL_01df: Unknown result type (might be due to invalid IL or missing references) //IL_0293: Unknown result type (might be due to invalid IL or missing references) //IL_0298: Unknown result type (might be due to invalid IL or missing references) HashSet<Component> hashSet = new HashSet<Component>(from b in _bound where (Object)(object)b.C != (Object)null select b.C); foreach (Canvas root in _roots) { if ((Object)(object)root == (Object)null) { continue; } Camera val = (((int)root.renderMode == 0) ? null : root.worldCamera); Vector2 val2 = (((Object)(object)val != (Object)null && (Object)(object)val.targetTexture != (Object)null) ? (new Vector2((float)((Texture)val.targetTexture).width, (float)((Texture)val.targetTexture).height) / 2f) : (new Vector2((float)Screen.width, (float)Screen.height) / 2f)); Graphic[] componentsInChildren = ((Component)root).GetComponentsInChildren<Graphic>(false); foreach (Graphic val3 in componentsInChildren) { if (((Behaviour)val3).enabled && !val3.canvasRenderer.cull && !(val3.canvasRenderer.GetInheritedAlpha() <= 0.001f) && !(val3.color.a <= 0.001f) && RectTransformUtility.RectangleContainsScreenPoint(val3.rectTransform, val2, val)) { Texture mainTexture = val3.mainTexture; Canvas canvas = val3.canvas; ManualLogSource log = Plugin.Log; string[] array = new string[5]; object[] obj = new object[6] { when, Recorder.ScenePath(((Component)val3).transform), ((object)val3).GetType().Name, hashSet.Contains((Component)(object)val3), null, null }; Rect rect = val3.rectTransform.rect; obj[4] = ((Rect)(ref rect)).size; obj[5] = ((Component)val3).transform.lossyScale.x; array[0] = string.Format("[probe {0}] {1} {2} recorded={3} rect={4} lossy={5:0.####} ", obj); array[1] = "tex="; array[2] = (((Object)(object)mainTexture != (Object)null) ? (((Object)mainTexture).name + " " + mainTexture.width + "x" + mainTexture.height) : "-"); array[3] = " canvas="; array[4] = (((Object)(object)canvas != (Object)null) ? (((Object)canvas).name + " " + ((object)canvas.renderMode/*cast due to .constrained prefix*/).ToString() + " order " + canvas.sortingOrder) : "-"); log.LogDebug((object)string.Concat(array)); } } } } private void MoveToCamera() { //IL_02a1: Unknown result type (might be due to invalid IL or missing references) //IL_02be: Unknown result type (might be due to invalid IL or missing references) //IL_01d5: Unknown result type (might be due to invalid IL or missing references) //IL_01da: Unknown result type (might be due to invalid IL or missing references) //IL_01f0: Unknown result type (might be due to invalid IL or missing references) //IL_01f5: Unknown result type (might be due to invalid IL or missing references) //IL_01f9: Unknown result type (might be due to invalid IL or missing references) //IL_018d: Unknown result type (might be due to invalid IL or missing references) if (ProbeOnRender) { ProbeCentre("render"); } if (!_materialsLogged) { _materialsLogged = true; foreach (Bound item in _bound) { Component c = item.C; Graphic val = (Graphic)(object)((c is Graphic) ? c : null); if (val == null || (Object)(object)val == (Object)null) { continue; } Material materialForRendering = val.materialForRendering; if (((Object)(object)materialForRendering != (Object)null && (Object)(object)materialForRendering != (Object)(object)Graphic.defaultGraphicMaterial) || item.Info.Path.IndexOf("rosshair", StringComparison.Ordinal) >= 0) { Image val2 = (Image)(object)((val is Image) ? val : null); ManualLogSource log = Plugin.Log; string[] obj = new string[10] { "[hud] ", item.Info.Path, ": material=", ((Object)(object)materialForRendering != (Object)null) ? ((Object)materialForRendering).name : "null", " shader=", ((Object)(object)materialForRendering != (Object)null && (Object)(object)materialForRendering.shader != (Object)null) ? ((Object)materialForRendering.shader).name : "null", " sprite=", null, null, null }; object obj2; if (!((Object)(object)val2 != (Object)null) || !((Object)(object)val2.sprite != (Object)null)) { obj2 = "-"; } else { object[] obj3 = new object[4] { ((Object)val2.sprite).name, null, null, null }; Texture2D texture = val2.sprite.texture; obj3[1] = ((texture != null) ? ((Object)texture).name : null); obj3[2] = val2.sprite.textureRect; obj3[3] = val2.sprite.packed; obj2 = string.Format("{0} tex={1} rect={2} packed={3}", obj3); } obj[7] = (string)obj2; obj[8] = " "; string arg = (((Object)(object)val2 != (Object)null) ? ((object)val2.type/*cast due to .constrained prefix*/).ToString() : "-"); Rect rect = val.rectTransform.rect; obj[9] = $"type={arg} size={((Rect)(ref rect)).size}"; log.LogDebug((object)string.Concat(obj)); } } } RenderTexture targetTexture = _renderCam.targetTexture; float w = (((Object)(object)targetTexture != (Object)null) ? ((Texture)targetTexture).width : _renderCam.pixelWidth); float h = (((Object)(object)targetTexture != (Object)null) ? ((Texture)targetTexture).height : _renderCam.pixelHeight); foreach (Canvas root in _roots) { if ((Object)(object)root == (Object)null || (int)root.renderMode != 0) { continue; } CanvasScaler component = ((Component)root).GetComponent<CanvasScaler>(); _moved.Add((root, root.renderMode, root.worldCamera, root.planeDistance, component, (Object)(object)component != (Object)null && ((Behaviour)component).enabled, root.scaleFactor)); float scaleFactor = ScaleFor(root, component, w, h); if ((Object)(object)component != (Object)null) { ((Behaviour)component).enabled = false; } root.renderMode = (RenderMode)1; root.worldCamera = _renderCam; root.planeDistance = 5000f; root.scaleFactor = scaleFactor; Renderer[] componentsInChildren = ((Component)root).GetComponentsInChildren<Renderer>(false); foreach (Renderer val3 in componentsInChildren) { if (val3.enabled) { val3.enabled = false; _hiddenRenderers.Add(val3); } } } if (!_renderersListed) { _renderersListed = true; List<Renderer> list = _moved.SelectMany(((Canvas c, RenderMode mode, Camera cam, float plane, CanvasScaler scaler, bool scalerOn, float scale) m) => ((Component)m.c).GetComponentsInChildren<Renderer>(true)).ToList(); Plugin.Log.LogDebug((object)($"[render] 3D renderers in the HUD canvases ({list.Count}): " + string.Join(", ", from r in list.Take(12) select $"{Recorder.ScenePath(((Component)r).transform)} {((object)r).GetType().Name} on={r.enabled && ((Component)r).gameObject.activeInHierarchy}"))); } if (_hiddenRenderers.Count > 0) { Plugin.Log.LogDebug((object)($"[render] hid {_hiddenRenderers.Count} 3D renderers inside the HUD canvases: " + string.Join(", ", from r in _hiddenRenderers.Take(6) select ((Object)r).name + " (" + ((object)r).GetType().Name + ")"))); } } private void RestoreFromCamera() { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) foreach (var (val, renderMode, worldCamera, planeDistance, val2, enabled, scaleFactor) in _moved) { if (!((Object)(object)val == (Object)null)) { val.renderMode = renderMode; val.worldCamera = worldCamera; val.planeDistance = planeDistance; val.scaleFactor = scaleFactor; if ((Object)(object)val2 != (Object)null) { ((Behaviour)val2).enabled = enabled; } } } _moved.Clear(); foreach (Renderer hiddenRenderer in _hiddenRenderers) { if ((Object)(object)hiddenRenderer != (Object)null) { hiddenRenderer.enabled = true; } } _hiddenRenderers.Clear(); } private static float ScaleFor(Canvas c, CanvasScaler s, float w, float h) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0039: 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) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Invalid comparison between Unknown and I4 //IL_004c: 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_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Invalid comparison between Unknown and I4 //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)s == (Object)null || !((Behaviour)s).enabled) { return c.scaleFactor * h / (float)Mathf.Max(1, Screen.height); } if ((int)s.uiScaleMode == 1) { Vector2 referenceResolution = s.referenceResolution; ScreenMatchMode screenMatchMode = s.screenMatchMode; if ((int)screenMatchMode != 1) { if ((int)screenMatchMode == 2) { return Mathf.Max(w / referenceResolution.x, h / referenceResolution.y); } float num = Mathf.Log(w / referenceResolution.x, 2f); float num2 = Mathf.Log(h / referenceResolution.y, 2f); return Mathf.Pow(2f, Mathf.Lerp(num, num2, s.matchWidthOrHeight)); } return Mathf.Min(w / referenceResolution.x, h / referenceResolution.y); } return c.scaleFactor * h / (float)Mathf.Max(1, Screen.height); } public void Apply(int frame) { //IL_028c: Unknown result type (might be due to invalid IL or missing references) //IL_0293: Expected O, but got Unknown //IL_025b: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_0380: Unknown result type (might be due to invalid IL or missing references) //IL_0385: Unknown result type (might be due to invalid IL or missing references) //IL_038a: Unknown result type (might be due to invalid IL or missing references) //IL_0410: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Unknown result type (might be due to invalid IL or missing references) //IL_0174: Unknown result type (might be due to invalid IL or missing references) //IL_0179: Unknown result type (might be due to invalid IL or missing references) //IL_017d: Unknown result type (might be due to invalid IL or missing references) //IL_0190: Unknown result type (might be due to invalid IL or missing references) //IL_0478: Unknown result type (might be due to invalid IL or missing references) //IL_047e: Invalid comparison between Unknown and I4 //IL_066b: Unknown result type (might be due to invalid IL or missing references) //IL_0679: Unknown result type (might be due to invalid IL or missing references) //IL_0687: Unknown result type (might be due to invalid IL or missing references) //IL_0693: Unknown result type (might be due to invalid IL or missing references) //IL_0698: Unknown result type (might be due to invalid IL or missing references) //IL_069c: Unknown result type (might be due to invalid IL or missing references) //IL_06a3: Unknown result type (might be due to invalid IL or missing references) //IL_06b1: Unknown result type (might be due to invalid IL or missing references) //IL_0314: Unknown result type (might be due to invalid IL or missing references) //IL_0319: Unknown result type (might be due to invalid IL or missing references) //IL_0598: Unknown result type (might be due to invalid IL or missing references) //IL_059d: Unknown result type (might be due to invalid IL or missing references) //IL_0585: Unknown result type (might be due to invalid IL or missing references) //IL_03f3: Unknown result type (might be due to invalid IL or missing references) //IL_032f: Unknown result type (might be due to invalid IL or missing references) //IL_0340: Unknown result type (might be due to invalid IL or missing references) //IL_01c8: Unknown result type (might be due to invalid IL or missing references) //IL_05a2: Unknown result type (might be due to invalid IL or missing references) //IL_05b9: Unknown result type (might be due to invalid IL or missing references) //IL_05b0: Unknown result type (might be due to invalid IL or missing references) //IL_05be: Unknown result type (might be due to invalid IL or missing references) //IL_05c2: Unknown result type (might be due to invalid IL or missing references) //IL_05d7: Unknown result type (might be due to invalid IL or missing references) //IL_0602: 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_061c: Unknown result type (might be due to invalid IL or missing references) //IL_0628: Unknown result type (might be due to invalid IL or missing references) //IL_0645: Unknown result type (might be due to invalid IL or missing references) if (!Shown) { return; } if (ProbeOnRender && (Object)(object)_renderCam != (Object)null && Time.realtimeSinceStartup > _nextProbe) { _nextProbe = Time.realtimeSinceStartup + 1f; foreach (Bound item in _bound) { Component c = item.C; Image val = (Image)(object)((c is Image) ? c : null); if (val != null && !((Object)(object)val == (Object)null) && item.Info.Path.IndexOf("/Crosshair", StringComparison.Ordinal) >= 0) { Sprite sprite = val.sprite; ManualLogSource log = Plugin.Log; object arg = frame; object arg2; if (!((Object)(object)sprite != (Object)null)) { arg2 = "null"; } else { object[] obj = new object[4] { ((Object)sprite).name, ((Object)sprite).GetInstanceID(), sprite.rect, null }; Texture2D texture = sprite.texture; obj[3] = ((texture != null) ? ((Object)texture).name : null); arg2 = string.Format("{0}#{1} rect={2} tex={3}", obj); } string text = $"[xhair] frame {arg} sprite={arg2} "; string text2 = string.Format("override={0} type={1} ", ((Object)(object)val.overrideSprite != (Object)null) ? (((Object)val.overrideSprite).name + "#" + ((Object)val.overrideSprite).GetInstanceID()) : "-", val.type); object[] array = new object[4]; Rect rect = ((Graphic)val).rectTransform.rect; array[0] = ((Rect)(ref rect)).size; array[1] = ((Transform)((Graphic)val).rectTransform).localScale; Material materialForRendering = ((Graphic)val).materialForRendering; array[2] = ((materialForRendering != null) ? ((Object)materialForRendering).name : null); Canvas canvas = ((Graphic)val).canvas; array[3] = ((canvas != null) ? new RenderMode?(canvas.renderMode) : ((RenderMode?)null)); log.LogDebug((object)(text + text2 + string.Format("size={0} scale={1} mat={2} canvas={3}", array))); } } } SuppressStrays(now: false); foreach (Bound item2 in _bound) { UiState uiState = StateAt(item2.Info, frame); if ((Object)(object)item2.C == (Object)null) { continue; } if (item2.Info.Kind == UiKind.Group) { ((CanvasGroup)item2.C).alpha = ((uiState != null && uiState.Visible) ? uiState.Alpha : 0f); continue; } Graphic val2 = (Graphic)item2.C; bool flag = uiState != null && uiState.Visible && (item2.Part < 0 || Plugin.HudShow[item2.Part].Value); if (flag && item2.Collapsed != null) { if (_data.Header.Version < 7) { flag = false; } else { foreach (Transform item3 in item2.Collapsed) { if ((Object)(object)item3 != (Object)null && item3.localScale != Vector3.one) { _expanded.Add((item3, item3.localScale)); item3.localScale = Vector3.one; } } } } if (((Behaviour)val2).enabled != flag) { ((Behaviour)val2).enabled = flag; } if (!flag) { continue; } Color val3 = Color32.op_Implicit(uiState.Color); if (item2.Groups != null) { foreach (UiElementInfo group in item2.Groups) { UiState uiState2 = StateAt(group, frame); val3.a *= ((uiState2 != null && uiState2.Visible) ? uiState2.Alpha : 0f); } if (val3.a <= 0.002f) { ((Behaviour)val2).enabled = false; continue; } } val2.color = val3; Image val4 = (Image)(object)((val2 is Image) ? val2 : null); if (val4 != null) { if (uiState.Sprite >= 0 && _data.UiStrings.TryGetValue(uiState.Sprite, out var value)) { Sprite val5 = FindSprite(value); if ((Object)(object)val5 != (Object)null && (Object)(object)val4.sprite != (Object)(object)val5) { val4.sprite = val5; } } if ((int)val4.type == 3) { val4.fillAmount = uiState.Fill; } } if (uiState.Text != null) { TMP_Text val6 = (TMP_Text)(object)((val2 is TMP_Text) ? val2 : null); if (val6 != null) { if (val6.text != uiState.Text) { if (uiState.Text.IndexOf("<sprite", StringComparison.OrdinalIgnoreCase) >= 0) { TMP_SpriteAsset val7 = SpriteAssetFor(uiState.Text); if ((Object)(object)val7 != (Object)null && (Object)(object)val6.spriteAsset != (Object)(object)val7) { val6.spriteAsset = val7; } } val6.text = uiState.Text; } } else { Text val8 = (Text)(object)((val2 is Text) ? val2 : null); if (val8 != null && val8.text != uiState.Text) { val8.text = uiState.Text; } } } RectTransform rectTransform = val2.rectTransform; if (item2.Info.Dynamic) { Rect val9 = (Rect)(((Object)(object)item2.RootCanvas != (Object)null) ? ((RectTransform)((Component)item2.RootCanvas).transform).rect : new Rect(0f, 0f, (float)Screen.width, (float)Screen.height)); Vector2 val10 = ((item2.LogBirth >= 0) ? item2.LogPos : uiState.Pos); rectT