using System; using Barotrauma.Networking; using Microsoft.Xna.Framework; using MoonSharp.Interpreter; namespace Barotrauma { internal enum LuaCsMessageOrigin { LuaCs, Unknown, LuaMod, CSharpMod, } class LuaCsLogger { #if SERVER private const string LogPrefix = "SV"; private const int NetMaxLength = 1024; private const int NetMaxMessages = 60; #else private const string LogPrefix = "CL"; #endif public static LuaCsMessageLogger MessageLogger; public static LuaCsExceptionHandler ExceptionHandler; public static void HandleException(Exception ex, LuaCsMessageOrigin origin) { switch (ex) { case NetRuntimeException netRuntimeException: if (netRuntimeException.DecoratedMessage == null) { LogError(netRuntimeException.ToString(), origin); } else { // FIXME: netRuntimeException.ToString() doesn't print the InnerException's stack trace... LogError($"{netRuntimeException.DecoratedMessage}: {netRuntimeException}", origin); } break; case InterpreterException interpreterException: if (interpreterException.DecoratedMessage == null) { LogError(interpreterException.ToString(), origin); } else { LogError(interpreterException.DecoratedMessage, origin); } break; default: var msg = ex.StackTrace != null ? ex.ToString() : $"{ex}\n{Environment.StackTrace}"; LogError(msg, origin); break; } } public static void LogError(string message, LuaCsMessageOrigin origin) { switch (origin) { case LuaCsMessageOrigin.LuaCs: case LuaCsMessageOrigin.Unknown: LogError($"[{LogPrefix} ERROR] {message}"); break; case LuaCsMessageOrigin.LuaMod: LogError($"[{LogPrefix} LUA ERROR] {message}"); break; case LuaCsMessageOrigin.CSharpMod: LogError($"[{LogPrefix} CS ERROR] {message}"); break; } } public static void LogError(string message) { Log($"{message}", Color.Red, ServerLog.MessageType.Error); } public static void LogMessage(string message, Color? serverColor = null, Color? clientColor = null) { if (serverColor == null) { serverColor = Color.MediumPurple; } if (clientColor == null) { clientColor = Color.Purple; } #if SERVER Log(message, serverColor); #else Log(message, clientColor); #endif } // This is used so its possible to call logging functions inside the serverLog // hook without creating an infinite loop private static bool lockLog = false; public static void Log(string message, Color? color = null, ServerLog.MessageType messageType = ServerLog.MessageType.ServerMessage) { MessageLogger?.Invoke(message); DebugConsole.NewMessage(message, color); #if SERVER void broadcastMessage(string m) { foreach (var client in GameMain.Server.ConnectedClients) { //if (client.ChatMsgQueue.Count > NetMaxMessages) //{ // If there's an error or message happening many times per second (inside Update loop for example) // we will need to discart some messages so the client doesn't get overloaded by all // those net messages. // continue; //} ChatMessage consoleMessage = ChatMessage.Create("", m, ChatMessageType.Console, null, textColor: color); GameMain.Server.SendDirectChatMessage(consoleMessage, client); if (!GameMain.Server.ServerSettings.SaveServerLogs || !client.HasPermission(ClientPermissions.ServerLog)) { continue; } ChatMessage logMessage = ChatMessage.Create(messageType.ToString(), "[LuaCs] " + m, ChatMessageType.ServerLog, null); GameMain.Server.SendDirectChatMessage(logMessage, client); } } if (GameMain.Server != null) { if (GameMain.Server.ServerSettings.SaveServerLogs) { string logMessage = "[LuaCs] " + message; GameMain.Server.ServerSettings.ServerLog.WriteLine(logMessage, messageType, false); if (!lockLog) { lockLog = true; GameMain.LuaCs?.Hook?.Call("serverLog", logMessage, messageType); lockLog = false; } } for (int i = 0; i < message.Length; i += NetMaxLength) { string subStr = message.Substring(i, Math.Min(1024, message.Length - i)); broadcastMessage(subStr); } } #endif } } partial class LuaCsSetup { // Compatibility with cs mods that use this method. public void PrintLuaError(string message) => LuaCsLogger.LogError(message, LuaCsMessageOrigin.LuaMod); public void PrintCsError(string message) => LuaCsLogger.LogError(message, LuaCsMessageOrigin.CSharpMod); public void PrintGenericError(string message) => LuaCsLogger.LogError(message, LuaCsMessageOrigin.LuaCs); internal void PrintMessage(string message) => LuaCsLogger.LogMessage(message); public static void PrintCsMessage(string message) => LuaCsLogger.LogMessage(message); internal void HandleException(Exception ex, LuaCsMessageOrigin origin) => LuaCsLogger.HandleException(ex, origin); } }