using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using LethalCompanyInputUtils.Api; using UnityEngine; using UnityEngine.InputSystem; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyCompany("Log_Backup")] [assembly: AssemblyDescription("This mod provides a simple way for user to point out issues")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("Log_Backup")] [assembly: AssemblyTitle("Log_Backup")] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyVersion("1.0.0.0")] namespace Log_Backup; public class LogBackupInputs : LcInputActions { [InputAction("/f9", Name = "Log Backup Marker", ActionId = "log_backup_marker")] public InputAction MarkerKey { get; set; } } [BepInPlugin("LKK.Log_Backup", "Log_Backup", "1.0.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Log_BackupPlugin : BaseUnityPlugin { private static class RunningCode { private static readonly Dictionary Seen = new Dictionary(); private static readonly Dictionary Methods = new Dictionary(); private static readonly HashSet ThisFrame = new HashSet(); private static int _frame = -1; public static bool Pending; public static void Apply(Harmony harmony) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Expected O, but got Unknown HarmonyMethod val = new HarmonyMethod(AccessTools.Method(typeof(RunningCode), "Capture", (Type[])null, (Type[])null)); foreach (Type item in AccessTools.AllTypes()) { if (item.IsAbstract || item.IsInterface || item.IsGenericTypeDefinition || item == typeof(Log_BackupPlugin) || !typeof(MonoBehaviour).IsAssignableFrom(item)) { continue; } foreach (MethodInfo declaredMethod in AccessTools.GetDeclaredMethods(item)) { if ((!(declaredMethod.Name != "Update") || !(declaredMethod.Name != "LateUpdate") || !(declaredMethod.Name != "FixedUpdate")) && !declaredMethod.IsStatic) { try { harmony.Patch((MethodBase)declaredMethod, (HarmonyMethod)null, val, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } catch { } } } } } public static void Capture(MethodBase __originalMethod) { try { if (Time.frameCount != _frame) { _frame = Time.frameCount; ThisFrame.Clear(); } if (ThisFrame.Add(__originalMethod)) { string key = __originalMethod.DeclaringType.Name + "." + __originalMethod.Name; Seen[key] = Time.time; Methods[key] = __originalMethod; } if (Pending) { Pending = false; float cutoff = Time.time - 5f; IEnumerable values = from kv in Seen where kv.Value >= cutoff orderby kv.Value descending select " " + (IsModPatched(Methods[kv.Key]) ? "* " : "") + kv.Key; Debug.Log((object)("[Log_Backup] Running in the last 5 seconds:\n" + string.Join("\n", values))); } } catch { } } private static bool IsModPatched(MethodBase m) { try { Patches patchInfo = Harmony.GetPatchInfo(m); if (patchInfo == null) { return false; } return patchInfo.Prefixes.Any((Patch p) => p.owner != "LKK.Log_Backup") || patchInfo.Postfixes.Any((Patch p) => p.owner != "LKK.Log_Backup") || patchInfo.Transpilers.Any((Patch p) => p.owner != "LKK.Log_Backup") || patchInfo.Finalizers.Any((Patch p) => p.owner != "LKK.Log_Backup"); } catch { return false; } } } public const string PLUGIN_GUID = "LKK.Log_Backup"; public const string PLUGIN_NAME = "Log_Backup"; public const string PLUGIN_VERSION = "1.0.0"; public const string PLUGIN_VERSION_FULL = "1.0.0.0"; private const string MarkerToken = "Log_Backup::MARKER"; private const string CrashMarker = "Crash!!!"; private const string InputUtilsGuid = "com.rune580.LethalCompanyInputUtils"; public static ManualLogSource logger; public static Log_BackupPlugin Instance; private bool _markerPressed; private bool _quitHandled; private Key _markerFallbackKey; private ConfigEntry _runningCode; private string _backupFolder; private string _playerLogPath; private string _playerPrevLogPath; private string _logOutputPath; private InputAction _fallbackAction; private void Awake() { //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_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Expected O, but got Unknown Instance = this; logger = ((BaseUnityPlugin)this).Logger; ((Object)((Component)this).gameObject).hideFlags = (HideFlags)61; _markerFallbackKey = ((BaseUnityPlugin)this).Config.Bind("Log_Backup", "MarkerFallbackKey", (Key)102, "Fallback key used when InputUtils is not loaded.").Value; _runningCode = ((BaseUnityPlugin)this).Config.Bind("Log_Backup", "RunningCode", false, "When enabled, records which Update/LateUpdate/FixedUpdate methods ran in the last 5 seconds and prints them when the marker key is pressed. This requires patching those methods."); _playerLogPath = Application.consoleLogPath; _playerPrevLogPath = Path.Combine(Path.GetDirectoryName(_playerLogPath), "Player-prev.log"); _logOutputPath = Path.Combine(Paths.BepInExRootPath, "LogOutput.log"); _backupFolder = Path.Combine(Paths.BepInExRootPath, "Log_Backup", DateTime.Now.ToString("MM-dd-yyyy_HH-mm-ss")); TryBackupPrevLog(); SetupMarkerInput(); if (_runningCode.Value) { try { RunningCode.Apply(new Harmony("LKK.Log_Backup")); } catch { } } } private void OnMarkerPerformed(CallbackContext context) { _markerPressed = true; string text = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"); Debug.Log((object)("[Log_Backup] Log_Backup::MARKER " + text)); if (_runningCode.Value) { RunningCode.Pending = true; } try { if ((Object)(object)HUDManager.Instance != (Object)null) { HUDManager.Instance.DisplayTip("Log_Backup", "Marker logged at " + text, false, false, "Log_Backup_Tip"); } } catch { } } private void OnApplicationQuit() { if (!_quitHandled && _markerPressed) { _quitHandled = true; CopyLog(_playerLogPath, "Player"); CopyLog(_logOutputPath, "LogOutput"); } } private void CopyLog(string source, string tag) { if (!File.Exists(source)) { return; } EnsureBackupFolder(); string text = Path.Combine(_backupFolder, tag + ".log"); try { File.Copy(source, text, overwrite: true); logger.LogInfo((object)("[Log_Backup] backed up " + text)); } catch (Exception arg) { logger.LogError((object)$"[Log_Backup] {arg}"); } } private void TryBackupPrevLog() { if (!File.Exists(_playerPrevLogPath)) { return; } string text; try { text = File.ReadAllText(_playerPrevLogPath); } catch (Exception arg) { logger.LogError((object)$"[Log_Backup] {arg}"); return; } if (!text.Contains("Crash!!!") && !text.Contains("Log_Backup::MARKER")) { return; } EnsureBackupFolder(); string text2 = Path.Combine(_backupFolder, "Player-prev.log"); try { File.Copy(_playerPrevLogPath, text2, overwrite: true); logger.LogInfo((object)("[Log_Backup] backed up " + text2)); } catch (Exception arg2) { logger.LogError((object)$"[Log_Backup] {arg2}"); } } private void EnsureBackupFolder() { if (!Directory.Exists(_backupFolder)) { Directory.CreateDirectory(_backupFolder); } } private void SetupMarkerInput() { if (Chainloader.PluginInfos.ContainsKey("com.rune580.LethalCompanyInputUtils")) { TrySetupInputUtils(); } else { SetupFallbackInput(); } } private void TrySetupInputUtils() { try { new LogBackupInputs().MarkerKey.performed += OnMarkerPerformed; } catch (Exception ex) { logger.LogWarning((object)("[Log_Backup] LethalCompanyInputUtils keybind setup failed: " + ex.Message)); SetupFallbackInput(); } } private void SetupFallbackInput() { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Expected O, but got Unknown string text = "/" + ((object)Unsafe.As(ref _markerFallbackKey)/*cast due to .constrained prefix*/).ToString().ToLowerInvariant(); try { _fallbackAction = new InputAction("Log_Backup Marker", (InputActionType)1, text, (string)null, (string)null, (string)null); _fallbackAction.performed += OnMarkerPerformed; _fallbackAction.Enable(); } catch (Exception ex) { logger.LogError((object)("[Log_Backup] Failed to bind fallback input " + text + ": " + ex.Message)); } } }