Decompiled source of ChaosTricks SBG TwitchIntegration v1.0.0
ChaosTricks_SBG_plugins/EventsIO.dll
Decompiled a day 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_SBG_plugins/InteractiveMod.dll
Decompiled a day agousing System; using System.Collections; 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.Runtime.Versioning; using BepInEx; using EventsIO; using EventsIO.Interfaces; using HarmonyLib; using Mirror; using ModHelper; using ModHelper.Interfaces; using ModHelper.Wrappers; using ModHelperUnity.Interfaces; using ModHelperUnity.TypedNotify; using ModHelperUnity.Utilities; using Newtonsoft.Json; using UnityEngine; using UnityEngine.InputSystem; using UnityEngine.InputSystem.Utilities; using UnityEngine.SceneManagement; using WebSocketIO; using bft_mod.Commands.Base; using bft_mod.Commands.Interfaces; using bft_mod.Patchers; using bft_mod.Services; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("sbg_bft_mod")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("BFT LLC")] [assembly: AssemblyProduct("ChaosTricksMod")] [assembly: AssemblyCopyright("Copyright © 2026")] [assembly: AssemblyTrademark("BFT")] [assembly: ComVisible(false)] [assembly: Guid("95844EA6-4892-4399-9DA6-6B15C259038B")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyVersion("1.0.0.0")] namespace bft_mod { [BepInPlugin("bft.chaostricks", "Chaos Tricks", "1.0.0")] internal class BepInExPlugin : BaseUnityPlugin { public const string GUID = "bft.chaostricks"; public const string NAME = "Chaos Tricks"; private GameObject hookObj; private bool isPatched; public void Awake() { try { SettingsUtils.BaseFolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); SceneManager.sceneLoaded += OnSceneLoaded; } catch (Exception arg) { ((HelperLog)Utils.logger).LogError((object)string.Format("{0} v{1} error: {2}", "Chaos Tricks", "1.0.0", arg)); } } private void OnSceneLoaded(Scene scene, LoadSceneMode loadSceneMode) { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Expected O, but got Unknown try { ((HelperLog)Utils.logger).Log((object)("OnSceneLoaded triggered: " + ((Scene)(ref scene)).name)); if (!isPatched) { ((HelperLog)Utils.logger).LogInfo((object)"Background task: trying to create mod instance"); hookObj = new GameObject(); Object.DontDestroyOnLoad((Object)(object)hookObj); hookObj.AddComponent<InteractiveMod>(); hookObj.SetActive(true); isPatched = true; SceneManager.sceneLoaded -= OnSceneLoaded; } } catch (Exception arg) { ((HelperLog)Utils.logger).LogError((object)string.Format("{0} v{1} OnSceneLoaded error: {2}", "Chaos Tricks", "1.0.0", arg)); } } } public static class GameUtils { public static IEnumerable<PlayerInfo> Players => GameManager.RemotePlayers.Where((PlayerInfo p) => (Object)(object)p != (Object)null && !IsPlayerSpectator(p)); public static bool IsHost() { try { return NetworkServer.active; } catch (Exception arg) { ((HelperLog)Utils.logger).LogError((object)$"IsHost, detecting game host error: {arg}"); return true; } } public static ulong GetCurrentPlayerGUID() { try { return GameManager.LocalPlayerId.Guid; } catch (Exception arg) { ((HelperLog)Utils.logger).LogError((object)$"GetCurrentPlayerGUID error: {arg}"); return ulong.MaxValue; } } public static PlayerInfo GetCurrentPlayer() { try { return GameManager.LocalPlayerInfo; } catch (Exception arg) { ((HelperLog)Utils.logger).LogError((object)$"GetCurrentNetworkPlayerID, detecting player id error: {arg}"); return null; } } public static string GetPlayerName(PlayerInfo p) { try { return p.PlayerId.PlayerName; } catch (Exception arg) { ((HelperLog)Utils.logger).LogError((object)$"GetPlayerName error: {arg}"); return ""; } } public static ulong GetPlayerGUID(PlayerInfo p) { try { return p.PlayerId.Guid; } catch (Exception arg) { ((HelperLog)Utils.logger).LogError((object)$"GetPlayerGUID error: {arg}"); return ulong.MaxValue; } } public static bool IsPlayerSpectator(PlayerInfo p) { PlayerSpectator asSpectator = p.AsSpectator; if ((Object)(object)asSpectator == (Object)null) { return false; } return asSpectator.IsSpectating; } public static PlayerInfo GetPlayerByNetworkID(ulong id) { foreach (PlayerInfo player in Players) { if (GetPlayerGUID(player) == id) { return player; } } return null; } public static void ApplyForceToPlayer(PlayerInfo p, in Vector3 dirForce, in Vector3 dirCartForce) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) GolfCartInfo golfCart = p.ActiveGolfCartSeat.golfCart; if ((Object)(object)golfCart != (Object)null && ((NetworkBehaviour)golfCart).authority && (Object)(object)golfCart.AsEntity != (Object)null) { Rigidbody rigidbody = golfCart.AsEntity.Rigidbody; if ((Object)(object)rigidbody == (Object)null) { ((HelperLog)Utils.logger).LogWarning((object)"ApplyForceToPlayer cart Rigidbody is null"); } else { rigidbody.AddForce(dirCartForce, (ForceMode)1); } return; } PlayerMovement movement = p.Movement; if ((Object)(object)movement == (Object)null) { ((HelperLog)Utils.logger).LogWarning((object)"ApplyForceToPlayer movement is null"); return; } Rigidbody component = ((Component)movement).GetComponent<Rigidbody>(); if ((Object)(object)component == (Object)null) { ((HelperLog)Utils.logger).LogWarning((object)"ApplyForceToPlayer Rigidbody is null"); } else { component.AddForce(dirForce, (ForceMode)1); } } public static Vector3 GetLocalPlayerForwardOffset(float offsetForward = 1f, float offsetHeight = 0.5f) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0067: 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_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)GetCurrentPlayer() == (Object)null) { ((HelperLog)Utils.logger).LogWarning((object)"GetLocalPlayerForwardOffset player is null"); return Vector3.zero; } PlayerMovement movement = GetCurrentPlayer().Movement; if ((Object)(object)movement == (Object)null) { ((HelperLog)Utils.logger).LogWarning((object)"GetLocalPlayerForwardOffset movement is null"); return Vector3.zero; } Transform transform = ((Component)movement).transform; Vector3 position = transform.position; Vector3 forward = transform.forward; return position + ((Vector3)(ref forward)).normalized * offsetForward + new Vector3(0f, offsetHeight, 0f); } public static Vector3 GetLocalPlayerForwardWay() { //IL_002f: 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) PlayerMovement movement = GetCurrentPlayer().Movement; if ((Object)(object)movement == (Object)null) { ((HelperLog)Utils.logger).LogWarning((object)"GetLocalPlayerForwardOffset movement is null"); return Vector3.forward; } return ((Component)movement).transform.forward; } public static Vector3 GetLocalPlayerRightWay() { //IL_002f: 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) PlayerMovement movement = GetCurrentPlayer().Movement; if ((Object)(object)movement == (Object)null) { ((HelperLog)Utils.logger).LogWarning((object)"GetLocalPlayerRightWay movement is null"); return Vector3.forward; } return ((Component)movement).transform.right; } public static Vector3 GetLocalPlayerUpWay() { //IL_002f: 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) PlayerMovement movement = GetCurrentPlayer().Movement; if ((Object)(object)movement == (Object)null) { ((HelperLog)Utils.logger).LogWarning((object)"GetLocalPlayerUpWay movement is null"); return Vector3.up; } return ((Component)movement).transform.up; } public static void TeleportPlayer(PlayerInfo p, in Vector3 pos) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) p.Movement.Teleport(pos, p.Movement.Rotation, true); } } public sealed class InteractiveMod : MonoBehaviour { public static InteractiveMod inst; public const string MOD_VERSION = "1.0.0"; private readonly ServiceProvider serviceProvider = ServiceProvider.inst; private readonly BufferedLogger logger = Utils.logger; private ScheduleManager systemScheduleManager; private ScheduleManager scheduleManager; private EventEmitter eventEmitter; private WebSocketEventsReader<SettingsData> eventsReader; private IEventsDataParser eventsParser; private ICommandManager commandManager; private IComponentTypedNotify notifyManager; private CommandConsole console; private Dictionary<string, IInternalStandaloneCommand> commands; private TranslationService translationService; private LimitedLogWrapper limitedLogger; private LimitedLogWrapper limitedSceneLogger; private const string DEFAULT_LANG = "en"; private string lastUsedLang = "en"; private bool readyToActivateEvents; private readonly List<IForceEnd> forceEndEvents = new List<IForceEnd>(); public void Awake() { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Expected O, but got Unknown //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Expected O, but got Unknown inst = this; ((HelperLog)logger).ClearLogBySize(200000, (Action<string>)Debug.LogError); limitedLogger = new LimitedLogWrapper(100, (IDebugLogger)(object)Utils.logger); limitedSceneLogger = new LimitedLogWrapper(50, (IDebugLogger)(object)Utils.logger); ((HelperLog)logger).LogInfo((object)"BFT mod Awake"); ((HelperLog)logger).LogInfo((object)"mod version 1.0.0"); FlushLog(); MainPatcher.InitPatch(); SubscribeOnLangChanged(); } private void SubscribeOnLangChanged() { try { LocalizationManager.LanguageChanged += OnLangChanged; } catch (Exception arg) { ((HelperLog)logger).LogError((object)$"mod lang subscribe error: {arg}"); } } private void UnsubscribeOnLangChanged() { try { LocalizationManager.LanguageChanged -= OnLangChanged; } catch (Exception arg) { ((HelperLog)logger).LogError((object)$"mod lang unsubscribe error: {arg}"); } } private void OnLangChanged() { SetLangBasedOnGame(); ((HelperLog)logger).LogInfo((object)("mod lang is changed to '" + lastUsedLang + "'")); } private void SetLangBasedOnGame() { try { lastUsedLang = LocalizationManager.CurrentLanguage; } catch (Exception arg) { ((HelperLog)logger).LogError((object)$"mod lang initiation error: {arg}"); lastUsedLang = "en"; } } public void Start() { ((HelperLog)logger).LogInfo((object)"BFT mod Start"); try { JsonUtils.RegisterCustomGenerator((Func<IJsonUtils>)(() => (IJsonUtils)(object)new JsonParser())); ((HelperLog)logger).LogInfo((object)"init mod services"); InitServices(); ((HelperLog)logger).LogInfo((object)"init mod readers"); InitReaders(); ((HelperLog)logger).LogInfo((object)"init mod commands"); InitCommands(needValidate: false); ((HelperLog)logger).LogInfo((object)"mod initiation ends"); } catch (Exception arg) { ((HelperLog)logger).LogError((object)$"mod initiation error: {arg}"); } FlushLog(); SetLangBasedOnGame(); } public void OnDestroy() { ((HelperLog)logger).LogInfo((object)"BFT mod OnDestroy"); FlushLog(); SceneManager.sceneLoaded -= SceneLoaded; UnsubscribeOnLangChanged(); ((HelperLog)logger).LogInfo((object)"BFT mod OnDestroy ends"); } private void FlushLog() { logger.Flush(true); } private void InitServices() { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Expected O, but got Unknown //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_005c: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Expected O, but got Unknown //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Expected O, but got Unknown eventEmitter = new EventEmitter(); serviceProvider.RegisterEventEmitter(eventEmitter); systemScheduleManager = new ScheduleManager((ILogger)(object)logger, 0); serviceProvider.RegisterSystemScheduleManager(systemScheduleManager); systemScheduleManager.NewPeriodicTask(new PeriodicTaskData { periodicAction = FlushLog, finishAction = FlushLog, periodInSec = 5f }, false); scheduleManager = new ScheduleManager((ILogger)(object)logger, 0); serviceProvider.RegisterScheduleManager(scheduleManager); translationService = new TranslationService(); translationService.LoadData(); serviceProvider.RegisterTranslationService(translationService); if (notifyManager == null) { notifyManager = (IComponentTypedNotify)(object)((Component)this).gameObject.AddComponent<TypedNotifyOnGUI>(); } notifyManager.ForcePostInit(Utils.modFolder, (IDebugLogger)(object)Utils.logger, (Func<string, byte[]>)null); SceneManager.sceneLoaded += SceneLoaded; } private void SceneLoaded(Scene scene, LoadSceneMode mode) { ((HelperLog)Utils.logger).LogInfo((object)("scene loaded: " + ((Scene)(ref scene)).name)); readyToActivateEvents = true; } private void InitReaders() { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Expected O, but got Unknown //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Expected O, but got Unknown console = new CommandConsole((IDebugLogger)(object)logger, (List<string>)null); eventsParser = (IEventsDataParser)new EventsDataParser((Action<string>)((HelperLog)logger).LogWarning); eventsReader = new WebSocketEventsReader<SettingsData>((Action<IEventsData>)ProcessEvent, eventsParser, (Action<string>)((HelperLog)logger).LogInfo, (Action<string>)((HelperLog)logger).LogInfo, 0.5f, 1f, 0.5f, true); eventsReader.InitDefaultSocket(Utils.modFolder, "chaostricks_sbgolf", 13715, "127.0.0.1"); Action<string> defaultOnConfig = eventsReader.SocketHandler.OnConfigMessage; eventsReader.SocketHandler.OnConfigMessage = delegate(string s) { defaultOnConfig?.Invoke(s); SettingsManager.QueueUpdateSettings(eventsReader.Settings); }; eventsReader.OpenSocket(true); } public void InitCommands(bool needValidate) { //IL_01a4: Unknown result type (might be due to invalid IL or missing references) //IL_01ae: Expected O, but got Unknown forceEndEvents.Clear(); Type type = typeof(IInternalStandaloneCommand); IEnumerable<Type> enumerable = from p in Assembly.GetExecutingAssembly().GetTypes() where type.IsAssignableFrom(p) && p.IsClass && !p.IsAbstract select p; ((HelperLog)logger).LogInfo((object)$"found {enumerable.Count()} commands"); commands = new Dictionary<string, IInternalStandaloneCommand>(); foreach (Type item2 in enumerable) { IInternalStandaloneCommand internalStandaloneCommand = Activator.CreateInstance(item2) as IInternalStandaloneCommand; if (internalStandaloneCommand != null) { console.RegisterCommand((IConsoleCommand)internalStandaloneCommand); if (commands.ContainsKey(((IConsoleCommand)internalStandaloneCommand).Id)) { ((HelperLog)logger).LogWarning((object)("repeated id command " + ((IConsoleCommand)internalStandaloneCommand).Id + ". The command will replace existed.")); } commands[((IConsoleCommand)internalStandaloneCommand).Id] = internalStandaloneCommand; if (internalStandaloneCommand is IForceEnd item) { forceEndEvents.Add(item); } ((HelperLog)logger).LogInfo((object)("init command '" + ((IConsoleCommand)internalStandaloneCommand).Id + "' complete")); } else { ((HelperLog)logger).LogError((object)("init command '" + ((IConsoleCommand)internalStandaloneCommand).Id + "' failed")); } } ((HelperLog)logger).LogInfo((object)$"found {commands.Count} commands and {forceEndEvents.Count} timers"); ((HelperLog)logger).LogInfo((object)"init HelperCommandManager"); commandManager = (ICommandManager)new HelperCommandManagerFormatted((IDebugLogger)(object)logger); commandManager.InitFromFile(Utils.GetRelativeModFilePath("commands.data")); int num = commandManager.GetCommands().Length; ((HelperLog)logger).LogInfo((object)$"found {num} events"); if (!needValidate) { return; } ((HelperLog)logger).LogInfo((object)"validate commands"); string[] array = commandManager.GetCommands(); foreach (string text in array) { if (!console.IsValidCommandLine(text?.Trim())) { ((HelperLog)logger).LogError((object)("Command line '" + text + "' invalid")); } } ((HelperLog)logger).LogInfo((object)"init HelperCommandManager ends"); } private void ProcessEvent(IEventsData data) { if (string.IsNullOrEmpty(data.EventID)) { ((HelperLog)logger).LogError((object)"ProcessEvent eventID is null or empty"); return; } if (!GameUtils.IsHost()) { ChaosModNetwork.ActivateEventOnHostSide(GameUtils.GetCurrentPlayerGUID(), data); return; } ActivateEventLocally(data); ((HelperDebugLog)Utils.logger).LogDebugInfo((object)$"network data, p count {GameUtils.Players.Count()}, all {SettingsManager.Data.applyEffectsToAll}"); if (GameUtils.Players.Count() >= 1) { ChaosModNetwork.ActivateNetworkEventByHost(commandManager, commands, data); } } private void ActivateEventLocally(IEventsData data) { string eventID = data.EventID; if (string.IsNullOrEmpty(eventID)) { ((HelperLog)logger).LogError((object)"ActivateEventLocally eventID is null or empty"); return; } ((HelperLog)logger).LogInfo((object)("Try to execute event: '" + eventID + "'")); string text = commandManager.GetCommandData(eventID, true)?.Trim(); try { ((HelperLog)logger).LogInfo((object)("Command: " + text)); if (console.RunCommand(text, data, (Action<string>)null)) { ((HelperLog)logger).LogInfo((object)("Event '" + data.EventID + "' executing is completed")); if (notifyManager != null) { notifyManager.AddNotifyToQueue(data, translationService.translation, (Func<string, string>)null, true); } } else { ((HelperDebugLog)logger).LogDebugError((object)("Event '" + data.EventID + "' executing is failed")); } } catch (Exception arg) { ((HelperLog)logger).LogError((object)$"ActivateEventLocally '{data.EventID}' unexpected error: {arg}"); } } private void CancelEvents() { try { ((HelperLog)Utils.logger).LogInfo((object)"CancelEvents triggered"); foreach (IForceEnd forceEndEvent in forceEndEvents) { try { forceEndEvent.ForceEnd(); } catch (Exception arg) { ((HelperLog)Utils.logger).LogError((object)$"CancelEvents force end for {((IConsoleCommand)forceEndEvent).Id} error: {arg}"); } } if (notifyManager != null) { notifyManager.ClearNotifyQueue(); notifyManager.StopCurrentNotify(); } } catch (Exception arg2) { ((HelperLog)Utils.logger).LogError((object)$"CancelEvents {arg2}"); } } public void Update() { try { float deltaTime = Time.deltaTime; systemScheduleManager.OnUpdate(deltaTime); SettingsManager.OnUpdate(); scheduleManager.OnUpdate(deltaTime); if (readyToActivateEvents && (Object)(object)GameUtils.GetCurrentPlayer() != (Object)null) { eventEmitter.TriggerOnUpdateEvent(this, deltaTime); ((EventsReaderOnFrame)eventsReader).ReadAndProcessAllWithDelayOnFrame(deltaTime); ChaosModNetwork.ProcessNetworkEvents(commandManager, commands, ActivateEventLocally); } } catch (Exception arg) { limitedLogger.LogError((object)$"OnUpdate error: {arg}"); } } public void ReinitMod() { try { ((HelperLog)logger).LogInfo((object)"ReinitMod starts"); FlushLog(); CancelEvents(); InitCommands(needValidate: false); notifyManager.ForcePostInit(Utils.modFolder, (IDebugLogger)(object)Utils.logger, (Func<string, byte[]>)null); ((HelperLog)logger).LogInfo((object)"ReinitMod ends"); } catch (Exception arg) { ((HelperLog)logger).LogError((object)$"ReinitMod error: {arg}"); } FlushLog(); } } internal sealed class JsonParser : IJsonUtils { public T FromFile<T>(string path) where T : class { using StreamReader streamReader = new StreamReader(path); return FromString<T>(streamReader.ReadToEnd()); } public T FromString<T>(string s) where T : class { return JsonConvert.DeserializeObject<T>(s); } } public static class Utils { public static readonly string modFolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); public static readonly BufferedLogger logger = new BufferedLogger(modFolder, "latest_log.txt", false, 50); public static string GetRelativeModFilePath(string fname) { return Path.Combine(modFolder, fname); } } } namespace bft_mod.Services { public static class ExtensionHelper { public static string ReadStringOrDefault(this IEnumerator<string> e, string defaultVal = null) { if (!e.MoveNext()) { return defaultVal; } return e.Current; } } public class ChaosModNetwork { public struct DataSource { public ulong playerID; public string eventID; public string lang; public string username; public DataSource(ulong id, IEventsData data) { playerID = id; eventID = data.EventID; lang = data.Lang; username = data.Username; } public DataSource(IEnumerator<string> e) { playerID = ulong.Parse(e.ReadStringOrDefault()); eventID = e.ReadStringOrDefault(""); lang = e.ReadStringOrDefault("en"); username = e.ReadStringOrDefault("unknown"); } public EventsData ToEventData() { //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_0011: 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) //IL_002a: Expected O, but got Unknown return new EventsData { Username = username, EventID = eventID, Lang = lang }; } } private static readonly Queue<DataSource> commandQueue = new Queue<DataSource>(); public const ulong ANY_PLAYER_ID = ulong.MaxValue; private const string CHAT_PREFIX = "[CHAOS_TRICKS]"; private const string SIDE_HOST = "1"; private const string SIDE_CLIENT = "2"; private const string CHECK_BLOCK = "ㅤ"; public static bool HandleChatMessage(string msg, PlayerInfo sender) { ((HelperDebugLog)Utils.logger).LogDebugInfo((object)("HandleChatMessage debug: " + msg)); if (msg == null || !msg.StartsWith("[CHAOS_TRICKS]") || !msg.EndsWith("ㅤ")) { return false; } if (msg.Length == "[CHAOS_TRICKS]".Length) { ((HelperLog)Utils.logger).LogWarning((object)"HandleChatMessage warn: wrong msg len"); return true; } IEnumerable<string> enumerable = from s in msg.Substring("[CHAOS_TRICKS]".Length, msg.Length - "[CHAOS_TRICKS]".Length - "ㅤ".Length).Split(new char[1] { '|' }) where !string.IsNullOrWhiteSpace(s) select s into x select x.Trim(); if (enumerable.Count() < 3) { ((HelperLog)Utils.logger).LogError((object)$"HandleChatMessage error: wrong items count, got {enumerable.Count()}"); } IEnumerator<string> enumerator = enumerable.GetEnumerator(); string text = enumerator.ReadStringOrDefault(); DataSource data = new DataSource(enumerator); if (!(text == "1")) { if (text == "2") { ActivateClientEvent_ChatCallback(data); } else { ((HelperLog)Utils.logger).LogError((object)("HandleChatMessage error: wrong target side " + text)); } } else { ActivateHostEvent_ChatCallback(data); } return true; } private static void ActivateHostEvent_ChatCallback(DataSource data) { try { if (GameUtils.IsHost()) { ((HelperLog)Utils.logger).LogInfo((object)"ChaosModNetwork->ActivateHostEvent_ChatCallback triggered"); AddEvent(data); } } catch (Exception arg) { ((HelperLog)Utils.logger).LogError((object)$"ChaosModNetwork->ActivateHostEvent_ChatCallback error: {arg}"); } } private static void ActivateClientEvent_ChatCallback(DataSource data) { try { if (!GameUtils.IsHost()) { ((HelperLog)Utils.logger).LogInfo((object)"ChaosModNetwork->ActivateClientEvent_ChatCallback triggered"); AddEvent(data); } } catch (Exception arg) { ((HelperLog)Utils.logger).LogError((object)$"ChaosModNetwork->ActivateClientEvent_ChatCallback error: {arg}"); } } public static void ActivateEventOnHostSide(ulong playerID, IEventsData data) { ((HelperLog)Utils.logger).LogInfo((object)$"ChaosModNetwork->ActivateEventOnHostSide triggered for {playerID} {data.EventID}"); try { TextChatManager.SendChatMessage(string.Format("{0}{1}|{2}|{3}|{4}|{5}{6}", "[CHAOS_TRICKS]", "1", playerID, data.EventID, data.Lang, data.Username, "ㅤ")); } catch (Exception arg) { ((HelperLog)Utils.logger).LogError((object)$"ChaosModNetwork->ActivateEventOnHostSide error: {arg}"); } } public static void ActivateEventForOthers(DataSource data) { ((HelperLog)Utils.logger).LogInfo((object)$"ChaosModNetwork->ActivateEventForOthers triggered for {data.playerID} {data.eventID}"); try { TextChatManager.SendChatMessage(string.Format("{0}{1}|{2}|{3}|{4}|{5}{6}", "[CHAOS_TRICKS]", "2", data.playerID, data.eventID, data.lang, data.username, "ㅤ")); } catch (Exception arg) { ((HelperLog)Utils.logger).LogError((object)$"ChaosModNetwork->ActivateEventForOthers error: {arg}"); } } private static bool AnyCommandRequiresOnlyApplyOnce(string[] eventCommands, Dictionary<string, IInternalStandaloneCommand> commands, out bool sendToOtherClients) { for (int i = 0; i < eventCommands.Length; i++) { string key = CommandConsole.ParseArgs(eventCommands[i])[0]; try { if (commands[key] is INetworkApplyOnce networkApplyOnce) { sendToOtherClients = networkApplyOnce.ShouldTriggerClientSideForOthers(); return true; } } catch (Exception arg) { ((HelperLog)Utils.logger).LogError((object)$"ChaosModNetwork->AnyCommandRequiresNetworkSync: {arg}"); sendToOtherClients = false; return false; } } sendToOtherClients = false; return false; } private static void AddEvent(DataSource data) { ((HelperLog)Utils.logger).LogInfo((object)$"ChaosModNetwork->AddEvent triggered for {data.playerID} {data.eventID}"); if (commandQueue == null) { ((HelperLog)Utils.logger).LogError((object)"ChaosModNetwork->AddEvent an attempt to store events before initiating"); } else { commandQueue.Enqueue(data); } } public static void ProcessNetworkEvents(ICommandManager cm, Dictionary<string, IInternalStandaloneCommand> commands, Action<IEventsData> activateEventLocally) { bool flag = GameUtils.IsHost(); while (commandQueue.Count > 0) { try { if (flag) { ProcessNetworkEvents_OnHostSide(cm, commands, activateEventLocally); } else { ProcessNetworkEvents_OnClientSide(activateEventLocally); } } catch (Exception arg) { ((HelperLog)Utils.logger).LogError((object)$"ChaosModNetwork->ProcessNetworkEvents (host {flag}): {arg}"); } } } private static void ProcessNetworkEvents_OnHostSide(ICommandManager cm, Dictionary<string, IInternalStandaloneCommand> commands, Action<IEventsData> activateEventLocally) { DataSource data = commandQueue.Dequeue(); ((HelperLog)Utils.logger).LogInfo((object)$"ChaosModNetwork->ProcessNetworkEvents_OnHostSide event id {data.eventID} for {data.playerID}"); if (data.playerID == ulong.MaxValue || data.playerID == GameUtils.GetCurrentPlayerGUID()) { ((HelperLog)Utils.logger).LogError((object)$"ChaosModNetwork->ProcessNetworkEvents_OnHostSide should not get here any player ID or host ID (got {data.playerID})"); return; } string text = cm.GetCommandData(data.eventID, true)?.Trim(); if (string.IsNullOrEmpty(text)) { ((HelperLog)Utils.logger).LogWarning((object)"ChaosModNetwork->ProcessNetworkEvents_OnHostSide can't find commands"); return; } string[] eventCommands = CommandConsole.ParseCommandLine(text); ulong num = (SettingsManager.Data.applyEffectsToAll ? ulong.MaxValue : data.playerID); if (AnyCommandRequiresOnlyApplyOnce(eventCommands, commands, out var sendToOtherClients)) { ulong playerID = data.playerID; if (sendToOtherClients) { data.playerID = ulong.MaxValue; } ActivateEventForOthers(data); ApplyCommandsHostEffectsForOthers(eventCommands, playerID, commands); } else { data.playerID = num; ActivateEventForOthers(data); if (SettingsManager.Data.applyEffectsToAll) { activateEventLocally((IEventsData)(object)data.ToEventData()); } ApplyCommandsHostEffectsForOthers(eventCommands, num, commands); } } public static void ActivateNetworkEventByHost(ICommandManager cm, Dictionary<string, IInternalStandaloneCommand> commands, IEventsData data) { string[] eventCommands = CommandConsole.ParseCommandLine(cm.GetCommandData(data.EventID, true)?.Trim()); if (AnyCommandRequiresOnlyApplyOnce(eventCommands, commands, out var sendToOtherClients) && sendToOtherClients) { ActivateEventForOthers(new DataSource(ulong.MaxValue, data)); } else if (SettingsManager.Data.applyEffectsToAll) { ActivateEventForOthers(new DataSource(ulong.MaxValue, data)); ApplyCommandsHostEffectsForOthers(eventCommands, ulong.MaxValue, commands); } } private static void ApplyCommandsHostEffectsForOthers(string[] eventCommands, ulong targetPlayerID, Dictionary<string, IInternalStandaloneCommand> commands) { PlayerInfo[] array; if (targetPlayerID == ulong.MaxValue) { PlayerInfo currentPlayer = GameUtils.GetCurrentPlayer(); array = GameUtils.Players.Where((PlayerInfo ch) => (Object)(object)ch != (Object)(object)currentPlayer).ToArray(); } else { if (targetPlayerID == GameUtils.GetCurrentPlayerGUID()) { ((HelperLog)Utils.logger).LogError((object)"ChaosModNetwork->ApplyCommandsHostEffectsForOthers: target player is host"); return; } PlayerInfo playerByNetworkID = GameUtils.GetPlayerByNetworkID(targetPlayerID); if ((Object)(object)playerByNetworkID == (Object)null) { ((HelperLog)Utils.logger).LogError((object)"ChaosModNetwork->ApplyCommandsHostEffectsForOthers: null target"); return; } array = (PlayerInfo[])(object)new PlayerInfo[1] { playerByNetworkID }; } PlayerInfo[] array2 = array; foreach (PlayerInfo val in array2) { foreach (string text in eventCommands) { string[] array3 = CommandConsole.ParseArgs(text); string key = array3[0]; try { if (commands[key] is IHostNetworkCommand hostNetworkCommand) { hostNetworkCommand.ExecuteHostAction(array3.Skip(1), val); } } catch (Exception ex) { string playerName = GameUtils.GetPlayerName(val); ulong playerGUID = GameUtils.GetPlayerGUID(val); ((HelperLog)Utils.logger).LogError((object)$"ChaosModNetwork->ApplyCommandsHostEffectsForOthers cmd {text}, target {playerName}, id {playerGUID}: {ex}"); } } } } private static void ProcessNetworkEvents_OnClientSide(Action<IEventsData> activateEventLocally) { DataSource dataSource = commandQueue.Dequeue(); if (dataSource.playerID == ulong.MaxValue || dataSource.playerID == GameUtils.GetCurrentPlayerGUID()) { ((HelperLog)Utils.logger).LogInfo((object)$"ChaosModNetwork->ProcessNetworkEvents_OnClientSide event id {dataSource.eventID} for {dataSource.playerID}"); activateEventLocally((IEventsData)(object)dataSource.ToEventData()); } else { ((HelperLog)Utils.logger).LogInfo((object)$"ChaosModNetwork->ProcessNetworkEvents_OnClientSide event id {dataSource.eventID} for other player {dataSource.playerID}. Skipped."); } } } internal static class ArgsReaderFactory { public static CommandArgsReader NewReader(IEnumerable<string> args) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected O, but got Unknown return new CommandArgsReader(args, (ILogger)(object)Utils.logger); } } public sealed class EventEmitter { private enum Event { OnUpdate, OnConfigChangedThreadSafe } private class EmitterAction { public string id; public Action<object, object> action; } private readonly ILogger logger = (ILogger)new LimitedLogWrapper(100, (IDebugLogger)(object)Utils.logger); private readonly Dictionary<Event, List<EmitterAction>> eventHandlers; public EventEmitter() { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Expected O, but got Unknown eventHandlers = new Dictionary<Event, List<EmitterAction>>(); foreach (Event item in Enum.GetValues(typeof(Event)).OfType<Event>()) { eventHandlers[item] = new List<EmitterAction>(); } } private void ReplaceOrAddHandler(Event key, string id, Action<object, object> handler) { if (id != null) { eventHandlers[key].RemoveAll((EmitterAction action) => action.id == id); } eventHandlers[key].Add(new EmitterAction { action = handler, id = id }); } private void TriggerEvent(Event key, object sender, object data) { try { if (!eventHandlers.TryGetValue(key, out var value)) { return; } foreach (EmitterAction item in value) { try { item.action(sender, data); } catch (Exception arg) { logger.LogError((object)$"EventEmitter->TriggerEvent inner {key} error: {arg}"); } } } catch (Exception arg2) { logger.LogError((object)$"EventEmitter->TriggerEvent {key} error: {arg2}"); } } public void ReplaceOrAddOnUpdateHandler(string id, Action<object, float> handler) { ReplaceOrAddHandler(Event.OnUpdate, id, delegate(object sender, object data) { handler(sender, (float)data); }); } public void TriggerOnUpdateEvent(object sender, float dtInSec) { TriggerEvent(Event.OnUpdate, sender, dtInSec); } public void ReplaceOrAddOnConfigChanged_ThreadSafeHandler(string id, Action<object, SettingsData> handler) { ReplaceOrAddHandler(Event.OnConfigChangedThreadSafe, id, delegate(object sender, object settings) { handler(sender, (SettingsData)settings); }); } public void TriggerOnConfigChangedEvent_ThreadSafe(object sender, SettingsData settings) { TriggerEvent(Event.OnConfigChangedThreadSafe, sender, settings); } } public sealed class ServiceProvider { public static readonly ServiceProvider inst = new ServiceProvider(); public ScheduleManager systemScheduleManager; public ScheduleManager scheduleManager; public EventEmitter eventEmitter; public TranslationService translationService; public void RegisterSystemScheduleManager(ScheduleManager systemScheduleManager) { this.systemScheduleManager = systemScheduleManager; } public void RegisterScheduleManager(ScheduleManager scheduleManager) { this.scheduleManager = scheduleManager; } public void RegisterEventEmitter(EventEmitter eventEmitter) { this.eventEmitter = eventEmitter; } public void RegisterTranslationService(TranslationService translationService) { this.translationService = translationService; } } public sealed class SettingsData { public bool applyEffectsToAll = true; } public static class SettingsManager { private static SettingsData newData; public static SettingsData Data { get; private set; } = new SettingsData(); public static void QueueUpdateSettings(SettingsData data) { newData = data; } public static void OnUpdate() { if (newData != null) { Data = newData; ServiceProvider.inst.eventEmitter.TriggerOnConfigChangedEvent_ThreadSafe(null, newData); newData = null; } } } public class TranslationService { public readonly ITranslation translation; public TranslationService() { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Expected O, but got Unknown translation = (ITranslation)new HelperLanguagesFormatted((IDebugLogger)(object)Utils.logger); } public void LoadData() { translation.InitFromFile(Utils.GetRelativeModFilePath("langs.data")); } } } namespace bft_mod.Patchers { internal class ChatPatcher { [HarmonyPatch(typeof(TextChatManager), "UserCode_RpcMessage__String__PlayerInfo")] public static class TextChatManagerPatch { [HarmonyPrefix] public static bool Prefix(string message, PlayerInfo sender) { try { return !ChaosModNetwork.HandleChatMessage(message, sender); } catch (Exception arg) { ((HelperLog)Utils.logger).LogError((object)$"TextChatManagerPatch unexpecter error: {arg}"); return false; } } } } public static class MainPatcher { private static bool isPatched; public static void InitPatch() { //IL_0022: Unknown result type (might be due to invalid IL or missing references) if (isPatched) { return; } isPatched = true; try { ((HelperLog)Utils.logger).Log((object)"MainPatcher init"); new Harmony("com.Loki.patch").PatchAll(Assembly.GetExecutingAssembly()); } catch (Exception arg) { ((HelperLog)Utils.logger).LogError((object)$"MainPatcher error: {arg}"); } } } } namespace bft_mod.Commands { internal class ClearInventory : IInternalStandaloneCommand, IConsoleCommand { public string Id => "clear_inventory"; public bool Execute(IEnumerable<string> args) { PlayerInventory inventory = GameUtils.GetCurrentPlayer().Inventory; int count = inventory.slots.Count; for (int i = 0; i < count; i++) { if (inventory.IsItemSlotOccupied(i)) { Traverse.Create((object)inventory).Method("RemoveItemAt", new object[2] { i, false }).GetValue(); } } return true; } public bool IsValidCommandArgs(IEnumerable<string> args) { throw new NotImplementedException(); } } internal class MinesSurround : IInternalStandaloneCommand, IConsoleCommand, IHostNetworkCommand { private static int minesUseIndex = 15000; public string Id => "mines_surround"; public bool Execute(IEnumerable<string> args) { if (!GameUtils.IsHost()) { return true; } return ExecuteHostAction(args, GameUtils.GetCurrentPlayer()); } public bool ExecuteHostAction(IEnumerable<string> args, PlayerInfo targetPlayer) { //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_005b: 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_0064: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0087: 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_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: 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_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_010a: 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) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: 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_0152: Unknown result type (might be due to invalid IL or missing references) //IL_0154: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_0132: 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_013f: Unknown result type (might be due to invalid IL or missing references) CommandArgsReader val = ArgsReaderFactory.NewReader(args); float num = Mathf.Max(0, val.ReadInt(0)); float num2 = Mathf.Max(0, val.ReadInt(10)); int num3 = Mathf.Max(1, val.ReadInt(10)); Vector3 position = targetPlayer.Movement.Position; ulong playerGUID = GameUtils.GetPlayerGUID(targetPlayer); PlayerInventory inventory = targetPlayer.Inventory; RaycastHit hit = default(RaycastHit); RaycastHit hit2 = default(RaycastHit); ItemUseId val3 = default(ItemUseId); for (int i = 0; i < num3; i++) { try { Vector3 val2 = UnityMathUtils.FindRandomSpawnPointNearPosition(position, num, num2); int num4 = LayerMask.op_Implicit(GameManager.LayerSettings.TerrainMask) | LayerMask.op_Implicit(GameManager.LayerSettings.PlayerGroundableMask); if (Physics.Raycast(val2 + Vector3.up * 2f, Vector3.down, ref hit, 50f, num4)) { val2 = ValidateHitObject(hit); } else if (Physics.Raycast(val2 + Vector3.up * 25f, Vector3.down, ref hit2, 100f, num4)) { val2 = ValidateHitObject(hit2); } ((ItemUseId)(ref val3))..ctor(playerGUID, minesUseIndex++, (ItemType)8); CourseManager.ServerSpawnLandmine(val2, Quaternion.identity, Vector3.zero, Vector3.zero, (LandmineArmType)1, val3, inventory); if (((NetworkBehaviour)inventory).isServer) { VfxManager.ServerPlayPooledVfxForAllClients((VfxType)23, val2, Quaternion.identity, default(Vector3), 0u, false, 0f, (NetworkConnectionToClient)null); } else { VfxManager.ClientPlayPooledVfxForAllClients((VfxType)23, val2, Quaternion.identity, default(Vector3), 0u, false, 0f); } } catch (Exception arg) { ((HelperLog)Utils.logger).LogError((object)$"spawn mine error: {arg}"); } } targetPlayer.PlayerAudio.PlayLandminePlantForAllClients(true); return true; } private Vector3 ValidateHitObject(RaycastHit hit) { //IL_0002: 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_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) Vector3 point = ((RaycastHit)(ref hit)).point; int layer = ((Component)((RaycastHit)(ref hit)).transform).gameObject.layer; if (layer == GameManager.LayerSettings.GolfCartLayer || layer == GameManager.LayerSettings.GolfCartPassengersLayer || layer == GameManager.LayerSettings.PlayerLayer) { point.y = ((RaycastHit)(ref hit)).transform.position.y; } return point; } public bool IsValidCommandArgs(IEnumerable<string> args) { throw new NotImplementedException(); } } internal class KnockOut : IInternalStandaloneCommand, IConsoleCommand { public string Id => "knock_out"; public bool Execute(IEnumerable<string> args) { Traverse.Create((object)GameUtils.GetCurrentPlayer().Movement).Method("SetKnockOutState", new object[1] { (object)(KnockoutState)2 }).GetValue(); return true; } public bool IsValidCommandArgs(IEnumerable<string> args) { throw new NotImplementedException(); } } internal class ShieldPlayer : IInternalStandaloneCommand, IConsoleCommand { private int shieldUseIndex = 20000; public string Id => "activate_shield"; public bool Execute(IEnumerable<string> args) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) PlayerInfo currentPlayer = GameUtils.GetCurrentPlayer(); ItemUseId val = default(ItemUseId); ((ItemUseId)(ref val))..ctor(GameUtils.GetPlayerGUID(currentPlayer), shieldUseIndex++, (ItemType)10); currentPlayer.LocalPlayerActivateElectromagnetShield(val); return true; } public bool IsValidCommandArgs(IEnumerable<string> args) { throw new NotImplementedException(); } } internal class PlayerHeadScaleDown : IInternalStandaloneCommand, IConsoleCommand { public static float scaleCoeff = 1f; private static int counter; private static Vector3 originalBoneScale; private static Vector3 originalBonePos; private static bool saved; public string Id => "head_scale_down"; public bool IsActive { get; private set; } private static bool CanRestoreDefault => counter <= 0; public bool Execute(IEnumerable<string> args) { //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Expected O, but got Unknown CommandArgsReader val = ArgsReaderFactory.NewReader(args); float durationInSec = val.ReadFloat(30f); float num = Mathf.Abs(val.ReadFloat(0.2f)); float num2 = Mathf.Max(0f, Mathf.Abs(val.ReadFloat(0.05f))); scaleCoeff -= num; scaleCoeff = Mathf.Max(scaleCoeff, num2); ApplyScale(scaleCoeff); if (!IsActive) { MarkActive(); IsActive = true; } ServiceProvider.inst.scheduleManager.AppendTimerTask(new TimerTaskData { id = Id, durationInSec = durationInSec, finishAction = delegate { IsActive = false; RestoreDefault(); } }, true); return true; } public static void RestoreDefault() { //IL_0028: 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) counter--; if (CanRestoreDefault) { scaleCoeff = 1f; PlayerInfo currentPlayer = GameUtils.GetCurrentPlayer(); currentPlayer.HeadBone.localScale = GetPlayerOriginalBoneScale(); currentPlayer.HeadBone.localPosition = GetPlayerOriginalBonePos(); } } public static void MarkActive() { counter++; } public bool IsValidCommandArgs(IEnumerable<string> args) { throw new NotImplementedException(); } public static void ApplyScale(float scaleCoeff) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) SavePlayerOriginalSizes(); PlayerInfo currentPlayer = GameUtils.GetCurrentPlayer(); currentPlayer.HeadBone.localScale = GetPlayerOriginalBoneScale() * scaleCoeff; currentPlayer.HeadBone.localPosition = GetPlayerOriginalBonePos() * scaleCoeff; } private static void SavePlayerOriginalSizes() { //IL_0018: 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) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) if (!saved) { saved = true; Transform headBone = GameUtils.GetCurrentPlayer().HeadBone; originalBoneScale = headBone.localScale; originalBonePos = headBone.localPosition; } } public static Vector3 GetPlayerOriginalBoneScale() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) return originalBoneScale; } public static Vector3 GetPlayerOriginalBonePos() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) return originalBonePos; } } internal class PlayerHeadScaleUp : IInternalStandaloneCommand, IConsoleCommand { public string Id => "head_scale_up"; public bool IsActive { get; private set; } public bool Execute(IEnumerable<string> args) { //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0088: 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) //IL_00a7: Expected O, but got Unknown CommandArgsReader obj = ArgsReaderFactory.NewReader(args); float durationInSec = obj.ReadFloat(30f); float num = Mathf.Abs(obj.ReadFloat(0.5f)); float num2 = Mathf.Abs(obj.ReadFloat(10f)); PlayerHeadScaleDown.scaleCoeff += num; PlayerHeadScaleDown.scaleCoeff = Mathf.Min(PlayerHeadScaleDown.scaleCoeff, num2); PlayerHeadScaleDown.ApplyScale(PlayerHeadScaleDown.scaleCoeff); if (!IsActive) { PlayerHeadScaleDown.MarkActive(); IsActive = true; } ServiceProvider.inst.scheduleManager.AppendTimerTask(new TimerTaskData { id = Id, durationInSec = durationInSec, finishAction = delegate { IsActive = false; PlayerHeadScaleDown.RestoreDefault(); } }, true); return true; } public bool IsValidCommandArgs(IEnumerable<string> args) { throw new NotImplementedException(); } } internal class ChangeGravity : IInternalStandaloneCommand, IConsoleCommand { private Vector3 originalGravity; private bool saved; public string Id => "change_gravity"; public bool IsActive { get; private set; } public bool Execute(IEnumerable<string> args) { //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006e: 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_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Expected O, but got Unknown //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) CommandArgsReader obj = ArgsReaderFactory.NewReader(args); float durationInSec = obj.ReadFloat(30f); float num = obj.ReadFloat(-3f); if (!saved) { saved = true; originalGravity = Physics.gravity; } Physics.gravity = new Vector3(originalGravity.x, num, originalGravity.z); IsActive = true; ServiceProvider.inst.scheduleManager.AppendTimerTask(new TimerTaskData { id = Id, durationInSec = durationInSec, finishAction = delegate { //IL_0008: Unknown result type (might be due to invalid IL or missing references) IsActive = false; Physics.gravity = originalGravity; } }, true); return true; } public bool IsValidCommandArgs(IEnumerable<string> args) { throw new NotImplementedException(); } } internal class SpeedBoost : IInternalStandaloneCommand, IConsoleCommand { public string Id => "speed_boost"; public bool Execute(IEnumerable<string> args) { float num = ArgsReaderFactory.NewReader(args).ReadFloat(30f); PlayerMovement movement = GameUtils.GetCurrentPlayer().Movement; try { if (movement.IsKnockedOutOrRecovering) { Traverse.Create((object)movement).Method("SetKnockOutState", new object[1] { (object)(KnockoutState)0 }).GetValue(); } Traverse.Create((object)movement).Field<double>("knockoutTimestamp").Value = 0.0; } catch (Exception arg) { ((HelperLog)Utils.logger).LogError((object)$"fix IsKnockedOutOrRecovering error: {arg}"); } Traverse.Create((object)movement).Method("AddSpeedBoost", new object[1] { num }).GetValue(); return true; } public bool IsValidCommandArgs(IEnumerable<string> args) { throw new NotImplementedException(); } } internal class DropSelectedItem : IInternalStandaloneCommand, IConsoleCommand { public string Id => "drop_item"; public bool Execute(IEnumerable<string> args) { GameUtils.GetCurrentPlayer().Inventory.DropItem(); return true; } public bool IsValidCommandArgs(IEnumerable<string> args) { throw new NotImplementedException(); } } internal class LaserStrikeAutoAim : IInternalStandaloneCommand, IConsoleCommand, IHostNetworkCommand { public string Id => "laser_strike_auto_aim"; public bool Execute(IEnumerable<string> args) { if (!GameUtils.IsHost()) { return true; } return ExecuteHostAction(args, GameUtils.GetCurrentPlayer()); } public bool ExecuteHostAction(IEnumerable<string> args, PlayerInfo targetPlayer) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) ItemUseId val = default(ItemUseId); ((ItemUseId)(ref val))..ctor(GameUtils.GetPlayerGUID(targetPlayer), LaserStrike.GetNextLaserIndex(), (ItemType)10); OrbitalLaserManager.ServerActivateLaser(targetPlayer.AsHittable, ((Component)targetPlayer).transform.position, targetPlayer.Inventory, val); return true; } public bool IsValidCommandArgs(IEnumerable<string> args) { throw new NotImplementedException(); } } internal class LaserStrike : IInternalStandaloneCommand, IConsoleCommand, IHostNetworkCommand { [CompilerGenerated] private sealed class <DelayedStrike>d__5 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public float waitInSec; public PlayerInfo targetPlayer; public float minRange; public float maxRange; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <DelayedStrike>d__5(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Expected O, but got Unknown //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_006e: 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) switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = (object)new WaitForSeconds(waitInSec); <>1__state = 1; return true; case 1: { <>1__state = -1; ItemUseId val = default(ItemUseId); ((ItemUseId)(ref val))..ctor(GameUtils.GetPlayerGUID(targetPlayer), GetNextLaserIndex(), (ItemType)10); OrbitalLaserManager.ServerActivateLaser((Hittable)null, UnityMathUtils.FindRandomSpawnPointNearPosition(((Component)targetPlayer).transform.position, minRange, maxRange), targetPlayer.Inventory, val); return false; } } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private static int laserUseIndex = 10000; public string Id => "laser_strike"; public bool Execute(IEnumerable<string> args) { if (!GameUtils.IsHost()) { return true; } return ExecuteHostAction(args, GameUtils.GetCurrentPlayer()); } public bool ExecuteHostAction(IEnumerable<string> args, PlayerInfo targetPlayer) { CommandArgsReader val = ArgsReaderFactory.NewReader(args); float minRange = Mathf.Max(0f, val.ReadFloat(0f)); float maxRange = Mathf.Max(0f, val.ReadFloat(2f)); int num = Mathf.Max(1, val.ReadInt(1)); for (int i = 0; i < num; i++) { ((MonoBehaviour)InteractiveMod.inst).StartCoroutine(DelayedStrike(0.015f * (float)i, targetPlayer, minRange, maxRange)); } return true; } [IteratorStateMachine(typeof(<DelayedStrike>d__5))] private IEnumerator DelayedStrike(float waitInSec, PlayerInfo targetPlayer, float minRange, float maxRange) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <DelayedStrike>d__5(0) { waitInSec = waitInSec, targetPlayer = targetPlayer, minRange = minRange, maxRange = maxRange }; } public static int GetNextLaserIndex() { return laserUseIndex++; } public bool IsValidCommandArgs(IEnumerable<string> args) { throw new NotImplementedException(); } } internal class GiveItem : IInternalStandaloneCommand, IConsoleCommand, IHostNetworkCommand { public string Id => "give_item"; public bool Execute(IEnumerable<string> args) { if (!GameUtils.IsHost()) { return true; } return ExecuteHostAction(args, GameUtils.GetCurrentPlayer()); } public bool ExecuteHostAction(IEnumerable<string> args, PlayerInfo targetPlayer) { //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) CommandArgsReader obj = ArgsReaderFactory.NewReader(args); string text = obj.ReadString(""); int usageCount = obj.ReadInt(1); ((HelperLog)Utils.logger).LogInfo((object)("try to give '" + text + "'")); if (text == "random") { ItemType randomItem = GetRandomItem(); targetPlayer.Inventory.ServerTryAddItem(randomItem, ValidateMaxUsage(usageCount, randomItem)); ((HelperLog)Utils.logger).LogInfo((object)$"random selected '{randomItem}'"); return true; } if (!Enum.TryParse<ItemType>(text, out ItemType result)) { ((HelperLog)Utils.logger).LogWarning((object)("can't parse '" + text + "', use random")); result = GetRandomItem(); } targetPlayer.Inventory.ServerTryAddItem(result, ValidateMaxUsage(usageCount, result)); return true; } private int ValidateMaxUsage(int usageCount, ItemType item) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) try { ItemData val = default(ItemData); if (!GameManager.AllItems.TryGetItemData(item, ref val)) { return 1; } return Mathf.Min(usageCount, val.MaxUses); } catch (Exception arg) { ((HelperLog)Utils.logger).LogError((object)$"ValidateMaxUsage for {item} error: {arg}"); return 1; } } private ItemType GetRandomItem() { //IL_003d: Unknown result type (might be due to invalid IL or missing references) return RandomUtils.GetRandomItemFromList<ItemType>((IList<ItemType>)(from ItemType e in Enum.GetValues(typeof(ItemType)) where (int)e > 0 select e).ToList()); } public bool IsValidCommandArgs(IEnumerable<string> args) { throw new NotImplementedException(); } } internal class LockCamera : IInternalStandaloneCommand, IConsoleCommand, IForceEnd { public string Id => "lock_camera"; public bool IsActive { get; private set; } private string PeriodicId => Id + "_period"; public bool Execute(IEnumerable<string> args) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0033: 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_0052: Expected O, but got Unknown //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Expected O, but got Unknown float durationInSec = ArgsReaderFactory.NewReader(args).ReadFloat(30f); IsActive = true; ServiceProvider.inst.scheduleManager.AppendTimerTask(new TimerTaskData { id = Id, durationInSec = durationInSec, finishAction = delegate { //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) IsActive = false; CameraActions camera2 = InputManager.Controls.Camera; ((CameraActions)(ref camera2)).Enable(); ServiceProvider.inst.scheduleManager.RemovePeriodicTask(PeriodicId); ((HelperLog)Utils.logger).LogInfo((object)(Id + " ends")); } }, false); ServiceProvider.inst.scheduleManager.NewPeriodicTask(new PeriodicTaskData { id = PeriodicId, periodInSec = 0.005f, periodicAction = delegate { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) if (IsActive) { CameraActions camera = InputManager.Controls.Camera; ((CameraActions)(ref camera)).Disable(); } } }, false); return true; } public void ForceEnd() { ServiceProvider.inst.scheduleManager.FinishImmediatlyTimerTask(Id); } public bool IsValidCommandArgs(IEnumerable<string> args) { throw new NotImplementedException(); } } internal class ApplyForceToPlayer_UpWay : IInternalStandaloneCommand, IConsoleCommand { public string Id => "apply_force_to_player_up"; public bool Execute(IEnumerable<string> args) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: 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) //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_0042: 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_0049: Unknown result type (might be due to invalid IL or missing references) CommandArgsReader obj = ArgsReaderFactory.NewReader(args); float num = obj.ReadFloat(5000f); float num2 = obj.ReadFloat(25000f); int num3 = obj.ReadInt(1); Vector3 val = GameUtils.GetLocalPlayerUpWay() * (float)num3; PlayerInfo currentPlayer = GameUtils.GetCurrentPlayer(); Vector3 dirForce = val * num; Vector3 dirCartForce = val * num2; GameUtils.ApplyForceToPlayer(currentPlayer, in dirForce, in dirCartForce); return true; } public bool IsValidCommandArgs(IEnumerable<string> args) { throw new NotImplementedException(); } } internal class ApplyForceToPlayer_ForwardWay : IInternalStandaloneCommand, IConsoleCommand { public string Id => "apply_force_to_player_forward"; public bool Execute(IEnumerable<string> args) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: 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) //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_0042: 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_0049: Unknown result type (might be due to invalid IL or missing references) CommandArgsReader obj = ArgsReaderFactory.NewReader(args); float num = obj.ReadFloat(5000f); float num2 = obj.ReadFloat(25000f); int num3 = obj.ReadInt(1); Vector3 val = GameUtils.GetLocalPlayerForwardWay() * (float)num3; PlayerInfo currentPlayer = GameUtils.GetCurrentPlayer(); Vector3 dirForce = val * num; Vector3 dirCartForce = val * num2; GameUtils.ApplyForceToPlayer(currentPlayer, in dirForce, in dirCartForce); return true; } public bool IsValidCommandArgs(IEnumerable<string> args) { throw new NotImplementedException(); } } internal class ApplyForceToPlayer_RightWay : IInternalStandaloneCommand, IConsoleCommand { public string Id => "apply_force_to_player_right"; public bool Execute(IEnumerable<string> args) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: 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) //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_0042: 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_0049: Unknown result type (might be due to invalid IL or missing references) CommandArgsReader obj = ArgsReaderFactory.NewReader(args); float num = obj.ReadFloat(5000f); float num2 = obj.ReadFloat(25000f); int num3 = obj.ReadInt(1); Vector3 val = GameUtils.GetLocalPlayerRightWay() * (float)num3; PlayerInfo currentPlayer = GameUtils.GetCurrentPlayer(); Vector3 dirForce = val * num; Vector3 dirCartForce = val * num2; GameUtils.ApplyForceToPlayer(currentPlayer, in dirForce, in dirCartForce); return true; } public bool IsValidCommandArgs(IEnumerable<string> args) { throw new NotImplementedException(); } } internal class ControllerInvertX : MouseInvertBase { public override string Id => "controller_invert_x"; protected override void SetInverted(bool invert) { GameSettings.All.Controls.Controller.invertX = invert; } protected override bool GetInvertSetting() { return GameSettings.All.Controls.Controller.invertX; } } internal class ControllerInvertY : MouseInvertBase { public override string Id => "controller_invert_y"; protected override void SetInverted(bool invert) { GameSettings.All.Controls.Controller.invertY = invert; } protected override bool GetInvertSetting() { return GameSettings.All.Controls.Controller.invertY; } } internal class PlayEmote : IInternalStandaloneCommand, IConsoleCommand, IForceEnd { public string Id => "play_emote"; public bool IsActive { get; private set; } public bool Execute(IEnumerable<string> args) { //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0053: 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_0066: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Expected O, but got Unknown //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: 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_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) CommandArgsReader obj = ArgsReaderFactory.NewReader(args); string text = obj.ReadString(""); float durationInSec = obj.ReadFloat(2f); PlayerInfo currentPlayer = GameUtils.GetCurrentPlayer(); currentPlayer.ExitGolfCart((GolfCartExitType)0); IsActive = true; GameplayActions gameplay = InputManager.Controls.Gameplay; ((GameplayActions)(ref gameplay)).Disable(); ServiceProvider.inst.scheduleManager.NewTimerTask(new TimerTaskData { id = Id, durationInSec = durationInSec, finishAction = delegate { //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) IsActive = false; GameplayActions gameplay2 = InputManager.Controls.Gameplay; ((GameplayActions)(ref gameplay2)).Enable(); ((HelperLog)Utils.logger).LogInfo((object)(Id + " ends")); } }, false); ((HelperLog)Utils.logger).LogInfo((object)("try to play emote '" + text + "'")); if (text == "random") { Emote randomEmote = GetRandomEmote(); currentPlayer.SetEmoteToPlay(randomEmote); ((HelperLog)Utils.logger).LogInfo((object)$"random selected '{randomEmote}'"); return true; } if (!Enum.TryParse<Emote>(text, out Emote result)) { ((HelperLog)Utils.logger).LogWarning((object)("can't parse '" + text + "', use random")); result = GetRandomEmote(); } currentPlayer.SetEmoteToPlay(result); return true; } private Emote GetRandomEmote() { //IL_003d: Unknown result type (might be due to invalid IL or missing references) return RandomUtils.GetRandomItemFromList<Emote>((IList<Emote>)(from Emote e in Enum.GetValues(typeof(Emote)) where (int)e > 0 select e).ToList()); } public bool IsValidCommandArgs(IEnumerable<string> args) { throw new NotImplementedException(); } public void ForceEnd() { ServiceProvider.inst.scheduleManager.FinishImmediatlyTimerTask(Id); } } internal class JumpPower : IInternalStandaloneCommand, IConsoleCommand, IForceEnd { private bool isInitiated; private float lastPower; private float oldBoostedJumpSpeed; private float oldJumpSpeed; public string Id => "jump_power"; public bool IsActive { get; private set; } public bool Execute(IEnumerable<string> args) { //IL_009e: 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_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_00c9: Expected O, but got Unknown if (!isInitiated) { isInitiated = true; oldJumpSpeed = GameUtils.GetCurrentPlayer().Movement.Settings.JumpUpwardsSpeed; oldBoostedJumpSpeed = GameManager.ItemSettings.SpringBootsJumpUpwardsSpeed; } CommandArgsReader obj = ArgsReaderFactory.NewReader(args); float durationInSec = obj.ReadFloat(30f); float num = obj.ReadFloat(0f); bool num2 = lastPower != num; lastPower = num; SetJumpSpeed(GameUtils.GetCurrentPlayer().Movement.Settings.JumpUpwardsSpeed * num); SetBoostedJumpSpeed(GameManager.ItemSettings.SpringBootsJumpUpwardsSpeed * num); IsActive = true; TimerTaskData val = new TimerTaskData { id = Id, durationInSec = durationInSec, finishAction = delegate { IsActive = false; SetJumpSpeed(oldJumpSpeed); SetBoostedJumpSpeed(oldBoostedJumpSpeed); ((HelperLog)Utils.logger).LogInfo((object)(Id + " ends")); } }; if (num2) { ServiceProvider.inst.scheduleManager.NewTimerTask(val, false); } else { ServiceProvider.inst.scheduleManager.AppendTimerTask(val, false); } return true; } private void SetJumpSpeed(float speed) { Traverse.Create((object)GameUtils.GetCurrentPlayer().Movement.Settings).Property("JumpUpwardsSpeed", (object[])null).SetValue((object)speed); } private void SetBoostedJumpSpeed(float speed) { Traverse.Create((object)GameManager.ItemSettings).Property("SpringBootsJumpUpwardsSpeed", (object[])null).SetValue((object)speed); } public void ForceEnd() { ServiceProvider.inst.scheduleManager.FinishImmediatlyTimerTask(Id); } public bool IsValidCommandArgs(IEnumerable<string> args) { throw new NotImplementedException(); } } internal class ChangeMouseSens : IInternalStandaloneCommand, IConsoleCommand, IForceEnd { private float oldMouseSens; private float oldConstrollerSens; private float lastMouseCommandSens; private bool needStoreOldSettings = true; public string Id => "change_mouse_move_sens"; public bool IsActive { get; private set; } public bool Execute(IEnumerable<string> args) { //IL_0080: 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) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Expected O, but got Unknown CommandArgsReader obj = ArgsReaderFactory.NewReader(args); float durationInSec = obj.ReadFloat(30f); float num = obj.ReadFloat(2.5f); float sensitivity = obj.ReadFloat(2.5f); float mouseSetting = GetMouseSetting(); float controllerSetting = GetControllerSetting(); if (needStoreOldSettings) { oldMouseSens = mouseSetting; oldConstrollerSens = controllerSetting; needStoreOldSettings = false; } GameSettings.All.Controls.Mouse.sensitivity = num; GameSettings.All.Controls.Controller.sensitivity = sensitivity; TimerTaskData val = new TimerTaskData { id = Id, durationInSec = durationInSec, finishAction = delegate { IsActive = false; GameSettings.All.Controls.Mouse.sensitivity = oldMouseSens; GameSettings.All.Controls.Controller.sensitivity = oldConstrollerSens; needStoreOldSettings = true; } }; if (lastMouseCommandSens != num) { if (IsActive) { ((HelperLog)Utils.logger).LogInfo((object)"ChangeMouseSens reset timer"); } ServiceProvider.inst.scheduleManager.NewTimerTask(val, false); } else { ServiceProvider.inst.scheduleManager.AppendTimerTask(val, true); } IsActive = true; lastMouseCommandSens = num; return true; } private float GetMouseSetting() { return GameSettings.All.Controls.Mouse.sensitivity; } private float GetControllerSetting() { return GameSettings.All.Controls.Controller.sensitivity; } public void ForceEnd() { ServiceProvider.inst.scheduleManager.FinishImmediatlyTimerTask(Id); } public bool IsValidCommandArgs(IEnumerable<string> args) { throw new NotImplementedException(); } } internal class MouseInvertY : MouseInvertBase { public override string Id => "mouse_invert_y"; protected override void SetInverted(bool invert) { GameSettings.All.Controls.Mouse.invertY = invert; } protected override bool GetInvertSetting() { return GameSettings.All.Controls.Mouse.invertY; } } internal class MouseInvertX : MouseInvertBase { public override string Id => "mouse_invert_x"; protected override void SetInverted(bool invert) { GameSettings.All.Controls.Mouse.invertX = invert; } protected override bool GetInvertSetting() { return GameSettings.All.Controls.Mouse.invertX; } } internal class ShufflePlayerMovement : IInternalStandaloneCommand, IConsoleCommand, IForceEnd { public string Id => "shuffle_player_movement"; public bool IsActive { get; private set; } public bool Execute(IEnumerable<string> args) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Expected O, but got Unknown float durationInSec = ArgsReaderFactory.NewReader(args).ReadFloat(30f); ServiceProvider.inst.scheduleManager.AppendTimerTask(new TimerTaskData { id = Id, durationInSec = durationInSec, finishAction = delegate { IsActive = false; RestoreInput(); ((HelperLog)Utils.logger).LogInfo((object)(Id + " ends")); } }, false); if (ShuffleBinds()) { IsActive = true; return true; } return false; } private bool ShuffleBinds() { //IL_0005: 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) GameplayActions gameplay = PlayerInput.Controls.Gameplay; InputAction move = ((GameplayActions)(ref gameplay)).Move; SwapBinds(move, 1, 2); SwapBinds(move, 3, 4); SwapBinds(move, 6, 7); SwapBinds(move, 8, 9); return true; } private void SwapBinds(InputAction action, int bindIndex1, int bindIndex2) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) ReadOnlyArray<InputBinding> bindings = action.bindings; if (bindIndex1 >= bindings.Count || bindIndex2 >= bindings.Count) { ((HelperLog)Utils.logger).LogWarning((object)$"rebind wrong indexes {bindIndex1}, {bindIndex2} of {bindings.Count}"); return; } InputBinding val = bindings[bindIndex1]; InputBinding val2 = bindings[bindIndex2]; ((HelperLog)Utils.logger).LogInfo((object)("rebind " + ((InputBinding)(ref val)).name + " from " + ((InputBinding)(ref val)).path + " to " + ((InputBinding)(ref val2)).path)); ((HelperLog)Utils.logger).LogInfo((object)("rebind " + ((InputBinding)(ref val2)).name + " from " + ((InputBinding)(ref val2)).path + " to " + ((InputBinding)(ref val)).path)); ((InputBinding)(ref val)).overridePath = ((InputBinding)(ref val2)).path; ((InputBinding)(ref val2)).overridePath = ((InputBinding)(ref val)).path; InputActionRebindingExtensions.ApplyBindingOverride(action, bindIndex1, val); InputActionRebindingExtensions.ApplyBindingOverride(action, bindIndex2, val2); } private void RestoreInput() { //IL_0005: 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_002b: 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_0064: Unknown result type (might be due to invalid IL or missing references) GameplayActions gameplay = PlayerInput.Controls.Gameplay; InputAction move = ((GameplayActions)(ref gameplay)).Move; ReadOnlyArray<InputBinding> bindings = move.bindings; int count = bindings.Count; for (int i = 0; i < count; i++) { InputBinding val = bindings[i]; ((InputBinding)(ref val)).overridePath = null; ((HelperLog)Utils.logger).LogInfo((object)("reset bind " + ((InputBinding)(ref val)).name + " to " + ((InputBinding)(ref val)).path)); InputActionRebindingExtensions.ApplyBindingOverride(move, i, val); } } public void ForceEnd() { ServiceProvider.inst.scheduleManager.FinishImmediatlyTimerTask(Id); } public bool IsValidCommandArgs(IEnumerable<string> args) { throw new NotImplementedException(); } } internal class TeleportToRandomPlayer : IInternalStandaloneCommand, IConsoleCommand, IHostNetworkCommand, INetworkApplyOnce { private const float DELAY = 0.5f; private DateTime lastTriggerTime = DateTime.MinValue; private bool teleportEnds = true; public string Id => "teleport_to_random_player"; public bool Execute(IEnumerable<string> args) { GameUtils.GetCurrentPlayer().ExitGolfCart((GolfCartExitType)0); if (!GameUtils.IsHost()) { return true; } return ExecuteHostAction(args, GameUtils.GetCurrentPlayer()); } public bool ExecuteHostAction(IEnumerable<string> args, PlayerInfo originalPlayer) { //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Expected O, but got Unknown if (!teleportEnds && (DateTime.Now - lastTriggerTime).TotalSeconds < 1.5) { ((HelperLog)Utils.logger).LogWarning((object)(Id + " spams too much. Old teleport is not finished")); return true; } teleportEnds = false; lastTriggerTime = DateTime.Now; ServiceProvider.inst.scheduleManager.NewTimerTask(new TimerTaskData { id = Id, durationInSec = 0.5f, finishAction = delegate { //IL_0052: 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_0087: Unknown result type (might be due to invalid IL or missing references) //IL_009e: 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_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) try { PlayerInfo[] teleportTargets = GetTeleportTargets(originalPlayer); if (teleportTargets == null) { ((HelperLog)Utils.logger).LogWarning((object)(Id + " can't apply teleport, other players doesn't found")); } else { PlayerInfo randomItemFromList = RandomUtils.GetRandomItemFromList<PlayerInfo>((IList<PlayerInfo>)teleportTargets); string playerName = GameUtils.GetPlayerName(randomItemFromList); Vector3 position = originalPlayer.Movement.Position; ((HelperLog)Utils.logger).LogInfo((object)$"{Id} found otherPlayers {teleportTargets.Length}, target {playerName}, base pos {position}"); Vector3 pos = randomItemFromList.Movement.Position + Vector3.up * 1.5f; ((HelperLog)Utils.logger).LogInfo((object)$"selected pos {pos}"); GameUtils.TeleportPlayer(originalPlayer, in pos); } } finally { teleportEnds = true; } } }, false); return true; } private PlayerInfo[] GetTeleportTargets(PlayerInfo originalPlayer) { try { List<PlayerInfo> list = GameUtils.Players.ToList(); list.Add(GameUtils.GetCurrentPlayer()); PlayerInfo[] array = list.Where((PlayerInfo p) => (Object)(object)p != (Object)(object)originalPlayer).ToArray(); if (array.Length == 0) { return null; } return array; } catch (Exception arg) { ((HelperLog)Utils.logger).LogError((object)$"{Id} GetTeleportTargets can't apply teleport, error: {arg}"); return null; } } public bool ShouldTriggerClientSideForOthers() { return false; } public bool IsValidCommandArgs(IEnumerable<string> args) { throw new NotImplementedException(); } } internal class TeleportShufflePlayers : IInternalStandaloneCommand, IConsoleCommand, IHostNetworkCommand, INetworkApplyOnce { public string Id => "teleport_shuffle_players"; public bool Execute(IEnumerable<string> args) { GameUtils.GetCurrentPlayer().ExitGolfCart((GolfCartExitType)0); if (!GameUtils.IsHost()) { return true; } return ExecuteHostAction(args, null); } public bool ExecuteHostAction(IEnumerable<string> args, PlayerInfo targetCharacter) { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Expected O, but got Unknown if (ServiceProvider.inst.scheduleManager.IsTaskExists(Id)) { ((HelperLog)Utils.logger).LogWarning((object)(Id + " spams too much. Old teleport is not finished")); return true; } ServiceProvider.inst.scheduleManager.NewTimerTask(new TimerTaskData { id = Id, durationInSec = 1f, finishAction = delegate { //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) List<PlayerInfo> list = GameUtils.Players.ToList(); list.Add(GameUtils.GetCurrentPlayer()); if (list.Count <= 1) { ((HelperLog)Utils.logger).LogWarning((object)(Id + " can't apply teleport, other players doesn't found")); } else { List<Vector3> list2 = RandomUtils.ShuffleForceRandom<Vector3>(list.Select((PlayerInfo p) => p.Movement.Position)); ((HelperLog)Utils.logger).LogInfo((object)$"{Id} found {list.Count} players and {list2.Count} positions"); if (list2.Count != list.Count) { ((HelperLog)Utils.logger).LogError((object)(Id + " wrong arr sizes")); } else { for (int i = 0; i < list.Count; i++) { PlayerInfo p2 = list[i]; Vector3 pos = list2[i]; GameUtils.TeleportPlayer(p2, in pos); } } } } }, false); return true; } public bool ShouldTriggerClientSideForOthers() { return true; } public bool IsValidCommandArgs(IEnumerable<string> args) { throw new NotImplementedException(); } } } namespace bft_mod.Commands.Base { internal abstract class MouseInvertBase : IInternalStandaloneCommand, IConsoleCommand, IForceEnd { protected bool oldState; protected bool needStoreOldSettings = true; public abstract string Id { get; } public bool IsActive { get; private set; } public bool Execute(IEnumerable<string> args) { //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0053: 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_0066: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Expected O, but got Unknown float durationInSec = ArgsReaderFactory.NewReader(args).ReadFloat(30f); bool invertSetting = GetInvertSetting(); if (needStoreOldSettings) { oldState = invertSetting; needStoreOldSettings = false; } SetInverted(!oldState); IsActive = true; ServiceProvider.inst.scheduleManager.AppendTimerTask(new TimerTaskData { id = Id, durationInSec = durationInSec, finishAction = delegate { IsActive = false; SetInverted(oldState); needStoreOldSettings = true; } }, true); return true; } protected abstract void SetInverted(bool invert); protected abstract bool GetInvertSetting(); public void ForceEnd() { ServiceProvider.inst.scheduleManager.FinishImmediatlyTimerTask(Id); } public bool IsValidCommandArgs(IEnumerable<string> args) { throw new NotImplementedException(); } } } namespace bft_mod.Commands.Interfaces { public interface INetworkApplyOnce { bool ShouldTriggerClientSideForOthers(); } public interface IHostNetworkCommand : IConsoleCommand { bool ExecuteHostAction(IEnumerable<string> args, PlayerInfo targetPlayer); } public interface IInternalStandaloneCommand : IConsoleCommand { } public interface IInternalStandaloneCommandWithData : IInternalStandaloneCommand, IConsoleCommand, IConsoleCommandWithData { } public interface IForceEnd : IInternalStandaloneCommand, IConsoleCommand { bool IsActive { get; } void ForceEnd(); } }
ChaosTricks_SBG_plugins/ModHelper.dll
Decompiled a day 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.Runtime.Versioning; 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: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [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) { return !args.MoveNext(); } return true; } 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 periodInSec; internal float periodCalculatedInSec; public int triggerTimes; public bool isInfiniteRepeates = true; public Action periodicAction; public Action finishAction; public override string ToString() { return "id=" + id + ", " + $"period={periodInSec}s, " + $"calc_period={periodCalculatedInSec}s, " + $"triggerTimes={triggerTimes}, " + $"isInfiniteRepeates={isInfiniteRepeates}"; } } public class TimerTaskData { public string id; public float durationInSec; public Action finishAction; public override string ToString() { return $"id={id}, duration={durationInSec}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) { if (queue.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; if (queue.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 : IJsonUtils { 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) { if (c != '"') { return c; } 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.GetGenericArguments()[0] : resultType.GetElementType()); 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 && 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 (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, int onUpdateErrorLimit = 0) { this.logger = logger; this.onUpdateErrorLimit = onUpdateErrorLimit; } 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.periodCalculatedInSec = task.periodInSec; 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.durationInSec += timerTaskData.durationInSec; 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 dtInSec) { List<TimerTaskData> list2 = new List<TimerTaskData>(); foreach (TimerTaskData item in list) { item.durationInSec -= dtInSec; if (item.durationInSec <= 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 dtInSec) { List<PeriodicTaskData> list2 = new List<PeriodicTaskData>(); foreach (PeriodicTaskData item in list) { item.periodCalculatedInSec -= dtInSec; if (!(item.periodCalculatedInSec <= 0f)) { continue; } if (item.isInfiniteRepeates || item.triggerTimes > 0) { SafeRunAction(item.periodicAction); item.periodCalculatedInSec = item.periodInSec; 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 dtInSec) { try { foreach (TimerTaskData item in ProcessTimersList(timerTasks.Values, dtInSec)) { timerTasks.Remove(item.id); logger?.LogInfo($"ScheduleManager OnUpdate finished timer task {item}"); } foreach (PeriodicTaskData item2 in ProcessPeriodicList(periodicTasks.Values, dtInSec)) { periodicTasks.Remove(item2.id); logger?.LogInfo($"ScheduleManager OnUpdate finished periodic task {item2}"); } foreach (TimerTaskData item3 in ProcessTimersList(timerTasksNoId, dtInSec)) { timerTasksNoId.Remove(item3); logger?.LogInfo($"ScheduleManager OnUpdate finished timer no id task {item3}"); } foreach (PeriodicTaskData item4 in ProcessPeriodicList(periodicTasksNoId, dtInSec)) { 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 float GetTimerTaskDurationInSec(string id) { if (!timerTasks.ContainsKey(id)) { return -1f; } return timerTasks[id].durationInSec; } 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 CommandConsole { 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 CommandConsole(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 array[0]; } return ""; } 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; private readonly IEnumerator<string> args; public CommandArgsReader(IEnumerable<string> argsSource, ILogger logger) { args = argsSource.GetEnumerator(); this.logger = logger; } public int ReadInt(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(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(string defaultValue = "") { if (args != null && args.MoveNext()) { return args.Current; } return defaultValue; } public bool ReadBool(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 string ReadSpacedString(string defaultValue = "") { return ParseItemPath(ReadString(defaultValue)); } public string ReadAllAsSingleString(string separator = " ", string defaultValue = "") { if (args == null) { return defaultValue; } StringBuilder stringBuilder = new StringBuilder(); bool flag = true; while (args.MoveNext()) { if (!flag && !string.IsNullOrEmpty(separator)) { stringBuilder.Append(separator); } flag = false; stringBuilder.Append(args.Current); } string text = stringBuilder.ToString(); if (!string.IsNullOrEmpty(text)) { return text; } return defaultValue; } public string[] ParseList(string s, string separator = "|") { if (string.IsNullOrEmpty(s)) { return null; } return (from item in s.Split(new string[1] { separator }, StringSplitOptions.None) select item.Trim() into item where !string.IsNullOrWhiteSpace(item) select item).ToArray(); } public static string ParseItemPath(string path) { return path?.Replace("_", " "); } } public static class RandomUtils { private static readonly Random rnd = new Random(Guid.NewGuid().GetHashCode()); public static T GetRandomItemFromList<T>(IList<T> list) { if (list != null && list.Count > 0) { return list[rnd.Next(list.Count)]; } return default(T); } public static List<T> Shuffle<T>(IEnumerable<T> list) { if (list == null) { return new List<T>(); } int num = list.Count(); if (num <= 1) { return new List<T>(list); } List<T> list2 = new List<T>(list); for (int i = 0; i < num; i++) { T value = list2[i]; int index = rnd.Next(num); list2[i] = list2[index]; list2[index] = value; } return list2; } public static List<T> ShuffleForceRandom<T>(IEnumerable<T> list) { if (list == null) { return new List<T>(); } int num = list.Count(); if (num <= 1) { return new List<T>(list); } T[] array = new T[num]; T[] array2 = list.ToArray(); List<int> list2 = new List<int>(Enumerable.Range(0, num)); for (int i = 0; i < num; i++) { List<int> list3 = new List<int>(list2); list3.Remove(i); if (list3.Count == 0) { break; } int num2 = list3[rnd.Next(list3.Count)]; array[i] = array2[num2]; list2.Remove(num2); } if (list2.Count == 1) { int num3 = num - 1; int num4 = rnd.Next(num3); array[num3] = array[num4]; array[num4] = array2[num3]; } return array.ToList(); } } 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 = JsonUtils.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 = JsonUtils.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) { if (cmd.Length > logCommandMaxLength) { return cmd.Substring(0, logCommandMaxLength) + "..."; } return cmd; } return cmd; } public virtual string GetCommandData(string eventKey, bool isLogError = false) { if (commandsDict == null) { logger?.LogWarning("HelperCommandManagerFormatted GetCommandData: commandsDict null"); return ""; } try { eventKey = eventKey.Trim(); string text = commandsDict[eventKey]; if (text != null) { return text; } 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(); string text = commandsDict[eventKey]; if (text != null) { return text; } 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 new List<CustomEvent>(); } return eventsDict.Values; } public CustomEvent GetEvent(string eventID, bool isLogError = false) { try { eventID = eventID.Trim(); CustomEvent val = eventsDict[eventID]; if (val != null) { return val; } 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 = JsonUtils.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 = JsonUtils.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 ClearLog(Action<string> onError) { if (path == null) { return; } try { using (new StreamWriter(path)) { } } catch (Exception arg) { onError?.Invoke($"ClearLog error: {arg}"); } } public virtual void ClearLogBySize(int fileSizeInBytes, Action<string> onError) { try { FileInfo fileInfo = new FileInfo(path); if (fileInfo.Exists && fileInfo.Length > fileSizeInBytes) { ClearLog(onError); } } catch (Exception arg) { onError?.Invoke($"ClearLogBySize error: {arg}"); } } } 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 fields[0].FieldType; } return type; } public bool TryParseEnum<TEnum>(string arg, out TEnum result, TEnum defaultValue = default(TEnum)) { Type typeFromHandle = typeof(TEnum); try { Type enumUnderlyingType = GetEnumUnderlyingType(typeFromHandle); if (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 (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 JsonUtils { private static Func<IJsonUtils> customGenerator; public static IJsonUtils Generate(IDebugLogger logger) { if (customGenerator == null) { return new HelperJson(logger, File.Exists(".mod_json_debug")); } return customGenerator(); } public static void RegisterCustomGenerator(Func<IJsonUtils> generator) { customGenerator = generator; } } public class SettingsUtils { 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 = JsonUtils.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) { default: return Languages.en; case "ru": case "russian": case "rus": case "русский": case "ру": case "рус": return Languages.ru; } } } 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.Wrappers { public class LimitedLogWrapper : IDebugLogger, ILoggerWithConsole, ILogger { private readonly IDebugLogger logger; private int messagesLimit; public LimitedLogWrapper(int messagesLimit, IDebugLogger logger) { this.logger = logger; this.messagesLimit = messagesLimit; } public void Log(object obj) { if (messagesLimit > 0) { messagesLimit--; logger.Log(obj); } } public void LogDebugInfo(object obj) { if (messagesLimit > 0) { messagesLimit--; logger.LogDebugInfo(obj); } } public void LogDebugWarning(object obj) { if (messagesLimit > 0) { messagesLimit--; logger.LogDebugWarning(obj); } } public void LogDebugError(object obj) { if (messagesLimit > 0) { messagesLimit--; logger.LogDebugError(obj); } } public void LogInfo(object obj) { if (messagesLimit > 0) { messagesLimit--; logger.LogInfo(obj); } } public void LogInfoConsoleOnly(object obj) { if (messagesLimit > 0) { messagesLimit--; logger.LogInfoConsoleOnly(obj); } } public void LogInfoFileOnly(object obj) { if (messagesLimit > 0) { messagesLimit--; logger.LogInfoFileOnly(obj); } } public void LogWarning(object obj) { if (messagesLimit > 0) { messagesLimit--; logger.LogWarning(obj); } } public void LogWarningConsoleOnly(object obj) { if (messagesLimit > 0) { messagesLimit--; logger.LogWarningConsoleOnly(obj); } } public void LogWarningFileOnly(object obj) { if (messagesLimit > 0) { messagesLimit--; logger.LogWarningFileOnly(obj); } } public void LogError(object obj) { if (messagesLimit > 0) { messagesLimit--; logger.LogError(obj); } } public void LogErrorConsoleOnly(object obj) { if (messagesLimit > 0) { messagesLimit--; logger.LogErrorConsoleOnly(obj); } } public void LogErrorFileOnly(object obj) { if (messagesLimit > 0) { messagesLimit--; logger.LogErrorFileOnly(obj); } } public void UpdateLimit(int limit) { messagesLimit = limit; } public void ClearLog(Action<string> onError) { logger.ClearLog(onError); } public void ClearLogBySize(int fileSizeInBytes, Action<string> onError) { logger.ClearLogBySize(fileSizeInBytes, onError); } } } 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 IJsonUtils { 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 ClearLog(Action<string> onError); void ClearLogBySize(int fileSizeInBytes, Action<string> onError); } 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_SBG_plugins/ModHelperUnity.dll
Decompiled a day agousing System; using System.Collections; 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.Runtime.Versioning; 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.Utilities; 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: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] namespace ModHelperUnity.Utilities { public static class CoroutineUtils { [CompilerGenerated] private sealed class <ActionCoroutine>d__1 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public float delayInSec; public Action action; public Action<string> log; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <ActionCoroutine>d__1(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; if (delayInSec == 0f) { <>2__current = null; <>1__state = 1; return true; } <>2__current = (object)new WaitForSeconds(delayInSec); <>1__state = 2; return true; case 1: <>1__state = -1; break; case 2: <>1__state = -1; break; } try { action(); } catch (Exception arg) { log?.Invoke($"ActionCoroutine for {delayInSec} error: {arg}"); } return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <ActionCoroutineInFrames>d__3 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public int delayInFrames; public Action action; public Action<string> log; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <ActionCoroutineInFrames>d__3(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { switch (<>1__state) { default: return false; case 0: <>1__state = -1; break; case 1: <>1__state = -1; break; } if (delayInFrames > 0) { int num = delayInFrames - 1; delayInFrames = num; <>2__current = null; <>1__state = 1; return true; } try { action(); } catch (Exception arg) { log?.Invoke($"ActionCoroutineInFrames for {delayInFrames} error: {arg}"); } return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <WhileCoroutine>d__5 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public float repeatDelayInSec; public Func<bool> action; public Action<string> log; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <WhileCoroutine>d__5(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Expected O, but got Unknown int num = <>1__state; if (num != 0) { if (num != 1) { return false; } <>1__state = -1; bool flag; try { flag = action(); } catch (Exception arg) { log?.Invoke($"ActionCoroutine for {repeatDelayInSec} error: {arg}"); flag = false; } if (!flag) { return false; } } else { <>1__state = -1; } <>2__current = (object)new WaitForSeconds(repeatDelayInSec); <>1__state = 1; return true; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } public static void StartCoroutine(MonoBehaviour script, float delayInSec, Action action, Action<string> log = null) { if ((Object)(object)script == (Object)null) { return; } if (action == null) { log?.Invoke("StartCoroutine got null action"); return; } if (delayInSec < 0f) { delayInSec = 0f; log?.Invoke($"StartCoroutine got invalid delay {delayInSec}"); } script.StartCoroutine(ActionCoroutine(delayInSec, action)); } [IteratorStateMachine(typeof(<ActionCoroutine>d__1))] private static IEnumerator ActionCoroutine(float delayInSec, Action action, Action<string> log = null) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <ActionCoroutine>d__1(0) { delayInSec = delayInSec, action = action, log = log }; } public static void StartCoroutineInFrames(MonoBehaviour script, int delayInFrames, Action action, Action<string> log = null) { if ((Object)(object)script == (Object)null) { return; } if (action == null) { log?.Invoke("StartCoroutineInFrames got null action"); return; } if (delayInFrames <= 0) { log?.Invoke($"StartCoroutineInFrames got invalid delay in frames {delayInFrames}. Replaced to 1."); delayInFrames = 1; } script.StartCoroutine(ActionCoroutineInFrames(delayInFrames, action)); } [IteratorStateMachine(typeof(<ActionCoroutineInFrames>d__3))] private static IEnumerator ActionCoroutineInFrames(int delayInFrames, Action action, Action<string> log = null) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <ActionCoroutineInFrames>d__3(0) { delayInFrames = delayInFrames, action = action, log = log }; } public static void StartCoroutineWhile(MonoBehaviour script, float repeatDelayInSec, Func<bool> action, Action<string> log = null) { if ((Object)(object)script == (Object)null) { return; } if (action == null) { log?.Invoke("StartCoroutine got null action"); return; } if (repeatDelayInSec < 0f) { repeatDelayInSec = 0f; log?.Invoke($"StartCoroutine got invalid delay {repeatDelayInSec}"); } script.StartCoroutine(WhileCoroutine(repeatDelayInSec, action)); } [IteratorStateMachine(typeof(<WhileCoroutine>d__5))] private static IEnumerator WhileCoroutine(float repeatDelayInSec, Func<bool> action, Action<string> log = null) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <WhileCoroutine>d__5(0) { repeatDelayInSec = repeatDelayInSec, action = action, log = log }; } } public static class GameObjectUtils { public static T GetClosestObject<T>(Vector3 pos, Func<T, bool> filter, Action<string> log) where T : MonoBehaviour { //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0096: 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_00bc: 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_00c6: Unknown result type (might be due to invalid IL or missing references) T[] array = Object.FindObjectsOfType<T>(); int num = array.Length; log?.Invoke($"GetClosestObject found {num}"); if (num == 0) { return default(T); } if (filter != null) { array = array.Where(filter).ToArray(); num = array.Length; log?.Invoke($"GetClosestObject filtered size {num}"); } switch (num) { case 0: return default(T); case 1: return array[0]; default: { T val = array[0]; Vector3 val2 = pos - ((Component)(object)val).transform.position; float num2 = ((Vector3)(ref val2)).sqrMagnitude; for (int i = 1; i < num; i++) { T val3 = array[i]; val2 = pos - ((Component)(object)val3).transform.position; float sqrMagnitude = ((Vector3)(ref val2)).sqrMagnitude; if (sqrMagnitude < num2) { val = val3; num2 = sqrMagnitude; } } return val; } } } public static void DebugFindAndPrintAllObjects<T>(Action<string> log) where T : MonoBehaviour { T[] array = Resources.FindObjectsOfTypeAll<T>(); StringBuilder stringBuilder = new StringBuilder("--- Found object list (names) ---\n"); T[] array2 = array; foreach (T val in array2) { stringBuilder.AppendLine(((Object)(object)val).name ?? ""); } log?.Invoke(stringBuilder.ToString()); } public static void DebugLoadAndPrintAllObjects<T>(string resourcePath, bool replaceSpaces, Action<string> log) where T : MonoBehaviour { T[] array = Resources.LoadAll<T>(resourcePath); StringBuilder stringBuilder = new StringBuilder("\n--- Loaded object list (path) ---\n"); T[] array2 = array; foreach (T val in array2) { string value = (replaceSpaces ? ((Object)(object)val).name.Replace(" ", "_") : ((Object)(object)val).name); stringBuilder.AppendLine(value); } log?.Invoke(stringBuilder.ToString()); } } public static class HelperUI { 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 UnityMathUtils { public static bool GetRandomBool() { return Random.value > 0.5f; } public static int GetRandomSign() { if (!GetRandomBool()) { 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); } } } namespace ModHelperUnity.Interfaces { public interface IComponentTypedNotify { void AddNotifyToQueue(string message, string type); void AddNotifyToQueue(IEventsData eventData, ITranslation translation, Func<string, string> converter = null, bool applyUpperCase = true); 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); void RegisterPostProcessEvent(string key, IPostProcessText e); } public interface IPostProcessText { string PostProcessText(string text, string langKey); } public interface ISoundManager { void PlaySound(string path, int volume = 50); void StopSound(); } public interface IDictionaryItemJson<T> { string Key { get; } T Value { get; } } } namespace ModHelperUnity.TypedNotify { 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>(); protected readonly Dictionary<string, IPostProcessText> postProcessEvents = new Dictionary<string, IPostProcessText>(); 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_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Expected O, but got Unknown if (!messageTextures.ContainsKey(type)) { return new Texture2D(2, 2); } return messageTextures[type]; } protected void LoadFadeSettings(string settingsFilePath, Func<string, byte[]> customFileReader = null) { try { if (customFileReader == null) { Settings = JsonUtils.Generate(logger).FromFile<TypedNotifySettings>(settingsFilePath); } else { byte[] bytes = customFileReader(settingsFilePath); string @string = Encoding.UTF8.GetString(bytes); Settings = JsonUtils.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 = HelperUI.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%", HelperUI.GetColoredText(eventData.Username, typedNotifyParameters.nicknameTextColor)).Replace("%message%", HelperUI.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, bool applyUpperCase = true) { 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); } text = PostProcessEvent(text, eventData.EventID, eventData.Lang); AddNotifyToQueue(new TypedNotifyMessage(applyUpperCase ? text.ToUpperInvariant() : text, 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 void RegisterPostProcessEvent(string key, IPostProcessText e) { if (string.IsNullOrEmpty(key) || e == null) { IDebugLogger obj = logger; if (obj != null) { ((ILogger)obj).LogError((object)("TypedNotifyOnGUI RegisterPostProcessEvent invalid arg error for key '" + key + "'")); } } else { postProcessEvents[key] = e; } } protected string PostProcessEvent(string text, string eventKey, string langKey) { if (string.IsNullOrEmpty(eventKey) || text == null) { IDebugLogger obj = logger; if (obj != null) { ((ILogger)obj).LogWarning((object)("TypedNotifyOnGUI PostProcessEvent invalid arg error for key '" + eventKey + "', text " + text)); } return text; } if (!postProcessEvents.TryGetValue(eventKey, out var value)) { return text; } return value.PostProcessText(text, langKey); } } 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)$"TypedNotifyOnGUI 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 = HelperUI.CalcScreenFactor(HelperUI.StandardScreenWidth, Screen.width); float num2 = HelperUI.CalcScreenFactor(HelperUI.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.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 durationInSec; public NotifyMessage(string msg, float durationInSec) { this.msg = (string.IsNullOrEmpty(msg?.Trim()) ? string.Empty : msg); this.durationInSec = durationInSec; } public string GetMessage() { return msg; } public bool IsFinished() { return durationInSec <= 0f; } public void OnFrame(float dtInSec) { if (!IsFinished()) { durationInSec -= dtInSec; } } } }
ChaosTricks_SBG_plugins/websocket-sharp.dll
Decompiled a day 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.Linq; 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.Runtime.Versioning; 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; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("websocket-sharp")] [assembly: AssemblyDescription("A C# implementation of the WebSocket protocol client and server")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("websocket-sharp.dll")] [assembly: AssemblyCopyright("sta.blockhead")] [assembly: AssemblyTrademark("")] [assembly: TargetFramework(".NETFramework,Version=v4.6", FrameworkDisplayName = ".NET Framework 4.6")] [assembly: AssemblyVersion("1.0.2.18559")] namespace WebSocketSharp { public static class Ext { private static readonly byte[] _last = new byte[1]; private static readonly int _retry = 5; private const string _tspecials = "()<>@,;:\\\"/[]?={} \t"; 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); stream.CopyTo(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 deflateStream = new DeflateStream(stream, CompressionMode.Decompress, leaveOpen: true); deflateStream.CopyTo(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 bool isHttpMethod(this string value) { int result; switch (value) { default: result = ((value == "TRACE") ? 1 : 0); break; case "GET": case "HEAD": case "POST": case "PUT": case "DELETE": case "CONNECT": case "OPTIONS": result = 1; break; } return (byte)result != 0; } private static bool isHttpMethod10(this string value) { return value == "GET" || value == "HEAD" || value == "POST"; } internal static byte[] Append(this ushort code, string reason) { byte[] array = code.InternalToByteArray(ByteOrder.Big); if (reason == null || reason.Length == 0) { return array; } List<byte> list = new List<byte>(array); list.AddRange(Encoding.UTF8.GetBytes(reason)); return list.ToArray(); } 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(this string value, params char[] anyOf) { return anyOf != null && anyOf.Length != 0 && value.IndexOfAny(anyOf) > -1; } internal static bool Contains(this NameValueCollection collection, string name) { return collection[name] != null; } internal static bool Contains(this NameValueCollection collection, string name, string value, StringComparison comparisonTypeForValue) { 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, comparisonTypeForValue)) { return true; } } return false; } 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; int end = len - 1; Func<int, bool> seek = null; seek = delegate(int idx) { if (idx == end) { return false; } string text = values[idx]; for (int i = idx + 1; i < len; i++) { if (values[i] == text) { return true; } } return seek(++idx); }; return seek(0); } internal static T[] Copy<T>(this T[] source, int length) { T[] array = new T[length]; Array.Copy(source, 0, array, 0, length); return array; } 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 (true) { num = source.Read(buffer, 0, bufferLength); if (num <= 0) { break; } 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 void Emit(this EventHandler eventHandler, object sender, EventArgs e) { eventHandler?.Invoke(sender, e); } internal static void Emit<TEventArgs>(this EventHandler<TEventArgs> eventHandler, object sender, TEventArgs e) where TEventArgs : EventArgs { eventHandler?.Invoke(sender, e); } 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 WebSocketSharp.Net.CookieCollection GetCookies(this NameValueCollection headers, bool response) { string text = headers[response ? "Set-Cookie" : "Cookie"]; return (text != null) ? WebSocketSharp.Net.CookieCollection.Parse(text, response) : new WebSocketSharp.Net.CookieCollection(); } internal static string GetDnsSafeHost(this Uri uri, bool bracketIPv6) { return (bracketIPv6 && uri.HostNameType == UriHostNameType.IPv6) ? uri.Host : uri.DnsSafeHost; } 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 GetUTF8DecodedString(this byte[] bytes) { return Encoding.UTF8.GetString(bytes); } internal static byte[] GetUTF8EncodedBytes(this string s) { return Encoding.UTF8.GetBytes(s); } internal static string GetValue(this string nameAndValue, char separator) { return nameAndValue.GetValue(separator, unquote: false); } 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 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 IsHttpMethod(this string value, Version version) { return (version == WebSocketSharp.Net.HttpVersion.Version10) ? value.isHttpMethod10() : value.isHttpMethod(); } 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 < ' ') { if ("\r\n\t".IndexOf(c) == -1) { return false; } if (c == '\n') { i++; if (i == length) { break; } c = value[i]; if (" \t".IndexOf(c) == -1) { return false; } } } else if (c == '\u007f') { return false; } } return true; } internal static bool IsToken(this string value) { foreach (char c in value) { if (c < ' ') { return false; } if (c > '~') { return false; } if ("()<>@,;:\\\"/[]?={} \t".IndexOf(c) > -1) { return false; } } return true; } internal static bool KeepsAlive(this NameValueCollection headers, Version version) { StringComparison comparisonTypeForValue = StringComparison.OrdinalIgnoreCase; return (version < WebSocketSharp.Net.HttpVersion.Version11) ? headers.Contains("Connection", "keep-alive", comparisonTypeForValue) : (!headers.Contains("Connection", "close", comparisonTypeForValue)); } 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; int num2 = 0; int num3 = 0; while (length > 0) { num3 = stream.Read(array, num, length); if (num3 <= 0) { if (num2 >= _retry) { return array.SubArray(0, num); } num2++; } else { num2 = 0; num += num3; length -= num3; } } return array; } internal static byte[] ReadBytes(this Stream stream, long length, int bufferLength) { using MemoryStream memoryStream = new MemoryStream(); byte[] buffer = new byte[bufferLength]; int num = 0; int num2 = 0; while (length > 0) { if (length < bufferLength) { bufferLength = (int)length; } num2 = stream.Read(buffer, 0, bufferLength); if (num2 <= 0) { if (num >= _retry) { break; } num++; } else { num = 0; memoryStream.Write(buffer, 0, num2); length -= num2; } } 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) { if (retry < _retry) { retry++; stream.BeginRead(buff, offset, length, callback, null); } else if (completed != null) { completed(buff.SubArray(0, offset)); } } else if (num == length) { if (completed != null) { completed(buff); } } 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) { if (retry < _retry) { int num2 = retry; retry = num2 + 1; read(len); } else { if (completed != null) { dest.Close(); completed(dest.ToArray()); } dest.Dispose(); } } else { dest.Write(buff, 0, num); if (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 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; int end = len - 1; StringBuilder buff = new StringBuilder(32); bool escaped = false; bool quoted = false; for (int i = 0; i <= end; i++) { char c = value[i]; buff.Append(c); switch (c) { case '"': if (escaped) { escaped = false; } else { quoted = !quoted; } continue; case '\\': if (i == end) { break; } if (value[i + 1] == '"') { escaped = true; } continue; default: if (Array.IndexOf(separators, c) > -1 && !quoted) { buff.Length--; yield return buff.ToString(); buff.Length = 0; } continue; } break; } yield return buff.ToString(); } internal static byte[] ToByteArray(this Stream stream) { using MemoryStream memoryStream = new MemoryStream(); stream.Position = 0L; stream.CopyTo(memoryStream, 1024); memoryStream.Close(); return memoryStream.ToArray(); } internal static CompressionMethod ToCompressionMethod(this string value) { Array values = Enum.GetValues(typeof(CompressionMethod)); foreach (CompressionMethod item in values) { if (item.ToExtensionString() == value) { return item; } } 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()}"; return (parameters != null && parameters.Length != 0) ? string.Format("{0}; {1}", text, parameters.ToString("; ")) : text; } internal static IPAddress ToIPAddress(this string value) { if (value == null || value.Length == 0) { return null; } if (IPAddress.TryParse(value, out IPAddress address)) { return address; } try { IPAddress[] hostAddresses = Dns.GetHostAddresses(value); return hostAddresses[0]; } catch { return null; } } internal static List<TSource> ToList<TSource>(this IEnumerable<TSource> source) { return new List<TSource>(source); } internal static string ToString(this IPAddress address, bool bracketIPv6) { return (bracketIPv6 && address.AddressFamily == AddressFamily.InterNetworkV6) ? $"[{address.ToString()}]" : address.ToString(); } 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 IEnumerable<string> TrimEach(this IEnumerable<string> source) { foreach (string elm in source) { yield return elm.Trim(); } } internal static string TrimSlashFromEnd(this string value) { string text = value.TrimEnd(new char[1] { '/' }); return (text.Length > 0) ? text : "/"; } internal static string TrimSlashOrBackslashFromEnd(this string value) { string text = value.TrimEnd('/', '\\'); return (text.Length > 0) ? text : value[0].ToString(); } internal static bool TryCreateVersion(this string versionString, out Version result) { result = null; try { result = new Version(versionString); } catch { return false; } return true; } internal static bool TryCreateWebSocketUri(this string uriString, out Uri result, out string message) { result = null; message = null; Uri uri = uriString.ToUri(); if (uri == null) { message = "An invalid URI string."; return false; } if (!uri.IsAbsoluteUri) { message = "A relative URI."; return false; } string scheme = uri.Scheme; if (!(scheme == "ws") && !(scheme == "wss")) { message = "The scheme part is not 'ws' or 'wss'."; return false; } int port = uri.Port; if (port == 0) { message = "The port part is zero."; return false; } if (uri.Fragment.Length > 0) { message = "It includes the fragment component."; return false; } result = ((port != -1) ? uri : new Uri(string.Format("{0}://{1}:{2}{3}", scheme, uri.Host, (scheme == "ws") ? 80 : 443, uri.PathAndQuery))); return true; } internal static bool TryGetUTF8DecodedString(this byte[] bytes, out string s) { s = null; try { s = Encoding.UTF8.GetString(bytes); } catch { return false; } return true; } internal static bool TryGetUTF8EncodedBytes(this string s, out byte[] bytes) { bytes = null; try { bytes = Encoding.UTF8.GetBytes(s); } catch { return false; } return true; } internal static bool TryOpenRead(this FileInfo fileInfo, out FileStream fileStream) { fileStream = null; try { fileStream = fileInfo.OpenRead(); } catch { return false; } return true; } internal static string Unquote(this string value) { int num = value.IndexOf('"'); if (num == -1) { return value; } int num2 = value.LastIndexOf('"'); if (num2 == num) { return value; } int num3 = num2 - num - 1; return (num3 > 0) ? value.Substring(num + 1, num3).Replace("\\\"", "\"") : string.Empty; } internal static bool Upgrades(this NameValueCollection headers, string protocol) { StringComparison comparisonTypeForValue = StringComparison.OrdinalIgnoreCase; return headers.Contains("Upgrade", protocol, comparisonTypeForValue) && headers.Contains("Connection", "Upgrade", comparisonTypeForValue); } internal static string UrlDecode(this string value, Encoding encoding) { return HttpUtility.UrlDecode(value, encoding); } internal static string UrlEncode(this string value, Encoding encoding) { return HttpUtility.UrlEncode(value, encoding); } internal static void WriteBytes(this Stream stream, byte[] bytes, int bufferLength) { using MemoryStream memoryStream = new MemoryStream(bytes); memoryStream.CopyTo(stream, bufferLength); } internal static void WriteBytesAsync(this Stream stream, byte[] bytes, int bufferLength, Action completed, Action<Exception> error) { MemoryStream src = new MemoryStream(bytes); src.CopyToAsync(stream, bufferLength, delegate { if (completed != null) { completed(); } src.Dispose(); }, delegate(Exception ex) { src.Dispose(); if (error != null) { error(ex); } }); } 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) { if (value == null) { return false; } int length = value.Length; if (length < 2) { return false; } return value[0] == c && 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) { throw new ArgumentNullException("address"); } 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; } switch (value[0]) { case 'h': return value == "http" || value == "https"; case 'w': return value == "ws" || value == "wss"; case 'f': return value == "file" || value == "ftp"; case 'g': return value == "gopher"; case 'm': return value == "mailto"; case 'n': { char c = value[1]; return (c != 'e') ? (value == "nntp") : (value == "news" || value == "net.pipe" || value == "net.tcp"); } default: return false; } } public static bool MaybeUri(this string value) { if (value == null) { return false; } if (value.Length == 0) { return false; } int num = value.IndexOf(':'); if (num == -1) { return false; } if (num >= 10) { return false; } string value2 = value.Substring(0, num); return value2.IsPredefinedScheme(); } public static T[] SubArray<T>(this T[] array, int startIndex, int length) { if (array == null) { throw new ArgumentNullException("array"); } int num = array.Length; if (num == 0) { if (startIndex != 0) { throw new ArgumentOutOfRangeException("startIndex"); } if (length != 0) { throw new ArgumentOutOfRangeException("length"); } return array; } if (startIndex < 0 || startIndex >= num) { throw new ArgumentOutOfRangeException("startIndex"); } if (length < 0 || length > num - startIndex) { throw new ArgumentOutOfRangeException("length"); } if (length == 0) { return new T[0]; } if (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) { if (array == null) { throw new ArgumentNullException("array"); } long num = array.LongLength; if (num == 0) { if (startIndex != 0) { throw new ArgumentOutOfRangeException("startIndex"); } if (length != 0) { throw new ArgumentOutOfRangeException("length"); } return array; } if (startIndex < 0 || startIndex >= num) { throw new ArgumentOutOfRangeException("startIndex"); } if (length < 0 || length > num - startIndex) { throw new ArgumentOutOfRangeException("length"); } if (length == 0) { return new T[0]; } if (length == num) { 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) { for (int i = 0; i < n; i++) { action(); } } } public static void Times(this long n, Action action) { if (n > 0 && action != null) { for (long num = 0L; num < n; num++) { action(); } } } public static void Times(this uint n, Action action) { if (n != 0 && action != null) { for (uint num = 0u; num < n; num++) { action(); } } } public static void Times(this ulong n, Action action) { if (n != 0 && action != null) { for (ulong num = 0uL; num < n; num++) { 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); } } } [Obsolete("This method will be removed.")] 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 (typeFromHandle == typeof(bool)) ? ((T)(object)BitConverter.ToBoolean(value, 0)) : ((typeFromHandle == typeof(char)) ? ((T)(object)BitConverter.ToChar(value, 0)) : ((typeFromHandle == typeof(double)) ? ((T)(object)BitConverter.ToDouble(value, 0)) : ((typeFromHandle == typeof(short)) ? ((T)(object)BitConverter.ToInt16(value, 0)) : ((typeFromHandle == typeof(int)) ? ((T)(object)BitConverter.ToInt32(value, 0)) : ((typeFromHandle == typeof(long)) ? ((T)(object)BitConverter.ToInt64(value, 0)) : ((typeFromHandle == typeof(float)) ? ((T)(object)BitConverter.ToSingle(value, 0)) : ((typeFromHandle == typeof(ushort)) ? ((T)(object)BitConverter.ToUInt16(value, 0)) : ((typeFromHandle == typeof(uint)) ? ((T)(object)BitConverter.ToUInt32(value, 0)) : ((typeFromHandle == typeof(ulong)) ? ((T)(object)BitConverter.ToUInt64(value, 0)) : default(T)))))))))); } [Obsolete("This method will be removed.")] public static byte[] ToByteArray<T>(this T value, ByteOrder order) where T : struct { Type typeFromHandle = typeof(T); byte[] array = ((typeFromHandle == typeof(bool)) ? BitConverter.GetBytes((bool)(object)value) : ((!(typeFromHandle == typeof(byte))) ? ((typeFromHandle == typeof(char)) ? BitConverter.GetBytes((char)(object)value) : ((typeFromHandle == typeof(double)) ? BitConverter.GetBytes((double)(object)value) : ((typeFromHandle == typeof(short)) ? BitConverter.GetBytes((short)(object)value) : ((typeFromHandle == typeof(int)) ? BitConverter.GetBytes((int)(object)value) : ((typeFromHandle == typeof(long)) ? BitConverter.GetBytes((long)(object)value) : ((typeFromHandle == typeof(float)) ? BitConverter.GetBytes((float)(object)value) : ((typeFromHandle == typeof(ushort)) ? BitConverter.GetBytes((ushort)(object)value) : ((typeFromHandle == typeof(uint)) ? BitConverter.GetBytes((uint)(object)value) : ((typeFromHandle == typeof(ulong)) ? BitConverter.GetBytes((ulong)(object)value) : WebSocket.EmptyBytes))))))))) : new byte[1] { (byte)(object)value })); 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"); } if (source.Length < 2) { return source; } if (sourceOrder.IsHostOrder()) { return source; } return source.Reverse(); } 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 stringBuilder = new StringBuilder(64); int num2 = num - 1; for (int i = 0; i < num2; i++) { stringBuilder.AppendFormat("{0}{1}", array[i], separator); } stringBuilder.Append(array[num2].ToString()); return stringBuilder.ToString(); } public static Uri ToUri(this string value) { Uri.TryCreate(value, value.MaybeUri() ? UriKind.Absolute : UriKind.Relative, out Uri result); return result; } [Obsolete("This method will be removed.")] 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 num = content.LongLength; if (num == 0) { response.Close(); return; } response.ContentLength64 = num; Stream outputStream = response.OutputStream; if (num <= int.MaxValue) { outputStream.Write(content, 0, (int)num); } else { outputStream.WriteBytes(content, 1024); } outputStream.Close(); } } public class MessageEventArgs : EventArgs { private string _data; private bool _dataSet; private Opcode _opcode; private byte[] _rawData; internal Opcode Opcode => _opcode; public string Data { get { setData(); return _data; } } public bool IsBinary => _opcode == Opcode.Binary; public bool IsPing => _opcode == Opcode.Ping; public bool IsText => _opcode == Opcode.Text; public byte[] RawData { get { setData(); return _rawData; } } 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; } private void setData() { if (_dataSet) { return; } if (_opcode == Opcode.Binary) { _dataSet = true; return; } if (_rawData.TryGetUTF8DecodedString(out var s)) { _data = s; } _dataSet = true; } } public class CloseEventArgs : EventArgs { private bool _clean; private PayloadData _payloadData; public ushort Code => _payloadData.Code; public string Reason => _payloadData.Reason; public bool WasClean => _clean; internal CloseEventArgs(PayloadData payloadData, bool clean) { _payloadData = payloadData; _clean = clean; } internal CloseEventArgs(ushort code, string reason, bool clean) { _payloadData = new PayloadData(code, reason); _clean = clean; } } 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 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 string _extensions; private bool _extensionsRequested; private object _forMessageEventQueue; private object _forPing; private object _forSend; private object _forState; private MemoryStream _fragmentsBuffer; private bool _fragmentsCompressed; private Opcode _fragmentsOpcode; private const string _guid = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; private Func<WebSocketContext, string> _handshakeRequestChecker; private bool _ignoreExtensions; private bool _inContinuation; private volatile bool _inMessage; private volatile Logger _logger; private static readonly int _maxRetryCountForConnect; private Action<MessageEventArgs> _message; private Queue<MessageEventArgs> _messageEventQueue; private uint _nonceCount; private string _origin; private ManualResetEvent _pongReceived; 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 ManualResetEvent _receivingExited; private int _retryCountForConnect; private bool _secure; private ClientSslConfiguration _sslConfig; private Stream _stream; private TcpClient _tcpClient; private Uri _uri; private const string _version = "13"; 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 { string text = null; if (!_client) { text = "This instance is not a client."; throw new InvalidOperationException(text); } if (!canSet(out text)) { _logger.Warn(text); return; } lock (_forState) { if (!canSet(out text)) { _logger.Warn(text); } else { _compression = value; } } } } public IEnumerable<WebSocketSharp.Net.Cookie> Cookies { get { lock (_cookies.SyncRoot) { foreach (WebSocketSharp.Net.Cookie cookie in _cookies) { yield return cookie; } } } } public WebSocketSharp.Net.NetworkCredential Credentials => _credentials; public bool EmitOnPing { get { return _emitOnPing; } set { _emitOnPing = value; } } public bool EnableRedirection { get { return _enableRedirection; } set { string text = null; if (!_client) { text = "This instance is not a client."; throw new InvalidOperationException(text); } if (!canSet(out text)) { _logger.Warn(text); return; } lock (_forState) { if (!canSet(out text)) { _logger.Warn(text); } else { _enableRedirection = value; } } } } public string Extensions => _extensions ?? string.Empty; public bool IsAlive => ping(EmptyBytes); public bool IsSecure => _secure; public Logger Log { get { return _logger; } internal set { _logger = value; } } public string Origin { get { return _origin; } set { string text = null; if (!_client) { text = "This instance is not a client."; throw new InvalidOperationException(text); } if (!value.IsNullOrEmpty()) { if (!Uri.TryCreate(value, UriKind.Absolute, out Uri result)) { text = "Not an absolute URI string."; throw new ArgumentException(text, "value"); } if (result.Segments.Length > 1) { text = "It includes the path segments."; throw new ArgumentException(text, "value"); } } if (!canSet(out text)) { _logger.Warn(text); return; } lock (_forState) { if (!canSet(out text)) { _logger.Warn(text); return; } _origin = ((!value.IsNullOrEmpty()) ? value.TrimEnd(new char[1] { '/' }) : value); } } } public string Protocol { get { return _protocol ?? string.Empty; } internal set { _protocol = value; } } public WebSocketState ReadyState => _readyState; public ClientSslConfiguration SslConfiguration { get { if (!_client) { string text = "This instance is not a client."; throw new InvalidOperationException(text); } if (!_secure) { string text2 = "This instance does not use a secure connection."; throw new InvalidOperationException(text2); } return getSslConfiguration(); } } public Uri Url => _client ? _uri : _context.RequestUri; public TimeSpan WaitTime { get { return _waitTime; } set { if (value <= TimeSpan.Zero) { throw new ArgumentOutOfRangeException("value", "Zero or less."); } if (!canSet(out var text)) { _logger.Warn(text); return; } lock (_forState) { if (!canSet(out text)) { _logger.Warn(text); } else { _waitTime = value; } } } } public event EventHandler<CloseEventArgs> OnClose; public event EventHandler<ErrorEventArgs> OnError; public event EventHandler<MessageEventArgs> OnMessage; public event EventHandler OnOpen; static WebSocket() { _maxRetryCountForConnect = 10; 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) { if (!checkProtocols(protocols, out text)) { 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() { if (_readyState == WebSocketState.Open) { string text = "The handshake request has already been accepted."; _logger.Warn(text); return false; } lock (_forState) { if (_readyState == WebSocketState.Open) { string text2 = "The handshake request has already been accepted."; _logger.Warn(text2); return false; } if (_readyState == WebSocketState.Closing) { string text3 = "The close process has set in."; _logger.Error(text3); text3 = "An interruption has occurred while attempting to accept."; error(text3, null); return false; } if (_readyState == WebSocketState.Closed) { string text4 = "The connection has been closed."; _logger.Error(text4); text4 = "An interruption has occurred while attempting to accept."; error(text4, null); return false; } try { if (!acceptHandshake()) { return false; } } catch (Exception ex) { _logger.Fatal(ex.Message); _logger.Debug(ex.ToString()); string text5 = "An exception has occurred while attempting to accept."; fatal(text5, ex); return false; } _readyState = WebSocketState.Open; return true; } } private bool acceptHandshake() { _logger.Debug($"A handshake request from {_context.UserEndPoint}:\n{_context}"); if (!checkHandshakeRequest(_context, out var text)) { _logger.Error(text); refuseHandshake(CloseStatusCode.ProtocolError, "A handshake error has occurred while attempting to accept."); return false; } if (!customCheckHandshakeRequest(_context, out text)) { _logger.Error(text); refuseHandshake(CloseStatusCode.PolicyViolation, "A handshake error has occurred while attempting to accept."); return false; } _base64Key = _context.Headers["Sec-WebSocket-Key"]; if (_protocol != null) { IEnumerable<string> secWebSocketProtocols = _context.SecWebSocketProtocols; processSecWebSocketProtocolClientHeader(secWebSocketProtocols); } if (!_ignoreExtensions) { string value = _context.Headers["Sec-WebSocket-Extensions"]; processSecWebSocketExtensionsClientHeader(value); } return sendHttpResponse(createHandshakeResponse()); } private bool canSet(out string message) { message = null; if (_readyState == WebSocketState.Open) { message = "The connection has already been established."; return false; } if (_readyState == WebSocketState.Closing) { message = "The connection is closing."; return false; } return true; } private bool checkHandshakeRequest(WebSocketContext context, out string message) { message = null; if (!context.IsWebSocketRequest) { message = "Not a handshake request."; return false; } if (context.RequestUri == null) { message = "It specifies an invalid Request-URI."; return false; } NameValueCollection headers = context.Headers; string text = headers["Sec-WebSocket-Key"]; if (text == null) { message = "It includes no Sec-WebSocket-Key header."; return false; } if (text.Length == 0) { message = "It includes an invalid Sec-WebSocket-Key header."; return false; } string text2 = headers["Sec-WebSocket-Version"]; if (text2 == null) { message = "It includes no Sec-WebSocket-Version header."; return false; } if (text2 != "13") { message = "It includes an invalid Sec-WebSocket-Version header."; return false; } string text3 = headers["Sec-WebSocket-Protocol"]; if (text3 != null && text3.Length == 0) { message = "It includes an invalid Sec-WebSocket-Protocol header."; return false; } if (!_ignoreExtensions) { string text4 = headers["Sec-WebSocket-Extensions"]; if (text4 != null && text4.Length == 0) { message = "It 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 static bool checkProtocols(string[] protocols, out string message) { message = null; Func<string, bool> condition = (string protocol) => protocol.IsNullOrEmpty() || !protocol.IsToken(); if (protocols.Contains(condition)) { message = "It contains a value that is not a token."; return false; } if (protocols.ContainsTwice()) { message = "It contains a value twice."; return false; } return true; } 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 is not 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(ushort code, string reason) { if (_readyState == WebSocketState.Closing) { _logger.Info("The closing is already in progress."); return; } if (_readyState == WebSocketState.Closed) { _logger.Info("The connection has already been closed."); return; } if (code == 1005) { close(PayloadData.Empty, send: true, receive: true, received: false); return; } bool receive = !code.IsReserved(); close(new PayloadData(code, reason), receive, receive, received: false); } private void close(PayloadData payloadData, bool send, bool receive, bool received) { lock (_forState) { if (_readyState == WebSocketState.Closing) { _logger.Info("The closing is already in progress."); return; } if (_readyState == WebSocketState.Closed) { _logger.Info("The connection has already been closed."); return; } send = send && _readyState == WebSocketState.Open; receive = send && receive; _readyState = WebSocketState.Closing; } _logger.Trace("Begin closing the connection."); bool clean = closeHandshake(payloadData, send, receive, received); releaseResources(); _logger.Trace("End closing the connection."); _readyState = WebSocketState.Closed; CloseEventArgs e = new CloseEventArgs(payloadData, clean); try { this.OnClose.Emit(this, e); } catch (Exception ex) { _logger.Error(ex.Message); _logger.Debug(ex.ToString()); } } private void closeAsync(ushort code, string reason) { if (_readyState == WebSocketState.Closing) { _logger.Info("The closing is already in progress."); return; } if (_readyState == WebSocketState.Closed) { _logger.Info("The connection has already been closed."); return; } if (code == 1005) { closeAsync(PayloadData.Empty, send: true, receive: true, received: false); return; } bool receive = !code.IsReserved(); closeAsync(new PayloadData(code, reason), receive, receive, received: false); } private void closeAsync(PayloadData payloadData, bool send, bool receive, bool received) { Action<PayloadData, bool, bool, bool> closer = close; closer.BeginInvoke(payloadData, 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); if (!received && flag && receive && _receivingExited != null) { received = _receivingExited.WaitOne(_waitTime); } bool flag2 = flag && received; _logger.Debug($"Was clean?: {flag2}\n sent: {flag}\n received: {received}"); return flag2; } private bool closeHandshake(PayloadData payloadData, bool send, bool receive, bool received) { bool flag = false; if (send) { WebSocketFrame webSocketFrame = WebSocketFrame.CreateCloseFrame(payloadData, _client); flag = sendBytes(webSocketFrame.ToArray()); if (_client) { webSocketFrame.Unmask(); } } if (!received && flag && receive && _receivingExited != null) { received = _receivingExited.WaitOne(_waitTime); } bool flag2 = flag && received; _logger.Debug($"Was clean?: {flag2}\n sent: {flag}\n received: {received}"); return flag2; } private bool connect() { if (_readyState == WebSocketState.Open) { string text = "The connection has already been established."; _logger.Warn(text); return false; } lock (_forState) { if (_readyState == WebSocketState.Open) { string text2 = "The connection has already been established."; _logger.Warn(text2); return false; } if (_readyState == WebSocketState.Closing) { string text3 = "The close process has set in."; _logger.Error(text3); text3 = "An interruption has occurred while attempting to connect."; error(text3, null); return false; } if (_retryCountForConnect > _maxRetryCountForConnect) { string text4 = "An opportunity for reconnecting has been lost."; _logger.Error(text4); text4 = "An interruption has occurred while attempting to connect."; error(text4, null); return false; } _readyState = WebSocketState.Connecting; try { doHandshake(); } catch (Exception ex) { _retryCountForConnect++; _logger.Fatal(ex.Message); _logger.Debug(ex.ToString()); string text5 = "An exception has occurred while attempting to connect."; fatal(text5, ex); return false; } _retryCountForConnect = 1; _readyState = WebSocketState.Open; 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; if (_handshakeRequestChecker == null) { return true; } message = _handshakeRequestChecker(context); return message == null; } private MessageEventArgs dequeueFromMessageEventQueue() { lock (_forMessageEventQueue) { return (_messageEventQueue.Count > 0) ? _messageEventQueue.Dequeue() : null; } } private void doHandshake() { setClientStream(); HttpResponse httpResponse = sendHandshakeRequest(); if (!checkHandshakeResponse(httpResponse, out var text)) { throw new WebSocketException(CloseStatusCode.ProtocolError, text); } if (_protocolsRequested) { _protocol = httpResponse.Headers["Sec-WebSocket-Protocol"]; } if (_extensionsRequested) { processSecWebSocketExtensionsServerHeader(httpResponse.Headers["Sec-WebSocket-Extensions"]); } processCookies(httpResponse.Cookies); } 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.Message); _logger.Debug(ex.ToString()); } } private void fatal(string message, Exception exception) { CloseStatusCode code = ((exception is WebSocketException) ? ((WebSocketException)exception).Code : CloseStatusCode.Abnormal); fatal(message, (ushort)code); } private void fatal(string message, ushort code) { PayloadData payloadData = new PayloadData(code, message); close(payloadData, !code.IsReserved(), receive: false, received: false); } private void fatal(string message, CloseStatusCode code) { fatal(message, (ushort)code); } private ClientSslConfiguration getSslConfiguration() { if (_sslConfig == null) { _sslConfig = new ClientSslConfiguration(_uri.DnsSafeHost); } return _sslConfig; } private void init() { _compression = CompressionMethod.None; _cookies = new WebSocketSharp.Net.CookieCollection(); _forPing = new object(); _forSend = new object(); _forState = 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 error 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 error 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 error 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 ping(byte[] data) { if (_readyState != WebSocketState.Open) { return false; } ManualResetEvent pongReceived = _pongReceived; if (pongReceived == null) { return false; } lock (_forPing) { try { pongReceived.Reset(); if (!send(Fin.Final, Opcode.Ping, data, compressed: false)) { return false; } return pongReceived.WaitOne(_waitTime); } catch (ObjectDisposedException) { return false; } } } private bool processCloseFrame(WebSocketFrame frame) { PayloadData payloadData = frame.PayloadData; close(payloadData, !payloadData.HasReservedCode, 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) { _logger.Trace("A ping was received."); WebSocketFrame webSocketFrame = WebSocketFrame.CreatePongFrame(frame.PayloadData, _client); lock (_forState) { if (_readyState != WebSocketState.Open) { _logger.Error("The connection is closing."); return true; } if (!sendBytes(webSocketFrame.ToArray())) { return false; } } _logger.Trace("A pong to this ping has been sent."); if (_emitOnPing) { if (_client) { webSocketFrame.Unmask(); } enqueueToMessageEventQueue(new MessageEventArgs(frame)); } return true; } private bool processPongFrame(WebSocketFrame frame) { _logger.Trace("A pong was received."); try { _pongReceived.Set(); } catch (NullReferenceException ex) { _logger.Error(ex.Message); _logger.Debug(ex.ToString()); return false; } catch (ObjectDisposedException ex2) { _logger.Error(ex2.Message); _logger.Debug(ex2.ToString()); return false; } _logger.Trace("It has been signaled."); 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 text = item.Trim(); if (text.Length != 0 && !flag && text.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 processSecWebSocketProtocolClientHeader(IEnumerable<string> values) { if (!values.Contains((string val) => val == _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 refuseHandshake(CloseStatusCode code, string reason) { _readyState = WebSocketState.Closing; HttpResponse response = createHandshakeFailureResponse(WebSocketSharp.Net.HttpStatusCode.BadRequest); sendHttpResponse(response); releaseServerResources(); _readyState = WebSocketState.Closed; CloseEventArgs e = new CloseEventArgs((ushort)code, reason, clean: false); try { this.OnClose.Emit(this, e); } catch (Exception ex) { _logger.Error(ex.Message); _logger.Debug(ex.ToString()); } } 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 (_pongReceived != null) { _pongReceived.Close(); _pongReceived = null; } if (_receivingExited != null) { _receivingExited.Close(); _receivingExited = 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(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("A send has been interrupted.", null); } } catch (Exception ex) { _logger.Error(ex.ToString()); error("An error has occurred during a send.", 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: false); } long num = length / FragmentLength; int num2 = (int)(length % FragmentLength); byte[] array = null; switch (num) { case 0L: array = new byte[num2]; return stream.Read(array, 0, num2) == num2 && send(Fin.Final, opcode, array, compressed); case 1L: if (num2 == 0) { array = new byte[FragmentLength]; return stream.Read(array, 0, FragmentLength) == FragmentLength && send(Fin.Final, opcode, array, compressed); } break; } array = new byte[FragmentLength]; 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: false)) { 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: false); } private bool send(Fin fin, Opcode opcode, byte[] data, bool compressed) { lock (_forState) { if (_readyState != WebSocketState.Open) { _logger.Error("The connection is closing."); return false; } WebSocketFrame webSocketFrame = new WebSocketFrame(fin, opcode, data, compressed, _client); return sendBytes(webSocketFrame.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 error has occurred during the callback for an async send.", ex); } }, null); } private bool sendBytes(byte[] bytes) { try { _stream.Write(bytes, 0, bytes.Length); } catch (Exception ex) { _logger.Error(ex.Message); _logger.Debug(ex.ToString()); return false; } return true; } 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 {_context.UserEndPoint}:\n{response}"); 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 = getSslConfiguration(); 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(); } _pongReceived = new ManualResetEvent(initialState: false); _receivingExited = new ManualResetEvent(initialState: false); Action receive = null; receive = delegate { WebSocketFrame.ReadFrameAsync(_stream, unmask: false, delegate(WebSocketFrame frame) { if (!processReceivedFrame(frame) || _readyState == WebSocketState.Closed) { _receivingExited?.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 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 validateSecWebSocketProtocolServerHeader(string value) { if (value == null) { return !_protocolsRequested; } if (value.Length == 0) { return false; } return _protocolsRequested && _protocols.Contains((string p) => p == value); } private bool validateSecWebSocketVersionServerHeader(string value) { return value == null || value == "13"; } 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(PayloadData payloadData, byte[] frameAsBytes) { lock (_forState) { if (_readyState == WebSocketState.Closing) { _logger.Info("The closing is already in progress."); return; } if (_readyState == WebSocketState.Closed) { _logger.Info("The connection has already been closed."); return; } _readyState = WebSocketState.Closing; } _logger.Trace("Begin closing the connection."); bool flag = frameAsBytes != null && sendBytes(frameAsBytes); bool flag2 = flag && _receivingExited != null && _receivingExited.WaitOne(_waitTime); bool flag3 = flag && flag2; _logger.Debug($"Was clean?: {flag3}\n sent: {flag}\n received: {flag2}"); releaseServerResources(); releaseCommonResources(); _logger.Trace("End closing the connection."); _readyState = WebSocketState.Closed; CloseEventArgs e = new CloseEventArgs(payloadData, flag3); try { this.OnClose.Emit(this, e); } catch (Exception ex) { _logger.Error(ex.Message); _logger.Debug(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().GetUTF8EncodedBytes()); return Convert.ToBase64String(inArray); } internal void InternalAccept() { try { if (!acceptHandshake()) { return; } } catch (Exception ex) { _logger.Fatal(ex.Message); _logger.Debug(ex.ToString()); string text = "An exception has occurred while attempting to accept."; fatal(text, ex); return; } _readyState = WebSocketState.Open; open(); } internal bool Ping(byte[] frameAsBytes, TimeSpan timeout) { if (_readyState != WebSocketState.Open) { return false; } ManualResetEvent pongReceived = _pongReceived; if (pongReceived == null) { return false; } lock (_forPing) { try { pongReceived.Reset(); lock (_forState) { if (_readyState != WebSocketState.Open) { return false; } if (!sendBytes(frameAsBytes)) { return false; } } return pongReceived.WaitOne(timeout); } catch (ObjectDisposedException) { return false; } } } internal void Send(Opcode opcode, byte[] data, Dictionary<CompressionMethod, byte[]> cache) { lock (_forSend) { lock (_forState) { if (_readyState != WebSocketState.Open) { _logger.Error("The connection is closing."); return; } 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); } } } internal void Send(Opcode opcode, Stream stream, Dictionary<CompressionMethod, Stream> cache) { lock (_forSend) { 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); } } public void Accept() { if (_client) { string text = "This instance is a client."; throw new InvalidOperationException(text); } if (_readyState == WebSocketState.Closing) { string text2 = "The close process is in progress."; throw new InvalidOperationException(text2); } if (_readyState == WebSocketState.Closed) { string text3 = "The connection has already been closed."; throw new InvalidOperationException(text3); } if (accept()) { open(); } } public void AcceptAsync() { if (_client) { string text = "This instance is a client."; throw new InvalidOperationException(text); } if (_readyState == WebSocketState.Closing) { string text2 = "The close process is in progress."; throw new InvalidOperationException(text2); } if (_readyState == WebSocketState.Closed) { string text3 = "The connection has already been closed."; throw new InvalidOperationException(text3); } Func<bool> acceptor = accept; acceptor.BeginInvoke(delegate(IAsyncResult ar) { if (acceptor.EndInvoke(ar)) { open(); } }, null); } public void Close() { close(1005, string.Empty); } public void Close(ushort code) { if (!code.IsCloseStatusCode()) { string text = "Less than 1000 or greater than 4999."; throw new ArgumentOutOfRangeException("code", text); } if (_client && code == 1011) { string text2 = "1011 cannot be used."; throw new ArgumentException(text2, "code"); } if (!_client && code == 1010) { string text3 = "1010 cannot be used."; throw new ArgumentException(text3, "code"); } close(code, string.Empty); } public void Close(CloseStatusCode code) { if (_client && code == CloseStatusCode.ServerError) { string text = "ServerError cannot be used."; throw new ArgumentException(text, "code"); } if (!_client && code == CloseStatusCode.MandatoryExtension) { string text2 = "MandatoryExtension cannot be used."; throw new ArgumentException(text2, "code"); } close((ushort)code, string.Empty); } public void Close(ushort code, string reason) { if (!code.IsCloseStatusCode()) { string text = "Less than 1000 or greater than 4999."; throw new ArgumentOutOfRangeException("code", text); } if (_client && code == 1011) { string text2 = "1011 cannot be used."; throw new ArgumentException(text2, "code"); } if (!_client && code == 1010) { string text3 = "1010 cannot be used."; throw new ArgumentException(text3, "code"); } if (reason.IsNullOrEmpty()) { close(code, string.Empty); return; } if (code == 1005) { string text4 = "1005 cannot be used."; throw new ArgumentException(text4, "code"); } if (!reason.TryGetUTF8EncodedBytes(out var bytes)) { string text5 = "It could not be UTF-8-encoded."; throw new ArgumentException(text5, "reason"); } if (bytes.Length > 123) { string text6 = "Its size is greater than 123 bytes."; throw new ArgumentOutOfRangeException("reason", text6); } close(code, reason); } public void Close(CloseStatusCode code, string reason) { if (_client && code == CloseStatusCode.ServerError) { string text = "ServerError cannot be used."; throw new ArgumentException(text, "code"); } if (!_client && code == CloseStatusCode.MandatoryExtension) { string text2 = "MandatoryExtension cannot be used."; throw new ArgumentException(text2, "code"); } if (reason.IsNullOrEmpty()) { close((ushort)code, string.Empty); return; } if (code == CloseStatusCode.NoStatus) { string text3 = "NoStatus cannot be used."; throw new ArgumentException(text3, "code"); } if (!reason.TryGetUTF8EncodedBytes(out var bytes)) { string text4 = "It could not be UTF-8-encoded."; throw new ArgumentException(text4, "reason"); } if (bytes.Length > 123) { string text5 = "Its size is greater than 123 bytes."; throw new ArgumentOutOfRangeException("reason", text5); } close((ushort)code, reason); } public void CloseAsync() { closeAsync(1005, string.Empty); } public void CloseAsync(ushort code) { if (!code.IsCloseStatusCode()) { string text = "Less than 1000 or greater than 4999."; throw new ArgumentOutOfRangeException("code", text); } if (_client && code == 1011) { string text2 = "1011 cannot be used."; throw new ArgumentException(text2, "code"); } if (!_client && code == 1010) { string text3 = "1010 cannot be used."; throw new ArgumentException(text3, "code"); } closeAsync(code, string.Empty); } public void CloseAsync(CloseStatusCode code) { if (_client && code == CloseStatusCode.ServerError) { string text = "ServerError cannot be used."; throw new ArgumentException(text, "code"); } if (!_client && code == CloseStatusCode.MandatoryExtension) { string text2 = "MandatoryExtension cannot be used."; throw new ArgumentException(text2, "code"); } closeAsync((ushort)code, string.Empty); } public void CloseAsync(ushort code, string reason) { if (!code.IsCloseStatusCode()) { string text = "Less than 1000 or greater than 4999."; throw new ArgumentOutOfRangeException("code", text); } if (_client && code == 1011) { string text2 = "1011 cannot be used."; throw new ArgumentException(text2, "code"); } if (!_client && code == 1010) { string text3 = "1010 cannot be used."; throw new ArgumentException(text3, "code"); } if (reason.IsNullOrEmpty()) { closeAsync(code, string.Empty); return; } if (code == 1005) { string text4 = "1005 cannot be used."; throw new ArgumentException(text4, "code"); } if (!reason.TryGetUTF8EncodedBytes(out var bytes)) { string text5 = "It could not be UTF-8-encoded."; throw new ArgumentException(text5, "reason"); } if (bytes.Length > 123) { string text6 = "Its size is greater than 123 bytes."; throw new ArgumentOutOfRangeException("reason", text6); } closeAsync(code, reason); } public void CloseAsync(CloseStatusCode code, string reason) { if (_client && code == CloseStatusCode.ServerError) { string text = "ServerError cannot be used."; throw new ArgumentException(text, "code"); } if (!_client && code == CloseStatusCode.MandatoryExtension) { string text2 = "MandatoryExtension cannot be used."; throw new ArgumentException(text2, "code"); } if (reason.IsNullOrEmpty()) { closeAsync((ushort)code, string.Empty); return; } if (code == CloseStatusCode.NoStatus) { string text3 = "NoStatus cannot be used."; throw new ArgumentException(text3, "code"); } if (!reason.TryGetUTF8EncodedBytes(out var bytes)) { string text4 = "It could not be UTF-8-encoded."; throw new ArgumentException(text4, "reason"); } if (bytes.Length > 123) { string text5 = "Its size is greater than 123 bytes."; throw new ArgumentOutOfRangeException("reason", text5); } closeAsync((ushort)code, reason); } public void Connect() { if (!_client) { string text = "This instance is not a client."; throw new InvalidOperationException(text); } if (_readyState == WebSocketState.Closing) { string text2 = "The close process is in progress."; throw new InvalidOperationException(text2); } if (_retryCountForConnect > _maxRetryCountForConnect) { string text3 = "A series of reconnecting has failed."; throw new InvalidOperationException(text3); } if (connect()) { open(); } } public void ConnectAsync() { if (!_client) { string text = "This instance is not a client."; throw new InvalidOperationException(text); } if (_readyState == WebSocketState.Closing) { string text2 = "The close process is in progress."; throw new InvalidOperationException(text2); } if (_retryCountForConnect > _maxRetryCountForConnect) { string text3 = "A series of reconnecting has failed."; throw new InvalidOperationException(text3); } Func<bool> connector = connect; connector.BeginInvoke(delegate(IAsyncResult ar) { if (connector.EndInvoke(ar)) { open(); } }, null); } public bool Ping() { return ping(EmptyBytes); } public bool Ping(string message) { if (message.IsNullOrEmpty()) { return ping(EmptyBytes); } if (!message.TryGetUTF8EncodedBytes(out var bytes)) { string text = "It could not be UTF-8-encoded."; throw new ArgumentException(text, "message"); } if (bytes.Length > 125) { string text2 = "Its size is greater than 125 bytes."; throw new ArgumentOutOfRangeException("message", text2); } return ping(bytes); } public void Send(byte[] data) { if (_readyState != WebSocketState.Open) { string text = "The current state of the connection is not Open."; throw new InvalidOperationException(text); } if (data == null) { throw new ArgumentNullException("data"); } send(Opcode.Binary, new MemoryStream(data)); } public void Send(FileInfo fileInfo) { if (_readyState != WebSocketState.Open) { string text = "The current state of the connection is not Open."; throw new InvalidOperationException(text); } if (fileInfo == null) { throw new ArgumentNullException("fileInfo"); } if (!fileInfo.Exists) { string text2 = "The file does not exist."; throw new ArgumentException(text2, "fileInfo"); } if (!fileInfo.TryOpenRead(out var fileStream)) { string text3 = "The file could not be opened."; throw new ArgumentException(text3, "fileInfo"); } send(Opcode.Binary, fileStream); } public void Send(string data) { if (_readyState != WebSocketState.Open) { string text = "The current state of the connection is not Open."; throw new InvalidOperationException(text); } if (data == null) { throw new ArgumentNullException("data"); } if (!data.TryGetUTF8EncodedBytes(out var bytes)) { string text2 = "It could not be UTF-8-encoded."; throw new ArgumentException(text2, "data"); } send(Opcode.Text, new MemoryStream(bytes)); } public void Send(Stream stream, int length) { if (_readyState != WebSocketState.Open) { string text = "The current state of the connection is not Open."; throw new InvalidOperationException(text); } if (stream == null) { throw new ArgumentNullException("stream"); } if (!stream.CanRead) { string text2 = "It cannot be read."; throw new ArgumentException(text2, "stream"); } if (length < 1) { string text3 = "Less than 1."; throw new ArgumentException(text3, "length"); } byte[] array = stream.ReadBytes(length); int num = array.Length; if (num == 0) { string text4 = "No data could be read from it."; throw new ArgumentException(text4, "stream"); } if (num < length) { _logger.Warn($"Only {num} byte(s) of data could be read from the stream."); } send(Opcode.Binary, new MemoryStream(array)); } public void SendAsync(byte[] data, Action<bool> completed) { if (_readyState != WebSocketState.Open) { string text = "The current state of the connection is not Open."; throw new InvalidOperationException(text); } if (data == null) { throw new ArgumentNullException("data"); } sendAsync(Opcode.Binary, new MemoryStream(data), completed); } public void SendAsync(FileInfo fileInfo, Action<bool> completed) { if (_readyState != WebSocketState.Open) { string text = "The current state of the connection is not Open."; throw new InvalidOperationException(text); } if (fileInfo == null) { throw new ArgumentNullException("fileInfo"); } if (!fileInfo.Exists) { string text2 = "The file does not exist."; throw new ArgumentException(text2, "fileInfo"); } if (!fileInfo.TryOpenRead(out var fileStream)) { string text3 = "The file could not be opened."; throw new ArgumentException(text3, "fileInfo"); } sendAsync(Opcode.Binary, fileStream, completed); } public void SendAsync(string data, Action<bool> completed) { if (_readyState != WebSocketState.Open) { string text = "The current state of the connection is not Open."; throw new InvalidOperationException(text); } if (data == null) { throw new ArgumentNullException("data"); } if (!data.TryGetUTF8EncodedBytes(out var bytes)) { string text2 = "It could not be UTF-8-encoded."; throw new ArgumentException(text2, "data"); } sendAsync(Opcode.Text, new MemoryStream(bytes), completed); } public void SendAsync(Stream stream, int length, Action<bool> completed) { if (_readyState != WebSocketState.Open) { string text = "The current state of the connection is not Open."; throw new InvalidOperationException(text); } if (stream == null) { throw new ArgumentNullException("stream"); } if (!stream.CanRead) { string text2 = "It cannot be read."; throw new ArgumentException(text2, "stream"); } if (length < 1) { string text3 = "Less than 1."; throw new ArgumentException(text3, "length"); } byte[] array = stream.ReadBytes(length); int num = array.Length; if (num == 0) { string text4 = "No data could be read from it."; throw new ArgumentException(text4, "stream"); } if (num < length) { _logger.Warn($"Only {num} byte(s) of data could be read from the stream."); } sendAsync(Opcode.Binary, new MemoryStream(array), completed); } public void SetCookie(WebSocketSharp.Net.Cookie cookie) { string text = null; if (!_client) { text = "This instance is not a client."; throw new InvalidOperationException(text); } if (cookie == null) { throw new ArgumentNullException("cookie"); } if (!canSet(out text)) { _logger.Warn(text); return; } lock (_forState) { if (!canSet(out text)) { _logger.Warn(text); return; } lock (_cookies.SyncRoot) { _cookies.SetOrRemove(cookie); } } } public void SetCredentials(string username, string password, bool preAuth) { string text = null; if (!_client) { text = "This instance is not a client."; throw new InvalidOperationException(text); } if (!username.IsNullOrEmpty() && (Ext.Contains(username, ':') || !username.IsText())) { text = "It contains an invalid character."; throw new ArgumentException(text, "username"); } if (!password.IsNullOrEmpty() && !password.IsText()) { text = "It contains an invalid character."; throw new ArgumentException(text, "password"); } if (!canSet(out text)) { _logger.Warn(text); return; } lock (_forState) { if (!canSet(out text)) { _logger.Warn(text); } else if (username.IsNullOrEmpty()) { _credentials = null; _preAuth = false; } else { _credentials = new WebSocketSharp.Net.NetworkCredential(username, password, _uri.PathAndQuery); _preAuth = preAuth; } } } public void SetProxy(string url, string username, string password) { string text = null; if (!_client) { text = "This instance is not a client."; throw new InvalidOperationException(text); } Uri result = null; if (!url.IsNullOrEmpty()) { if (!Uri.TryCreate(url, UriKind.Absolute, out result)) { text = "Not an absolute URI string."; throw new ArgumentException(text, "url"); } if (result.Scheme != "http") { text = "The scheme part is not http."; throw new ArgumentException(text, "url"); } if (result.Segments.Length > 1) { text = "It includes the path segments."; throw new ArgumentException(text, "url"); } } if (!username.IsNullOrEmpty() && (Ext.Contains(username, ':') || !username.IsText())) { text = "It contains an invalid character."; throw new ArgumentException(text, "username"); } if (!password.IsNullOrEmpty() && !password.IsText()) { text = "It contains an invalid character."; throw new ArgumentException(text, "password"); } if (!canSet(out text)) { _logger.Warn(text); return; } lock (_forState) { if (!canSet(out text)) { _logger.Warn(text); }
ChaosTricks_SBG_plugins/WebSocketIO.dll
Decompiled a day agousing System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; 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: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [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 JsonUtils.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; protected bool logOnConnectionError; 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, bool logOnConnectionError = false) : base("", processEvent, parser, log, errorLog, checkPeriod, delay, initDelay) { this.logOnConnectionError = logOnConnectionError; } 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 = JsonUtils.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) { WebSocket socket = Socket; try { 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}"); } try { socket.Close(); } catch (Exception) { } } } 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_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Expected O, but got Unknown WebSocket val = new WebSocket($"ws://{ip}:{port}/{room}", Array.Empty<string>()); 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; SetSocketForConnectLimit(val, int.MaxValue); } public void SetSocketForConnectLimit(WebSocket ws, int max) { FieldInfo field = ((object)ws).GetType().GetField("_maxRetryCountForConnect", BindingFlags.Static | BindingFlags.NonPublic); if (field == null) { ((EventsReader)this).ReaderLogError("FixSocketLimit error, maxRetryField is null"); } else { field.SetValue(ws, max); } } 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(logOnConnectionError); } } ((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 + "\"}"; } } }