Decompiled source of ConsoleStdinHeeler v1.0.1

ConsoleStdinHeeler.dll

Decompiled 4 days ago
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("ConsoleStdinHeeler")]
[assembly: AssemblyDescription("Non-blocking STDIN console input and native server management commands for Valheim dedicated servers. For more information, visit https://github.com/dreamwraith/Valheim-ConsoleStdinHeeler")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("dreamwraith (https://github.com/dreamwraith/Valheim-ConsoleStdinHeeler)")]
[assembly: AssemblyProduct("ConsoleStdinHeeler")]
[assembly: AssemblyCopyright("Copyright © 2026 dreamwraith")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("70a849c3-5859-452b-86d7-c8c2c4f8ebd6")]
[assembly: AssemblyFileVersion("1.0.1")]
[assembly: AssemblyInformationalVersion("1.0.1")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.1.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[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 ConsoleStdinHeeler
{
	public static class CommandFilter
	{
		private static readonly HashSet<string> ClientAndPlayerCommands = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
		{
			"blowkiss", "bow", "challenge", "cheer", "comehere", "cower", "cry", "dance", "despair", "flex",
			"headbang", "kneel", "laugh", "loveyou", "nonono", "point", "relax", "rest", "roar", "shrug",
			"sit", "thumbsup", "toast", "vibe", "wave", "god", "ghost", "fly", "nocost", "die",
			"puke", "heal", "pos", "goto", "beard", "hair", "model", "raiseskill", "resetskill", "freefly",
			"ffsmooth", "tame", "killall", "killenemies", "killenemycreatures", "killtame", "exploremap", "resetmap", "resetsharedmap", "tombstone",
			"itemset", "catch", "resetcharacter", "resetknownitems", "tutorialreset", "clearstatus", "addstatus", "setpower", "repairall", "sortcraft",
			"filtercraft", "inventoryclean", "inventorysize", "nomap", "resetspawn", "s", "w", "whisper", "msg", "tell",
			"debugmode", "dpsdebug", "adrenaline", "aggravate", "achievements", "getstat", "stats", "setkeyplayer", "removekeyplayer", "yesiuseddevcommandsbutiwantmyachievementsanyway",
			"biomeinfo", "haslocation", "printlocations", "printnetobj", "printcreatures", "recall", "vegetation", "height", "forcedelete", "snow",
			"location", "find", "findbiome", "findbiometp", "findtp", "stopfire", "stopsmoke", "setfuel", "printseeds", "noportals",
			"removedrops", "removebirds", "removefish", "nextseed", "setworldmodifier", "setworldpreset", "clear", "clearpopups", "fov", "lodbias",
			"maxfps", "cr", "unlockcinematics", "cinematic", "cinematicsleep", "xb:version", "resetbuildui", "resetplayerprefs", "bind", "unbind",
			"printbinds", "resetbinds", "exclusivefullscreen", "hidebetatext", "devcommands", "confirmcheats", "test", "env", "wind", "resetenv",
			"resetwind"
		};

		private static readonly HashSet<string> BuiltInServerCommands = InitializeBuiltInCommands();

		public static bool IsServerIncompatible(string commandName, ConsoleCommand? commandInstance = null)
		{
			if (!ClientAndPlayerCommands.Contains(commandName))
			{
				if (commandInstance == null)
				{
					return false;
				}
				return commandInstance.Description?.StartsWith("emote:", StringComparison.OrdinalIgnoreCase) == true;
			}
			return true;
		}

		public static bool IsBuiltInServerCommand(string commandName)
		{
			return BuiltInServerCommands.Contains(commandName);
		}

		private static HashSet<string> InitializeBuiltInCommands()
		{
			HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "help", "broadcast", "alert", "teleport" };
			(string, string)[] dedicatedCommands = CommandCustom.DedicatedCommands;
			for (int i = 0; i < dedicatedCommands.Length; i++)
			{
				string[] array = dedicatedCommands[i].Item1.Split('[', '<')[0].Split(new char[1] { '/' });
				for (int j = 0; j < array.Length; j++)
				{
					string text = array[j].Trim();
					if (!string.IsNullOrEmpty(text))
					{
						hashSet.Add(text);
					}
				}
			}
			return hashSet;
		}
	}
	public static class CommandServer
	{
		private static readonly Regex CoordRegex = new Regex("^-?\\d+(?:\\.\\d+)?,-?\\d+(?:\\.\\d+)?(?:,-?\\d+(?:\\.\\d+)?)?$", RegexOptions.Compiled);

		public static void Execute(string rawCommandLine)
		{
			if (string.IsNullOrWhiteSpace(rawCommandLine))
			{
				return;
			}
			try
			{
				string text = Plugin.ConsolePrompt?.Value ?? "> ";
				Plugin.Log.LogInfo(TerminalColor.Gray + text + TerminalColor.Cyan + rawCommandLine + TerminalColor.Reset);
				string text2 = rawCommandLine.Trim();
				int num = text2.IndexOf(' ');
				string text3 = ((num < 0) ? text2 : text2.Substring(0, num)).ToLowerInvariant();
				string text4 = ((num < 0) ? string.Empty : text2.Substring(num + 1).Trim());
				if (string.IsNullOrEmpty(text3))
				{
					return;
				}
				if (CommandFilter.IsServerIncompatible(text3))
				{
					Plugin.Log.LogWarning("Command '" + text3 + "' requires an active game client or in-game player character and cannot be run from a dedicated server console.");
					return;
				}
				switch (text3)
				{
				case "save":
					CommandCustom.HandleSaveCommand();
					break;
				case "stop":
				case "exit":
				case "quit":
				case "shutdown":
					CommandCustom.HandleShutdownCommand(text4);
					break;
				case "kickall":
					CommandCustom.HandleKickAllCommand(text4);
					break;
				case "teleport":
				case "tp":
					CommandCustom.HandleTeleportCommand(text4);
					break;
				case "list":
				case "players":
					CommandCustom.HandlePlayersCommand();
					break;
				case "say":
					CommandCustom.HandleSayCommand(text4);
					break;
				case "announce":
				case "broadcast":
				case "alert":
					CommandCustom.HandleAnnounceCommand(text4);
					break;
				case "tod":
					CommandOverrides.HandleTodCommand(text4);
					break;
				case "event":
					CommandOverrides.HandleEventCommand(text4);
					break;
				case "stopevent":
					CommandOverrides.HandleStopEventCommand();
					break;
				case "sleep":
					CommandOverrides.HandleSleepCommand();
					break;
				case "spawn":
					CommandOverrides.HandleSpawnCommand(text4);
					break;
				case "help":
					CommandCustom.HandleHelpCommand(text4);
					break;
				default:
					ExecuteTerminalCommand(rawCommandLine);
					break;
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError("Error executing STDIN command '" + rawCommandLine + "': " + ex.Message);
				Plugin.Log.LogDebug(ex.ToString());
			}
		}

		public static void ExecuteTerminalCommand(string commandLine)
		{
			if ((Object)(object)Console.instance == (Object)null)
			{
				Plugin.Log.LogWarning("Valheim Console/Terminal instance is not available yet.");
				return;
			}
			bool cheat = Terminal.m_cheat;
			try
			{
				if (Plugin.EnableCheatsByDefault != null && Plugin.EnableCheatsByDefault.Value)
				{
					Terminal.m_cheat = true;
				}
				((Terminal)Console.instance).TryRunCommand(commandLine, false, true);
			}
			finally
			{
				Terminal.m_cheat = cheat;
			}
		}

		public static ZNetPeer? FindPeer(string playerIdentifier)
		{
			if (string.IsNullOrWhiteSpace(playerIdentifier) || (Object)(object)ZNet.instance == (Object)null)
			{
				return null;
			}
			string cleanId = playerIdentifier.Trim();
			if (string.IsNullOrEmpty(cleanId))
			{
				return null;
			}
			List<ZNetPeer> connectedPeers = ZNet.instance.GetConnectedPeers();
			if (connectedPeers == null || connectedPeers.Count == 0)
			{
				return null;
			}
			if (string.Equals(cleanId, "@random", StringComparison.OrdinalIgnoreCase))
			{
				List<ZNetPeer> list = connectedPeers.FindAll((ZNetPeer p) => p != null);
				if (list.Count == 0)
				{
					return null;
				}
				int index = Random.Range(0, list.Count);
				return list[index];
			}
			return connectedPeers.Find(delegate(ZNetPeer p)
			{
				if (p == null)
				{
					return false;
				}
				if (string.Equals(p.m_playerName, cleanId, StringComparison.OrdinalIgnoreCase))
				{
					return true;
				}
				if (p.m_uid.ToString() == cleanId)
				{
					return true;
				}
				if (!string.IsNullOrEmpty(p.m_playfabId) && string.Equals(p.m_playfabId, cleanId, StringComparison.OrdinalIgnoreCase))
				{
					return true;
				}
				if (p.m_playerID.ToString() == cleanId || ((ZDOID)(ref p.m_characterID)).UserID.ToString() == cleanId)
				{
					return true;
				}
				ISocket socket = p.m_socket;
				string text = ((socket != null) ? socket.GetHostName() : null);
				return (!string.IsNullOrEmpty(text) && (string.Equals(text, cleanId, StringComparison.OrdinalIgnoreCase) || string.Equals(text, "Steam_" + cleanId, StringComparison.OrdinalIgnoreCase))) ? true : false;
			});
		}

		public static bool TryResolvePeer(string playerIdentifier, out ZNetPeer peer, string roleDescription = "Player")
		{
			peer = null;
			if (string.IsNullOrWhiteSpace(playerIdentifier))
			{
				return false;
			}
			if ((Object)(object)ZNet.instance == (Object)null)
			{
				Plugin.Log.LogWarning("Cannot find player: Server world is not loaded.");
				return false;
			}
			if (ZNet.instance.GetConnectedPeers().Count == 0)
			{
				Plugin.Log.LogWarning("Cannot find player: No players are currently connected to the server.");
				return false;
			}
			ZNetPeer val = FindPeer(playerIdentifier);
			if (val == null)
			{
				Plugin.Log.LogWarning(roleDescription + " '" + playerIdentifier.Trim() + "' not found among connected peers.");
				return false;
			}
			peer = val;
			return true;
		}

		public static bool TryParseCoordinates(string text, out Vector3 coords)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			coords = Vector3.zero;
			if (string.IsNullOrWhiteSpace(text) || !CoordRegex.IsMatch(text))
			{
				return false;
			}
			string[] array = text.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries);
			if (array.Length == 3 && float.TryParse(array[0], NumberStyles.Float, CultureInfo.InvariantCulture, out var result) && float.TryParse(array[1], NumberStyles.Float, CultureInfo.InvariantCulture, out var result2) && float.TryParse(array[2], NumberStyles.Float, CultureInfo.InvariantCulture, out var result3))
			{
				coords = new Vector3(result, result2, result3);
				return true;
			}
			if (array.Length == 2 && float.TryParse(array[0], NumberStyles.Float, CultureInfo.InvariantCulture, out var result4) && float.TryParse(array[1], NumberStyles.Float, CultureInfo.InvariantCulture, out var result5))
			{
				float num = (((Object)(object)ZoneSystem.instance != (Object)null) ? (ZoneSystem.instance.GetSolidHeight(new Vector3(result4, 0f, result5)) + 0.5f) : 30f);
				coords = new Vector3(result4, num, result5);
				return true;
			}
			return false;
		}

		public static bool TryResolveTarget(string targetToken, out CommandTarget target)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_013e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			target = default(CommandTarget);
			if (string.IsNullOrWhiteSpace(targetToken))
			{
				return false;
			}
			if (TryParseCoordinates(targetToken, out var coords))
			{
				target = new CommandTarget(coords, Vector3.forward, null, null, $"coordinates ({coords.x:F1}, {coords.y:F1}, {coords.z:F1})", isCoordinates: true);
				return true;
			}
			if (!TryResolvePeer(targetToken, out ZNetPeer peer, "Target player or coordinates"))
			{
				return false;
			}
			Player val = null;
			List<Player> allPlayers = Player.GetAllPlayers();
			if (allPlayers != null)
			{
				val = allPlayers.Find((Player p) => (Object)(object)p != (Object)null && (string.Equals(p.GetPlayerName(), peer.m_playerName, StringComparison.OrdinalIgnoreCase) || p.GetPlayerID() == peer.m_playerID));
			}
			Vector3 val2;
			Vector3 forward;
			string description;
			if ((Object)(object)val != (Object)null)
			{
				val2 = ((Component)val).transform.position;
				forward = ((Component)val).transform.forward;
				description = $"player '{TerminalColor.Cyan}{val.GetPlayerName()}{TerminalColor.Reset}' at {val2}";
			}
			else
			{
				val2 = peer.m_refPos;
				forward = Vector3.forward;
				description = $"player '{TerminalColor.Cyan}{peer.m_playerName}{TerminalColor.Reset}' at {val2}";
			}
			target = new CommandTarget(val2, forward, peer, val, description, isCoordinates: false);
			return true;
		}
	}
	public readonly struct CommandTarget
	{
		public Vector3 Position { get; }

		public Vector3 Forward { get; }

		public ZNetPeer? Peer { get; }

		public Player? Player { get; }

		public string Description { get; }

		public bool IsCoordinates { get; }

		public CommandTarget(Vector3 position, Vector3 forward, ZNetPeer? peer, Player? player, string description, bool isCoordinates)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			Position = position;
			Forward = forward;
			Peer = peer;
			Player = player;
			Description = description;
			IsCoordinates = isCoordinates;
		}
	}
	public static class CommandCustom
	{
		private static readonly FieldInfo? TerminalCommandsField = typeof(Terminal).GetField("commands", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);

		private static bool _hasLoggedReflectionWarning;

		internal static readonly (string Syntax, string Description)[] DedicatedCommands = new(string, string)[37]
		{
			("save", "Force save world and player profile data"),
			("stop / shutdown [min] [msg]", "Stop server (optional countdown, e.g. 'stop 5 Reboot')"),
			("stop cancel", "Cancel an active shutdown countdown"),
			("players / list", "List all connected players, endpoints, ping, and IDs"),
			("kick <name/ip/userID>", "Kick a single player from the server"),
			("kickall [seconds] [reason]", "Save world and kick all connected players (default: 3s grace delay)"),
			("ban <name/ip/userID>", "Ban a player by name, IP, or user ID"),
			("unban <name/ip/userID>", "Unban a player"),
			("banned", "List all currently banned players"),
			("say <@all/*|player> <msg>", "Display top-left notification to all clients or a specific player"),
			("announce <@all/*|player> <msg>", "Display prominent center banner to all clients or a specific player"),
			("tp <player> <target/x,y,z>", "Teleport a player to another player or coordinates"),
			("time", "Display current world time, day count, and sleep status"),
			("tod <0-1>", "Set time of day for all connected clients (e.g. tod 0.5)"),
			("skiptime [gameseconds]", "Skip ahead in seconds (default: 240)"),
			("sleep", "Fast-forward time to next morning"),
			("timescale [scale]", "Adjust game simulation speed (default: 1.0)"),
			("event <name> <target/x,y,z>", "Start a raid/event near a player or coordinates (e.g. event army_eikthyr Thor)"),
			("stopevent", "Stop any currently active raid/event"),
			("randomevent", "Start a random raid/event near a player"),
			("pevents [list/start/stop/here]", "Manage player events and raids (subcommands: list, start, stop, here)"),
			("spawn <prefab> <target/x,y,z> [amt] [lvl]", "Spawn near a player or coordinates (e.g. spawn Boar Thor 3 2)"),
			("listkeys", "List active world progress keys, modifiers, and presets"),
			("setkey <name>", "Set a global world progress key (e.g. boss keys)"),
			("removekey <name>", "Remove an active global world progress key"),
			("resetkeys", "Reset all global world progress keys"),
			("resetworldkeys", "Reset all world modifiers to default settings"),
			("optterrain", "Optimize older terrain modifications across loaded sectors"),
			("genloc", "Regenerate missing world locations"),
			("updatecover", "Force refresh of shelter and roof cover calculations"),
			("nospawn", "Toggle natural spawning of monsters on/off"),
			("respawntime <seconds>", "Set player respawn delay timer in seconds"),
			("restartparty", "Restart PlayFab Party network connection"),
			("altbioms", "List biomes with active modifiers"),
			("gc", "Run garbage collection and report freed memory"),
			("ping", "Show server ping"),
			("info", "Print server memory & system specs")
		};

		private static float _kickDisconnectTime = -1f;

		private static bool _isShutdownScheduled;

		private static float _shutdownTargetTime;

		private static string _shutdownReason = string.Empty;

		private static int _lastAnnouncedSecondsLeft = -1;

		private static readonly int[] ShutdownMilestones = new int[8] { 600, 300, 180, 120, 60, 30, 10, 5 };

		public static void HandleHelpCommand(string helpArguments)
		{
			if (helpArguments.Equals("all", StringComparison.OrdinalIgnoreCase) || helpArguments.Equals("-all", StringComparison.OrdinalIgnoreCase) || helpArguments.Equals("--all", StringComparison.OrdinalIgnoreCase))
			{
				Plugin.Log.LogInfo(TerminalColor.Bold + TerminalColor.Orange + "=== Complete Native Command Catalog (Unfiltered) ===" + TerminalColor.Reset);
				CommandServer.ExecuteTerminalCommand("help");
				return;
			}
			Plugin.Log.LogInfo(TerminalColor.Bold + TerminalColor.Orange + "=== Dedicated Server Commands ===" + TerminalColor.Reset);
			(string, string)[] dedicatedCommands = DedicatedCommands;
			for (int i = 0; i < dedicatedCommands.Length; i++)
			{
				var (syntax, text) = dedicatedCommands[i];
				Plugin.Log.LogInfo("  " + FormatCommandSyntax(syntax) + TerminalColor.Gray + "-" + TerminalColor.Reset + " " + text);
			}
			Dictionary<string, ConsoleCommand> registeredTerminalCommands = GetRegisteredTerminalCommands();
			if (registeredTerminalCommands != null && registeredTerminalCommands.Count > 0)
			{
				List<KeyValuePair<string, ConsoleCommand>> list = new List<KeyValuePair<string, ConsoleCommand>>();
				foreach (KeyValuePair<string, ConsoleCommand> item in registeredTerminalCommands)
				{
					string key = item.Key;
					ConsoleCommand value = item.Value;
					if (!CommandFilter.IsBuiltInServerCommand(key) && !CommandFilter.IsServerIncompatible(key, value) && !value.IsSecret)
					{
						list.Add(item);
					}
				}
				if (list.Count > 0)
				{
					Plugin.Log.LogInfo(TerminalColor.Bold + TerminalColor.Orange + "=== Modded & Additional Available Commands ===" + TerminalColor.Reset);
					list.Sort((KeyValuePair<string, ConsoleCommand> first, KeyValuePair<string, ConsoleCommand> second) => string.Compare(first.Key, second.Key, StringComparison.OrdinalIgnoreCase));
					foreach (KeyValuePair<string, ConsoleCommand> item2 in list)
					{
						string text2 = (string.IsNullOrWhiteSpace(item2.Value.Description) ? "No description provided." : item2.Value.Description);
						Plugin.Log.LogInfo("  " + FormatCommandSyntax(item2.Key) + TerminalColor.Gray + "-" + TerminalColor.Reset + " " + text2);
					}
				}
			}
			Plugin.Log.LogInfo(TerminalColor.Gray + "Tip: Type 'help all' to display the complete, unfiltered native command catalog." + TerminalColor.Reset);
		}

		private static Dictionary<string, ConsoleCommand>? GetRegisteredTerminalCommands()
		{
			if (TerminalCommandsField != null)
			{
				try
				{
					if (TerminalCommandsField.GetValue(null) is Dictionary<string, ConsoleCommand> result)
					{
						return result;
					}
				}
				catch (Exception ex)
				{
					Plugin.Log.LogDebug("Could not read Terminal.commands dictionary: " + ex.Message);
				}
			}
			if (!_hasLoggedReflectionWarning)
			{
				_hasLoggedReflectionWarning = true;
				Plugin.Log.LogWarning("Could not reflect Terminal.commands dictionary. Mod command auto-discovery in 'help' will be disabled.");
			}
			return null;
		}

		private static string FormatCommandSyntax(string syntax, int padWidth = 28)
		{
			int num = syntax.IndexOf(' ');
			if (num < 0)
			{
				string text = ((syntax.Length < padWidth) ? syntax.PadRight(padWidth) : (syntax + " "));
				return TerminalColor.Yellow + text + TerminalColor.Reset;
			}
			string text2 = syntax.Substring(0, num);
			string text3 = syntax.Substring(num);
			string text4 = ((syntax.Length < padWidth) ? text3.PadRight(padWidth - text2.Length) : (text3 + " "));
			return TerminalColor.Yellow + text2 + TerminalColor.Cyan + text4 + TerminalColor.Reset;
		}

		public static void HandleSayCommand(string arguments)
		{
			ZNetPeer peer;
			if (!TryParseMessageTarget(arguments, out string targetPlayer, out string message))
			{
				Plugin.Log.LogWarning("Invalid parameters. Usage: say <@all|*|player|\"player name\"> <message>");
			}
			else if (ZRoutedRpc.instance == null)
			{
				Plugin.Log.LogWarning("Cannot send message: ZRoutedRpc is not ready.");
			}
			else if (targetPlayer == null)
			{
				ZRoutedRpc.instance.InvokeRoutedRPC(0L, "ShowMessage", new object[2] { 1, message });
				Plugin.Log.LogInfo("Sent top-left notification to all clients: " + TerminalColor.Cyan + "\"" + message + "\"" + TerminalColor.Reset);
			}
			else if (CommandServer.TryResolvePeer(targetPlayer, out peer, "Target player"))
			{
				ZRoutedRpc.instance.InvokeRoutedRPC(peer.m_uid, "ShowMessage", new object[2] { 1, message });
				Plugin.Log.LogInfo("Sent top-left notification to '" + TerminalColor.Cyan + peer.m_playerName + TerminalColor.Reset + "': " + TerminalColor.Cyan + "\"" + message + "\"" + TerminalColor.Reset);
			}
		}

		public static void HandleAnnounceCommand(string arguments)
		{
			ZNetPeer peer;
			if (!TryParseMessageTarget(arguments, out string targetPlayer, out string message))
			{
				Plugin.Log.LogWarning("Invalid parameters. Usage: announce <@all|*|player|\"player name\"> <message>");
			}
			else if (ZRoutedRpc.instance == null)
			{
				Plugin.Log.LogWarning("Cannot send message: ZRoutedRpc is not ready.");
			}
			else if (targetPlayer == null)
			{
				ZRoutedRpc.instance.InvokeRoutedRPC(0L, "ShowMessage", new object[2] { 2, message });
				Plugin.Log.LogInfo("Sent center announcement banner to all clients: " + TerminalColor.Gold + "\"" + message + "\"" + TerminalColor.Reset);
			}
			else if (CommandServer.TryResolvePeer(targetPlayer, out peer, "Target player"))
			{
				ZRoutedRpc.instance.InvokeRoutedRPC(peer.m_uid, "ShowMessage", new object[2] { 2, message });
				Plugin.Log.LogInfo("Sent center announcement banner to '" + TerminalColor.Cyan + peer.m_playerName + TerminalColor.Reset + "': " + TerminalColor.Gold + "\"" + message + "\"" + TerminalColor.Reset);
			}
		}

		private static bool TryParseMessageTarget(string arguments, out string? targetPlayer, out string message)
		{
			targetPlayer = null;
			message = string.Empty;
			if (string.IsNullOrWhiteSpace(arguments))
			{
				return false;
			}
			string text = arguments.Trim();
			string text2;
			if (text.StartsWith("\""))
			{
				int num = text.IndexOf('"', 1);
				if (num < 0)
				{
					return false;
				}
				text2 = text.Substring(1, num - 1).Trim();
				message = text.Substring(num + 1).Trim();
			}
			else
			{
				int num2 = text.IndexOf(' ');
				if (num2 < 0)
				{
					return false;
				}
				text2 = text.Substring(0, num2).Trim();
				message = text.Substring(num2 + 1).Trim();
			}
			if (string.IsNullOrWhiteSpace(text2) || string.IsNullOrWhiteSpace(message))
			{
				return false;
			}
			if (string.Equals(text2, "@all", StringComparison.OrdinalIgnoreCase) || text2 == "*")
			{
				targetPlayer = null;
			}
			else
			{
				targetPlayer = text2;
			}
			return true;
		}

		public static void HandleTeleportCommand(string arguments)
		{
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_017f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_0139: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)ZNet.instance == (Object)null)
			{
				Plugin.Log.LogWarning("Cannot teleport: Server world is not loaded.");
				return;
			}
			if (string.IsNullOrWhiteSpace(arguments))
			{
				Plugin.Log.LogWarning("Invalid parameters. Usage: tp <player|\"player name\"> <target|\"target player\"|coords>");
				Plugin.Log.LogInfo("Coordinates must strictly follow 0,0 or 0,0,0 mask with no spaces.");
				return;
			}
			List<string> list = TerminalUtils.ParseArguments(arguments.Trim());
			if (list.Count != 2)
			{
				Plugin.Log.LogWarning("Invalid parameters. Usage: tp <player|\"player name\"> <target|\"target player\"|coords>");
				Plugin.Log.LogInfo("Coordinates must strictly follow 0,0 or 0,0,0 mask with no spaces.");
			}
			else
			{
				if (!CommandServer.TryResolvePeer(list[0], out ZNetPeer peer, "Source player") || !CommandServer.TryResolveTarget(list[1], out var target))
				{
					return;
				}
				if (!target.IsCoordinates && target.Peer == peer)
				{
					Plugin.Log.LogWarning("Source player and destination player cannot be the same.");
					return;
				}
				Vector3 val = (target.IsCoordinates ? target.Position : (target.Position + target.Forward * 1.5f + Vector3.up * 0.2f));
				string description = target.Description;
				if (ZRoutedRpc.instance != null)
				{
					ZRoutedRpc.instance.InvokeRoutedRPC(0L, peer.m_characterID, "RPC_TeleportTo", new object[3]
					{
						val,
						Quaternion.identity,
						true
					});
					ZRoutedRpc.instance.InvokeRoutedRPC(peer.m_uid, "ShowMessage", new object[2] { 2, "Teleported by administrator" });
				}
				peer.m_refPos = val;
				Plugin.Log.LogInfo("Teleported '" + TerminalColor.Cyan + peer.m_playerName + TerminalColor.Reset + "' to " + description + ".");
			}
		}

		public static void HandleKickAllCommand(string arguments)
		{
			if ((Object)(object)ZNet.instance == (Object)null)
			{
				Plugin.Log.LogWarning("Cannot kick players: Server is not running.");
				return;
			}
			List<ZNetPeer> connectedPeers = ZNet.instance.GetConnectedPeers();
			if (connectedPeers.Count == 0)
			{
				Plugin.Log.LogInfo("No players are currently connected.");
				return;
			}
			string[] array = arguments.Trim().Split(new char[1] { ' ' }, 2, StringSplitOptions.RemoveEmptyEntries);
			float num = 3f;
			string text = "Kicked by administrator";
			if (array.Length != 0 && float.TryParse(array[0], out var result))
			{
				num = Math.Max(0f, result);
				text = ((array.Length > 1) ? array[1] : text);
			}
			else if (!string.IsNullOrWhiteSpace(arguments))
			{
				text = arguments.Trim();
			}
			Plugin.Log.LogInfo($"Kicking {TerminalColor.Cyan}{connectedPeers.Count}{TerminalColor.Reset} connected player(s) in {num:G}s. Reason: {TerminalColor.Yellow}{text}{TerminalColor.Reset}");
			if (ZRoutedRpc.instance != null)
			{
				ZRoutedRpc.instance.InvokeRoutedRPC(0L, "ShowMessage", new object[2]
				{
					2,
					"Server: " + text
				});
			}
			Plugin.Log.LogInfo("Triggering world and player profile save prior to kicking all players...");
			ZNet.instance.Save(false, true, false);
			Plugin.Log.LogInfo(TerminalColor.Green + "World and player profile save triggered successfully." + TerminalColor.Reset);
			_kickDisconnectTime = Time.realtimeSinceStartup + num;
		}

		private static void UpdateKickAll()
		{
			if (!(_kickDisconnectTime >= 0f) || !(Time.realtimeSinceStartup >= _kickDisconnectTime))
			{
				return;
			}
			_kickDisconnectTime = -1f;
			if ((Object)(object)ZNet.instance == (Object)null)
			{
				return;
			}
			foreach (ZNetPeer item in new List<ZNetPeer>(ZNet.instance.GetConnectedPeers()))
			{
				try
				{
					ZRpc rpc = item.m_rpc;
					if (rpc != null)
					{
						rpc.Invoke("Kicked", Array.Empty<object>());
					}
					ZNet.instance.Disconnect(item);
				}
				catch (Exception ex)
				{
					Plugin.Log.LogDebug("Exception disconnecting peer " + item.m_playerName + ": " + ex.Message);
				}
			}
			Plugin.Log.LogInfo(TerminalColor.Green + "All connected players successfully disconnected." + TerminalColor.Reset);
		}

		public static void HandleSaveCommand()
		{
			if ((Object)(object)ZNet.instance == (Object)null || (Object)(object)Game.instance == (Object)null || (Object)(object)ZoneSystem.instance == (Object)null)
			{
				Plugin.Log.LogWarning("Cannot save: Server world is still loading. Please wait until startup completes.");
				return;
			}
			Plugin.Log.LogInfo("Triggering world and player profile save...");
			ZNet.instance.Save(false, true, false);
			Plugin.Log.LogInfo(TerminalColor.Green + "World and player profile save triggered successfully." + TerminalColor.Reset);
		}

		public static void HandleShutdownCommand(string arguments)
		{
			string text = arguments.Trim();
			if (text.Equals("cancel", StringComparison.OrdinalIgnoreCase) || text.Equals("abort", StringComparison.OrdinalIgnoreCase))
			{
				if (!_isShutdownScheduled)
				{
					Plugin.Log.LogInfo("No shutdown countdown is currently active.");
					return;
				}
				_isShutdownScheduled = false;
				_lastAnnouncedSecondsLeft = -1;
				if (ZRoutedRpc.instance != null)
				{
					ZRoutedRpc.instance.InvokeRoutedRPC(0L, "ShowMessage", new object[2] { 2, "Server shutdown countdown canceled." });
				}
				Plugin.Log.LogInfo(TerminalColor.Green + "Server shutdown countdown successfully canceled." + TerminalColor.Reset);
				return;
			}
			if (string.IsNullOrEmpty(text))
			{
				ExecuteImmediateShutdown();
				return;
			}
			string[] array = text.Split(new char[1] { ' ' }, 2, StringSplitOptions.RemoveEmptyEntries);
			if (!float.TryParse(array[0], NumberStyles.Float, CultureInfo.InvariantCulture, out var result) || result <= 0f)
			{
				Plugin.Log.LogWarning("Invalid parameters. Usage: stop [minutes] [reason] OR stop cancel");
				return;
			}
			string arg = (_shutdownReason = ((array.Length > 1) ? array[1].Trim() : "Server maintenance"));
			_shutdownTargetTime = Time.realtimeSinceStartup + result * 60f;
			_isShutdownScheduled = true;
			_lastAnnouncedSecondsLeft = (int)(result * 60f);
			string text2 = $"Server shutting down in {result:F0} min! Reason: {arg}";
			if (ZRoutedRpc.instance != null)
			{
				ZRoutedRpc.instance.InvokeRoutedRPC(0L, "ShowMessage", new object[2] { 2, text2 });
			}
			Plugin.Log.LogInfo(TerminalColor.Orange + text2 + TerminalColor.Reset);
		}

		public static void HandlePlayersCommand()
		{
			//IL_01a4: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)ZNet.instance == (Object)null || (Object)(object)Game.instance == (Object)null)
			{
				Plugin.Log.LogWarning("Cannot list players: Server world is still loading.");
				return;
			}
			List<ZNetPeer> connectedPeers = ZNet.instance.GetConnectedPeers();
			Plugin.Log.LogInfo($"{TerminalColor.Bold}{TerminalColor.Orange}=== Connected Players ({connectedPeers.Count}) ==={TerminalColor.Reset}");
			int num = 1;
			foreach (ZNetPeer item in connectedPeers)
			{
				ISocket socket = item.m_socket;
				string text = ((socket != null) ? socket.GetHostName() : null) ?? "unknown";
				string text2 = (string.IsNullOrEmpty(item.m_playerName) ? "<connecting>" : item.m_playerName);
				float num2 = ((item.m_rpc != null) ? item.m_rpc.GetTimeSinceLastPing() : (-1f));
				string text3 = ((num2 < 0f) ? TerminalColor.Gray : ((num2 < 0.1f) ? TerminalColor.Green : ((num2 < 0.2f) ? TerminalColor.Yellow : TerminalColor.Red)));
				string text4 = ((num2 >= 0f) ? $"{num2 * 1000f:F0}ms" : "n/a");
				Plugin.Log.LogInfo($"  [{num}] {TerminalColor.Cyan}{text2}{TerminalColor.Reset} | Ping: {text3}{text4}{TerminalColor.Reset} | Endpoint: {TerminalColor.Gray}{text}{TerminalColor.Reset} | ID: {TerminalColor.Gray}{item.m_characterID}{TerminalColor.Reset}");
				num++;
			}
		}

		internal static void Update()
		{
			UpdateShutdown();
			UpdateKickAll();
		}

		private static void UpdateShutdown()
		{
			if (!_isShutdownScheduled)
			{
				return;
			}
			float num = _shutdownTargetTime - Time.realtimeSinceStartup;
			if (num <= 0f)
			{
				_isShutdownScheduled = false;
				if (ZRoutedRpc.instance != null)
				{
					ZRoutedRpc.instance.InvokeRoutedRPC(0L, "ShowMessage", new object[2] { 2, "Server shutting down NOW!" });
				}
				ExecuteImmediateShutdown();
				return;
			}
			int num2 = (int)num;
			int[] shutdownMilestones = ShutdownMilestones;
			foreach (int num3 in shutdownMilestones)
			{
				if (_lastAnnouncedSecondsLeft > num3 && num2 <= num3)
				{
					_lastAnnouncedSecondsLeft = num3;
					string text = ((num3 >= 60) ? $"{num3 / 60} minute(s)" : $"{num3} seconds");
					string text2 = "Server shutting down in " + text + "! (" + _shutdownReason + ")";
					if (ZRoutedRpc.instance != null)
					{
						ZRoutedRpc.instance.InvokeRoutedRPC(0L, "ShowMessage", new object[2] { 2, text2 });
					}
					Plugin.Log.LogInfo(TerminalColor.Orange + text2 + TerminalColor.Reset);
					break;
				}
			}
		}

		private static void ExecuteImmediateShutdown()
		{
			Plugin.Log.LogInfo("Initiating graceful server shutdown via Application.Quit()...");
			Plugin.Instance?.StopListener();
			Application.Quit();
		}
	}
	public static class CommandOverrides
	{
		private static readonly MethodInfo? SendNetTimeMethod = typeof(ZNet).GetMethod("SendNetTime", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

		public static void HandleEventCommand(string arguments)
		{
			//IL_0138: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)RandEventSystem.instance == (Object)null || (Object)(object)ZNet.instance == (Object)null)
			{
				Plugin.Log.LogWarning("Cannot trigger event: RandEventSystem is not ready or world is still loading.");
				return;
			}
			if (string.IsNullOrWhiteSpace(arguments))
			{
				Plugin.Log.LogWarning("Invalid parameters. Usage: event <event_name> <player|\"player name\"|coords>");
				Plugin.Log.LogInfo("Coordinates must strictly follow 0,0 or 0,0,0 mask with no spaces.");
				ListAvailableEvents();
				return;
			}
			List<string> list = TerminalUtils.ParseArguments(arguments.Trim());
			if (list.Count != 2)
			{
				Plugin.Log.LogWarning("Invalid parameters. Usage: event <event_name> <player|\"player name\"|coords>");
				Plugin.Log.LogInfo("Coordinates must strictly follow 0,0 or 0,0,0 mask with no spaces.");
				ListAvailableEvents();
				return;
			}
			string text = list[0];
			RandomEvent val = null;
			if (RandEventSystem.instance.m_events != null)
			{
				foreach (RandomEvent @event in RandEventSystem.instance.m_events)
				{
					if (@event != null && @event.m_enabled && string.Equals(@event.m_name, text, StringComparison.OrdinalIgnoreCase))
					{
						val = @event;
						break;
					}
				}
			}
			CommandTarget target;
			if (val == null)
			{
				Plugin.Log.LogWarning("Random event '" + text + "' not found or is disabled.");
				ListAvailableEvents();
			}
			else if (CommandServer.TryResolveTarget(list[1], out target))
			{
				RandEventSystem.instance.SetRandomEvent(val, target.Position);
				Plugin.Log.LogInfo("Triggered event '" + TerminalColor.Yellow + val.m_name + TerminalColor.Reset + "' at " + target.Description + ".");
			}
		}

		public static void HandleStopEventCommand()
		{
			if ((Object)(object)RandEventSystem.instance == (Object)null)
			{
				Plugin.Log.LogWarning("Cannot stop event: RandEventSystem is not ready.");
				return;
			}
			RandomEvent currentRandomEvent = RandEventSystem.instance.GetCurrentRandomEvent();
			if (currentRandomEvent == null)
			{
				Plugin.Log.LogInfo("No random event/raid is currently active.");
				return;
			}
			string name = currentRandomEvent.m_name;
			RandEventSystem.instance.ResetRandomEvent();
			Plugin.Log.LogInfo("Stopped active random event: '" + TerminalColor.Yellow + name + TerminalColor.Reset + "'.");
		}

		private static void ListAvailableEvents()
		{
			if ((Object)(object)RandEventSystem.instance == (Object)null || RandEventSystem.instance.m_events == null)
			{
				return;
			}
			List<string> list = new List<string>();
			foreach (RandomEvent @event in RandEventSystem.instance.m_events)
			{
				if (@event != null && @event.m_enabled)
				{
					list.Add(@event.m_name);
				}
			}
			list.Sort(StringComparer.OrdinalIgnoreCase);
			Plugin.Log.LogInfo("Available events: " + TerminalColor.Yellow + string.Join(TerminalColor.Reset + ", " + TerminalColor.Yellow, list) + TerminalColor.Reset);
		}

		public static void HandleSpawnCommand(string arguments)
		{
			//IL_0247: Unknown result type (might be due to invalid IL or missing references)
			//IL_024c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0250: Unknown result type (might be due to invalid IL or missing references)
			//IL_0255: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0343: Unknown result type (might be due to invalid IL or missing references)
			//IL_0345: Unknown result type (might be due to invalid IL or missing references)
			//IL_034f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0354: Unknown result type (might be due to invalid IL or missing references)
			//IL_0359: Unknown result type (might be due to invalid IL or missing references)
			//IL_035b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0313: Unknown result type (might be due to invalid IL or missing references)
			//IL_0315: Unknown result type (might be due to invalid IL or missing references)
			//IL_031c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0321: Unknown result type (might be due to invalid IL or missing references)
			//IL_0326: Unknown result type (might be due to invalid IL or missing references)
			//IL_0330: Unknown result type (might be due to invalid IL or missing references)
			//IL_0335: Unknown result type (might be due to invalid IL or missing references)
			//IL_033a: Unknown result type (might be due to invalid IL or missing references)
			//IL_033c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0360: Unknown result type (might be due to invalid IL or missing references)
			//IL_0364: Unknown result type (might be due to invalid IL or missing references)
			//IL_0366: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)ZNetScene.instance == (Object)null || (Object)(object)ZNet.instance == (Object)null)
			{
				Plugin.Log.LogWarning("Cannot spawn: ZNetScene or server world is not loaded.");
				return;
			}
			if (string.IsNullOrWhiteSpace(arguments))
			{
				Plugin.Log.LogWarning("Invalid parameters. Usage: spawn <prefab> <player|\"player name\"|coords> [count] [stars/rank]");
				Plugin.Log.LogInfo("Coordinates must strictly follow 0,0 or 0,0,0 mask with no spaces.");
				return;
			}
			List<string> list = TerminalUtils.ParseArguments(arguments.Trim());
			if (list.Count < 2 || list.Count > 4)
			{
				Plugin.Log.LogWarning("Invalid parameters. Usage: spawn <prefab> <player|\"player name\"|coords> [count] [stars/rank]");
				Plugin.Log.LogInfo("Coordinates must strictly follow 0,0 or 0,0,0 mask with no spaces.");
				return;
			}
			string text = list[0];
			string targetToken = list[1];
			int num = 1;
			int num2 = 1;
			if (list.Count > 2)
			{
				if (!int.TryParse(list[2], out var result) || result < 1)
				{
					Plugin.Log.LogWarning("Invalid count '" + list[2] + "'. Count must be a positive integer.");
					return;
				}
				num = Math.Min(1000, result);
			}
			if (list.Count > 3)
			{
				if (!int.TryParse(list[3], out var result2) || result2 < 1)
				{
					Plugin.Log.LogWarning("Invalid stars/rank '" + list[3] + "'. Level must be a positive integer.");
					return;
				}
				num2 = Math.Min(10, result2);
			}
			GameObject prefab = ZNetScene.instance.GetPrefab(text);
			if ((Object)(object)prefab == (Object)null)
			{
				List<string> prefabNames = ZNetScene.instance.GetPrefabNames();
				List<string> list2 = new List<string>(8);
				if (prefabNames != null)
				{
					foreach (string item in prefabNames)
					{
						if (string.Equals(item, text, StringComparison.OrdinalIgnoreCase))
						{
							prefab = ZNetScene.instance.GetPrefab(item);
							break;
						}
						if (list2.Count < 8 && item.IndexOf(text, StringComparison.OrdinalIgnoreCase) >= 0)
						{
							list2.Add(item);
						}
					}
				}
				if ((Object)(object)prefab == (Object)null)
				{
					Plugin.Log.LogWarning("Prefab '" + text + "' not found in ZNetScene.");
					if (list2.Count > 0)
					{
						Plugin.Log.LogInfo("Matching prefabs: " + TerminalColor.Yellow + string.Join(TerminalColor.Reset + ", " + TerminalColor.Yellow, list2) + TerminalColor.Reset);
					}
					return;
				}
			}
			if (!CommandServer.TryResolveTarget(targetToken, out var target))
			{
				return;
			}
			Vector3 position = target.Position;
			Vector3 forward = target.Forward;
			string description = target.Description;
			ItemDrop component = prefab.GetComponent<ItemDrop>();
			int val = ((!((Object)(object)component != (Object)null) || component.m_itemData?.m_shared == null) ? 1 : Math.Max(1, component.m_itemData.m_shared.m_maxStackSize));
			int num3 = num;
			int num4 = 0;
			while (num3 > 0)
			{
				int num5 = Math.Min(num3, val);
				num3 -= num5;
				Vector3 val2 = ((num4 == 0) ? Vector3.zero : (Random.insideUnitSphere * Mathf.Min(8f, 0.5f + (float)num4 * 0.3f)));
				val2.y = Mathf.Abs(val2.y) * 0.2f;
				Vector3 val3 = (target.IsCoordinates ? (position + Vector3.up * 0.5f + val2) : (position + forward * 2f + Vector3.up * 0.5f + val2));
				GameObject val4 = Object.Instantiate<GameObject>(prefab, val3, Quaternion.identity);
				num4++;
				ItemDrop component2 = val4.GetComponent<ItemDrop>();
				if ((Object)(object)component2 != (Object)null)
				{
					ItemDrop.OnCreateNew(val4, true);
					if (component2.m_itemData != null)
					{
						component2.m_itemData.m_durability = component2.m_itemData.GetMaxDurability();
						component2.m_itemData.m_stack = num5;
						if (num2 > 1)
						{
							component2.SetQuality(Mathf.Min(num2, 4));
						}
					}
				}
				Character component3 = val4.GetComponent<Character>();
				if ((Object)(object)component3 != (Object)null && num2 > 1)
				{
					component3.SetLevel(num2);
				}
				ZNetView component4 = val4.GetComponent<ZNetView>();
				if ((Object)(object)component4 != (Object)null && component4.IsValid())
				{
					component4.GetZDO().Set(ZDOVars.s_cheated, true);
				}
			}
			if ((Object)(object)target.Player != (Object)null)
			{
				((Character)target.Player).Message((MessageType)1, "Spawning object " + ((Object)prefab).name + ((num > 1) ? $" x{num}" : ""), 0, (Sprite)null, false);
			}
			else if (target.Peer != null && ZRoutedRpc.instance != null)
			{
				ZRoutedRpc.instance.InvokeRoutedRPC(target.Peer.m_uid, "ShowMessage", new object[2]
				{
					1,
					"Spawning object " + ((Object)prefab).name + ((num > 1) ? $" x{num}" : "")
				});
			}
			string text2 = ((num2 > 1) ? $" (Level {num2})" : string.Empty);
			Plugin.Log.LogInfo($"Spawned {TerminalColor.Green}{((Object)prefab).name}{text2} x{num}{TerminalColor.Reset} at {description}.");
		}

		public static void HandleTodCommand(string arguments)
		{
			if ((Object)(object)ZNet.instance == (Object)null)
			{
				Plugin.Log.LogWarning("Cannot set time of day: Server world is not loaded.");
				return;
			}
			if (string.IsNullOrWhiteSpace(arguments) || !float.TryParse(arguments.Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out var result) || result < 0f || result > 1f)
			{
				Plugin.Log.LogWarning("Invalid parameters. Usage: tod <0-1> (e.g. tod 0.5 for noon)");
				return;
			}
			double timeSeconds = ZNet.instance.GetTimeSeconds();
			long num = (((Object)(object)EnvMan.instance != (Object)null && EnvMan.instance.m_dayLengthSec > 0) ? EnvMan.instance.m_dayLengthSec : 1800);
			long num2 = (long)(timeSeconds / (double)num);
			float num3 = Mathf.Clamp01(result);
			double num4 = (float)(num2 * num) + num3 * (float)num;
			if (num4 < timeSeconds)
			{
				num4 += (double)num;
			}
			if ((Object)(object)EnvMan.instance != (Object)null)
			{
				EnvMan.instance.m_debugTimeOfDay = false;
			}
			ZNet.instance.SetNetTime(num4);
			SynchronizeNetworkTime();
			Plugin.Log.LogInfo($"Setting time of day: {TerminalColor.Cyan}{result:G}{TerminalColor.Reset}");
		}

		public static void HandleSleepCommand()
		{
			if ((Object)(object)EnvMan.instance == (Object)null || (Object)(object)ZNet.instance == (Object)null)
			{
				Plugin.Log.LogWarning("Cannot skip time to morning: EnvMan/ZNet is not ready.");
				return;
			}
			EnvMan.instance.SkipToMorning();
			SynchronizeNetworkTime();
			int day = EnvMan.instance.GetDay();
			Plugin.Log.LogInfo($"Skipping time to morning (Day {TerminalColor.Cyan}{day + 1}{TerminalColor.Reset})...");
		}

		private static void SynchronizeNetworkTime()
		{
			try
			{
				SendNetTimeMethod?.Invoke(ZNet.instance, null);
			}
			catch
			{
			}
		}
	}
	[BepInPlugin("dreamwraith.ConsoleStdinHeeler", "ConsoleStdinHeeler", "1.0.1")]
	public class Plugin : BaseUnityPlugin
	{
		public enum ColorTagMode
		{
			Ansi,
			Strip,
			Raw
		}

		public const string ModGUID = "dreamwraith.ConsoleStdinHeeler";

		public const string ModName = "ConsoleStdinHeeler";

		public const string ModVersion = "1.0.1";

		public static ConfigEntry<bool> EnableMod;

		public static ConfigEntry<bool> EnableCheatsByDefault;

		public static ConfigEntry<ColorTagMode> ColorFormatting;

		public static ConfigEntry<string> ConsolePrompt;

		public static ConfigEntry<bool> EnableDebugLogs;

		private Harmony? _harmony;

		private const int MaxConsecutiveEofRetries = 3;

		private const int EofRetryIntervalMs = 1000;

		private readonly ConcurrentQueue<string> _commandQueue = new ConcurrentQueue<string>();

		private Thread? _stdinThread;

		private volatile bool _isRunning;

		private bool _hasAnnouncedServerReady;

		internal static Plugin? Instance { get; private set; }

		internal static PluginLogger Log { get; private set; }

		private void Awake()
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Expected O, but got Unknown
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Expected O, but got Unknown
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Expected O, but got Unknown
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Expected O, but got Unknown
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Expected O, but got Unknown
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: Expected O, but got Unknown
			Instance = this;
			Log = new PluginLogger(((BaseUnityPlugin)this).Logger);
			EnableMod = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - General", "EnableMod", true, new ConfigDescription("Master switch to enable or disable the STDIN console listener.", (AcceptableValueBase)null, Array.Empty<object>()));
			EnableCheatsByDefault = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - General", "EnableCheatsByDefault", true, new ConfigDescription("Allows modded and admin cheat commands to execute on the dedicated server.", (AcceptableValueBase)null, Array.Empty<object>()));
			ConsolePrompt = ((BaseUnityPlugin)this).Config.Bind<string>("2 - Display", "ConsolePrompt", "> ", new ConfigDescription("Prefix displayed in logs when an STDIN command is received.", (AcceptableValueBase)null, Array.Empty<object>()));
			ColorFormatting = ((BaseUnityPlugin)this).Config.Bind<ColorTagMode>("2 - Display", "ColorFormatting", ColorTagMode.Ansi, new ConfigDescription("How Unity rich-text color tags from console outputs are handled: Ansi (render in terminal colors), Strip (clean plain text), or Raw (keep tags unchanged).", (AcceptableValueBase)null, Array.Empty<object>()));
			EnableDebugLogs = ((BaseUnityPlugin)this).Config.Bind<bool>("9 - Debug", "EnableDebugLogs", false, new ConfigDescription("Enables verbose diagnostic logging.", (AcceptableValueBase)null, new object[1]
			{
				new ConfigurationManagerAttributes
				{
					IsAdvanced = true
				}
			}));
			if (!EnableMod.Value)
			{
				Log.LogInfo("ConsoleStdinHeeler is disabled in config.");
				return;
			}
			try
			{
				_harmony = new Harmony("dreamwraith.ConsoleStdinHeeler");
				_harmony.PatchAll(typeof(Plugin).Assembly);
			}
			catch (Exception ex)
			{
				Log.LogWarning("Failed to initialize Harmony patches: " + ex.Message);
			}
			if (IsDedicatedServerEnvironment())
			{
				StartStdinListener();
			}
			else
			{
				Log.LogInfo("Dedicated server environment not detected at Awake; listener deferred until networking initializes.");
			}
		}

		private void Update()
		{
			if (!_isRunning)
			{
				if (Time.frameCount % 30 != 0 || (Object)(object)ZNet.instance == (Object)null)
				{
					return;
				}
				if (!ZNet.instance.IsDedicated())
				{
					Log.LogInfo("Client environment detected (ZNet.instance.IsDedicated() is false). ConsoleStdinHeeler is disabling itself.");
					((Behaviour)this).enabled = false;
					return;
				}
				Log.LogInfo("Dedicated server confirmed via ZNet.instance.IsDedicated(); starting deferred STDIN listener.");
				StartStdinListener();
			}
			if (!_hasAnnouncedServerReady && (Object)(object)Game.instance != (Object)null && (Object)(object)ZoneSystem.instance != (Object)null)
			{
				_hasAnnouncedServerReady = true;
				Log.LogInfo(TerminalColor.Bold + TerminalColor.Green + "Server world loaded successfully. STDIN console ready for commands." + TerminalColor.Reset);
			}
			CommandCustom.Update();
			string result;
			while (_commandQueue.TryDequeue(out result))
			{
				CommandServer.Execute(result);
			}
		}

		private void OnDestroy()
		{
			StopListener();
			_stdinThread?.Interrupt();
			try
			{
				Harmony? harmony = _harmony;
				if (harmony != null)
				{
					harmony.UnpatchSelf();
				}
			}
			catch
			{
			}
		}

		internal void StopListener()
		{
			_isRunning = false;
		}

		private void StartStdinListener()
		{
			if (!_isRunning)
			{
				Console.SetConsoleEnabledForThisSession();
				_isRunning = true;
				_stdinThread = new Thread(ReadStdinLoop)
				{
					Name = "ConsoleStdinHeeler_Reader",
					IsBackground = true
				};
				_stdinThread.Start();
				Log.LogInfo(TerminalColor.Green + "ConsoleStdinHeeler v1.0.1 loaded successfully. STDIN listener started." + TerminalColor.Reset);
			}
		}

		private void ReadStdinLoop()
		{
			int num = 0;
			while (_isRunning)
			{
				try
				{
					string text = Console.ReadLine();
					if (text == null)
					{
						num++;
						if (num >= 3)
						{
							Log.LogInfo("STDIN stream closed or detached (EOF detected). Listener thread shutting down.");
							break;
						}
						Thread.Sleep(1000);
					}
					else
					{
						num = 0;
						text = text.Trim();
						if (text.Length > 0)
						{
							_commandQueue.Enqueue(text);
						}
					}
				}
				catch (ThreadAbortException)
				{
					break;
				}
				catch (ThreadInterruptedException)
				{
					break;
				}
				catch (Exception ex3)
				{
					Log.LogWarning("Exception in STDIN reader thread: " + ex3.Message);
					Thread.Sleep(1000);
				}
			}
		}

		private static bool IsDedicatedServerEnvironment()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Invalid comparison between Unknown and I4
			bool num = (int)SystemInfo.graphicsDeviceType == 4;
			string commandLine = Environment.CommandLine;
			bool flag = commandLine.IndexOf("valheim_server", StringComparison.OrdinalIgnoreCase) >= 0;
			bool flag2 = commandLine.IndexOf("-batchmode", StringComparison.OrdinalIgnoreCase) >= 0;
			return num || flag || flag2;
		}
	}
	internal class ConfigurationManagerAttributes
	{
		public bool? IsAdvanced { get; set; }

		public int? Order { get; set; }

		public bool? Browsable { get; set; }

		public Action<ConfigEntryBase>? CustomDrawer { get; set; }
	}
	public class PluginLogger
	{
		private readonly ManualLogSource _underlying;

		public PluginLogger(ManualLogSource underlying)
		{
			_underlying = underlying ?? throw new ArgumentNullException("underlying");
		}

		public void LogInfo(object data)
		{
			_underlying.LogInfo(data);
		}

		public void LogWarning(object data)
		{
			string text = data?.ToString() ?? string.Empty;
			string text2 = ((text.StartsWith("Warning:", StringComparison.OrdinalIgnoreCase) || text.StartsWith("[Warning]", StringComparison.OrdinalIgnoreCase)) ? text : ("Warning: " + text));
			_underlying.LogWarning((object)(TerminalColor.Yellow + text2 + TerminalColor.Reset));
		}

		public void LogError(object data)
		{
			string text = data?.ToString() ?? string.Empty;
			string text2 = ((text.StartsWith("Error:", StringComparison.OrdinalIgnoreCase) || text.StartsWith("[Error]", StringComparison.OrdinalIgnoreCase) || text.StartsWith("Failed:", StringComparison.OrdinalIgnoreCase) || text.StartsWith("Exception", StringComparison.OrdinalIgnoreCase)) ? text : ("Error: " + text));
			_underlying.LogError((object)(TerminalColor.Red + text2 + TerminalColor.Reset));
		}

		public void LogDebug(object data)
		{
			ConfigEntry<bool> enableDebugLogs = Plugin.EnableDebugLogs;
			if (enableDebugLogs != null && enableDebugLogs.Value)
			{
				_underlying.LogInfo((object)$"[DEBUG] {data}");
			}
		}

		public void LogMessage(object data)
		{
			_underlying.LogMessage(data);
		}

		public void LogFatal(object data)
		{
			_underlying.LogFatal(data);
		}

		public void Log(LogLevel level, object data)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0004: Invalid comparison between Unknown and I4
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Invalid comparison between Unknown and I4
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Invalid comparison between Unknown and I4
			if (level - 1 > 1)
			{
				if ((int)level != 4)
				{
					if ((int)level == 32)
					{
						LogDebug(data);
					}
					else
					{
						LogInfo(data);
					}
				}
				else
				{
					LogWarning(data);
				}
			}
			else
			{
				LogError(data);
			}
		}
	}
	public static class TerminalColor
	{
		private static bool Enabled
		{
			get
			{
				if (Plugin.ColorFormatting != null)
				{
					return Plugin.ColorFormatting.Value == Plugin.ColorTagMode.Ansi;
				}
				return true;
			}
		}

		public static string Reset
		{
			get
			{
				if (!Enabled)
				{
					return string.Empty;
				}
				return "\u001b[0m";
			}
		}

		public static string Bold
		{
			get
			{
				if (!Enabled)
				{
					return string.Empty;
				}
				return "\u001b[1m";
			}
		}

		public static string BoldReset
		{
			get
			{
				if (!Enabled)
				{
					return string.Empty;
				}
				return "\u001b[22m";
			}
		}

		public static string Default
		{
			get
			{
				if (!Enabled)
				{
					return string.Empty;
				}
				return "\u001b[39m";
			}
		}

		public static string Black
		{
			get
			{
				if (!Enabled)
				{
					return string.Empty;
				}
				return "\u001b[30m";
			}
		}

		public static string Gray
		{
			get
			{
				if (!Enabled)
				{
					return string.Empty;
				}
				return "\u001b[90m";
			}
		}

		public static string DarkGray => Gray;

		public static string Red
		{
			get
			{
				if (!Enabled)
				{
					return string.Empty;
				}
				return "\u001b[91m";
			}
		}

		public static string Green
		{
			get
			{
				if (!Enabled)
				{
					return string.Empty;
				}
				return "\u001b[92m";
			}
		}

		public static string Yellow
		{
			get
			{
				if (!Enabled)
				{
					return string.Empty;
				}
				return "\u001b[93m";
			}
		}

		public static string Blue
		{
			get
			{
				if (!Enabled)
				{
					return string.Empty;
				}
				return "\u001b[94m";
			}
		}

		public static string Magenta
		{
			get
			{
				if (!Enabled)
				{
					return string.Empty;
				}
				return "\u001b[95m";
			}
		}

		public static string Purple => Magenta;

		public static string Fuchsia => Magenta;

		public static string Cyan
		{
			get
			{
				if (!Enabled)
				{
					return string.Empty;
				}
				return "\u001b[96m";
			}
		}

		public static string Aqua => Cyan;

		public static string White
		{
			get
			{
				if (!Enabled)
				{
					return string.Empty;
				}
				return "\u001b[97m";
			}
		}

		public static string DarkRed
		{
			get
			{
				if (!Enabled)
				{
					return string.Empty;
				}
				return "\u001b[31m";
			}
		}

		public static string Maroon => DarkRed;

		public static string DarkGreen
		{
			get
			{
				if (!Enabled)
				{
					return string.Empty;
				}
				return "\u001b[32m";
			}
		}

		public static string DarkYellow
		{
			get
			{
				if (!Enabled)
				{
					return string.Empty;
				}
				return "\u001b[33m";
			}
		}

		public static string DarkBlue
		{
			get
			{
				if (!Enabled)
				{
					return string.Empty;
				}
				return "\u001b[34m";
			}
		}

		public static string Navy => DarkBlue;

		public static string DarkMagenta
		{
			get
			{
				if (!Enabled)
				{
					return string.Empty;
				}
				return "\u001b[35m";
			}
		}

		public static string DarkCyan
		{
			get
			{
				if (!Enabled)
				{
					return string.Empty;
				}
				return "\u001b[36m";
			}
		}

		public static string Teal => DarkCyan;

		public static string LightGray
		{
			get
			{
				if (!Enabled)
				{
					return string.Empty;
				}
				return "\u001b[37m";
			}
		}

		public static string Silver => LightGray;

		public static string Orange
		{
			get
			{
				if (!Enabled)
				{
					return string.Empty;
				}
				return "\u001b[38;2;255;165;0m";
			}
		}

		public static string Gold
		{
			get
			{
				if (!Enabled)
				{
					return string.Empty;
				}
				return "\u001b[38;2;234;168;0m";
			}
		}

		public static string Amber => Gold;

		public static string Lime
		{
			get
			{
				if (!Enabled)
				{
					return string.Empty;
				}
				return "\u001b[38;2;0;255;0m";
			}
		}

		public static string Olive
		{
			get
			{
				if (!Enabled)
				{
					return string.Empty;
				}
				return "\u001b[38;2;128;128;0m";
			}
		}

		public static string Brown
		{
			get
			{
				if (!Enabled)
				{
					return string.Empty;
				}
				return "\u001b[38;2;165;42;42m";
			}
		}

		public static string LightBlue
		{
			get
			{
				if (!Enabled)
				{
					return string.Empty;
				}
				return "\u001b[38;2;173;216;230m";
			}
		}

		public static string FromRgb(int r, int g, int b)
		{
			if (!Enabled)
			{
				return string.Empty;
			}
			return $"\u001b[38;2;{r};{g};{b}m";
		}

		public static string? FromHex(string hex)
		{
			if (!Enabled || string.IsNullOrWhiteSpace(hex))
			{
				return string.Empty;
			}
			hex = hex.TrimStart(new char[1] { '#' });
			if (hex.Length == 6 && byte.TryParse(hex.Substring(0, 2), NumberStyles.HexNumber, null, out var result) && byte.TryParse(hex.Substring(2, 2), NumberStyles.HexNumber, null, out var result2) && byte.TryParse(hex.Substring(4, 2), NumberStyles.HexNumber, null, out var result3))
			{
				return FromRgb(result, result2, result3);
			}
			return null;
		}

		public static string? FromName(string name)
		{
			if (string.IsNullOrWhiteSpace(name))
			{
				return null;
			}
			string text = name.Trim().ToLowerInvariant();
			if (text.StartsWith("#") || (text.Length == 6 && IsValidHex(text)))
			{
				string text2 = FromHex(text);
				if (text2 != null)
				{
					return text2;
				}
			}
			switch (text)
			{
			case "red":
				return Red;
			case "darkred":
			case "maroon":
				return DarkRed;
			case "green":
				return Green;
			case "darkgreen":
				return DarkGreen;
			case "lime":
				return Lime;
			case "yellow":
				return Yellow;
			case "darkyellow":
				return DarkYellow;
			case "orange":
				return Orange;
			case "amber":
			case "gold":
				return Gold;
			case "blue":
				return Blue;
			case "navy":
			case "darkblue":
				return DarkBlue;
			case "lightblue":
				return LightBlue;
			case "magenta":
			case "fuchsia":
				return Magenta;
			case "purple":
				return Purple;
			case "darkmagenta":
				return DarkMagenta;
			case "cyan":
			case "aqua":
				return Cyan;
			case "teal":
			case "darkcyan":
				return DarkCyan;
			case "white":
				return White;
			case "grey":
			case "gray":
			case "darkgray":
			case "darkgrey":
				return Gray;
			case "silver":
			case "lightgray":
			case "lightgrey":
				return LightGray;
			case "black":
				return Black;
			case "olive":
				return Olive;
			case "brown":
				return Brown;
			case "default":
				return Default;
			default:
				return null;
			}
		}

		private static bool IsValidHex(string s)
		{
			foreach (char c in s)
			{
				if ((c < '0' || c > '9') && (c < 'a' || c > 'f') && (c < 'A' || c > 'F'))
				{
					return false;
				}
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(Terminal))]
	public static class TerminalPatches
	{
		[HarmonyPatch("AddString", new Type[] { typeof(string) })]
		[HarmonyPrefix]
		private static void AddStringPrefix(ref string text)
		{
			if (!string.IsNullOrEmpty(text) && Plugin.ColorFormatting != null)
			{
				text = TerminalUtils.ProcessText(text, Plugin.ColorFormatting.Value);
			}
		}
	}
	public static class TerminalUtils
	{
		private static readonly Regex TagRegex = new Regex("<([^>]+)>", RegexOptions.Compiled);

		public static string ProcessText(string text, Plugin.ColorTagMode mode)
		{
			if (string.IsNullOrEmpty(text))
			{
				return text;
			}
			return mode switch
			{
				Plugin.ColorTagMode.Strip => StripRichTextTags(text), 
				Plugin.ColorTagMode.Ansi => ConvertRichTextToAnsi(text), 
				_ => text, 
			};
		}

		public static string StripRichTextTags(string input)
		{
			if (!string.IsNullOrEmpty(input) && input.IndexOf('<') >= 0)
			{
				return TagRegex.Replace(input, string.Empty);
			}
			return input;
		}

		public static string ConvertRichTextToAnsi(string input)
		{
			if (string.IsNullOrEmpty(input) || input.IndexOf('<') < 0)
			{
				return input;
			}
			bool appliedFormatting = false;
			string text = TagRegex.Replace(input, delegate(Match match)
			{
				string text2 = match.Groups[1].Value.Trim();
				if (text2.StartsWith("color=", StringComparison.OrdinalIgnoreCase))
				{
					string ansiColorCode = GetAnsiColorCode(text2.Substring(6).Trim().Trim(new char[1] { '"' }));
					if (ansiColorCode != null)
					{
						appliedFormatting = true;
						return ansiColorCode;
					}
					return string.Empty;
				}
				if (text2.Equals("/color", StringComparison.OrdinalIgnoreCase))
				{
					return TerminalColor.Reset;
				}
				if (text2.Equals("b", StringComparison.OrdinalIgnoreCase))
				{
					appliedFormatting = true;
					return TerminalColor.Bold;
				}
				return text2.Equals("/b", StringComparison.OrdinalIgnoreCase) ? TerminalColor.BoldReset : string.Empty;
			});
			if (appliedFormatting && !string.IsNullOrEmpty(TerminalColor.Reset) && !text.EndsWith(TerminalColor.Reset))
			{
				text += TerminalColor.Reset;
			}
			return text;
		}

		public static List<string> ParseArguments(string input)
		{
			List<string> list = new List<string>();
			if (string.IsNullOrWhiteSpace(input))
			{
				return list;
			}
			bool flag = false;
			StringBuilder stringBuilder = new StringBuilder();
			foreach (char c in input)
			{
				switch (c)
				{
				case '"':
					flag = !flag;
					continue;
				case ' ':
					if (!flag)
					{
						if (stringBuilder.Length > 0)
						{
							list.Add(stringBuilder.ToString());
							stringBuilder.Clear();
						}
						continue;
					}
					break;
				}
				stringBuilder.Append(c);
			}
			if (stringBuilder.Length > 0)
			{
				list.Add(stringBuilder.ToString());
			}
			return list;
		}

		private static string? GetAnsiColorCode(string colorSpec)
		{
			if (colorSpec.StartsWith("#"))
			{
				string text = colorSpec.Substring(1);
				if (text.Length == 3)
				{
					int r = Convert.ToInt32(new string(text[0], 2), 16);
					int g = Convert.ToInt32(new string(text[1], 2), 16);
					int b = Convert.ToInt32(new string(text[2], 2), 16);
					return TerminalColor.FromRgb(r, g, b);
				}
				if (text.Length >= 6)
				{
					int r2 = Convert.ToInt32(text.Substring(0, 2), 16);
					int g2 = Convert.ToInt32(text.Substring(2, 2), 16);
					int b2 = Convert.ToInt32(text.Substring(4, 2), 16);
					return TerminalColor.FromRgb(r2, g2, b2);
				}
				return null;
			}
			return TerminalColor.FromName(colorSpec);
		}
	}
	internal static class VersionInfo
	{
		public const string Version = "1.0.1";
	}
}