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.1.0")] [assembly: AssemblyInformationalVersion("0.1.1+58c8e9e0cf4f453ced7123d17397547eda32900a")] [assembly: AssemblyProduct("AndrewLin.OnTogether.Alpha")] [assembly: AssemblyTitle("AndrewLin.OnTogether.Alpha")] [assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/andrewlimforfun/ot-mods")] [assembly: AssemblyVersion("0.1.1.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.1")] public class AlphaPlugin : BaseUnityPlugin { private static readonly ConcurrentQueue _mainThreadQueue = new ConcurrentQueue(); public const string ModGUID = "com.andrewlin.ontogether.alpha"; public const string ModName = "Alpha"; public const string ModVersion = "0.1.1"; public static ConfigEntry? EnableFeature { get; private set; } public static ConfigEntry? ShowCommand { get; private set; } public static ConfigEntry? TimestampLog { get; private set; } public static ConfigEntry? SuppressPurrNetNullRef { get; private set; } public static ChatCommandManager? CommandManager { get; private set; } public static DateTime? ServerJoinTime { get; internal 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.1 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("General", "EnableFeature", true, "Enable or disable the mod feature."); ShowCommand = ((BaseUnityPlugin)this).Config.Bind("General", "ShowCommand", false, "Show the command in chat when used."); TimestampLog = ((BaseUnityPlugin)this).Config.Bind("Logging", "TimestampLog", true, "Prepend [HH:mm:ss] timestamps to each line in LogOutput.log and the console."); SuppressPurrNetNullRef = ((BaseUnityPlugin)this).Config.Bind("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.1"; } 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.1"; } } namespace Alpha.Patches { [HarmonyPatch(typeof(TextChannelManager))] public class TextChannelManagerPatch { [HarmonyPatch("Start")] [HarmonyPostfix] public static void Start_Postfix() { AlphaPlugin.ServerJoinTime = DateTime.UtcNow; } [HarmonyPatch("OnEnterPressed")] [HarmonyPrefix] public static void OnEnterPressedPrefix() { string text = MonoSingleton.I.MessageInput.text; if (!string.IsNullOrEmpty(text) && text.StartsWith('/') && AlphaPlugin.CommandManager != null) { bool flag = AlphaPlugin.CommandManager.ProcessInput(text); ConfigEntry? 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("]*>", RegexOptions.IgnoreCase | RegexOptions.Compiled); public const int MaxMessageLength = 250; public static void AddGlobalNotification(string text) { TextChannelManager i = NetworkSingleton.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.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.I.IsActive ? 5 : 0); MonoSingleton.I.SetLockState(lockState); EventSystem.current.SetSelectedGameObject((GameObject)null); string text = MonoSingleton.I.MessageInput.text; if (!text.StartsWith("/help")) { MonoSingleton.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.I.MessageInput; messageInput.text = text; ((UnityEvent)(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().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 _adminIds = new HashSet { "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.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.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 FindPlayers(Func 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.I; if ((Object)(object)i == (Object)null) { return new List(); } List list = new List(); 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 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.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 FindPlayersByQuery(string query) { string query2 = query; if (string.IsNullOrWhiteSpace(query2)) { return new List(); } 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().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 GetAllPlayers() { return FindPlayers((string _sid, PlayerID _pid, PlayerIDInfo _info, NetworkTransform _t) => true); } public static string GetLobbyCode() { return MonoSingleton.I.LobbyCode; } public static string GetLobbyName() { return MonoSingleton.I.LobbyName; } public static int GetPlayerCount() { return (NetworkSingleton.I?.IDInfos?.Count).GetValueOrDefault(); } public static int GetMaxPlayers() { //IL_000b: Unknown result type (might be due to invalid IL or missing references) return MonoSingleton.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.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 d__0 : IEnumerable, IEnumerable, IEnumerator, 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 5__1; string IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public 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; } 5__1 = 0; break; case 1: <>1__state = -1; 5__1 += maxLength; break; } if (5__1 < text.Length) { <>2__current = text.Substring(5__1, Math.Min(maxLength, text.Length - 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 IEnumerable.GetEnumerator() { d__0 d__; if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; d__ = this; } else { d__ = new d__0(0) { <>4__this = <>4__this }; } d__.text = <>3__text; d__.maxLength = <>3__maxLength; return d__; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } } [IteratorStateMachine(typeof(d__0))] public IEnumerable Chunk(string text, int maxLength) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__0(-2) { <>4__this = this, <>3__text = text, <>3__maxLength = maxLength }; } } public interface IStringChunker { IEnumerable Chunk(string text, int maxLength); } public class WordBoundaryChunker : IStringChunker { [CompilerGenerated] private sealed class d__0 : IEnumerable, IEnumerable, IEnumerator, 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 5__1; private int 5__2; private int 5__3; string IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public 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; } 5__1 = 0; break; case 1: <>1__state = -1; return false; case 2: <>1__state = -1; 5__1 += maxLength; break; case 3: <>1__state = -1; 5__1 = 5__3 + 1; break; } if (5__1 < this.text.Length) { 5__2 = this.text.Length - 5__1; int num; if (5__2 <= maxLength) { string text = this.text; num = 5__1; <>2__current = text.Substring(num, text.Length - num).Trim(); <>1__state = 1; return true; } 5__3 = this.text.LastIndexOf(' ', 5__1 + maxLength - 1, maxLength); if (5__3 <= 5__1) { string obj = this.text; num = 5__1; <>2__current = obj.Substring(num, 5__1 + maxLength - num); <>1__state = 2; return true; } string obj2 = this.text; num = 5__1; <>2__current = obj2.Substring(num, 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 IEnumerable.GetEnumerator() { d__0 d__; if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; d__ = this; } else { d__ = new d__0(0) { <>4__this = <>4__this }; } d__.text = <>3__text; d__.maxLength = <>3__maxLength; return d__; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } } [IteratorStateMachine(typeof(d__0))] public IEnumerable Chunk(string text, int maxLength) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new 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 _commands = new Dictionary(); private readonly Dictionary> _byNamespace = new Dictionary>(); 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 value)) { value = new List(); _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 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 { 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.CompareTo(IChatCommand? other) { if (other == null) { return 1; } return string.Compare(Name, other.Name, StringComparison.Ordinal); } } internal class NamespaceHelpCommand : IChatCommand, IComparable { private readonly string _namespace; private readonly List _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 commands) { _namespace = ns; _commands = commands; } public void Execute(string[] args) { SortedSet sortedSet = new SortedSet(_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 { 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 { 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 { 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 { 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(); string text = "unknown"; if (AlphaPlugin.ServerJoinTime.HasValue) { TimeSpan timeSpan = DateTime.UtcNow - AlphaPlugin.ServerJoinTime.Value; text = $"{(int)timeSpan.TotalHours:D2}h {timeSpan.Minutes:D2}m"; } string text2 = "Lobby Name: " + PlayerUtils.GetLobbyName() + "\nLobby Code: " + PlayerUtils.GetLobbyCode() + "\n" + $"Player Count: {PlayerUtils.GetPlayerCount()}/{PlayerUtils.GetMaxPlayers()}\n" + "Host Name: " + host?.UserName + "\nHost Steam: " + host?.SteamPersonaName + "\nSession Duration: " + text; _log.LogInfo((object)text2); ChatUtils.AddGlobalNotification(text2); } } public class AlphaUnloadUnusedAssetsCommand : IChatCommand, IComparable { 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 { 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_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: 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_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_0107: 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 list = PlayerUtils.FindPlayersByQuery(text); if (list.Count == 0) { ChatUtils.AddGlobalNotification("No players found matching \"" + text + "\"."); return; } string value = $"Found {list.Count} player(s) matching \"{text}\":"; StringBuilder stringBuilder = new StringBuilder(value); 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); stringBuilder.Append($"\n| {text2} | {text3} | {item.SteamID} | {item.Position} | {num} |"); } string text4 = stringBuilder.ToString(); _log.LogInfo((object)text4); ChatUtils.AddGlobalNotification(text4); } } }