Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of ChaosTricks RoR2 TwitchIntegration v1.0.0
ChaosTricks_RoR2_plugins/EventsIO.dll
Decompiled 2 years agousing System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text; using EventsIO.Interfaces; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("EventIO")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("BFT")] [assembly: AssemblyProduct("EventIO")] [assembly: AssemblyCopyright("Copyright © 2020")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("ab7abff2-5203-43d0-88ed-aebd4b6a130c")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyVersion("1.0.0.0")] namespace EventsIO { public class EventsData : IEventsData { public string Username { get; set; } public string Cost { get; set; } public string EventID { get; set; } public string Lang { get; set; } public string ExtraInfo { get; set; } public override string ToString() { return "EventsData: " + Username + " " + Cost + " " + EventID + " " + Lang + " " + ExtraInfo; } } public class EventsDataEncoder : IEventsDataEncoder, IEventsDataEncoderParams { internal static readonly string clientAppSep = "&"; internal static readonly char clientAppSepChar = '&'; internal static readonly string clientAppEqual = "="; internal static readonly char clientAppEqualChar = '='; protected static readonly Dictionary<string, string> symbolCodes = new Dictionary<string, string> { { clientAppSep, "%encode_amp%" }, { clientAppEqual, "%encode_equal%" } }; string IEventsDataEncoderParams.ClientAppSep => clientAppSep; char IEventsDataEncoderParams.ClientAppSepChar => clientAppSepChar; string IEventsDataEncoderParams.ClientAppEqual => clientAppEqual; char IEventsDataEncoderParams.ClientAppEqualChar => clientAppEqualChar; public virtual string Encode(string s) { foreach (KeyValuePair<string, string> symbolCode in symbolCodes) { s = s?.Replace(symbolCode.Key, symbolCode.Value); } return s; } public virtual string Decode(string s) { foreach (KeyValuePair<string, string> symbolCode in symbolCodes) { s = s?.Replace(symbolCode.Value, symbolCode.Key); } return s; } } public class EventsDataParser : IEventsDataParser { protected readonly Action<string> log; protected readonly IEventsDataEncoder encoder; protected readonly IEventsDataEncoderParams encoderParams; public bool isLogInfoError = true; public bool isLogSkipEmpty; public EventsDataParser(Action<string> log = null) { this.log = log; encoderParams = (IEventsDataEncoderParams)(encoder = new EventsDataEncoder()); } protected virtual void ParserLog(string s) { log?.Invoke(s); } public virtual IEventsData ParseEvent(string data) { EventsData eventsData = new EventsData(); string[] array = data.Split(new char[1] { encoderParams.ClientAppSepChar }, StringSplitOptions.RemoveEmptyEntries); if (array == null) { if (isLogInfoError) { ParserLog("get event info error. Wrong args."); } return eventsData; } string[] array2 = array; foreach (string text in array2) { string[] array3 = text.Split(new char[1] { encoderParams.ClientAppEqualChar }, StringSplitOptions.RemoveEmptyEntries); if (array3.Length != 2) { if (isLogSkipEmpty) { ParserLog("skip empty item: " + text); } continue; } string text2 = encoder.Decode(array3[0]); string text3 = encoder.Decode(array3[1]); switch (text2.ToLowerInvariant()) { case "username": eventsData.Username = text3; break; case "eventid": eventsData.EventID = text3; break; case "cost": eventsData.Cost = text3; break; case "lang": eventsData.Lang = text3; break; case "extrainfo": eventsData.ExtraInfo = text3; break; } } return eventsData; } } public class EventsGenerator : IEventsGenerator { protected internal enum FieldNames { UserName, EventID, Cost, Lang, ExtraInfo } protected EventsData data; protected readonly IEventsDataEncoder encoder; protected readonly IEventsDataEncoderParams encoderParams; public EventsGenerator() { data = new EventsData(); encoderParams = (IEventsDataEncoderParams)(encoder = new EventsDataEncoder()); } public virtual void SetCost(string s) { data.Cost = encoder.Encode(s); } public virtual void SetEventID(string s) { data.EventID = encoder.Encode(s); } public virtual void SetLang(string s) { data.Lang = encoder.Encode(s); } public virtual void SetUsername(string s) { data.Username = encoder.Encode(s); } public virtual void SetExtraInfo(string s) { data.ExtraInfo = encoder.Encode(s); } public virtual string Generate() { Dictionary<FieldNames, string> obj = new Dictionary<FieldNames, string> { { FieldNames.UserName, data.Username }, { FieldNames.Cost, data.Cost }, { FieldNames.EventID, data.EventID }, { FieldNames.Lang, data.Lang }, { FieldNames.ExtraInfo, data.ExtraInfo } }; StringBuilder stringBuilder = new StringBuilder(obj.Count); string clientAppSep = encoderParams.ClientAppSep; string clientAppEqual = encoderParams.ClientAppEqual; bool flag = true; foreach (KeyValuePair<FieldNames, string> item in obj) { if (flag) { stringBuilder.Append($"{item.Key}{clientAppEqual}{item.Value}"); flag = false; continue; } stringBuilder.Append($"{clientAppSep}{item.Key}{clientAppEqual}{item.Value}"); } data = new EventsData(); return stringBuilder.ToString(); } } public class EventsReaderOnKey : EventsReader, IEventsReaderOnKey, IEventsReader { protected readonly Action<IEventsData> processEvent; protected readonly IEventsDataParser parser; public EventsReaderOnKey(Action<IEventsData> processEvent, IEventsDataParser parser, Action<string> log = null, Action<string> logError = null) : base(log, logError) { this.processEvent = processEvent; this.parser = parser; } protected virtual void ProcessOnKey(string[] events) { if (events == null || events.Length == 0) { return; } foreach (IEventsData item in events.Select((string item) => parser?.ParseEvent(item))) { try { ReaderLog($"StartProcessOnKey {item}"); processEvent?.Invoke(item); } catch (Exception arg) { ReaderLogError($"StartProcessOnKey error: {arg}"); } } } public virtual void ProcessAllOnKey(string[] events) { try { ProcessOnKey(events); } catch (Exception arg) { ReaderLogError($"ProcessAllOnKey error: {arg}"); } } public virtual void ReadAndProcessAllOnKey(string path, bool isClearFile = true) { ProcessAllOnKey(ReadAll(path, isClearFile)); } } public class EventsReaderOnFrame : EventsReader, IEventsReaderOnFrame, IEventsReader { protected bool isFirstRun = true; protected readonly float delay; protected float delayCounter; protected float initDelay; protected float initCounter; protected readonly float checkPeriod; protected float periodCounter; protected readonly Action<IEventsData> processEvent; protected readonly IEventsDataParser parser; protected IEnumerator<IEventsData> eventsData; protected readonly string path; private bool isDelayEveryProcessing; public bool IsDelayEveryProcessing { get { return isDelayEveryProcessing; } set { isDelayEveryProcessing = value; } } protected virtual void StartProcessOnFrame() { while (eventsData.MoveNext()) { try { ReaderLog($"StartProcessOnFrame {eventsData.Current}"); processEvent?.Invoke(eventsData.Current); } catch (Exception arg) { ReaderLogError($"StartProcessOnFrame error: {arg}"); } } eventsData = null; } protected virtual void StartProcessWithDelayOnFrame() { if (eventsData.MoveNext()) { try { ReaderLog($"StartProcessWithDelayOnFrame {eventsData.Current}"); processEvent?.Invoke(eventsData.Current); return; } catch (Exception arg) { ReaderLogError($"StartProcessWithDelayOnFrame error: {arg}"); return; } } isFirstRun = false; eventsData = null; ReaderLog("StartProcessWithDelayOnFrame end"); } public EventsReaderOnFrame(string path, Action<IEventsData> processEvent, IEventsDataParser parser, Action<string> log = null, Action<string> errorLog = null, float checkPeriod = 2f, float delay = 1f, float initDelay = 0.5f) : base(log, errorLog) { this.processEvent = processEvent; this.parser = parser; this.delay = delay; this.initDelay = initDelay; this.path = path; this.checkPeriod = checkPeriod; } public virtual void SetEventsToProcess(string[] events) { try { if (events == null || events.Length == 0) { eventsData = null; return; } ReaderLog($"SetEventsToProcess read {events.Length} events"); eventsData = events.Select((string item) => parser?.ParseEvent(item))?.GetEnumerator(); } catch (Exception arg) { ReaderLogError($"SetEventsToProcess error: {arg}"); } } public virtual bool IsProcessEnd() { return eventsData == null; } public virtual void ProcessAllWithDelayOnFrame(float dt) { if (IsProcessEnd()) { return; } try { if (isDelayEveryProcessing || isFirstRun) { if (initDelay != 0f) { initCounter += dt; if (initCounter >= initDelay) { initCounter = 0f; initDelay = 0f; StartProcessWithDelayOnFrame(); } } else { delayCounter += dt; if (delayCounter >= delay) { delayCounter = 0f; StartProcessWithDelayOnFrame(); } } } else { StartProcessOnFrame(); } } catch (Exception arg) { ReaderLogError($"ProcessAllWithDelay error: {arg}"); } } public virtual void ReadAndProcessAllWithDelayOnFrame(float dt) { if (IsProcessEnd()) { periodCounter += dt; if (periodCounter >= checkPeriod) { periodCounter = 0f; string[] eventsToProcess = ReadAll(path); SetEventsToProcess(eventsToProcess); } } ProcessAllWithDelayOnFrame(dt); } } public class EventsReader : IEventsReader { protected readonly Action<string> log; protected readonly Action<string> logError; public EventsReader(Action<string> log = null, Action<string> logError = null) { this.log = log; this.logError = logError; } protected virtual void ReaderLog(string s) { log?.Invoke(s); } protected virtual void ReaderLogError(string s) { logError?.Invoke(s); } public virtual string[] ReadAllUnsafe(string path, bool isClearFile = true) { using FileStream fileStream = new FileStream(path, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None); using StreamReader streamReader = new StreamReader(fileStream, Encoding.UTF8); char[] separator = new char[2] { '\r', '\n' }; string[] array = streamReader.ReadToEnd().Split(separator, StringSplitOptions.RemoveEmptyEntries); if (isClearFile && array != null && array.Length >= 1) { fileStream.SetLength(0L); } return array; } public virtual string[] ReadAll(string path, bool isClearFile = true) { try { return ReadAllUnsafe(path, isClearFile); } catch (FileNotFoundException) { } catch (DirectoryNotFoundException) { } catch (Exception arg) { ReaderLogError($"read event error: {arg}"); } return null; } } } namespace EventsIO.Interfaces { public interface IEventsData { string Username { get; } string Cost { get; } string EventID { get; } string Lang { get; } string ExtraInfo { get; } } public interface IEventsDataEncoderParams { string ClientAppSep { get; } char ClientAppSepChar { get; } string ClientAppEqual { get; } char ClientAppEqualChar { get; } } public interface IEventsDataEncoder { string Encode(string s); string Decode(string s); } public interface IEventsDataParser { IEventsData ParseEvent(string s); } public interface IEventsGenerator { void SetUsername(string s); void SetEventID(string s); void SetCost(string s); void SetLang(string s); void SetExtraInfo(string s); string Generate(); } public interface IEventsReaderOnKey : IEventsReader { void ProcessAllOnKey(string[] events); void ReadAndProcessAllOnKey(string path, bool isClearFile = true); } public interface IEventsReaderOnFrame : IEventsReader { void SetEventsToProcess(string[] events); bool IsProcessEnd(); void ProcessAllWithDelayOnFrame(float dt); void ReadAndProcessAllWithDelayOnFrame(float dt); } public interface IEventsReader { string[] ReadAll(string path, bool isClearFile = true); } }
ChaosTricks_RoR2_plugins/InteractiveMod.dll
Decompiled 2 years agousing System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Logging; using EventsIO; using EventsIO.Interfaces; using HarmonyLib; using ModHelper; using ModHelper.Interfaces; using ModHelperUnity; using ModHelperUnity.Interfaces; using ModHelperUnity.UtilityGUI; using RoR2; using RoR2.CharacterAI; using RoR2.ConVar; using UnityEngine; using UnityEngine.Networking; using UnityEngine.SceneManagement; using WebSocketIO; using ror2_interactive_mod.Commands; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("ror2_interactive_mod")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("ror2_interactive_mod")] [assembly: AssemblyCopyright("Copyright © 2020")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("0fdefecb-0e54-4f2d-90d1-44b98749c3df")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyVersion("1.0.0.0")] namespace ror2_interactive_mod { internal class HelperUnit { public static void SpawnUnit(Vector3 pos, GameObject unitPrefab, EliteIndex eliteIndex, TeamIndex teamIndex = 2, bool braindead = false) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Invalid comparison between Unknown and I4 //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_022a: Unknown result type (might be due to invalid IL or missing references) //IL_022c: Invalid comparison between Unknown and I4 //IL_022e: Unknown result type (might be due to invalid IL or missing references) //IL_0230: Invalid comparison between Unknown and I4 //IL_023d: Unknown result type (might be due to invalid IL or missing references) //IL_024f: Unknown result type (might be due to invalid IL or missing references) try { GameObject val = Object.Instantiate<GameObject>(unitPrefab, pos, Quaternion.identity); CharacterMaster component = val.GetComponent<CharacterMaster>(); NetworkServer.Spawn(val); component.SpawnBody(pos, Quaternion.identity); if ((int)eliteIndex != -1) { component.inventory.SetEquipmentIndex(EliteCatalog.GetEliteDef(eliteIndex).eliteEquipmentDef.equipmentIndex); EliteTierDef tierDef = Tools.GetTierDef(eliteIndex); if (tierDef != null && tierDef.eliteTypes?.Length > 0) { EliteDef val2 = tierDef.eliteTypes[0]; float num = (val2?.healthBoostCoefficient ?? 1f) * 10f; Tools.Logger.LogDebugInfo((object)$"healthBoostCoefficient {val2?.healthBoostCoefficient}"); component.inventory.GiveItem(Items.BoostHp, Mathf.RoundToInt(num)); num = (val2?.damageBoostCoefficient ?? 1f) * 10f; Tools.Logger.LogDebugInfo((object)$"damageBoostCoefficient {val2?.damageBoostCoefficient}"); component.inventory.GiveItem(Items.BoostDamage, Mathf.RoundToInt(num)); } } GameObject bodyObject = component.GetBodyObject(); DeathRewards val3 = bodyObject.GetComponent<DeathRewards>(); if ((Object)(object)val3 == (Object)null) { Tools.Log("add rewards"); val3 = bodyObject.AddComponent<DeathRewards>(); } val3.expReward = (uint)(0.4f * Run.instance.compensatedDifficultyCoefficient); if (val3.expReward < 3) { val3.expReward = 3u; } val3.goldReward = (uint)(0.8f * Run.instance.compensatedDifficultyCoefficient); if (val3.goldReward < 3) { val3.goldReward = 3u; } if (braindead) { Object.Destroy((Object)(object)((Component)component).GetComponent<BaseAI>()); } if ((int)teamIndex >= -1 && (int)teamIndex < 5) { component.teamIndex = teamIndex; component.GetBody().teamComponent.teamIndex = teamIndex; } } catch (Exception arg) { Tools.Log($"SpawnUnit error: {arg}"); } } public static string GetBodyName(string name) { if (name == null) { Tools.Log("GetBodyName error: incorrect name " + name); return string.Empty; } try { int num = 0; foreach (CharacterBody allBodyPrefabBodyBodyComponent in BodyCatalog.allBodyPrefabBodyBodyComponents) { if ((Object)(object)allBodyPrefabBodyBodyComponent == (Object)null || ((Object)allBodyPrefabBodyBodyComponent).name == null) { num++; continue; } if ((int.TryParse(name, out var result) && num == result) || ((Object)allBodyPrefabBodyBodyComponent).name.Equals(name, StringComparison.InvariantCultureIgnoreCase) || ((Object)allBodyPrefabBodyBodyComponent).name.ToLower().Replace("body", string.Empty).Equals(name, StringComparison.InvariantCultureIgnoreCase)) { return ((Object)allBodyPrefabBodyBodyComponent).name; } num++; } } catch (Exception arg) { Tools.Log($"GetBodyName error: {arg}"); } return string.Empty; } public static string GetMasterName(string name) { if (name == null) { Tools.Log("GetMasterName error: incorrect name"); return string.Empty; } try { int num = 0; IEnumerable<CharacterMaster> allAiMasters = MasterCatalog.allAiMasters; if (allAiMasters == null) { Tools.Log("GetMasterName error: MasterCatalog.allAiMasters"); return string.Empty; } foreach (CharacterMaster item in allAiMasters) { if ((Object)(object)item == (Object)null || ((Object)item).name == null) { num++; continue; } if ((int.TryParse(name, out var result) && num == result) || ((Object)item).name.Equals(name, StringComparison.InvariantCultureIgnoreCase) || ((Object)item).name.ToLower().Replace("master", string.Empty).Equals(name, StringComparison.InvariantCultureIgnoreCase)) { return ((Object)item).name; } num++; } } catch (Exception arg) { Tools.Log($"GetMasterName error: {arg}"); } return string.Empty; } } public class HelperEquip { public static EquipmentIndex GetEquipFromString(string name) { //IL_0003: 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_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) try { return EquipmentCatalog.FindEquipmentIndex(name); } catch (Exception arg) { Tools.Log($"GetEquipFromString error: {arg}"); } return (EquipmentIndex)(-1); } public static ItemIndex GetItemFromString(string name) { //IL_0003: 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_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) try { return ItemCatalog.FindItemIndex(name); } catch (Exception arg) { Tools.Log($"GetItemFromString error: {arg}"); } return (ItemIndex)(-1); } } public class InteractiveMod { private WebSocketEventsReader<SettingsData> eventsReader; private IEventsReaderOnKey eventsReaderByKey; private IEventsDataParser eventsParser; private ICommandManager commandManager; private ITranslation translateManager; private IComponentTypedNotify notifyManager; private string keyEventsPath; private bool isNeedFirstInit = true; private bool isQuiting; private GameObject gameObject; private Dictionary<string, ICommandExecutor> commandsDict; private float firstDelay = 4f; public InteractiveMod(BepInExPlugin plugin) { gameObject = ((Component)plugin).gameObject; } public void Awake() { Tools.Log("InteractiveMod Awake"); MainPatcher.InitPatch(); } public void OnDestroy() { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Expected O, but got Unknown Tools.Log("InteractiveMod OnDestroy"); if (!isQuiting) { Tools.Log("InteractiveMod reinit mod script"); GameObject val = new GameObject(); val.AddComponent(typeof(InteractiveMod)); val.SetActive(true); Loader.HookObj = val; } } public void OnApplicationQuit() { Tools.Log("InteractiveMod OnApplicationQuit"); isQuiting = true; } public void InitCommandsWithNotify() { commandsDict = new Dictionary<string, ICommandExecutor> { { "spawn_as", new CommandChangeBody() }, { "give_equip", new CommandGiveEquip() }, { "give_item", new CommandGiveItem() }, { "kill_all", new CommandKillAll() }, { "remove_item", new CommandRemoveItem() }, { "spawn_ai", new CommandSpawnAI() }, { "give_item_or_equip", new CommandGiveItemOrEquip() } }; } private string GetBasePath(string filename) { return Path.Combine(UtilitySettings.BaseFolder, filename); } public void InitCommands() { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Expected O, but got Unknown //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Expected O, but got Unknown Tools.Log("init HelperCommandManager"); commandManager = (ICommandManager)new HelperCommandManagerFormatted(Tools.Logger); commandManager.InitFromFile(GetBasePath("commands.data")); Tools.Log("init HelperLanguages"); translateManager = (ITranslation)new HelperLanguagesFormatted(Tools.Logger); translateManager.InitFromFile(GetBasePath("langs.data")); InitCommandsWithNotify(); } public void Start() { Tools.Log("InteractiveMod OnStart"); } public void FirstInit() { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Expected O, but got Unknown //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Expected O, but got Unknown Tools.Log("FirstInit"); eventsParser = (IEventsDataParser)new EventsDataParser((Action<string>)Tools.Log); Tools.Log("init EventsReaderOnFrame"); if (eventsReader == null) { eventsReader = new WebSocketEventsReader<SettingsData>((Action<IEventsData>)ProcessEvent, eventsParser, (Action<string>)Tools.Log, (Action<string>)Tools.Log, 1f, 1f, 0.5f); eventsReader.InitDefaultSocket(UtilitySettings.BaseFolder, "chaostricks_ror2", 13715, "127.0.0.1"); eventsReader.OpenSocket(true); } Tools.Log("init EventsReaderOnKey"); keyEventsPath = GetBasePath("events_key.txt"); eventsReaderByKey = (IEventsReaderOnKey)new EventsReaderOnKey((Action<IEventsData>)ProcessEvent, eventsParser, (Action<string>)Tools.Log, (Action<string>)null); InitCommands(); if (notifyManager == null) { notifyManager = (IComponentTypedNotify)(object)gameObject.AddComponent<TypedNotifyOnGUI>(); } IComponentTypedNotify obj = notifyManager; if (obj != null) { obj.PostInit(UtilitySettings.BaseFolder, Tools.Logger, (Func<string, byte[]>)null); } SettingsManager.LoadSettings(); Tools.Log("InteractiveMod init ended (1.0.0)"); } private bool ExecuteCommandOnePlayer(ICommandExecutor command, ConCommandArgs args) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) Tools.Log("run command for single player"); args.sender = NetworkUser.readOnlyLocalPlayersList[0]; try { command.Execute(args); return true; } catch (Exception arg) { Tools.Log($"command run error: {arg}"); return false; } } private bool ExecuteCommandAllPlayers(ICommandExecutor command, ConCommandArgs args) { //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) if (SettingsManager.Data.isAllPlayers) { bool result = true; foreach (NetworkUser readOnlyInstances in NetworkUser.readOnlyInstancesList) { try { Tools.Log("run command for player " + readOnlyInstances?.userName); args.sender = readOnlyInstances; command.Execute(args); } catch (Exception arg) { Tools.Log($"run command for player {readOnlyInstances?.userName} error: {arg}"); result = false; } } return result; } return ExecuteCommandOnePlayer(command, args); } private bool ExecuteCommand(ICommandExecutor command, string[] args) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) Tools.EnableCheats(); Tools.Log("command: '" + ((ICommand)command).Id + "'"); ConCommandArgs args2 = default(ConCommandArgs); List<string> list = new List<string>(args); list.RemoveAt(0); args2.userArgs = list; if (command is ICommandTargets) { return ExecuteCommandAllPlayers(command, args2); } return ExecuteCommandOnePlayer(command, args2); } private void ProcessEvent(IEventsData data) { string eventID = data.EventID; if (string.IsNullOrWhiteSpace(eventID)) { return; } if (eventID == UtilitySettings.CommandUpdateSettingsID) { SettingsManager.LoadSettings(); Tools.Log("settings reloaded"); return; } Tools.Log("try to execute event: '" + eventID + "'"); string text = string.Empty; string commandData = commandManager.GetCommandData(eventID, true); string[] array = commandData.Split(); if (array.Length != 0) { text = array[0].Trim(); } if (commandsDict.TryGetValue(text, out var value)) { if (!ExecuteCommand(value, array)) { Tools.Log("event '" + eventID + "' executing is failed"); } } else { Tools.Log("command not found " + text); } Tools.Log("event '" + eventID + "' executing is completed"); ICommandNotify val = (ICommandNotify)((value is ICommandNotify) ? value : null); if (val != null) { IComponentTypedNotify obj = notifyManager; if (obj != null) { obj.AddNotifyToQueue(data, translateManager, (Func<string, string>)val.ProcessMsg); } } else { IComponentTypedNotify obj2 = notifyManager; if (obj2 != null) { obj2.AddNotifyToQueue(data, translateManager, (Func<string, string>)null); } } } public bool IsAllPlayersDeadAndNoLifes(IReadOnlyCollection<NetworkUser> list) { if (list == null) { return true; } foreach (NetworkUser item in list) { if (item != null) { CharacterMaster master = item.master; if (((master != null) ? new bool?(master.IsDeadAndOutOfLivesServer()) : null) == false) { return false; } } } return true; } public bool IsNotReadyForCheckEvent() { //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) int num = NetworkUser.readOnlyLocalPlayersList?.Count ?? 0; if (num <= 0) { return true; } ReadOnlyCollection<NetworkUser> readOnlyInstancesList = NetworkUser.readOnlyInstancesList; if (readOnlyInstancesList != null && readOnlyInstancesList.Count > 1) { if (IsAllPlayersDeadAndNoLifes(NetworkUser.readOnlyInstancesList)) { return true; } } else if (IsAllPlayersDeadAndNoLifes(NetworkUser.readOnlyLocalPlayersList)) { return true; } Scene activeScene = SceneManager.GetActiveScene(); string text = ((Scene)(ref activeScene)).name?.ToLower(); return "intro" == text || "title" == text || "lobby" == text || MasterCatalog.allAiMasters == null; } public void Update() { //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) if (Input.GetKeyDown((KeyCode)278)) { InitCommands(); } if (IsNotReadyForCheckEvent()) { return; } if (isNeedFirstInit) { FirstInit(); isNeedFirstInit = false; } firstDelay -= Time.deltaTime; if (firstDelay > 0f) { return; } if (Input.GetKey((KeyCode)306) && Input.GetKeyDown((KeyCode)261)) { eventsReaderByKey.ReadAndProcessAllOnKey(keyEventsPath, false); } if (Input.GetKey((KeyCode)306) && Input.GetKeyDown((KeyCode)112)) { try { NetworkUser val = NetworkUser.readOnlyLocalPlayersList[0]; CharacterBody body = val.master.GetBody(); if (Object.op_Implicit((Object)(object)((body != null) ? body.healthComponent : null))) { body.healthComponent.Suicide((GameObject)null, (GameObject)null, default(DamageTypeCombo)); } } catch (Exception arg) { ((ILogger)Tools.Logger).Log((object)$"Selfkill error: {arg}"); } } ((EventsReaderOnFrame)eventsReader).ReadAndProcessAllWithDelayOnFrame(Time.deltaTime); } } internal interface ICommandExecutor : ICommand { void Execute(ConCommandArgs args); } public class MainPatcher { public static void InitPatch() { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Expected O, but got Unknown try { ((ILogger)Tools.Logger).Log((object)"HelperPatcher init"); Harmony val = new Harmony("com.Loki.patch"); val.PatchAll(); } catch (Exception arg) { ((ILogger)Tools.Logger).Log((object)$"HelperPatcher error: {arg}"); } } } public class SettingsData { public bool isAllPlayers = true; } public class SettingsManager { private static SettingsData data = new SettingsData(); public static SettingsData Data => data; public static void LoadSettings() { try { SettingsData settingsData = UtilitySettings.LoadSettings<SettingsData>(Tools.Logger); if (settingsData != null) { data = settingsData; } else { Tools.Log("LoadSettings using default."); } } catch (Exception arg) { Tools.Log($"LoadSettings error: {arg}"); } } } [BepInPlugin("bft.chaostricks", "Chaos Tricks", "1.0.0")] public class BepInExPlugin : BaseUnityPlugin { private ManualLogSource loggerHook; private InteractiveMod mod; public const string pluginGuid = "bft.chaostricks"; public const string pluginName = "Chaos Tricks"; public const string pluginVersion = "1.0.0"; public void Awake() { loggerHook = ((BaseUnityPlugin)this).Logger; try { UtilitySettings.BaseFolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); ((ILogger)Tools.Logger).LogClear(); } catch (Exception ex) { ManualLogSource obj = loggerHook; if (obj != null) { obj.LogError((object)ex); } } mod = new InteractiveMod(this); mod.Awake(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"plugin init finished"); } public void OnDestroy() { mod?.OnDestroy(); } public void Start() { mod?.Start(); } public void Update() { mod?.Update(); } } public static class Tools { private static readonly Lazy<IDebugLogger> instance; public static IDebugLogger Logger => instance.Value; public static IParseManager ParseManager { get; } static Tools() { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Expected O, but got Unknown instance = new Lazy<IDebugLogger>((Func<IDebugLogger>)(() => (IDebugLogger)new BufferedLogger(UtilitySettings.BaseFolder, "interactive_mod_log.txt", true, 50))); ParseManager = (IParseManager)new HelperParse((ILogger)(object)Logger); } public static void Log(string text) { ((ILogger)Logger).Log((object)text); } public static bool EnableCheats() { try { if (CheatsConVar.instance.boolValue) { return true; } Log("try to enable cheats"); Type type = ((object)CheatsConVar.instance).GetType(); if (type == null) { Log("can't get type"); return false; } FieldInfo field = type.GetField("_boolValue", BindingFlags.Instance | BindingFlags.NonPublic); if (field == null) { Log("can't get field1"); return false; } field.SetValue(CheatsConVar.instance, true); ((BaseConVar)CheatsConVar.instance).SetString("1"); return CheatsConVar.instance.boolValue; } catch (Exception arg) { Log($"cheats enable error: {arg}"); } return false; } public static EliteTierDef GetTierDef(EliteIndex index) { //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Invalid comparison between Unknown and I4 //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Invalid comparison between Unknown and I4 //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) try { object value = typeof(CombatDirector).GetField("eliteTiers").GetValue(null); EliteTierDef[] array = (EliteTierDef[])value; if (array == null) { Log("GetTierDef error: can't get tiers"); return null; } if ((int)index <= -1 || (int)index >= EliteCatalog.eliteList.Count) { Log("GetTierDef error: index out"); return null; } int num = 0; for (int i = 0; i < array.Length; i++) { for (int j = 0; j < array[i].eliteTypes.Length; j++) { if (array[i].eliteTypes[j].eliteIndex == index) { num = i; break; } } } return array[num]; } catch (Exception arg) { Log($"GetTierDef error: {arg}"); return null; } } public static List<string> GetItemsFromFileByListName(string listName, bool isCreateFileIfNotExist = true) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Expected O, but got Unknown string text = null; try { text = Path.Combine(UtilitySettings.BaseFolder, listName + ".data"); HelperJson val = new HelperJson(Logger, false); List<string> list = val.FromFile<List<string>>(text); if (list == null) { list = new List<string>(); } Log($"Items from file: found {listName} {list.Count}"); foreach (string item in list) { Log("found value: " + item); } return list; } catch (FileNotFoundException) { if (isCreateFileIfNotExist) { try { File.Create(text); } catch (Exception arg) { Log($"Items from file: create file error {arg}"); } } } catch (Exception arg2) { Log($"Items from file: load error {arg2}"); } return new List<string>(); } private static string GetTabs(string text, int stringMaxLength) { return new string(' ', stringMaxLength - text.Length + 4); } public static void DebugPrintPrefabs() { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: 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) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0030: 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) //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_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: 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_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_0322: Unknown result type (might be due to invalid IL or missing references) StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("Items:"); GenericStaticEnumerable<ItemIndex, AllItemsEnumerator> allItems = ItemCatalog.allItems; AllItemsEnumerator enumerator = allItems.GetEnumerator(); try { while (((AllItemsEnumerator)(ref enumerator)).MoveNext()) { ItemIndex current = ((AllItemsEnumerator)(ref enumerator)).Current; ItemDef itemDef = ItemCatalog.GetItemDef(current); string localizedStringByToken = Language.currentLanguage.GetLocalizedStringByToken(itemDef.nameToken); string tabs = GetTabs(((object)(ItemIndex)(ref current)).ToString(), 3); string tabs2 = GetTabs(((Object)itemDef).name, 25); stringBuilder.AppendLine($"Item: index {current}{tabs}prefabName {((Object)itemDef).name}{tabs2}gameName {localizedStringByToken}"); } } finally { ((IDisposable)(AllItemsEnumerator)(ref enumerator)).Dispose(); } stringBuilder.AppendLine("\n---------------\nEquipments:"); GenericStaticEnumerable<EquipmentIndex, AllEquipmentEnumerator> allEquipment = EquipmentCatalog.allEquipment; AllEquipmentEnumerator enumerator2 = allEquipment.GetEnumerator(); try { while (((AllEquipmentEnumerator)(ref enumerator2)).MoveNext()) { EquipmentIndex current2 = ((AllEquipmentEnumerator)(ref enumerator2)).Current; EquipmentDef equipmentDef = EquipmentCatalog.GetEquipmentDef(current2); string localizedStringByToken2 = Language.currentLanguage.GetLocalizedStringByToken(equipmentDef.nameToken); string tabs3 = GetTabs(((object)(EquipmentIndex)(ref current2)).ToString(), 3); string tabs4 = GetTabs(((Object)equipmentDef).name, 20); stringBuilder.AppendLine($"Equipment: index {current2}{tabs3}prefabName {((Object)equipmentDef).name}{tabs4}name {localizedStringByToken2}"); } } finally { ((IDisposable)(AllEquipmentEnumerator)(ref enumerator2)).Dispose(); } stringBuilder.AppendLine("\n---------------\nMasters:"); foreach (CharacterMaster allMaster in MasterCatalog.allMasters) { string tabs5 = GetTabs(((Object)allMaster.bodyPrefab).name, 22); stringBuilder.AppendLine("nMasters: bodyName " + ((Object)allMaster.bodyPrefab).name + tabs5 + "prefabName " + ((Object)allMaster).name); } stringBuilder.AppendLine("\n---------------\nMasters AI:"); foreach (CharacterMaster allAiMaster in MasterCatalog.allAiMasters) { string tabs6 = GetTabs(((Object)allAiMaster.bodyPrefab).name, 22); stringBuilder.AppendLine("Masters AI: index " + ((Object)allAiMaster.bodyPrefab).name + tabs6 + "prefabName " + ((Object)allAiMaster).name); } stringBuilder.AppendLine("\n---------------\nBody models:"); foreach (CharacterBody allBodyPrefabBodyBodyComponent in BodyCatalog.allBodyPrefabBodyBodyComponents) { string bodyName = HelperUnit.GetBodyName(((Object)allBodyPrefabBodyBodyComponent).name); string tabs7 = GetTabs(((object)(BodyIndex)(ref allBodyPrefabBodyBodyComponent.bodyIndex)).ToString(), 3); string tabs8 = GetTabs(((Object)allBodyPrefabBodyBodyComponent).name, 28); stringBuilder.AppendLine($"Equipment: index {allBodyPrefabBodyBodyComponent.bodyIndex}{tabs7}prefabName {((Object)allBodyPrefabBodyBodyComponent).name}{tabs8}{bodyName}"); } Log(stringBuilder.ToString()); } } } namespace ror2_interactive_mod.Commands { public class CommandGiveItemOrEquip : ICommandExecutor, ICommand, ICommandNotify, ICommandTargets { public const string name = "give_item_or_equip"; private const string itemsRandomName = "RandomBlue"; private readonly List<string> itemsRandom; private EquipmentIndex lastEquip; private ItemIndex lastItem; private bool lastIsItem; public string Id => "give_item_or_equip"; public bool IsAllPlayers { get; set; } = true; public CommandGiveItemOrEquip() { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Invalid comparison between Unknown and I4 //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Invalid comparison between Unknown and I4 itemsRandom = Tools.GetItemsFromFileByListName("RandomBlue"); for (int num = itemsRandom.Count - 1; num >= 0; num--) { string text = itemsRandom[num]; if ((int)HelperEquip.GetEquipFromString(text) == -1 && (int)HelperEquip.GetItemFromString(text) == -1) { Tools.Log("Command give_item_or_equip error: missed equip or item - " + text + " in category RandomBlue"); itemsRandom.RemoveAt(num); } } } public string ProcessMsg(string msg) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) try { string text = ((!lastIsItem) ? EquipmentCatalog.GetEquipmentDef(lastEquip).nameToken : ItemCatalog.GetItemDef(lastItem).nameToken); string localizedStringByToken = Language.currentLanguage.GetLocalizedStringByToken(text); msg = msg.Replace("%value%", localizedStringByToken); } catch (Exception arg) { Tools.Log(string.Format("Command {0} process msg error: {1}", "give_item_or_equip", arg)); } return msg; } public void Execute(ConCommandArgs args) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_00af: 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_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Invalid comparison between Unknown and I4 //IL_00ed: 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_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Invalid comparison between Unknown and I4 //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) try { if (((ConCommandArgs)(ref args)).Count < 1) { Tools.Log("Command give_item_or_equip wrong args count"); return; } NetworkUser sender = args.sender; if ((Object)(object)sender == (Object)null) { Tools.Log("Command give_item_or_equip, error: player not found"); return; } NetworkUser sender2 = args.sender; Inventory val = ((sender2 != null) ? sender2.master.inventory : null); if ((Object)(object)val == (Object)null) { Tools.Log("Command give_item_or_equip, error: inventory not found"); return; } string text = ((ConCommandArgs)(ref args))[0]; string text2 = ((!text.Equals("RandomBlue", StringComparison.InvariantCultureIgnoreCase)) ? text : UtilityRandom.GetRandomItemFromList<string>((IList<string>)itemsRandom)); lastItem = (ItemIndex)(-1); lastEquip = HelperEquip.GetEquipFromString(text2); if ((int)lastEquip != -1) { val.SetEquipmentIndex(lastEquip); lastIsItem = false; } else { lastItem = HelperEquip.GetItemFromString(text2); if ((int)lastItem != -1) { val.GiveItem(lastItem, 1); lastIsItem = true; } else { Tools.Log("Command give_item_or_equip, error: item/equip not found " + ((ConCommandArgs)(ref args))[0] + " : " + text2); } } Tools.Log("Command give_item_or_equip: player " + sender.masterController.GetDisplayName() + " got " + text2); } catch (Exception arg) { Tools.Log(string.Format("Command {0} error: {1}", "give_item_or_equip", arg)); } } } public class CommandGiveItem : ICommandExecutor, ICommand, ICommandNotify, ICommandTargets { public const string name = "give_item"; private readonly Dictionary<string, List<string>> itemsLists; private readonly string[] listNames = new string[5] { "RandomWhite", "RandomGreen", "RandomYellow", "RandomRed", "RandomAll" }; private ItemIndex lastItem; public bool IsAllPlayers { get; set; } = true; public string Id => "give_item"; public CommandGiveItem() { //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Invalid comparison between Unknown and I4 itemsLists = new Dictionary<string, List<string>>(listNames.Length); string[] array = listNames; foreach (string text in array) { List<string> itemsFromFileByListName = Tools.GetItemsFromFileByListName(text); itemsLists[text] = itemsFromFileByListName; for (int num = itemsFromFileByListName.Count - 1; num >= 0; num--) { string text2 = itemsFromFileByListName[num]; if ((int)HelperEquip.GetItemFromString(text2) == -1) { Tools.Log("Command " + Id + " error: missed item - " + text2 + " in category " + text); itemsFromFileByListName.RemoveAt(num); } } } } public string ProcessMsg(string msg) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) try { ItemDef itemDef = ItemCatalog.GetItemDef(lastItem); string localizedStringByToken = Language.currentLanguage.GetLocalizedStringByToken(itemDef.nameToken); msg = msg.Replace("%value%", localizedStringByToken); } catch (Exception arg) { Tools.Log(string.Format("Command {0} process msg error: {1}", "give_item", arg)); } return msg; } public void Execute(ConCommandArgs args) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: 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_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Invalid comparison between Unknown and I4 //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) try { if (((ConCommandArgs)(ref args)).Count < 1) { Tools.Log("Command give_item wrong args count"); return; } NetworkUser sender = args.sender; if ((Object)(object)sender == (Object)null) { Tools.Log("Command give_item, error: player not found"); return; } NetworkUser sender2 = args.sender; Inventory val = ((sender2 != null) ? sender2.master.inventory : null); if ((Object)(object)val == (Object)null) { Tools.Log("Command give_item, error: inventory not found"); return; } if (((ConCommandArgs)(ref args)).Count < 2 || !int.TryParse(((ConCommandArgs)(ref args))[1], out var result)) { result = 1; } string text = ((ConCommandArgs)(ref args))[0]; string text2 = ((!itemsLists.ContainsKey(text)) ? text : UtilityRandom.GetRandomItemFromList<string>((IList<string>)itemsLists[text])); ItemIndex val2 = (lastItem = HelperEquip.GetItemFromString(text2)); if ((int)val2 != -1) { val.GiveItem(val2, result); Tools.Log(string.Format("Command {0}: player {1} got {2} named {3}", "give_item", sender.masterController.GetDisplayName(), val2, text2)); } else { Tools.Log("Command give_item, error: item " + text2 + " from " + text + " not found"); } } catch (Exception arg) { Tools.Log(string.Format("Command {0} error: {1}", "give_item", arg)); } } } public class CommandSpawnAI : ICommandExecutor, ICommand, ICommandNotify, ICommandTargets { public const string name = "spawn_ai"; private readonly Dictionary<string, List<string>> enemiesLists; private readonly string[] listNames = new string[2] { "T1Mobs", "T2Mobs" }; public string Id => "spawn_ai"; public bool IsAllPlayers { get; set; } = true; public CommandSpawnAI() { enemiesLists = new Dictionary<string, List<string>>(listNames.Length); string[] array = listNames; foreach (string text in array) { List<string> itemsFromFileByListName = Tools.GetItemsFromFileByListName(text); enemiesLists[text] = itemsFromFileByListName; for (int num = itemsFromFileByListName.Count - 1; num >= 0; num--) { string text2 = itemsFromFileByListName[num]; if ((Object)(object)GetUnitPrefabByName(text2, text) == (Object)null) { Tools.Log("Command " + Id + " error: missed enemy - " + text2 + " in category " + text); itemsFromFileByListName.RemoveAt(num); } } } } public string ProcessMsg(string msg) { return msg; } private GameObject GetUnitPrefabByName(string unitName, string categoryTextLog = null) { string text = ((categoryTextLog == null) ? string.Empty : (" in category " + categoryTextLog)); if (string.IsNullOrWhiteSpace(unitName)) { Tools.Log("Command spawn_ai error: missed mob with name " + unitName + text); return null; } string masterName = HelperUnit.GetMasterName(unitName); GameObject val = MasterCatalog.FindMasterPrefab(masterName); if ((Object)(object)val == (Object)null) { Tools.Log("Command spawn_ai error: missed prefab for mob " + masterName + " with name " + unitName + text); return null; } return val; } private GameObject GetUnitPrefab(string unitCategory) { string unitName = ((!enemiesLists.ContainsKey(unitCategory)) ? unitCategory : UtilityRandom.GetRandomItemFromList<string>((IList<string>)enemiesLists[unitCategory])); return GetUnitPrefabByName(unitName, unitCategory); } public void Execute(ConCommandArgs args) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_01d5: Unknown result type (might be due to invalid IL or missing references) //IL_0235: Unknown result type (might be due to invalid IL or missing references) //IL_025b: Unknown result type (might be due to invalid IL or missing references) //IL_0260: Unknown result type (might be due to invalid IL or missing references) //IL_0276: Unknown result type (might be due to invalid IL or missing references) //IL_027d: Unknown result type (might be due to invalid IL or missing references) //IL_0282: Unknown result type (might be due to invalid IL or missing references) //IL_0286: Unknown result type (might be due to invalid IL or missing references) //IL_028b: Unknown result type (might be due to invalid IL or missing references) //IL_0290: Unknown result type (might be due to invalid IL or missing references) //IL_029c: Unknown result type (might be due to invalid IL or missing references) //IL_02a0: Unknown result type (might be due to invalid IL or missing references) //IL_02a2: Unknown result type (might be due to invalid IL or missing references) try { if (((ConCommandArgs)(ref args)).Count < 1) { Tools.Log("Command spawn_ai wrong args count"); return; } NetworkUser sender = args.sender; NetworkUser sender2 = args.sender; Inventory val = ((sender2 != null) ? sender2.master.inventory : null); if ((Object)(object)sender == (Object)null) { Tools.Log("Command spawn_ai, error: player not found"); return; } float result = 1f; if (((ConCommandArgs)(ref args)).Count > 1 && !float.TryParse(((ConCommandArgs)(ref args))[1], out result)) { Tools.Log("Command spawn_ai can't parse spawn range min offset " + ((ConCommandArgs)(ref args))[1]); return; } float result2 = 2f; if (((ConCommandArgs)(ref args)).Count > 2 && !float.TryParse(((ConCommandArgs)(ref args))[2], out result2)) { Tools.Log("Command spawn_ai can't parse spawn range max offset " + ((ConCommandArgs)(ref args))[2]); return; } if (result > result2) { Tools.Log(string.Format("Command {0} error: spawn range min offset {1} > max offset {2}", "spawn_ai", result, result2)); return; } int result3 = 1; if (((ConCommandArgs)(ref args)).Count > 3 && !int.TryParse(((ConCommandArgs)(ref args))[3], out result3)) { Tools.Log("Command spawn_ai can't parse count of unit " + ((ConCommandArgs)(ref args))[3]); return; } if (result3 <= 0) { Tools.Log(string.Format("Command {0} error: incorrect count {1}", "spawn_ai", result3)); return; } EliteIndex eliteIndex = default(EliteIndex); if (((ConCommandArgs)(ref args)).Count <= 4 || !Tools.ParseManager.TryParseEnum<EliteIndex>(((ConCommandArgs)(ref args))[4], ref eliteIndex, (EliteIndex)0)) { eliteIndex = (EliteIndex)(-1); } bool braindead = default(bool); if (((ConCommandArgs)(ref args)).Count <= 5 || !Tools.ParseManager.TryParseBool(((ConCommandArgs)(ref args))[5], ref braindead, false)) { braindead = false; } TeamIndex teamIndex = default(TeamIndex); if (((ConCommandArgs)(ref args)).Count <= 6 || !Tools.ParseManager.TryParseEnum<TeamIndex>(((ConCommandArgs)(ref args))[6], ref teamIndex, (TeamIndex)0)) { teamIndex = (TeamIndex)2; } string text = ((ConCommandArgs)(ref args))[0]; for (int i = 0; i < result3; i++) { Vector3 position = ((Component)sender.master.GetBody()).transform.position; int num = ((text == "ClayBoss") ? 5 : 2); Vector3 val2 = position; float num2 = result; float num3 = result2; float num4 = num; LayerIndex world = LayerIndex.world; position = MathUtility.FindRandomSpawnPointNearPositionFixY(val2, num2, num3, num4, ((LayerIndex)(ref world)).mask); GameObject unitPrefab = GetUnitPrefab(text); HelperUnit.SpawnUnit(position, unitPrefab, eliteIndex, teamIndex, braindead); Tools.Log("Command spawn_ai spawn " + ((Object)unitPrefab).name); } Tools.Log(string.Format("Command {0} total spawns count {1}", "spawn_ai", result3)); } catch (Exception arg) { Tools.Log(string.Format("Command {0} error: {1}", "spawn_ai", arg)); } } } public class CommandRemoveItem : ICommandExecutor, ICommand, ICommandNotify, ICommandTargets { public const string name = "remove_item"; public string Id => "remove_item"; public bool IsAllPlayers { get; set; } = true; public string ProcessMsg(string msg) { return msg; } public void Execute(ConCommandArgs args) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: 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_00ea: Invalid comparison between Unknown and I4 //IL_0111: 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) //IL_0183: Unknown result type (might be due to invalid IL or missing references) try { if (((ConCommandArgs)(ref args)).Count < 1) { Tools.Log("Command remove_item wrong args count"); return; } NetworkUser sender = args.sender; if ((Object)(object)sender == (Object)null) { Tools.Log("Command remove_item, error: player not found"); return; } NetworkUser sender2 = args.sender; Inventory val = ((sender2 != null) ? sender2.master.inventory : null); if ((Object)(object)val == (Object)null) { Tools.Log("Command remove_item, error: inventory not found"); return; } if ("all".Equals(((ConCommandArgs)(ref args))[0], StringComparison.InvariantCultureIgnoreCase)) { val.CopyItemsFrom(new GameObject().AddComponent<Inventory>()); Tools.Log("Command remove_item: removing inventory"); return; } if (((ConCommandArgs)(ref args)).Count < 2) { Tools.Log("Command remove_item wrong args count."); return; } ItemIndex itemFromString = HelperEquip.GetItemFromString(((ConCommandArgs)(ref args))[0]); if ((int)itemFromString != -1) { int result; if ("all".Equals(((ConCommandArgs)(ref args))[1], StringComparison.InvariantCultureIgnoreCase)) { result = val.GetItemCount(itemFromString); } else { int.TryParse(((ConCommandArgs)(ref args))[1], out result); } if (result > 0) { val.RemoveItem(itemFromString, result); } Tools.Log(string.Format("Command {0}: removed {1} {2} from {3}", "remove_item", result, itemFromString, sender.masterController.GetDisplayName())); } else { Tools.Log("Command remove_item: item " + ((ConCommandArgs)(ref args))[0] + " not found"); } } catch (Exception arg) { Tools.Log(string.Format("Command {0} error: {1}", "remove_item", arg)); } } } public class CommandKillAll : ICommandExecutor, ICommand, ICommandNotify { public const string name = "kill_all"; public string Id => "kill_all"; public string ProcessMsg(string msg) { return msg; } public void Execute(ConCommandArgs args) { //IL_002c: 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_004a: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) try { TeamIndex val = default(TeamIndex); if (((ConCommandArgs)(ref args)).Count == 0 || !Tools.ParseManager.TryParseEnum<TeamIndex>(((ConCommandArgs)(ref args))[0], ref val, (TeamIndex)0)) { val = (TeamIndex)2; } int num = 0; CharacterMaster[] array = Object.FindObjectsOfType<CharacterMaster>(); foreach (CharacterMaster val2 in array) { if (val2.teamIndex == val) { CharacterBody val3 = ((val2 != null) ? val2.GetBody() : null); if (Object.op_Implicit((Object)(object)((val3 != null) ? val3.healthComponent : null))) { val3.healthComponent.Suicide((GameObject)null, (GameObject)null, default(DamageTypeCombo)); num++; } } } Tools.Log(string.Format("Command {0}: killed {1} of team {2}", "kill_all", num, val)); } catch (Exception arg) { Tools.Log(string.Format("Command {0} error: {1}", "kill_all", arg)); } } } public class CommandChangeBody : ICommandExecutor, ICommand, ICommandNotify, ICommandTargets { public const string name = "spawn_as"; private string lastMasterBodyName; private readonly List<string> bodyRandom; private const string bodyRandomName = "RandomBody"; public string Id => "spawn_as"; public bool IsAllPlayers { get; set; } = true; public CommandChangeBody() { bodyRandom = Tools.GetItemsFromFileByListName("RandomBody"); } public string ProcessMsg(string msg) { try { msg = msg.Replace("%value%", lastMasterBodyName); Tools.Log("trans " + lastMasterBodyName); } catch (Exception arg) { Tools.Log(string.Format("Command {0} process msg error: {1}", "spawn_as", arg)); } return msg; } private void Respawn(CharacterMaster master) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) master.Respawn(((Component)master.GetBody()).transform.position, ((Component)master.GetBody()).transform.rotation, false); } public void Execute(ConCommandArgs args) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_01bc: Unknown result type (might be due to invalid IL or missing references) //IL_01c3: Expected O, but got Unknown try { if (((ConCommandArgs)(ref args)).Count < 1) { Tools.Log("Command spawn_as wrong args count"); return; } NetworkUser sender = args.sender; if ((Object)(object)sender == (Object)null) { Tools.Log("Command spawn_as, error: player not found"); return; } CharacterMaster master = sender.master; if (!Object.op_Implicit((Object)(object)master.GetBody())) { Tools.Log("Command spawn_as, error: can't find player body. Probably player despawned."); return; } string text = ((ConCommandArgs)(ref args))[0]; string currentName = ((Object)sender.master.GetBody()).name; int num = currentName.IndexOf("("); if (num != -1) { currentName = currentName.Substring(0, num); } currentName = HelperUnit.GetBodyName(currentName); Tools.Log("current body base " + ((Object)sender.master.GetBody()).name + ", processed " + currentName); if (text.Equals("RandomBody", StringComparison.InvariantCultureIgnoreCase)) { List<string> list = bodyRandom.Where((string name) => !string.Equals(HelperUnit.GetBodyName(name), currentName, StringComparison.OrdinalIgnoreCase)).ToList(); text = UtilityRandom.GetRandomItemFromList<string>((IList<string>)list); } text = HelperUnit.GetBodyName(text); if (string.IsNullOrWhiteSpace(text)) { Tools.Log("Command spawn_as, error: can't find body index " + text); return; } GameObject bodyPrefab = BodyCatalog.FindBodyPrefab(text); master.bodyPrefab = bodyPrefab; Tools.Log("Command spawn_as: " + sender.userName + " is spawning as " + text); BoolConVar val = (BoolConVar)(typeof(Stage).GetField("stage1PodConVar")?.GetValue(null)); if (val != null) { bool value = val.value; val.SetBool(false); Respawn(master); val.SetBool(value); } else { Respawn(master); } lastMasterBodyName = master.GetBody().GetDisplayName(); Tools.Log("Command spawn_as: spawning " + lastMasterBodyName + " end"); } catch (Exception arg) { Tools.Log(string.Format("Command {0} error: {1}", "spawn_as", arg)); } } } public class CommandGiveEquip : ICommandExecutor, ICommand, ICommandNotify, ICommandTargets { public const string name = "give_equip"; private const string equipRandomName = "RandomEquip"; private readonly List<string> equipRandom; private EquipmentIndex lastEquip; public string Id => "give_equip"; public bool IsAllPlayers { get; set; } = true; public CommandGiveEquip() { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Invalid comparison between Unknown and I4 equipRandom = Tools.GetItemsFromFileByListName("RandomEquip"); for (int num = equipRandom.Count - 1; num >= 0; num--) { string text = equipRandom[num]; if ((int)HelperEquip.GetEquipFromString(text) == -1) { Tools.Log("Command give_equip error: missed equip item - " + text + " in category RandomEquip"); equipRandom.RemoveAt(num); } } } public string ProcessMsg(string msg) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) try { EquipmentDef equipmentDef = EquipmentCatalog.GetEquipmentDef(lastEquip); string localizedStringByToken = Language.currentLanguage.GetLocalizedStringByToken(equipmentDef.nameToken); msg = msg.Replace("%value%", localizedStringByToken); } catch (Exception arg) { Tools.Log(string.Format("Command {0} process msg error: {1}", "give_equip", arg)); } return msg; } public void Execute(ConCommandArgs args) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: 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_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Invalid comparison between Unknown and I4 //IL_00eb: 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_0113: Unknown result type (might be due to invalid IL or missing references) try { if (((ConCommandArgs)(ref args)).Count < 1) { Tools.Log("Command give_equip wrong args count"); return; } NetworkUser sender = args.sender; if ((Object)(object)sender == (Object)null) { Tools.Log("Command give_equip, error: player not found"); return; } NetworkUser sender2 = args.sender; Inventory val = ((sender2 != null) ? sender2.master.inventory : null); if ((Object)(object)val == (Object)null) { Tools.Log("Command give_equip, error: inventory not found"); return; } string text = ((ConCommandArgs)(ref args))[0]; string text2 = ((!text.Equals("RandomEquip", StringComparison.InvariantCultureIgnoreCase)) ? text : UtilityRandom.GetRandomItemFromList<string>((IList<string>)equipRandom)); EquipmentIndex val2 = (lastEquip = HelperEquip.GetEquipFromString(text2)); if ((int)val2 != -1) { val.SetEquipmentIndex(val2); } else { Tools.Log(string.Format("Command {0}, error: item not found {1} : {2}", "give_equip", ((ConCommandArgs)(ref args))[0], val2)); } Tools.Log(string.Format("Command {0}: player {1} got {2}", "give_equip", sender.masterController.GetDisplayName(), val2)); } catch (Exception arg) { Tools.Log(string.Format("Command {0} error: {1}", "give_equip", arg)); } } } }
ChaosTricks_RoR2_plugins/ModHelper.dll
Decompiled 2 years agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text; using EventsIO; using EventsIO.Interfaces; using ModHelper.Interfaces; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("ModHelper")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("BFT")] [assembly: AssemblyProduct("ModHelper")] [assembly: AssemblyCopyright("Copyright © 2020")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("8d858f35-342c-4916-8e50-2b2cfd18640d")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyVersion("1.0.0.0")] namespace ModHelper { public class CommandArgsValidator { private readonly ILogger logger; public CommandArgsValidator(ILogger logger) { this.logger = logger; } public bool IsZeroArgs(IEnumerable<string> args) { int num = args?.Count() ?? 0; if (num != 0) { logger?.LogWarning($"CommandArgsValidator wrong args count {num} (must be 0)"); return false; } return true; } public bool IsZeroArgs(IEnumerator<string> args) { if (args == null || !args.MoveNext()) { return true; } logger?.LogWarning("CommandArgsValidator wrong args count (more than needed)"); return false; } private bool IsInvalidArgsCount(IEnumerator<string> args) { if (args == null || !args.MoveNext()) { return true; } return false; } public bool IsValidInt(IEnumerator<string> args, int minValue, int maxValue, bool isSkippable = false) { if (IsInvalidArgsCount(args)) { if (isSkippable) { return true; } logger?.LogWarning("CommandArgsValidator wrong args count"); return false; } try { int num = int.Parse(args.Current); if (num < minValue || num > maxValue) { string obj = $"CommandArgsValidator wrong integer value {num} (must be in range from {minValue} to {maxValue})"; logger?.LogWarning(obj); return false; } } catch (Exception arg) { logger?.LogWarning($"CommandArgsValidator can't parse integer value from '{args.Current}', {arg}"); return false; } return true; } public bool IsValidFloat(IEnumerator<string> args, float minValue, float maxValue, bool isSkippable = false) { if (IsInvalidArgsCount(args)) { if (isSkippable) { return true; } logger?.LogWarning("CommandArgsValidator wrong args count"); return false; } try { float num = float.Parse(args.Current, CultureInfo.InvariantCulture.NumberFormat); if (num < minValue || num > maxValue) { string obj = $"CommandArgsValidator wrong float value {num} (must be in range from {minValue} to {maxValue})"; logger?.LogWarning(obj); return false; } } catch (Exception arg) { logger?.LogWarning($"CommandArgsValidator can't parse float value from '{args.Current}', {arg}"); } return true; } public bool IsValidString(IEnumerator<string> args, Func<string, bool> validator, bool isSkippable = false) { if (IsInvalidArgsCount(args)) { if (isSkippable) { return true; } logger?.LogWarning("CommandArgsValidator wrong args count"); return false; } if (validator == null || validator(args.Current)) { return true; } logger?.LogWarning("CommandArgsValidator wrong string value " + args.Current); return false; } public bool IsValidBool(IEnumerator<string> args, bool isSkippable = false) { if (IsInvalidArgsCount(args)) { if (isSkippable) { return true; } logger?.LogWarning("CommandArgsValidator wrong args count"); return false; } try { bool.Parse(args.Current.ToLower()); } catch (Exception arg) { logger?.LogWarning($"CommandArgsValidator can't parse bool value from '{args.Current}', {arg}"); return false; } return true; } } public class PeriodicTaskData { public string id; public float period; internal float periodCalculated; public int triggerTimes; public bool isInfiniteRepeates = true; public Action periodicAction; public Action finishAction; public override string ToString() { return "id=" + id + ", " + $"period={period}s, " + $"calc_period={periodCalculated}s, " + $"triggerTimes={triggerTimes}, " + $"isInfiniteRepeates={isInfiniteRepeates}"; } } public class TimerTaskData { public string id; public float duration; public Action finishAction; public override string ToString() { return $"id={id}, duration={duration}s"; } } public class BufferedLogger : HelperDebugLog, IDisposable { protected readonly Queue<string> queue; protected readonly int bufferRecordsCount; private bool isDisposed; public BufferedLogger(string folderPath = null, string logFileName = null, bool isDebug = false, int bufferRecordsCount = 10) : base(folderPath, logFileName, isDebug) { this.bufferRecordsCount = bufferRecordsCount; queue = new Queue<string>(); } public virtual void Flush(bool isNeedClearQueue = false) { Queue<string> obj = queue; if (obj == null || obj.Count != 0) { WriteToFile(string.Join("\n", queue.ToArray())); if (isNeedClearQueue) { queue.Clear(); } } } public override void Log(object obj) { if (obj != null && isLogFile) { queue.Enqueue($"{LogTime} {obj}"); if (queue.Count >= bufferRecordsCount) { Flush(isNeedClearQueue: true); } } } protected virtual void Dispose(bool isDisposing) { if (!isDisposed) { isDisposed = true; Queue<string> obj = queue; if (obj != null && obj.Count > 0) { Flush(); } } } public void Dispose() { Dispose(isDisposing: true); GC.SuppressFinalize(this); } ~BufferedLogger() { Dispose(isDisposing: false); } } public static class HelperGroups { public static Dictionary<string, List<string>> GenerateNewEmptyGroupsDict() { return new Dictionary<string, List<string>>(StringComparer.InvariantCultureIgnoreCase); } private static bool SafeApplyValidator(Func<string, bool> groupItemValidator, string itemName, ILogger logger = null) { try { return groupItemValidator?.Invoke(itemName) ?? true; } catch (Exception arg) { logger?.LogError($"RandomGroup.SafeApplyValidator unexpected error: {arg}"); } return false; } public static void InitGroupsFromFiles(string dataDir, Dictionary<string, List<string>> groups, string groupsPrefix, Func<string, bool> groupItemValidator = null, IDebugLogger logger = null) { try { if (string.IsNullOrEmpty(groupsPrefix)) { logger?.LogError("RandomGroup error: wrong groupsPrefix " + groupsPrefix); return; } string[] files = Directory.GetFiles(dataDir); foreach (string path in files) { string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(path); if (fileNameWithoutExtension.StartsWith(groupsPrefix)) { groups[fileNameWithoutExtension] = GetItemsFromFile(path, logger); } } foreach (KeyValuePair<string, List<string>> group in groups) { logger?.LogDebugInfo("RandomGroup validate list " + group.Key + ":"); List<string> list = new List<string>(); foreach (string item in group.Value) { if (!SafeApplyValidator(groupItemValidator, item, logger)) { logger?.LogWarning("invalid name " + item); list.Add(item); } } if (list.Count > 0) { foreach (string item2 in list) { group.Value.Remove(item2); } logger?.LogWarning("list " + group.Key + " is invalid"); } else { logger?.LogDebugInfo("list " + group.Key + " is valid"); } } } catch (Exception arg) { logger?.LogError($"RandomGroup.InitGroupsFromFiles unexpected error: {arg}"); } } public static Dictionary<string, List<string>> GenerateGroupsFromFiles(string dataDir, string groupsPrefix, Func<string, bool> groupItemValidator = null, IDebugLogger logger = null) { Dictionary<string, List<string>> dictionary = GenerateNewEmptyGroupsDict(); InitGroupsFromFiles(dataDir, dictionary, groupsPrefix, groupItemValidator, logger); return dictionary; } public static List<string> GetItemsFromFile(string path, IDebugLogger logger = null) { try { List<string> list = new HelperJson(logger).FromFile<List<string>>(path); if (list == null) { list = new List<string>(); } logger?.LogInfo($"Items from file {path}: found {list.Count}"); foreach (string item in list) { logger?.LogDebugInfo("value " + item); } return list; } catch (Exception arg) { logger?.LogError($"HelperGroups.GetItemsFromFile unexpected error: {arg}"); } return new List<string>(); } public static bool IsValidGroupName(Dictionary<string, List<string>> dict, string name) { return dict?.ContainsKey(name) ?? false; } public static void PrintGroups(Dictionary<string, List<string>> dict, ILogger logger, string groupsName = "default_name") { if (logger == null) { return; } if (dict == null || dict.Count == 0) { logger?.LogWarning("No groups found for " + groupsName); return; } logger?.LogInfo("---------------Groups " + groupsName + " list---------------"); foreach (KeyValuePair<string, List<string>> item in dict) { logger?.LogInfo(item.Key ?? ""); } logger?.LogInfo("---------------Groups " + groupsName + " list end---------------"); } } public class HelperJson : IJsonUtil { private class ContainerObjAndInt { public object valueObj; public int valueInt; } private class ContainerStringAndInt { public string valueString; public int valueInt; } private ILogger logger; private const char startClass = '{'; private const char endClass = '}'; private const char startArray = '['; private const char endArray = ']'; private const char isHasNextField = ','; private const char special = '\\'; private const char startString = '"'; private const char nameValueSeparator = ':'; private char[] ignoreChars = new char[9] { ' ', '\n', '\r', '\t', '\b', '\f', '\0', '{', '[' }; private string logMsgBaseError = "HelperJson error:"; private string logMsgBase = "HelperJson:"; private bool isVerboseDebugLog; private void VerboseDebugLog(string s) { if (isVerboseDebugLog) { logger?.LogInfo("[DEBUG] " + s); } } public HelperJson(IDebugLogger logger = null, bool isVerboseDebugLog = false) { this.logger = logger; this.isVerboseDebugLog = isVerboseDebugLog; } public T FromFile<T>(string path) where T : class { string s; using (StreamReader streamReader = new StreamReader(path)) { s = streamReader.ReadToEnd(); } return FromString<T>(s); } public T FromString<T>(string s) where T : class { return GetFromString(typeof(T), s, 0).valueObj as T; } private char GetSpecialChar(char c) { _ = 34; return c; } private void SetFieldClass<T, R>(T instance, string fieldName, R fieldValue) where T : class where R : class { Type type = instance.GetType(); VerboseDebugLog("type=" + type.Name + ", field=" + fieldName); type.GetField(fieldName).SetValue(instance, fieldValue); } private ContainerStringAndInt ParseNextStringValue(string s, int index, bool isSkipSep = true) { StringBuilder stringBuilder = new StringBuilder(); bool flag = false; int i; for (i = index; i < s.Length; i++) { char c = s[i]; VerboseDebugLog($"{logMsgBase} ParseNextStringValue for process {c}"); if (!flag) { i = SkipIgnoredChars(s, i, isSkipHasNextField: false, isSkipSep); if (i >= s.Length) { logger?.Log(logMsgBaseError + " class field value parsing internal issue. Set default value."); break; } c = s[i]; if (c == '"') { flag = true; VerboseDebugLog(logMsgBase + " ParseNextStringValue is startString case"); continue; } if (c == ']' || c == '}') { break; } if (c == ',' || c == ':') { i = SkipIgnoredChars(s, i, isSkipHasNextField: true, isSkipSep); break; } } else if (c == '\\') { VerboseDebugLog(logMsgBase + " ParseNextStringValue is special case"); i++; if (i >= s.Length) { logger?.Log(logMsgBaseError + " class field value parsing internal issue with special symbols. Set default value."); break; } c = GetSpecialChar(s[i]); if (c != '"') { stringBuilder.Append('\\'); } } else if (c == '"') { VerboseDebugLog(logMsgBase + " ParseNextStringValue is startString end case"); i = SkipIgnoredChars(s, ++i, isSkipHasNextField: true, isSkipSep); break; } VerboseDebugLog($"{logMsgBase} ParseNextStringValue append {c}"); stringBuilder.Append(c); } string text = stringBuilder.ToString(); VerboseDebugLog($"{logMsgBase} ParseNextStringValue {text}, end at index {i}"); return new ContainerStringAndInt { valueString = text, valueInt = i }; } private ContainerStringAndInt GetNextFieldName(string s, int index) { VerboseDebugLog(logMsgBase + " GetNextFieldName"); return ParseNextStringValue(s, index, isSkipSep: false); } private ContainerObjAndInt GetNextValue(Type valueType, string s, int index, bool isSkipSep) { VerboseDebugLog(logMsgBase + " GetNextValue"); int num = SkipIgnoredChars(s, index, isSkipHasNextField: true, isSkipSep); if (num >= s.Length) { logger?.LogError(logMsgBaseError + " class parsing internal issue at value type " + valueType.Name + ". Set default value."); } if (valueType.IsPrimitive) { ContainerStringAndInt containerStringAndInt = ParseNextStringValue(s, num, isSkipSep); try { TypeCode typeCode = Type.GetTypeCode(valueType); object valueObj; if ((uint)(typeCode - 5) <= 10u) { if (double.TryParse(containerStringAndInt.valueString, NumberStyles.Any, CultureInfo.InvariantCulture, out var result)) { valueObj = Convert.ChangeType(result, valueType); } else { valueObj = Activator.CreateInstance(valueType); logger?.Log(logMsgBaseError + " incorrect convert, use default."); logger?.Log("Read value: " + containerStringAndInt.valueString + ", type: " + valueType.Name); } } else { valueObj = Convert.ChangeType(containerStringAndInt.valueString, valueType); } return new ContainerObjAndInt { valueObj = valueObj, valueInt = containerStringAndInt.valueInt }; } catch (Exception arg) { logger?.Log($"{logMsgBaseError} incorrect format, use default. Msg: {arg}"); logger?.Log("read value: " + containerStringAndInt.valueString + ", type: " + valueType.Name); return new ContainerObjAndInt { valueObj = Activator.CreateInstance(valueType), valueInt = containerStringAndInt.valueInt }; } } if (valueType.IsAssignableFrom(typeof(string))) { ContainerStringAndInt containerStringAndInt2 = ParseNextStringValue(s, num, isSkipSep); return new ContainerObjAndInt { valueObj = containerStringAndInt2.valueString, valueInt = containerStringAndInt2.valueInt }; } ContainerObjAndInt fromString = GetFromString(valueType, s, num); return new ContainerObjAndInt { valueObj = fromString.valueObj, valueInt = fromString.valueInt }; } private int SkipIgnoredChars(string s, int index, bool isSkipHasNextField = false, bool isSkipSep = false) { for (int i = index; i < s.Length; i++) { if (ignoreChars.Contains(s[i])) { VerboseDebugLog($"skip char '{s[i]}'"); continue; } if (isSkipHasNextField && s[i] == ',') { VerboseDebugLog($"skip char '{s[i]}'"); continue; } if (isSkipSep && s[i] == ':') { VerboseDebugLog($"skip char '{s[i]}'"); continue; } return i; } return s.Length; } private ContainerObjAndInt ParseIListByItemType(Type itemType, string s, int index) { if (!(Activator.CreateInstance(typeof(List<>).MakeGenericType(itemType)) is IList list)) { logger?.LogError(logMsgBaseError + " can't create IList for item type " + itemType.Name); return new ContainerObjAndInt { valueObj = null, valueInt = s.Length }; } do { ContainerObjAndInt nextValue = GetNextValue(itemType, s, index, isSkipSep: true); object valueObj = nextValue.valueObj; index = nextValue.valueInt; list.Add(valueObj); index = SkipIgnoredChars(s, index, isSkipHasNextField: true, isSkipSep: true); } while (index < s.Length && s[index] != ']' && s[index] != '}'); return new ContainerObjAndInt { valueObj = list, valueInt = index + 1 }; } private ContainerObjAndInt ParseIList(Type resultType, string s, int index) { Type itemType = ((!resultType.IsGenericType) ? resultType.GetElementType() : resultType.GetGenericArguments()[0]); return ParseIListByItemType(itemType, s, index); } private ContainerObjAndInt ParseArray(Type resultType, string s, int index) { Type elementType = resultType.GetElementType(); ContainerObjAndInt containerObjAndInt = ParseIListByItemType(elementType, s, index); Array array; if (containerObjAndInt.valueObj is IList list) { array = Array.CreateInstance(elementType, list.Count); for (int i = 0; i < array.Length; i++) { array.SetValue(list[i], i); } } else { logger?.Log(logMsgBaseError + " create empty Array"); array = Array.CreateInstance(elementType, 0); } return new ContainerObjAndInt { valueObj = array, valueInt = containerObjAndInt.valueInt }; } private ContainerObjAndInt ParseIDictionary(Type dictType, string s, int index) { Type[] genericArguments = dictType.GetGenericArguments(); if (genericArguments.Length != 2) { logger?.Log(logMsgBaseError + " can't create IDictionary, invalid args"); } if (dictType.IsGenericType) { if (!dictType.IsGenericTypeDefinition) { dictType = dictType.GetGenericTypeDefinition(); } dictType = dictType.MakeGenericType(genericArguments); } if (!(Activator.CreateInstance(dictType) is IDictionary dictionary)) { string name = dictType.GetType().Name; logger?.Log(logMsgBaseError + " can't create IDictionary " + name + " for item type " + genericArguments[0].Name + ", " + genericArguments[1].Name); return new ContainerObjAndInt { valueObj = null, valueInt = s.Length }; } Type valueType = genericArguments[0]; Type valueType2 = genericArguments[1]; do { ContainerObjAndInt nextValue = GetNextValue(valueType, s, index, isSkipSep: false); index = nextValue.valueInt; ContainerObjAndInt nextValue2 = GetNextValue(valueType2, s, index, isSkipSep: true); index = nextValue2.valueInt; dictionary.Add(nextValue.valueObj, nextValue2.valueObj); VerboseDebugLog($"{logMsgBase} dict add key {nextValue.valueObj}"); index = SkipIgnoredChars(s, index, isSkipHasNextField: true, isSkipSep: true); } while (index < s.Length && s[index] != '}' && s[index] != ']'); return new ContainerObjAndInt { valueObj = dictionary, valueInt = index + 1 }; } private bool IsTypeOf(Type targetType, Type sourceType, int argsCount) { if (sourceType.IsAssignableFrom(targetType)) { VerboseDebugLog(logMsgBase + " is " + targetType.Name); return true; } Type[] types = sourceType.Assembly.GetTypes(); foreach (Type type in types) { if (!type.IsClass) { continue; } Type[] interfaces = type.GetInterfaces(); foreach (Type type2 in interfaces) { if (type2.IsGenericType && (object)type2.GetGenericTypeDefinition() == targetType && sourceType.GetGenericArguments().Length == argsCount) { VerboseDebugLog(logMsgBase + " is " + targetType.Name + " assembly interface"); return true; } } } return false; } private ContainerObjAndInt GetFromString(Type resultType, string s, int index) { try { VerboseDebugLog(logMsgBase + " GetFromString"); if (resultType.IsArray) { VerboseDebugLog(logMsgBase + " is array"); return ParseArray(resultType, s, index); } if (resultType.IsAssignableFrom(typeof(IList)) || IsTypeOf(typeof(IList<>), resultType, 1)) { return ParseIList(resultType, s, index); } if (resultType.IsAssignableFrom(typeof(IDictionary)) || IsTypeOf(typeof(IDictionary<, >), resultType, 2)) { return ParseIDictionary(resultType, s, index); } if (resultType.IsGenericType && !resultType.IsGenericTypeDefinition) { Type[] genericArguments = resultType.GetGenericArguments(); resultType = resultType.GetGenericTypeDefinition(); resultType = resultType.MakeGenericType(genericArguments); } object obj = Activator.CreateInstance(resultType); int num = index; while (num < s.Length && s[num] != ']' && s[num] != '}') { ContainerStringAndInt nextFieldName = GetNextFieldName(s, num); string valueString = nextFieldName.valueString; if (string.IsNullOrEmpty(valueString?.Trim())) { VerboseDebugLog(logMsgBase + " IsNullOrWhiteSpace field " + valueString + ", class type " + resultType.Name); num = GetNextValue(typeof(string), s, num, isSkipSep: true).valueInt; continue; } num = nextFieldName.valueInt; FieldInfo field = resultType.GetField(valueString); VerboseDebugLog(logMsgBase + " field " + valueString + ", class type " + resultType.Name); if (isVerboseDebugLog) { FieldInfo[] fields = resultType.GetFields(); VerboseDebugLog(logMsgBase + " fields in class: "); FieldInfo[] array = fields; foreach (FieldInfo fieldInfo in array) { VerboseDebugLog(fieldInfo.Name); } } if ((object)field == null) { logger?.LogWarning(logMsgBaseError + " can't find field " + valueString + " for type " + resultType.Name + ". Try to skip."); num = GetNextValue(typeof(string), s, num, isSkipSep: true).valueInt; } else { ContainerObjAndInt nextValue = GetNextValue(field.FieldType, s, num, isSkipSep: true); object valueObj = nextValue.valueObj; num = nextValue.valueInt; SetFieldClass(obj, valueString, valueObj); } } num = SkipIgnoredChars(s, num + 1, isSkipHasNextField: true, isSkipSep: true); return new ContainerObjAndInt { valueObj = obj, valueInt = num }; } catch (Exception arg) { logger?.LogError($"{logMsgBaseError} {arg}"); } return new ContainerObjAndInt { valueObj = null, valueInt = s.Length }; } } public class HelperDebugLog : HelperLog, IDebugLogger, ILoggerWithConsole, ILogger { protected bool isDebug; public HelperDebugLog(string folderPath = null, string logFileName = null, bool isDebug = false) : base(folderPath, logFileName) { this.isDebug = isDebug; } public virtual void LogDebugInfo(object obj) { if (isDebug) { LogInfo($"[DEBUG] {obj}"); } } public virtual void LogDebugWarning(object obj) { if (isDebug) { LogWarning($"[DEBUG] {obj}"); } } public virtual void LogDebugError(object obj) { if (isDebug) { LogError($"[DEBUG] {obj}"); } } } public class ScheduleManager { protected ILogger logger; protected Dictionary<string, TimerTaskData> timerTasks = new Dictionary<string, TimerTaskData>(); protected Dictionary<string, PeriodicTaskData> periodicTasks = new Dictionary<string, PeriodicTaskData>(); protected List<TimerTaskData> timerTasksNoId = new List<TimerTaskData>(); protected List<PeriodicTaskData> periodicTasksNoId = new List<PeriodicTaskData>(); protected int onUpdateErrorLimit = 10; public ScheduleManager(ILogger logger = null) { this.logger = logger; } public void NewTimerTask(TimerTaskData task, bool triggerFinishIfExists = false) { if (task == null) { logger?.LogInfo($"ScheduleManager new timer task null error. Details info: {task}"); return; } if (task.id == null) { NewTimerTaskWithOutId(task); return; } if (triggerFinishIfExists && timerTasks.ContainsKey(task.id)) { SafeRunAction(timerTasks[task.id].finishAction); } timerTasks[task.id] = task; logger?.LogInfo($"ScheduleManager new timer task {task}"); } public void NewPeriodicTask(PeriodicTaskData task, bool triggerFinishIfExists = false) { if (task == null) { logger?.LogInfo($"ScheduleManager new periodic task null error. Details info: {task}"); return; } task.periodCalculated = task.period; if (task.id == null) { NewPeriodicTaskWithOutId(task); return; } if (triggerFinishIfExists && periodicTasks.ContainsKey(task.id)) { SafeRunAction(periodicTasks[task.id].finishAction); } periodicTasks[task.id] = task; logger?.LogInfo($"ScheduleManager new periodic task {task}"); } public void AppendPeriodicTask(PeriodicTaskData task, bool isReplaceAction = false) { if (task.id == null || !periodicTasks.ContainsKey(task.id)) { NewPeriodicTask(task); return; } logger?.LogInfo($"ScheduleManager append periodic task {task}"); PeriodicTaskData periodicTaskData = periodicTasks[task.id]; periodicTaskData.triggerTimes += task.triggerTimes; if (isReplaceAction) { periodicTaskData.finishAction = task.finishAction; } } protected void NewTimerTaskWithOutId(TimerTaskData task) { if (task == null) { logger?.LogWarning($"ScheduleManager new timer no id task null error. Details info: {task}"); return; } timerTasksNoId.Add(task); logger?.LogInfo($"ScheduleManager new timer no id task {task}"); } protected void NewPeriodicTaskWithOutId(PeriodicTaskData task) { if (task == null) { logger?.LogWarning($"ScheduleManager new periodic no id task null error. Details info: {task}"); return; } periodicTasksNoId.Add(task); logger?.LogInfo($"ScheduleManager new periodic no id task {task}"); } public void AppendTimerTask(TimerTaskData task, bool isReplaceAction = true) { if (!timerTasks.ContainsKey(task.id)) { NewTimerTask(task); return; } logger?.LogInfo($"ScheduleManager append timer task {task}"); TimerTaskData timerTaskData = timerTasks[task.id]; timerTasks[task.id] = task; task.duration += timerTaskData.duration; if (!isReplaceAction) { task.finishAction = timerTaskData.finishAction; } } public bool IsTaskExists(string id) { if (!periodicTasks.ContainsKey(id)) { return timerTasks.ContainsKey(id); } return true; } public void RemoveTimerTask(string id) { if (timerTasks.Remove(id)) { logger?.LogInfo("ScheduleManager remove timer task " + id); } } public void RemovePeriodicTask(string id) { if (periodicTasks.Remove(id)) { logger?.LogInfo("ScheduleManager remove periodic task " + id); } } public void RemoveAllTasks(string id) { logger?.LogInfo("ScheduleManager RemoveAllTasks with id " + id); RemoveTimerTask(id); RemovePeriodicTask(id); } public void RemoveAllTasks(bool isSuppressLog = false) { timerTasks.Clear(); periodicTasks.Clear(); timerTasksNoId.Clear(); periodicTasksNoId.Clear(); if (!isSuppressLog && logger != null) { logger.LogInfo("ScheduleManager RemoveAllTasks"); } } protected List<TimerTaskData> ProcessTimersList(ICollection<TimerTaskData> list, float dt) { List<TimerTaskData> list2 = new List<TimerTaskData>(); foreach (TimerTaskData item in list) { item.duration -= dt; if (item.duration <= 0f) { SafeRunAction(item.finishAction); list2.Add(item); logger?.LogInfo("ScheduleManager triggered finish action timer task " + item.id); } } return list2; } protected List<PeriodicTaskData> ProcessPeriodicList(ICollection<PeriodicTaskData> list, float dt) { List<PeriodicTaskData> list2 = new List<PeriodicTaskData>(); foreach (PeriodicTaskData item in list) { item.periodCalculated -= dt; if (!(item.periodCalculated <= 0f)) { continue; } if (item.isInfiniteRepeates || item.triggerTimes > 0) { SafeRunAction(item.periodicAction); item.periodCalculated = item.period; if (item.triggerTimes == 1) { logger?.LogInfo("ScheduleManager triggered action periodic task " + item.id); } } if (!item.isInfiniteRepeates) { item.triggerTimes--; if (item.triggerTimes <= 0) { SafeRunAction(item.finishAction); list2.Add(item); logger?.LogInfo("ScheduleManager triggered finish action periodic task " + item.id); } } } return list2; } public void OnUpdate(float dt) { try { foreach (TimerTaskData item in ProcessTimersList(timerTasks.Values, dt)) { timerTasks.Remove(item.id); logger?.LogInfo($"ScheduleManager OnUpdate finished timer task {item}"); } foreach (PeriodicTaskData item2 in ProcessPeriodicList(periodicTasks.Values, dt)) { periodicTasks.Remove(item2.id); logger?.LogInfo($"ScheduleManager OnUpdate finished periodic task {item2}"); } foreach (TimerTaskData item3 in ProcessTimersList(timerTasksNoId, dt)) { timerTasksNoId.Remove(item3); logger?.LogInfo($"ScheduleManager OnUpdate finished timer no id task {item3}"); } foreach (PeriodicTaskData item4 in ProcessPeriodicList(periodicTasksNoId, dt)) { periodicTasksNoId.Remove(item4); logger?.LogInfo($"ScheduleManager OnUpdate finished periodic no id task {item4}"); } } catch (Exception arg) { if (onUpdateErrorLimit > 0) { logger?.LogError($"ScheduleManager unexpected onUpdate error: {arg}"); onUpdateErrorLimit--; } } } public void FinishImmediatlyTimerTask(string id) { if (timerTasks.ContainsKey(id)) { SafeRunAction(timerTasks[id].finishAction); timerTasks.Remove(id); logger?.LogInfo("ScheduleManager finish and remove timer task " + id); } } public void FinishImmediatlyPeriodicTask(string id) { if (periodicTasks.ContainsKey(id)) { SafeRunAction(periodicTasks[id].finishAction); periodicTasks.Remove(id); logger?.LogInfo("ScheduleManager finish and remove periodic task " + id); } } public void FinishAllImmediatly(string id) { FinishImmediatlyTimerTask(id); FinishImmediatlyPeriodicTask(id); } public void FinishAllImmediatly() { foreach (TimerTaskData value in timerTasks.Values) { SafeRunAction(value.finishAction); } foreach (PeriodicTaskData value2 in periodicTasks.Values) { SafeRunAction(value2.finishAction); } foreach (TimerTaskData item in timerTasksNoId) { SafeRunAction(item.finishAction); } foreach (PeriodicTaskData item2 in periodicTasksNoId) { SafeRunAction(item2.finishAction); } RemoveAllTasks(); } protected void SafeRunAction(Action action) { if (action == null) { return; } try { action(); } catch (Exception arg) { logger?.LogError($"SafeRunAction error: {arg}"); } } } public class UtilityConsole { private readonly Dictionary<string, IConsoleCommand> consoleCommandsDict; private readonly IDebugLogger logger; private readonly List<string> ignoreValidationCommands; public bool isLogCheckCommand = true; public bool isLogCheckCommandParameters = true; public int logCheckCommandParametersMaxLength = 40; public bool isLogProcessCommand = true; public bool isLogProcessCommandParameters = true; public int logProcessCommandParametersMaxLength = 40; public UtilityConsole(IDebugLogger logger = null, List<string> ignoreValidationCommands = null) { consoleCommandsDict = new Dictionary<string, IConsoleCommand>(); this.logger = logger; this.ignoreValidationCommands = ignoreValidationCommands; } public void RegisterCommand(IConsoleCommand command) { if (string.IsNullOrEmpty(command?.Id)) { logger?.LogWarning("UtilityConsole.RegisterCommand: invalid console command"); } else { consoleCommandsDict[command.Id] = command; } } public static string[] ParseCommandLine(string commandLine) { return commandLine.Split(new char[1] { ';' }, StringSplitOptions.RemoveEmptyEntries); } public static string[] ParseArgs(string command) { return command.Split(new char[1] { ' ' }, StringSplitOptions.RemoveEmptyEntries); } private string GetCmdName(string cmd) { string[] array = cmd.Split(new char[1] { ' ' }, StringSplitOptions.RemoveEmptyEntries); if (array.Length == 0) { return ""; } return array[0]; } private void LogCommand(string funcPrefix, string cmd, bool isLog, bool isLogParams, int maxLen) { if (logger == null || !isLog) { return; } if (string.IsNullOrEmpty(cmd)) { logger.LogWarning(funcPrefix + " null or empty"); } else if (isLogParams) { if (cmd.Length > maxLen) { string text = cmd.Substring(0, maxLen); logger.Log(funcPrefix + " " + text + "..."); } else { logger.Log(funcPrefix + " " + cmd); } } else { logger.Log(funcPrefix + " " + GetCmdName(cmd)); } } public bool IsValidCommandLine(string commandLine) { try { if (string.IsNullOrEmpty(commandLine)) { logger?.LogDebugError("UtilityConsole.IsValidCommandLine: invalid command line"); return false; } string[] array = ParseCommandLine(commandLine); if (array == null || array.Length < 1) { logger?.LogDebugError("UtilityConsole.IsValidCommandLine: invalid commands count"); return false; } bool flag = true; string[] array2 = array; for (int i = 0; i < array2.Length; i++) { string text = array2[i]?.Trim(); LogCommand("UtilityConsole.IsValidCommandLine: check command", text, isLogCheckCommand, isLogCheckCommandParameters, logCheckCommandParametersMaxLength); string[] array3 = ParseArgs(text); if (array3 == null || array3.Length < 1) { logger?.LogDebugError("UtilityConsole.IsValidCommandLine: invalid commands count"); flag = false; continue; } string text2 = array3[0]; List<string> list = ignoreValidationCommands; if (list != null && list.Contains(text2)) { logger?.LogDebugInfo("UtilityConsole.IsValidCommandLine: validation is ignored for this command"); } else if (consoleCommandsDict.ContainsKey(text2)) { bool flag2 = consoleCommandsDict[text2].IsValidCommandArgs(array3.Skip(1)); if (!flag2) { logger?.LogDebugError("UtilityConsole.IsValidCommandLine: command with id " + text2 + " is invalid"); } flag = flag && flag2; } else { logger?.LogDebugError("UtilityConsole.IsValidCommandLine: can't find custom command with id " + text2); flag = false; } } return flag; } catch (Exception arg) { logger?.LogDebugError(string.Format("{0} error: {1}", "UtilityConsole.IsValidCommandLine:", arg)); return false; } } public bool RunCommand(string commandLine, IEventsData data, Action<string> onCustomCommandNotFound = null) { try { string[] array = ParseCommandLine(commandLine); foreach (string text in array) { LogCommand("UtilityConsole.RunCommand: process command", text, isLogProcessCommand, isLogProcessCommandParameters, logProcessCommandParametersMaxLength); string[] array2 = ParseArgs(text); string key = array2[0]; if (consoleCommandsDict.ContainsKey(key)) { try { if (consoleCommandsDict[key] is IConsoleCommandWithData consoleCommandWithData) { consoleCommandWithData.Execute(array2.Skip(1), data); } else { consoleCommandsDict[key].Execute(array2.Skip(1)); } } catch (Exception arg) { logger?.LogError(string.Format("{0} execute command error {1}", "UtilityConsole.RunCommand:", arg)); } } else if (onCustomCommandNotFound != null) { onCustomCommandNotFound(text); } else { logger?.LogError("UtilityConsole.RunCommand: execute command not found error"); } } } catch (Exception arg2) { logger?.LogError(string.Format("{0} error {1}", "UtilityConsole.RunCommand:", arg2)); return false; } return true; } } public class CommandArgsReader { private readonly ILogger logger; public CommandArgsReader(ILogger logger) { this.logger = logger; } public int ReadInt(IEnumerator<string> args, int defaultValue = 0) { if (args == null || !args.MoveNext()) { return defaultValue; } try { return int.Parse(args.Current); } catch (Exception arg) { logger?.LogWarning($"CommandArgsReader: {arg}"); return defaultValue; } } public float ReadFloat(IEnumerator<string> args, float defaultValue = 0f) { if (args == null || !args.MoveNext()) { return defaultValue; } try { return float.Parse(args.Current, CultureInfo.InvariantCulture.NumberFormat); } catch (Exception arg) { logger?.LogWarning($"CommandArgsReader: {arg}"); return defaultValue; } } public string ReadString(IEnumerator<string> args, string defaultValue = "") { if (args == null || !args.MoveNext()) { return defaultValue; } return args.Current; } public bool ReadBool(IEnumerator<string> args, bool defaultValue = false) { if (args == null || !args.MoveNext()) { return defaultValue; } try { return bool.Parse(args.Current.ToLower()); } catch (Exception arg) { logger?.LogWarning($"CommandArgsReader: {arg}"); return defaultValue; } } } public static class UtilityRandom { private static readonly Random rnd = new Random(DateTime.Now.Millisecond); public static T GetRandomItemFromList<T>(IList<T> list) { if (list == null || list.Count <= 0) { return default(T); } return list[rnd.Next(list.Count)]; } } public class HelperCommandManagerFormatted : ICommandManager { private Dictionary<string, string> commandsDict; private readonly IDebugLogger logger; private readonly string errorString = string.Empty; public int logCommandMaxLength = 50; public bool isUseLogCommandLimit = true; public HelperCommandManagerFormatted(IDebugLogger logger) { this.logger = logger; } public virtual void InitFromFile(string path) { try { Dictionary<string, string> dictionary = UtilityJson.Generate(logger).FromFile<Dictionary<string, string>>(path); commandsDict = new Dictionary<string, string>(dictionary, StringComparer.OrdinalIgnoreCase); CheckLoadedDict(); } catch (Exception arg) { logger?.LogError($"HelperCommandManagerFormatted InitFromFile load: {arg}"); commandsDict = null; } } public virtual void InitFromString(string data) { try { Dictionary<string, string> dictionary = UtilityJson.Generate(logger).FromString<Dictionary<string, string>>(data); commandsDict = new Dictionary<string, string>(dictionary, StringComparer.OrdinalIgnoreCase); CheckLoadedDict(); } catch (Exception arg) { logger?.LogError($"HelperCommandManagerFormatted InitFromString load: {arg}"); commandsDict = null; } } protected virtual void CheckLoadedDict() { if (commandsDict == null) { logger?.LogWarning("HelperCommandManagerFormatted: commandsDict null"); return; } logger?.LogInfo($"HelperCommandManagerFormatted: found commands {commandsDict.Count}"); foreach (KeyValuePair<string, string> item in commandsDict) { logger?.LogDebugInfo("command: key=" + item.Key + ", value=" + GetSubstringCmd(item.Value)); } } protected virtual string GetSubstringCmd(string cmd) { if (!isUseLogCommandLimit || cmd == null) { return cmd; } if (cmd.Length <= logCommandMaxLength) { return cmd; } return cmd.Substring(0, logCommandMaxLength) + "..."; } public virtual string GetCommandData(string eventKey, bool isLogError = false) { if (commandsDict == null) { logger?.LogWarning("HelperCommandManagerFormatted GetCommandData: commandsDict null"); return ""; } try { eventKey = eventKey.Trim(); return commandsDict[eventKey] ?? throw new NullReferenceException(); } catch (Exception arg) { if (isLogError) { logger?.LogError($"HelperCommandManagerFormatted key {eventKey}, error: {arg}"); } return errorString; } } public virtual string[] GetCommands() { if (commandsDict == null) { logger?.LogWarning("HelperCommandManagerFormatted GetCommands: commandsDict null"); return new string[0]; } List<string> list = new List<string>(); foreach (KeyValuePair<string, string> item in commandsDict) { list.Add(item.Value); } return list.ToArray(); } } public class HelperDictManager : IDictManager { private readonly ILogger logger; private readonly IEventsDataEncoder encoder; private readonly IEventsDataEncoderParams encoderParams; public HelperDictManager(ILogger logger = null) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Expected O, but got Unknown this.logger = logger; encoderParams = (IEventsDataEncoderParams)(object)(encoder = (IEventsDataEncoder)new EventsDataEncoder()); } public Dictionary<string, string> ParseDict(string data) { Dictionary<string, string> dictionary = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); try { string[] array = data.Split(new char[1] { '\n' }, StringSplitOptions.RemoveEmptyEntries); if (array == null) { logger?.LogError("HelperDictManager error, wrong args. Source: " + data); return dictionary; } string[] array2 = array; foreach (string text in array2) { string[] array3 = text.Split(new char[1] { encoderParams.ClientAppSepChar }, StringSplitOptions.RemoveEmptyEntries); if (array3.Length != 2) { logger?.LogWarning("HelperDictManager, invalid item: " + text); continue; } string text2 = array3[0]; string text3 = array3[1]; if (text3 == null || text2 == null) { logger?.LogWarning("HelperDictManager, invalid key/val: " + text2 + "/" + text3); continue; } string key = encoder.Decode(text2).Trim(); string value = encoder.Decode(text3).Trim(); dictionary.Add(key, value); } } catch (Exception arg) { logger?.LogError($"HelperDictManager error: {arg}"); } return dictionary; } } public class HelperCommandManager : ICommandManager { private readonly Dictionary<string, string> commandsDict; private readonly IDebugLogger logger; private readonly string errorString = string.Empty; public HelperCommandManager(IDebugLogger logger, string commandsDir, string commandsFname = "commands.data") { this.logger = logger; try { string path = Path.Combine(commandsDir, commandsFname); IDictManager dictManager = new HelperDictManager(); using StreamReader streamReader = new StreamReader(path); string data = streamReader.ReadToEnd(); Dictionary<string, string> dictionary = dictManager.ParseDict(data); commandsDict = new Dictionary<string, string>(dictionary, StringComparer.OrdinalIgnoreCase); logger?.LogInfo($"HelperCommandManager: found commands {commandsDict.Count}"); foreach (KeyValuePair<string, string> item in commandsDict) { logger?.LogDebugInfo("command: key=" + item.Key + ", value=" + item.Value); } } catch (Exception arg) { logger?.LogError($"HelperCommandManager load: {arg}"); commandsDict = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); } } public string GetCommandData(string eventKey, bool isLogError = false) { try { eventKey = eventKey.Trim(); return commandsDict[eventKey] ?? throw new NullReferenceException(); } catch (Exception arg) { if (isLogError) { logger?.LogError($"HelperCommandManager key {eventKey}: {arg}"); } return errorString; } } public string[] GetCommands() { List<string> list = new List<string>(); foreach (KeyValuePair<string, string> item in commandsDict) { list.Add(item.Value); } return list.ToArray(); } public virtual void InitFromFile(string path) { throw new NotImplementedException(); } public virtual void InitFromString(string data) { throw new NotImplementedException(); } } public class HelperEventManager<CustomEvent> : IEventManager<CustomEvent> where CustomEvent : class, IEvent { private readonly Dictionary<string, CustomEvent> eventsDict; private readonly IDebugLogger logger; public HelperEventManager(IDebugLogger logger) { this.logger = logger; eventsDict = new Dictionary<string, CustomEvent>(StringComparer.OrdinalIgnoreCase); try { Type type = typeof(CustomEvent); IEnumerable<Type> enumerable = from p in AppDomain.CurrentDomain.GetAssemblies().SelectMany(delegate(Assembly s) { try { return s.GetTypes(); } catch (Exception) { return new Type[0]; } }) where p.IsClass && !p.IsAbstract && !p.IsInterface && type.IsAssignableFrom(p) select p; logger?.LogInfo($"HelperEventManager: found {enumerable.Count()} events"); foreach (Type item in enumerable) { CustomEvent val = Activator.CreateInstance(item) as CustomEvent; if (val != null) { eventsDict.Add(val.Id, val); logger?.LogDebugInfo("init event '" + val.Id + "' complete"); } else { logger?.LogWarning("init event '" + val.Id + "' failed"); } } } catch (Exception arg) { logger?.LogError($"HelperEventManager error: {arg}"); } } public HelperEventManager(IDebugLogger logger, IEventManager<IEvent> manager) { this.logger = logger; eventsDict = new Dictionary<string, CustomEvent>(StringComparer.OrdinalIgnoreCase); string name = typeof(CustomEvent).Name; try { foreach (IEvent item in manager.GetEventsCollection()) { if (item is CustomEvent val) { eventsDict.Add(val.Id, val); logger?.LogDebugInfo("init event '" + val.Id + "' as '" + name + "' complete"); } } } catch (Exception arg) { logger?.LogError($"HelperEventManager: {arg}"); } } public IEnumerable<CustomEvent> GetEventsCollection() { if (eventsDict != null) { return eventsDict.Values; } return new List<CustomEvent>(); } public CustomEvent GetEvent(string eventID, bool isLogError = false) { try { eventID = eventID.Trim(); return eventsDict[eventID] ?? throw new NullReferenceException(); } catch (Exception arg) { if (isLogError) { logger?.LogError($"HelperCommandManager key {eventID}: {arg}"); } return null; } } } public class HelperLanguagesFormatted : ITranslation { protected Dictionary<string, Text> transDict; protected readonly IDebugLogger logger; protected readonly string errorString = "trans_error"; public bool isLogOnlyEnItems; public bool isSuppressLogItems = true; public HelperLanguagesFormatted(IDebugLogger logger) { this.logger = logger; } public virtual void InitFromFile(string path) { try { Dictionary<string, Text> dictionary = UtilityJson.Generate(logger).FromFile<Dictionary<string, Text>>(path); transDict = new Dictionary<string, Text>(dictionary, StringComparer.OrdinalIgnoreCase); CheckLoadedDict(); } catch (Exception arg) { logger?.LogError($"HelperLanguagesFormatted InitFromFile load: {arg}"); transDict = null; } } public virtual void InitFromString(string data) { try { Dictionary<string, Text> dictionary = UtilityJson.Generate(logger).FromString<Dictionary<string, Text>>(data); transDict = new Dictionary<string, Text>(dictionary, StringComparer.OrdinalIgnoreCase); CheckLoadedDict(); } catch (Exception arg) { logger?.LogError($"HelperLanguagesFormatted InitFromString load: {arg}"); transDict = null; } } protected virtual void CheckLoadedDict() { if (transDict == null) { logger?.LogWarning("HelperLanguagesFormatted: transDict null"); return; } logger?.LogInfo($"HelperLanguagesFormatted: found translates {transDict.Count}"); if (isSuppressLogItems || logger == null) { return; } foreach (KeyValuePair<string, Text> item in transDict) { if (isLogOnlyEnItems) { logger.LogDebugInfo("key=" + item.Key + ", en=" + item.Value.en); continue; } logger.LogDebugInfo("key=" + item.Key + ", ru=" + item.Value.ru + ", en=" + item.Value.en); } } public virtual string GetTrans(string key, Languages lang) { return GetTrans(key, lang.ToString()); } public virtual string GetTrans(string key, string lang) { if (transDict == null) { logger?.LogWarning("HelperLanguagesFormatted transDict is null"); return errorString; } try { key = key.Trim(); lang = lang.Trim(); return transDict[key].GetTrans(lang); } catch (Exception arg) { logger?.LogError($"HelperLanguagesFormatted key {key} lang {lang}, error: {arg}"); return errorString; } } } public class HelperLog : ILoggerWithConsole, ILogger { protected readonly string path; protected const string baseLogName = "interactive_mod_log.txt"; public bool isLogConsole = true; public bool isLogFile = true; public ConsoleColor infoColor = ConsoleColor.White; public ConsoleColor warningColor = ConsoleColor.Yellow; public ConsoleColor errorColor = ConsoleColor.Red; protected virtual string LogTime => DateTime.Now.ToString("h:mm:ss:fff"); public HelperLog(string logDir) : this(logDir, "interactive_mod_log.txt") { } public HelperLog(string logDir, string logFname) { if (logDir == "" || Directory.Exists(logDir)) { path = Path.Combine(logDir, logFname); } } protected virtual void WriteToFile(string s) { if (path != null) { using (StreamWriter streamWriter = new StreamWriter(path, append: true, Encoding.UTF8)) { streamWriter.WriteLine(s); } } } public virtual void Log(object obj) { if (isLogFile) { WriteToFile($"{LogTime} {obj}"); } } public virtual void LogConsole(string text, string prefix, ConsoleColor prefixColor) { Console.ForegroundColor = prefixColor; Console.Write(LogTime + " " + prefix + " "); Console.ResetColor(); Console.WriteLine(text); } protected virtual void LogWithConsole(object obj, string prefix, ConsoleColor color) { Log($"{prefix} {obj}"); if (isLogConsole) { LogConsole(obj.ToString(), prefix, color); } } public virtual void LogInfo(object obj) { LogWithConsole(obj, "[INFO]", infoColor); } public virtual void LogWarning(object obj) { LogWithConsole(obj, "[WARNING]", warningColor); } public virtual void LogError(object obj) { LogWithConsole(obj, "[ERROR]", errorColor); } public virtual void LogInfoConsoleOnly(object obj) { if (isLogConsole) { LogConsole(obj.ToString(), "[INFO]", infoColor); } } public virtual void LogWarningConsoleOnly(object obj) { if (isLogConsole) { LogConsole(obj.ToString(), "[WARNING]", warningColor); } } public virtual void LogErrorConsoleOnly(object obj) { if (isLogConsole) { LogConsole(obj.ToString(), "[ERROR]", errorColor); } } public virtual void LogInfoFileOnly(object obj) { Log($"[INFO] {obj}"); } public virtual void LogWarningFileOnly(object obj) { Log($"[WARNING] {obj}"); } public virtual void LogErrorFileOnly(object obj) { Log($"[ERROR] {obj}"); } public virtual void LogClear() { if (path != null) { using (new StreamWriter(path)) { } } } } public class HelperParse : IParseManager { private readonly ILogger logger; public HelperParse(ILogger logger = null) { this.logger = logger; } public Type GetEnumUnderlyingType(Type type) { if (!type.IsEnum) { return type; } FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (fields == null || fields.Length < 1) { return type; } return fields[0].FieldType; } public bool TryParseEnum<TEnum>(string arg, out TEnum result, TEnum defaultValue = default(TEnum)) { Type typeFromHandle = typeof(TEnum); try { Type enumUnderlyingType = GetEnumUnderlyingType(typeFromHandle); if ((object)enumUnderlyingType == typeof(int)) { if (int.TryParse(arg, out var result2) && Enum.IsDefined(typeFromHandle, result2)) { result = (TEnum)Enum.ToObject(typeFromHandle, result2); return true; } logger?.LogWarning("TryParseEnum can't parse int from " + arg + " for enum " + typeFromHandle.Name); } else if ((object)enumUnderlyingType == typeof(sbyte)) { if (sbyte.TryParse(arg, out var result3) && Enum.IsDefined(typeFromHandle, result3)) { result = (TEnum)Enum.ToObject(typeFromHandle, result3); return true; } logger?.LogWarning("TryParseEnum can't parse sbyte from " + arg + " for enum " + typeFromHandle.Name); } else { foreach (TEnum value in Enum.GetValues(typeFromHandle)) { if (Enum.GetName(typeFromHandle, value).Equals(arg, StringComparison.OrdinalIgnoreCase)) { result = value; return true; } } logger?.LogWarning("TryParseEnum can't find item by direct name " + arg + " for enum " + typeFromHandle.Name); } } catch (Exception arg2) { logger?.LogError($"TryParseEnum error happened when process {arg} for enum {typeFromHandle.Name}: {arg2}"); } result = defaultValue; return false; } public bool TryParseBool(string arg, out bool result, bool defaultValue = false) { if (bool.TryParse(arg, out result)) { return true; } if (int.TryParse(arg, out var result2)) { result = result2 != 0; return true; } logger?.LogWarning($"TryParseBool error happened when process {arg}. Will be used default {defaultValue}"); result = defaultValue; return false; } } public class UtilityJson { private static Func<IJsonUtil> customGenerator; public static IJsonUtil Generate(IDebugLogger logger) { if (customGenerator == null) { return new HelperJson(logger, File.Exists(".mod_json_debug")); } return customGenerator(); } public static void RegisterCustomGenerator(Func<IJsonUtil> generator) { customGenerator = generator; } } public class UtilitySettings { public static string CommandUpdateSettingsID => "command_update_parameters"; public static string BaseFolder { get; set; } = "ChaosTricks_InteractiveModData"; public static string SettingsFileName => "settings.txt"; public static string SettingsPath => Path.Combine(BaseFolder, SettingsFileName); public static T LoadSettings<T>(IDebugLogger logger) where T : class { string text = string.Empty; try { text = SettingsPath; T result = UtilityJson.Generate(logger).FromFile<T>(text); logger?.LogInfo("settings loaded"); return result; } catch (FileNotFoundException) { logger?.LogWarning("can't load settings. File not found at " + text + ". Using standard."); } catch (Exception arg) { logger?.LogError($"can't load settings. Using standard. \n{arg}"); } T result2 = null; try { result2 = Activator.CreateInstance<T>(); return result2; } catch (Exception arg2) { logger?.LogError($"can't create default data class. \n{arg2}"); } return result2; } } public enum Languages { ru, en } public class Text { public string ru; public string en; public Text(string ru, string en) { this.ru = ru; this.en = en; } public Text() { } public string GetTrans(Languages lang) { if (lang != Languages.en) { return ru; } return en; } public string GetTrans(string lang) { if (GetLangFromAppLang(lang) != Languages.en) { return ru; } return en; } private Languages GetLangFromAppLang(string lang) { lang = lang?.Trim()?.ToLower(); switch (lang) { case "ru": case "russian": case "rus": case "русский": case "ру": case "рус": return Languages.ru; default: return Languages.en; } } } public class HelperLanguages : ITranslation { private readonly Dictionary<string, Text> transDict; private readonly ILogger logger; private readonly string errorString = "trans_error"; public HelperLanguages(ILogger logger, string langsDir, string langsFname = "langs.data") { this.logger = logger; try { string path = Path.Combine(langsDir, langsFname); IDictManager dictManager = new HelperDictManager(logger); using (StreamReader streamReader = new StreamReader(path)) { string data = streamReader.ReadToEnd(); Dictionary<string, string> source = dictManager.ParseDict(data); transDict = GetTransDict(source); } logger?.LogInfo($"HelperLanguages: found translates {transDict.Count}"); } catch (Exception arg) { logger?.LogError($"HelperLanguages load: {arg}"); transDict = new Dictionary<string, Text>(StringComparer.OrdinalIgnoreCase); } } protected Dictionary<string, Text> GetTransDict(Dictionary<string, string> source) { Dictionary<string, Text> dictionary = new Dictionary<string, Text>(StringComparer.OrdinalIgnoreCase); foreach (KeyValuePair<string, string> item in source) { string[] array = item.Value.Split(new string[1] { "%lang%" }, StringSplitOptions.RemoveEmptyEntries); if (array == null || array.Length != 2) { logger?.LogError("HelperLanguages parse item: " + item.Key); continue; } string ru = array[0]; string en = array[1]; dictionary.Add(item.Key, new Text(ru, en)); } return dictionary; } public string GetTrans(string key, Languages lang) { return GetTrans(key, lang.ToString()); } public string GetTrans(string key, string lang) { try { key = key.Trim(); lang = lang.Trim(); return transDict[key].GetTrans(lang); } catch (Exception arg) { logger?.LogError($"HelperLanguages key {key} lang {lang}: {arg}"); return errorString; } } public virtual void InitFromFile(string path) { throw new NotImplementedException(); } public void InitFromString(string data) { throw new NotImplementedException(); } } } namespace ModHelper.Interfaces { public interface ICommandTargets { bool IsAllPlayers { get; } } public interface IConsoleCommandWithData : IConsoleCommand { bool Execute(IEnumerable<string> args, IEventsData data); } public interface IConsoleCommand { string Id { get; } bool Execute(IEnumerable<string> args); bool IsValidCommandArgs(IEnumerable<string> args); } public interface IDebugLogger : ILoggerWithConsole, ILogger { void LogDebugInfo(object obj); void LogDebugWarning(object obj); void LogDebugError(object obj); } public interface ILoggerWithConsole : ILogger { void LogInfoConsoleOnly(object obj); void LogWarningConsoleOnly(object obj); void LogErrorConsoleOnly(object obj); void LogInfoFileOnly(object obj); void LogWarningFileOnly(object obj); void LogErrorFileOnly(object obj); } public interface ICommandNotify { string ProcessMsg(string msg); } public interface ICommand { string Id { get; } } public interface IDictionaryItem<T> { string Key { get; } T Value { get; } } public interface IJsonUtil { T FromFile<T>(string path) where T : class; T FromString<T>(string s) where T : class; } public interface IDictManager { Dictionary<string, string> ParseDict(string data); } public interface ICommandManager { string GetCommandData(string eventKey, bool isLogError = false); string[] GetCommands(); void InitFromString(string data); void InitFromFile(string path); } public interface IEventManager<CustomEvent> { CustomEvent GetEvent(string eventID, bool isLogError = false); IEnumerable<CustomEvent> GetEventsCollection(); } public interface IEventWithData : IEvent { bool Execute(IEventsData data); } public interface IEvent { string Id { get; } bool Execute(); } public interface ILogger { void Log(object obj); void LogInfo(object obj); void LogWarning(object obj); void LogError(object obj); void LogClear(); } public interface ITranslation { string GetTrans(string key, Languages lang); string GetTrans(string key, string lang); void InitFromString(string data); void InitFromFile(string path); } public interface IParseManager { bool TryParseEnum<TEnum>(string arg, out TEnum result, TEnum defaultValue = default(TEnum)); bool TryParseBool(string arg, out bool result, bool defaultValue = false); } }
ChaosTricks_RoR2_plugins/ModHelperUnity.dll
Decompiled 2 years agousing System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Security; using System.Security.Permissions; using System.Text; using System.Text.RegularExpressions; using EventsIO.Interfaces; using ModHelper; using ModHelper.Interfaces; using ModHelperUnity.Data; using ModHelperUnity.Interfaces; using ModHelperUnity.UtilityGUI; using Mono.Cecil; using Mono.Cecil.Cil; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("ModHelperUnity")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("BFT")] [assembly: AssemblyProduct("ModHelperUnity")] [assembly: AssemblyCopyright("Copyright © 2020")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("4afa0e1e-341b-4554-97c1-0c38ad74f246")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] namespace ModHelperUnity { public abstract class TypedNotifyBase : MonoBehaviour, IComponentTypedNotify { private bool isDisposed; private Queue<TypedNotifyMessage> messages; private bool isInitiated; private bool isMessageProcessed; private float delayAfterNotify; private bool isShowAnimationStageFinished; private bool isShowMessageStageFinished; private bool isHideAnimationStageFinished; protected int logLimit; protected IDebugLogger logger; protected Dictionary<string, Texture2D> messageTextures = new Dictionary<string, Texture2D>(); public TypedNotifySettings Settings { get; protected set; } protected TypedNotifyMessage CurrentMessage { get; private set; } protected TypedNotifyParameters CurrentNotifyParameters { get; private set; } protected virtual void Log(object obj) { IDebugLogger obj2 = logger; if (obj2 != null) { ((ILogger)obj2).LogInfo((object)$"TypedNotifyBase: {obj}"); } } protected virtual void LimitedLogError(object obj) { if (logLimit > 0 && logger != null) { ((ILogger)logger).LogError((object)$"TypedNotifyBase: {obj}"); logLimit--; } } protected virtual Texture2D GetMessageTexture(string type) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Expected O, but got Unknown if (messageTextures.ContainsKey(type)) { return messageTextures[type]; } return new Texture2D(2, 2); } protected void LoadFadeSettings(string settingsFilePath, Func<string, byte[]> customFileReader = null) { try { if (customFileReader == null) { Settings = UtilityJson.Generate(logger).FromFile<TypedNotifySettings>(settingsFilePath); } else { byte[] bytes = customFileReader(settingsFilePath); string @string = Encoding.UTF8.GetString(bytes); Settings = UtilityJson.Generate(logger).FromString<TypedNotifySettings>(@string); } } catch (Exception arg) { Log($"LoadFadeSettings error: {arg}"); } if (Settings == null) { Settings = new TypedNotifySettings(); } } protected Texture2D LoadImage(string imageFilePath, Func<string, byte[]> customFileReader = null) { //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Expected O, but got Unknown try { Texture2D val = UtilityUI.LoadImage(imageFilePath, customFileReader); Log($"LoadImage {imageFilePath}: width {((Texture)val).width}, height {((Texture)val).height}"); return val; } catch (Exception arg) { Log($"LoadImage {imageFilePath} error: {arg}"); return new Texture2D(2, 2, (TextureFormat)4, false); } } protected void LoadResources(string folderPath, Func<string, byte[]> customFileReader = null) { Log("LoadResources"); string text = "notify_settings.data"; string settingsFilePath = ((folderPath == null) ? text : Path.Combine(folderPath, text)); LoadFadeSettings(settingsFilePath, customFileReader); ClearMessageTextures(); if (Settings.notifyParameters != null) { TypedNotifyParameters[] notifyParameters = Settings.notifyParameters; foreach (TypedNotifyParameters typedNotifyParameters in notifyParameters) { Log(typedNotifyParameters.ToString()); string imageFilePath = ((folderPath == null) ? typedNotifyParameters.imageFileName : Path.Combine(folderPath, typedNotifyParameters.imageFileName)); Texture2D val = LoadImage(imageFilePath, customFileReader); messageTextures[typedNotifyParameters.type] = val; ((Texture)val).filterMode = (FilterMode)2; ((Texture)val).anisoLevel = 16; } } } public virtual void PostInit(string folderPath, IDebugLogger logger = null, Func<string, byte[]> customFileReader = null) { if (!isInitiated) { ForcePostInit(folderPath, logger, customFileReader); } Log("post init completed"); } public virtual void ForcePostInit(string folderPath, IDebugLogger logger = null, Func<string, byte[]> customFileReader = null) { this.logger = logger; try { messages = new Queue<TypedNotifyMessage>(); CurrentMessage = null; CurrentNotifyParameters = new TypedNotifyParameters(); logLimit = 10; isInitiated = true; LoadResources(folderPath, customFileReader); } catch (Exception arg) { Log($"ForcePostInit error: {arg}"); } Log("force init"); } protected virtual string ProcessCustomTemplates(string message, IEventsData eventData, ITranslation translation) { try { return Regex.Replace(message, "%template_.+?%", (Match s) => translation.GetTrans(s.Value, eventData.Lang)); } catch (Exception arg) { Log($"ProcessCustomTemplates error: {arg}"); return message; } } protected virtual string GenerateMessage(IEventsData eventData, ITranslation translation) { //IL_002d: 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) TypedNotifyParameters typedNotifyParameters = GetTypedNotifyParameters(eventData); string trans = translation.GetTrans(eventData.EventID, eventData.Lang); string message = typedNotifyParameters.messageTemplate.Replace("%name%", UtilityUI.GetColoredText(eventData.Username, typedNotifyParameters.nicknameTextColor)).Replace("%message%", UtilityUI.GetColoredText(trans, typedNotifyParameters.messageTextColor)); return ProcessCustomTemplates(message, eventData, translation); } public virtual TypedNotifyParameters GetTypedNotifyParameters(string type) { TypedNotifyParameters[] notifyParameters = Settings.notifyParameters; if (notifyParameters == null || notifyParameters.Length == 0) { Log("warning, notify types empty (use default)"); return new TypedNotifyParameters(); } TypedNotifyParameters[] array = notifyParameters; foreach (TypedNotifyParameters typedNotifyParameters in array) { if (typedNotifyParameters.type == type) { return typedNotifyParameters; } } return notifyParameters[0]; } public virtual TypedNotifyParameters GetTypedNotifyParameters(IEventsData eventData) { TypedNotifyParameters[] notifyParameters = Settings.notifyParameters; if (notifyParameters == null || notifyParameters.Length == 0) { Log("warning, notify types empty (use default)"); return new TypedNotifyParameters(); } TypedNotifyParameters[] array = notifyParameters; foreach (TypedNotifyParameters typedNotifyParameters in array) { string[] events = typedNotifyParameters.events; if (events != null && events.Contains(eventData.EventID)) { return typedNotifyParameters; } } return notifyParameters[0]; } public virtual void AddNotifyToQueue(IEventsData eventData, ITranslation translation, Func<string, string> converter = null) { if (eventData == null) { Log("warning, eventData is null"); } if (translation == null) { Log("warning, translation is null"); } TypedNotifyParameters typedNotifyParameters = GetTypedNotifyParameters(eventData); string text = GenerateMessage(eventData, translation); if (converter != null) { text = converter(text); } AddNotifyToQueue(new TypedNotifyMessage(text.ToUpperInvariant(), typedNotifyParameters.type, typedNotifyParameters.showMessageDuration, typedNotifyParameters.showFadeAnimationDuration, typedNotifyParameters.hideFadeAnimationDuration)); } public virtual void AddNotifyToQueue(string message, string type) { TypedNotifyParameters typedNotifyParameters = GetTypedNotifyParameters(type); AddNotifyToQueue(new TypedNotifyMessage(message, type, typedNotifyParameters.showMessageDuration, typedNotifyParameters.showFadeAnimationDuration, typedNotifyParameters.hideFadeAnimationDuration)); } public virtual void AddNotifyToQueue(TypedNotifyMessage notifyMessage) { if (!isInitiated) { Log("error, attempt to use the manager before init completed"); return; } if (notifyMessage == null) { Log("error, message is null"); return; } messages.Enqueue(notifyMessage); Log("add new notify message: " + notifyMessage.message); } public virtual void ClearNotifyQueue() { if (isInitiated) { messages.Clear(); } } public virtual void StopCurrentNotify() { CurrentMessage = null; isShowAnimationStageFinished = true; isShowMessageStageFinished = true; isHideAnimationStageFinished = true; isMessageProcessed = false; } protected virtual void Update() { try { if (!isInitiated) { return; } if (CurrentMessage == null) { if (delayAfterNotify > 0f) { delayAfterNotify -= Time.deltaTime; } else if (messages.Count > 0) { CurrentMessage = messages.Peek(); CurrentNotifyParameters = GetTypedNotifyParameters(CurrentMessage.messageType); delayAfterNotify = CurrentNotifyParameters.delayAfterNotify; StartShowAnimation(); } return; } if (!isShowAnimationStageFinished) { UpdateProcessShowAnimation(); } else if (!isShowMessageStageFinished) { UpdateProcessNoAnimationStage(); } else if (!isHideAnimationStageFinished) { UpdateProcessHideAnimation(); } if (isMessageProcessed) { messages.Dequeue(); CurrentMessage = null; isMessageProcessed = false; } } catch (Exception obj) { LimitedLogError(obj); } } protected virtual void UpdateProcessShowAnimation() { if (CurrentMessage.showFadeAnimationDuration > 0f) { CurrentMessage.showFadeAnimationDuration -= Time.deltaTime; } else { FinishShowAnimation(); } } protected virtual void UpdateProcessNoAnimationStage() { if (CurrentMessage.showMessageDuration > 0f) { CurrentMessage.showMessageDuration -= Time.deltaTime; } else { StartHideAnimation(); } } protected virtual void UpdateProcessHideAnimation() { if (CurrentMessage.hideFadeAnimationDuration > 0f) { CurrentMessage.hideFadeAnimationDuration -= Time.deltaTime; } else { FinishHideAnimation(); } } protected virtual void Start() { } protected virtual void Awake() { } protected virtual void OnGUI() { } protected virtual void StartShowAnimation() { isShowAnimationStageFinished = false; Log("start show animation"); } protected virtual void FinishShowAnimation() { isShowAnimationStageFinished = true; isShowMessageStageFinished = false; Log("finish show animation"); } protected virtual void StartHideAnimation() { isHideAnimationStageFinished = false; isShowMessageStageFinished = true; Log("start hide animation"); } protected virtual void FinishHideAnimation() { isHideAnimationStageFinished = true; isMessageProcessed = true; Log("finish hide animation"); } public void Dispose() { Dispose(disposing: true); GC.SuppressFinalize(this); } protected virtual void ClearMessageTextures() { if (messageTextures == null) { return; } foreach (Texture2D value in messageTextures.Values) { ((Object)value).hideFlags = (HideFlags)61; Object.Destroy((Object)(object)value); } } protected virtual void Dispose(bool disposing) { if (!isDisposed) { ClearMessageTextures(); messageTextures = null; isDisposed = true; } } ~TypedNotifyBase() { try { Dispose(disposing: false); } finally { ((object)this).Finalize(); } } } public static class UtilityUI { public static int StandardScreenWidth => 2560; public static int StandardScreenHeight => 1440; public static string GetColoredText(string text, Color32 color) { //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) string text2 = ColorUtility.ToHtmlStringRGBA(Color32.op_Implicit(color)); return "<color=#" + text2 + ">" + text + "</color>"; } public static Texture2D LoadImage(string imageFilePath, Func<string, byte[]> customFileReader = null) { //IL_0017: 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) //IL_0023: Expected O, but got Unknown //IL_0025: Expected O, but got Unknown byte[] array = ((customFileReader == null) ? File.ReadAllBytes(imageFilePath) : customFileReader(imageFilePath)); Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false); ImageConversion.LoadImage(val, array); return val; } public static float CalcScreenFactor(int baseScreenSize, int currentScreenSize) { if (baseScreenSize != currentScreenSize) { return (float)currentScreenSize / (float)baseScreenSize; } return 1f; } } public class MathUtility { public static bool RandomBool() { return Random.value > 0.5f; } public static int GetRandomSign() { if (!RandomBool()) { return 1; } return -1; } public static Vector3 GetRandomPointOnCircle(float radius = 1f) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: 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_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) Vector2 insideUnitCircle = Random.insideUnitCircle; return Vector2.op_Implicit(((Vector2)(ref insideUnitCircle)).normalized * radius); } public static Vector3 GetRandomPointOnCircleInForward(Vector3 forward, float radiusMin, float radiusMax, float minAngleInDeg = -90f, float maxAngleInDeg = 90f) { //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_0010: 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_005d: 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) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) Vector3 val = forward; val.y = 0f; val = ((Vector3)(ref val)).normalized; if (minAngleInDeg > maxAngleInDeg) { float num = minAngleInDeg; minAngleInDeg = maxAngleInDeg; maxAngleInDeg = num; } float num2 = Random.Range(minAngleInDeg, maxAngleInDeg); if (radiusMin < 0f) { radiusMin = 0f; } if (radiusMax < 0f) { radiusMax = 1f; } if (radiusMin > radiusMax) { float num3 = radiusMin; radiusMin = radiusMax; radiusMax = num3; } float num4 = Random.Range(radiusMin, radiusMax); Vector3 result = default(Vector3); float num5 = (float)Math.PI / 180f * num2; float num6 = Mathf.Atan2(val.z, val.x); num5 += num6; result.x = num4 * Mathf.Cos(num5); result.z = num4 * Mathf.Sin(num5); return result; } public static Vector3 FindRandomSpawnPointNearPosition(Vector3 pos, float minDistance, float maxDistance) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) if (maxDistance < 0f) { maxDistance = 10f; } if (minDistance < 0f || minDistance > maxDistance) { minDistance = 0f; } Vector3 result = default(Vector3); float num = Random.Range(-(float)Math.PI, (float)Math.PI); float num2 = Random.Range(minDistance, maxDistance); result.x = Mathf.Floor(pos.x + num2 * Mathf.Cos(num)); result.z = Mathf.Floor(pos.z + num2 * Mathf.Sin(num)); result.y = pos.y; return result; } public static Vector3 FindRandomSpawnPointNearPositionFixY(Vector3 pos, float minDistance, float maxDistance, float yFixOffset, LayerMask mask) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0003: 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) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_004c: 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_003f: Unknown result type (might be due to invalid IL or missing references) Vector3 result = FindRandomSpawnPointNearPosition(pos, minDistance, maxDistance); RaycastHit val = default(RaycastHit); if (Physics.Raycast(pos + Vector3.up * 10f, Vector3.down, ref val, 10f, LayerMask.op_Implicit(mask))) { result = ((RaycastHit)(ref val)).point; result.y += yFixOffset; } return result; } public static Vector3 GetRandomVector(Vector3 randomRangeMin, Vector3 randomRangeMax) { //IL_0000: 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_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_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) float num = Random.Range(randomRangeMin.x, randomRangeMax.x); float num2 = Random.Range(randomRangeMin.y, randomRangeMax.y); float num3 = Random.Range(randomRangeMin.z, randomRangeMax.z); return new Vector3(num, num2, num3); } public static void LookAt(Transform obj, Transform target) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: 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_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) Vector3 val = target.position - obj.position; obj.rotation = Quaternion.LookRotation(val); } } public static class Loader { private static GameObject hookObj; private static readonly string AssemblyName; private static readonly string ClassMod; public static ILogger Logger { get; } public static GameObject HookObj { get; set; } static Loader() { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Expected O, but got Unknown AssemblyName = "InteractiveMod"; ClassMod = AssemblyName; Logger = (ILogger)new HelperLog(UtilitySettings.BaseFolder, "loader_log.txt"); Logger.LogClear(); } public static void LoadAssembly() { //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Expected O, but got Unknown Logger.LogInfo((object)"Load mod assembly"); Assembly assembly = AppDomain.CurrentDomain.Load(AssemblyName); if (string.Equals(assembly.GetName().Name, AssemblyName, StringComparison.OrdinalIgnoreCase)) { Type[] types = assembly.GetTypes(); foreach (Type type in types) { bool num = string.Equals(type.Name, ClassMod, StringComparison.OrdinalIgnoreCase); Type typeFromHandle = typeof(MonoBehaviour); bool flag = type.IsAssignableFrom(typeFromHandle) || type.IsSubclassOf(typeFromHandle); if (num && flag) { hookObj = new GameObject(); Component obj = hookObj.AddComponent(type); Component obj2 = ((obj is MonoBehaviour) ? obj : null); hookObj.SetActive(true); ((Behaviour)obj2).enabled = true; Logger.LogInfo((object)"Loader init success"); return; } } } else { Logger.LogWarning((object)"Wrong assembly mod name"); } Logger.LogError((object)"Init failed"); } public static void Init() { Logger.LogClear(); Logger.LogInfo((object)"Loader triggered"); try { LoadAssembly(); } catch (Exception arg) { Logger.LogError((object)$"ModHelperUnity.Init: {arg}"); } } } public class Patcher { private readonly string nameModDll = "ModHelperUnity.dll"; private readonly string nameMod = "ModHelperUnity"; private readonly ILogger logger = (ILogger)new HelperLog(UtilitySettings.BaseFolder, "patcher_log.txt"); public void ExecutePatch() { try { logger.LogClear(); logger.LogInfo((object)$"Patcher v{Assembly.GetExecutingAssembly().GetName().Version}"); bool flag = false; string[] files = Directory.GetFiles(Directory.GetCurrentDirectory()); for (int i = 0; i < files.Length; i++) { string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(files[i]); string path = Path.Combine(Environment.CurrentDirectory, fileNameWithoutExtension + "_Data"); path = Path.Combine(path, "Managed"); string text = "UnityEngine.CoreModule.dll"; string text2 = "UnityEngine.dll"; string fullPath = Path.GetFullPath(Path.Combine(path, text)); string fullPath2 = Path.GetFullPath(Path.Combine(path, text2)); if (!Directory.Exists(path) || (!File.Exists(fullPath2) && !File.Exists(fullPath))) { continue; } flag = true; logger.LogInfo((object)("found game " + fileNameWithoutExtension)); logger.LogInfo((object)("target managed " + path)); logger.LogInfo((object)("try to patching " + text)); if (!PatchUnityEngine(path, fullPath, text)) { logger.LogInfo((object)("try to patching " + text2)); if (!PatchUnityEngine(path, fullPath2, text2)) { logger.LogWarning((object)"patching failed"); } } } if (!flag) { logger.LogError((object)"didn't find any games to patch"); } } catch (Exception arg) { logger.LogError((object)$"Patcher unexpected error: {arg}"); } } private bool PatchUnityEngine(string managedDir, string unityOutputDll, string targetDllName) { try { string fullPath = Path.GetFullPath(Path.Combine(managedDir, targetDllName + ".bak")); using MemoryStream memoryStream = new MemoryStream(File.ReadAllBytes(unityOutputDll)); AssemblyDefinition val = AssemblyDefinition.ReadAssembly((Stream)memoryStream); try { if (val == null) { logger.LogInfo((object)(unityOutputDll + " not found")); return false; } if (IsNeedPatching(val)) { AssemblyDefinition val2 = AssemblyDefinition.ReadAssembly(Path.Combine(Preloader.GetAssemblyModFolderFullPath(), nameModDll)); try { if (val2 == null) { return false; } logger.LogInfo((object)("found mod dll: " + val2.FullName)); logger.LogInfo((object)("try to backup into " + fullPath)); File.Copy(unityOutputDll, fullPath, overwrite: true); InjectAssembly(val, val2); val.Write(unityOutputDll); } finally { ((IDisposable)val2)?.Dispose(); } } } finally { ((IDisposable)val)?.Dispose(); } } catch (Exception arg) { logger.LogError((object)$"Patcher: {arg}"); return false; } logger.LogInfo((object)"Patching successful finished"); return true; } private void InjectAssembly(AssemblyDefinition unity, AssemblyDefinition injected) { //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Expected O, but got Unknown //IL_00e9: 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) logger.LogInfo((object)"InjectAssembly started"); MethodDefinition val = ((IEnumerable<MethodDefinition>)((IEnumerable<TypeDefinition>)injected.MainModule.Types).First((TypeDefinition x) => ((MemberReference)x).Name == "Loader").Methods).First((MethodDefinition x) => ((MemberReference)x).Name == "Init"); MethodReference val2 = unity.MainModule.ImportReference((MethodReference)(object)val); logger.LogInfo((object)"try to find Application in unity"); TypeDefinition obj = ((IEnumerable<TypeDefinition>)unity.MainModule.Types).First((TypeDefinition x) => ((MemberReference)x).Name == "Application"); TypeReference val3 = unity.MainModule.ImportReference(typeof(void)); MethodDefinition val4 = new MethodDefinition(".cctor", (MethodAttributes)6289, val3); ILProcessor iLProcessor = val4.Body.GetILProcessor(); iLProcessor.Append(iLProcessor.Create(OpCodes.Call, val2)); iLProcessor.Append(iLProcessor.Create(OpCodes.Ret)); obj.Methods.Add(val4); logger.LogInfo((object)"injecting assembly finished"); } private bool IsNeedPatching(AssemblyDefinition unity) { if (((IEnumerable<AssemblyNameReference>)unity.MainModule.AssemblyReferences).Any((AssemblyNameReference x) => x.Name.Contains(nameMod))) { logger.LogInfo((object)"this assembly has already been patched"); return false; } return true; } } public class Preloader { private static string baseFolderFullPath; private static readonly ILogger logger = (ILogger)new HelperLog(UtilitySettings.BaseFolder, "preloader_log.txt"); public static string GetAssemblyModFolderFullPath() { return baseFolderFullPath; } public static void Main() { logger.LogClear(); logger.LogInfo((object)"Preloader main"); baseFolderFullPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); AppDomain.CurrentDomain.AssemblyResolve += ModAssemblyResolve; new Patcher().ExecutePatch(); } private static Assembly ModAssemblyResolve(object sender, ResolveEventArgs args) { try { string text = Path.Combine(GetAssemblyModFolderFullPath(), new AssemblyName(args.Name).Name + ".dll"); logger.LogInfo((object)text); if (File.Exists(text)) { return Assembly.LoadFrom(text); } } catch (Exception arg) { logger.LogError((object)$"error: {arg}"); } return null; } } } namespace ModHelperUnity.UtilityGUI { public class TypedNotifyOnGUI : TypedNotifyBase { private float currentAlpha; private float targetAlpha; protected Dictionary<string, Font> fonts; public override void ForcePostInit(string folderPath, IDebugLogger logger = null, Func<string, byte[]> customFileReader = null) { base.ForcePostInit(folderPath, logger, customFileReader); try { fonts = new Dictionary<string, Font>(); TypedNotifyParameters[] notifyParameters = base.Settings.notifyParameters; foreach (TypedNotifyParameters typedNotifyParameters in notifyParameters) { try { string fontPath = typedNotifyParameters.fontPath; if (!fonts.ContainsKey(fontPath)) { Font val = Resources.Load<Font>(fontPath); if ((Object)(object)val != (Object)null) { fonts.Add(fontPath, val); } } } catch (Exception arg) { if (logger != null) { ((ILogger)logger).LogError((object)$"TypedNotifyOnGUI loading font: {arg}"); } } } } catch (Exception arg2) { if (logger != null) { ((ILogger)logger).LogError((object)$"TypedNotifyOnGUI PostInit: {arg2}"); } } } protected Font GetFont(string path, int size) { try { if (fonts.ContainsKey(path)) { return fonts[path]; } string key = $"{path}_{size}"; if (fonts.ContainsKey(key)) { return fonts[key]; } Font val = Font.CreateDynamicFontFromOSFont(path, size); if ((Object)(object)val != (Object)null) { fonts.Add(key, val); } return val; } catch (Exception arg) { IDebugLogger obj = logger; if (obj != null) { ((ILogger)obj).LogError((object)$"finding font: {arg}"); } } return null; } protected virtual void SetupAlpha(float baseDuration) { if (!Mathf.Approximately(currentAlpha, targetAlpha)) { currentAlpha = Mathf.MoveTowards(currentAlpha, targetAlpha, Time.deltaTime / baseDuration); } } protected override void UpdateProcessShowAnimation() { SetupAlpha(base.CurrentNotifyParameters.showFadeAnimationDuration); base.UpdateProcessShowAnimation(); } protected override void UpdateProcessNoAnimationStage() { SetupAlpha(base.CurrentNotifyParameters.showMessageDuration); base.UpdateProcessNoAnimationStage(); } protected override void UpdateProcessHideAnimation() { SetupAlpha(base.CurrentNotifyParameters.hideFadeAnimationDuration); base.UpdateProcessHideAnimation(); } protected override void StartShowAnimation() { base.StartShowAnimation(); targetAlpha = 1f; } protected override void StartHideAnimation() { base.StartHideAnimation(); targetAlpha = 0f; } protected string GetFadedText(string text) { string text2 = ((int)(255f * currentAlpha)).ToString("X2"); return text.Replace("FF>", text2 + ">"); } protected override void OnGUI() { //IL_0039: 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_0051: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: 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_0122: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Expected O, but got Unknown //IL_01e9: Unknown result type (might be due to invalid IL or missing references) //IL_01ef: Unknown result type (might be due to invalid IL or missing references) base.OnGUI(); TypedNotifyParameters currentNotifyParameters = base.CurrentNotifyParameters; if (!base.Settings.isDisableNotify && base.CurrentMessage != null && currentNotifyParameters != null && !currentNotifyParameters.isDisable) { Matrix4x4 matrix = GUI.matrix; Color color = GUI.color; color.a = currentAlpha; GUI.color = color; Texture2D messageTexture = GetMessageTexture(base.CurrentMessage.messageType); float num = UtilityUI.CalcScreenFactor(UtilityUI.StandardScreenWidth, Screen.width); float num2 = UtilityUI.CalcScreenFactor(UtilityUI.StandardScreenHeight, Screen.height); float num3 = (float)((Texture)messageTexture).width * num; float num4 = (float)((Texture)messageTexture).height * num2; Rect val = default(Rect); ((Rect)(ref val)).x = ((float)Screen.width - num3) * (0.5f + currentNotifyParameters.notifyHorizontalOffset); ((Rect)(ref val)).y = ((float)Screen.height - num4) * (0.5f + currentNotifyParameters.notifyVerticalOffset); ((Rect)(ref val)).width = num3; ((Rect)(ref val)).height = num4; Rect val2 = val; float num5 = Math.Min(num, num2); float num6 = Math.Max(num, num2); int num7 = (int)((float)currentNotifyParameters.fontSize * num5); GUIStyle val3 = new GUIStyle(GUI.skin.label) { fontSize = num7, alignment = (TextAnchor)4, richText = true, fixedWidth = num3, fixedHeight = num4 }; Font font = GetFont(currentNotifyParameters.fontPath, num7); if ((Object)(object)font != (Object)null) { val3.font = font; } val3.padding.top = (int)((float)currentNotifyParameters.textPadding.top * num6); val3.padding.bottom = (int)((float)currentNotifyParameters.textPadding.bottom * num6); val3.padding.left = (int)((float)currentNotifyParameters.textPadding.left * num6); val3.padding.right = (int)((float)currentNotifyParameters.textPadding.right * num6); val3.normal.textColor = color; GUI.DrawTexture(val2, (Texture)(object)messageTexture); GUI.Label(val2, GetFadedText(base.CurrentMessage.message), val3); GUI.matrix = matrix; } } } public class TypedNotifySettings { public bool isDisableNotify; public TypedNotifyParameters[] notifyParameters = new TypedNotifyParameters[0]; public override string ToString() { if (notifyParameters == null) { return "TypedNotifySettings: not found notifyParameters"; } string text = $"isDisableNotify={isDisableNotify}"; TypedNotifyParameters[] array = notifyParameters; for (int i = 0; i < array.Length; i++) { _ = array[i]; text = string.Join(Environment.NewLine, text, "notifyParameters:", notifyParameters.ToString()); } return text; } } } namespace ModHelperUnity.Interfaces { public interface IComponentTypedNotify { void AddNotifyToQueue(string message, string type); void AddNotifyToQueue(IEventsData eventData, ITranslation translation, Func<string, string> converter = null); void ClearNotifyQueue(); void StopCurrentNotify(); void PostInit(string folderPath, IDebugLogger logger = null, Func<string, byte[]> customFileReader = null); void ForcePostInit(string folderPath, IDebugLogger logger = null, Func<string, byte[]> customFileReader = null); } public interface ISoundManager { void PlaySound(string path, int volume = 50); void StopSound(); } public interface IDictionaryItemJson<T> { string Key { get; } T Value { get; } } } namespace ModHelperUnity.Data { public class TypedNotifyParameters { public bool isDisable; public string imageFileName = string.Empty; public string type = "default"; public string messageTemplate = "%name% %message%"; public string fontPath = ""; public float showMessageDuration = 5f; public float showFadeAnimationDuration = 1f; public float hideFadeAnimationDuration = 1f; public float delayAfterNotify = 1f; public float notifyHorizontalOffset; public float notifyVerticalOffset = -0.45f; public int fontSize = 19; public Padding textPadding = new Padding { bottom = 20, top = 20, left = 24, right = 24 }; public Color32 nicknameTextColor = new Color32((byte)65, (byte)160, (byte)94, byte.MaxValue); public Color32 messageTextColor = new Color32((byte)65, (byte)160, (byte)94, byte.MaxValue); public string[] events = new string[0]; public override string ToString() { //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Unknown result type (might be due to invalid IL or missing references) return string.Join(Environment.NewLine, "imageFileName: " + imageFileName, "type: " + type, $"showMessageDuration: {showMessageDuration}", $"showFadeAnimationDuration: {showFadeAnimationDuration}", $"hideFadeAnimationDuration: {hideFadeAnimationDuration}", $"delayAfterNotify: {delayAfterNotify}", $"notifyHorizontalOffset: {notifyHorizontalOffset}", $"notifyVerticalOffset: {notifyVerticalOffset}", $"textPadding: {textPadding}", $"fontSize: {fontSize}", $"isDisable: {isDisable}", $"nicknameTextColor: {nicknameTextColor}", $"messageTextColor: {messageTextColor}", "events: " + string.Join(Environment.NewLine, events), "fontPath: " + fontPath); } } public class Padding { public int left; public int right; public int top; public int bottom; public Padding() { } public Padding(int left, int right, int top, int bottom) { this.left = left; this.right = right; this.top = top; this.bottom = bottom; } public RectOffset GetRect() { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Expected O, but got Unknown return new RectOffset(left, right, top, bottom); } public override string ToString() { return $"left: {left}, right: {right}, top: {top}, bottom: {bottom}"; } } public class TypedNotifyMessage { public readonly string message; public readonly string messageType; public float showMessageDuration; public float showFadeAnimationDuration; public float hideFadeAnimationDuration; public TypedNotifyMessage(string message, string messageType, float showMessageDuration, float showFadeAnimationDuration, float hideFadeAnimationDuration) { this.message = (string.IsNullOrEmpty(message?.Trim()) ? string.Empty : message); this.messageType = messageType; this.showMessageDuration = showMessageDuration; this.showFadeAnimationDuration = showFadeAnimationDuration; this.hideFadeAnimationDuration = hideFadeAnimationDuration; } } public class NotifyMessage { private readonly string msg; private float duration; public NotifyMessage(string msg, float duration) { this.msg = (string.IsNullOrEmpty(msg?.Trim()) ? string.Empty : msg); this.duration = duration; } public string GetMessage() { return msg; } public bool IsFinished() { return duration <= 0f; } public void OnFrame(float dt) { if (!IsFinished()) { duration -= dt; } } } }
ChaosTricks_RoR2_plugins/websocket-sharp.dll
Decompiled 2 years ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Collections.Specialized; using System.ComponentModel; using System.Diagnostics; using System.Globalization; using System.IO; using System.IO.Compression; using System.Net; using System.Net.Security; using System.Net.Sockets; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Security.Authentication; using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; using System.Security.Permissions; using System.Security.Principal; using System.Text; using System.Threading; using System.Timers; using WebSocketSharp.Net; using WebSocketSharp.Net.WebSockets; using WebSocketSharp.Server; [assembly: AssemblyProduct("websocket-sharp.dll")] [assembly: CompilationRelaxations(8)] [assembly: AssemblyCompany("")] [assembly: AssemblyCopyright("sta.blockhead")] [assembly: AssemblyTrademark("")] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: AssemblyTitle("websocket-sharp")] [assembly: AssemblyDescription("A C# implementation of the WebSocket protocol client and server")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyVersion("1.0.2.59611")] namespace WebSocketSharp { public static class Ext { private const string _tspecials = "()<>@,;:\\\"/[]?={} \t"; private static readonly byte[] _last; private static readonly int _retry; private static byte[] compress(this byte[] data) { if (data.LongLength == 0) { return data; } using MemoryStream stream = new MemoryStream(data); return stream.compressToArray(); } private static MemoryStream compress(this Stream stream) { MemoryStream memoryStream = new MemoryStream(); if (stream.Length == 0) { return memoryStream; } stream.Position = 0L; using DeflateStream deflateStream = new DeflateStream(memoryStream, CompressionMode.Compress, leaveOpen: true); CopyTo(stream, deflateStream, 1024); deflateStream.Close(); memoryStream.Write(_last, 0, 1); memoryStream.Position = 0L; return memoryStream; } private static byte[] compressToArray(this Stream stream) { using MemoryStream memoryStream = stream.compress(); memoryStream.Close(); return memoryStream.ToArray(); } private static byte[] decompress(this byte[] data) { if (data.LongLength == 0) { return data; } using MemoryStream stream = new MemoryStream(data); return stream.decompressToArray(); } private static MemoryStream decompress(this Stream stream) { MemoryStream memoryStream = new MemoryStream(); if (stream.Length == 0) { return memoryStream; } stream.Position = 0L; using DeflateStream source = new DeflateStream(stream, CompressionMode.Decompress, leaveOpen: true); CopyTo(source, memoryStream, 1024); memoryStream.Position = 0L; return memoryStream; } private static byte[] decompressToArray(this Stream stream) { using MemoryStream memoryStream = stream.decompress(); memoryStream.Close(); return memoryStream.ToArray(); } private static void times(this ulong n, Action action) { for (ulong num = 0uL; num < n; num++) { action(); } } internal static byte[] Append(this ushort code, string reason) { byte[] array = code.InternalToByteArray(ByteOrder.Big); if (reason != null && reason.Length > 0) { List<byte> list = new List<byte>(array); list.AddRange(Encoding.UTF8.GetBytes(reason)); array = list.ToArray(); } return array; } internal static string CheckIfAvailable(this ServerState state, bool ready, bool start, bool shutting) { return ((!ready && (state == ServerState.Ready || state == ServerState.Stop)) || (!start && state == ServerState.Start) || (!shutting && state == ServerState.ShuttingDown)) ? ("This operation isn't available in: " + state.ToString().ToLower()) : null; } internal static string CheckIfAvailable(this WebSocketState state, bool connecting, bool open, bool closing, bool closed) { return ((!connecting && state == WebSocketState.Connecting) || (!open && state == WebSocketState.Open) || (!closing && state == WebSocketState.Closing) || (!closed && state == WebSocketState.Closed)) ? ("This operation isn't available in: " + state.ToString().ToLower()) : null; } internal static string CheckIfValidProtocols(this string[] protocols) { return protocols.Contains((string protocol) => protocol == null || protocol.Length == 0 || !protocol.IsToken()) ? "Contains an invalid value." : (protocols.ContainsTwice() ? "Contains a value twice." : null); } internal static string CheckIfValidServicePath(this string path) { return (path == null || path.Length == 0) ? "'path' is null or empty." : ((path[0] != '/') ? "'path' isn't an absolute path." : ((path.IndexOfAny(new char[2] { '?', '#' }) > -1) ? "'path' includes either or both query and fragment components." : null)); } internal static string CheckIfValidSessionID(this string id) { return (id == null || id.Length == 0) ? "'id' is null or empty." : null; } internal static string CheckIfValidWaitTime(this TimeSpan time) { return (time <= TimeSpan.Zero) ? "A wait time is zero or less." : null; } internal static bool CheckWaitTime(this TimeSpan time, out string message) { message = null; if (time <= TimeSpan.Zero) { message = "A wait time is zero or less."; return false; } return true; } internal static void Close(this WebSocketSharp.Net.HttpListenerResponse response, WebSocketSharp.Net.HttpStatusCode code) { response.StatusCode = (int)code; response.OutputStream.Close(); } internal static void CloseWithAuthChallenge(this WebSocketSharp.Net.HttpListenerResponse response, string challenge) { response.Headers.InternalSet("WWW-Authenticate", challenge, response: true); response.Close(WebSocketSharp.Net.HttpStatusCode.Unauthorized); } internal static byte[] Compress(this byte[] data, CompressionMethod method) { return (method == CompressionMethod.Deflate) ? data.compress() : data; } internal static Stream Compress(this Stream stream, CompressionMethod method) { return (method == CompressionMethod.Deflate) ? stream.compress() : stream; } internal static byte[] CompressToArray(this Stream stream, CompressionMethod method) { return (method == CompressionMethod.Deflate) ? stream.compressToArray() : stream.ToByteArray(); } internal static bool Contains<T>(this IEnumerable<T> source, Func<T, bool> condition) { foreach (T item in source) { if (condition(item)) { return true; } } return false; } internal static bool ContainsTwice(this string[] values) { int len = values.Length; Func<int, bool> contains = null; contains = delegate(int idx) { if (idx < len - 1) { for (int i = idx + 1; i < len; i++) { if (values[i] == values[idx]) { return true; } } return contains(++idx); } return false; }; return contains(0); } internal static T[] Copy<T>(this T[] source, long length) { T[] array = new T[length]; Array.Copy(source, 0L, array, 0L, length); return array; } internal static void CopyTo(this Stream source, Stream destination, int bufferLength) { byte[] buffer = new byte[bufferLength]; int num = 0; while ((num = source.Read(buffer, 0, bufferLength)) > 0) { destination.Write(buffer, 0, num); } } internal static void CopyToAsync(this Stream source, Stream destination, int bufferLength, Action completed, Action<Exception> error) { byte[] buff = new byte[bufferLength]; AsyncCallback callback = null; callback = delegate(IAsyncResult ar) { try { int num = source.EndRead(ar); if (num <= 0) { if (completed != null) { completed(); } } else { destination.Write(buff, 0, num); source.BeginRead(buff, 0, bufferLength, callback, null); } } catch (Exception obj2) { if (error != null) { error(obj2); } } }; try { source.BeginRead(buff, 0, bufferLength, callback, null); } catch (Exception obj) { if (error != null) { error(obj); } } } internal static byte[] Decompress(this byte[] data, CompressionMethod method) { return (method == CompressionMethod.Deflate) ? data.decompress() : data; } internal static Stream Decompress(this Stream stream, CompressionMethod method) { return (method == CompressionMethod.Deflate) ? stream.decompress() : stream; } internal static byte[] DecompressToArray(this Stream stream, CompressionMethod method) { return (method == CompressionMethod.Deflate) ? stream.decompressToArray() : stream.ToByteArray(); } internal static bool EqualsWith(this int value, char c, Action<int> action) { action(value); return value == c; } internal static string GetAbsolutePath(this Uri uri) { if (uri.IsAbsoluteUri) { return uri.AbsolutePath; } string originalString = uri.OriginalString; if (originalString[0] != '/') { return null; } int num = originalString.IndexOfAny(new char[2] { '?', '#' }); return (num > 0) ? originalString.Substring(0, num) : originalString; } internal static string GetMessage(this CloseStatusCode code) { return code switch { CloseStatusCode.TlsHandshakeFailure => "An error has occurred during a TLS handshake.", CloseStatusCode.ServerError => "WebSocket server got an internal error.", CloseStatusCode.MandatoryExtension => "WebSocket client didn't receive expected extension(s).", CloseStatusCode.TooBig => "A too big message has been received.", CloseStatusCode.PolicyViolation => "A policy violation has occurred.", CloseStatusCode.InvalidData => "Invalid data has been received.", CloseStatusCode.Abnormal => "An exception has occurred.", CloseStatusCode.UnsupportedData => "Unsupported data has been received.", CloseStatusCode.ProtocolError => "A WebSocket protocol error has occurred.", _ => string.Empty, }; } internal static string GetName(this string nameAndValue, char separator) { int num = nameAndValue.IndexOf(separator); return (num > 0) ? nameAndValue.Substring(0, num).Trim() : null; } internal static string GetValue(this string nameAndValue, char separator) { int num = nameAndValue.IndexOf(separator); return (num > -1 && num < nameAndValue.Length - 1) ? nameAndValue.Substring(num + 1).Trim() : null; } internal static string GetValue(this string nameAndValue, char separator, bool unquote) { int num = nameAndValue.IndexOf(separator); if (num < 0 || num == nameAndValue.Length - 1) { return null; } string text = nameAndValue.Substring(num + 1).Trim(); return unquote ? text.Unquote() : text; } internal static TcpListenerWebSocketContext GetWebSocketContext(this TcpClient tcpClient, string protocol, bool secure, ServerSslConfiguration sslConfig, Logger logger) { return new TcpListenerWebSocketContext(tcpClient, protocol, secure, sslConfig, logger); } internal static byte[] InternalToByteArray(this ushort value, ByteOrder order) { byte[] bytes = BitConverter.GetBytes(value); if (!order.IsHostOrder()) { Array.Reverse((Array)bytes); } return bytes; } internal static byte[] InternalToByteArray(this ulong value, ByteOrder order) { byte[] bytes = BitConverter.GetBytes(value); if (!order.IsHostOrder()) { Array.Reverse((Array)bytes); } return bytes; } internal static bool IsCompressionExtension(this string value, CompressionMethod method) { return value.StartsWith(method.ToExtensionString()); } internal static bool IsControl(this byte opcode) { return opcode > 7 && opcode < 16; } internal static bool IsControl(this Opcode opcode) { return (int)opcode >= 8; } internal static bool IsData(this byte opcode) { return opcode == 1 || opcode == 2; } internal static bool IsData(this Opcode opcode) { return opcode == Opcode.Text || opcode == Opcode.Binary; } internal static bool IsPortNumber(this int value) { return value > 0 && value < 65536; } internal static bool IsReserved(this ushort code) { return code == 1004 || code == 1005 || code == 1006 || code == 1015; } internal static bool IsReserved(this CloseStatusCode code) { return code == CloseStatusCode.Undefined || code == CloseStatusCode.NoStatus || code == CloseStatusCode.Abnormal || code == CloseStatusCode.TlsHandshakeFailure; } internal static bool IsSupported(this byte opcode) { return Enum.IsDefined(typeof(Opcode), opcode); } internal static bool IsText(this string value) { int length = value.Length; for (int i = 0; i < length; i++) { char c = value[i]; if (c < ' ' && !Contains("\r\n\t", c)) { return false; } switch (c) { case '\u007f': return false; case '\n': if (++i < length) { c = value[i]; if (!Contains(" \t", c)) { return false; } } break; } } return true; } internal static bool IsToken(this string value) { foreach (char c in value) { if (c < ' ' || c >= '\u007f' || Contains("()<>@,;:\\\"/[]?={} \t", c)) { return false; } } return true; } internal static string Quote(this string value) { return string.Format("\"{0}\"", value.Replace("\"", "\\\"")); } internal static byte[] ReadBytes(this Stream stream, int length) { byte[] array = new byte[length]; int num = 0; try { int num2 = 0; while (length > 0) { num2 = stream.Read(array, num, length); if (num2 == 0) { break; } num += num2; length -= num2; } } catch { } return array.SubArray(0, num); } internal static byte[] ReadBytes(this Stream stream, long length, int bufferLength) { using MemoryStream memoryStream = new MemoryStream(); try { byte[] buffer = new byte[bufferLength]; int num = 0; while (length > 0) { if (length < bufferLength) { bufferLength = (int)length; } num = stream.Read(buffer, 0, bufferLength); if (num == 0) { break; } memoryStream.Write(buffer, 0, num); length -= num; } } catch { } memoryStream.Close(); return memoryStream.ToArray(); } internal static void ReadBytesAsync(this Stream stream, int length, Action<byte[]> completed, Action<Exception> error) { byte[] buff = new byte[length]; int offset = 0; int retry = 0; AsyncCallback callback = null; callback = delegate(IAsyncResult ar) { try { int num = stream.EndRead(ar); if (num == 0 && retry < _retry) { retry++; stream.BeginRead(buff, offset, length, callback, null); } else if (num == 0 || num == length) { if (completed != null) { completed(buff.SubArray(0, offset + num)); } } else { retry = 0; offset += num; length -= num; stream.BeginRead(buff, offset, length, callback, null); } } catch (Exception obj2) { if (error != null) { error(obj2); } } }; try { stream.BeginRead(buff, offset, length, callback, null); } catch (Exception obj) { if (error != null) { error(obj); } } } internal static void ReadBytesAsync(this Stream stream, long length, int bufferLength, Action<byte[]> completed, Action<Exception> error) { MemoryStream dest = new MemoryStream(); byte[] buff = new byte[bufferLength]; int retry = 0; Action<long> read = null; read = delegate(long len) { if (len < bufferLength) { bufferLength = (int)len; } stream.BeginRead(buff, 0, bufferLength, delegate(IAsyncResult ar) { try { int num = stream.EndRead(ar); if (num > 0) { dest.Write(buff, 0, num); } if (num == 0 && retry < _retry) { retry++; read(len); } else if (num == 0 || num == len) { if (completed != null) { dest.Close(); completed(dest.ToArray()); } dest.Dispose(); } else { retry = 0; read(len - num); } } catch (Exception obj2) { dest.Dispose(); if (error != null) { error(obj2); } } }, null); }; try { read(length); } catch (Exception obj) { dest.Dispose(); if (error != null) { error(obj); } } } internal static string RemovePrefix(this string value, params string[] prefixes) { int num = 0; foreach (string text in prefixes) { if (value.StartsWith(text)) { num = text.Length; break; } } return (num > 0) ? value.Substring(num) : value; } internal static T[] Reverse<T>(this T[] array) { int num = array.Length; T[] array2 = new T[num]; int num2 = num - 1; for (int i = 0; i <= num2; i++) { array2[i] = array[num2 - i]; } return array2; } internal static IEnumerable<string> SplitHeaderValue(this string value, params char[] separators) { int len = value.Length; string seps = new string(separators); StringBuilder buff = new StringBuilder(32); bool escaped = false; bool quoted = false; for (int i = 0; i < len; i++) { char c = value[i]; switch (c) { case '"': if (escaped) { escaped = !escaped; } else { quoted = !quoted; } break; case '\\': if (i < len - 1 && value[i + 1] == '"') { escaped = true; } break; default: if (Contains(seps, c) && !quoted) { yield return buff.ToString(); buff.Length = 0; continue; } break; } buff.Append(c); } if (buff.Length > 0) { yield return buff.ToString(); } } internal static byte[] ToByteArray(this Stream stream) { using MemoryStream memoryStream = new MemoryStream(); stream.Position = 0L; CopyTo(stream, memoryStream, 1024); memoryStream.Close(); return memoryStream.ToArray(); } internal static CompressionMethod ToCompressionMethod(this string value) { foreach (CompressionMethod value2 in Enum.GetValues(typeof(CompressionMethod))) { if (value2.ToExtensionString() == value) { return value2; } } return CompressionMethod.None; } internal static string ToExtensionString(this CompressionMethod method, params string[] parameters) { if (method == CompressionMethod.None) { return string.Empty; } string text = $"permessage-{method.ToString().ToLower()}"; if (parameters == null || parameters.Length == 0) { return text; } return string.Format("{0}; {1}", text, parameters.ToString("; ")); } internal static IPAddress ToIPAddress(this string hostnameOrAddress) { if (IPAddress.TryParse(hostnameOrAddress, out IPAddress address)) { return address; } try { return Dns.GetHostAddresses(hostnameOrAddress)[0]; } catch { return null; } } internal static List<TSource> ToList<TSource>(this IEnumerable<TSource> source) { return new List<TSource>(source); } internal static ushort ToUInt16(this byte[] source, ByteOrder sourceOrder) { return BitConverter.ToUInt16(source.ToHostOrder(sourceOrder), 0); } internal static ulong ToUInt64(this byte[] source, ByteOrder sourceOrder) { return BitConverter.ToUInt64(source.ToHostOrder(sourceOrder), 0); } internal static string TrimEndSlash(this string value) { value = value.TrimEnd(new char[1] { '/' }); return (value.Length > 0) ? value : "/"; } internal static bool TryCreateWebSocketUri(this string uriString, out Uri result, out string message) { result = null; Uri uri = uriString.ToUri(); if (uri == null) { message = "An invalid URI string: " + uriString; return false; } if (!uri.IsAbsoluteUri) { message = "Not an absolute URI: " + uriString; return false; } string scheme = uri.Scheme; if (!(scheme == "ws") && !(scheme == "wss")) { message = "The scheme part isn't 'ws' or 'wss': " + uriString; return false; } if (uri.Fragment.Length > 0) { message = "Includes the fragment component: " + uriString; return false; } int port = uri.Port; if (port == 0) { message = "The port part is zero: " + uriString; return false; } result = ((port != -1) ? uri : new Uri(string.Format("{0}://{1}:{2}{3}", scheme, uri.Host, (scheme == "ws") ? 80 : 443, uri.PathAndQuery))); message = string.Empty; return true; } internal static string Unquote(this string value) { int num = value.IndexOf('"'); if (num < 0) { return value; } int num2 = value.LastIndexOf('"'); int num3 = num2 - num - 1; return (num3 < 0) ? value : ((num3 == 0) ? string.Empty : value.Substring(num + 1, num3).Replace("\\\"", "\"")); } internal static string UTF8Decode(this byte[] bytes) { try { return Encoding.UTF8.GetString(bytes); } catch { return null; } } internal static byte[] UTF8Encode(this string s) { return Encoding.UTF8.GetBytes(s); } internal static void WriteBytes(this Stream stream, byte[] bytes, int bufferLength) { using MemoryStream source = new MemoryStream(bytes); CopyTo(source, stream, bufferLength); } internal static void WriteBytesAsync(this Stream stream, byte[] bytes, int bufferLength, Action completed, Action<Exception> error) { MemoryStream input = new MemoryStream(bytes); input.CopyToAsync(stream, bufferLength, delegate { if (completed != null) { completed(); } input.Dispose(); }, delegate(Exception ex) { input.Dispose(); if (error != null) { error(ex); } }); } public static bool Contains(this string value, params char[] chars) { return chars == null || chars.Length == 0 || (value != null && value.Length != 0 && value.IndexOfAny(chars) > -1); } public static bool Contains(this NameValueCollection collection, string name) { return collection != null && collection.Count > 0 && collection[name] != null; } public static bool Contains(this NameValueCollection collection, string name, string value) { if (collection == null || collection.Count == 0) { return false; } string text = collection[name]; if (text == null) { return false; } string[] array = text.Split(new char[1] { ',' }); foreach (string text2 in array) { if (text2.Trim().Equals(value, StringComparison.OrdinalIgnoreCase)) { return true; } } return false; } public static void Emit(this EventHandler eventHandler, object sender, EventArgs e) { eventHandler?.Invoke(sender, e); } public static void Emit<TEventArgs>(this EventHandler<TEventArgs> eventHandler, object sender, TEventArgs e) where TEventArgs : EventArgs { eventHandler?.Invoke(sender, e); } public static WebSocketSharp.Net.CookieCollection GetCookies(this NameValueCollection headers, bool response) { string name = (response ? "Set-Cookie" : "Cookie"); return (headers != null && headers.Contains(name)) ? WebSocketSharp.Net.CookieCollection.Parse(headers[name], response) : new WebSocketSharp.Net.CookieCollection(); } public static string GetDescription(this WebSocketSharp.Net.HttpStatusCode code) { return ((int)code).GetStatusDescription(); } public static string GetStatusDescription(this int code) { return code switch { 100 => "Continue", 101 => "Switching Protocols", 102 => "Processing", 200 => "OK", 201 => "Created", 202 => "Accepted", 203 => "Non-Authoritative Information", 204 => "No Content", 205 => "Reset Content", 206 => "Partial Content", 207 => "Multi-Status", 300 => "Multiple Choices", 301 => "Moved Permanently", 302 => "Found", 303 => "See Other", 304 => "Not Modified", 305 => "Use Proxy", 307 => "Temporary Redirect", 400 => "Bad Request", 401 => "Unauthorized", 402 => "Payment Required", 403 => "Forbidden", 404 => "Not Found", 405 => "Method Not Allowed", 406 => "Not Acceptable", 407 => "Proxy Authentication Required", 408 => "Request Timeout", 409 => "Conflict", 410 => "Gone", 411 => "Length Required", 412 => "Precondition Failed", 413 => "Request Entity Too Large", 414 => "Request-Uri Too Long", 415 => "Unsupported Media Type", 416 => "Requested Range Not Satisfiable", 417 => "Expectation Failed", 422 => "Unprocessable Entity", 423 => "Locked", 424 => "Failed Dependency", 500 => "Internal Server Error", 501 => "Not Implemented", 502 => "Bad Gateway", 503 => "Service Unavailable", 504 => "Gateway Timeout", 505 => "Http Version Not Supported", 507 => "Insufficient Storage", _ => string.Empty, }; } public static bool IsCloseStatusCode(this ushort value) { return value > 999 && value < 5000; } public static bool IsEnclosedIn(this string value, char c) { return value != null && value.Length > 1 && value[0] == c && value[value.Length - 1] == c; } public static bool IsHostOrder(this ByteOrder order) { return !(BitConverter.IsLittleEndian ^ (order == ByteOrder.Little)); } public static bool IsLocal(this IPAddress address) { if (address == null) { return false; } if (address.Equals(IPAddress.Any)) { return true; } if (address.Equals(IPAddress.Loopback)) { return true; } if (Socket.OSSupportsIPv6) { if (address.Equals(IPAddress.IPv6Any)) { return true; } if (address.Equals(IPAddress.IPv6Loopback)) { return true; } } string hostName = Dns.GetHostName(); IPAddress[] hostAddresses = Dns.GetHostAddresses(hostName); IPAddress[] array = hostAddresses; foreach (IPAddress obj in array) { if (address.Equals(obj)) { return true; } } return false; } public static bool IsNullOrEmpty(this string value) { return value == null || value.Length == 0; } public static bool IsPredefinedScheme(this string value) { if (value == null || value.Length < 2) { return false; } char c = value[0]; if (c == 'h') { return value == "http" || value == "https"; } if (c == 'w') { return value == "ws" || value == "wss"; } if (c == 'f') { return value == "file" || value == "ftp"; } if (c == 'n') { c = value[1]; return (c != 'e') ? (value == "nntp") : (value == "news" || value == "net.pipe" || value == "net.tcp"); } return (c == 'g' && value == "gopher") || (c == 'm' && value == "mailto"); } public static bool IsUpgradeTo(this WebSocketSharp.Net.HttpListenerRequest request, string protocol) { if (request == null) { throw new ArgumentNullException("request"); } if (protocol == null) { throw new ArgumentNullException("protocol"); } if (protocol.Length == 0) { throw new ArgumentException("An empty string.", "protocol"); } return request.Headers.Contains("Upgrade", protocol) && request.Headers.Contains("Connection", "Upgrade"); } public static bool MaybeUri(this string value) { if (value == null || value.Length == 0) { return false; } int num = value.IndexOf(':'); if (num == -1) { return false; } if (num >= 10) { return false; } return value.Substring(0, num).IsPredefinedScheme(); } public static T[] SubArray<T>(this T[] array, int startIndex, int length) { int num; if (array == null || (num = array.Length) == 0) { return new T[0]; } if (startIndex < 0 || length <= 0 || startIndex + length > num) { return new T[0]; } if (startIndex == 0 && length == num) { return array; } T[] array2 = new T[length]; Array.Copy(array, startIndex, array2, 0, length); return array2; } public static T[] SubArray<T>(this T[] array, long startIndex, long length) { long longLength; if (array == null || (longLength = array.LongLength) == 0) { return new T[0]; } if (startIndex < 0 || length <= 0 || startIndex + length > longLength) { return new T[0]; } if (startIndex == 0 && length == longLength) { return array; } T[] array2 = new T[length]; Array.Copy(array, startIndex, array2, 0L, length); return array2; } public static void Times(this int n, Action action) { if (n > 0 && action != null) { ((ulong)n).times(action); } } public static void Times(this long n, Action action) { if (n > 0 && action != null) { ((ulong)n).times(action); } } public static void Times(this uint n, Action action) { if (n != 0 && action != null) { times(n, action); } } public static void Times(this ulong n, Action action) { if (n != 0 && action != null) { n.times(action); } } public static void Times(this int n, Action<int> action) { if (n > 0 && action != null) { for (int i = 0; i < n; i++) { action(i); } } } public static void Times(this long n, Action<long> action) { if (n > 0 && action != null) { for (long num = 0L; num < n; num++) { action(num); } } } public static void Times(this uint n, Action<uint> action) { if (n != 0 && action != null) { for (uint num = 0u; num < n; num++) { action(num); } } } public static void Times(this ulong n, Action<ulong> action) { if (n != 0 && action != null) { for (ulong num = 0uL; num < n; num++) { action(num); } } } public static T To<T>(this byte[] source, ByteOrder sourceOrder) where T : struct { if (source == null) { throw new ArgumentNullException("source"); } if (source.Length == 0) { return default(T); } Type typeFromHandle = typeof(T); byte[] value = source.ToHostOrder(sourceOrder); return ((object)typeFromHandle == typeof(bool)) ? ((T)(object)BitConverter.ToBoolean(value, 0)) : (((object)typeFromHandle == typeof(char)) ? ((T)(object)BitConverter.ToChar(value, 0)) : (((object)typeFromHandle == typeof(double)) ? ((T)(object)BitConverter.ToDouble(value, 0)) : (((object)typeFromHandle == typeof(short)) ? ((T)(object)BitConverter.ToInt16(value, 0)) : (((object)typeFromHandle == typeof(int)) ? ((T)(object)BitConverter.ToInt32(value, 0)) : (((object)typeFromHandle == typeof(long)) ? ((T)(object)BitConverter.ToInt64(value, 0)) : (((object)typeFromHandle == typeof(float)) ? ((T)(object)BitConverter.ToSingle(value, 0)) : (((object)typeFromHandle == typeof(ushort)) ? ((T)(object)BitConverter.ToUInt16(value, 0)) : (((object)typeFromHandle == typeof(uint)) ? ((T)(object)BitConverter.ToUInt32(value, 0)) : (((object)typeFromHandle == typeof(ulong)) ? ((T)(object)BitConverter.ToUInt64(value, 0)) : default(T)))))))))); } public static byte[] ToByteArray<T>(this T value, ByteOrder order) where T : struct { Type typeFromHandle = typeof(T); byte[] array = (((object)typeFromHandle == typeof(bool)) ? BitConverter.GetBytes((bool)(object)value) : (((object)typeFromHandle == typeof(byte)) ? new byte[1] { (byte)(object)value } : (((object)typeFromHandle == typeof(char)) ? BitConverter.GetBytes((char)(object)value) : (((object)typeFromHandle == typeof(double)) ? BitConverter.GetBytes((double)(object)value) : (((object)typeFromHandle == typeof(short)) ? BitConverter.GetBytes((short)(object)value) : (((object)typeFromHandle == typeof(int)) ? BitConverter.GetBytes((int)(object)value) : (((object)typeFromHandle == typeof(long)) ? BitConverter.GetBytes((long)(object)value) : (((object)typeFromHandle == typeof(float)) ? BitConverter.GetBytes((float)(object)value) : (((object)typeFromHandle == typeof(ushort)) ? BitConverter.GetBytes((ushort)(object)value) : (((object)typeFromHandle == typeof(uint)) ? BitConverter.GetBytes((uint)(object)value) : (((object)typeFromHandle == typeof(ulong)) ? BitConverter.GetBytes((ulong)(object)value) : WebSocket.EmptyBytes))))))))))); if (array.Length > 1 && !order.IsHostOrder()) { Array.Reverse((Array)array); } return array; } public static byte[] ToHostOrder(this byte[] source, ByteOrder sourceOrder) { if (source == null) { throw new ArgumentNullException("source"); } return (source.Length > 1 && !sourceOrder.IsHostOrder()) ? source.Reverse() : source; } public static string ToString<T>(this T[] array, string separator) { if (array == null) { throw new ArgumentNullException("array"); } int num = array.Length; if (num == 0) { return string.Empty; } if (separator == null) { separator = string.Empty; } StringBuilder buff = new StringBuilder(64); (num - 1).Times(delegate(int i) { buff.AppendFormat("{0}{1}", array[i].ToString(), separator); }); buff.Append(array[num - 1].ToString()); return buff.ToString(); } public static Uri ToUri(this string uriString) { Uri.TryCreate(uriString, uriString.MaybeUri() ? UriKind.Absolute : UriKind.Relative, out Uri result); return result; } public static string UrlDecode(this string value) { return (value != null && value.Length > 0) ? HttpUtility.UrlDecode(value) : value; } public static string UrlEncode(this string value) { return (value != null && value.Length > 0) ? HttpUtility.UrlEncode(value) : value; } public static void WriteContent(this WebSocketSharp.Net.HttpListenerResponse response, byte[] content) { if (response == null) { throw new ArgumentNullException("response"); } if (content == null) { throw new ArgumentNullException("content"); } long longLength = content.LongLength; if (longLength == 0) { response.Close(); return; } response.ContentLength64 = longLength; Stream outputStream = response.OutputStream; if (longLength <= int.MaxValue) { outputStream.Write(content, 0, (int)longLength); } else { outputStream.WriteBytes(content, 1024); } outputStream.Close(); } static Ext() { byte[] last = new byte[1]; _last = last; _retry = 5; } } public class MessageEventArgs : EventArgs { private string _data; private bool _dataSet; private Opcode _opcode; private byte[] _rawData; public string Data { get { if (!_dataSet) { _data = ((_opcode != Opcode.Binary) ? _rawData.UTF8Decode() : BitConverter.ToString(_rawData)); _dataSet = true; } return _data; } } public bool IsBinary => _opcode == Opcode.Binary; public bool IsPing => _opcode == Opcode.Ping; public bool IsText => _opcode == Opcode.Text; public byte[] RawData => _rawData; [Obsolete("This property will be removed. Use any of the Is properties instead.")] public Opcode Type => _opcode; internal MessageEventArgs(WebSocketFrame frame) { _opcode = frame.Opcode; _rawData = frame.PayloadData.ApplicationData; } internal MessageEventArgs(Opcode opcode, byte[] rawData) { if ((ulong)rawData.LongLength > PayloadData.MaxLength) { throw new WebSocketException(CloseStatusCode.TooBig); } _opcode = opcode; _rawData = rawData; } } public class CloseEventArgs : EventArgs { private bool _clean; private ushort _code; private PayloadData _payloadData; private string _reason; internal PayloadData PayloadData => _payloadData ?? (_payloadData = new PayloadData(_code.Append(_reason))); public ushort Code => _code; public string Reason => _reason ?? string.Empty; public bool WasClean { get { return _clean; } internal set { _clean = value; } } internal CloseEventArgs() { _code = 1005; _payloadData = PayloadData.Empty; } internal CloseEventArgs(ushort code) { _code = code; } internal CloseEventArgs(CloseStatusCode code) : this((ushort)code) { } internal CloseEventArgs(PayloadData payloadData) { _payloadData = payloadData; byte[] applicationData = payloadData.ApplicationData; int num = applicationData.Length; _code = (ushort)((num > 1) ? applicationData.SubArray(0, 2).ToUInt16(ByteOrder.Big) : 1005); _reason = ((num > 2) ? applicationData.SubArray(2, num - 2).UTF8Decode() : string.Empty); } internal CloseEventArgs(ushort code, string reason) { _code = code; _reason = reason; } internal CloseEventArgs(CloseStatusCode code, string reason) : this((ushort)code, reason) { } } public enum ByteOrder { Little, Big } public class ErrorEventArgs : EventArgs { private Exception _exception; private string _message; public Exception Exception => _exception; public string Message => _message; internal ErrorEventArgs(string message) : this(message, null) { } internal ErrorEventArgs(string message, Exception exception) { _message = message; _exception = exception; } } public class WebSocket : IDisposable { private const string _guid = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; private const string _version = "13"; private AuthenticationChallenge _authChallenge; private string _base64Key; private bool _client; private Action _closeContext; private CompressionMethod _compression; private WebSocketContext _context; private WebSocketSharp.Net.CookieCollection _cookies; private WebSocketSharp.Net.NetworkCredential _credentials; private bool _emitOnPing; private bool _enableRedirection; private AutoResetEvent _exitReceiving; private string _extensions; private bool _extensionsRequested; private object _forConn; private object _forMessageEventQueue; private object _forSend; private MemoryStream _fragmentsBuffer; private bool _fragmentsCompressed; private Opcode _fragmentsOpcode; private Func<WebSocketContext, string> _handshakeRequestChecker; private bool _ignoreExtensions; private bool _inContinuation; private volatile bool _inMessage; private volatile Logger _logger; private Action<MessageEventArgs> _message; private Queue<MessageEventArgs> _messageEventQueue; private uint _nonceCount; private string _origin; private bool _preAuth; private string _protocol; private string[] _protocols; private bool _protocolsRequested; private WebSocketSharp.Net.NetworkCredential _proxyCredentials; private Uri _proxyUri; private volatile WebSocketState _readyState; private AutoResetEvent _receivePong; private bool _secure; private ClientSslConfiguration _sslConfig; private Stream _stream; private TcpClient _tcpClient; private Uri _uri; private TimeSpan _waitTime; internal static readonly byte[] EmptyBytes; internal static readonly int FragmentLength; internal static readonly RandomNumberGenerator RandomNumber; internal WebSocketSharp.Net.CookieCollection CookieCollection => _cookies; internal Func<WebSocketContext, string> CustomHandshakeRequestChecker { get { return _handshakeRequestChecker; } set { _handshakeRequestChecker = value; } } internal bool HasMessage { get { lock (_forMessageEventQueue) { return _messageEventQueue.Count > 0; } } } internal bool IgnoreExtensions { get { return _ignoreExtensions; } set { _ignoreExtensions = value; } } internal bool IsConnected => _readyState == WebSocketState.Open || _readyState == WebSocketState.Closing; public CompressionMethod Compression { get { return _compression; } set { lock (_forConn) { if (!checkIfAvailable(client: true, server: false, connecting: true, open: false, closing: false, closed: true, out var text)) { _logger.Error(text); error("An error has occurred in setting the compression.", null); } else { _compression = value; } } } } public IEnumerable<WebSocketSharp.Net.Cookie> Cookies { get { object syncRoot; object obj = (syncRoot = _cookies.SyncRoot); Monitor.Enter(syncRoot); try { foreach (WebSocketSharp.Net.Cookie cookie in _cookies) { yield return cookie; } } finally { Monitor.Exit(obj); } } } public WebSocketSharp.Net.NetworkCredential Credentials => _credentials; public bool EmitOnPing { get { return _emitOnPing; } set { _emitOnPing = value; } } public bool EnableRedirection { get { return _enableRedirection; } set { lock (_forConn) { if (!checkIfAvailable(client: true, server: false, connecting: true, open: false, closing: false, closed: true, out var text)) { _logger.Error(text); error("An error has occurred in setting the enable redirection.", null); } else { _enableRedirection = value; } } } } public string Extensions => _extensions ?? string.Empty; public bool IsAlive => Ping(); public bool IsSecure => _secure; public Logger Log { get { return _logger; } internal set { _logger = value; } } public string Origin { get { return _origin; } set { lock (_forConn) { Uri result; if (!checkIfAvailable(client: true, server: false, connecting: true, open: false, closing: false, closed: true, out var text)) { _logger.Error(text); error("An error has occurred in setting the origin.", null); } else if (value.IsNullOrEmpty()) { _origin = value; } else if (!Uri.TryCreate(value, UriKind.Absolute, out result) || result.Segments.Length > 1) { _logger.Error("The syntax of an origin must be '<scheme>://<host>[:<port>]'."); error("An error has occurred in setting the origin.", null); } else { _origin = value.TrimEnd(new char[1] { '/' }); } } } } public string Protocol { get { return _protocol ?? string.Empty; } internal set { _protocol = value; } } public WebSocketState ReadyState => _readyState; public ClientSslConfiguration SslConfiguration { get { return _client ? (_sslConfig ?? (_sslConfig = new ClientSslConfiguration(_uri.DnsSafeHost))) : null; } set { lock (_forConn) { if (!checkIfAvailable(client: true, server: false, connecting: true, open: false, closing: false, closed: true, out var text)) { _logger.Error(text); error("An error has occurred in setting the ssl configuration.", null); } else { _sslConfig = value; } } } } public Uri Url => _client ? _uri : _context.RequestUri; public TimeSpan WaitTime { get { return _waitTime; } set { lock (_forConn) { if (!checkIfAvailable(client: true, server: true, connecting: true, open: false, closing: false, closed: true, out var text) || !value.CheckWaitTime(out text)) { _logger.Error(text); error("An error has occurred in setting the wait time.", null); } else { _waitTime = value; } } } } public event EventHandler<CloseEventArgs> OnClose; public event EventHandler<ErrorEventArgs> OnError; public event EventHandler<MessageEventArgs> OnMessage; public event EventHandler OnOpen; static WebSocket() { EmptyBytes = new byte[0]; FragmentLength = 1016; RandomNumber = new RNGCryptoServiceProvider(); } internal WebSocket(HttpListenerWebSocketContext context, string protocol) { _context = context; _protocol = protocol; _closeContext = context.Close; _logger = context.Log; _message = messages; _secure = context.IsSecureConnection; _stream = context.Stream; _waitTime = TimeSpan.FromSeconds(1.0); init(); } internal WebSocket(TcpListenerWebSocketContext context, string protocol) { _context = context; _protocol = protocol; _closeContext = context.Close; _logger = context.Log; _message = messages; _secure = context.IsSecureConnection; _stream = context.Stream; _waitTime = TimeSpan.FromSeconds(1.0); init(); } public WebSocket(string url, params string[] protocols) { if (url == null) { throw new ArgumentNullException("url"); } if (url.Length == 0) { throw new ArgumentException("An empty string.", "url"); } if (!url.TryCreateWebSocketUri(out _uri, out var text)) { throw new ArgumentException(text, "url"); } if (protocols != null && protocols.Length > 0) { text = protocols.CheckIfValidProtocols(); if (text != null) { throw new ArgumentException(text, "protocols"); } _protocols = protocols; } _base64Key = CreateBase64Key(); _client = true; _logger = new Logger(); _message = messagec; _secure = _uri.Scheme == "wss"; _waitTime = TimeSpan.FromSeconds(5.0); init(); } private bool accept() { lock (_forConn) { if (!checkIfAvailable(connecting: true, open: false, closing: false, closed: false, out var text)) { _logger.Error(text); error("An error has occurred in accepting.", null); return false; } try { if (!acceptHandshake()) { return false; } _readyState = WebSocketState.Open; } catch (Exception ex) { _logger.Fatal(ex.ToString()); fatal("An exception has occurred while accepting.", ex); return false; } return true; } } private bool acceptHandshake() { _logger.Debug($"A request from {_context.UserEndPoint}:\n{_context}"); if (!checkHandshakeRequest(_context, out var text)) { sendHttpResponse(createHandshakeFailureResponse(WebSocketSharp.Net.HttpStatusCode.BadRequest)); _logger.Fatal(text); fatal("An error has occurred while accepting.", CloseStatusCode.ProtocolError); return false; } if (!customCheckHandshakeRequest(_context, out text)) { sendHttpResponse(createHandshakeFailureResponse(WebSocketSharp.Net.HttpStatusCode.BadRequest)); _logger.Fatal(text); fatal("An error has occurred while accepting.", CloseStatusCode.PolicyViolation); return false; } _base64Key = _context.Headers["Sec-WebSocket-Key"]; if (_protocol != null) { processSecWebSocketProtocolHeader(_context.SecWebSocketProtocols); } if (!_ignoreExtensions) { processSecWebSocketExtensionsClientHeader(_context.Headers["Sec-WebSocket-Extensions"]); } return sendHttpResponse(createHandshakeResponse()); } private bool checkHandshakeRequest(WebSocketContext context, out string message) { message = null; if (context.RequestUri == null) { message = "Specifies an invalid Request-URI."; return false; } if (!context.IsWebSocketRequest) { message = "Not a WebSocket handshake request."; return false; } NameValueCollection headers = context.Headers; if (!validateSecWebSocketKeyHeader(headers["Sec-WebSocket-Key"])) { message = "Includes no Sec-WebSocket-Key header, or it has an invalid value."; return false; } if (!validateSecWebSocketVersionClientHeader(headers["Sec-WebSocket-Version"])) { message = "Includes no Sec-WebSocket-Version header, or it has an invalid value."; return false; } if (!validateSecWebSocketProtocolClientHeader(headers["Sec-WebSocket-Protocol"])) { message = "Includes an invalid Sec-WebSocket-Protocol header."; return false; } if (!_ignoreExtensions && !validateSecWebSocketExtensionsClientHeader(headers["Sec-WebSocket-Extensions"])) { message = "Includes an invalid Sec-WebSocket-Extensions header."; return false; } return true; } private bool checkHandshakeResponse(HttpResponse response, out string message) { message = null; if (response.IsRedirect) { message = "Indicates the redirection."; return false; } if (response.IsUnauthorized) { message = "Requires the authentication."; return false; } if (!response.IsWebSocketResponse) { message = "Not a WebSocket handshake response."; return false; } NameValueCollection headers = response.Headers; if (!validateSecWebSocketAcceptHeader(headers["Sec-WebSocket-Accept"])) { message = "Includes no Sec-WebSocket-Accept header, or it has an invalid value."; return false; } if (!validateSecWebSocketProtocolServerHeader(headers["Sec-WebSocket-Protocol"])) { message = "Includes no Sec-WebSocket-Protocol header, or it has an invalid value."; return false; } if (!validateSecWebSocketExtensionsServerHeader(headers["Sec-WebSocket-Extensions"])) { message = "Includes an invalid Sec-WebSocket-Extensions header."; return false; } if (!validateSecWebSocketVersionServerHeader(headers["Sec-WebSocket-Version"])) { message = "Includes an invalid Sec-WebSocket-Version header."; return false; } return true; } private bool checkIfAvailable(bool connecting, bool open, bool closing, bool closed, out string message) { message = null; if (!connecting && _readyState == WebSocketState.Connecting) { message = "This operation isn't available in: connecting"; return false; } if (!open && _readyState == WebSocketState.Open) { message = "This operation isn't available in: open"; return false; } if (!closing && _readyState == WebSocketState.Closing) { message = "This operation isn't available in: closing"; return false; } if (!closed && _readyState == WebSocketState.Closed) { message = "This operation isn't available in: closed"; return false; } return true; } private bool checkIfAvailable(bool client, bool server, bool connecting, bool open, bool closing, bool closed, out string message) { message = null; if (!client && _client) { message = "This operation isn't available in: client"; return false; } if (!server && !_client) { message = "This operation isn't available in: server"; return false; } return checkIfAvailable(connecting, open, closing, closed, out message); } private bool checkReceivedFrame(WebSocketFrame frame, out string message) { message = null; bool isMasked = frame.IsMasked; if (_client && isMasked) { message = "A frame from the server is masked."; return false; } if (!_client && !isMasked) { message = "A frame from a client isn't masked."; return false; } if (_inContinuation && frame.IsData) { message = "A data frame has been received while receiving continuation frames."; return false; } if (frame.IsCompressed && _compression == CompressionMethod.None) { message = "A compressed frame has been received without any agreement for it."; return false; } if (frame.Rsv2 == Rsv.On) { message = "The RSV2 of a frame is non-zero without any negotiation for it."; return false; } if (frame.Rsv3 == Rsv.On) { message = "The RSV3 of a frame is non-zero without any negotiation for it."; return false; } return true; } private void close(CloseEventArgs e, bool send, bool receive, bool received) { lock (_forConn) { if (_readyState == WebSocketState.Closing) { _logger.Info("The closing is already in progress."); return; } if (_readyState == WebSocketState.Closed) { _logger.Info("The connection has been closed."); return; } send = send && _readyState == WebSocketState.Open; receive = receive && send; _readyState = WebSocketState.Closing; } _logger.Trace("Begin closing the connection."); byte[] frameAsBytes = (send ? WebSocketFrame.CreateCloseFrame(e.PayloadData, _client).ToArray() : null); e.WasClean = closeHandshake(frameAsBytes, receive, received); releaseResources(); _logger.Trace("End closing the connection."); _readyState = WebSocketState.Closed; try { this.OnClose.Emit(this, e); } catch (Exception ex) { _logger.Error(ex.ToString()); error("An exception has occurred during the OnClose event.", ex); } } private void closeAsync(CloseEventArgs e, bool send, bool receive, bool received) { Action<CloseEventArgs, bool, bool, bool> closer = close; closer.BeginInvoke(e, send, receive, received, delegate(IAsyncResult ar) { closer.EndInvoke(ar); }, null); } private bool closeHandshake(byte[] frameAsBytes, bool receive, bool received) { bool flag = frameAsBytes != null && sendBytes(frameAsBytes); received = received || (receive && flag && _exitReceiving != null && _exitReceiving.WaitOne(_waitTime)); bool flag2 = flag && received; _logger.Debug($"Was clean?: {flag2}\n sent: {flag}\n received: {received}"); return flag2; } private bool connect() { lock (_forConn) { if (!checkIfAvailable(connecting: true, open: false, closing: false, closed: true, out var text)) { _logger.Error(text); error("An error has occurred in connecting.", null); return false; } try { _readyState = WebSocketState.Connecting; if (!doHandshake()) { return false; } _readyState = WebSocketState.Open; } catch (Exception ex) { _logger.Fatal(ex.ToString()); fatal("An exception has occurred while connecting.", ex); return false; } return true; } } private string createExtensions() { StringBuilder stringBuilder = new StringBuilder(80); if (_compression != 0) { string arg = _compression.ToExtensionString("server_no_context_takeover", "client_no_context_takeover"); stringBuilder.AppendFormat("{0}, ", arg); } int length = stringBuilder.Length; if (length > 2) { stringBuilder.Length = length - 2; return stringBuilder.ToString(); } return null; } private HttpResponse createHandshakeFailureResponse(WebSocketSharp.Net.HttpStatusCode code) { HttpResponse httpResponse = HttpResponse.CreateCloseResponse(code); httpResponse.Headers["Sec-WebSocket-Version"] = "13"; return httpResponse; } private HttpRequest createHandshakeRequest() { HttpRequest httpRequest = HttpRequest.CreateWebSocketRequest(_uri); NameValueCollection headers = httpRequest.Headers; if (!_origin.IsNullOrEmpty()) { headers["Origin"] = _origin; } headers["Sec-WebSocket-Key"] = _base64Key; _protocolsRequested = _protocols != null; if (_protocolsRequested) { headers["Sec-WebSocket-Protocol"] = _protocols.ToString(", "); } _extensionsRequested = _compression != CompressionMethod.None; if (_extensionsRequested) { headers["Sec-WebSocket-Extensions"] = createExtensions(); } headers["Sec-WebSocket-Version"] = "13"; AuthenticationResponse authenticationResponse = null; if (_authChallenge != null && _credentials != null) { authenticationResponse = new AuthenticationResponse(_authChallenge, _credentials, _nonceCount); _nonceCount = authenticationResponse.NonceCount; } else if (_preAuth) { authenticationResponse = new AuthenticationResponse(_credentials); } if (authenticationResponse != null) { headers["Authorization"] = authenticationResponse.ToString(); } if (_cookies.Count > 0) { httpRequest.SetCookies(_cookies); } return httpRequest; } private HttpResponse createHandshakeResponse() { HttpResponse httpResponse = HttpResponse.CreateWebSocketResponse(); NameValueCollection headers = httpResponse.Headers; headers["Sec-WebSocket-Accept"] = CreateResponseKey(_base64Key); if (_protocol != null) { headers["Sec-WebSocket-Protocol"] = _protocol; } if (_extensions != null) { headers["Sec-WebSocket-Extensions"] = _extensions; } if (_cookies.Count > 0) { httpResponse.SetCookies(_cookies); } return httpResponse; } private bool customCheckHandshakeRequest(WebSocketContext context, out string message) { message = null; return _handshakeRequestChecker == null || (message = _handshakeRequestChecker(context)) == null; } private MessageEventArgs dequeueFromMessageEventQueue() { lock (_forMessageEventQueue) { return (_messageEventQueue.Count > 0) ? _messageEventQueue.Dequeue() : null; } } private bool doHandshake() { setClientStream(); HttpResponse httpResponse = sendHandshakeRequest(); if (!checkHandshakeResponse(httpResponse, out var text)) { _logger.Fatal(text); fatal("An error has occurred while connecting.", CloseStatusCode.ProtocolError); return false; } if (_protocolsRequested) { _protocol = httpResponse.Headers["Sec-WebSocket-Protocol"]; } if (_extensionsRequested) { processSecWebSocketExtensionsServerHeader(httpResponse.Headers["Sec-WebSocket-Extensions"]); } processCookies(httpResponse.Cookies); return true; } private void enqueueToMessageEventQueue(MessageEventArgs e) { lock (_forMessageEventQueue) { _messageEventQueue.Enqueue(e); } } private void error(string message, Exception exception) { try { this.OnError.Emit(this, new ErrorEventArgs(message, exception)); } catch (Exception ex) { _logger.Error(ex.ToString()); } } private void fatal(string message, Exception exception) { CloseStatusCode code = ((exception is WebSocketException) ? ((WebSocketException)exception).Code : CloseStatusCode.Abnormal); fatal(message, code); } private void fatal(string message, CloseStatusCode code) { close(new CloseEventArgs(code, message), !code.IsReserved(), receive: false, received: false); } private void init() { _compression = CompressionMethod.None; _cookies = new WebSocketSharp.Net.CookieCollection(); _forConn = new object(); _forSend = new object(); _messageEventQueue = new Queue<MessageEventArgs>(); _forMessageEventQueue = ((ICollection)_messageEventQueue).SyncRoot; _readyState = WebSocketState.Connecting; } private void message() { MessageEventArgs obj = null; lock (_forMessageEventQueue) { if (_inMessage || _messageEventQueue.Count == 0 || _readyState != WebSocketState.Open) { return; } _inMessage = true; obj = _messageEventQueue.Dequeue(); } _message(obj); } private void messagec(MessageEventArgs e) { while (true) { try { this.OnMessage.Emit(this, e); } catch (Exception ex) { _logger.Error(ex.ToString()); error("An exception has occurred during an OnMessage event.", ex); } lock (_forMessageEventQueue) { if (_messageEventQueue.Count == 0 || _readyState != WebSocketState.Open) { _inMessage = false; break; } e = _messageEventQueue.Dequeue(); } bool flag = true; } } private void messages(MessageEventArgs e) { try { this.OnMessage.Emit(this, e); } catch (Exception ex) { _logger.Error(ex.ToString()); error("An exception has occurred during an OnMessage event.", ex); } lock (_forMessageEventQueue) { if (_messageEventQueue.Count == 0 || _readyState != WebSocketState.Open) { _inMessage = false; return; } e = _messageEventQueue.Dequeue(); } ThreadPool.QueueUserWorkItem(delegate { messages(e); }); } private void open() { _inMessage = true; startReceiving(); try { this.OnOpen.Emit(this, EventArgs.Empty); } catch (Exception ex) { _logger.Error(ex.ToString()); error("An exception has occurred during the OnOpen event.", ex); } MessageEventArgs obj = null; lock (_forMessageEventQueue) { if (_messageEventQueue.Count == 0 || _readyState != WebSocketState.Open) { _inMessage = false; return; } obj = _messageEventQueue.Dequeue(); } _message.BeginInvoke(obj, delegate(IAsyncResult ar) { _message.EndInvoke(ar); }, null); } private bool processCloseFrame(WebSocketFrame frame) { PayloadData payloadData = frame.PayloadData; close(new CloseEventArgs(payloadData), !payloadData.IncludesReservedCloseStatusCode, receive: false, received: true); return false; } private void processCookies(WebSocketSharp.Net.CookieCollection cookies) { if (cookies.Count != 0) { _cookies.SetOrRemove(cookies); } } private bool processDataFrame(WebSocketFrame frame) { enqueueToMessageEventQueue(frame.IsCompressed ? new MessageEventArgs(frame.Opcode, frame.PayloadData.ApplicationData.Decompress(_compression)) : new MessageEventArgs(frame)); return true; } private bool processFragmentFrame(WebSocketFrame frame) { if (!_inContinuation) { if (frame.IsContinuation) { return true; } _fragmentsOpcode = frame.Opcode; _fragmentsCompressed = frame.IsCompressed; _fragmentsBuffer = new MemoryStream(); _inContinuation = true; } _fragmentsBuffer.WriteBytes(frame.PayloadData.ApplicationData, 1024); if (frame.IsFinal) { using (_fragmentsBuffer) { byte[] rawData = (_fragmentsCompressed ? _fragmentsBuffer.DecompressToArray(_compression) : _fragmentsBuffer.ToArray()); enqueueToMessageEventQueue(new MessageEventArgs(_fragmentsOpcode, rawData)); } _fragmentsBuffer = null; _inContinuation = false; } return true; } private bool processPingFrame(WebSocketFrame frame) { if (send(new WebSocketFrame(Opcode.Pong, frame.PayloadData, _client).ToArray())) { _logger.Trace("Returned a pong."); } if (_emitOnPing) { enqueueToMessageEventQueue(new MessageEventArgs(frame)); } return true; } private bool processPongFrame(WebSocketFrame frame) { _receivePong.Set(); _logger.Trace("Received a pong."); return true; } private bool processReceivedFrame(WebSocketFrame frame) { if (!checkReceivedFrame(frame, out var text)) { throw new WebSocketException(CloseStatusCode.ProtocolError, text); } frame.Unmask(); return frame.IsFragment ? processFragmentFrame(frame) : (frame.IsData ? processDataFrame(frame) : (frame.IsPing ? processPingFrame(frame) : (frame.IsPong ? processPongFrame(frame) : (frame.IsClose ? processCloseFrame(frame) : processUnsupportedFrame(frame))))); } private void processSecWebSocketExtensionsClientHeader(string value) { if (value == null) { return; } StringBuilder stringBuilder = new StringBuilder(80); bool flag = false; foreach (string item in value.SplitHeaderValue(',')) { string value2 = item.Trim(); if (!flag && value2.IsCompressionExtension(CompressionMethod.Deflate)) { _compression = CompressionMethod.Deflate; stringBuilder.AppendFormat("{0}, ", _compression.ToExtensionString("client_no_context_takeover", "server_no_context_takeover")); flag = true; } } int length = stringBuilder.Length; if (length > 2) { stringBuilder.Length = length - 2; _extensions = stringBuilder.ToString(); } } private void processSecWebSocketExtensionsServerHeader(string value) { if (value == null) { _compression = CompressionMethod.None; } else { _extensions = value; } } private void processSecWebSocketProtocolHeader(IEnumerable<string> values) { if (!values.Contains((string p) => p == _protocol)) { _protocol = null; } } private bool processUnsupportedFrame(WebSocketFrame frame) { _logger.Fatal("An unsupported frame:" + frame.PrintToString(dumped: false)); fatal("There is no way to handle it.", CloseStatusCode.PolicyViolation); return false; } private void releaseClientResources() { if (_stream != null) { _stream.Dispose(); _stream = null; } if (_tcpClient != null) { _tcpClient.Close(); _tcpClient = null; } } private void releaseCommonResources() { if (_fragmentsBuffer != null) { _fragmentsBuffer.Dispose(); _fragmentsBuffer = null; _inContinuation = false; } if (_receivePong != null) { _receivePong.Close(); _receivePong = null; } if (_exitReceiving != null) { _exitReceiving.Close(); _exitReceiving = null; } } private void releaseResources() { if (_client) { releaseClientResources(); } else { releaseServerResources(); } releaseCommonResources(); } private void releaseServerResources() { if (_closeContext != null) { _closeContext(); _closeContext = null; _stream = null; _context = null; } } private bool send(byte[] frameAsBytes) { lock (_forConn) { if (_readyState != WebSocketState.Open) { _logger.Error("The sending has been interrupted."); return false; } return sendBytes(frameAsBytes); } } private bool send(Opcode opcode, Stream stream) { lock (_forSend) { Stream stream2 = stream; bool flag = false; bool flag2 = false; try { if (_compression != 0) { stream = stream.Compress(_compression); flag = true; } flag2 = send(opcode, stream, flag); if (!flag2) { error("The sending has been interrupted.", null); } } catch (Exception ex) { _logger.Error(ex.ToString()); error("An exception has occurred while sending data.", ex); } finally { if (flag) { stream.Dispose(); } stream2.Dispose(); } return flag2; } } private bool send(Opcode opcode, Stream stream, bool compressed) { long length = stream.Length; if (length == 0) { return send(Fin.Final, opcode, EmptyBytes, compressed); } long num = length / FragmentLength; int num2 = (int)(length % FragmentLength); byte[] array = null; if (num == 0) { array = new byte[num2]; return stream.Read(array, 0, num2) == num2 && send(Fin.Final, opcode, array, compressed); } array = new byte[FragmentLength]; if (num == 1 && num2 == 0) { return stream.Read(array, 0, FragmentLength) == FragmentLength && send(Fin.Final, opcode, array, compressed); } if (stream.Read(array, 0, FragmentLength) != FragmentLength || !send(Fin.More, opcode, array, compressed)) { return false; } long num3 = ((num2 == 0) ? (num - 2) : (num - 1)); for (long num4 = 0L; num4 < num3; num4++) { if (stream.Read(array, 0, FragmentLength) != FragmentLength || !send(Fin.More, Opcode.Cont, array, compressed)) { return false; } } if (num2 == 0) { num2 = FragmentLength; } else { array = new byte[num2]; } return stream.Read(array, 0, num2) == num2 && send(Fin.Final, Opcode.Cont, array, compressed); } private bool send(Fin fin, Opcode opcode, byte[] data, bool compressed) { lock (_forConn) { if (_readyState != WebSocketState.Open) { _logger.Error("The sending has been interrupted."); return false; } return sendBytes(new WebSocketFrame(fin, opcode, data, compressed, _client).ToArray()); } } private void sendAsync(Opcode opcode, Stream stream, Action<bool> completed) { Func<Opcode, Stream, bool> sender = send; sender.BeginInvoke(opcode, stream, delegate(IAsyncResult ar) { try { bool obj = sender.EndInvoke(ar); if (completed != null) { completed(obj); } } catch (Exception ex) { _logger.Error(ex.ToString()); error("An exception has occurred during a send callback.", ex); } }, null); } private bool sendBytes(byte[] bytes) { try { _stream.Write(bytes, 0, bytes.Length); return true; } catch (Exception ex) { _logger.Error(ex.ToString()); return false; } } private HttpResponse sendHandshakeRequest() { HttpRequest httpRequest = createHandshakeRequest(); HttpResponse httpResponse = sendHttpRequest(httpRequest, 90000); if (httpResponse.IsUnauthorized) { string text = httpResponse.Headers["WWW-Authenticate"]; _logger.Warn($"Received an authentication requirement for '{text}'."); if (text.IsNullOrEmpty()) { _logger.Error("No authentication challenge is specified."); return httpResponse; } _authChallenge = AuthenticationChallenge.Parse(text); if (_authChallenge == null) { _logger.Error("An invalid authentication challenge is specified."); return httpResponse; } if (_credentials != null && (!_preAuth || _authChallenge.Scheme == WebSocketSharp.Net.AuthenticationSchemes.Digest)) { if (httpResponse.HasConnectionClose) { releaseClientResources(); setClientStream(); } AuthenticationResponse authenticationResponse = new AuthenticationResponse(_authChallenge, _credentials, _nonceCount); _nonceCount = authenticationResponse.NonceCount; httpRequest.Headers["Authorization"] = authenticationResponse.ToString(); httpResponse = sendHttpRequest(httpRequest, 15000); } } if (httpResponse.IsRedirect) { string text2 = httpResponse.Headers["Location"]; _logger.Warn($"Received a redirection to '{text2}'."); if (_enableRedirection) { if (text2.IsNullOrEmpty()) { _logger.Error("No url to redirect is located."); return httpResponse; } if (!text2.TryCreateWebSocketUri(out var result, out var text3)) { _logger.Error("An invalid url to redirect is located: " + text3); return httpResponse; } releaseClientResources(); _uri = result; _secure = result.Scheme == "wss"; setClientStream(); return sendHandshakeRequest(); } } return httpResponse; } private HttpResponse sendHttpRequest(HttpRequest request, int millisecondsTimeout) { _logger.Debug("A request to the server:\n" + request.ToString()); HttpResponse response = request.GetResponse(_stream, millisecondsTimeout); _logger.Debug("A response to this request:\n" + response.ToString()); return response; } private bool sendHttpResponse(HttpResponse response) { _logger.Debug("A response to this request:\n" + response.ToString()); return sendBytes(response.ToByteArray()); } private void sendProxyConnectRequest() { HttpRequest httpRequest = HttpRequest.CreateConnectRequest(_uri); HttpResponse httpResponse = sendHttpRequest(httpRequest, 90000); if (httpResponse.IsProxyAuthenticationRequired) { string text = httpResponse.Headers["Proxy-Authenticate"]; _logger.Warn($"Received a proxy authentication requirement for '{text}'."); if (text.IsNullOrEmpty()) { throw new WebSocketException("No proxy authentication challenge is specified."); } AuthenticationChallenge authenticationChallenge = AuthenticationChallenge.Parse(text); if (authenticationChallenge == null) { throw new WebSocketException("An invalid proxy authentication challenge is specified."); } if (_proxyCredentials != null) { if (httpResponse.HasConnectionClose) { releaseClientResources(); _tcpClient = new TcpClient(_proxyUri.DnsSafeHost, _proxyUri.Port); _stream = _tcpClient.GetStream(); } AuthenticationResponse authenticationResponse = new AuthenticationResponse(authenticationChallenge, _proxyCredentials, 0u); httpRequest.Headers["Proxy-Authorization"] = authenticationResponse.ToString(); httpResponse = sendHttpRequest(httpRequest, 15000); } if (httpResponse.IsProxyAuthenticationRequired) { throw new WebSocketException("A proxy authentication is required."); } } if (httpResponse.StatusCode[0] != '2') { throw new WebSocketException("The proxy has failed a connection to the requested host and port."); } } private void setClientStream() { if (_proxyUri != null) { _tcpClient = new TcpClient(_proxyUri.DnsSafeHost, _proxyUri.Port); _stream = _tcpClient.GetStream(); sendProxyConnectRequest(); } else { _tcpClient = new TcpClient(_uri.DnsSafeHost, _uri.Port); _stream = _tcpClient.GetStream(); } if (_secure) { ClientSslConfiguration sslConfiguration = SslConfiguration; string targetHost = sslConfiguration.TargetHost; if (targetHost != _uri.DnsSafeHost) { throw new WebSocketException(CloseStatusCode.TlsHandshakeFailure, "An invalid host name is specified."); } try { SslStream sslStream = new SslStream(_stream, leaveInnerStreamOpen: false, sslConfiguration.ServerCertificateValidationCallback, sslConfiguration.ClientCertificateSelectionCallback); sslStream.AuthenticateAsClient(targetHost, sslConfiguration.ClientCertificates, sslConfiguration.EnabledSslProtocols, sslConfiguration.CheckCertificateRevocation); _stream = sslStream; } catch (Exception innerException) { throw new WebSocketException(CloseStatusCode.TlsHandshakeFailure, innerException); } } } private void startReceiving() { if (_messageEventQueue.Count > 0) { _messageEventQueue.Clear(); } _exitReceiving = new AutoResetEvent(initialState: false); _receivePong = new AutoResetEvent(initialState: false); Action receive = null; receive = delegate { WebSocketFrame.ReadFrameAsync(_stream, unmask: false, delegate(WebSocketFrame frame) { if (!processReceivedFrame(frame) || _readyState == WebSocketState.Closed) { _exitReceiving?.Set(); } else { receive(); if (!_inMessage && HasMessage && _readyState == WebSocketState.Open) { message(); } } }, delegate(Exception ex) { _logger.Fatal(ex.ToString()); fatal("An exception has occurred while receiving.", ex); }); }; receive(); } private bool validateSecWebSocketAcceptHeader(string value) { return value != null && value == CreateResponseKey(_base64Key); } private bool validateSecWebSocketExtensionsClientHeader(string value) { return value == null || value.Length > 0; } private bool validateSecWebSocketExtensionsServerHeader(string value) { if (value == null) { return true; } if (value.Length == 0) { return false; } if (!_extensionsRequested) { return false; } bool flag = _compression != CompressionMethod.None; foreach (string item in value.SplitHeaderValue(',')) { string text = item.Trim(); if (flag && text.IsCompressionExtension(_compression)) { if (!text.Contains("server_no_context_takeover")) { _logger.Error("The server hasn't sent back 'server_no_context_takeover'."); return false; } if (!text.Contains("client_no_context_takeover")) { _logger.Warn("The server hasn't sent back 'client_no_context_takeover'."); } string method = _compression.ToExtensionString(); if (text.SplitHeaderValue(';').Contains(delegate(string t) { t = t.Trim(); return t != method && t != "server_no_context_takeover" && t != "client_no_context_takeover"; })) { return false; } continue; } return false; } return true; } private bool validateSecWebSocketKeyHeader(string value) { return value != null && value.Length > 0; } private bool validateSecWebSocketProtocolClientHeader(string value) { return value == null || value.Length > 0; } private bool validateSecWebSocketProtocolServerHeader(string value) { if (value == null) { return !_protocolsRequested; } if (value.Length == 0) { return false; } return _protocolsRequested && _protocols.Contains((string p) => p == value); } private bool validateSecWebSocketVersionClientHeader(string value) { return value != null && value == "13"; } private bool validateSecWebSocketVersionServerHeader(string value) { return value == null || value == "13"; } internal static string CheckCloseParameters(ushort code, string reason, bool client) { return (!code.IsCloseStatusCode()) ? "An invalid close status code." : ((code != 1005) ? ((code == 1010 && !client) ? "MandatoryExtension cannot be used by a server." : ((code == 1011 && client) ? "ServerError cannot be used by a client." : ((!reason.IsNullOrEmpty() && reason.UTF8Encode().Length > 123) ? "A reason has greater than the allowable max size." : null))) : ((!reason.IsNullOrEmpty()) ? "NoStatus cannot have a reason." : null)); } internal static string CheckCloseParameters(CloseStatusCode code, string reason, bool client) { return (code != CloseStatusCode.NoStatus) ? ((code == CloseStatusCode.MandatoryExtension && !client) ? "MandatoryExtension cannot be used by a server." : ((code == CloseStatusCode.ServerError && client) ? "ServerError cannot be used by a client." : ((!reason.IsNullOrEmpty() && reason.UTF8Encode().Length > 123) ? "A reason has greater than the allowable max size." : null))) : ((!reason.IsNullOrEmpty()) ? "NoStatus cannot have a reason." : null); } internal static string CheckPingParameter(string message, out byte[] bytes) { bytes = message.UTF8Encode(); return (bytes.Length > 125) ? "A message has greater than the allowable max size." : null; } internal static string CheckSendParameter(byte[] data) { return (data == null) ? "'data' is null." : null; } internal static string CheckSendParameter(FileInfo file) { return (file == null) ? "'file' is null." : null; } internal static string CheckSendParameter(string data) { return (data == null) ? "'data' is null." : null; } internal static string CheckSendParameters(Stream stream, int length) { return (stream == null) ? "'stream' is null." : ((!stream.CanRead) ? "'stream' cannot be read." : ((length < 1) ? "'length' is less than 1." : null)); } internal void Close(HttpResponse response) { _readyState = WebSocketState.Closing; sendHttpResponse(response); releaseServerResources(); _readyState = WebSocketState.Closed; } internal void Close(WebSocketSharp.Net.HttpStatusCode code) { Close(createHandshakeFailureResponse(code)); } internal void Close(CloseEventArgs e, byte[] frameAsBytes, bool receive) { lock (_forConn) { if (_readyState == WebSocketState.Closing) { _logger.Info("The closing is already in progress."); return; } if (_readyState == WebSocketState.Closed) { _logger.Info("The connection has been closed."); return; } _readyState = WebSocketState.Closing; } e.WasClean = closeHandshake(frameAsBytes, receive, received: false); releaseServerResources(); releaseCommonResources(); _readyState = WebSocketState.Closed; try { this.OnClose.Emit(this, e); } catch (Exception ex) { _logger.Error(ex.ToString()); } } internal static string CreateBase64Key() { byte[] array = new byte[16]; RandomNumber.GetBytes(array); return Convert.ToBase64String(array); } internal static string CreateResponseKey(string base64Key) { StringBuilder stringBuilder = new StringBuilder(base64Key, 64); stringBuilder.Append("258EAFA5-E914-47DA-95CA-C5AB0DC85B11"); SHA1 sHA = new SHA1CryptoServiceProvider(); byte[] inArray = sHA.ComputeHash(stringBuilder.ToString().UTF8Encode()); return Convert.ToBase64String(inArray); } internal void InternalAccept() { try { if (!acceptHandshake()) { return; } _readyState = WebSocketState.Open; } catch (Exception ex) { _logger.Fatal(ex.ToString()); fatal("An exception has occurred while accepting.", ex); return; } open(); } internal bool Ping(byte[] frameAsBytes, TimeSpan timeout) { if (_readyState != WebSocketState.Open) { return false; } if (!send(frameAsBytes)) { return false; } return _receivePong?.WaitOne(timeout) ?? false; } internal void Send(Opcode opcode, byte[] data, Dictionary<CompressionMethod, byte[]> cache) { lock (_forSend) { lock (_forConn) { if (_readyState != WebSocketState.Open) { _logger.Error("The sending has been interrupted."); return; } try { if (!cache.TryGetValue(_compression, out var value)) { value = new WebSocketFrame(Fin.Final, opcode, data.Compress(_compression), _compression != CompressionMethod.None, mask: false).ToArray(); cache.Add(_compression, value); } sendBytes(value); } catch (Exception ex) { _logger.Error(ex.ToString()); } } } } internal void Send(Opcode opcode, Stream stream, Dictionary<CompressionMethod, Stream> cache) { lock (_forSend) { try { if (!cache.TryGetValue(_compression, out var value)) { value = stream.Compress(_compression); cache.Add(_compression, value); } else { value.Position = 0L; } send(opcode, value, _compression != CompressionMethod.None); } catch (Exception ex) { _logger.Error(ex.ToString()); } } } public void Accept() { if (!checkIfAvailable(client: false, server: true, connecting: true, open: false, closing: false, closed: false, out var text)) { _logger.Error(text); error("An error has occurred in accepting.", null); } else if (accept()) { open(); } } public void AcceptAsync() { if (!checkIfAvailable(client: false, server: true, connecting: true, open: false, closing: false, closed: false, out var text)) { _logger.Error(text); error("An error has occurred in accepting.", null); return; } Func<bool> acceptor = accept; acceptor.BeginInvoke(delegate(IAsyncResult ar) { if (acceptor.EndInvoke(ar)) { open(); } }, null); } public void Close() { if (!checkIfAvailable(connecting: true, open: true, closing: false, closed: false, out var text)) { _logger.Error(text); error("An error has occurred in closing the connection.", null); } else { close(new CloseEventArgs(), send: true, receive: true, received: false); } } public void Close(ushort code) { string text = _readyState.CheckIfAvailable(connecting: true, open: true, closing: false, closed: false) ?? CheckCloseParameters(code, null, _client); if (text != null) { _logger.Error(text); error("An error has occurred in closing the connection.", null); } else if (code == 1005) { close(new CloseEventArgs(), send: true, receive: true, received: false); } else { bool receive = !code.IsReserved(); close(new CloseEventArgs(code), receive, receive, received: false); } } public void Close(CloseStatusCode code) { string text = _readyState.CheckIfAvailable(connecting: true, open: true, closing: false, closed: false) ?? CheckCloseParameters(code, null, _client); if (text != null) { _logger.Error(text); error("An error has occurred in closing the connection.", null); } else if (code == CloseStatusCode.NoStatus) { close(new CloseEventArgs(), send: true, receive: true, received: false); } else { bool receive = !code.IsReserved(); close(new CloseEventArgs(code), receive, receive, received: false); } } public void Close(ushort code, string reason) { string text = _readyState.CheckIfAvailable(connecting: true, open: true, closing: false, closed: false) ?? CheckCloseParameters(code, reason, _client); if (text != null) { _logger.Error(text); error("An error has occurred in closing the connection.", null); } else if (code == 1005) { close(new CloseEventArgs(), send: true, receive: true, received: false); } else { bool receive = !code.IsReserved(); close(new CloseEventArgs(code, reason), receive, receive, received: false); } } public void Close(CloseStatusCode code, string reason) { string text = _readyState.CheckIfAvailable(connecting: true, open: true, closing: false, closed: false) ?? CheckCloseParameters(code, reason, _client); if (text != null) { _logger.Error(text); error("An error has occurred in closing the connection.", null); } else if (code == CloseStatusCode.NoStatus) { close(new CloseEventArgs(), send: true, receive: true, received: false); } else { bool receive = !code.IsReserved(); close(new CloseEventArgs(code, reason), receive, receive, received: false); } } public void CloseAsync() { if (!checkIfAvailable(connecting: true, open: true, closing: false, closed: false, out var text)) { _logger.Error(text); error("An error has occurred in closing the connection.", null); } else { closeAsync(new CloseEventArgs(), send: true, receive: true, received: false); } } public void CloseAsync(ushort code) { string text = _readyState.CheckIfAvailable(connecting: true, open: true, closing: false, closed: false) ?? CheckCloseParameters(code, null, _client); if (text != null) { _logger.Error(text); error("An error has occurred in closing the connection.", null); } else if (code == 1005) { closeAsync(new CloseEventArgs(), send: true, receive: true, received: false); } else { bool receive = !code.IsReserved(); closeAsync(new CloseEventArgs(code), receive, receive, received: false); } } public void CloseAsync(CloseStatusCode code) { string text = _readyState.CheckIfAvailable(connecting: true, open: true, closing: false, closed: false) ?? CheckCloseParameters(code, null, _client); if (text != null) { _logger.Error(text); error("An error has occurred in closing the connection.", null); } else if (code == CloseStatusCode.NoStatus) { closeAsync(new CloseEventArgs(), send: true, receive: true, received: false); } else { bool receive = !code.IsReserved(); closeAsync(new CloseEventArgs(code), receive, receive, received: false); } } public void CloseAsync(ushort code, string reason) { string text = _readyState.CheckIfAvailable(connecting: true, open: true, closing: false, closed: false) ?? CheckCloseParameters(code, reason, _client); if (text != null) { _logger.Error(text); error("An error has occurred in closing the connection.", null); } else if (code == 1005) { closeAsync(new CloseEventArgs(), send: true, receive: true, received: false); } else { bool receive = !code.IsReserved(); closeAsync(new CloseEventArgs(code, reason), receive, receive, received: false); } } public void CloseAsync(CloseStatusCode code, string reason) { string text = _readyState.CheckIfAvailable(connecting: true, open: true, closing: false, closed: false) ?? CheckCloseParameters(code, reason, _client); if (text != null) { _logger.Error(text); error("An error has occurred in closing the connection.", null); } else if (code == CloseStatusCode.NoStatus) { closeAsync(new CloseEventArgs(), send: true, receive: true, received: false); } else { bool receive = !code.IsReserved(); closeAsync(new CloseEventArgs(code, reason), receive, receive, received: false); } } public void Connect() { if (!checkIfAvailable(client: true, server: false, connecting: true, open: false, closing: false, closed: true, out var text)) { _logger.Error(text); error("An error has occurred in connecting.", null); } else if (connect()) { open(); } } public void ConnectAsync() { if (!checkIfAvailable(client: true, server: false, connecting: true, open: false, closing: false, closed: true, out var text)) { _logger.Error(text); error("An error has occurred in connecting.", null); return; } Func<bool> connector = connect; connector.BeginInvoke(delegate(IAsyncResult ar) { if (connector.EndInvoke(ar)) { open(); } }, null); } public bool Ping() { byte[] frameAsBytes = (_client ? WebSocketFrame.CreatePingFrame(mask: true).ToArray() : WebSocketFrame.EmptyPingBytes); return Ping(frameAsBytes, _waitTime); } public bool Ping(string message) { if (message == null || message.Length == 0) { return Ping(); } byte[] bytes; string text = CheckPingParameter(message, out bytes); if (text != null) { _logger.Error(text); error("An error has occurred in sending a ping.", null); return false; } return Ping(WebSocketFrame.CreatePingFrame(bytes, _client).ToArray(), _waitTime); } public void Send(byte[] data) { string text = _readyState.CheckIfAvailable(connecting: false, open: true, closing: false, closed: false) ?? CheckSendParameter(data); if (text != null) { _logger.Error(text); error("An error has occurred in sending data.", null); } else { send(Opcode.Binary, new MemoryStream(data)); } } public void Send(FileInfo file) { string text = _readyState.CheckIfAvailable(connecting: false, open: true, closing: false, closed: false) ?? CheckSendParameter(file); if (text != null) { _logger.Error(text); error("An error has occurred in sending data.", null); } else { send(Opcode.Binary, file.OpenRead()); } } public void Send(string data) { string text = _readyState.CheckIfAvailable(connecting: false, open: true, closing: false, closed: false) ?? CheckSendParameter(data); if (text != null) { _logger.Error(text); error("An error has occurred in sending data.", null); } else { send(Opcode.Text, new MemoryStream(data.UTF8Encode())); } } public void SendAsync(byte[] data, Action<bool> completed) { string text = _readyState.CheckIfAvailable(connecting: false, open: true, closing: false, closed: false) ?? CheckSendParameter(data); if (text != null) { _logger.Error(text); error("An error has occurred in sending data.", null); } else { sendAsync(Opcode.Binary, new MemoryStream(data), completed); } } public void SendAsync(FileInfo file, Action<bool> completed) { string text = _readyState.CheckIfAvailable(connecting: false, open: true, closing: false, closed: false) ?? CheckSendParameter(file); if (text != null) { _logger.Error(text); error("An error has occurred in sending data.", null); } else { sendAsync(Opcode.Binary, file.OpenRead(), completed); } } public void SendAsync(string data, Action<bool> completed) { string text = _readyState.CheckIfAvailable(connecting: false, open: true, closing: false, closed: false) ?? CheckSendParameter(data); if (text != null) { _logger.Error(text); error("An error has occurred in sending data.", null); } else { sendAsync(Opcode.Text, new MemoryStream(data.UTF8Encode()), completed); } } public void SendAsync(Stream stream, int length, Action<bool> completed) { string text = _readyState.CheckIfAvailable(connecting: false, open: true, closing: false, closed: false) ?? CheckSendParameters(stream, length); if (text != null) { _logger.Error(text); error("An error has occurred in sending data.", null); return; } stream.ReadBytesAsync(length, delegate(byte[] data) { int num = data.Length; if (num == 0) { _logger.Error("The data cannot be read from 'stream'."); error("An error has occurred in sending data.", null); } else { if (num < length) { _logger.Warn($"The length of the data is less than 'length':\n expected: {length}\n actual: {num}"); } bool obj = send(Opcode.Binary, new MemoryStream(data)); if (completed != null) { completed(obj); } } }, delegate(Exception ex) { _logger.Error(ex.ToString()); error("An exception has occurred while sending data.", ex); }); } public void SetCookie(WebSocketSharp.Net.Cookie cookie) { if (!checkIfAvailable(client: true, server: false, connecting: true, open: false, closing: false, closed: true, out var text)) { _logger.Error(text); error("An error has occurred in setting a cookie.", null); return; } lock (_forConn) { if (!checkIfAvailable(connecting: true, open: false, closing: false, closed: true, out text)) { _logger.Error(text); error("An error has occurred in setting a cookie.", null); return; } if (cookie == null) { _logger.Error("'cookie' is null."); error("An error has occurred in setting a cookie.", null); return; } lock (_cookies.SyncRoot) { _cookies.SetOrRemove(cookie); } } } public void SetCredentials(string username, string password, bool preAuth) { if (!checkIfAvailable(client: true, server: false, connecting: true, open: false, closing: false, closed: true, out var text)) { _logger.Error(text); error("An error has occurred in setting the credentials.", null); return; } lock (_forConn) { if (!checkIfAvailable(connecting: true, open: false, closing: false, closed: true, out text)) { _logger.Error(text); error("An error has occurred in setting the credentials.", null); } else if (username.IsNullOrEmpty()) { _logger.Warn("The credentials are set back to the default."); _credentials = null; _preAuth = false; } else if (Ext.Contains(username, ':') || !username.IsText()) { _logger.Error("'username' contains an invalid character."); error("An error has occurred in setting the credentials.", null); } else if (!password.IsNullOrEmpty() && !password.IsText()) { _logger.Error("'password' contains an invalid character."); error("An error has occurred in setting the credentials.", null); } else { _credentials = new WebSocketSharp.Net.NetworkCredential(username, password, _uri.PathAndQuery); _preAuth = preAuth; } } } public void SetProxy(string url, string username, string password) { if (!checkIfAvailable(client: true, server: false, connecting: true, open: false, closing: false, closed: true, out var text)) { _logger.Error(text); error("An error has occurred in setting the proxy.", null); return; } lock (_forConn) { Uri result; if (!checkIfAvailable(connecting: true, open: false, closing: false, closed: true, out text)) { _logger.Error(text); error("An error has occurred in setting the proxy.", null); } else if (url.IsNullOrEmpty()) { _logger.Warn("The proxy url and credentials are set back to the default."); _proxyUri = null; _proxyCredentials = null; } else if (!Uri.TryCreate(url, UriKind.Absolute, out result) || result.Scheme != "http" || result.Segments.Length > 1) { _logger.Error("The syntax of a proxy url must be 'http://<host>[:<port>]'."); error("An error has occurred in setting the proxy.", null); } else if (username.IsNullOrEmpty()) { _logger.Warn("The proxy credentials are set back to the default."); _proxyUri = result; _proxyCredentials = null; } else if (Ext.Contains(username, ':') || !username.IsText()) { _logger.Error("'username' contains an invalid character."); error("An error has occurred in setting the proxy.", null); } else if (!password.IsNullOrEmpty() && !password.IsText()) { _logger.Error("'password' contains an invalid character."); error("An error has occurred in setting the proxy.", null); } else { _proxyUri = result; _proxyCredentials = new WebSocketSharp.Net.NetworkCredential(username, password, $"{_uri.DnsSafeHost}:{_uri.Port}"); } } } void IDisposable.Dispose() { close(new CloseEventArgs(CloseStatusCode.Away), send: true, receive: true, received: false); } } } namespace WebSocketSharp.Server { public class WebSocketServer { private IPAddress _address; private WebSocketSharp.Net.AuthenticationSchemes _authSchemes; private static readonly string _defaultRealm; private bool _dnsStyle; private string _hostname; private TcpListener _listener; private Logger _logger; private int _port; private string _realm; private Thread _receiveThread; private bool _reuseAddress; private bool _secure; private WebSocketServiceManager _services; private ServerSslConfiguration _sslConfig; private volatile ServerState _state; private object _sync; private Func<IIdentity, WebSocketSharp.Net.NetworkCredential> _userCredFinder; public IPAddress Address => _address; public WebSocketSharp.Net.AuthenticationSchemes AuthenticationSchemes { get { return _authSchemes; } set { string text = _state.CheckIfAvailable(ready: true, start: false, shutting: false); if (text != null) { _logger.Error(text); } else { _authSchemes = value; } } } public bool IsListening => _state == ServerState.Start; public bool IsSecure => _secure; public bool KeepClean { get { return _services.KeepClean; } set { string text = _state.CheckIfAvailable(ready: true, start: false, shutting: false); if (text != null) { _logger.Error(text); } else { _services.KeepClean = value; } } } public Logger Log => _logger; public int Port => _port; public string Realm { get { return _realm; } set { string text = _state.CheckIfAvailable(ready: true, start: false, shutting: false); if (text != null) { _logger.Error(text); } else { _realm = value; } } } public bool ReuseAddress { get { return _reuseAddress; } set { string text = _state.CheckIfAvailable(ready: true, start: false, shutting: false); if (text != null) { _logger.Error(text); } else { _reuseAddress = value; } } } public ServerSslConfiguration SslConfiguration { get { return _sslConfig ?? (_sslConfig = new ServerSslConfiguration(null)); } set { string text = _state.CheckIfAvailable(ready: true, start: false, shutting: false); if (text != null) { _logger.Error(text); } else { _sslConfig = value; } } } public Func<IIdentity, WebSocketSharp.Net.NetworkCredential> UserCredentialsFinder { get { return _userCredFinder; } set { string text = _state.CheckIfAvailable(ready: true, start: false, shutting: false); if (text != null) { _logger.Error(text); } else { _userCredFinder = value; } } } public TimeSpan WaitTime { get { return _services.WaitTime; } set { string text = _state.CheckIfAvailable(ready: true, start: false, shutting: false) ?? value.CheckIfValidWaitTime(); if (text != null) { _logger.Error(text); } else { _services.WaitTime = value; } } } public WebSocketServiceManager WebSocketServices => _services; static WebSocketServer() { _defaultRealm = "SECRET AREA"; } public WebSocketServer() { init(null, IPAddress.Any, 80, secure: false); } public WebSocketServer(int port) : this(port, port == 443) { } public WebSocketServer(string url) { if (url == null) { throw new ArgumentNullException("url"); } if (url.Length == 0) { throw new ArgumentException("An empty string.", "url"); } if (!tryCreateUri(url, out var result, out var message)) { throw new ArgumentException(message, "url"); } string dnsSafeHost = result.DnsSafeHost; IPAddress address = dnsSafeHost.ToIPAddress(); if (!address.IsLocal()) { throw new ArgumentException("The host part isn't a local host name: " + url, "url"); } init(dnsSafeHost, address, result.Port, result.Scheme == "wss"); } public WebSocketServer(int port, bool secure) { if (!port.IsPortNumber()) { throw new ArgumentOutOfRangeException("port", "Not between 1 and 65535 inclusive: " + port); } init(null, IPAddress.Any, port, secure); } public WebSocketServer(IPAddress address, int port) : this(address, port, port == 443) { } public WebSocketServer(IPAddress address, int port, bool secure) { if (address == null) { throw new ArgumentNullException("address"); } if (!address.IsLocal()) { throw new ArgumentException("Not a local IP address: " + address, "address"); } if (!port.IsPortNumber()) { throw new ArgumentOutOfRangeException("port", "Not between 1 and 65535 inclusive: " + port); } init(null, address, port, secure); } private void abort() { lock (_sync) { if (!IsListening) { return; } _state = ServerState.ShuttingDown; } _listener.Stop(); _services.Stop(new CloseEventArgs(CloseStatusCode.ServerError), send: true, receive: false); _state = ServerState.Stop; } private string checkIfCertificateExists() { return (_secure && (_sslConfig == null || _sslConfig.ServerCertificate == null)) ? "The secure connection requires a server certificate." : null; } private string getRealm() { string realm = _realm; return (realm != null && realm.Length > 0) ? realm : _defaultRealm; } private void init(string hostname, IPAddress address, int port, bool secure) { _hostname = hostname ?? address.ToString(); _address = address; _port = port; _secure = se
ChaosTricks_RoR2_plugins/WebSocketIO.dll
Decompiled 2 years agousing System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using EventsIO; using EventsIO.Interfaces; using ModHelper; using ModHelper.Interfaces; using WebSocketIO.Data; using WebSocketSharp; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("WebSocketIO")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("BFT")] [assembly: AssemblyProduct("WebSocketIO")] [assembly: AssemblyCopyright("Copyright © 2022")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("27b98c5b-ac6a-4518-ae12-3c9957b291e4")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyVersion("1.0.0.0")] namespace WebSocketIO { public class ChaosWebSocketHandler { public const string TypeEventMessage = "event"; public const string TypeConfigMessage = "config"; public bool isEnableDebugLog = true; public bool isEnableDebugLogOnClose; public bool isEnableDebugLogOnOpen; public bool isEnableDebugLogOnCloseValidConnect = true; protected bool isNeedLogOnCloseValidConnect; protected ILogger logger; public Action<string, string> OnCustomMessage { get; set; } public Action<string> OnEventMessage { get; set; } public Action<string> OnConfigMessage { get; set; } public Action OnWebSocketOpen { get; set; } public Action<CloseEventArgs> OnWebSocketClose { get; set; } public Action<ErrorEventArgs> OnWebSocketError { get; set; } public ChaosWebSocketHandler(ILogger logger = null) { this.logger = logger; } protected void DebugWebSocketLog(string s) { if (isEnableDebugLog && logger != null) { logger.LogInfo((object)("[DEBUG] ChaosTricks WebSocketHandler: " + s)); } } protected void DebugWebSocketLogError(string s) { if (isEnableDebugLog && logger != null) { logger.LogError((object)("[DEBUG] ChaosTricks WebSocketHandler: " + s)); } } public void OnOpen() { if (isEnableDebugLogOnOpen) { DebugWebSocketLog("OnOpen"); } try { if (isEnableDebugLogOnCloseValidConnect) { isNeedLogOnCloseValidConnect = true; } OnWebSocketOpen?.Invoke(); } catch (Exception arg) { if (isEnableDebugLogOnOpen) { DebugWebSocketLogError($"OnOpen {arg}"); } } } public void OnClose(CloseEventArgs e) { if (isEnableDebugLogOnClose) { DebugWebSocketLog("OnClose " + e.Reason); } try { OnWebSocketClose?.Invoke(e); } catch (Exception arg) { if (isEnableDebugLogOnClose) { DebugWebSocketLogError($"OnClose {arg}"); } else if (isEnableDebugLogOnCloseValidConnect && isNeedLogOnCloseValidConnect) { isNeedLogOnCloseValidConnect = false; DebugWebSocketLogError($"OnClose {arg}"); } } } public void OnError(ErrorEventArgs e) { DebugWebSocketLogError("Error " + e.Message); try { OnWebSocketError?.Invoke(e); } catch (Exception arg) { DebugWebSocketLogError($"OnError inner error {arg}"); } } public WebSocketMessage ParseWebSocketMessage(string data) { try { return UtilityJson.Generate((IDebugLogger)null).FromString<WebSocketMessage>(data) ?? new WebSocketMessage(); } catch (Exception arg) { DebugWebSocketLogError($"ParseWebSocketMessage {arg}"); return new WebSocketMessage(); } } public void OnMessage(MessageEventArgs e) { if (!e.IsText) { return; } try { WebSocketMessage webSocketMessage = ParseWebSocketMessage(e.Data); string type = webSocketMessage.type; string data = webSocketMessage.data; if (!(type == "config")) { if (type == "event") { DebugWebSocketLog("OnMessage - event"); OnEventMessage?.Invoke(data); } else { DebugWebSocketLog("OnMessage - custom msg"); OnCustomMessage?.Invoke(type, data); } } else { DebugWebSocketLog("OnMessage - config"); OnConfigMessage?.Invoke(data); } } catch (Exception arg) { DebugWebSocketLogError($"OnMessage {arg}"); } } } public class WebSocketEventsReader<T> : EventsReaderOnFrame, IDisposable where T : class { protected object locker = new object(); protected List<string> eventListFromSocket = new List<string>(); protected bool isDisposed; protected bool isSocketMessageProcessing; public bool isAutoRequestSettingsOnOpen = true; public bool isAutoConnectOnRead = true; public const int DEFAULT_PORT = 13715; public float autoConnectOnReadPeriod = 8f; protected float autoConnectOnReadPeriodTicks; protected bool isNeedLogOnClose; public virtual ChaosWebSocketHandler SocketHandler { get; set; } public virtual WebSocket Socket { get; set; } public virtual T Settings { get; protected set; } public Action<MessageEventArgs> OnMessage { get; set; } public Action OnOpen { get; set; } public Action<CloseEventArgs> OnCloseOnlyAfterConnect { get; set; } public Action<ErrorEventArgs> OnErrorOnlyAfterConnect { get; set; } public Action<CloseEventArgs> OnClose { get; set; } public Action<ErrorEventArgs> OnError { get; set; } public WebSocketEventsReader(Action<IEventsData> processEvent, IEventsDataParser parser, Action<string> log = null, Action<string> errorLog = null, float checkPeriod = 2f, float delay = 1f, float initDelay = 0.5f) : base("", processEvent, parser, log, errorLog, checkPeriod, delay, initDelay) { } public virtual int GetPortFromSettingsOrDefault(string settingsDir) { try { string path = Path.Combine(settingsDir, "ChaosWebSocketConfig.txt"); if (File.Exists(path)) { return int.Parse(File.ReadAllLines(path)[0]); } } catch (Exception arg) { ((EventsReader)this).ReaderLogError($"GetPortFromSettingsOrDefault error: {arg}. (will be used {13715})"); } return 13715; } public virtual T ParseSettings(string data) { try { T result = UtilityJson.Generate((IDebugLogger)null).FromString<T>(data); ((EventsReader)this).ReaderLog("settings parsing completed: " + data); return result; } catch (Exception arg) { ((EventsReader)this).ReaderLogError($"error: {arg}.\nCan't parse settings. Using standard."); } T result2 = null; try { result2 = Activator.CreateInstance<T>(); return result2; } catch (Exception arg2) { ((EventsReader)this).ReaderLogError($"error: {arg2}.\nCan't create default data class."); return result2; } } public virtual void OpenSocket(bool isLogOnError = true) { try { WebSocket socket = Socket; if (socket != null && !socket.IsAlive) { ((EventsReader)this).ReaderLog("try to open socket connection"); socket.ConnectAsync(); } } catch (Exception arg) { if (isLogOnError) { ((EventsReader)this).ReaderLogError($"OpenSocket error: {arg}"); } } } public virtual void CloseSocket() { try { WebSocket socket = Socket; if (socket != null) { socket.Close(); } } catch (Exception arg) { ((EventsReader)this).ReaderLogError($"CloseSocket error: {arg}"); } } public virtual void RequestSettings() { try { WebSocket socket = Socket; if (socket != null) { socket.Send(new WebSocketMessage("config", "").ToString()); } } catch (Exception arg) { ((EventsReader)this).ReaderLogError($"RequestSettings error: {arg}"); } } public virtual void InitDefaultSocket(string settingsDir, string room, int port, string ip = "127.0.0.1") { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Expected O, but got Unknown WebSocket val = new WebSocket($"ws://{ip}:{port}/{room}", new string[0]); ChaosWebSocketHandler socketHandler = new ChaosWebSocketHandler { OnEventMessage = delegate(string data) { isSocketMessageProcessing = true; lock (locker) { eventListFromSocket.Add(data); } isSocketMessageProcessing = false; }, OnConfigMessage = delegate(string data) { Settings = ParseSettings(data); }, OnWebSocketOpen = delegate { isNeedLogOnClose = true; ((EventsReader)this).ReaderLog("ChaosTricks connected"); if (isAutoRequestSettingsOnOpen) { RequestSettings(); } try { OnOpen?.Invoke(); } catch (Exception arg6) { ((EventsReader)this).ReaderLogError($"ChaosTricks custom OnOpen error: {arg6}"); } }, OnWebSocketClose = delegate(CloseEventArgs e) { if (isNeedLogOnClose) { isNeedLogOnClose = false; ((EventsReader)this).ReaderLog($"ChaosTricks disconnected {e.Reason} {e.Code}"); try { OnCloseOnlyAfterConnect?.Invoke(e); } catch (Exception arg4) { ((EventsReader)this).ReaderLogError($"ChaosTricks custom OnClose after success connection error: {arg4}"); } } try { OnClose?.Invoke(e); } catch (Exception arg5) { ((EventsReader)this).ReaderLogError($"ChaosTricks custom OnClose error: {arg5}"); } }, OnWebSocketError = delegate(ErrorEventArgs e) { if (isNeedLogOnClose) { ((EventsReader)this).ReaderLog($"ChaosTricks ws error {e.Message} {e.Exception}"); try { OnErrorOnlyAfterConnect?.Invoke(e); } catch (Exception arg2) { ((EventsReader)this).ReaderLogError($"ChaosTricks custom OnError after success connection error: {arg2}"); } } try { OnError?.Invoke(e); } catch (Exception arg3) { ((EventsReader)this).ReaderLogError($"ChaosTricks custom OnError error: {arg3}"); } } }; val.OnMessage += delegate(object sender, MessageEventArgs e) { socketHandler.OnMessage(e); try { OnMessage?.Invoke(e); } catch (Exception arg) { ((EventsReader)this).ReaderLogError($"ChaosTricks custom OnMessage error: {arg}"); } }; val.OnOpen += delegate { socketHandler.OnOpen(); }; val.OnClose += delegate(object sender, CloseEventArgs e) { socketHandler.OnClose(e); }; val.OnError += delegate(object sender, ErrorEventArgs e) { socketHandler.OnError(e); }; if (!File.Exists(Path.Combine(settingsDir ?? "", ".debug_websocket"))) { val.Log.Level = (LogLevel)10; } SocketHandler = socketHandler; Socket = val; } public override string[] ReadAll(string path, bool isClearFile = true) { string[] result = null; if (!isSocketMessageProcessing) { lock (locker) { if (eventListFromSocket.Count > 0) { result = eventListFromSocket.ToArray(); eventListFromSocket.Clear(); } } } return result; } public override void ReadAndProcessAllWithDelayOnFrame(float dt) { if (isAutoConnectOnRead) { autoConnectOnReadPeriodTicks += dt; if (autoConnectOnReadPeriodTicks > autoConnectOnReadPeriod) { autoConnectOnReadPeriodTicks = 0f; OpenSocket(isLogOnError: false); } } ((EventsReaderOnFrame)this).ReadAndProcessAllWithDelayOnFrame(dt); } protected virtual void Dispose(bool disposing) { if (!isDisposed) { isDisposed = true; if (disposing) { ((IDisposable)Socket)?.Dispose(); } } } ~WebSocketEventsReader() { try { Dispose(disposing: false); } finally { ((object)this).Finalize(); } } public void Dispose() { Dispose(disposing: true); GC.SuppressFinalize(this); } } } namespace WebSocketIO.Interfaces { public interface IChaosWebSocket { void Start(); void Stop(); } } namespace WebSocketIO.Data { public class WebSocketMessage { public string type = ""; public string data = ""; public WebSocketMessage() { } public WebSocketMessage(string type, string data) { this.type = type; this.data = data; } public override string ToString() { string text = data.Replace("\"", "\\\""); return "{\"type\":\"" + type + "\", \"data\":\"" + text + "\"}"; } } }