void OutputThread()
        {
            try
            {
                var list = new OutputEntry [ProgramLog.LOG_THREAD_BATCH_SIZE];

                while (exit == false || EntryCount() > 0)
                {
                    int items = 0;

                    lock (entries)
                    {
                        while (entries.Count > 0)
                        {
                            list[items++] = entries.Dequeue ();
                            if (items == ProgramLog.LOG_THREAD_BATCH_SIZE) break;
                        }
                    }

                    if (items == 0)
                    {
                        if (exit)
                            break;
                        else
                            signal.WaitForIt ();
                    }

                    for (int i = 0; i < items; i++)
                    {
                        var entry = list[i];
                        list[i] = default(OutputEntry);

                        if (entry.prefix != null)
                        {
                            file.Write (entry.prefix);
                        }

                        if (entry.message is string)
                        {
                            var str = (string) entry.message;
                            file.WriteLine (str);
                            file.Flush ();
                        }
                        else if (entry.message is ProgressLogger)
                        {
                            var prog = (ProgressLogger) entry.message;
                            var str = "";

                            if (entry.arg == -1) // new one
                            {
                                str = String.Format ("{0}: started.", prog.Message);
                            }
                            else if (entry.arg == -2) // finished one
                            {
                                str = prog.Format (true);
                            }
                            else // update
                            {
                                str = prog.Format (prog.Max != 100, entry.arg);
                            }

                            file.WriteLine (str);
                            file.Flush ();
                        }
                    }
                }
            }
            catch (Exception e)
            {
                Console.Error.WriteLine (e.ToString());
            }

            try
            {
                file.Close ();
            }
            catch {}
        }
 public void Send(OutputEntry entry)
 {
     lock (entries)
     {
         entries.Enqueue (entry);
     }
     signal.Signal ();
 }
        protected virtual void OutputThread()
        {
            try
            {
                var list = new OutputEntry [ProgramLog.LOG_THREAD_BATCH_SIZE];
                var progs = new List<ProgressLogger> ();
                var backspace = 0;

                while (exit == false || EntryCount() > 0)
                {
                    int items = 0;

                    lock (entries)
                    {
                        while (entries.Count > 0)
                        {
                            list[items++] = entries.Dequeue ();
                            if (items == ProgramLog.LOG_THREAD_BATCH_SIZE) break;
                        }
                    }

                    if (items == 0)
                    {
                        if (exit)
                            break;
                        else if (progs.Count == 0)
                            signal.WaitForIt ();
                    }

                    if (backspace > 0)
                    {
                        writer.Write ("\r");
                    }

                    for (int i = 0; i < items; i++)
                    {
                        var entry = list[i];
                        list[i] = default(OutputEntry);

                        if (entry.prefix != null)
                        {
                            SetColor (ConsoleColor.DarkGray);
                            writer.Write (entry.prefix);
                            backspace -= entry.prefix.Length;
                        }

                        if (entry.color != null)
                            SetColor ((ConsoleColor) entry.color);
                        else
                            SetColor (ConsoleColor.Gray);

                        if (entry.message is string)
                        {
                            var str = (string) entry.message;
                            writer.WriteLine(str);
                            HandleConsoleHook(str, entry.logger);
                            backspace -= str.Length;
                        }
                        else if (entry.message is ProgressLogger)
                        {
                            var prog = (ProgressLogger) entry.message;
                            var str = "";

                            if (entry.arg == -1) // new one
                            {
                                progs.Add (prog);
                                str = String.Format ("{0}: started.", prog.Message);
                            }
                            else if (entry.arg == -2) // finished one
                            {
                                progs.Remove (prog);
                                str = prog.Format (true);
                            }
                            else // update
                            {
                                str = prog.Format (prog.Max != 100, entry.arg);
                            }

                            backspace -= str.Length;
                            if (backspace <= 0)
                            {
                                writer.WriteLine(str);
                                HandleConsoleHook(str, entry.logger);
                            }
                            else
                            {
                                writer.Write(str);
                                for (int j = 0; j < backspace; j++)
                                    writer.Write(" ");
                            }
                        }

                        ResetColor ();
                    }

                    backspace = 0;
                    foreach (var prog in progs)
                    {
                        var str = String.Format ("[ {0} ] ", prog.Format());
                        backspace += str.Length;
                        writer.Write (str);
                    }

                    if (progs.Count > 0)
                        SignalIncompleteLine ();

                    if (backspace > 0 && EntryCount() == 0)
                    {
                        signal.WaitForIt (100);
                    }
                }
            }
            catch (Exception e)
            {
                if (! passExceptions)
                    Console.Error.WriteLine (e.ToString());
                else
                    throw;
            }
        }
 static void Send(LogTarget target, OutputEntry output)
 {
     if (target == null)
     {
         lock (logTargets)
             foreach (var tar in logTargets)
             {
                 tar.Send(output);
             }
     }
     else
         target.Send(output);
 }
        static void LogDispatchThread()
        {
            try
            {
                var list = new LogEntry[LOG_THREAD_BATCH_SIZE];
                var progs = new List<ProgressLogger>();
                var last = default(OutputEntry);
                var run = 0;

                while (exit == false || EntryCount() > 0)
                {
                    int items = 0;

                    lock (entries)
                    {
                        while (entries.Count > 0)
                        {
                            list[items++] = entries.Dequeue();
                            if (items == LOG_THREAD_BATCH_SIZE) break;
                        }
                    }

                    if (items == 0)
                    {
                        if (exit)
                            break;
                        else
                            logSignal.WaitForIt();
                    }

                    for (int i = 0; i < items; i++)
                    {
                        var entry = list[i];
                        list[i] = default(LogEntry);
                        OutputEntry output;

                        Build(entry, out output);

                        if (entry.message is ProgressLogger)
                        {
                            var prog = (ProgressLogger)entry.message;

                            if (progs.Remove(prog))
                            {
                                // it's done
                                output.arg = -2;
                            }
                            else
                            {
                                // new one
                                progs.Add(prog);
                                output.arg = -1;
                            }
                        }
                        else
                        {
                            // force updates of progress loggers in the same thread
                            foreach (var prog in progs)
                            {
                                if (prog.Thread == entry.thread)
                                {
                                    var upd = new OutputEntry { prefix = output.prefix, message = prog, arg = prog.Value };
                                    Send(entry.target, upd);
                                    last = upd;
                                    run = 0;
                                }
                            }
                        }

                        if (output.message.Equals(last.message) && output.prefix == last.prefix && output.arg == last.arg)
                        {
                            run += 1;
                            //System.ProgramLog.Log (run);
                        }
                        else if (run > 0)
                        {
                            //System.ProgramLog.Log ("sending");
                            last.message = String.Format("Log message repeated {0} times", run);
                            Send(entry.target, last);
                            last = output;
                            run = 0;
                            Send(entry.target, output);
                        }
                        else
                        {
                            last = output;
                            Send(entry.target, output);
                        }
                    }
                }
            }
            catch (Exception e)
            {
                System.Console.WriteLine(e.ToString());
            }

            lock (logTargets)
                foreach (var tar in logTargets)
                {
                    tar.Close();
                }

            //Statics.IsActive = false;
            Terraria.Netplay.disconnect = true;
        }
        //static int nextPoolIndex = 0;
        static void Build(LogEntry entry, out OutputEntry output)
        {
            Exception error = null;
            output = default(OutputEntry);

            if (entry.channel != null)
                output.color = entry.channel.Color;
            else if (entry.color != null)
                output.color = entry.color.Value;

            output.logger = entry.logger;

            try
            {
                if (entry.message is string)
                {
                    var text = (string)entry.message;

                    if (entry.args != null)
                    {
                        var args = (object[])entry.args;
                        try
                        {
                            text = String.Format(text, args);
                        }
                        catch (Exception)
                        {
                            text = String.Format("<Incorrect log message format string or argument list: message=\"{0}\", args=({1})>",
                                text, String.Join(", ", args));
                        }
                    }

                    output.message = text;
                }
                else if (entry.message is Exception)
                {
                    var e = (Exception)entry.message;

                    if (entry.args is string)
                        output.message = String.Format("{0}:{1}{2}", entry.args, Environment.NewLine, e.ToString());
                    else
                        output.message = e.ToString();
                }
                else
                    output.message = entry.message;

                var thread = "?";
                if (entry.thread != null)
                {
                    if (entry.thread.IsThreadPoolThread)
                    {
                        thread = "Pool";
                        //						string name;
                        //						if (poolNames.TryGetValue (entry.thread, out name))
                        //						{
                        //							thread = name;
                        //						}
                        //						else
                        //						{
                        //							thread = String.Format ("P{0:000}", nextPoolIndex++);
                        //							poolNames[entry.thread] = thread;
                        //						}
                    }
                    else if (entry.thread.Name != null)
                        thread = entry.thread.Name;
                }

                if (entry.thread != null && entry.time != default(DateTime))
                    output.prefix = String.Format("{0} {1}> ", entry.time, thread);
            }
            catch (Exception e)
            {
                error = e;
            }

            if (error != null)
            {
                try
                {
                    System.Console.WriteLine("Error writing log entry:");
                    System.Console.WriteLine(error.ToString());
                }
                catch (Exception) { }
            }
        }