Decompiled source of Alpha v0.1.0

AndrewLin.OnTogether.Alpha.dll

Decompiled 3 days ago
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using System.Xml;
using Alpha.Core.Command;
using Alpha.Core.Commands;
using Alpha.Core.Util;
using Alpha.Patches;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using PurrNet;
using Steamworks;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("AndrewLin")]
[assembly: AssemblyConfiguration("Publish")]
[assembly: AssemblyDescription("Alpha: A mod for On-Together to provide common utilities and features.")]
[assembly: AssemblyFileVersion("0.1.0.0")]
[assembly: AssemblyInformationalVersion("0.1.0+587928ff6442b995d7585cea51766753af75276d")]
[assembly: AssemblyProduct("AndrewLin.OnTogether.Alpha")]
[assembly: AssemblyTitle("AndrewLin.OnTogether.Alpha")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/andrewlimforfun/ot-mods")]
[assembly: AssemblyVersion("0.1.0.0")]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.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]
	[Microsoft.CodeAnalysis.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;
		}
	}
}
namespace Alpha
{
	[BepInPlugin("com.andrewlin.ontogether.alpha", "Alpha", "0.1.0")]
	public class AlphaPlugin : BaseUnityPlugin
	{
		private static readonly ConcurrentQueue<Action> _mainThreadQueue = new ConcurrentQueue<Action>();

		public const string ModGUID = "com.andrewlin.ontogether.alpha";

		public const string ModName = "Alpha";

		public const string ModVersion = "0.1.0";

		public static ConfigEntry<bool>? EnableFeature { get; private set; }

		public static ConfigEntry<bool>? ShowCommand { get; private set; }

		public static ConfigEntry<bool>? TimestampLog { get; private set; }

		public static ConfigEntry<bool>? SuppressPurrNetNullRef { get; private set; }

		public static ChatCommandManager? CommandManager { get; private set; }

		public static void RunOnMainThread(Action action)
		{
			_mainThreadQueue.Enqueue(action);
		}

		private void Awake()
		{
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Expected O, but got Unknown
			InitConfig();
			if (TimestampLog.Value)
			{
				TimestampLogListener.Install();
			}
			TimestampLogListener.SuppressPurrNetNullRef = SuppressPurrNetNullRef.Value;
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Alpha v0.1.0 is loaded!");
			Harmony val = new Harmony("com.andrewlin.ontogether.alpha");
			val.PatchAll(typeof(TextChannelManagerPatch));
			CommandManager = new ChatCommandManager();
			CommandManager.Register(new AlphaMyPositionCommand());
			CommandManager.Register(new AlphaWhoIsCommand());
			CommandManager.Register(new AlphaServerInfoCommand());
			CommandManager.Register(new AlphaAddNotificationCommand());
			CommandManager.Register(new AlphaUnloadUnusedAssetsCommand());
		}

		private void InitConfig()
		{
			EnableFeature = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "EnableFeature", true, "Enable or disable the mod feature.");
			ShowCommand = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ShowCommand", false, "Show the command in chat when used.");
			TimestampLog = ((BaseUnityPlugin)this).Config.Bind<bool>("Logging", "TimestampLog", true, "Prepend [HH:mm:ss] timestamps to each line in LogOutput.log and the console.");
			SuppressPurrNetNullRef = ((BaseUnityPlugin)this).Config.Bind<bool>("Logging", "SuppressPurrNetNullRef", true, "Suppress spammy PurrNet NetworkReflection NullReferenceException lines from LogOutput.log and the console (known PurrNet bug).");
		}

		private void Update()
		{
			Action result;
			while (_mainThreadQueue.TryDequeue(out result))
			{
				try
				{
					result();
				}
				catch (Exception ex)
				{
					((BaseUnityPlugin)this).Logger.LogError((object)("Main thread action failed: " + ex.Message));
				}
			}
		}

		private void Start()
		{
		}

		private void OnDestroy()
		{
		}
	}
	public static class BuildInfo
	{
		public const string Version = "0.1.0";
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "AndrewLin.OnTogether.Alpha";

		public const string PLUGIN_NAME = "AndrewLin.OnTogether.Alpha";

		public const string PLUGIN_VERSION = "0.1.0";
	}
}
namespace Alpha.Patches
{
	[HarmonyPatch(typeof(TextChannelManager))]
	public class TextChannelManagerPatch
	{
		[HarmonyPatch("OnEnterPressed")]
		[HarmonyPrefix]
		public static void OnEnterPressedPrefix()
		{
			string text = MonoSingleton<UIManager>.I.MessageInput.text;
			if (!string.IsNullOrEmpty(text) && text.StartsWith('/') && AlphaPlugin.CommandManager != null)
			{
				bool flag = AlphaPlugin.CommandManager.ProcessInput(text);
				ConfigEntry<bool>? showCommand = AlphaPlugin.ShowCommand;
				if (showCommand != null && !showCommand.Value && flag)
				{
					ChatUtils.CleanCommand();
				}
			}
		}
	}
}
namespace Alpha.Core.Util
{
	public static class ChatUtils
	{
		private static readonly Regex _commonTMPTagRegex = new Regex("</?(?:color|b|i|u|s|sup|sub|size|alpha|mark|cspace|width|uppercase|lowercase|smallcaps|font|voffset|nobr|noparse|sprite|link|align|rotate|#[0-9a-fA-F]{3,8})[^>]*>", RegexOptions.IgnoreCase | RegexOptions.Compiled);

		public const int MaxMessageLength = 250;

		public static void AddGlobalNotification(string text)
		{
			TextChannelManager i = NetworkSingleton<TextChannelManager>.I;
			if (!((Object)(object)i == (Object)null))
			{
				i.AddNotification(text);
			}
		}

		public static void SendMessageAsync(string userName, string text, bool IsLocal = false, string chunkStrategy = "word", Vector3? position = null)
		{
			string text2 = chunkStrategy.ToLower();
			if (1 == 0)
			{
			}
			IStringChunker stringChunker = ((!(text2 == "word")) ? ((IStringChunker)new HardCutChunker()) : ((IStringChunker)new WordBoundaryChunker()));
			if (1 == 0)
			{
			}
			IStringChunker stringChunker2 = stringChunker;
			foreach (string item in stringChunker2.Chunk(text, 250))
			{
				SendMessageTruncatedAsync(userName, item, IsLocal, position);
			}
		}

		public static void SendMessageTruncatedAsync(string userName, string text, bool IsLocal = false, Vector3? position = null)
		{
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			byte[] bytes = Encoding.Unicode.GetBytes(text.Substring(0, Math.Min(250, text.Length)));
			byte[] bytes2 = Encoding.Unicode.GetBytes(userName);
			string playerSteamID = SteamUtils.GetPlayerSteamID();
			TextChannelManager i = NetworkSingleton<TextChannelManager>.I;
			Transform mainPlayer = i.MainPlayer;
			i.SendMessageAsync(bytes, bytes2, IsLocal, (Vector3)(((??)position) ?? mainPlayer.position), playerSteamID, default(RPCInfo));
		}

		public static void CleanCommand()
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			LockState lockState = (LockState)(NetworkSingleton<MusicManager>.I.IsActive ? 5 : 0);
			MonoSingleton<TaskManager>.I.SetLockState(lockState);
			EventSystem.current.SetSelectedGameObject((GameObject)null);
			string text = MonoSingleton<UIManager>.I.MessageInput.text;
			if (!text.StartsWith("/help"))
			{
				MonoSingleton<UIManager>.I.MessageInput.text = "";
			}
		}

		public static string CleanTMPTags(string input)
		{
			return _commonTMPTagRegex.Replace(input, string.Empty);
		}

		public static void UISendMessage(string text)
		{
			TMP_InputField messageInput = MonoSingleton<UIManager>.I.MessageInput;
			messageInput.text = text;
			((UnityEvent<string>)(object)messageInput.onSubmit).Invoke(messageInput.text);
		}
	}
	public class PlayerDetail
	{
		public readonly string SteamID;

		public readonly PlayerID PlayerID;

		public readonly PlayerIDInfo PlayerIDInfo;

		public readonly NetworkTransform PlayerTransform;

		public TextMeshProUGUI UserNameTMP => ((Component)PlayerTransform).GetComponent<PlayerController>().PlayerNameText;

		public string UserName => ((TMP_Text)UserNameTMP).text;

		public string UserNameClean => ChatUtils.CleanTMPTags(UserName).Trim();

		public string SteamPersonaName => SteamUtils.GetSteamPersonaName(SteamID);

		public Vector3 Position => ((Component)PlayerTransform).transform.position;

		public PlayerDetail(string steamID, PlayerID playerID, PlayerIDInfo playerIDInfo, NetworkTransform playerTransform)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			SteamID = steamID;
			PlayerID = playerID;
			PlayerIDInfo = playerIDInfo;
			PlayerTransform = playerTransform;
		}
	}
	public static class PlayerLists
	{
		private static ManualLogSource _log = Logger.CreateLogSource("Alpha.PL");

		private static readonly HashSet<string> _adminIds = new HashSet<string> { "76561198144499930", "76561198729588983" };

		public static bool IsAdmin(string steamId)
		{
			if (string.IsNullOrEmpty(steamId))
			{
				return false;
			}
			return _adminIds.Contains(steamId);
		}
	}
	public static class PlayerUtils
	{
		private static readonly Regex _digitsRegex = new Regex("^\\d+$", RegexOptions.Compiled);

		private static ManualLogSource _log = Logger.CreateLogSource("Alpha.PU");

		public static string GetUserName()
		{
			string userName = NetworkSingleton<TextChannelManager>.I.UserName;
			if (string.IsNullOrEmpty(userName))
			{
				PlayerDetail playerDetail = GetPlayerDetail();
				if (playerDetail != null)
				{
					userName = playerDetail.UserName;
				}
			}
			return userName;
		}

		public static string GetUserNameNoFormat()
		{
			return ChatUtils.CleanTMPTags(GetUserName());
		}

		public static PlayerDetail? GetPlayerDetail()
		{
			try
			{
				PlayerDetail playerDetail = null;
				TextChannelManager i = NetworkSingleton<TextChannelManager>.I;
				PlayerID? playerId = ((i != null) ? ((NetworkIdentity)i).localPlayer : null);
				if (playerId.HasValue)
				{
					playerDetail = FindPlayer(delegate(string _sid, PlayerID _playerId, PlayerIDInfo _info, NetworkTransform _transform)
					{
						//IL_0000: Unknown result type (might be due to invalid IL or missing references)
						//IL_0001: Unknown result type (might be due to invalid IL or missing references)
						//IL_0015: Unknown result type (might be due to invalid IL or missing references)
						//IL_0018: Unknown result type (might be due to invalid IL or missing references)
						PlayerID? val = playerId;
						return val.HasValue && _playerId == val.GetValueOrDefault();
					});
				}
				if (playerDetail == null)
				{
					string playerSteamID = SteamUtils.GetPlayerSteamID();
					playerDetail = FindPlayerBySteamID(playerSteamID);
				}
				if (playerDetail == null)
				{
					_log.LogWarning((object)"Could not find player detail for local player.");
				}
				return playerDetail;
			}
			catch (Exception arg)
			{
				_log.LogError((object)$"Error getting player ID: {arg}");
				return null;
			}
		}

		public static List<PlayerDetail> FindPlayers(Func<string, PlayerID, PlayerIDInfo, NetworkTransform, bool> predicate)
		{
			//IL_0040: 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_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_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			PlayerPanelController i = NetworkSingleton<PlayerPanelController>.I;
			if ((Object)(object)i == (Object)null)
			{
				return new List<PlayerDetail>();
			}
			List<PlayerDetail> list = new List<PlayerDetail>();
			for (int j = 0; j < i.PlayerIDs.Count; j++)
			{
				string text = i.PlayerSteamIDs[j];
				PlayerID val = i.PlayerIDs[j];
				PlayerIDInfo val2 = i.IDInfos[j];
				NetworkTransform val3 = i.PlayerTransforms[j];
				if (predicate(text, val, val2, val3))
				{
					list.Add(new PlayerDetail(text, val, val2, val3));
				}
			}
			return list;
		}

		public static PlayerDetail? FindPlayer(Func<string, PlayerID, PlayerIDInfo, NetworkTransform, bool> predicate)
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			PlayerPanelController i = NetworkSingleton<PlayerPanelController>.I;
			if ((Object)(object)i == (Object)null)
			{
				return null;
			}
			for (int j = 0; j < i.PlayerIDs.Count; j++)
			{
				string text = i.PlayerSteamIDs[j];
				PlayerID val = i.PlayerIDs[j];
				PlayerIDInfo val2 = i.IDInfos[j];
				NetworkTransform val3 = i.PlayerTransforms[j];
				if (predicate(text, val, val2, val3))
				{
					return new PlayerDetail(text, val, val2, val3);
				}
			}
			return null;
		}

		public static PlayerDetail? FindPlayerBySteamID(string steamId)
		{
			string steamId2 = steamId;
			return FindPlayer((string _steamId, PlayerID _pid, PlayerIDInfo _info, NetworkTransform _transform) => _steamId == steamId2);
		}

		public static PlayerDetail? FindPlayerByQuery(string query)
		{
			string query2 = query;
			if (string.IsNullOrWhiteSpace(query2))
			{
				return null;
			}
			if (query2.Equals("_host", StringComparison.OrdinalIgnoreCase))
			{
				return GetHost();
			}
			return FindPlayer((string _steamId, PlayerID _pid, PlayerIDInfo _info, NetworkTransform _transform) => QueryMatchesPlayer(_steamId, _pid, _info, _transform, query2));
		}

		public static List<PlayerDetail> FindPlayersByQuery(string query)
		{
			string query2 = query;
			if (string.IsNullOrWhiteSpace(query2))
			{
				return new List<PlayerDetail>();
			}
			return FindPlayers((string _steamId, PlayerID _pid, PlayerIDInfo _info, NetworkTransform _transform) => QueryMatchesPlayer(_steamId, _pid, _info, _transform, query2));
		}

		private static bool QueryMatchesPlayer(string steamId, PlayerID id, PlayerIDInfo info, NetworkTransform transform, string query)
		{
			if (_digitsRegex.IsMatch(query) && steamId.EndsWith(query))
			{
				return true;
			}
			string text = ((TMP_Text)((Component)transform).GetComponent<PlayerController>().PlayerNameText).text;
			if (query.Contains("<") && text.StartsWith(query, StringComparison.OrdinalIgnoreCase))
			{
				return true;
			}
			string text2 = ChatUtils.CleanTMPTags(text).Trim();
			if (text2.Contains(query, StringComparison.OrdinalIgnoreCase))
			{
				return true;
			}
			try
			{
				if (Regex.IsMatch(text2, query, RegexOptions.IgnoreCase))
				{
					return true;
				}
			}
			catch (ArgumentException)
			{
			}
			string steamPersonaName = SteamUtils.GetSteamPersonaName(steamId);
			if (steamPersonaName != null && steamPersonaName.Contains(query, StringComparison.OrdinalIgnoreCase))
			{
				return true;
			}
			return false;
		}

		public static PlayerDetail? GetHost()
		{
			PlayerDetail playerDetail = FindPlayer((string _sid, PlayerID _playerId, PlayerIDInfo _info, NetworkTransform _transform) => ((PlayerID)(ref _playerId)).isServer);
			if (playerDetail == null)
			{
				string hostSteamId = SteamUtils.GetLobbyOwnerSteamID();
				playerDetail = FindPlayer((string steamId, PlayerID _pid, PlayerIDInfo _info, NetworkTransform _t) => steamId == hostSteamId);
			}
			if (playerDetail == null)
			{
				_log.LogWarning((object)"Could not find host player in PlayerIDs.");
			}
			return playerDetail;
		}

		public static List<PlayerDetail> GetAllPlayers()
		{
			return FindPlayers((string _sid, PlayerID _pid, PlayerIDInfo _info, NetworkTransform _t) => true);
		}

		public static string GetLobbyCode()
		{
			return MonoSingleton<MultiplayerManager>.I.LobbyCode;
		}

		public static string GetLobbyName()
		{
			return MonoSingleton<MultiplayerManager>.I.LobbyName;
		}

		public static int GetPlayerCount()
		{
			return (NetworkSingleton<PlayerPanelController>.I?.IDInfos?.Count).GetValueOrDefault();
		}

		public static int GetMaxPlayers()
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			return MonoSingleton<MultiplayerManager>.I._lobbyManager.CurrentLobby.MaxPlayers;
		}
	}
	public static class SteamUtils
	{
		public static bool IsSteamID(string value)
		{
			ulong result;
			return value != null && value.Length == 17 && ulong.TryParse(value, out result);
		}

		public static string GetPlayerSteamID()
		{
			//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)
			CSteamID steamID = SteamUser.GetSteamID();
			return ((object)(CSteamID)(ref steamID)).ToString();
		}

		public static string GetSteamPersonaName()
		{
			return SteamFriends.GetPersonaName();
		}

		public static string GetSteamPersonaName(string steamId)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			return SteamFriends.GetFriendPersonaName(new CSteamID(ulong.Parse(steamId)));
		}

		public static string GetLobbyOwnerSteamID()
		{
			//IL_0019: 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)
			string lobbyCode = MonoSingleton<MultiplayerManager>.I.LobbyCode;
			CSteamID val = default(CSteamID);
			((CSteamID)(ref val))..ctor(ulong.Parse(lobbyCode));
			CSteamID lobbyOwner = SteamMatchmaking.GetLobbyOwner(val);
			return ((object)(CSteamID)(ref lobbyOwner)).ToString();
		}
	}
	public class HardCutChunker : IStringChunker
	{
		[CompilerGenerated]
		private sealed class <Chunk>d__0 : IEnumerable<string>, IEnumerable, IEnumerator<string>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private string <>2__current;

			private int <>l__initialThreadId;

			private string text;

			public string <>3__text;

			private int maxLength;

			public int <>3__maxLength;

			public HardCutChunker <>4__this;

			private int <start>5__1;

			string IEnumerator<string>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <Chunk>d__0(int <>1__state)
			{
				this.<>1__state = <>1__state;
				<>l__initialThreadId = Environment.CurrentManagedThreadId;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					if (string.IsNullOrEmpty(text))
					{
						return false;
					}
					<start>5__1 = 0;
					break;
				case 1:
					<>1__state = -1;
					<start>5__1 += maxLength;
					break;
				}
				if (<start>5__1 < text.Length)
				{
					<>2__current = text.Substring(<start>5__1, Math.Min(maxLength, text.Length - <start>5__1));
					<>1__state = 1;
					return true;
				}
				return false;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}

			[DebuggerHidden]
			IEnumerator<string> IEnumerable<string>.GetEnumerator()
			{
				<Chunk>d__0 <Chunk>d__;
				if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId)
				{
					<>1__state = 0;
					<Chunk>d__ = this;
				}
				else
				{
					<Chunk>d__ = new <Chunk>d__0(0)
					{
						<>4__this = <>4__this
					};
				}
				<Chunk>d__.text = <>3__text;
				<Chunk>d__.maxLength = <>3__maxLength;
				return <Chunk>d__;
			}

			[DebuggerHidden]
			IEnumerator IEnumerable.GetEnumerator()
			{
				return ((IEnumerable<string>)this).GetEnumerator();
			}
		}

		[IteratorStateMachine(typeof(<Chunk>d__0))]
		public IEnumerable<string> Chunk(string text, int maxLength)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <Chunk>d__0(-2)
			{
				<>4__this = this,
				<>3__text = text,
				<>3__maxLength = maxLength
			};
		}
	}
	public interface IStringChunker
	{
		IEnumerable<string> Chunk(string text, int maxLength);
	}
	public class WordBoundaryChunker : IStringChunker
	{
		[CompilerGenerated]
		private sealed class <Chunk>d__0 : IEnumerable<string>, IEnumerable, IEnumerator<string>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private string <>2__current;

			private int <>l__initialThreadId;

			private string text;

			public string <>3__text;

			private int maxLength;

			public int <>3__maxLength;

			public WordBoundaryChunker <>4__this;

			private int <start>5__1;

			private int <remaining>5__2;

			private int <cut>5__3;

			string IEnumerator<string>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <Chunk>d__0(int <>1__state)
			{
				this.<>1__state = <>1__state;
				<>l__initialThreadId = Environment.CurrentManagedThreadId;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					if (string.IsNullOrEmpty(this.text))
					{
						return false;
					}
					<start>5__1 = 0;
					break;
				case 1:
					<>1__state = -1;
					return false;
				case 2:
					<>1__state = -1;
					<start>5__1 += maxLength;
					break;
				case 3:
					<>1__state = -1;
					<start>5__1 = <cut>5__3 + 1;
					break;
				}
				if (<start>5__1 < this.text.Length)
				{
					<remaining>5__2 = this.text.Length - <start>5__1;
					int num;
					if (<remaining>5__2 <= maxLength)
					{
						string text = this.text;
						num = <start>5__1;
						<>2__current = text.Substring(num, text.Length - num).Trim();
						<>1__state = 1;
						return true;
					}
					<cut>5__3 = this.text.LastIndexOf(' ', <start>5__1 + maxLength - 1, maxLength);
					if (<cut>5__3 <= <start>5__1)
					{
						string obj = this.text;
						num = <start>5__1;
						<>2__current = obj.Substring(num, <start>5__1 + maxLength - num);
						<>1__state = 2;
						return true;
					}
					string obj2 = this.text;
					num = <start>5__1;
					<>2__current = obj2.Substring(num, <cut>5__3 - num).Trim();
					<>1__state = 3;
					return true;
				}
				return false;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}

			[DebuggerHidden]
			IEnumerator<string> IEnumerable<string>.GetEnumerator()
			{
				<Chunk>d__0 <Chunk>d__;
				if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId)
				{
					<>1__state = 0;
					<Chunk>d__ = this;
				}
				else
				{
					<Chunk>d__ = new <Chunk>d__0(0)
					{
						<>4__this = <>4__this
					};
				}
				<Chunk>d__.text = <>3__text;
				<Chunk>d__.maxLength = <>3__maxLength;
				return <Chunk>d__;
			}

			[DebuggerHidden]
			IEnumerator IEnumerable.GetEnumerator()
			{
				return ((IEnumerable<string>)this).GetEnumerator();
			}
		}

		[IteratorStateMachine(typeof(<Chunk>d__0))]
		public IEnumerable<string> Chunk(string text, int maxLength)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <Chunk>d__0(-2)
			{
				<>4__this = this,
				<>3__text = text,
				<>3__maxLength = maxLength
			};
		}
	}
	internal static class TimestampLogListener
	{
		private sealed class TimestampedDiskLogListener : ILogListener, IDisposable
		{
			private readonly TextWriter? _writer;

			private readonly LogLevel _displayedLogLevel;

			internal TimestampedDiskLogListener(TextWriter? writer, LogLevel displayedLogLevel)
			{
				//IL_0010: Unknown result type (might be due to invalid IL or missing references)
				//IL_0011: Unknown result type (might be due to invalid IL or missing references)
				_writer = writer;
				_displayedLogLevel = displayedLogLevel;
			}

			public void LogEvent(object sender, LogEventArgs eventArgs)
			{
				//IL_0015: Unknown result type (might be due to invalid IL or missing references)
				//IL_001b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0020: Unknown result type (might be due to invalid IL or missing references)
				//IL_0022: Invalid comparison between Unknown and I4
				try
				{
					if (_writer == null || (eventArgs.Level & _displayedLogLevel) == 0)
					{
						return;
					}
					if (SuppressPurrNetNullRef)
					{
						object data = eventArgs.Data;
						if (data != null && (data.ToString()?.Contains("PurrNet.NetworkReflection.ObserversRpc_Original_1")).GetValueOrDefault())
						{
							return;
						}
					}
					_writer.WriteLine(FormatWithTimestamp(eventArgs));
				}
				catch (ObjectDisposedException)
				{
				}
				catch (Exception ex2)
				{
					Diag("LogEvent threw: " + ex2.GetType().Name + ": " + ex2.Message);
				}
			}

			public void Dispose()
			{
			}
		}

		private const string PurrNetNullRefMarker = "PurrNet.NetworkReflection.ObserversRpc_Original_1";

		private static readonly string DiagPath = Path.Combine(Paths.BepInExRootPath, "TimestampLogListener.diag.log");

		internal static bool SuppressPurrNetNullRef { get; set; }

		private static void Diag(string msg)
		{
			try
			{
				File.AppendAllText(DiagPath, $"[{DateTime.Now:HH:mm:ss.fff}] {msg}{Environment.NewLine}");
			}
			catch
			{
			}
		}

		internal static void Install()
		{
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: 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_00fd: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				Diag("Install() begin");
				DiskLogListener val = null;
				ILogListener[] array = Logger.Listeners.ToArray();
				Diag($"Listeners snapshot count: {array.Length}");
				ILogListener[] array2 = array;
				foreach (ILogListener val2 in array2)
				{
					Diag("  Found listener: " + ((object)val2).GetType().FullName);
					DiskLogListener val3 = (DiskLogListener)(object)((val2 is DiskLogListener) ? val2 : null);
					if (val3 != null)
					{
						val = val3;
					}
				}
				if (val != null)
				{
					Diag($"DiskLogListener.LogWriter is null: {val.LogWriter == null}");
					TextWriter logWriter = val.LogWriter;
					LogLevel displayedLogLevel = val.DisplayedLogLevel;
					Diag($"DisplayedLogLevel: {displayedLogLevel}");
					Logger.Listeners.Remove((ILogListener)(object)val);
					Diag($"DiskLogListener removed. Writer still non-null: {logWriter != null}");
					Logger.Listeners.Add((ILogListener)(object)new TimestampedDiskLogListener(logWriter, displayedLogLevel));
					Diag("TimestampedDiskLogListener added OK");
				}
				else
				{
					Diag("No DiskLogListener found - nothing to replace");
				}
				Diag("Install() complete");
			}
			catch (Exception ex)
			{
				Diag("Install() FAILED: " + ex.GetType().Name + ": " + ex.Message);
				Diag(ex.StackTrace ?? "(no stack trace)");
			}
		}

		private static string FormatWithTimestamp(LogEventArgs eventArgs)
		{
			return $"[{DateTime.Now:HH:mm:ss}] {eventArgs}";
		}
	}
	public static class TimeUtils
	{
		public static bool TryParseDuration(string input, out TimeSpan result)
		{
			string text = input.ToUpperInvariant();
			string s = (text.StartsWith("P") ? text : ("PT" + text));
			try
			{
				result = XmlConvert.ToTimeSpan(s);
				return true;
			}
			catch
			{
			}
			return TimeSpan.TryParse(input, out result);
		}
	}
	public sealed class TokenValidator
	{
		private static readonly ManualLogSource _log = Logger.CreateLogSource("Alpha.TV");

		private readonly string _secretHash;

		public TokenValidator(string secretHash)
		{
			_secretHash = secretHash;
		}

		public bool IsValid(string? token)
		{
			if (string.IsNullOrEmpty(_secretHash))
			{
				return true;
			}
			if (string.IsNullOrEmpty(token))
			{
				_log.LogWarning((object)"Token is null or empty.");
				return false;
			}
			using SHA256 sHA = SHA256.Create();
			byte[] array = sHA.ComputeHash(Encoding.UTF8.GetBytes(token));
			string text = BitConverter.ToString(array).Replace("-", "").ToLower();
			bool flag = text == _secretHash;
			if (!flag)
			{
				_log.LogWarning((object)("Invalid token. Computed hash: " + text + " does not match expected hash."));
			}
			else
			{
				_log.LogInfo((object)"Token is valid.");
			}
			return flag;
		}
	}
}
namespace Alpha.Core.Command
{
	public class ChatCommandArgs
	{
		public static readonly ChatCommandArgs EMPTY = new ChatCommandArgs("", new string[0]);

		public string Name { get; }

		public string[] Args { get; }

		public ChatCommandArgs(string name, string[] args)
		{
			Name = name;
			Args = args;
		}

		public static bool TryParse(string input, out ChatCommandArgs result)
		{
			if (string.IsNullOrWhiteSpace(input) || !input.StartsWith('/'))
			{
				result = EMPTY;
				return false;
			}
			string text = input.Trim();
			string[] array = text.Substring(1, text.Length - 1).Split(' ', StringSplitOptions.RemoveEmptyEntries);
			string name = array[0].ToLower();
			string[] args = array.Skip(1).ToArray();
			result = new ChatCommandArgs(name, args);
			return true;
		}

		public override string ToString()
		{
			return "/" + Name + " " + string.Join(' ', Args);
		}
	}
	public class ChatCommandManager
	{
		private readonly ManualLogSource _log = Logger.CreateLogSource("Alpha.CM");

		private readonly Dictionary<string, IChatCommand> _commands = new Dictionary<string, IChatCommand>();

		private readonly Dictionary<string, List<IChatCommand>> _byNamespace = new Dictionary<string, List<IChatCommand>>();

		public void Register(IChatCommand? command)
		{
			if (command == null || string.IsNullOrWhiteSpace(command.Name))
			{
				_log.LogWarning((object)("Attempted to register null or nameless command: " + (command?.GetType().Name ?? "null")));
				return;
			}
			_commands[command.Name] = command;
			if (!string.IsNullOrWhiteSpace(command.ShortName))
			{
				_commands[command.ShortName] = command;
			}
			string text = command.Namespace ?? "";
			if (!string.IsNullOrWhiteSpace(text))
			{
				if (!_byNamespace.TryGetValue(text, out List<IChatCommand> value))
				{
					value = new List<IChatCommand>();
					_byNamespace[text] = value;
					NamespaceHelpCommand namespaceHelpCommand = new NamespaceHelpCommand(text, value);
					_commands[namespaceHelpCommand.Name] = namespaceHelpCommand;
					if (!string.IsNullOrWhiteSpace(namespaceHelpCommand.ShortName) && !_commands.ContainsKey(namespaceHelpCommand.ShortName))
					{
						_commands[namespaceHelpCommand.ShortName] = namespaceHelpCommand;
					}
					_log.LogInfo((object)("Auto-registered help: /" + namespaceHelpCommand.Name + " (/" + namespaceHelpCommand.ShortName + ")"));
				}
				if (!value.Contains(command))
				{
					value.Add(command);
				}
			}
			string text2 = (string.IsNullOrWhiteSpace(command.ShortName) ? "" : (" (/" + command.ShortName + ")"));
			_log.LogInfo((object)("Registered command: /" + command.Name + text2 + " [" + text + "]"));
		}

		public bool ContainsCommand(string commandName)
		{
			return _commands.ContainsKey(commandName);
		}

		public IEnumerable<IChatCommand> GetAllCommands()
		{
			return _commands.Values.Distinct();
		}

		public bool ProcessInput(string input)
		{
			if (!ChatCommandArgs.TryParse(input, out ChatCommandArgs result))
			{
				return false;
			}
			if (_commands.TryGetValue(result.Name, out IChatCommand value))
			{
				_log.LogInfo((object)$"Executing command: {result}");
				try
				{
					value.Execute(result.Args);
				}
				catch (Exception ex)
				{
					ChatUtils.AddGlobalNotification($"Error executing '{result}': {ex.Message}");
				}
				return true;
			}
			return false;
		}
	}
	public interface IChatCommand : IComparable<IChatCommand>
	{
		string Name { get; }

		string ShortName => "";

		string Description { get; }

		string Namespace { get; }

		bool IsHidden => false;

		void Execute(string[] args);

		new string ToString()
		{
			return Name;
		}

		int IComparable<IChatCommand>.CompareTo(IChatCommand? other)
		{
			if (other == null)
			{
				return 1;
			}
			return string.Compare(Name, other.Name, StringComparison.Ordinal);
		}
	}
	internal class NamespaceHelpCommand : IChatCommand, IComparable<IChatCommand>
	{
		private readonly string _namespace;

		private readonly List<IChatCommand> _commands;

		public string Name => _namespace + "help";

		public string ShortName => (_namespace.Length >= 1) ? (_namespace.Substring(0, 1) + "h") : "";

		public string Description => "Lists all " + _namespace + " commands.";

		public string Namespace => "";

		public NamespaceHelpCommand(string ns, List<IChatCommand> commands)
		{
			_namespace = ns;
			_commands = commands;
		}

		public void Execute(string[] args)
		{
			SortedSet<IChatCommand> sortedSet = new SortedSet<IChatCommand>(_commands);
			bool flag = args.Length == 1 && (args[0].ToLower() == "verbose" || args[0].ToLower() == "v");
			bool flag2 = args.Length == 1 && !flag;
			if (args.Length == 0 || flag)
			{
				StringBuilder stringBuilder = new StringBuilder("/" + _namespace + "help - available commands:");
				foreach (IChatCommand item in sortedSet)
				{
					if (!item.IsHidden)
					{
						string text = (string.IsNullOrWhiteSpace(item.ShortName) ? "" : (" (/" + item.ShortName + ")"));
						string text2 = (flag ? (": " + item.Description) : "");
						stringBuilder.Append("\n/" + item.Name + text + text2);
					}
				}
				ChatUtils.AddGlobalNotification(stringBuilder.ToString());
			}
			else if (flag2)
			{
				string needle = args[0].ToLower();
				IChatCommand chatCommand = sortedSet.FirstOrDefault((IChatCommand c) => c.Name == needle || c.ShortName == needle);
				if (chatCommand != null)
				{
					string text3 = (string.IsNullOrWhiteSpace(chatCommand.ShortName) ? "" : (" (/" + chatCommand.ShortName + ")"));
					ChatUtils.AddGlobalNotification("/" + chatCommand.Name + text3 + ": " + chatCommand.Description);
				}
				else
				{
					ChatUtils.AddGlobalNotification("Unknown command '" + needle + "'. Type /" + _namespace + "help for a list.");
				}
			}
		}
	}
}
namespace Alpha.Core.Commands
{
	public class AlphaAddNotificationCommand : IChatCommand, IComparable<IChatCommand>
	{
		private static readonly ManualLogSource _log = Logger.CreateLogSource("Alpha.AANPC");

		public string Name => "alphaaddnotification";

		public string ShortName => "aan";

		public string Description => "Add a notification. Usage: /alphaaddnotification [message]";

		public string Namespace => "alpha";

		public void Execute(string[] args)
		{
			if (args.Length == 0)
			{
				ChatUtils.AddGlobalNotification("Usage: /alphaaddnotification [message]");
				return;
			}
			string text = string.Join(" ", args).Trim();
			_log.LogInfo((object)("Adding notification: " + text));
			ChatUtils.AddGlobalNotification(text);
		}
	}
	public class AlphaMyPositionCommand : IChatCommand, IComparable<IChatCommand>
	{
		public string Name => "alphamyposition";

		public string ShortName => "amp";

		public string Description => "Show your current position. Usage: /alphamyposition";

		public string Namespace => "alpha";

		public void Execute(string[] args)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = PlayerUtils.GetPlayerDetail()?.Position ?? Vector3.zero;
			ChatUtils.AddGlobalNotification($"Your current position: {val}");
		}
	}
	public class AlphaQuitCommand : IChatCommand, IComparable<IChatCommand>
	{
		private static readonly ManualLogSource _log = Logger.CreateLogSource("Alpha.AQC");

		public string Name => "alphaquit";

		public string ShortName => "aq";

		public string Description => "Quit the game. Usage: /alphaquit";

		public string Namespace => "alpha";

		public bool IsHidden => true;

		public void Execute(string[] args)
		{
			_log.LogWarning((object)"Quitting game via /alphaquit command.");
			Application.Quit();
		}
	}
	public class AlphaServerInfoCommand : IChatCommand, IComparable<IChatCommand>
	{
		private static readonly ManualLogSource _log = Logger.CreateLogSource("Alpha.ASIC");

		public string Name => "alphaserverinfo";

		public string ShortName => "asi";

		public string Description => "Show server information. Usage: /alphaserverinfo";

		public string Namespace => "alpha";

		public void Execute(string[] args)
		{
			PlayerDetail host = PlayerUtils.GetHost();
			ChatUtils.AddGlobalNotification("Lobby Name: " + PlayerUtils.GetLobbyName() + "\nLobby Code: " + PlayerUtils.GetLobbyCode() + "\n" + $"Player Count: {PlayerUtils.GetPlayerCount()}/{PlayerUtils.GetMaxPlayers()}\n" + "Host: " + host?.UserName + " (Steam: " + host?.SteamPersonaName + ")");
		}
	}
	public class AlphaUnloadUnusedAssetsCommand : IChatCommand, IComparable<IChatCommand>
	{
		private static readonly ManualLogSource _log = Logger.CreateLogSource("Alpha.AUUA");

		public string Name => "alphaunloadunusedassets";

		public string ShortName => "auua";

		public string Description => "Unload unused Unity assets. Usage: /alphaunloadunusedassets";

		public string Namespace => "alpha";

		public void Execute(string[] args)
		{
			_log.LogInfo((object)"Unloading unused assets via /alphaunloadunusedassets command.");
			ChatUtils.AddGlobalNotification("Unloading unused assets...");
			Resources.UnloadUnusedAssets();
		}
	}
	public class AlphaWhoIsCommand : IChatCommand, IComparable<IChatCommand>
	{
		private static readonly ManualLogSource _log = Logger.CreateLogSource("Alpha.AWIC");

		public string Name => "alphawhois";

		public string ShortName => "awi";

		public string Description => "Show information about a player. Usage: /alphawhois [player]";

		public string Namespace => "alpha";

		public void Execute(string[] args)
		{
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			if (args.Length == 0)
			{
				ChatUtils.AddGlobalNotification("Usage: /alphawhois [player]");
				return;
			}
			string text = string.Join(" ", args).Trim();
			List<PlayerDetail> list = PlayerUtils.FindPlayersByQuery(text);
			if (list.Count == 0)
			{
				ChatUtils.AddGlobalNotification("No players found matching \"" + text + "\".");
				return;
			}
			_log.LogInfo((object)$"Found {list.Count} player(s) matching \"{text}\":");
			ChatUtils.AddGlobalNotification($"Found {list.Count} player(s) matching \"{text}\":");
			foreach (PlayerDetail item in list)
			{
				string text2 = ChatUtils.CleanTMPTags(item.UserName).Trim();
				string text3 = item.SteamPersonaName ?? "?";
				Vector3 val = PlayerUtils.GetPlayerDetail()?.Position ?? Vector3.zero;
				int num = (int)Vector3.Distance(item.Position, val);
				string text4 = $"{text2} | {text3} | {item.SteamID}  | {item.Position} ({num})";
				_log.LogInfo((object)text4);
				ChatUtils.AddGlobalNotification(text4);
			}
		}
	}
}