7using System.Collections.Generic;
 
    8using System.Diagnostics;
 
   11using System.Reflection;
 
   12using System.Runtime.ExceptionServices;
 
   14using System.Text.RegularExpressions;
 
   15using System.Threading;
 
   16using Terraria.Localization;
 
   17using Terraria.ModLoader.Core;
 
   18using Microsoft.Xna.Framework;
 
   19using Terraria.ModLoader.UI;
 
   25        public static readonly 
string LogDir = Path.Combine(Program.SavePath, 
"Logs");
 
   27        public static string LogPath { 
get; 
private set; }
 
   29        internal static ILog 
Terraria { 
get; } = LogManager.GetLogger(
"Terraria");
 
   30        internal static ILog tML { 
get; } = LogManager.GetLogger(
"tML");
 
   33        internal const string side = 
"client";
 
   35        internal const string side = 
"server";
 
   39        internal static void Init() {
 
   40            if (Program.LaunchParameters.ContainsKey(
"-build"))
 
   44            Utils.TryCreatingDirectory(
LogDir);
 
   48            tML.InfoFormat(
"Starting {0} {1} {2} ({3})", 
ModLoader.
versionedName, ReLogic.OS.Platform.Current.Type, side, DateTime.Now.ToString(
"d"));
 
   50            tML.InfoFormat(
"Executable: {0}", Assembly.GetEntryAssembly().Location);
 
   51            tML.InfoFormat(
"Working Directory: {0}", Path.GetFullPath(Directory.GetCurrentDirectory()));
 
   52            tML.InfoFormat(
"Launch Parameters: {0}", 
string.Join(
" ", Program.LaunchParameters.Select(p => (p.Key + 
" " + p.Value).Trim())));
 
   54            if (ModCompile.DeveloperMode)
 
   55                tML.Info(
"Developer mode enabled");
 
   60                AppDomain.CurrentDomain.UnhandledException += (s, args) => tML.Error(
"Unhandled Exception", args.ExceptionObject as 
Exception);
 
   63            AssemblyResolving.Init();
 
   65            LogArchiver.ArchiveLogs();
 
   69            var layout = 
new PatternLayout {
 
   70                ConversionPattern = 
"[%d{HH:mm:ss}] [%t/%level] [%logger]: %m%n" 
   72            layout.ActivateOptions();
 
   74            var appenders = 
new List<IAppender>();
 
   76            appenders.Add(
new ConsoleAppender {
 
   77                Name = 
"ConsoleAppender",
 
   81            appenders.Add(
new DebugAppender {
 
   82                Name = 
"DebugAppender",
 
   86            var fileAppender = 
new FileAppender {
 
   87                Name = 
"FileAppender",
 
   90                Encoding = Encoding.UTF8,
 
   93            fileAppender.ActivateOptions();
 
   94            appenders.Add(fileAppender);
 
   96            BasicConfigurator.Configure(appenders.ToArray());
 
  100            var pattern = 
new Regex($
"{baseName}(\\d*)\\.log$");
 
  101            var existingLogs = Directory.GetFiles(
LogDir).Where(s => pattern.IsMatch(Path.GetFileName(s))).ToList();
 
  103            if (!existingLogs.All(
CanOpen)) {
 
  104                int n = existingLogs.Select(s => {
 
  105                    var tok = pattern.Match(Path.GetFileName(s)).Groups[1].Value;
 
  106                    return tok.Length == 0 ? 1 : 
int.Parse(tok);
 
  108                return $
"{baseName}{n + 1}.log";
 
  111            foreach (var existingLog 
in existingLogs.OrderBy(File.GetCreationTime)) {
 
  114                while (File.Exists(existingLog + oldExt))
 
  115                    oldExt = $
".old{++n}";
 
  118                    File.Move(existingLog, existingLog + oldExt);
 
  121                    initWarnings.Add($
"Move failed during log initialization: {existingLog} -> {Path.GetFileName(existingLog)}{oldExt}\n{e}");
 
  125            return $
"{baseName}.log";
 
  128        private static bool CanOpen(
string fileName) {
 
  130                using (
new FileStream(fileName, FileMode.Append)) ;
 
  140                tML.Warn(
"First-chance exception reporting is not implemented on Mono");
 
  146        internal static void ResetPastExceptions() => 
pastExceptions.Clear();
 
  154            "System.Console.set_OutputEncoding", 
 
  155            "Terraria.ModLoader.Core.ModCompile",
 
  156            "Delegate.CreateDelegateNoSecurityCheck",
 
  157            "MethodBase.GetMethodBody",
 
  158            "Terraria.Net.Sockets.TcpSocket.Terraria.Net.Sockets.ISocket.AsyncSend", 
 
  159            "System.Diagnostics.Process.Kill", 
 
  160            "Terraria.ModLoader.Core.AssemblyManager.CecilAssemblyResolver.Resolve",
 
  161            "Terraria.ModLoader.Engine.TMLContentManager.OpenStream"  
  167            "A blocking operation was interrupted by a call to WSACancelBlockingCall", 
 
  168            "The request was aborted: The request was canceled.", 
 
  169            "Object name: 'System.Net.Sockets.Socket'.", 
 
  170            "Object name: 'System.Net.Sockets.NetworkStream'",
 
  171            "This operation cannot be performed on a completed asynchronous result object.", 
 
  172            "Object name: 'SslStream'.", 
 
  173            "Unable to load DLL 'Microsoft.DiaSymReader.Native.x86.dll'"  
  177            "at Terraria.Lighting.doColors_Mode", 
 
  178            "System.Threading.CancellationToken.Throw", 
 
  186        private static ThreadLocal<bool> 
handlerActive = 
new ThreadLocal<bool>(() => 
false);
 
  192            bool oom = args.Exception is OutOfMemoryException;
 
  203                handlerActive.Value = 
true;
 
  207                        args.Exception is ThreadAbortException ||
 
  209                        ignoreMessages.Any(str => args.Exception.Message?.Contains(str) ?? 
false) ||
 
  214                var stackTrace = 
new StackTrace(
true);
 
  216                var traceString = stackTrace.ToString();
 
  221                traceString = traceString.Substring(traceString.IndexOf(
'\n'));
 
  222                var exString = args.Exception.GetType() + 
": " + args.Exception.Message + traceString;
 
  229                var msg = args.Exception.Message + 
" " + Language.GetTextValue(
"tModLoader.RuntimeErrorSeeLogsForFullTrace", Path.GetFileName(
LogPath));
 
  231                if (ModCompile.activelyModding)
 
  234                Console.ForegroundColor = ConsoleColor.DarkMagenta;
 
  238                tML.Warn(Language.GetTextValue(
"tModLoader.RuntimeErrorSilentlyCaughtException") + 
'\n' + exString);
 
  241                    string error = Language.GetTextValue(
"tModLoader.OutOfMemory");
 
  243                    Interface.MessageBoxShow(error);
 
  248                tML.Warn(
"FirstChanceExceptionHandler exception", e);
 
  251                handlerActive.Value = 
false;
 
  260            float soundVolume = Main.soundVolume;
 
  261            Main.soundVolume = 0f;
 
  262            Main.NewText(msg, color);
 
  263            Main.soundVolume = soundVolume;
 
  267        internal static void LogStatusChange(
string oldStatusText, 
string newStatusText) {
 
  269            var oldBase = 
statusRegex.Match(oldStatusText).Groups[1].Value;
 
  270            var newBase = 
statusRegex.Match(newStatusText).Groups[1].Value;
 
  271            if (newBase != oldBase && newBase.Length > 0)
 
  272                LogManager.GetLogger(
"StatusText").Info(newBase);
 
  275        internal static void ServerConsoleLine(
string msg) => ServerConsoleLine(msg, Level.Info);
 
  276        internal static void ServerConsoleLine(
string msg, Level level, 
Exception ex = 
null, ILog log = 
null) {
 
  277            if (level == Level.Warn)
 
  278                Console.ForegroundColor = ConsoleColor.Yellow;
 
  279            else if (level == Level.Error)
 
  280                Console.ForegroundColor = ConsoleColor.Red;
 
  285            (log ?? 
Terraria).Logger.Log(
null, level, msg, ex);
 
  288        internal static readonly FieldInfo f_fileName =
 
  289            typeof(StackFrame).GetField(
"strFileName", BindingFlags.Instance | BindingFlags.NonPublic) ??
 
  290            typeof(StackFrame).GetField(
"fileName", BindingFlags.Instance | BindingFlags.NonPublic);
 
  298            foreach (var frame 
in frames) {
 
  299                string filename = frame.GetFileName();
 
  300                var assembly = frame.GetMethod()?.DeclaringType?.Assembly;
 
  301                if (filename == 
null || assembly == 
null)
 
  305                if (AssemblyManager.GetAssemblyOwner(assembly, out var modName))
 
  312                int idx = filename.LastIndexOf(trim, StringComparison.InvariantCultureIgnoreCase);
 
  314                    filename = filename.Substring(idx);
 
  315                    f_fileName.SetValue(frame, filename);
 
  322                Type.GetType(
"System.AppContextSwitches").GetField(
"_ignorePortablePDBsInStackTraces", BindingFlags.Static | BindingFlags.NonPublic).SetValue(
null, -1);
 
static readonly Version Version
 
static readonly Framework Framework
 
static List< string > ignoreMessages
 
static HashSet< string > ignoreSources
 
static List< string > initWarnings
 
static void PrettifyStackTraceSources(StackFrame[] frames)
 
static List< string > ignoreContents
 
static HashSet< string > pastExceptions
 
static void FirstChanceExceptionHandler(object sender, FirstChanceExceptionEventArgs args)
 
static void ConfigureAppenders()
 
static void LogFirstChanceExceptions()
 
static readonly string LogArchiveDir
 
static void IgnoreExceptionContents(string source)
 
static readonly Assembly TerrariaAssembly
 
static string GetNewLogFile(string baseName)
 
static List< string > ignoreThrowingMethods
 
static ThreadLocal< bool > handlerActive
 
static void EnablePortablePDBTraces()
 
static Exception previousException
 
static void IgnoreExceptionSource(string source)
 
static bool CanOpen(string fileName)
 
static readonly string LogDir
 
static void AddChatMessage(string msg, Color color)
 
This serves as the central class which loads mods. It contains many static fields and methods related...
 
static readonly string versionedName
 
@ Environment
Sandstorm, Hell, Above surface during Eclipse, Space
 
@ Console
Command can be used in server console during MP.