using System; using System.Diagnostics; using System.IO; using System.Net.Http; using System.Runtime.CompilerServices; using LogLevel = BepInEx.Logging.LogLevel; namespace AmongUsRevamped; public interface ILogHandler { public void Info(string text); public void Warn(string text); public void Error(string text); public void Fatal(string text); public void Msg(string text); public void Exception(Exception ex); } class LogHandler(string tag) : ILogHandler { public string Tag { get; } = tag; public void Info(string text) => Logger.Info(text, Tag, true); public void Warn(string text) => Logger.Warn(text, Tag, true); public void Error(string text) => Logger.Error(text, Tag, true); public void Fatal(string text) => Logger.Fatal(text, Tag, true); public void Msg(string text) => Logger.Msg(text, Tag, true); public void Exception(Exception ex) => Logger.Exception(ex, Tag); } class Logger { public static bool IsEnable = true; public static List DisableList = []; public static List SendToGameList = []; private static readonly HashSet NowDetailedErrorLog = []; public static bool isDetail = false; public static bool isAlsoInGame = false; public static void Enable() => IsEnable = true; public static void Disable() => IsEnable = false; public static void Enable(string tag, bool toGame = false) { DisableList.Remove(tag); if (toGame && !SendToGameList.Contains(tag)) SendToGameList.Add(tag); else SendToGameList.Remove(tag); } public static void Disable(string tag) { if (!DisableList.Contains(tag)) DisableList.Add(tag); } public static void SendInGame(string text) { if (!IsEnable) return; if (DestroyableSingleton._instance) DestroyableSingleton.Instance.Notifier.AddDisconnectMessage(text); } private static void SendToFile(string text, LogLevel level = LogLevel.Info, string tag = "", bool escapeCRLF = true, int lineNumber = 0, string fileName = "", bool multiLine = false) { if (!IsEnable || DisableList.Contains(tag)) return; var logger = Main.Logger; if (SendToGameList.Contains(tag) || isAlsoInGame) { SendInGame($"[{tag}]{text}"); } string log_text; if (level is LogLevel.Error or LogLevel.Fatal or LogLevel.Warning && !multiLine && !NowDetailedErrorLog.Contains(tag)) { string t = DateTime.Now.ToString("HH:mm:ss"); StackFrame stack = new(2); string className = stack.GetMethod()?.ReflectedType?.Name; string memberName = stack.GetMethod()?.Name; log_text = $"[{t}][{className}.{memberName}({Path.GetFileName(fileName)}:{lineNumber})][{tag}]{text}"; NowDetailedErrorLog.Add(tag); _ = new LateTask(() => NowDetailedErrorLog.Remove(tag), 3f); } else { if (escapeCRLF) text = text.Replace("\r", "\\r").Replace("\n", "\\n"); string t = DateTime.Now.ToString("HH:mm:ss"); log_text = $"[{t}][{tag}]{text}"; } switch (level) { case LogLevel.Info when !multiLine: logger.LogInfo(log_text); break; case LogLevel.Info: log_text.Split("\\n").Do(logger.LogInfo); break; case LogLevel.Warning when !multiLine: logger.LogWarning(log_text); break; case LogLevel.Warning: log_text.Split("\\n").Do(logger.LogWarning); break; case LogLevel.Error when !multiLine: logger.LogError(log_text); break; case LogLevel.Error: log_text.Split("\\n").Do(logger.LogError); break; case LogLevel.Fatal when !multiLine: logger.LogFatal(log_text); break; case LogLevel.Fatal: log_text.Split("\\n").Do(logger.LogFatal); break; case LogLevel.Message when !multiLine: logger.LogMessage(log_text); break; case LogLevel.Message: log_text.Split("\\n").Do(logger.LogMessage); break; case LogLevel.Debug when !multiLine: logger.LogFatal(log_text); break; case LogLevel.Debug: log_text.Split("\\n").Do(logger.LogFatal); break; default: logger.LogWarning("Error: Invalid LogLevel"); logger.LogInfo(log_text); break; } } public static void Test(object content, string tag = "======= Test =======", bool escapeCRLF = true, [CallerLineNumber] int lineNumber = 0, [CallerFilePath] string fileName = "", bool multiLine = false) => SendToFile(content.ToString(), LogLevel.Debug, tag, escapeCRLF, lineNumber, fileName, multiLine); public static void Info(string text, string tag, bool escapeCRLF = true, [CallerLineNumber] int lineNumber = 0, [CallerFilePath] string fileName = "", bool multiLine = false) => SendToFile(text, LogLevel.Info, tag, escapeCRLF, lineNumber, fileName, multiLine); public static void Warn(string text, string tag, bool escapeCRLF = true, [CallerLineNumber] int lineNumber = 0, [CallerFilePath] string fileName = "", bool multiLine = false) => SendToFile(text, LogLevel.Warning, tag, escapeCRLF, lineNumber, fileName, multiLine); public static void Error(string text, string tag, bool escapeCRLF = true, [CallerLineNumber] int lineNumber = 0, [CallerFilePath] string fileName = "", bool multiLine = false) => SendToFile(text, LogLevel.Error, tag, escapeCRLF, lineNumber, fileName, multiLine); public static void Fatal(string text, string tag, bool escapeCRLF = true, [CallerLineNumber] int lineNumber = 0, [CallerFilePath] string fileName = "", bool multiLine = false) => SendToFile(text, LogLevel.Fatal, tag, escapeCRLF, lineNumber, fileName, multiLine); public static void Msg(string text, string tag, bool escapeCRLF = true, [CallerLineNumber] int lineNumber = 0, [CallerFilePath] string fileName = "", bool multiLine = false) => SendToFile(text, LogLevel.Message, tag, escapeCRLF, lineNumber, fileName, multiLine); public static void Exception(Exception ex, string tag, [CallerLineNumber] int lineNumber = 0, [CallerFilePath] string fileName = "") => SendToFile(ex.ToString(), LogLevel.Error, tag, false, lineNumber, fileName); public static void CurrentMethod([CallerLineNumber] int lineNumber = 0, [CallerFilePath] string fileName = "") { StackFrame stack = new(1); Msg($"\"{stack.GetMethod().ReflectedType.Name}.{stack.GetMethod().Name}\" Called in \"{Path.GetFileName(fileName)}({lineNumber})\"", "Method"); } public static LogHandler Handler(string tag) => new(tag); }