Decompiled source of ValheimConsoleCapture v1.0.0

ValheimConsoleCapture.dll

Decompiled a week ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("ValheimConsoleCapture")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+3c0ba889c8abd636a53a4096f301836f6c3c1582")]
[assembly: AssemblyProduct("ValheimConsoleCapture")]
[assembly: AssemblyTitle("ValheimConsoleCapture")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace ValheimConsoleCapture
{
	internal static class ConsoleCommands
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static ConsoleEvent <0>__Copy;

			public static ConsoleEvent <1>__Dump;

			public static ConsoleEvent <2>__DumpCommand;

			public static ConsoleEvent <3>__Clear;

			public static ConsoleEvent <4>__Capture;

			public static ConsoleOptionsFetcher <5>__Options;
		}

		private const char ChainSeparator = '\u001e';

		internal static void ProtectChain(ref string text)
		{
			if (string.IsNullOrEmpty(text))
			{
				return;
			}
			int i;
			for (i = 0; i < text.Length && char.IsWhiteSpace(text[i]); i++)
			{
			}
			if (text.Length - i < "dumpcommand".Length || !string.Equals(text.Substring(i, "dumpcommand".Length), "dumpcommand", StringComparison.OrdinalIgnoreCase))
			{
				return;
			}
			int num = i + "dumpcommand".Length;
			if (num < text.Length && !char.IsWhiteSpace(text[num]))
			{
				return;
			}
			int num2 = text.IndexOf('"', num);
			int num3 = text.LastIndexOf('"');
			if (num2 < 0 || num3 <= num2)
			{
				return;
			}
			char[] array = text.ToCharArray();
			for (int j = num2 + 1; j < num3; j++)
			{
				if (array[j] == ';')
				{
					array[j] = '\u001e';
				}
			}
			text = new string(array);
		}

		internal static void Register()
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Expected O, but got Unknown
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Expected O, but got Unknown
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Expected O, but got Unknown
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Expected O, but got Unknown
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Expected O, but got Unknown
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Expected O, but got Unknown
			object obj = <>O.<0>__Copy;
			if (obj == null)
			{
				ConsoleEvent val = Copy;
				<>O.<0>__Copy = val;
				obj = (object)val;
			}
			new ConsoleCommand("copyconsole", "Copy buffered F5 lines to the clipboard. Optional count: copyconsole 50", (ConsoleEvent)obj, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
			object obj2 = <>O.<1>__Dump;
			if (obj2 == null)
			{
				ConsoleEvent val2 = Dump;
				<>O.<1>__Dump = val2;
				obj2 = (object)val2;
			}
			new ConsoleCommand("dumpconsole", "Write buffered F5 lines to BepInEx/ConsoleCaptures. Optional count: dumpconsole 100", (ConsoleEvent)obj2, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
			object obj3 = <>O.<2>__DumpCommand;
			if (obj3 == null)
			{
				ConsoleEvent val3 = DumpCommand;
				<>O.<2>__DumpCommand = val3;
				obj3 = (object)val3;
			}
			new ConsoleCommand("dumpcommand", "Run one or more console commands and dump only their output. dumpcommand altbioms    dumpcommand \"pos; seed\"", (ConsoleEvent)obj3, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
			object obj4 = <>O.<3>__Clear;
			if (obj4 == null)
			{
				ConsoleEvent val4 = Clear;
				<>O.<3>__Clear = val4;
				obj4 = (object)val4;
			}
			new ConsoleCommand("clearconsolebuffer", "Clear the in-memory console capture buffer. Does not clear the F5 console or delete the log.", (ConsoleEvent)obj4, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
			object obj5 = <>O.<4>__Capture;
			if (obj5 == null)
			{
				ConsoleEvent val5 = Capture;
				<>O.<4>__Capture = val5;
				obj5 = (object)val5;
			}
			object obj6 = <>O.<5>__Options;
			if (obj6 == null)
			{
				ConsoleOptionsFetcher val6 = Options;
				<>O.<5>__Options = val6;
				obj6 = (object)val6;
			}
			new ConsoleCommand("consolecapture", "Show capture status, or toggle it: consolecapture on / consolecapture off", (ConsoleEvent)obj5, false, false, false, false, false, false, (ConsoleOptionsFetcher)obj6, true, false, false);
		}

		private static List<string> Options()
		{
			return new List<string> { "on", "off" };
		}

		private static void Copy(ConsoleEventArgs args)
		{
			if (!TryParseCount(Rest(args), "copyconsole", out var count, out var error))
			{
				Reply(args, error);
				return;
			}
			ConsoleCapture.TryCopy(count, out var message);
			Reply(args, message);
		}

		private static void Dump(ConsoleEventArgs args)
		{
			if (!TryParseCount(Rest(args), "dumpconsole", out var count, out var error))
			{
				Reply(args, error);
				return;
			}
			ConsoleCapture.TryDump(count, out var message);
			Reply(args, message);
		}

		private static void DumpCommand(ConsoleEventArgs args)
		{
			string[] array = SplitChain(CommandText(args));
			if (array.Length == 0)
			{
				Reply(args, "Usage: dumpcommand <command>    or    dumpcommand \"command; command\"");
				return;
			}
			for (int i = 0; i < array.Length; i++)
			{
				string a = array[i].Split(' ')[0];
				if (string.Equals(a, "dumpcommand", StringComparison.OrdinalIgnoreCase))
				{
					Reply(args, "dumpcommand cannot run itself.");
					return;
				}
			}
			if (ConsoleCapture.IsScoping())
			{
				Reply(args, "dumpcommand is already running.");
				return;
			}
			Terminal val = args?.Context;
			if ((Object)(object)val == (Object)null)
			{
				val = (Terminal)(object)Console.instance;
			}
			if ((Object)(object)val == (Object)null)
			{
				Reply(args, "Console is not available.");
				return;
			}
			ConsoleCapture.BeginScope();
			string text = null;
			try
			{
				for (int j = 0; j < array.Length; j++)
				{
					val.TryRunCommand(ShieldSegment(array[j]), false, false);
				}
			}
			catch (Exception ex)
			{
				text = ((array.Length == 1) ? array[0] : "the command chain");
				if (ValheimConsoleCapturePlugin.ModLogger != null)
				{
					ValheimConsoleCapturePlugin.ModLogger.LogError((object)("dumpcommand failed: " + ex.Message));
				}
			}
			string[] array2 = ConsoleCapture.EndScope();
			if (array2.Length == 0)
			{
				Reply(args, (text != null) ? ("Failed to run " + text + ".") : "The command produced no console lines.");
				return;
			}
			ConsoleCapture.TryWriteDump(array2, ChainHint(array), out var message);
			Reply(args, message);
			if (text != null)
			{
				Reply(args, "Failed to run " + text + ".");
			}
		}

		internal static string ShieldSegment(string command)
		{
			if (string.IsNullOrEmpty(command) || command.IndexOf(';') < 0)
			{
				return command;
			}
			return command.Replace(';', '\u001e');
		}

		internal static void RestoreChain(ConsoleEventArgs args)
		{
			if (args == null)
			{
				return;
			}
			args.FullLine = Restore(args.FullLine);
			args.ArgsAll = Restore(args.ArgsAll);
			if (args.Args != null)
			{
				for (int i = 0; i < args.Args.Length; i++)
				{
					args.Args[i] = Restore(args.Args[i]);
				}
			}
		}

		private static string Restore(string text)
		{
			if (string.IsNullOrEmpty(text) || text.IndexOf('\u001e') < 0)
			{
				return text;
			}
			return text.Replace('\u001e', ';');
		}

		private static string CommandText(ConsoleEventArgs args)
		{
			string text = ((args == null || args.ArgsAll == null) ? "" : args.ArgsAll.Trim());
			if (text.IndexOf('\u001e') >= 0)
			{
				text = text.Replace('\u001e', ';');
			}
			if (text.Length >= 2 && text[0] == '"' && text[text.Length - 1] == '"')
			{
				text = text.Substring(1, text.Length - 2).Trim();
			}
			return text;
		}

		private static string[] SplitChain(string text)
		{
			if (string.IsNullOrWhiteSpace(text))
			{
				return Array.Empty<string>();
			}
			List<string> list = new List<string>();
			StringBuilder stringBuilder = new StringBuilder();
			bool flag = false;
			foreach (char c in text)
			{
				switch (c)
				{
				case '"':
					flag = !flag;
					stringBuilder.Append(c);
					continue;
				case ';':
					if (!flag)
					{
						string text2 = stringBuilder.ToString().Trim();
						if (text2.Length > 0)
						{
							list.Add(text2);
						}
						stringBuilder.Length = 0;
						continue;
					}
					break;
				}
				stringBuilder.Append(c);
			}
			string text3 = stringBuilder.ToString().Trim();
			if (text3.Length > 0)
			{
				list.Add(text3);
			}
			return list.ToArray();
		}

		private static string ChainHint(string[] commands)
		{
			StringBuilder stringBuilder = new StringBuilder();
			for (int i = 0; i < commands.Length; i++)
			{
				string text = commands[i].Split(' ')[0];
				StringBuilder stringBuilder2 = new StringBuilder();
				for (int j = 0; j < text.Length; j++)
				{
					if (stringBuilder2.Length >= 20)
					{
						break;
					}
					char c = text[j];
					if (char.IsLetterOrDigit(c))
					{
						stringBuilder2.Append(char.ToLowerInvariant(c));
					}
				}
				if (stringBuilder2.Length == 0)
				{
					continue;
				}
				if (stringBuilder.Length > 0)
				{
					if (stringBuilder.Length + 1 + stringBuilder2.Length > 40)
					{
						break;
					}
					stringBuilder.Append('-');
				}
				stringBuilder.Append(stringBuilder2);
			}
			return stringBuilder.ToString();
		}

		private static void Clear(ConsoleEventArgs args)
		{
			Reply(args, ConsoleCapture.ClearBuffer());
		}

		private static void Capture(ConsoleEventArgs args)
		{
			string[] array = Rest(args);
			if (array.Length > 1)
			{
				Reply(args, "Usage: consolecapture [on|off]");
				return;
			}
			if (array.Length == 1)
			{
				if (string.Equals(array[0], "on", StringComparison.OrdinalIgnoreCase))
				{
					ConsoleCapture.SetCaptureEnabled(enabled: true);
				}
				else
				{
					if (!string.Equals(array[0], "off", StringComparison.OrdinalIgnoreCase))
					{
						Reply(args, "Usage: consolecapture [on|off]");
						return;
					}
					ConsoleCapture.SetCaptureEnabled(enabled: false);
				}
			}
			string[] array2 = ConsoleCapture.StatusLines();
			for (int i = 0; i < array2.Length; i++)
			{
				Reply(args, array2[i]);
			}
		}

		private static string[] Rest(ConsoleEventArgs args)
		{
			if (args == null || args.Args == null || args.Args.Length <= 1)
			{
				return Array.Empty<string>();
			}
			string[] array = new string[args.Args.Length - 1];
			Array.Copy(args.Args, 1, array, 0, array.Length);
			return array;
		}

		private static bool TryParseCount(string[] args, string command, out int? count, out string error)
		{
			count = null;
			error = null;
			if (args == null || args.Length == 0)
			{
				return true;
			}
			if (args.Length == 1 && int.TryParse(args[0], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result) && result >= 1)
			{
				count = result;
				return true;
			}
			error = "Usage: " + command + " [count]";
			return false;
		}

		private static void Reply(ConsoleEventArgs args, string message)
		{
			Terminal val = args?.Context;
			if ((Object)(object)val != (Object)null)
			{
				val.AddString(message);
				return;
			}
			Console instance = Console.instance;
			if ((Object)(object)instance != (Object)null)
			{
				((Terminal)instance).AddString(message);
			}
			else if (ValheimConsoleCapturePlugin.ModLogger != null)
			{
				ValheimConsoleCapturePlugin.ModLogger.LogInfo((object)message);
			}
		}
	}
	internal static class ConsoleCapture
	{
		private static readonly Regex RichTextTags = new Regex("</?(?:b|i|u|s|color|size|material|quad|sprite|link|mark|noparse)(?:\\s[^>]*|=[^>]*)?>", RegexOptions.IgnoreCase | RegexOptions.Compiled);

		private static readonly object Gate = new object();

		private static readonly Queue<string> Lines = new Queue<string>();

		private static StreamWriter _writer;

		private static bool _runtimeEnabled;

		private static bool _expectCommandEcho;

		private static bool _shutdown;

		private static bool _inRecord;

		private static bool _fileFault;

		private static bool _loggedFault;

		private static string _lastAutocomplete;

		private static List<string> _scope;

		internal static void Start()
		{
			_shutdown = false;
			_runtimeEnabled = ValheimConsoleCapturePlugin.Enabled == null || ValheimConsoleCapturePlugin.Enabled.Value;
			if (_runtimeEnabled)
			{
				lock (Gate)
				{
					EnsureWriter();
				}
			}
		}

		internal static void Shutdown()
		{
			lock (Gate)
			{
				_shutdown = true;
				_runtimeEnabled = false;
				CloseWriter();
			}
		}

		internal static void SetCaptureEnabled(bool enabled)
		{
			lock (Gate)
			{
				_runtimeEnabled = enabled;
				if (!enabled)
				{
					_lastAutocomplete = null;
				}
				else
				{
					EnsureWriter();
				}
			}
		}

		internal static void ExpectCommandEcho()
		{
			_expectCommandEcho = true;
		}

		internal static void EndCommandEcho()
		{
			_expectCommandEcho = false;
		}

		internal static bool IsScoping()
		{
			lock (Gate)
			{
				return _scope != null;
			}
		}

		internal static void BeginScope()
		{
			lock (Gate)
			{
				_scope = new List<string>();
			}
		}

		internal static string[] EndScope()
		{
			lock (Gate)
			{
				string[] result = ((_scope == null) ? Array.Empty<string>() : _scope.ToArray());
				_scope = null;
				return result;
			}
		}

		internal static void OnTerminalLine(string text)
		{
			bool expectCommandEcho = _expectCommandEcho;
			_expectCommandEcho = false;
			if (text == null)
			{
				return;
			}
			bool flag = IsScoping();
			bool flag2 = _runtimeEnabled;
			if (flag2)
			{
				if (expectCommandEcho)
				{
					if (ValheimConsoleCapturePlugin.CaptureCommands != null && !ValheimConsoleCapturePlugin.CaptureCommands.Value)
					{
						flag2 = false;
					}
				}
				else if (ValheimConsoleCapturePlugin.CaptureOutput != null && !ValheimConsoleCapturePlugin.CaptureOutput.Value)
				{
					flag2 = false;
				}
			}
			if (!flag2 && !flag)
			{
				return;
			}
			foreach (string item in SplitLines(text))
			{
				string line = ApplyRichText(item);
				if (flag2)
				{
					Record(line);
				}
				else
				{
					RememberScope(line);
				}
			}
		}

		internal static void OnAutocomplete(string text)
		{
			if (!_runtimeEnabled || ValheimConsoleCapturePlugin.CaptureAutocomplete == null || !ValheimConsoleCapturePlugin.CaptureAutocomplete.Value)
			{
				return;
			}
			if (string.IsNullOrEmpty(text))
			{
				_lastAutocomplete = null;
				return;
			}
			string text2 = ApplyRichText(text);
			if (text2.Length != 0 && !(text2 == _lastAutocomplete))
			{
				_lastAutocomplete = text2;
				Record(text2);
			}
		}

		internal static string[] StatusLines()
		{
			int count;
			int num;
			string text;
			lock (Gate)
			{
				count = Lines.Count;
				num = MaxLines();
				text = FileStatus();
			}
			return new string[3]
			{
				"Console capture: " + (_runtimeEnabled ? "Enabled" : "Disabled"),
				"File logging: " + text,
				"Buffered lines: " + count.ToString(CultureInfo.InvariantCulture) + " / " + num.ToString(CultureInfo.InvariantCulture)
			};
		}

		internal static bool TryCopy(int? count, out string message)
		{
			if (ValheimConsoleCapturePlugin.EnableClipboard != null && !ValheimConsoleCapturePlugin.EnableClipboard.Value)
			{
				message = "Clipboard copying is disabled in config.";
				return false;
			}
			string[] array = CopyRecent(count);
			if (array.Length == 0)
			{
				message = "Console buffer is empty.";
				return false;
			}
			try
			{
				GUIUtility.systemCopyBuffer = string.Join(Environment.NewLine, array);
			}
			catch (Exception ex)
			{
				if (ValheimConsoleCapturePlugin.ModLogger != null)
				{
					ValheimConsoleCapturePlugin.ModLogger.LogError((object)("Clipboard copy failed: " + ex.Message));
				}
				message = "Failed to copy console lines to the clipboard.";
				return false;
			}
			message = ((array.Length == 1) ? "Copied 1 console line to clipboard." : ("Copied " + array.Length.ToString(CultureInfo.InvariantCulture) + " console lines to clipboard."));
			return true;
		}

		internal static bool TryDump(int? count, out string message)
		{
			string[] array = CopyRecent(count);
			if (array.Length == 0)
			{
				message = "Console buffer is empty.";
				return false;
			}
			return TryWriteDump(array, null, out message);
		}

		internal static bool TryWriteDump(string[] lines, string nameHint, out string message)
		{
			if (lines == null || lines.Length == 0)
			{
				message = "Nothing to dump.";
				return false;
			}
			try
			{
				string text = ResolveUnderGame(Path.Combine("BepInEx", "ConsoleCaptures"));
				Directory.CreateDirectory(text);
				string text2 = DateTime.Now.ToString("yyyy-MM-dd-HHmmss", CultureInfo.InvariantCulture);
				string text3 = SanitizeFileHint(nameHint);
				string text4 = (string.IsNullOrEmpty(text3) ? ("console-" + text2) : ("console-" + text3 + "-" + text2));
				string text5 = Path.Combine(text, text4 + ".txt");
				int num = 2;
				while (File.Exists(text5))
				{
					text5 = Path.Combine(text, text4 + "-" + num.ToString(CultureInfo.InvariantCulture) + ".txt");
					num++;
				}
				File.WriteAllText(text5, string.Join(Environment.NewLine, lines) + Environment.NewLine, new UTF8Encoding(encoderShouldEmitUTF8Identifier: false));
				string text6 = lines.Length.ToString(CultureInfo.InvariantCulture);
				message = "Dumped " + text6 + " console " + ((lines.Length == 1) ? "line" : "lines") + " to " + DisplayPath(text5) + ".";
				return true;
			}
			catch (Exception ex)
			{
				if (ValheimConsoleCapturePlugin.ModLogger != null)
				{
					ValheimConsoleCapturePlugin.ModLogger.LogError((object)("Console dump failed: " + ex.Message));
				}
				message = "Failed to write the console dump.";
				return false;
			}
		}

		internal static string ClearBuffer()
		{
			lock (Gate)
			{
				Lines.Clear();
				_lastAutocomplete = null;
			}
			return "Console buffer cleared.";
		}

		private static void Record(string line)
		{
			if (_inRecord)
			{
				return;
			}
			_inRecord = true;
			try
			{
				lock (Gate)
				{
					if (_scope != null)
					{
						_scope.Add(line ?? "");
					}
					if (_runtimeEnabled && !_shutdown)
					{
						Lines.Enqueue(line ?? "");
						Trim();
						WriteLine(line ?? "");
					}
				}
			}
			finally
			{
				_inRecord = false;
			}
		}

		private static void RememberScope(string line)
		{
			lock (Gate)
			{
				if (_scope != null)
				{
					_scope.Add(line ?? "");
				}
			}
		}

		private static string SanitizeFileHint(string nameHint)
		{
			if (string.IsNullOrWhiteSpace(nameHint))
			{
				return "";
			}
			string text = nameHint.Trim().Split(' ')[0];
			StringBuilder stringBuilder = new StringBuilder();
			for (int i = 0; i < text.Length; i++)
			{
				if (stringBuilder.Length >= 40)
				{
					break;
				}
				char c = text[i];
				if (char.IsLetterOrDigit(c) || c == '-' || c == '_')
				{
					stringBuilder.Append(char.ToLowerInvariant(c));
				}
			}
			return stringBuilder.ToString();
		}

		private static void Trim()
		{
			int num = MaxLines();
			while (Lines.Count > num)
			{
				Lines.Dequeue();
			}
		}

		private static int MaxLines()
		{
			if (ValheimConsoleCapturePlugin.BufferedLines == null)
			{
				return 1000;
			}
			int value = ValheimConsoleCapturePlugin.BufferedLines.Value;
			if (value >= 1)
			{
				return value;
			}
			return 1;
		}

		private static string[] CopyRecent(int? count)
		{
			lock (Gate)
			{
				Trim();
				string[] array = Lines.ToArray();
				if (array.Length == 0)
				{
					return Array.Empty<string>();
				}
				int num = array.Length;
				if (count.HasValue && count.Value < num)
				{
					num = count.Value;
				}
				if (num == array.Length)
				{
					return array;
				}
				string[] array2 = new string[num];
				Array.Copy(array, array.Length - num, array2, 0, num);
				return array2;
			}
		}

		private static void EnsureWriter()
		{
			if (_shutdown || _writer != null || ValheimConsoleCapturePlugin.LogToFile == null || !ValheimConsoleCapturePlugin.LogToFile.Value)
			{
				return;
			}
			try
			{
				string path = ResolveUnderGame((ValheimConsoleCapturePlugin.LogPath == null) ? "BepInEx/ValheimConsole.log" : ValheimConsoleCapturePlugin.LogPath.Value);
				string directoryName = Path.GetDirectoryName(path);
				if (!string.IsNullOrEmpty(directoryName))
				{
					Directory.CreateDirectory(directoryName);
				}
				FileMode mode = ((ValheimConsoleCapturePlugin.AppendMode == null || ValheimConsoleCapturePlugin.AppendMode.Value) ? FileMode.Append : FileMode.Create);
				FileStream stream = new FileStream(path, mode, FileAccess.Write, FileShare.ReadWrite);
				_writer = new StreamWriter(stream, new UTF8Encoding(encoderShouldEmitUTF8Identifier: false));
				_fileFault = false;
				string text = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture);
				_writer.WriteLine("============================================================");
				_writer.WriteLine("Valheim Console Capture");
				_writer.WriteLine("Session started: " + text);
				_writer.WriteLine("============================================================");
				_writer.Flush();
			}
			catch (Exception ex)
			{
				NoteFault(ex);
			}
		}

		private static void WriteLine(string line)
		{
			if (ValheimConsoleCapturePlugin.LogToFile == null || !ValheimConsoleCapturePlugin.LogToFile.Value)
			{
				return;
			}
			EnsureWriter();
			if (_writer == null)
			{
				return;
			}
			try
			{
				if (ValheimConsoleCapturePlugin.TimestampLines == null || ValheimConsoleCapturePlugin.TimestampLines.Value)
				{
					string text = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture);
					_writer.WriteLine("[" + text + "] " + line);
				}
				else
				{
					_writer.WriteLine(line);
				}
				if (ValheimConsoleCapturePlugin.FlushImmediately == null || ValheimConsoleCapturePlugin.FlushImmediately.Value)
				{
					_writer.Flush();
				}
			}
			catch (Exception ex)
			{
				NoteFault(ex);
			}
		}

		private static void CloseWriter()
		{
			if (_writer != null)
			{
				try
				{
					_writer.Flush();
					_writer.Dispose();
				}
				catch (Exception ex)
				{
					NoteFault(ex);
				}
				_writer = null;
			}
		}

		private static string FileStatus()
		{
			if (ValheimConsoleCapturePlugin.LogToFile == null || !ValheimConsoleCapturePlugin.LogToFile.Value)
			{
				return "Disabled";
			}
			if (_fileFault)
			{
				return "Error";
			}
			return "Enabled";
		}

		private static void NoteFault(Exception ex)
		{
			_fileFault = true;
			if (!_loggedFault && ValheimConsoleCapturePlugin.ModLogger != null)
			{
				_loggedFault = true;
				ValheimConsoleCapturePlugin.ModLogger.LogError((object)("Console log write failed: " + ex));
			}
		}

		private static string ApplyRichText(string line)
		{
			if (string.IsNullOrEmpty(line))
			{
				return line ?? "";
			}
			if (ValheimConsoleCapturePlugin.StripRichText == null || !ValheimConsoleCapturePlugin.StripRichText.Value)
			{
				return line;
			}
			return RichTextTags.Replace(line, "");
		}

		private static IEnumerable<string> SplitLines(string text)
		{
			if (text.Length == 0)
			{
				yield return "";
				yield break;
			}
			string text2 = text.Replace("\r\n", "\n").Replace('\r', '\n');
			bool flag = text2[text2.Length - 1] == '\n';
			string[] parts = text2.Split('\n');
			int count = parts.Length;
			if (flag && count > 1)
			{
				count--;
			}
			for (int i = 0; i < count; i++)
			{
				yield return parts[i];
			}
		}

		private static string ResolveUnderGame(string relativeOrAbsolute)
		{
			if (string.IsNullOrWhiteSpace(relativeOrAbsolute))
			{
				relativeOrAbsolute = "BepInEx/ValheimConsole.log";
			}
			if (Path.IsPathRooted(relativeOrAbsolute))
			{
				return Path.GetFullPath(relativeOrAbsolute);
			}
			string text = relativeOrAbsolute.Replace('/', Path.DirectorySeparatorChar).TrimStart(Path.DirectorySeparatorChar);
			string text2 = "BepInEx" + Path.DirectorySeparatorChar;
			if (text.Equals("BepInEx", StringComparison.OrdinalIgnoreCase))
			{
				return Paths.BepInExRootPath;
			}
			if (text.StartsWith(text2, StringComparison.OrdinalIgnoreCase))
			{
				return Path.GetFullPath(Path.Combine(Paths.BepInExRootPath, text.Substring(text2.Length)));
			}
			return Path.GetFullPath(Path.Combine(Paths.GameRootPath, text));
		}

		private static string DisplayPath(string fullPath)
		{
			if (string.IsNullOrEmpty(fullPath))
			{
				return fullPath;
			}
			string bepInExRootPath = Paths.BepInExRootPath;
			if (!string.IsNullOrEmpty(bepInExRootPath))
			{
				string text = bepInExRootPath.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar) + Path.DirectorySeparatorChar;
				if (fullPath.StartsWith(text, StringComparison.OrdinalIgnoreCase))
				{
					return "BepInEx/" + fullPath.Substring(text.Length).Replace('\\', '/');
				}
			}
			string gameRootPath = Paths.GameRootPath;
			if (!string.IsNullOrEmpty(gameRootPath))
			{
				string text2 = gameRootPath.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar) + Path.DirectorySeparatorChar;
				if (fullPath.StartsWith(text2, StringComparison.OrdinalIgnoreCase))
				{
					return fullPath.Substring(text2.Length).Replace('\\', '/');
				}
			}
			return fullPath;
		}
	}
	[HarmonyPatch(typeof(Terminal), "AddString", new Type[] { typeof(string) })]
	internal static class TerminalAddStringPatch
	{
		private static void Postfix(Terminal __instance, string text)
		{
			if (__instance is Console)
			{
				ConsoleCapture.OnTerminalLine(text);
			}
		}
	}
	[HarmonyPatch(typeof(Terminal), "InputText")]
	internal static class TerminalInputTextPatch
	{
		private static void Prefix(Terminal __instance)
		{
			if (__instance is Console)
			{
				ConsoleCapture.ExpectCommandEcho();
			}
		}

		private static void Postfix()
		{
			ConsoleCapture.EndCommandEcho();
		}
	}
	[HarmonyPatch(typeof(Terminal), "TryRunCommand")]
	internal static class TerminalTryRunCommandPatch
	{
		[HarmonyPriority(800)]
		private static void Prefix(ref string text)
		{
			ConsoleCommands.ProtectChain(ref text);
		}
	}
	[HarmonyPatch(typeof(ConsoleCommand), "RunAction")]
	internal static class TerminalRunActionPatch
	{
		[HarmonyPriority(800)]
		private static void Prefix(ConsoleEventArgs args)
		{
			ConsoleCommands.RestoreChain(args);
		}
	}
	[HarmonyPatch(typeof(Terminal), "updateSearch")]
	internal static class TerminalAutocompletePatch
	{
		private static void Postfix(Terminal __instance)
		{
			if (__instance is Console)
			{
				TMP_Text search = __instance.m_search;
				if (!((Object)(object)search == (Object)null))
				{
					ConsoleCapture.OnAutocomplete(search.text);
				}
			}
		}
	}
	[BepInPlugin("com.sonicdm.valheim.valheimconsolecapture", "ValheimConsoleCapture", "1.0.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	public sealed class ValheimConsoleCapturePlugin : BaseUnityPlugin
	{
		public const string PluginGuid = "com.sonicdm.valheim.valheimconsolecapture";

		public const string PluginName = "ValheimConsoleCapture";

		public const string PluginVersion = "1.0.0";

		internal static ManualLogSource ModLogger;

		internal static ConfigEntry<bool> Enabled;

		internal static ConfigEntry<bool> LogToFile;

		internal static ConfigEntry<string> LogPath;

		internal static ConfigEntry<bool> AppendMode;

		internal static ConfigEntry<bool> TimestampLines;

		internal static ConfigEntry<bool> FlushImmediately;

		internal static ConfigEntry<int> BufferedLines;

		internal static ConfigEntry<bool> EnableClipboard;

		internal static ConfigEntry<bool> CaptureCommands;

		internal static ConfigEntry<bool> CaptureOutput;

		internal static ConfigEntry<bool> StripRichText;

		internal static ConfigEntry<bool> CaptureAutocomplete;

		private Harmony _harmony;

		private void Awake()
		{
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Expected O, but got Unknown
			//IL_01b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bd: Expected O, but got Unknown
			ModLogger = ((BaseUnityPlugin)this).Logger;
			Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Capture F5 console lines when the game starts. consolecapture on/off overrides this until the next launch.");
			LogToFile = ((BaseUnityPlugin)this).Config.Bind<bool>("File", "LogToFile", true, "Append captured lines to the console log file.");
			LogPath = ((BaseUnityPlugin)this).Config.Bind<string>("File", "LogPath", "BepInEx/ValheimConsole.log", "Log file path. A BepInEx/... path is inside the active BepInEx folder (the Gale profile when using a mod manager). Other relative paths start at the game folder. Applied when the file is opened.");
			AppendMode = ((BaseUnityPlugin)this).Config.Bind<bool>("File", "AppendMode", true, "Append to an existing log. When false, the file is replaced at the start of the session. Applied when the file is opened.");
			TimestampLines = ((BaseUnityPlugin)this).Config.Bind<bool>("File", "TimestampLines", true, "Prefix each logged line with the local time. Clipboard and dump files stay unstamped.");
			FlushImmediately = ((BaseUnityPlugin)this).Config.Bind<bool>("File", "FlushImmediately", true, "Flush the log after every line so a crash still keeps the output.");
			BufferedLines = ((BaseUnityPlugin)this).Config.Bind<int>("Buffer", "BufferedLines", 1000, new ConfigDescription("How many recent console lines to keep in memory for copyconsole and dumpconsole.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 100000), Array.Empty<object>()));
			EnableClipboard = ((BaseUnityPlugin)this).Config.Bind<bool>("Clipboard", "EnableClipboard", true, "Allow copyconsole to write to the system clipboard.");
			CaptureCommands = ((BaseUnityPlugin)this).Config.Bind<bool>("Filtering", "CaptureCommands", true, "Record the command line Valheim echoes when you press Enter.");
			CaptureOutput = ((BaseUnityPlugin)this).Config.Bind<bool>("Filtering", "CaptureOutput", true, "Record command results and other F5 console lines.");
			StripRichText = ((BaseUnityPlugin)this).Config.Bind<bool>("Filtering", "StripRichText", false, "Remove Unity rich-text tags such as <color=yellow> from the log, clipboard, and dumps.");
			CaptureAutocomplete = ((BaseUnityPlugin)this).Config.Bind<bool>("Filtering", "CaptureAutocomplete", true, "Record the live suggestion bar. Tab completion writes that text field directly and does not call Terminal.AddString.");
			ConsoleCapture.Start();
			_harmony = new Harmony("com.sonicdm.valheim.valheimconsolecapture");
			try
			{
				_harmony.PatchAll(typeof(ValheimConsoleCapturePlugin).Assembly);
				ConsoleCommands.Register();
				((BaseUnityPlugin)this).Logger.LogInfo((object)"ValheimConsoleCapture 1.0.0 loaded.");
			}
			catch (Exception ex)
			{
				ConsoleCapture.Shutdown();
				((BaseUnityPlugin)this).Logger.LogError((object)("ValheimConsoleCapture failed to start: " + ex));
			}
		}

		private void OnDestroy()
		{
			if (_harmony != null)
			{
				try
				{
					_harmony.UnpatchSelf();
				}
				catch (Exception ex)
				{
					((BaseUnityPlugin)this).Logger.LogWarning((object)("Unpatch failed: " + ex.Message));
				}
				_harmony = null;
			}
			ConsoleCapture.Shutdown();
		}
	}
}