Decompiled source of Archipelago v2.0.7
Archipelago.MultiClient.Net.dll
Decompiled 2 weeks 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.Concurrent; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; using System.IO; using System.Linq; using System.Net; using System.Net.WebSockets; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Runtime.Versioning; using System.Text; using System.Threading; using System.Threading.Tasks; using Archipelago.MultiClient.Net.Cache; using Archipelago.MultiClient.Net.ConcurrentCollection; using Archipelago.MultiClient.Net.Converters; using Archipelago.MultiClient.Net.Enums; using Archipelago.MultiClient.Net.Exceptions; using Archipelago.MultiClient.Net.Extensions; using Archipelago.MultiClient.Net.Helpers; using Archipelago.MultiClient.Net.MessageLog.Messages; using Archipelago.MultiClient.Net.MessageLog.Parts; using Archipelago.MultiClient.Net.Models; using Archipelago.MultiClient.Net.Packets; using Newtonsoft.Json; using Newtonsoft.Json.Converters; using Newtonsoft.Json.Linq; using Newtonsoft.Json.Serialization; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: ComVisible(false)] [assembly: Guid("35a803ad-85ed-42e9-b1e3-c6b72096f0c1")] [assembly: InternalsVisibleTo("Archipelago.MultiClient.Net.Tests")] [assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")] [assembly: TargetFramework(".NETFramework,Version=v4.5", FrameworkDisplayName = ".NET Framework 4.5")] [assembly: AssemblyCompany("Jarno Westhof, Hussein Farran, Zach Parks")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyCopyright("Copyright © 2023")] [assembly: AssemblyDescription("A client library for use with .NET based prog-langs for interfacing with Archipelago hosts.")] [assembly: AssemblyFileVersion("5.0.5.0")] [assembly: AssemblyInformationalVersion("5.0.5")] [assembly: AssemblyProduct("Archipelago.MultiClient.Net")] [assembly: AssemblyTitle("Archipelago.MultiClient.Net")] [assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/ArchipelagoMW/Archipelago.MultiClient.Net")] [assembly: AssemblyVersion("5.0.5.0")] internal interface IConcurrentHashSet<T> { bool TryAdd(T item); bool Contains(T item); void UnionWith(T[] otherSet); T[] ToArray(); ReadOnlyCollection<T> AsToReadOnlyCollection(); ReadOnlyCollection<T> AsToReadOnlyCollectionExcept(IConcurrentHashSet<T> otherSet); } namespace Archipelago.MultiClient.Net { [Serializable] public abstract class ArchipelagoPacketBase { [JsonIgnore] internal JObject jobject; [JsonProperty("cmd")] [JsonConverter(typeof(StringEnumConverter))] public abstract ArchipelagoPacketType PacketType { get; } public JObject ToJObject() { return jobject; } } public class ArchipelagoSession { private const int ArchipelagoConnectionTimeoutInSeconds = 4; private TaskCompletionSource<LoginResult> loginResultTask = new TaskCompletionSource<LoginResult>(); private TaskCompletionSource<RoomInfoPacket> roomInfoPacketTask = new TaskCompletionSource<RoomInfoPacket>(); public IArchipelagoSocketHelper Socket { get; } public ReceivedItemsHelper Items { get; } public LocationCheckHelper Locations { get; } public PlayerHelper Players { get; } public DataStorageHelper DataStorage { get; } public ConnectionInfoHelper ConnectionInfo { get; } public RoomStateHelper RoomState { get; } public MessageLogHelper MessageLog { get; } internal ArchipelagoSession(IArchipelagoSocketHelper socket, ReceivedItemsHelper items, LocationCheckHelper locations, PlayerHelper players, RoomStateHelper roomState, ConnectionInfoHelper connectionInfo, DataStorageHelper dataStorage, MessageLogHelper messageLog) { Socket = socket; Items = items; Locations = locations; Players = players; RoomState = roomState; ConnectionInfo = connectionInfo; DataStorage = dataStorage; MessageLog = messageLog; socket.PacketReceived += Socket_PacketReceived; } private void Socket_PacketReceived(ArchipelagoPacketBase packet) { if (!(packet is ConnectedPacket) && !(packet is ConnectionRefusedPacket)) { if (packet is RoomInfoPacket result) { roomInfoPacketTask.TrySetResult(result); } return; } if (packet is ConnectedPacket && RoomState.Version != null && RoomState.Version >= new Version(0, 3, 8)) { LogUsedVersion(); } loginResultTask.TrySetResult(LoginResult.FromPacket(packet)); } private void LogUsedVersion() { try { string fileVersion = FileVersionInfo.GetVersionInfo(Assembly.GetExecutingAssembly().Location).FileVersion; Socket.SendPacketAsync(new SetPacket { Key = ".NetUsedVersions", DefaultValue = (JToken)(object)JObject.FromObject((object)new Dictionary<string, bool>()), Operations = new OperationSpecification[1] { Operation.Update(new Dictionary<string, bool> { { ConnectionInfo.Game + ":" + fileVersion + ":NET45", true } }) } }); } catch { } } public Task<RoomInfoPacket> ConnectAsync() { roomInfoPacketTask = new TaskCompletionSource<RoomInfoPacket>(); Task.Factory.StartNew(delegate { try { Task task = Socket.ConnectAsync(); task.Wait(TimeSpan.FromSeconds(4.0)); if (!task.IsCompleted) { roomInfoPacketTask.TrySetCanceled(); } } catch (AggregateException) { roomInfoPacketTask.TrySetCanceled(); } }); return roomInfoPacketTask.Task; } public Task<LoginResult> LoginAsync(string game, string name, ItemsHandlingFlags itemsHandlingFlags, Version version = null, string[] tags = null, string uuid = null, string password = null, bool requestSlotData = true) { loginResultTask = new TaskCompletionSource<LoginResult>(); if (!roomInfoPacketTask.Task.IsCompleted) { loginResultTask = new TaskCompletionSource<LoginResult>(); loginResultTask.SetResult(new LoginFailure("You are not connected, run ConnectAsync() first")); return loginResultTask.Task; } ConnectionInfo.SetConnectionParameters(game, tags, itemsHandlingFlags, uuid); try { Socket.SendPacket(BuildConnectPacket(name, password, version, requestSlotData)); } catch (ArchipelagoSocketClosedException) { loginResultTask.SetResult(new LoginFailure("You are not connected, run ConnectAsync() first")); return loginResultTask.Task; } SetResultAfterTimeout(loginResultTask, 4, new LoginFailure("Connection timed out.")); return loginResultTask.Task; } private static void SetResultAfterTimeout<T>(TaskCompletionSource<T> task, int timeoutInSeconds, T result) { new CancellationTokenSource(TimeSpan.FromSeconds(timeoutInSeconds)).Token.Register(delegate { task.TrySetResult(result); }); } public LoginResult TryConnectAndLogin(string game, string name, ItemsHandlingFlags itemsHandlingFlags, Version version = null, string[] tags = null, string uuid = null, string password = null, bool requestSlotData = true) { Task<RoomInfoPacket> task = ConnectAsync(); try { task.Wait(TimeSpan.FromSeconds(4.0)); } catch (AggregateException ex) { if (ex.GetBaseException() is OperationCanceledException) { return new LoginFailure("Connection timed out."); } return new LoginFailure(ex.GetBaseException().Message); } if (!task.IsCompleted) { return new LoginFailure("Connection timed out."); } return LoginAsync(game, name, itemsHandlingFlags, version, tags, uuid, password, requestSlotData).Result; } private ConnectPacket BuildConnectPacket(string name, string password, Version version, bool requestSlotData) { return new ConnectPacket { Game = ConnectionInfo.Game, Name = name, Password = password, Tags = ConnectionInfo.Tags, Uuid = ConnectionInfo.Uuid, Version = ((version != null) ? new NetworkVersion(version) : new NetworkVersion(0, 4, 0)), ItemsHandling = ConnectionInfo.ItemsHandlingFlags, RequestSlotData = requestSlotData }; } } public static class ArchipelagoSessionFactory { public static ArchipelagoSession CreateSession(Uri uri) { ArchipelagoSocketHelper socket = new ArchipelagoSocketHelper(uri); DataPackageCache dataPackageCache = new DataPackageCache(socket); LocationCheckHelper locationCheckHelper = new LocationCheckHelper(socket, dataPackageCache); ReceivedItemsHelper items = new ReceivedItemsHelper(socket, locationCheckHelper, dataPackageCache); ConnectionInfoHelper connectionInfoHelper = new ConnectionInfoHelper(socket); PlayerHelper players = new PlayerHelper(socket, connectionInfoHelper); RoomStateHelper roomState = new RoomStateHelper(socket, locationCheckHelper); DataStorageHelper dataStorage = new DataStorageHelper(socket, connectionInfoHelper); MessageLogHelper messageLog = new MessageLogHelper(socket, items, locationCheckHelper, players, connectionInfoHelper); return new ArchipelagoSession(socket, items, locationCheckHelper, players, roomState, connectionInfoHelper, dataStorage, messageLog); } public static ArchipelagoSession CreateSession(string hostname, int port = 38281) { return CreateSession(ParseUri(hostname, port)); } internal static Uri ParseUri(string hostname, int port) { string text = hostname; if (!text.StartsWith("ws://") && !text.StartsWith("wss://")) { text = "unspecified://" + text; } if (!text.Substring(text.IndexOf("://", StringComparison.Ordinal) + 3).Contains(":")) { text += $":{port}"; } if (text.EndsWith(":")) { text += port; } return new Uri(text); } } public abstract class LoginResult { public abstract bool Successful { get; } public static LoginResult FromPacket(ArchipelagoPacketBase packet) { if (!(packet is ConnectedPacket connectedPacket)) { if (packet is ConnectionRefusedPacket connectionRefusedPacket) { return new LoginFailure(connectionRefusedPacket); } throw new ArgumentOutOfRangeException("packet", "packet is not a connection result packet"); } return new LoginSuccessful(connectedPacket); } } public class LoginSuccessful : LoginResult { public override bool Successful => true; public int Team { get; } public int Slot { get; } public Dictionary<string, object> SlotData { get; } public LoginSuccessful(ConnectedPacket connectedPacket) { Team = connectedPacket.Team; Slot = connectedPacket.Slot; SlotData = connectedPacket.SlotData; } } public class LoginFailure : LoginResult { public override bool Successful => false; public ConnectionRefusedError[] ErrorCodes { get; } public string[] Errors { get; } public LoginFailure(ConnectionRefusedPacket connectionRefusedPacket) { if (connectionRefusedPacket.Errors != null) { ErrorCodes = connectionRefusedPacket.Errors.ToArray(); Errors = ErrorCodes.Select(GetErrorMessage).ToArray(); } else { ErrorCodes = new ConnectionRefusedError[0]; Errors = new string[0]; } } public LoginFailure(string message) { ErrorCodes = new ConnectionRefusedError[0]; Errors = new string[1] { message }; } private static string GetErrorMessage(ConnectionRefusedError errorCode) { return errorCode switch { ConnectionRefusedError.InvalidSlot => "The slot name did not match any slot on the server.", ConnectionRefusedError.InvalidGame => "The slot is set to a different game on the server.", ConnectionRefusedError.SlotAlreadyTaken => "The slot already has a connection with a different uuid established.", ConnectionRefusedError.IncompatibleVersion => "The client and server version mismatch.", ConnectionRefusedError.InvalidPassword => "The password is invalid.", ConnectionRefusedError.InvalidItemsHandling => "The item handling flags provided are invalid.", _ => $"Unknown error: {errorCode}.", }; } } } namespace Archipelago.MultiClient.Net.Packets { public class BouncedPacket : BouncePacket { public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.Bounced; } public class BouncePacket : ArchipelagoPacketBase { public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.Bounce; [JsonProperty("games")] public List<string> Games { get; set; } = new List<string>(); [JsonProperty("slots")] public List<int> Slots { get; set; } = new List<int>(); [JsonProperty("tags")] public List<string> Tags { get; set; } = new List<string>(); [JsonProperty("data")] public Dictionary<string, JToken> Data { get; set; } } public class ConnectedPacket : ArchipelagoPacketBase { public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.Connected; [JsonProperty("team")] public int Team { get; set; } [JsonProperty("slot")] public int Slot { get; set; } [JsonProperty("players")] public NetworkPlayer[] Players { get; set; } [JsonProperty("missing_locations")] public long[] MissingChecks { get; set; } [JsonProperty("checked_locations")] public long[] LocationsChecked { get; set; } [JsonProperty("slot_data")] public Dictionary<string, object> SlotData { get; set; } [JsonProperty("slot_info")] public Dictionary<int, NetworkSlot> SlotInfo { get; set; } [JsonProperty("hint_points")] public int? HintPoints { get; set; } } public class ConnectionRefusedPacket : ArchipelagoPacketBase { public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.ConnectionRefused; [JsonProperty("errors", ItemConverterType = typeof(StringEnumConverter))] public ConnectionRefusedError[] Errors { get; set; } } public class ConnectPacket : ArchipelagoPacketBase { public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.Connect; [JsonProperty("password")] public string Password { get; set; } [JsonProperty("game")] public string Game { get; set; } [JsonProperty("name")] public string Name { get; set; } [JsonProperty("uuid")] public string Uuid { get; set; } [JsonProperty("version")] public NetworkVersion Version { get; set; } [JsonProperty("tags")] public string[] Tags { get; set; } [JsonProperty("items_handling")] public ItemsHandlingFlags ItemsHandling { get; set; } [JsonProperty("slot_data")] public bool RequestSlotData { get; set; } } public class ConnectUpdatePacket : ArchipelagoPacketBase { public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.ConnectUpdate; [JsonProperty("tags")] public string[] Tags { get; set; } [JsonProperty("items_handling")] public ItemsHandlingFlags? ItemsHandling { get; set; } } public class DataPackagePacket : ArchipelagoPacketBase { public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.DataPackage; [JsonProperty("data")] public DataPackage DataPackage { get; set; } } public class GetDataPackagePacket : ArchipelagoPacketBase { public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.GetDataPackage; [JsonProperty("games")] public string[] Games { get; set; } } public class GetPacket : ArchipelagoPacketBase { public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.Get; [JsonProperty("keys")] public string[] Keys { get; set; } } public class InvalidPacketPacket : ArchipelagoPacketBase { public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.InvalidPacket; [JsonProperty("type")] public InvalidPacketErrorType ErrorType { get; set; } [JsonProperty("text")] public string ErrorText { get; set; } [JsonProperty("original_cmd")] public ArchipelagoPacketType OriginalCmd { get; set; } } public class LocationChecksPacket : ArchipelagoPacketBase { public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.LocationChecks; [JsonProperty("locations")] public long[] Locations { get; set; } } public class LocationInfoPacket : ArchipelagoPacketBase { public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.LocationInfo; [JsonProperty("locations")] public NetworkItem[] Locations { get; set; } } public class LocationScoutsPacket : ArchipelagoPacketBase { public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.LocationScouts; [JsonProperty("locations")] public long[] Locations { get; set; } [JsonProperty("create_as_hint")] public bool CreateAsHint { get; set; } } public class PrintJsonPacket : ArchipelagoPacketBase { public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.PrintJSON; [JsonProperty("data")] public JsonMessagePart[] Data { get; set; } [JsonProperty("type")] [JsonConverter(typeof(StringEnumConverter))] public JsonMessageType? MessageType { get; set; } } public class ItemPrintJsonPacket : PrintJsonPacket { [JsonProperty("receiving")] public int ReceivingPlayer { get; set; } [JsonProperty("item")] public NetworkItem Item { get; set; } } public class ItemCheatPrintJsonPacket : PrintJsonPacket { [JsonProperty("receiving")] public int ReceivingPlayer { get; set; } [JsonProperty("item")] public NetworkItem Item { get; set; } [JsonProperty("team")] public int Team { get; set; } } public class HintPrintJsonPacket : PrintJsonPacket { [JsonProperty("receiving")] public int ReceivingPlayer { get; set; } [JsonProperty("item")] public NetworkItem Item { get; set; } [JsonProperty("found")] public bool? Found { get; set; } } public class JoinPrintJsonPacket : PrintJsonPacket { [JsonProperty("team")] public int Team { get; set; } [JsonProperty("slot")] public int Slot { get; set; } [JsonProperty("tags")] public string[] Tags { get; set; } } public class LeavePrintJsonPacket : PrintJsonPacket { [JsonProperty("team")] public int Team { get; set; } [JsonProperty("slot")] public int Slot { get; set; } } public class ChatPrintJsonPacket : PrintJsonPacket { [JsonProperty("team")] public int Team { get; set; } [JsonProperty("slot")] public int Slot { get; set; } [JsonProperty("message")] public string Message { get; set; } } public class ServerChatPrintJsonPacket : PrintJsonPacket { [JsonProperty("message")] public string Message { get; set; } } public class TutorialPrintJsonPacket : PrintJsonPacket { } public class TagsChangedPrintJsonPacket : PrintJsonPacket { [JsonProperty("team")] public int Team { get; set; } [JsonProperty("slot")] public int Slot { get; set; } [JsonProperty("tags")] public string[] Tags { get; set; } } public class CommandResultPrintJsonPacket : PrintJsonPacket { } public class AdminCommandResultPrintJsonPacket : PrintJsonPacket { } public class GoalPrintJsonPacket : PrintJsonPacket { [JsonProperty("team")] public int Team { get; set; } [JsonProperty("slot")] public int Slot { get; set; } } public class ReleasePrintJsonPacket : PrintJsonPacket { [JsonProperty("team")] public int Team { get; set; } [JsonProperty("slot")] public int Slot { get; set; } } public class CollectPrintJsonPacket : PrintJsonPacket { [JsonProperty("team")] public int Team { get; set; } [JsonProperty("slot")] public int Slot { get; set; } } public class CountdownPrintJsonPacket : PrintJsonPacket { [JsonProperty("countdown")] public int RemainingSeconds { get; set; } } public class ReceivedItemsPacket : ArchipelagoPacketBase { public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.ReceivedItems; [JsonProperty("index")] public int Index { get; set; } [JsonProperty("items")] public NetworkItem[] Items { get; set; } } public class RetrievedPacket : ArchipelagoPacketBase { public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.Retrieved; [JsonProperty("keys")] public Dictionary<string, JToken> Data { get; set; } } public class RoomInfoPacket : ArchipelagoPacketBase { public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.RoomInfo; [JsonProperty("version")] public NetworkVersion Version { get; set; } [JsonProperty("tags")] public string[] Tags { get; set; } [JsonProperty("password")] public bool Password { get; set; } [JsonProperty("permissions")] public Dictionary<string, Permissions> Permissions { get; set; } [JsonProperty("hint_cost")] public int HintCostPercentage { get; set; } [JsonProperty("location_check_points")] public int LocationCheckPoints { get; set; } [JsonProperty("players")] public NetworkPlayer[] Players { get; set; } [JsonProperty("games")] public string[] Games { get; set; } [Obsolete("use DataPackageChecksums instead")] [JsonProperty("datapackage_versions")] public Dictionary<string, int> DataPackageVersions { get; set; } [JsonProperty("datapackage_checksums")] public Dictionary<string, string> DataPackageChecksums { get; set; } [JsonProperty("seed_name")] public string SeedName { get; set; } [JsonProperty("time")] public double Timestamp { get; set; } } public class RoomUpdatePacket : ArchipelagoPacketBase { public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.RoomUpdate; [JsonProperty("tags")] public string[] Tags { get; set; } [JsonProperty("password")] public bool? Password { get; set; } [JsonProperty("permissions")] public Dictionary<string, Permissions> Permissions { get; set; } = new Dictionary<string, Permissions>(); [JsonProperty("hint_cost")] public int? HintCostPercentage { get; set; } [JsonProperty("location_check_points")] public int? LocationCheckPoints { get; set; } [JsonProperty("players")] public NetworkPlayer[] Players { get; set; } [JsonProperty("hint_points")] public int? HintPoints { get; set; } [JsonProperty("checked_locations")] public long[] CheckedLocations { get; set; } } public class SayPacket : ArchipelagoPacketBase { public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.Say; [JsonProperty("text")] public string Text { get; set; } } public class SetNotifyPacket : ArchipelagoPacketBase { public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.SetNotify; [JsonProperty("keys")] public string[] Keys { get; set; } } public class SetPacket : ArchipelagoPacketBase { public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.Set; [JsonProperty("key")] public string Key { get; set; } [JsonProperty("default")] public JToken DefaultValue { get; set; } [JsonProperty("operations")] public OperationSpecification[] Operations { get; set; } [JsonProperty("want_reply")] public bool WantReply { get; set; } public Guid? Reference { get; set; } } public class SetReplyPacket : ArchipelagoPacketBase { public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.SetReply; [JsonProperty("key")] public string Key { get; set; } [JsonProperty("value")] public JToken Value { get; set; } [JsonProperty("default")] public JToken DefaultValue { get; set; } [JsonProperty("original_value")] public JToken OriginalValue { get; set; } [JsonProperty("operation")] public string Operation { get; set; } [JsonProperty("want_reply")] public bool WantReply { get; set; } public Guid? Reference { get; set; } } public class StatusUpdatePacket : ArchipelagoPacketBase { public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.StatusUpdate; [JsonProperty("status")] public ArchipelagoClientState Status { get; set; } } public class SyncPacket : ArchipelagoPacketBase { public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.Sync; } internal class UnknownPacket : ArchipelagoPacketBase { public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.Unknown; } } namespace Archipelago.MultiClient.Net.Models { public struct Color : IEquatable<Color> { public static Color Red = new Color(byte.MaxValue, 0, 0); public static Color Green = new Color(0, 128, 0); public static Color Yellow = new Color(byte.MaxValue, byte.MaxValue, 0); public static Color Blue = new Color(0, 0, byte.MaxValue); public static Color Magenta = new Color(byte.MaxValue, 0, byte.MaxValue); public static Color Cyan = new Color(0, byte.MaxValue, byte.MaxValue); public static Color Black = new Color(0, 0, 0); public static Color White = new Color(byte.MaxValue, byte.MaxValue, byte.MaxValue); public static Color SlateBlue = new Color(106, 90, 205); public static Color Salmon = new Color(250, 128, 114); public static Color Plum = new Color(221, 160, 221); public byte R { get; set; } public byte G { get; set; } public byte B { get; set; } public Color(byte r, byte g, byte b) { R = r; G = g; B = b; } public override bool Equals(object obj) { if (obj is Color color && R == color.R && G == color.G) { return B == color.B; } return false; } public bool Equals(Color other) { if (R == other.R && G == other.G) { return B == other.B; } return false; } public override int GetHashCode() { return ((-1520100960 * -1521134295 + R.GetHashCode()) * -1521134295 + G.GetHashCode()) * -1521134295 + B.GetHashCode(); } public static bool operator ==(Color left, Color right) { return left.Equals(right); } public static bool operator !=(Color left, Color right) { return !(left == right); } } public class DataPackage { [JsonProperty("games")] public Dictionary<string, GameData> Games { get; set; } = new Dictionary<string, GameData>(); } public class DataStorageElement { internal DataStorageElementContext Context; internal List<OperationSpecification> Operations = new List<OperationSpecification>(0); internal DataStorageHelper.DataStorageUpdatedHandler Callbacks; private JToken cachedValue; public event DataStorageHelper.DataStorageUpdatedHandler OnValueChanged { add { Context.AddHandler(Context.Key, value); } remove { Context.RemoveHandler(Context.Key, value); } } internal DataStorageElement(DataStorageElementContext context) { Context = context; } internal DataStorageElement(OperationType operationType, JToken value) { Operations = new List<OperationSpecification>(1) { new OperationSpecification { OperationType = operationType, Value = value } }; } internal DataStorageElement(DataStorageElement source, OperationType operationType, JToken value) : this(source.Context) { Operations = source.Operations.ToList(); Operations.Add(new OperationSpecification { OperationType = operationType, Value = value }); Callbacks = source.Callbacks; } internal DataStorageElement(DataStorageElement source, Callback callback) : this(source.Context) { Operations = source.Operations.ToList(); Callbacks = source.Callbacks; Callbacks = (DataStorageHelper.DataStorageUpdatedHandler)Delegate.Combine(Callbacks, callback.Method); } public static DataStorageElement operator ++(DataStorageElement a) { return new DataStorageElement(a, OperationType.Add, JToken.op_Implicit(1)); } public static DataStorageElement operator --(DataStorageElement a) { return new DataStorageElement(a, OperationType.Add, JToken.op_Implicit(-1)); } public static DataStorageElement operator +(DataStorageElement a, JToken b) { return new DataStorageElement(a, OperationType.Add, b); } public static DataStorageElement operator +(DataStorageElement a, IEnumerable b) { return new DataStorageElement(a, OperationType.Add, (JToken)(object)JArray.FromObject((object)b)); } public static DataStorageElement operator +(DataStorageElement a, OperationSpecification s) { return new DataStorageElement(a, s.OperationType, s.Value); } public static DataStorageElement operator +(DataStorageElement a, Callback c) { return new DataStorageElement(a, c); } public static DataStorageElement operator *(DataStorageElement a, JToken b) { return new DataStorageElement(a, OperationType.Mul, b); } public static DataStorageElement operator %(DataStorageElement a, JToken b) { return new DataStorageElement(a, OperationType.Mod, b); } public static DataStorageElement operator ^(DataStorageElement a, JToken b) { return new DataStorageElement(a, OperationType.Pow, b); } public static DataStorageElement operator -(DataStorageElement a, int b) { return new DataStorageElement(a, OperationType.Add, JToken.FromObject((object)(-b))); } public static DataStorageElement operator -(DataStorageElement a, long b) { return new DataStorageElement(a, OperationType.Add, JToken.FromObject((object)(-b))); } public static DataStorageElement operator -(DataStorageElement a, decimal b) { return new DataStorageElement(a, OperationType.Add, JToken.FromObject((object)(-b))); } public static DataStorageElement operator -(DataStorageElement a, double b) { return new DataStorageElement(a, OperationType.Add, JToken.FromObject((object)(0.0 - b))); } public static DataStorageElement operator -(DataStorageElement a, float b) { return new DataStorageElement(a, OperationType.Add, JToken.FromObject((object)(0f - b))); } public static DataStorageElement operator /(DataStorageElement a, int b) { return new DataStorageElement(a, OperationType.Mul, JToken.FromObject((object)(1m / (decimal)b))); } public static DataStorageElement operator /(DataStorageElement a, long b) { return new DataStorageElement(a, OperationType.Mul, JToken.FromObject((object)(1m / (decimal)b))); } public static DataStorageElement operator /(DataStorageElement a, decimal b) { return new DataStorageElement(a, OperationType.Mul, JToken.FromObject((object)(1m / b))); } public static DataStorageElement operator /(DataStorageElement a, double b) { return new DataStorageElement(a, OperationType.Mul, JToken.FromObject((object)(1.0 / b))); } public static DataStorageElement operator /(DataStorageElement a, float b) { return new DataStorageElement(a, OperationType.Mul, JToken.FromObject((object)(1.0 / (double)b))); } [Obsolete("Use + Operation.Min() instead")] public static DataStorageElement operator >>(DataStorageElement a, int b) { return new DataStorageElement(a, OperationType.Min, JToken.op_Implicit(b)); } [Obsolete("Use + Operation.Max() instead")] public static DataStorageElement operator <<(DataStorageElement a, int b) { return new DataStorageElement(a, OperationType.Max, JToken.op_Implicit(b)); } public static implicit operator DataStorageElement(bool b) { return new DataStorageElement(OperationType.Replace, JToken.op_Implicit(b)); } public static implicit operator DataStorageElement(int i) { return new DataStorageElement(OperationType.Replace, JToken.op_Implicit(i)); } public static implicit operator DataStorageElement(long l) { return new DataStorageElement(OperationType.Replace, JToken.op_Implicit(l)); } public static implicit operator DataStorageElement(decimal m) { return new DataStorageElement(OperationType.Replace, JToken.op_Implicit(m)); } public static implicit operator DataStorageElement(double d) { return new DataStorageElement(OperationType.Replace, JToken.op_Implicit(d)); } public static implicit operator DataStorageElement(float f) { return new DataStorageElement(OperationType.Replace, JToken.op_Implicit(f)); } public static implicit operator DataStorageElement(string s) { if (s != null) { return new DataStorageElement(OperationType.Replace, JToken.op_Implicit(s)); } return new DataStorageElement(OperationType.Replace, (JToken)(object)JValue.CreateNull()); } public static implicit operator DataStorageElement(JToken o) { return new DataStorageElement(OperationType.Replace, o); } public static implicit operator DataStorageElement(Array a) { return new DataStorageElement(OperationType.Replace, (JToken)(object)JArray.FromObject((object)a)); } public static implicit operator DataStorageElement(List<bool> l) { return new DataStorageElement(OperationType.Replace, (JToken)(object)JArray.FromObject((object)l)); } public static implicit operator DataStorageElement(List<int> l) { return new DataStorageElement(OperationType.Replace, (JToken)(object)JArray.FromObject((object)l)); } public static implicit operator DataStorageElement(List<long> l) { return new DataStorageElement(OperationType.Replace, (JToken)(object)JArray.FromObject((object)l)); } public static implicit operator DataStorageElement(List<decimal> l) { return new DataStorageElement(OperationType.Replace, (JToken)(object)JArray.FromObject((object)l)); } public static implicit operator DataStorageElement(List<double> l) { return new DataStorageElement(OperationType.Replace, (JToken)(object)JArray.FromObject((object)l)); } public static implicit operator DataStorageElement(List<float> l) { return new DataStorageElement(OperationType.Replace, (JToken)(object)JArray.FromObject((object)l)); } public static implicit operator DataStorageElement(List<string> l) { return new DataStorageElement(OperationType.Replace, (JToken)(object)JArray.FromObject((object)l)); } public static implicit operator DataStorageElement(List<object> l) { return new DataStorageElement(OperationType.Replace, (JToken)(object)JArray.FromObject((object)l)); } public static implicit operator bool(DataStorageElement e) { return RetrieveAndReturnBoolValue<bool>(e); } public static implicit operator bool?(DataStorageElement e) { return RetrieveAndReturnBoolValue<bool?>(e); } public static implicit operator int(DataStorageElement e) { return RetrieveAndReturnDecimalValue<int>(e); } public static implicit operator int?(DataStorageElement e) { return RetrieveAndReturnDecimalValue<int?>(e); } public static implicit operator long(DataStorageElement e) { return RetrieveAndReturnDecimalValue<long>(e); } public static implicit operator long?(DataStorageElement e) { return RetrieveAndReturnDecimalValue<long?>(e); } public static implicit operator decimal(DataStorageElement e) { return RetrieveAndReturnDecimalValue<decimal>(e); } public static implicit operator decimal?(DataStorageElement e) { return RetrieveAndReturnDecimalValue<decimal?>(e); } public static implicit operator double(DataStorageElement e) { return RetrieveAndReturnDecimalValue<double>(e); } public static implicit operator double?(DataStorageElement e) { return RetrieveAndReturnDecimalValue<double?>(e); } public static implicit operator float(DataStorageElement e) { return RetrieveAndReturnDecimalValue<float>(e); } public static implicit operator float?(DataStorageElement e) { return RetrieveAndReturnDecimalValue<float?>(e); } public static implicit operator string(DataStorageElement e) { return RetrieveAndReturnStringValue(e); } public static implicit operator bool[](DataStorageElement e) { return RetrieveAndReturnArrayValue<bool[]>(e); } public static implicit operator int[](DataStorageElement e) { return RetrieveAndReturnArrayValue<int[]>(e); } public static implicit operator long[](DataStorageElement e) { return RetrieveAndReturnArrayValue<long[]>(e); } public static implicit operator decimal[](DataStorageElement e) { return RetrieveAndReturnArrayValue<decimal[]>(e); } public static implicit operator double[](DataStorageElement e) { return RetrieveAndReturnArrayValue<double[]>(e); } public static implicit operator float[](DataStorageElement e) { return RetrieveAndReturnArrayValue<float[]>(e); } public static implicit operator string[](DataStorageElement e) { return RetrieveAndReturnArrayValue<string[]>(e); } public static implicit operator object[](DataStorageElement e) { return RetrieveAndReturnArrayValue<object[]>(e); } public static implicit operator List<bool>(DataStorageElement e) { return RetrieveAndReturnArrayValue<List<bool>>(e); } public static implicit operator List<int>(DataStorageElement e) { return RetrieveAndReturnArrayValue<List<int>>(e); } public static implicit operator List<long>(DataStorageElement e) { return RetrieveAndReturnArrayValue<List<long>>(e); } public static implicit operator List<decimal>(DataStorageElement e) { return RetrieveAndReturnArrayValue<List<decimal>>(e); } public static implicit operator List<double>(DataStorageElement e) { return RetrieveAndReturnArrayValue<List<double>>(e); } public static implicit operator List<float>(DataStorageElement e) { return RetrieveAndReturnArrayValue<List<float>>(e); } public static implicit operator List<string>(DataStorageElement e) { return RetrieveAndReturnArrayValue<List<string>>(e); } public static implicit operator List<object>(DataStorageElement e) { return RetrieveAndReturnArrayValue<List<object>>(e); } public static implicit operator Array(DataStorageElement e) { return RetrieveAndReturnArrayValue<Array>(e); } public static implicit operator JArray(DataStorageElement e) { return RetrieveAndReturnArrayValue<JArray>(e); } public static implicit operator JToken(DataStorageElement e) { return e.Context.GetData(e.Context.Key); } public void Initialize(JToken value) { Context.Initialize(Context.Key, value); } public void Initialize(IEnumerable value) { Context.Initialize(Context.Key, (JToken)(object)JArray.FromObject((object)value)); } public Task<T> GetAsync<T>() { return GetAsync().ContinueWith((Task<JToken> r) => r.Result.ToObject<T>()); } public Task<JToken> GetAsync() { return Context.GetAsync(Context.Key); } private static T RetrieveAndReturnArrayValue<T>(DataStorageElement e) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_003d: 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_0078: Invalid comparison between Unknown and I4 //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Invalid comparison between Unknown and I4 //IL_00d7: Unknown result type (might be due to invalid IL or missing references) if (e.cachedValue != null) { return ((JToken)(JArray)e.cachedValue).ToObject<T>(); } JArray val = (JArray)(((object)e.Context.GetData(e.Context.Key).ToObject<JArray>()) ?? ((object)new JArray())); foreach (OperationSpecification operation in e.Operations) { switch (operation.OperationType) { case OperationType.Add: if ((int)operation.Value.Type != 2) { throw new InvalidOperationException($"Cannot perform operation {OperationType.Add} on Array value, with a non Array value: {operation.Value}"); } ((JContainer)val).Merge((object)operation.Value); break; case OperationType.Replace: if ((int)operation.Value.Type != 2) { throw new InvalidOperationException($"Cannot replace Array value, with a non Array value: {operation.Value}"); } val = (JArray)(((object)operation.Value.ToObject<JArray>()) ?? ((object)new JArray())); break; default: throw new InvalidOperationException($"Cannot perform operation {operation.OperationType} on Array value"); } } e.cachedValue = (JToken)(object)val; return ((JToken)val).ToObject<T>(); } private static string RetrieveAndReturnStringValue(DataStorageElement e) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Invalid comparison between Unknown and I4 //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Invalid comparison between Unknown and I4 if (e.cachedValue != null) { return (string)e.cachedValue; } JToken val = e.Context.GetData(e.Context.Key); string text = (((int)val.Type == 10) ? null : ((object)val).ToString()); foreach (OperationSpecification operation in e.Operations) { switch (operation.OperationType) { case OperationType.Add: text += (string)operation.Value; break; case OperationType.Mul: if ((int)operation.Value.Type != 6) { throw new InvalidOperationException($"Cannot perform operation {OperationType.Mul} on string value, with a non interger value: {operation.Value}"); } text = string.Concat(Enumerable.Repeat(text, (int)operation.Value)); break; case OperationType.Replace: text = (string)operation.Value; break; default: throw new InvalidOperationException($"Cannot perform operation {operation.OperationType} on string value"); } } if (text == null) { e.cachedValue = (JToken)(object)JValue.CreateNull(); } else { e.cachedValue = JToken.op_Implicit(text); } return (string)e.cachedValue; } private static T RetrieveAndReturnBoolValue<T>(DataStorageElement e) { if (e.cachedValue != null) { return e.cachedValue.ToObject<T>(); } bool? flag = e.Context.GetData(e.Context.Key).ToObject<bool?>() ?? ((bool?)Activator.CreateInstance(typeof(T))); foreach (OperationSpecification operation in e.Operations) { if (operation.OperationType == OperationType.Replace) { flag = (bool?)operation.Value; continue; } throw new InvalidOperationException($"Cannot perform operation {operation.OperationType} on boolean value"); } e.cachedValue = JToken.op_Implicit(flag); if (!flag.HasValue) { return default(T); } return (T)Convert.ChangeType(flag.Value, IsNullable<T>() ? Nullable.GetUnderlyingType(typeof(T)) : typeof(T)); } private static T RetrieveAndReturnDecimalValue<T>(DataStorageElement e) { if (e.cachedValue != null) { return e.cachedValue.ToObject<T>(); } decimal? num = e.Context.GetData(e.Context.Key).ToObject<decimal?>(); if (!num.HasValue && !IsNullable<T>()) { num = Activator.CreateInstance<decimal>(); } foreach (OperationSpecification operation in e.Operations) { switch (operation.OperationType) { case OperationType.Replace: num = (decimal)operation.Value; break; case OperationType.Add: num += (decimal?)(decimal)operation.Value; break; case OperationType.Mul: num *= (decimal?)(decimal)operation.Value; break; case OperationType.Mod: num %= (decimal?)(decimal)operation.Value; break; case OperationType.Pow: num = (decimal)Math.Pow((double)num.Value, (double)operation.Value); break; case OperationType.Max: num = Math.Max(num.Value, (decimal)operation.Value); break; case OperationType.Min: num = Math.Min(num.Value, (decimal)operation.Value); break; case OperationType.Xor: num = (long)num.Value ^ (long)operation.Value; break; case OperationType.Or: num = (long)num.Value | (long)operation.Value; break; case OperationType.And: num = (long)num.Value & (long)operation.Value; break; case OperationType.LeftShift: num = (long)num.Value << (int)operation.Value; break; case OperationType.RightShift: num = (long)num.Value >> (int)operation.Value; break; } } e.cachedValue = JToken.op_Implicit(num); if (!num.HasValue) { return default(T); } return (T)Convert.ChangeType(num.Value, IsNullable<T>() ? Nullable.GetUnderlyingType(typeof(T)) : typeof(T)); } private static bool IsNullable<T>() { if (typeof(T).IsGenericType) { return typeof(T).GetGenericTypeDefinition() == typeof(Nullable<>).GetGenericTypeDefinition(); } return false; } public T To<T>() { if (Operations.Count != 0) { throw new InvalidOperationException("DataStorageElement.To<T>() cannot be used together with other operations on the DataStorageElement"); } return Context.GetData(Context.Key).ToObject<T>(); } public override string ToString() { return (Context?.ToString() ?? "(null)") + ", (" + ListOperations() + ")"; } private string ListOperations() { if (Operations != null) { return string.Join(", ", Operations.Select((OperationSpecification o) => o.ToString()).ToArray()); } return "none"; } } internal class DataStorageElementContext { internal string Key { get; set; } internal Action<string, DataStorageHelper.DataStorageUpdatedHandler> AddHandler { get; set; } internal Action<string, DataStorageHelper.DataStorageUpdatedHandler> RemoveHandler { get; set; } internal Func<string, JToken> GetData { get; set; } internal Action<string, JToken> Initialize { get; set; } internal Func<string, Task<JToken>> GetAsync { get; set; } public override string ToString() { return "Key: " + Key; } } public class GameData { [JsonProperty("location_name_to_id")] public Dictionary<string, long> LocationLookup { get; set; } = new Dictionary<string, long>(); [JsonProperty("item_name_to_id")] public Dictionary<string, long> ItemLookup { get; set; } = new Dictionary<string, long>(); [Obsolete("use Checksum instead")] [JsonProperty("version")] public int Version { get; set; } [JsonProperty("checksum")] public string Checksum { get; set; } } public class Hint { [JsonProperty("receiving_player")] public int ReceivingPlayer { get; set; } [JsonProperty("finding_player")] public int FindingPlayer { get; set; } [JsonProperty("item")] public long ItemId { get; set; } [JsonProperty("location")] public long LocationId { get; set; } [JsonProperty("item_flags")] public ItemFlags ItemFlags { get; set; } [JsonProperty("found")] public bool Found { get; set; } [JsonProperty("entrance")] public string Entrance { get; set; } } public class JsonMessagePart { [JsonProperty("type")] [JsonConverter(typeof(StringEnumConverter), new object[] { typeof(SnakeCaseNamingStrategy) })] public JsonMessagePartType? Type { get; set; } [JsonProperty("color")] [JsonConverter(typeof(StringEnumConverter), new object[] { typeof(SnakeCaseNamingStrategy) })] public JsonMessagePartColor? Color { get; set; } [JsonProperty("text")] public string Text { get; set; } [JsonProperty("player")] public int? Player { get; set; } [JsonProperty("flags")] public ItemFlags? Flags { get; set; } } public struct NetworkItem { [JsonProperty("item")] public long Item { get; set; } [JsonProperty("location")] public long Location { get; set; } [JsonProperty("player")] public int Player { get; set; } [JsonProperty("flags")] public ItemFlags Flags { get; set; } } public struct NetworkPlayer { [JsonProperty("team")] public int Team { get; set; } [JsonProperty("slot")] public int Slot { get; set; } [JsonProperty("alias")] public string Alias { get; set; } [JsonProperty("name")] public string Name { get; set; } } public struct NetworkSlot { [JsonProperty("name")] public string Name { get; set; } [JsonProperty("game")] public string Game { get; set; } [JsonProperty("type")] public SlotType Type { get; set; } [JsonProperty("group_members")] public int[] GroupMembers { get; set; } } public class NetworkVersion { [JsonProperty("major")] public int Major { get; set; } [JsonProperty("minor")] public int Minor { get; set; } [JsonProperty("build")] public int Build { get; set; } [JsonProperty("class")] public string Class => "Version"; public NetworkVersion() { } public NetworkVersion(int major, int minor, int build) { Major = major; Minor = minor; Build = build; } public NetworkVersion(Version version) { Major = version.Major; Minor = version.Minor; Build = version.Build; } public Version ToVersion() { return new Version(Major, Minor, Build); } } public class OperationSpecification { [JsonProperty("operation")] [JsonConverter(typeof(StringEnumConverter), new object[] { typeof(SnakeCaseNamingStrategy) })] public OperationType OperationType; [JsonProperty("value")] public JToken Value { get; set; } public override string ToString() { return $"{OperationType}: {Value}"; } } public static class Operation { public static OperationSpecification Min(JToken i) { return new OperationSpecification { OperationType = OperationType.Min, Value = i }; } public static OperationSpecification Max(JToken i) { return new OperationSpecification { OperationType = OperationType.Max, Value = i }; } public static OperationSpecification Remove(JToken value) { return new OperationSpecification { OperationType = OperationType.Remove, Value = value }; } public static OperationSpecification Pop(JToken value) { return new OperationSpecification { OperationType = OperationType.Pop, Value = value }; } public static OperationSpecification Update(IDictionary dictionary) { return new OperationSpecification { OperationType = OperationType.Update, Value = (JToken)(object)JObject.FromObject((object)dictionary) }; } } public static class Bitwise { public static OperationSpecification Xor(long i) { return new OperationSpecification { OperationType = OperationType.Xor, Value = JToken.op_Implicit(i) }; } public static OperationSpecification Or(long i) { return new OperationSpecification { OperationType = OperationType.Or, Value = JToken.op_Implicit(i) }; } public static OperationSpecification And(long i) { return new OperationSpecification { OperationType = OperationType.And, Value = JToken.op_Implicit(i) }; } public static OperationSpecification LeftShift(long i) { return new OperationSpecification { OperationType = OperationType.LeftShift, Value = JToken.op_Implicit(i) }; } public static OperationSpecification RightShift(long i) { return new OperationSpecification { OperationType = OperationType.RightShift, Value = JToken.op_Implicit(i) }; } } public class Callback { internal DataStorageHelper.DataStorageUpdatedHandler Method { get; set; } private Callback() { } public static Callback Add(DataStorageHelper.DataStorageUpdatedHandler callback) { return new Callback { Method = callback }; } } } namespace Archipelago.MultiClient.Net.MessageLog.Parts { public class EntranceMessagePart : MessagePart { internal EntranceMessagePart(JsonMessagePart messagePart) : base(MessagePartType.Entrance, messagePart, Color.Blue) { base.Text = messagePart.Text; } } public class ItemMessagePart : MessagePart { public ItemFlags Flags { get; } public long ItemId { get; } internal ItemMessagePart(IReceivedItemsHelper items, JsonMessagePart part) : base(MessagePartType.Item, part) { Flags = part.Flags.GetValueOrDefault(); base.Color = GetColor(Flags); JsonMessagePartType? type = part.Type; if (type.HasValue) { switch (type.GetValueOrDefault()) { case JsonMessagePartType.ItemId: ItemId = long.Parse(part.Text); base.Text = items.GetItemName(ItemId) ?? $"Item: {ItemId}"; break; case JsonMessagePartType.ItemName: ItemId = 0L; base.Text = part.Text; break; } } } private static Color GetColor(ItemFlags flags) { if (HasFlag(flags, ItemFlags.Advancement)) { return Color.Plum; } if (HasFlag(flags, ItemFlags.NeverExclude)) { return Color.SlateBlue; } if (HasFlag(flags, ItemFlags.Trap)) { return Color.Salmon; } return Color.Cyan; } private static bool HasFlag(ItemFlags flags, ItemFlags flag) { return flags.HasFlag(flag); } } public class LocationMessagePart : MessagePart { public long LocationId { get; } internal LocationMessagePart(ILocationCheckHelper locations, JsonMessagePart part) : base(MessagePartType.Location, part, Color.Green) { JsonMessagePartType? type = part.Type; if (type.HasValue) { switch (type.GetValueOrDefault()) { case JsonMessagePartType.LocationId: LocationId = long.Parse(part.Text); base.Text = locations.GetLocationNameFromId(LocationId) ?? $"Location: {LocationId}"; break; case JsonMessagePartType.PlayerName: LocationId = 0L; base.Text = part.Text; break; } } } } public class MessagePart { public string Text { get; internal set; } public MessagePartType Type { get; internal set; } public Color Color { get; internal set; } public bool IsBackgroundColor { get; internal set; } internal MessagePart(MessagePartType type, JsonMessagePart messagePart, Color? color = null) { Type = type; Text = messagePart.Text; if (color.HasValue) { Color = color.Value; } else if (messagePart.Color.HasValue) { Color = GetColor(messagePart.Color.Value); IsBackgroundColor = messagePart.Color.Value >= JsonMessagePartColor.BlackBg; } else { Color = Color.White; } } private static Color GetColor(JsonMessagePartColor color) { switch (color) { case JsonMessagePartColor.Red: case JsonMessagePartColor.RedBg: return Color.Red; case JsonMessagePartColor.Green: case JsonMessagePartColor.GreenBg: return Color.Green; case JsonMessagePartColor.Yellow: case JsonMessagePartColor.YellowBg: return Color.Yellow; case JsonMessagePartColor.Blue: case JsonMessagePartColor.BlueBg: return Color.Blue; case JsonMessagePartColor.Magenta: case JsonMessagePartColor.MagentaBg: return Color.Magenta; case JsonMessagePartColor.Cyan: case JsonMessagePartColor.CyanBg: return Color.Cyan; case JsonMessagePartColor.Black: case JsonMessagePartColor.BlackBg: return Color.Black; case JsonMessagePartColor.White: case JsonMessagePartColor.WhiteBg: return Color.White; default: return Color.White; } } public override string ToString() { return Text; } } public enum MessagePartType { Text, Player, Item, Location, Entrance } public class PlayerMessagePart : MessagePart { public bool IsActivePlayer { get; } public int SlotId { get; } internal PlayerMessagePart(IPlayerHelper players, IConnectionInfoProvider connectionInfo, JsonMessagePart part) : base(MessagePartType.Player, part) { switch (part.Type) { case JsonMessagePartType.PlayerId: SlotId = int.Parse(part.Text); IsActivePlayer = SlotId == connectionInfo.Slot; base.Text = players.GetPlayerAlias(SlotId) ?? $"Player {SlotId}"; break; case JsonMessagePartType.PlayerName: SlotId = 0; IsActivePlayer = false; base.Text = part.Text; break; } base.Color = GetColor(IsActivePlayer); } private static Color GetColor(bool isActivePlayer) { if (isActivePlayer) { return Color.Magenta; } return Color.Yellow; } } } namespace Archipelago.MultiClient.Net.MessageLog.Messages { public class AdminCommandResultLogMessage : LogMessage { internal AdminCommandResultLogMessage(MessagePart[] parts) : base(parts) { } } public class ChatLogMessage : PlayerSpecificLogMessage { public string Message { get; } internal ChatLogMessage(MessagePart[] parts, IPlayerHelper players, IConnectionInfoProvider connectionInfo, int team, int slot, string message) : base(parts, players, connectionInfo, team, slot) { Message = message; } } public class CollectLogMessage : PlayerSpecificLogMessage { internal CollectLogMessage(MessagePart[] parts, IPlayerHelper players, IConnectionInfoProvider connectionInfo, int team, int slot) : base(parts, players, connectionInfo, team, slot) { } } public class CommandResultLogMessage : LogMessage { internal CommandResultLogMessage(MessagePart[] parts) : base(parts) { } } public class CountdownLogMessage : LogMessage { public int RemainingSeconds { get; } internal CountdownLogMessage(MessagePart[] parts, int remainingSeconds) : base(parts) { RemainingSeconds = remainingSeconds; } } public class GoalLogMessage : PlayerSpecificLogMessage { internal GoalLogMessage(MessagePart[] parts, IPlayerHelper players, IConnectionInfoProvider connectionInfo, int team, int slot) : base(parts, players, connectionInfo, team, slot) { } } public class HintItemSendLogMessage : ItemSendLogMessage { public bool IsFound { get; } internal HintItemSendLogMessage(MessagePart[] parts, IPlayerHelper players, IConnectionInfoProvider connectionInfo, int receiver, int sender, NetworkItem item, bool found) : base(parts, players, connectionInfo, receiver, sender, item) { IsFound = found; } } public class ItemCheatLogMessage : ItemSendLogMessage { internal ItemCheatLogMessage(MessagePart[] parts, IPlayerHelper players, IConnectionInfoProvider connectionInfo, int team, int slot, NetworkItem item) : base(parts, players, connectionInfo, slot, 0, item, team) { } } public class ItemSendLogMessage : LogMessage { [Obsolete("Use Receiver.Slot instead")] public int ReceivingPlayerSlot { get; } [Obsolete("Use Sender.Slot instead")] public int SendingPlayerSlot { get; } public PlayerInfo Receiver { get; } public PlayerInfo Sender { get; } public bool IsReceiverTheActivePlayer { get; } public bool IsSenderTheActivePlayer { get; } public bool IsRelatedToActivePlayer { get; } public NetworkItem Item { get; } internal ItemSendLogMessage(MessagePart[] parts, IPlayerHelper players, IConnectionInfoProvider connectionInfo, int receiver, int sender, NetworkItem item) : this(parts, players, connectionInfo, receiver, sender, item, connectionInfo.Team) { } internal ItemSendLogMessage(MessagePart[] parts, IPlayerHelper players, IConnectionInfoProvider connectionInfo, int receiver, int sender, NetworkItem item, int team) : base(parts) { ReadOnlyDictionary<int, ReadOnlyCollection<PlayerInfo>> players2 = players.Players; ReceivingPlayerSlot = receiver; SendingPlayerSlot = sender; IsReceiverTheActivePlayer = connectionInfo.Team == team && connectionInfo.Slot == receiver; IsSenderTheActivePlayer = connectionInfo.Team == team && connectionInfo.Slot == sender; Receiver = ((players2.Count > team && players2[team].Count > receiver) ? players2[team][receiver] : new PlayerInfo()); Sender = ((players2.Count > team && players2[team].Count > sender) ? players2[team][sender] : new PlayerInfo()); IsRelatedToActivePlayer = IsReceiverTheActivePlayer || IsSenderTheActivePlayer || Receiver.IsSharingGroupWith(connectionInfo.Team, connectionInfo.Slot) || Sender.IsSharingGroupWith(connectionInfo.Team, connectionInfo.Slot); Item = item; } } public class JoinLogMessage : PlayerSpecificLogMessage { public string[] Tags { get; } internal JoinLogMessage(MessagePart[] parts, IPlayerHelper players, IConnectionInfoProvider connectionInfo, int team, int slot, string[] tags) : base(parts, players, connectionInfo, team, slot) { Tags = tags; } } public class LeaveLogMessage : PlayerSpecificLogMessage { internal LeaveLogMessage(MessagePart[] parts, IPlayerHelper players, IConnectionInfoProvider connectionInfo, int team, int slot) : base(parts, players, connectionInfo, team, slot) { } } public class LogMessage { public MessagePart[] Parts { get; } internal LogMessage(MessagePart[] parts) { Parts = parts; } public override string ToString() { if (Parts.Length == 1) { return Parts[0].Text; } StringBuilder stringBuilder = new StringBuilder(); MessagePart[] parts = Parts; foreach (MessagePart messagePart in parts) { stringBuilder.Append(messagePart.Text); } return stringBuilder.ToString(); } } public abstract class PlayerSpecificLogMessage : LogMessage { public PlayerInfo Player { get; } public bool IsActivePlayer { get; } public bool IsRelatedToActivePlayer { get; } internal PlayerSpecificLogMessage(MessagePart[] parts, IPlayerHelper players, IConnectionInfoProvider connectionInfo, int team, int slot) : base(parts) { ReadOnlyDictionary<int, ReadOnlyCollection<PlayerInfo>> players2 = players.Players; IsActivePlayer = connectionInfo.Team == team && connectionInfo.Slot == slot; Player = ((players2.Count > team && players2[team].Count > slot) ? players2[team][slot] : new PlayerInfo()); IsRelatedToActivePlayer = IsActivePlayer || Player.IsSharingGroupWith(connectionInfo.Team, connectionInfo.Slot); } } public class ReleaseLogMessage : PlayerSpecificLogMessage { internal ReleaseLogMessage(MessagePart[] parts, IPlayerHelper players, IConnectionInfoProvider connectionInfo, int team, int slot) : base(parts, players, connectionInfo, team, slot) { } } public class ServerChatLogMessage : LogMessage { public string Message { get; } internal ServerChatLogMessage(MessagePart[] parts, string message) : base(parts) { Message = message; } } public class TagsChangedLogMessage : PlayerSpecificLogMessage { public string[] Tags { get; } internal TagsChangedLogMessage(MessagePart[] parts, IPlayerHelper players, IConnectionInfoProvider connectionInfo, int team, int slot, string[] tags) : base(parts, players, connectionInfo, team, slot) { Tags = tags; } } public class TutorialLogMessage : LogMessage { internal TutorialLogMessage(MessagePart[] parts) : base(parts) { } } } namespace Archipelago.MultiClient.Net.Helpers { public class ArchipelagoSocketHelper : IArchipelagoSocketHelper { private static readonly ArchipelagoPacketConverter Converter = new ArchipelagoPacketConverter(); private const int ReceiveChunkSize = 1024; private const int SendChunkSize = 1024; private readonly BlockingCollection<Tuple<ArchipelagoPacketBase, TaskCompletionSource<bool>>> sendQueue = new BlockingCollection<Tuple<ArchipelagoPacketBase, TaskCompletionSource<bool>>>(); internal ClientWebSocket webSocket; public Uri Uri { get; } public bool Connected { get { if (webSocket.State != WebSocketState.Open) { return webSocket.State == WebSocketState.CloseReceived; } return true; } } public event ArchipelagoSocketHelperDelagates.PacketReceivedHandler PacketReceived; public event ArchipelagoSocketHelperDelagates.PacketsSentHandler PacketsSent; public event ArchipelagoSocketHelperDelagates.ErrorReceivedHandler ErrorReceived; public event ArchipelagoSocketHelperDelagates.SocketClosedHandler SocketClosed; public event ArchipelagoSocketHelperDelagates.SocketOpenedHandler SocketOpened; internal ArchipelagoSocketHelper(Uri hostUri) { Uri = hostUri; webSocket = new ClientWebSocket(); SecurityProtocolType securityProtocolType = SecurityProtocolType.Tls13; ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | securityProtocolType; } public async Task ConnectAsync() { await ConnectToProvidedUri(Uri); if (this.SocketOpened != null) { this.SocketOpened(); } Task.Run((Func<Task?>)PollingLoop); Task.Run((Func<Task?>)SendLoop); } private async Task ConnectToProvidedUri(Uri uri) { if (uri.Scheme != "unspecified") { await webSocket.ConnectAsync(uri, CancellationToken.None); return; } try { await ConnectToProvidedUri(uri.AsWss()); if (webSocket.State == WebSocketState.Open) { return; } } catch { webSocket = new ClientWebSocket(); } await ConnectToProvidedUri(uri.AsWs()); } private async Task PollingLoop() { byte[] buffer = new byte[1024]; while (webSocket.State == WebSocketState.Open) { string message = null; try { message = await ReadMessageAsync(buffer); } catch (Exception e) { OnError(e); } OnMessageReceived(message); } } private async Task SendLoop() { while (webSocket.State == WebSocketState.Open) { try { await HandleSendBuffer(); } catch (Exception e) { OnError(e); } } } private async Task<string> ReadMessageAsync(byte[] buffer) { StringBuilder stringResult = new StringBuilder(); WebSocketReceiveResult result; do { result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None); if (result.MessageType == WebSocketMessageType.Close) { try { await webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None); } catch { } OnSocketClosed(); } else { stringResult.Append(Encoding.UTF8.GetString(buffer, 0, result.Count)); } } while (!result.EndOfMessage); return stringResult.ToString(); } public async Task DisconnectAsync() { await webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Closure requested by client", CancellationToken.None); OnSocketClosed(); } public void SendPacket(ArchipelagoPacketBase packet) { SendMultiplePackets(new List<ArchipelagoPacketBase> { packet }); } public void SendMultiplePackets(List<ArchipelagoPacketBase> packets) { SendMultiplePackets(packets.ToArray()); } public void SendMultiplePackets(params ArchipelagoPacketBase[] packets) { SendMultiplePacketsAsync(packets).Wait(); } public Task SendPacketAsync(ArchipelagoPacketBase packet) { return SendMultiplePacketsAsync(new List<ArchipelagoPacketBase> { packet }); } public Task SendMultiplePacketsAsync(List<ArchipelagoPacketBase> packets) { return SendMultiplePacketsAsync(packets.ToArray()); } public Task SendMultiplePacketsAsync(params ArchipelagoPacketBase[] packets) { TaskCompletionSource<bool> taskCompletionSource = new TaskCompletionSource<bool>(); foreach (ArchipelagoPacketBase item in packets) { sendQueue.Add(new Tuple<ArchipelagoPacketBase, TaskCompletionSource<bool>>(item, taskCompletionSource)); } return taskCompletionSource.Task; } private async Task HandleSendBuffer() { List<ArchipelagoPacketBase> list = new List<ArchipelagoPacketBase>(); List<TaskCompletionSource<bool>> tasks = new List<TaskCompletionSource<bool>>(); Tuple<ArchipelagoPacketBase, TaskCompletionSource<bool>> tuple = sendQueue.Take(); list.Add(tuple.Item1); tasks.Add(tuple.Item2); Tuple<ArchipelagoPacketBase, TaskCompletionSource<bool>> item; while (sendQueue.TryTake(out item)) { list.Add(item.Item1); tasks.Add(item.Item2); } if (!list.Any()) { return; } if (webSocket.State != WebSocketState.Open) { throw new ArchipelagoSocketClosedException(); } ArchipelagoPacketBase[] packets = list.ToArray(); string s = JsonConvert.SerializeObject((object)packets); byte[] messageBuffer = Encoding.UTF8.GetBytes(s); int messagesCount = (int)Math.Ceiling((double)messageBuffer.Length / 1024.0); for (int i = 0; i < messagesCount; i++) { int num = 1024 * i; int num2 = 1024; bool endOfMessage = i + 1 == messagesCount; if (num2 * (i + 1) > messageBuffer.Length) { num2 = messageBuffer.Length - num; } await webSocket.SendAsync(new ArraySegment<byte>(messageBuffer, num, num2), WebSocketMessageType.Text, endOfMessage, CancellationToken.None); } foreach (TaskCompletionSource<bool> item2 in tasks) { item2.TrySetResult(result: true); } OnPacketSend(packets); } private void OnPacketSend(ArchipelagoPacketBase[] packets) { try { if (this.PacketsSent != null) { this.PacketsSent(packets); } } catch (Exception e) { OnError(e); } } private void OnSocketClosed() { try { if (this.SocketClosed != null) { this.SocketClosed(""); } } catch (Exception e) { OnError(e); } } private void OnMessageReceived(string message) { try { if (string.IsNullOrEmpty(message) || this.PacketReceived == null) { return; } List<ArchipelagoPacketBase> list = JsonConvert.DeserializeObject<List<ArchipelagoPacketBase>>(message, (JsonConverter[])(object)new JsonConverter[1] { Converter }); if (list == null) { return; } foreach (ArchipelagoPacketBase item in list) { this.PacketReceived(item); } } catch (Exception e) { OnError(e); } } private void OnError(Exception e) { try { if (this.ErrorReceived != null) { this.ErrorReceived(e, e.Message); } } catch (Exception ex) { Console.Out.WriteLine("Error occured during reporting of errorOuter Errror: " + e.Message + " " + e.StackTrace + "Inner Errror: " + ex.Message + " " + ex.StackTrace); } } } internal interface IConnectionInfoProvider { string Game { get; } int Team { get; } int Slot { get; } string[] Tags { get; } ItemsHandlingFlags ItemsHandlingFlags { get; } string Uuid { get; } void UpdateConnectionOptions(string[] tags); void UpdateConnectionOptions(ItemsHandlingFlags itemsHandlingFlags); void UpdateConnectionOptions(string[] tags, ItemsHandlingFlags itemsHandlingFlags); } public class ConnectionInfoHelper : IConnectionInfoProvider { private readonly IArchipelagoSocketHelper socket; public string Game { get; private set; } public int Team { get; private set; } public int Slot { get; private set; } public string[] Tags { get; internal set; } public ItemsHandlingFlags ItemsHandlingFlags { get; internal set; } public string Uuid { get; private set; } internal ConnectionInfoHelper(IArchipelagoSocketHelper socket) { this.socket = socket; Reset(); socket.PacketReceived += PacketReceived; } private void PacketReceived(ArchipelagoPacketBase packet) { if (!(packet is ConnectedPacket connectedPacket)) { if (packet is ConnectionRefusedPacket) { Reset(); } } else { Team = connectedPacket.Team; Slot = connectedPacket.Slot; } } internal void SetConnectionParameters(string game, string[] tags, ItemsHandlingFlags itemsHandlingFlags, string uuid) { Game = game; Tags = tags ?? new string[0]; ItemsHandlingFlags = itemsHandlingFlags; Uuid = uuid ?? Guid.NewGuid().ToString(); } private void Reset() { Game = null; Team = -1; Slot = -1; Tags = new string[0]; ItemsHandlingFlags = ItemsHandlingFlags.NoItems; Uuid = null; } public void UpdateConnectionOptions(string[] tags) { UpdateConnectionOptions(tags, ItemsHandlingFlags); } public void UpdateConnectionOptions(ItemsHandlingFlags itemsHandlingFlags) { UpdateConnectionOptions(Tags, ItemsHandlingFlags); } public void UpdateConnectionOptions(string[] tags, ItemsHandlingFlags itemsHandlingFlags) { SetConnectionParameters(Game, tags, itemsHandlingFlags, Uuid); socket.SendPacket(new ConnectUpdatePacket { Tags = Tags, ItemsHandling = ItemsHandlingFlags }); } } public class DataStorageHelper { public delegate void DataStorageUpdatedHandler(JToken originalValue, JToken newValue); private readonly Dictionary<string, DataStorageUpdatedHandler> onValueChangedEventHandlers = new Dictionary<string, DataStorageUpdatedHandler>(); private readonly Dictionary<Guid, DataStorageUpdatedHandler> operationSpecificCallbacks = new Dictionary<Guid, DataStorageUpdatedHandler>(); private readonly Dictionary<string, TaskCompletionSource<JToken>> asyncRetrievalTasks = new Dictionary<string, TaskCompletionSource<JToken>>(); private readonly IArchipelagoSocketHelper socket; private readonly IConnectionInfoProvider connectionInfoProvider; public DataStorageElement this[Scope scope, string key] { get { return this[AddScope(scope, key)]; } set { this[AddScope(scope, key)] = value; } } public DataStorageElement this[string key] { get { return new DataStorageElement(GetContextForKey(key)); } set { SetValue(key, value); } } internal DataStorageHelper(IArchipelagoSocketHelper socket, IConnectionInfoProvider connectionInfoProvider) { this.socket = socket; this.connectionInfoProvider = connectionInfoProvider; socket.PacketReceived += OnPacketReceived; } private void OnPacketReceived(ArchipelagoPacketBase packet) { if (!(packet is RetrievedPacket retrievedPacket)) { if (packet is SetReplyPacket setReplyPacket) { if (setReplyPacket.Reference.HasValue && operationSpecificCallbacks.TryGetValue(setReplyPacket.Reference.Value, out var value)) { value(setReplyPacket.OriginalValue, setReplyPacket.Value); operationSpecificCallbacks.Remove(setReplyPacket.Reference.Value); } if (onValueChangedEventHandlers.TryGetValue(setReplyPacket.Key, out var value2)) { value2(setReplyPacket.OriginalValue, setReplyPacket.Value); } } return; } foreach (KeyValuePair<string, JToken> datum in retrievedPacket.Data) { if (asyncRetrievalTasks.TryGetValue(datum.Key, out var value3)) { value3.SetResult(datum.Value); asyncRetrievalTasks.Remove(datum.Key); } } } private Task<JToken> GetAsync(string key) { if (asyncRetrievalTasks.TryGetValue(key, out var value)) { return value.Task; } TaskCompletionSource<JToken> taskCompletionSource = new TaskCompletionSource<JToken>(); asyncRetrievalTasks[key] = taskCompletionSource; socket.SendPacketAsync(new GetPacket { Keys = new string[1] { key } }); return taskCompletionSource.Task; } private void Initialize(string key, JToken value) { socket.SendPacketAsync(new SetPacket { Key = key, DefaultValue = value, Operations = new OperationSpecification[1] { new OperationSpecification { OperationType = OperationType.Default } } }); } private JToken GetValue(string key) { Task<JToken> async = GetAsync(key); if (!async.Wait(TimeSpan.FromSeconds(2.0))) { throw new TimeoutException("Timed out retrieving data for key `" + key + "`. This may be due to an attempt to retrieve a value from the DataStorageHelper in a synchronous fashion from within a PacketReceived handler. When using the DataStorageHelper from within code which runs on the websocket thread then use the asynchronous getters. Ex: `DataStorageHelper[\"" + key + "\"].GetAsync().ContinueWith(x => {});`Be aware that DataStorageHelper calls tend to cause packet responses, so making a call from within a PacketReceived handler may cause an infinite loop."); } return async.Result; } private void SetValue(string key, DataStorageElement e) { if (key.StartsWith("_read_")) { throw new InvalidOperationException("DataStorage write operation on readonly key '" + key + "' is not allowed"); } if (e == null) { e = new DataStorageElement(OperationType.Replace, (JToken)(object)JValue.CreateNull()); } if (e.Context == null) { e.Context = GetContextForKey(key); } else if (e.Context.Key != key) { e.Operations.Insert(0, new OperationSpecification { OperationType = OperationType.Replace, Value = GetValue(e.Context.Key) }); } if (e.Callbacks != null) { Guid guid = Guid.NewGuid(); operationSpecificCallbacks[guid] = e.Callbacks; socket.SendPacketAsync(new SetPacket { Key = key, Operations = e.Operations.ToArray(), WantReply = true, Reference = guid }); } else { socket.SendPacketAsync(new SetPacket { Key = key, Operations = e.Operations.ToArray() }); } } private DataStorageElementContext GetContextForKey(string key) { return new DataStorageElementContext { Key = key, GetData = GetValue, GetAsync = GetAsync, Initialize = Initialize, AddHandler = AddHandler, RemoveHandler = RemoveHandler }; } private void AddHandler(string key, DataStorageUpdatedHandler handler) { if (onValueChangedEventHandlers.ContainsKey(key)) { Dictionary<string, DataStorageUpdatedHandler> dictionary = onValueChangedEventHandlers; dictionary[key] = (DataStorageUpdatedHandler)Delegate.Combine(dictionary[key], handler); } else { onValueChangedEventHandlers[key] = handler; } socket.SendPacketAsync(new SetNotifyPacket { Keys = new string[1] { key } }); } private void RemoveHandler(string key, DataStorageUpdatedHandler handler) { if (onValueChangedEventHandlers.ContainsKey(key)) { Dictionary<string, DataStorageUpdatedHandler> dictionary = onValueChangedEventHandlers; dictionary[key] = (DataStorageUpdatedHandler)Delegate.Remove(dictionary[key], handler); if (onValueChangedEventHandlers[key] == null) { onValueChangedEventHandlers.Remove(key); } } } private string AddScope(Scope scope, string key) { return scope switch { Scope.Global => key, Scope.Game => $"{scope}:{connectionInfoProvider.Game}:{key}", Scope.Team => $"{scope}:{connectionInfoProvider.Team}:{key}", Scope.Slot => $"{scope}:{connectionInfoProvider.Slot}:{key}", Scope.ReadOnly => "_read_" + key, _ => throw new ArgumentOutOfRangeException("scope", scope, "Invalid scope for key " + key), }; } private DataStorageElement GetHintsElement(int? slot = null, int? team = null) { return this[Scope.ReadOnly, $"hints_{team ?? connectionInfoProvider.Team}_{slot ?? connectionInfoProvider.Slot}"]; } private DataStorageElement GetSlotDataElement(int? slot = null) { return this[Scope.ReadOnly, $"slot_data_{slot ?? connectionInfoProvider.Slot}"]; } private DataStorageElement GetItemNameGroupsElement(string game = null) { return this[Scope.ReadOnly, "item_name_groups_" + (game ?? connectionInfoProvider.Game)]; } public Hint[] GetHints(int? slot = null, int? team = null) { return GetHintsElement(slot, team).To<Hint[]>(); } public Task<Hint[]> GetHintsAsync(int? slot = null, int? team = null) { return GetHintsElement(slot, team).GetAsync<Hint[]>(); } public void TrackHints(Action<Hint[]> onHintsUpdated, bool retrieveCurrentlyUnlockedHints = true, int? slot = null, int? team = null) { GetHintsElement(slot, team).OnValueChanged += delegate(JToken _, JToken newValue) { onHintsUpdated(newValue.ToObject<Hint[]>()); }; if (retrieveCurrentlyUnlockedHints) { GetHintsAsync(slot, team).ContinueWith(delegate(Task<Hint[]> t) { onHintsUpdated(t.Result); }); } } public Dictionary<string, object> GetSlotData(int? slot = null) { return GetSlotDataElement(slot).To<Dictionary<string, object>>(); } public Task<Dictionary<string, object>> GetSlotDataAsync(int? slot = null) { return GetSlotDataElement(slot).GetAsync<Dictionary<string, object>>(); } public Dictionary<string, string[]> GetItemNameGroups(string game = null) { return GetItemNameGroupsElement(game).To<Dictionary<string, string[]>>(); } public Task<Dictionary<string, string[]>> GetItemNameGroupsAsync(string game = null) { return GetItemNameGroupsElement(game).GetAsync<Dictionary<string, string[]>>(); } } public class ArchipelagoSocketHelperDelagates { public delegate void PacketReceivedHandler(ArchipelagoPacketBase packet); public delegate void PacketsSentHandler(ArchipelagoPacketBase[] packets); public delegate void ErrorReceivedHandler(Exception e, string message); public delegate void SocketClosedHandler(string reason); public delegate void SocketOpenedHandler(); } public interface IArchipelagoSocketHelper { Uri Uri { get; } bool Connected { get; } event ArchipelagoSocketHelperDelagates.PacketReceivedHandler PacketReceived; event ArchipelagoSocketHelperDelagates.PacketsSentHandler PacketsSent; event ArchipelagoSocketHelperDelagates.ErrorReceivedHandler ErrorReceived; event ArchipelagoSocketHelperDelagates.SocketClosedHandler SocketClosed; event ArchipelagoSocketHelperDelagates.SocketOpenedHandler SocketOpened; void SendPacket(ArchipelagoPacketBase packet); void SendMultiplePackets(List<ArchipelagoPacketBase> packets); void SendMultiplePackets(params ArchipelagoPacketBase[] packets); Task ConnectAsync(); Task DisconnectAsync(); Task SendPacketAsync(ArchipelagoPacketBase packet); Task SendMultiplePacketsAsync(List<ArchipelagoPacketBase> packets); Task SendMultiplePacketsAsync(params ArchipelagoPacketBase[] packets); } public interface ILocationCheckHelper { ReadOnlyCollection<long> AllLocations { get; } ReadOnlyCollection<long> AllLocationsChecked { get; } ReadOnlyCollection<long> AllMissingLocations { get; } void CompleteLocationChecks(params long[] ids); Task CompleteLocationChecksAsync(params long[] ids); long GetLocationIdFromName(string game, string locationName); string GetLocationNameFromId(long locationId); } public class LocationCheckHelper : ILocationCheckHelper { public delegate void CheckedLocationsUpdatedHandler(ReadOnlyCollection<long> newCheckedLocations); private readonly IConcurrentHashSet<long> allLocations = new ConcurrentHashSet<long>(); private readonly IConcurrentHashSet<long> locationsChecked = new ConcurrentHashSet<long>(); private readonly IConcurrentHashSet<long> serverConfirmedChecks = new ConcurrentHashSet<long>(); private ReadOnlyCollection<long> missingLocations = new ReadOnlyCollection<long>(new long[0]); private readonly IArchipelagoSocketHelper socket; private readonly IDataPackageCache cache; private bool awaitingLocationInfoPacket; private TaskCompletionSource<LocationInfoPacket> locationInfoPacketCallbackTask; private Dictionary<string, Dictionary<string, long>> gameLocationNameToIdMapping; private Dictionary<long, string> locationIdToNameMapping; public ReadOnlyCollection<long> AllLocations => allLocations.AsToReadOnlyCollection(); public ReadOnlyCollection<long> AllLocationsChecked => locationsChecked.AsToReadOnlyCollection(); public ReadOnlyCollection<long> AllMissingLocations => missingLocations; public event CheckedLocationsUpdatedHandler CheckedLocationsUpdated; internal LocationCheckHelper(IArchipelagoSocketHelper socket, IDataPackageCache cache) { this.socket = socket; this.cache = cache; socket.PacketReceived += Socket_PacketReceived; } private void Socket_PacketReceived(ArchipelagoPacketBase packet) { if (!(packet is ConnectedPacket connectedPacket)) { if (!(packet is RoomUpdatePacket roomUpdatePacket)) { if (!(packet is LocationInfoPacket result)) { if (packet is InvalidPacketPacket invalidPacketPacket && awaitingLocationInfoPacket && invalidPacketPacket.OriginalCmd == ArchipelagoPacketType.LocationScouts) { locationInfoPacketCallbackTask.TrySetException(new ArchipelagoServerRejectedPacketException(invalidPacketPacket.OriginalCmd, invalidPacketPacket.ErrorType, "location scout rejected by the server: " + invalidPacketPacket.ErrorText)); awaitingLocationInfoPacket = false; locationInfoPacketCallbackTask = null; } } else if (awaitingLocationInfoPacket) { if (locationInfoPacketCallbackTask != null) { locationInfoPacketCallbackTask.SetResult(result); } awaitingLocationInfoPacket = false; locationInfoPacketCallbackTask = null; } } else { CheckLocations(roomUpdatePacket.CheckedLocations); if (roomUpdatePacket.CheckedLocations != null) { serverConfirmedChecks.UnionWith(roomUpdatePacket.CheckedLocations); } } } else { allLocations.UnionWith(connectedPacket.LocationsChecked); allLocations.UnionWith(connectedPacket.MissingChecks); serverConfirmedChecks.UnionWith(connectedPacket.LocationsChecked); missingLocations = new ReadOnlyCollection<long>(connectedPacket.MissingChecks); CheckLocations(connectedPacket.LocationsChecked); } } public void CompleteLocationChecks(params long[] ids) { CheckLocations(ids); LocationChecksPacket locationChecksPacket = GetLocationChecksPacket(); if (locationChecksPacket.Locations.Any()) { socket.SendPacket(locationChecksPacket); } } public Task CompleteLocationChecksAsync(params long[] ids) { return Task.Factory.StartNew(delegate { CheckLocations(ids); }).ContinueWith(delegate { if (GetLocationChecksPacket().Locations.Any()) { socket.SendPacketAsync(GetLocationChecksPacket()); } }); } private LocationChecksPacket GetLocationChecksPacket() { return new LocationChecksPacket { Locations = locationsChecked.AsToReadOnlyCollectionExcept(serverConfirmedChecks).ToArray() }; } public Task<LocationInfoPacket> ScoutLocationsAsync(bool createAsHint, params long[] ids) { locationInfoPacketCallbackTask = new TaskCompletionSource<LocationInfoPacket>(); awaitingLocationInfoPacket = true; socket.SendPacket(new LocationScoutsPacket { Locations = ids, CreateAsHint = createAsHint }); return locationInfoPacketCallbackTask.Task; } public Task<LocationInfoPacket> ScoutLocationsAsync(params long[] ids) { return ScoutLocationsAsync(createAsHint: false, ids); } public long GetLocationIdFromName(string game, string locationName) { if (!cache.TryGetDataPackageFromCache(out var package)) { return -1L; } if (gameLocationNameToIdMapping == null) { gameLocationNameToIdMapping = package.Games.ToDictionary((KeyValuePair<string, GameData> x) => x.Key, (KeyValuePair<string, GameData> x) => x.Value.LocationLookup.ToDictionary((KeyValuePair<string, long> y) => y.Key, (KeyValuePair<string, long> y) => y.Value)); } if (!gameLocationNameToIdMapping.TryGetValue(game, out var value)) { return -1L; } if (!value.TryGetValue(locationName, out var value2)) { return -1L; } return value2; } public string GetLocationNameFromId(long locationId) { if (!cache.TryGetDataPackageFromCache(out var package)) { return null; } if (locationIdToNameMapping == null) { locationIdToNameMapping = package.Games.Select((KeyValuePair<string, GameData> x) => x.Value).SelectMany((GameData x) => x.LocationLookup).ToDictionary((KeyValuePair<string, long> x) => x.Value, (KeyValuePair<string, long> x) => x.Key); } if (!locationIdToNameMapping.TryGetValue(locationId, out var value)) { return null; } return value; } private void CheckLocations(ICollection<long> locationIds) { if (locationIds == null || !locationIds.Any()) { return; } List<long> list = new List<long>(); foreach (long locationId in locationIds) { allLocations.TryAdd(locationId); if (locationsChecked.TryAdd(locationId)) { list.Add(locationId); } } missingLocations = allLocations.AsToReadOnlyCollectionExcept(locationsChecked); if (list.Any()) { this.CheckedLocationsUpdated?.Invoke(new ReadOnlyCollection<long>(list)); } } } public class MessageLogHelper { public delegate void MessageReceivedHandler(LogMessage message); private readonly IReceivedItemsHelper items; private readonly ILocationCheckHelper locations; private readonly IPlayerHelper players; private readonly IConnectionInfoProvider connectionInfo; public event MessageReceivedHandler OnMessageReceived; internal MessageLogHelper(IArchipelagoSocketHelper socket, IReceivedItemsHelper items, ILocationCheckHelper locations, IPlayerHelper players, IConnectionInfoProvider connectionInfo) { this.items = items; this.locations = locations; this.players = players; this.connectionInfo = connectionInfo; socket.PacketReceived += Socket_PacketReceived; } private void Socket_PacketReceived(ArchipelagoPacketBase packet) { if (this.OnMessageReceived != null && packet is PrintJsonPacket printJsonPacket) { TriggerOnMessageReceived(printJsonPacket); } } private void TriggerOnMessageReceived(PrintJsonPacket printJsonPacket) { foreach (PrintJsonPacket item in SplitPacketsPerLine(printJsonPacket)) { MessagePart[] parsedData = GetParsedData(item); LogMessage message = ((item is ItemPrintJsonPacket itemPrintJsonPacket) ? new ItemSendLogMessage(parsedData, players, connectionInfo, itemPrintJsonPacket.ReceivingPlayer, itemPrintJsonPacket.Item.Player, itemPrintJsonPacket.Item) : ((item is ItemCheatPrintJsonPacket itemCheatPrintJsonPacket) ? new ItemCheatLogMessage(parsedData, players, connectionInfo, itemCheatPrintJsonPacket.Team, itemCheatPrintJsonPacket.ReceivingPlayer, itemCheatPrintJsonPacket.Item) : ((item is HintPrintJsonPacket hintPrintJsonPacket) ? new HintItemSendLogMessage(parsedData, players, connectionInfo, hintPrintJsonPacket.ReceivingPlayer, hintPrintJsonPacket.Item.Player, hintPrintJsonPacket.Item, hintPrintJsonPacket.Found.HasValue && hintPrintJsonPacket.Found.Value) : ((item is JoinPrintJsonPacket joinPrintJsonPacket) ? new JoinLogMessage(parsedData, players, connectionInfo, joinPrintJsonPacket.Team, joinPrintJsonPacket.Slot, joinPrintJsonPacket.Tags) : ((item is LeavePrintJsonPacket leavePrintJsonPacket) ? new LeaveLogMessage(parsedData, players, connectionInfo, leavePrintJsonPacket.Team, leavePrintJsonPacket.Slot) : ((item is ChatPrintJsonPacket chatPrintJsonPacket) ? new ChatLogMessage(parsedData, players, connectionInfo, chatPrintJsonPacket.Team, chatPrintJsonPacket.Slot, chatPrintJsonPacket.Message) : ((item is ServerChatPrintJsonPacket serverChatPrintJsonPacket) ? new ServerChatLogMessage(parsedData, serverChatPrintJsonPacket.Message) : ((item is TutorialPrintJsonPacket) ? new TutorialLogMessage(parsedData) : ((item is TagsChangedPrintJsonPacket tagsChangedPrintJsonPacket) ? new TagsChangedLogMessage(parsedData, players, connectionInfo, tagsChangedPrintJsonPacket.Team, tagsChangedPrintJsonPacket.Slot, tagsChangedPrintJsonPacket.Tags) : ((item is CommandResultPrintJsonPacket) ? new CommandResultLogMessage(parsedData) : ((item is AdminCommandResultPrintJsonPacket) ? new AdminCommandResultLogMessage(parsedData) : ((item is GoalPrintJsonPacket goalPrintJsonPacket) ? new GoalLogMessage(parsedData, players, connectionInfo, goalPrintJsonPacket.Team, goalPrintJsonPacket.Slot) : ((item is ReleasePrintJsonPacket releasePrintJsonPacket) ? new ReleaseLogMessage(parsedData, players, connectionInfo, releasePrintJsonPacket.Team, releasePrintJsonPacket.Slot) : ((item is CollectPrintJsonPacket collectPrintJsonPacket) ? new CollectLogMessage(parsedData, players, connectionInfo, collectPrintJsonPacket.Team, collectPrintJsonPacket.Slot) : ((!(item is CountdownPrintJsonPacket countdownPrintJsonPacket)) ? new LogMessage(parsedData) : new CountdownLogMessage(parsedData, countdownPrintJsonPacket.RemainingSeconds)))))))))))))))); this.OnMessageReceived?.Invoke(message); } } private static IEnumerable<PrintJsonPacket> SplitPacketsPerLine(PrintJsonPacket printJsonPacket) { List<PrintJsonPacket> list = new List<PrintJsonPacket>(); List<JsonMessagePart> list2 = new List<JsonMessagePart>(); JsonMessagePart[] data = printJsonPacket.Data; foreach (JsonMessagePart jsonMessagePart in data) { string[] array = jsonMessagePart.Text.Split(new char[1] { '\n' }); for (int j = 0; j < array.Length; j++) { string text = array[j]; list2.Add(new JsonMessagePart { Text = text, Type = jsonMessagePart.Type, Color = jsonMessagePart.Color, Flags = jsonMessagePart.Flags, Player = jsonMessagePart.Player }); if (j < array.Length - 1) { PrintJsonPacket printJsonPacket2 = CloneWithoutData(printJsonPacket); printJsonPacket2.Data = list2.ToArray(); list.Add(printJsonPacket2); list2 = new List<JsonMessagePart>(); } } } PrintJsonPacket printJsonPacket3 = CloneWithoutData(printJsonPacket); printJsonPacket3.Data = list2.ToArray(); list.Add(printJsonPacket3); return list; } private static PrintJsonPacket CloneWithoutData(PrintJsonPacket source) { if (!(source is ItemPrintJsonPacket itemPrintJsonPacket)) { if (!(source is ItemCheatPrintJsonPacket itemCheatPrintJsonPacket)) { if (!(source is HintPrintJsonPacket hintPrintJsonPacket)) { if (!(source is JoinPrintJsonPacket joinPrintJsonPacket)) { if (!(source is LeavePrintJsonPacket leavePrintJsonPacket)) { if (!(source is ChatPrintJsonPacket chatPrintJsonPacket)) { if (!(source is ServerChatPrintJsonPacket serverChatPrintJsonPacket)) { if (!(source is TutorialPrintJsonPacket tutorialPrintJsonPacket)) { if (!(source is TagsChangedPrintJsonPacket tagsChangedPrintJsonPacket)) { if (!(source is CommandResultPrintJsonPacket commandResultPrintJsonPacket)) { if (!(source is AdminCommandResultPrintJsonPacket adminCommandResultPrintJsonPacket)) { if (!(source is GoalPrintJsonPacket goalPrintJsonPacket)) { if (!(source is ReleasePrintJsonPacket releasePrintJsonPacket)) { if (!(source is CollectPrintJsonPacket collectPrintJsonPacket)) { if (source is CountdownPrintJsonPacket countdownPrintJsonPacket) { return new CountdownPrintJsonPacket { RemainingSeconds = countdownPrintJsonPacket.RemainingSeconds }; } return new PrintJsonPacket { MessageType = source.MessageType }; } return new CollectPrintJsonPacket { MessageType = collectPrintJsonPacket.MessageType, Team = collectPrintJsonPacket.Team, Slot = collectPrintJsonPacket.Slot }; } return new ReleasePrintJsonPacket { MessageType = releasePrintJsonPacket.MessageType, Team = releasePrintJsonPacket.Team, Slot = releasePrintJsonPacket.Slot }; } return new GoalPrintJsonPacket { MessageType = goalPrintJsonPacket.MessageType, Team = goalPrintJsonPacket.Team, Slot = goalPrintJsonPacket.Slot }; } return new AdminCommandResultPrintJsonPacket { MessageType = adminCommandResultPrintJsonPacket.MessageType }; } return new CommandResultPrintJsonPacket { MessageType = commandResultPrintJsonPacket.MessageType }; } return new TagsChangedPrintJsonPacket { MessageType = tagsChangedPrintJsonPacket.MessageType, Team = tagsChangedPrintJsonPacket.Team, Slot = tagsChangedPrintJsonPacket.Slot, Tags = tagsChangedPrintJsonPacket.Tags }; } return new TutorialPrintJsonPacket { MessageType = tutorialPrintJsonPacket.MessageType }; } return new ServerChatPrintJsonPacket { MessageType = serverChatPrintJsonPacket.MessageType, Message = serverChatPrintJsonPacket.Message }; } return new ChatPrintJsonPacket { MessageType = chatPrintJsonPacket.MessageType, Team = chatPrintJsonPacket.Team, Slot = chatPrintJsonPacket.Slot, Message = chatPrintJsonPacket.Message }; } return new LeavePrintJsonPacket { MessageType = leavePrintJsonPacket.MessageType, Team = leavePrintJsonPacket.Team, Slot = leavePrintJsonPacket.Slot }; } return new JoinPrintJsonPacket { MessageType = joinPrintJsonPacket.MessageType, Team = joinPrintJsonPacket.Team, Slot = joinPrintJsonPacket.Slot, Tags = joinPrintJsonPacket.Tags }; } return new HintPrintJsonPacket { MessageType = hintPrintJsonPacket.MessageType, ReceivingPlayer = hintPrintJsonPacket.ReceivingPlayer, Item = hintPrintJsonPacket.Item, Found = hintPrintJsonPacket.Found }; } return new ItemCheatPrintJsonPacket { MessageType = itemCheatPrintJsonPacket.MessageType, ReceivingPlayer = itemCheatPrintJsonPacket.ReceivingPlayer, Item = itemCheatPrintJsonPacket.Item, Team = itemCheatPrintJsonPacket.Team }; } return new ItemPrintJsonPacket { MessageType = itemPrintJsonPacket.MessageType, ReceivingPlayer = itemPrintJsonPacket.ReceivingPlayer, Item = itemPrintJsonPacket.Item }; } internal MessagePart[] GetParsedData(PrintJsonPacket packet) { return packet.Data.Select(GetMessagePart).ToArray(); } private MessagePart GetMessagePart(JsonMessagePart part) { switch (part.Type) { case JsonMessagePartType.ItemId: case JsonMessagePartType.ItemName: return new ItemMessagePart(items, part); case JsonMessagePartType.PlayerId: case JsonMessagePartType.PlayerName: return new PlayerMessagePart(players, connectionInfo, part); case JsonMessagePartType.LocationId: case JsonMessagePartType.LocationName: return new LocationMessagePart(locations, part); case JsonMessagePartType.EntranceName: return new EntranceMessagePart(part); default: return new MessagePart(MessagePartType.Text, part); } } } public interface IPlayerHelper { ReadOnlyDictionary<int, ReadOnlyCollection<PlayerInfo>> Players { get; } IEnumerable<PlayerInfo> AllPlayers { get; } string GetPlayerAlias(int slot); string GetPlayerName(int slot); string GetPlayerAliasAndName(int slot); } public class PlayerHelper : IPlayerHelper { private readonly IConnectionInfoProvider connectionInfo; private ReadOnlyDictionary<int, ReadOnlyCollection<PlayerInfo>> players = new ReadOnlyDictionary<int, ReadOnlyCollection<PlayerInfo>>(new Dictionary<int, ReadOnlyCollection<PlayerInfo>>(0)); public ReadOnlyDictionary<int, ReadOnlyCollection<PlayerInfo>> Players => players; public IEnumerable<PlayerInfo> AllPlayers => players.SelectMany((KeyValuePair<int, ReadOnlyCollection<PlayerInfo>> kvp) => kvp.Value); internal PlayerHelper(IArchipelagoSocketHelper socket, IConnectionInfoProvider connectionInfo) { this.connectionInfo = connectionInfo; socket.PacketReceived += PacketReceived; } public string GetPlayerAlias(int slot) { if (players == null) { return null; } return players[connectionInfo.Team].FirstOrDefault((PlayerInfo p) => p.Slot == slot)?.Alias; } public string GetPlayerName(int slot) { if (players == null) { return null; } return players[connectionInfo.Team].FirstOrDefault((PlayerInfo p) => p.Slot == slot)?.Name; } public string GetPlayerAliasAndName(int slot) { if (players == null) { return null; } PlayerInfo playerInfo = players[connectionInfo.Team].FirstOrDefault((PlayerInfo p) => p.Slot == slot); if (playerInfo == null) { return null; } return playerInfo.Alias + " (" + playerInfo.Name + ")"; } private void PacketReceived(ArchipelagoPacketBase packet) { if (!(packet is ConnectedPacket connectedPacket)) { if (packet is RoomUpdatePacket roomUpdatePacket) { UpdatePlayerInfo(roomUpdatePacket.Players); } } else { CreatePlayerInfo(connectedPacket.Players, connectedPacket.SlotInfo); } } private void CreatePlayerInfo(NetworkPlayer[] networkPlayers, Dictionary<int, NetworkSlot> slotInfos) { NetworkSlot[] source = ((slotInfos == null) ? new NetworkSlot[0] : slotInfos.Values.Where((NetworkSlot s) => s.Type == SlotType.Group).ToArray()); int num = 0; int num2 = 0; NetworkPlayer[] array = networkPlayers; for (int i = 0; i < array.Length; i++) { NetworkPlayer networkPlayer = array[i]; if (networkPlayer.Team > num) { num = networkPlayer.Team; } if (networkPlayer.Slot > num2) { num2 = networkPlayer.Slot; } } Dictionary<int, PlayerInfo[]> dictionary = new Dictionary<int, PlayerInfo[]>(num); for (int j = 0; j <= num; j++) { dictionary[j] = new PlayerInfo[num2 + 1]; dictionary[j][0] = new PlayerInfo { Team = j, Slot = 0, Name = "Server", Alias = "Server", Game = "Archipelago", Groups = new NetworkSlot[0] }; } array = networkPlayers; for (int i = 0; i < array.Length; i++) { NetworkPlayer p = array[i]; dictionary[p.Team][p.Slot] = new PlayerInfo { Team = p.Team, Slot = p.Slot, Name = p.Name, Alias = p.Alias, Game = slotInfos?[p.Slot].Game, Groups = source.Where((NetworkSlot g) => g.GroupMembers.Contains(p.Slot)).ToArray() }; } Dictionary<int, ReadOnlyCollection<PlayerInfo>> dictionary2 = new Dictionary<int, ReadOnlyCollection<PlayerInfo>>(dictionary.Count); foreach (KeyValuePair<int, PlayerInfo[]> item in dictionary) { dictionary2[item.Key] = new ReadOnlyCollection<PlayerInfo>(item.Value); } players = new ReadOnlyDictionary<int, ReadOnlyCollection<PlayerInfo>>(dictionary2); } private void UpdatePlayerInfo(NetworkPlayer[] networkPlayers) { if (networkPlayers != null && networkPlayers.Length != 0) { for (int i = 0; i < networkPlayers.Length; i++) { NetworkPlayer networkPlayer = networkPlayers[i];
ArchipelagoULTRAKILL.dll
Decompiled 2 weeks ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.CodeDom.Compiler; using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Resources; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Text; using Archipelago.MultiClient.Net; using Archipelago.MultiClient.Net.BounceFeatures.DeathLink; using Archipelago.MultiClient.Net.Enums; using Archipelago.MultiClient.Net.Helpers; using Archipelago.MultiClient.Net.Models; using Archipelago.MultiClient.Net.Packets; using ArchipelagoULTRAKILL.Commands; using ArchipelagoULTRAKILL.Components; using ArchipelagoULTRAKILL.Powerups; using ArchipelagoULTRAKILL.Properties; using ArchipelagoULTRAKILL.Structures; using BepInEx; using BepInEx.Logging; using GameConsole; using HarmonyLib; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using PluginConfig.API; using PluginConfig.API.Decorators; using PluginConfig.API.Fields; using PluginConfig.API.Functionals; using TMPro; using UnityEngine; using UnityEngine.AddressableAssets; using UnityEngine.AddressableAssets.ResourceLocators; using UnityEngine.EventSystems; using UnityEngine.Events; using UnityEngine.Networking; using UnityEngine.SceneManagement; using UnityEngine.UI; using plog; using plog.Models; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("ArchipelagoULTRAKILL")] [assembly: AssemblyDescription("Connect to an Archipelago server to play ULTRAKILL randomizer.")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("ArchipelagoULTRAKILL")] [assembly: AssemblyCopyright("Copyright © TRPG 2024")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("c7de03cb-cf51-44da-ba1f-6fcecd638e0a")] [assembly: AssemblyFileVersion("2.0.7")] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyVersion("2.0.7.0")] namespace ArchipelagoULTRAKILL { public static class AudioManager { private static readonly Dictionary<string, string> multiMusicBattle = new Dictionary<string, string> { ["1"] = "Assets/Music/0-1.wav", ["2"] = "Assets/Music/0-2.wav", ["3"] = "Assets/Music/0-1.wav", ["4"] = "Assets/Music/0-2.wav", ["6B"] = "Assets/Music/1-1.wav", ["7B"] = "Assets/Music/1-2 Noise Battle.wav", ["8"] = "Assets/Music/1-3.wav", ["10"] = "Assets/Music/2-1.wav", ["11"] = "Assets/Music/2-2.wav", ["12"] = "Assets/Music/2-3.wav", ["14A"] = "Assets/Music/3-1 Guts.wav", ["14B"] = "Assets/Music/3-1 Glory.wav", ["16"] = "Assets/Music/4-1.wav", ["17"] = "Assets/Music/4-2.wav", ["18A"] = "Assets/Music/4-3 Phase 1.wav", ["18B"] = "Assets/Music/4-3 Phase 2.wav", ["18C"] = "Assets/Music/4-3 Phase 3.wav", ["20"] = "Assets/Music/5-1.wav", ["22A"] = "Assets/Music/5-3.wav", ["22B"] = "Assets/Music/5-3 Aftermath.wav", ["24A"] = "Assets/Music/6-1.wav", ["26B"] = "Assets/Music/7-1.wav", ["27A"] = "Assets/Music/7-2 Intro Battle.wav", ["27B"] = "Assets/Music/7-2.wav", ["28B"] = "Assets/Music/7-3.wav", ["667A"] = "Assets/Music/P-2.wav" }; private static readonly Dictionary<string, string> multiMusicClean = new Dictionary<string, string> { ["1"] = "Assets/Music/0-1 Clean.wav", ["2"] = "Assets/Music/0-2 Clean.wav", ["3"] = "Assets/Music/0-1 Clean.wav", ["4"] = "Assets/Music/0-2 Clean.wav", ["6B"] = "Assets/Music/1-1 Clean.wav", ["7B"] = "Assets/Music/1-2 Noise Clean.wav", ["8"] = "Assets/Music/1-3 Clean.wav", ["10"] = "Assets/Music/2-1 Clean.wav", ["11"] = "Assets/Music/2-2 Clean.wav", ["12"] = "Assets/Music/2-3 Clean.wav", ["14A"] = "Assets/Music/3-1 Guts Clean.wav", ["14B"] = "Assets/Music/3-1 Glory Clean.wav", ["16"] = "Assets/Music/4-1 Clean.wav", ["17"] = "Assets/Music/4-2 Clean.wav", ["18A"] = "Assets/Music/4-3 Phase 1 Clean.wav", ["18B"] = "Assets/Music/4-3 Phase 2 Clean.wav", ["18C"] = "Assets/Music/4-3 Phase 3.wav", ["20"] = "Assets/Music/5-1 Clean.wav", ["22A"] = "Assets/Music/5-3 Clean.wav", ["22B"] = "Assets/Music/5-3 Aftermath Clean.wav", ["24A"] = "Assets/Music/6-1 Clean.wav", ["26B"] = "Assets/Music/7-1 Clean.wav", ["27A"] = "Assets/Music/7-2 Intro Clean.wav", ["27B"] = "Assets/Music/7-2 Clean.wav", ["28B"] = "Assets/Music/7-3 Clean.wav", ["667A"] = "Assets/Music/P-2 Clean.wav" }; private static readonly Dictionary<string, string> singleMusic = new Dictionary<string, string> { ["5"] = "Assets/Music/Bosses/Cerberus A.mp3", ["6A"] = "Assets/Music/Misc/A Thousand Greetings.wav", ["7A"] = "Assets/Music/Misc/A Thousand Greetings.wav", ["9A"] = "Assets/Music/Misc/Clair_de_lune_(Claude_Debussy)_Suite_bergamasque (CREATIVE COMMONS).ogg", ["9B"] = "Assets/Music/Bosses/V2 1-4.wav", ["13"] = "Assets/Music/Bosses/Minos Corpse B.wav", ["15A"] = "Assets/Music/Bosses/Gabriel 3-2 Intro.wav", ["15B"] = "Assets/Music/Bosses/Gabriel 3-2.wav", ["18D"] = "Assets/Music/Misc/themeofcancer.wav", ["19"] = "Assets/Music/Bosses/V2 4-4.wav", ["24B"] = "Assets/Music/6-1 Hall of Sacreligious Remains.wav", ["25A"] = "Assets/Music/Bosses/Gabriel 6-2 Intro B.wav", ["25B"] = "Assets/Music/Bosses/Gabriel 6-2.wav", ["26A"] = "Assets/Music/7-1 Intro.wav", ["26C"] = "Assets/Music/Misc/themeofcancer.wav", ["26D"] = "Assets/Music/Bosses/Minotaur A.wav", ["26E"] = "Assets/Music/Bosses/Minotaur B.wav", ["28A"] = "Assets/Music/7-3 Intro Clean.wav", ["666A"] = "Assets/Music/Bosses/Flesh Prison.wav", ["666B"] = "Assets/Music/Bosses/Minos Prime.wav", ["667B"] = "Assets/Music/Bosses/Flesh panopticon.wav", ["667C"] = "Assets/Music/Bosses/Sisyphus Prime.wav" }; public static AudioClip LoadNewSingleTrack(AudioClip source, string id) { //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) if (Core.data.music.ContainsKey(id)) { id = Core.data.music[id]; if (singleMusic.ContainsKey(id)) { try { return Addressables.LoadAssetAsync<AudioClip>((object)singleMusic[id]).WaitForCompletion(); } catch { Core.Logger.LogError((object)("Failed to load music track. (ID: " + id + " | Address: " + singleMusic[id])); return source; } } Core.Logger.LogError((object)("Couldn't find address for key " + id + ". Returning original source.")); return source; } Core.Logger.LogError((object)("Music dictionary does not contain key " + id + ". Returning original source.")); return source; } public static AudioClip LoadNewCleanTrack(AudioClip source, string id) { //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) if (Core.data.music.ContainsKey(id)) { id = Core.data.music[id]; if (multiMusicClean.ContainsKey(id)) { try { return Addressables.LoadAssetAsync<AudioClip>((object)multiMusicClean[id]).WaitForCompletion(); } catch { Core.Logger.LogError((object)("Failed to load music track. (ID: " + id + " | Address: " + multiMusicClean[id])); return source; } } Core.Logger.LogError((object)("Couldn't find address for key " + id + ". Returning original source.")); return source; } Core.Logger.LogError((object)("Music dictionary does not contain key " + id + ". Returning original source.")); return source; } public static AudioClip LoadNewBattleTrack(AudioClip source, string id) { //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) if (Core.data.music.ContainsKey(id)) { id = Core.data.music[id]; if (multiMusicBattle.ContainsKey(id)) { try { return Addressables.LoadAssetAsync<AudioClip>((object)multiMusicBattle[id]).WaitForCompletion(); } catch { Core.Logger.LogError((object)("Failed to load music track. (ID: " + id + " | Address: " + multiMusicBattle[id])); return source; } } Core.Logger.LogError((object)("Couldn't find address for key " + id + ". Returning original source.")); return source; } Core.Logger.LogError((object)("Music dictionary does not contain key " + id + ". Returning original source.")); return source; } public static void LoadMusicManagerTracks(string id, bool single = false) { if (single) { MonoSingleton<MusicManager>.Instance.cleanTheme.clip = LoadNewSingleTrack(MonoSingleton<MusicManager>.Instance.cleanTheme.clip, id); MonoSingleton<MusicManager>.Instance.battleTheme.clip = LoadNewSingleTrack(MonoSingleton<MusicManager>.Instance.battleTheme.clip, id); MonoSingleton<MusicManager>.Instance.bossTheme.clip = LoadNewSingleTrack(MonoSingleton<MusicManager>.Instance.bossTheme.clip, id); } else { MonoSingleton<MusicManager>.Instance.cleanTheme.clip = LoadNewCleanTrack(MonoSingleton<MusicManager>.Instance.cleanTheme.clip, id); MonoSingleton<MusicManager>.Instance.battleTheme.clip = LoadNewBattleTrack(MonoSingleton<MusicManager>.Instance.battleTheme.clip, id); MonoSingleton<MusicManager>.Instance.bossTheme.clip = LoadNewBattleTrack(MonoSingleton<MusicManager>.Instance.bossTheme.clip, id); } } public static void ChangeMusic() { if (Core.CurrentLevelInfo.Music == MusicType.Normal) { LoadMusicManagerTracks(Core.CurrentLevelInfo.Id.ToString()); } else { switch (SceneHelper.CurrentScene) { default: return; case "Level 0-5": foreach (AudioSource item in Core.FindAllComponentsInCurrentScene<AudioSource>()) { if ((Object)(object)((Component)item).transform.parent != (Object)null && (((Object)((Component)item).transform.parent).name == "4 Contents" || ((Object)((Component)item).transform.parent).name == "4 Contents(Clone)") && ((Object)((Component)item).transform).name == "Music") { item.clip = LoadNewSingleTrack(item.clip, "5"); ((Component)((Component)item).transform.parent.Find("Enemies").Find("StatueEnemy (1)")).GetComponent<SoundChanger>().newSound = LoadNewSingleTrack(item.clip, "5"); } } break; case "Level 1-1": LoadMusicManagerTracks("6A", single: true); foreach (MusicChanger item2 in Core.FindAllComponentsInCurrentScene<MusicChanger>()) { if (((Object)((Component)item2).gameObject).name == "MusicChanger") { item2.clean = LoadNewCleanTrack(item2.clean, "6B"); item2.battle = LoadNewBattleTrack(item2.battle, "6B"); } } break; case "Level 1-2": LoadMusicManagerTracks("7A", single: true); foreach (MusicChanger item3 in Core.FindAllComponentsInCurrentScene<MusicChanger>()) { if (((Object)((Component)item3).gameObject).name == "MusicActivator") { item3.clean = LoadNewCleanTrack(item3.clean, "7B"); item3.battle = LoadNewBattleTrack(item3.battle, "7B"); } } break; case "Level 1-4": foreach (AudioSource item4 in Core.FindAllComponentsInCurrentScene<AudioSource>()) { if (((Object)((Component)item4).gameObject).name == "Music - Clair de Lune") { item4.clip = LoadNewSingleTrack(item4.clip, "9A"); } else if (((Object)((Component)item4).gameObject).name == "Music - Versus") { item4.clip = LoadNewSingleTrack(item4.clip, "9B"); } } break; case "Level 2-1": foreach (MusicChanger item5 in Core.FindAllComponentsInCurrentScene<MusicChanger>()) { if (((Object)((Component)item5).gameObject).name == "Cube (1)") { item5.clean = LoadNewCleanTrack(item5.clean, "10"); item5.battle = LoadNewBattleTrack(item5.battle, "10"); } } break; case "Level 2-4": foreach (AudioSource item6 in Core.FindAllComponentsInCurrentScene<AudioSource>()) { if (((Object)((Component)item6).gameObject).name == "BossMusic") { item6.clip = LoadNewSingleTrack(item6.clip, "13"); } } break; case "Level 3-1": LoadMusicManagerTracks("14A"); foreach (MusicChanger item7 in Core.FindAllComponentsInCurrentScene<MusicChanger>()) { if (((Object)((Component)item7).gameObject).name == "MusicChanger") { item7.clean = LoadNewCleanTrack(item7.clean, "14B"); item7.battle = LoadNewBattleTrack(item7.battle, "14B"); } } break; case "Level 3-2": foreach (AudioSource item8 in Core.FindAllComponentsInCurrentScene<AudioSource>()) { if (((Object)((Component)item8).gameObject).name == "Music 2") { item8.clip = LoadNewSingleTrack(item8.clip, "15A"); } else if (((Object)((Component)item8).gameObject).name == "Music 3") { item8.clip = LoadNewSingleTrack(item8.clip, "15B"); } } break; case "Level 4-3": foreach (MusicChanger item9 in Core.FindAllComponentsInCurrentScene<MusicChanger>()) { if (((Object)((Component)item9).gameObject).name == "OnLight") { item9.clean = LoadNewCleanTrack(item9.clean, "18A"); item9.battle = LoadNewBattleTrack(item9.battle, "18A"); } else if (((Object)((Component)item9).gameObject).name == "Music Changer") { item9.clean = LoadNewCleanTrack(item9.clean, "18B"); item9.battle = LoadNewBattleTrack(item9.battle, "18B"); } else if (((Object)((Component)item9).gameObject).name == "Music Changer (Normal)") { item9.clean = LoadNewCleanTrack(item9.clean, "18B"); item9.battle = LoadNewBattleTrack(item9.battle, "18B"); } else if (((Object)((Component)item9).gameObject).name == "Music") { item9.clean = LoadNewCleanTrack(item9.clean, "18C"); item9.battle = LoadNewBattleTrack(item9.battle, "18C"); } else if (((Object)((Component)item9).gameObject).name == "Trigger (Fight)") { item9.clean = LoadNewSingleTrack(item9.clean, "18D"); item9.battle = LoadNewSingleTrack(item9.battle, "18D"); item9.boss = LoadNewSingleTrack(item9.boss, "18D"); } } break; case "Level 4-4": foreach (AudioSource item10 in Core.FindAllComponentsInCurrentScene<AudioSource>()) { if (((Object)((Component)item10).gameObject).name == "Versus 2") { item10.clip = LoadNewSingleTrack(item10.clip, "19"); } } break; case "Level 5-3": LoadMusicManagerTracks("22A"); foreach (MusicChanger item11 in Core.FindAllComponentsInCurrentScene<MusicChanger>()) { if (((Object)((Component)item11).gameObject).name == "InstantVer") { item11.clean = LoadNewCleanTrack(item11.clean, "22B"); item11.battle = LoadNewBattleTrack(item11.battle, "22B"); } else if (((Object)((Component)item11).gameObject).name == "NormalVer") { item11.clean = LoadNewCleanTrack(item11.clean, "22B"); item11.battle = LoadNewBattleTrack(item11.battle, "22B"); } } break; case "Level 6-1": foreach (MusicChanger item12 in Core.FindAllComponentsInCurrentScene<MusicChanger>()) { if (((Object)((Component)item12).gameObject).name == "MusicChanger") { item12.clean = LoadNewCleanTrack(item12.clean, "24A"); item12.battle = LoadNewBattleTrack(item12.battle, "24A"); } } foreach (AudioSource item13 in Core.FindAllComponentsInCurrentScene<AudioSource>()) { if (((Object)((Component)item13).gameObject).name == "ClimaxMusic") { item13.clip = LoadNewSingleTrack(item13.clip, "24B"); } } break; case "Level 6-2": foreach (AudioSource item14 in Core.FindAllComponentsInCurrentScene<AudioSource>()) { if (((Object)((Component)item14).gameObject).name == "Organ") { item14.clip = LoadNewSingleTrack(item14.clip, "25A"); } else if (((Object)((Component)item14).gameObject).name == "BossMusic") { item14.clip = LoadNewSingleTrack(item14.clip, "25B"); } } break; case "Level 7-1": foreach (MusicChanger item15 in Core.FindAllComponentsInCurrentScene<MusicChanger>()) { if (((Object)item15).name == "LevelMusicStart") { item15.clean = LoadNewCleanTrack(item15.clean, "26B"); item15.battle = LoadNewBattleTrack(item15.battle, "26B"); item15.boss = LoadNewBattleTrack(item15.battle, "26B"); } } foreach (AudioSource item16 in Core.FindAllComponentsInCurrentScene<AudioSource>()) { if (((Object)item16).name == "IntroMusic") { item16.clip = LoadNewSingleTrack(item16.clip, "26A"); } else if (((Object)item16).name == "BigJohnatronMusic") { item16.clip = LoadNewSingleTrack(item16.clip, "26C"); } else if (((Object)item16).name == "MinotaurPhase1Music") { item16.clip = LoadNewSingleTrack(item16.clip, "26D"); } else if (((Object)item16).name == "MinotaurPhase2Music") { item16.clip = LoadNewSingleTrack(item16.clip, "26E"); } } break; case "Level 7-2": LoadMusicManagerTracks("27A"); foreach (MusicChanger item17 in Core.FindAllComponentsInCurrentScene<MusicChanger>()) { if (((Object)item17).name == "MusicActivator") { item17.clean = LoadNewCleanTrack(item17.clean, "27B"); item17.battle = LoadNewBattleTrack(item17.battle, "27B"); item17.boss = LoadNewBattleTrack(item17.battle, "27B"); } } break; case "Level 7-3": LoadMusicManagerTracks("28A", single: true); foreach (MusicChanger item18 in Core.FindAllComponentsInCurrentScene<MusicChanger>()) { if (((Object)item18).name == "SecondTrackStart") { item18.clean = LoadNewCleanTrack(item18.clean, "28B"); item18.battle = LoadNewBattleTrack(item18.battle, "28B"); item18.boss = LoadNewBattleTrack(item18.battle, "28B"); } } break; case "Level P-1": foreach (AudioSource item19 in Core.FindAllComponentsInCurrentScene<AudioSource>()) { if (((Object)((Component)item19).gameObject).name == "Chaos") { item19.clip = LoadNewSingleTrack(item19.clip, "666A"); } else if (((Object)((Component)item19).gameObject).name == "Music 3") { item19.clip = LoadNewSingleTrack(item19.clip, "666B"); } } break; case "Level P-2": foreach (MusicChanger item20 in Core.FindAllComponentsInCurrentScene<MusicChanger>()) { if (((Object)((Component)item20).gameObject).name == "DelayedMusicActivator") { item20.clean = LoadNewCleanTrack(item20.clean, "667A"); item20.battle = LoadNewBattleTrack(item20.battle, "667A"); item20.boss = LoadNewBattleTrack(item20.battle, "667A"); } } foreach (AudioSource item21 in Core.FindAllComponentsInCurrentScene<AudioSource>()) { if (((Object)((Component)item21).gameObject).name == "FleshPrison") { item21.clip = LoadNewSingleTrack(item21.clip, "667B"); } else if (((Object)((Component)item21).gameObject).name == "Sisyphus") { item21.clip = LoadNewSingleTrack(item21.clip, "667C"); } } break; } } Core.Logger.LogInfo((object)"Music changed successfully."); } } public static class ColorRandomizer { public static void RandomizeGunColors() { MonoSingleton<PrefsManager>.Instance.SetBool("gunColorType.1", true); MonoSingleton<PrefsManager>.Instance.SetBool("gunColorType.1.a", true); MonoSingleton<PrefsManager>.Instance.SetBool("gunColorType.2", true); MonoSingleton<PrefsManager>.Instance.SetBool("gunColorType.3", true); MonoSingleton<PrefsManager>.Instance.SetBool("gunColorType.3.a", true); MonoSingleton<PrefsManager>.Instance.SetBool("gunColorType.4", true); MonoSingleton<PrefsManager>.Instance.SetBool("gunColorType.5", true); for (int i = 1; i <= 5; i++) { for (int j = 1; j <= 2; j++) { if (j != 2 || (i != 2 && i != 4 && i != 5)) { bool flag = false; if (j == 2) { flag = true; } for (int k = 1; k <= 3; k++) { MonoSingleton<PrefsManager>.Instance.SetFloat(string.Concat(new object[6] { "gunColor.", i.ToString(), ".", k.ToString(), flag ? ".a" : ".", "r" }), Random.Range(0f, 1f)); MonoSingleton<PrefsManager>.Instance.SetFloat(string.Concat(new object[6] { "gunColor.", i.ToString(), ".", k.ToString(), flag ? ".a" : ".", "g" }), Random.Range(0f, 1f)); MonoSingleton<PrefsManager>.Instance.SetFloat(string.Concat(new object[6] { "gunColor.", i.ToString(), ".", k.ToString(), flag ? ".a" : ".", "b" }), Random.Range(0f, 1f)); MonoSingleton<PrefsManager>.Instance.SetFloat(string.Concat(new object[6] { "gunColor.", i.ToString(), ".", k.ToString(), flag ? ".a" : ".", "a" }), Random.Range(0f, 1f)); } } } } if (Core.IsPlaying) { MonoSingleton<GunColorController>.Instance.UpdateGunColors(); GunColorTypeGetter[] array = Object.FindObjectsOfType<GunColorTypeGetter>(); foreach (GunColorTypeGetter val in array) { val.UpdatePreview(); } } } public static void RandomizeUIColors() { for (int i = 1; i <= 3; i++) { string text = ".r"; if (i == 2) { text = ".g"; } if (i == 3) { text = ".b"; } MonoSingleton<PrefsManager>.Instance.SetFloat("hudColor.hp" + text, Random.Range(0f, 1f)); MonoSingleton<PrefsManager>.Instance.SetFloat("hudColor.hptext" + text, Random.Range(0f, 1f)); MonoSingleton<PrefsManager>.Instance.SetFloat("hudColor.hpaft" + text, Random.Range(0f, 1f)); MonoSingleton<PrefsManager>.Instance.SetFloat("hudColor.hphdmg" + text, Random.Range(0f, 1f)); MonoSingleton<PrefsManager>.Instance.SetFloat("hudColor.hpover" + text, Random.Range(0f, 1f)); MonoSingleton<PrefsManager>.Instance.SetFloat("hudColor.stm" + text, Random.Range(0f, 1f)); MonoSingleton<PrefsManager>.Instance.SetFloat("hudColor.stmchr" + text, Random.Range(0f, 1f)); MonoSingleton<PrefsManager>.Instance.SetFloat("hudColor.stmemp" + text, Random.Range(0f, 1f)); MonoSingleton<PrefsManager>.Instance.SetFloat("hudColor.raifull" + text, Random.Range(0f, 1f)); MonoSingleton<PrefsManager>.Instance.SetFloat("hudColor.raicha" + text, Random.Range(0f, 1f)); MonoSingleton<PrefsManager>.Instance.SetFloat("hudColor.var0" + text, Random.Range(0f, 1f)); MonoSingleton<PrefsManager>.Instance.SetFloat("hudColor.var1" + text, Random.Range(0f, 1f)); MonoSingleton<PrefsManager>.Instance.SetFloat("hudColor.var2" + text, Random.Range(0f, 1f)); MonoSingleton<PrefsManager>.Instance.SetFloat("hudColor.var3" + text, Random.Range(0f, 1f)); } if (Core.IsPlaying) { MonoSingleton<ColorBlindSettings>.Instance.UpdateHudColors(); MonoSingleton<ColorBlindSettings>.Instance.UpdateWeaponColors(); } } } public static class ConfigManager { [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static OnClick <>9__65_0; public static OnClick <>9__65_1; public static OnClick <>9__65_2; public static OnClick <>9__65_3; public static PostStringValueChangeEvent <>9__65_4; public static BoolValueChangeEventDelegate <>9__65_5; public static IntValueChangeEventDelegate <>9__65_6; public static IntValueChangeEventDelegate <>9__65_7; public static OnClick <>9__65_8; public static OnClick <>9__65_9; public static OnClick <>9__65_10; public static OnClick <>9__65_11; internal void <Initialize>b__65_0() { if (Multiworld.Authenticated) { connectionInfo.text = "Already connected to server."; } else if (SceneHelper.CurrentScene != "Main Menu") { connectionInfo.text = "Can only connect to an Archipelago server on the main menu."; } else if ((GameProgressSaver.GetTutorial() || GameProgressSaver.GetIntro()) && !Core.DataExists() && !hintMode.value) { connectionInfo.text = "No Archipelago data found. Start a new save file before connecting."; } else if (Core.DataExists() && hintMode.value) { connectionInfo.text = "Can't use hint mode on a save file that already has randomizer data."; } else if (!Multiworld.Authenticated) { Core.data.slot_name = playerName.value; Core.data.host_name = serverAddress.value; Core.data.password = serverPassword.value; if (Core.data.password == "") { Core.data.password = null; } if (hintMode.value) { Multiworld.ConnectBK(); } else { Multiworld.Connect(); } } } internal void <Initialize>b__65_1() { //IL_003f: Unknown result type (might be due to invalid IL or missing references) if (Multiworld.Authenticated) { Multiworld.Disconnect(); connectionInfo.text = "Disconnected from server."; if (SceneHelper.CurrentScene == "Main Menu") { ((Graphic)UIManager.menuIcon.GetComponent<Image>()).color = Colors.Red; } } } internal void <Initialize>b__65_2() { if (Multiworld.Authenticated) { Core.data.deathLink = true; Multiworld.EnableDeathLink(); } } internal void <Initialize>b__65_3() { if (Multiworld.Authenticated) { Core.data.deathLink = false; Multiworld.DisableDeathLink(); } } internal void <Initialize>b__65_4(string value) { //IL_0024: 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_0036: Expected O, but got Unknown if (Multiworld.Authenticated) { if (value != "") { Multiworld.Session.Socket.SendPacket((ArchipelagoPacketBase)new SayPacket { Text = value }); } chat.value = ""; } } internal void <Initialize>b__65_5(BoolValueChangeEvent e) { ((Component)UIManager.log).gameObject.SetActive(e.value); } internal void <Initialize>b__65_6(IntValueChangeEvent e) { UIManager.lines = e.value; while (Multiworld.messages.Count > e.value) { Multiworld.messages.RemoveAt(0); } } internal void <Initialize>b__65_7(IntValueChangeEvent e) { ((TMP_Text)UIManager.log).fontSize = e.value; } internal void <Initialize>b__65_8() { UIManager.SetLogText(""); Multiworld.messages.Clear(); } internal void <Initialize>b__65_9() { MonoSingleton<PrefsManager>.Instance.SetBool("gunColorType.1", true); MonoSingleton<PrefsManager>.Instance.SetBool("gunColorType.1.a", true); MonoSingleton<PrefsManager>.Instance.SetBool("gunColorType.2", true); MonoSingleton<PrefsManager>.Instance.SetBool("gunColorType.3", true); MonoSingleton<PrefsManager>.Instance.SetBool("gunColorType.3.a", true); MonoSingleton<PrefsManager>.Instance.SetBool("gunColorType.4", true); MonoSingleton<PrefsManager>.Instance.SetBool("gunColorType.5", true); } internal void <Initialize>b__65_10() { MonoSingleton<PrefsManager>.Instance.SetBool("gunColorType.1", false); MonoSingleton<PrefsManager>.Instance.SetBool("gunColorType.1.a", false); MonoSingleton<PrefsManager>.Instance.SetBool("gunColorType.2", false); MonoSingleton<PrefsManager>.Instance.SetBool("gunColorType.3", false); MonoSingleton<PrefsManager>.Instance.SetBool("gunColorType.3.a", false); MonoSingleton<PrefsManager>.Instance.SetBool("gunColorType.4", false); MonoSingleton<PrefsManager>.Instance.SetBool("gunColorType.5", false); } internal void <Initialize>b__65_11() { //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Expected O, but got Unknown //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Invalid comparison between Unknown and I4 //IL_013e: Unknown result type (might be due to invalid IL or missing references) //IL_0183: Unknown result type (might be due to invalid IL or missing references) //IL_01c8: Unknown result type (might be due to invalid IL or missing references) //IL_020d: Unknown result type (might be due to invalid IL or missing references) //IL_0242: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) if (!Multiworld.Authenticated) { return; } Object.Destroy((Object)(object)Traverse.Create((object)hintList).Field("panelObject").GetValue<GameObject>()); Traverse.Create((object)hintsPanel).Field("fieldObjects").GetValue<List<List<Transform>>>() .RemoveAt(2); Traverse.Create((object)hintsPanel).Field("fields").GetValue<List<ConfigField>>() .RemoveAt(2); hintList = null; hintList = new ConfigDivision(hintsPanel, "hintList"); Hint[] hints = Multiworld.Session.DataStorage.GetHints((int?)null, (int?)null); Hint[] array = hints; foreach (Hint val in array) { if (!hintAdvancementOnly.value || (int)val.ItemFlags == 1) { if (Array.IndexOf(hints, val) != 0) { new ConfigHeader((ConfigPanel)(object)hintList, "-----", 24); } ((ConfigField)new StringField((ConfigPanel)(object)hintList, "ITEM", $"hint{Array.IndexOf(hints, val)}_item", Multiworld.Session.Items.GetItemName(val.ItemId), true, false)).interactable = false; ((ConfigField)new StringField((ConfigPanel)(object)hintList, "RECEIVING PLAYER", $"hint{Array.IndexOf(hints, val)}_receiving_player", Multiworld.Session.Players.GetPlayerAlias(val.ReceivingPlayer), true, false)).interactable = false; ((ConfigField)new StringField((ConfigPanel)(object)hintList, "LOCATION", $"hint{Array.IndexOf(hints, val)}_location", Multiworld.Session.Locations.GetLocationNameFromId(val.LocationId), true, false)).interactable = false; ((ConfigField)new StringField((ConfigPanel)(object)hintList, "SENDING PLAYER", $"hint{Array.IndexOf(hints, val)}_sending_player", Multiworld.Session.Players.GetPlayerAlias(val.FindingPlayer), true, false)).interactable = false; ((ConfigField)new BoolField((ConfigPanel)(object)hintList, "FOUND", $"hint{Array.IndexOf(hints, val)}_found", val.Found, false)).interactable = false; } } } } public static PluginConfigurator config; public static ConfigPanel playerPanel; public static BoolField isConnected; public static StringField playerName; public static StringField serverAddress; public static StringField serverPassword; public static BoolField hintMode; public static ButtonField connectButton; public static ButtonField disconnectButton; public static ConfigHeader connectionInfo; public static ButtonField deathLinkOnButton; public static ButtonField deathLinkOffButton; public static StringField chat; public static StringField goal; public static StringField goalProgress; public static StringField locationsChecked; public static EnumField<BossOptions> bossRewards; public static BoolField challengeRewards; public static BoolField pRankRewards; public static BoolField fishRewards; public static BoolField randomizeFire2; public static BoolField randomizeSkulls; public static BoolField musicRandomizer; public static BoolField cybergrindHints; public static BoolField deathLink; public static ConfigPanel logPanel; public static BoolField showLog; public static IntField logLines; public static IntField logFontSize; public static ButtonField logClear; public static ConfigPanel colorPanel; public static EnumField<ColorOptions> uiColorRandomizer; public static EnumField<ColorOptions> gunColorRandomizer; public static ButtonField enableCustomButton; public static ButtonField disableCustomButton; public static ColorField APPlayerSelf; public static ColorField APPlayerOther; public static ColorField APItemAdvancement; public static ColorField APItemNeverExclude; public static ColorField APItemFiller; public static ColorField APItemTrap; public static ColorField APLocation; public static ColorField layer0Color; public static ColorField layer1Color; public static ColorField layer2Color; public static ColorField layer3Color; public static ColorField layer4Color; public static ColorField layer5Color; public static ColorField layer6Color; public static ColorField layer7Color; public static ColorField primeColor; public static ColorField altColor; public static ColorField arm0Color; public static ColorField arm1Color; public static ColorField arm2Color; public static ColorField blueSkullColor; public static ColorField redSkullColor; public static ColorField pointsColor; public static ColorField dualwieldColor; public static ColorField doublejumpColor; public static ColorField trapColor; public static ConfigPanel hintsPanel; public static BoolField hintAdvancementOnly; public static ButtonField hintRefresh; public static ConfigDivision hintList; public static void Initialize() { //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Expected O, but got Unknown //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Expected O, but got Unknown //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Expected O, but got Unknown //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Expected O, but got Unknown //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Expected O, but got Unknown //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Expected O, but got Unknown //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Expected O, but got Unknown //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_0162: Expected O, but got Unknown //IL_0173: Unknown result type (might be due to invalid IL or missing references) //IL_017d: Expected O, but got Unknown //IL_018a: Unknown result type (might be due to invalid IL or missing references) //IL_019d: Unknown result type (might be due to invalid IL or missing references) //IL_01a7: Expected O, but got Unknown //IL_01b6: Unknown result type (might be due to invalid IL or missing references) //IL_01c0: Expected O, but got Unknown //IL_01f9: Unknown result type (might be due to invalid IL or missing references) //IL_0203: Expected O, but got Unknown //IL_01d9: Unknown result type (might be due to invalid IL or missing references) //IL_01de: Unknown result type (might be due to invalid IL or missing references) //IL_01e4: Expected O, but got Unknown //IL_023c: Unknown result type (might be due to invalid IL or missing references) //IL_0246: Expected O, but got Unknown //IL_021c: Unknown result type (might be due to invalid IL or missing references) //IL_0221: Unknown result type (might be due to invalid IL or missing references) //IL_0227: Expected O, but got Unknown //IL_027f: Unknown result type (might be due to invalid IL or missing references) //IL_0289: Expected O, but got Unknown //IL_025f: Unknown result type (might be due to invalid IL or missing references) //IL_0264: Unknown result type (might be due to invalid IL or missing references) //IL_026a: Expected O, but got Unknown //IL_02c9: Unknown result type (might be due to invalid IL or missing references) //IL_02ce: Unknown result type (might be due to invalid IL or missing references) //IL_02db: Expected O, but got Unknown //IL_02a2: Unknown result type (might be due to invalid IL or missing references) //IL_02a7: Unknown result type (might be due to invalid IL or missing references) //IL_02ad: Expected O, but got Unknown //IL_0311: Unknown result type (might be due to invalid IL or missing references) //IL_032d: Unknown result type (might be due to invalid IL or missing references) //IL_0332: Unknown result type (might be due to invalid IL or missing references) //IL_033f: Expected O, but got Unknown //IL_0355: Unknown result type (might be due to invalid IL or missing references) //IL_035a: Unknown result type (might be due to invalid IL or missing references) //IL_0367: Expected O, but got Unknown //IL_037d: Unknown result type (might be due to invalid IL or missing references) //IL_0382: Unknown result type (might be due to invalid IL or missing references) //IL_038f: Expected O, but got Unknown //IL_03f6: Unknown result type (might be due to invalid IL or missing references) //IL_03fb: Unknown result type (might be due to invalid IL or missing references) //IL_0408: Expected O, but got Unknown //IL_0419: Unknown result type (might be due to invalid IL or missing references) //IL_041e: Unknown result type (might be due to invalid IL or missing references) //IL_042b: Expected O, but got Unknown //IL_043c: Unknown result type (might be due to invalid IL or missing references) //IL_0441: Unknown result type (might be due to invalid IL or missing references) //IL_044e: Expected O, but got Unknown //IL_045f: Unknown result type (might be due to invalid IL or missing references) //IL_0464: Unknown result type (might be due to invalid IL or missing references) //IL_0471: Expected O, but got Unknown //IL_0482: Unknown result type (might be due to invalid IL or missing references) //IL_0487: Unknown result type (might be due to invalid IL or missing references) //IL_0494: Expected O, but got Unknown //IL_04a5: Unknown result type (might be due to invalid IL or missing references) //IL_04aa: Unknown result type (might be due to invalid IL or missing references) //IL_04b7: Expected O, but got Unknown //IL_04c8: Unknown result type (might be due to invalid IL or missing references) //IL_04cd: Unknown result type (might be due to invalid IL or missing references) //IL_04da: Expected O, but got Unknown //IL_04eb: Unknown result type (might be due to invalid IL or missing references) //IL_04f0: Unknown result type (might be due to invalid IL or missing references) //IL_04fd: Expected O, but got Unknown //IL_050e: Unknown result type (might be due to invalid IL or missing references) //IL_0518: Expected O, but got Unknown //IL_02f4: Unknown result type (might be due to invalid IL or missing references) //IL_02f9: Unknown result type (might be due to invalid IL or missing references) //IL_02ff: Expected O, but got Unknown //IL_0557: Unknown result type (might be due to invalid IL or missing references) //IL_0561: Expected O, but got Unknown //IL_0531: Unknown result type (might be due to invalid IL or missing references) //IL_0536: Unknown result type (might be due to invalid IL or missing references) //IL_053c: Expected O, but got Unknown //IL_05a1: Unknown result type (might be due to invalid IL or missing references) //IL_05ab: Expected O, but got Unknown //IL_057a: Unknown result type (might be due to invalid IL or missing references) //IL_057f: Unknown result type (might be due to invalid IL or missing references) //IL_0585: Expected O, but got Unknown //IL_05e4: Unknown result type (might be due to invalid IL or missing references) //IL_05ee: Expected O, but got Unknown //IL_05c4: Unknown result type (might be due to invalid IL or missing references) //IL_05c9: Unknown result type (might be due to invalid IL or missing references) //IL_05cf: Expected O, but got Unknown //IL_06c3: Unknown result type (might be due to invalid IL or missing references) //IL_06cd: Expected O, but got Unknown //IL_0607: Unknown result type (might be due to invalid IL or missing references) //IL_060c: Unknown result type (might be due to invalid IL or missing references) //IL_0612: Expected O, but got Unknown //IL_0706: Unknown result type (might be due to invalid IL or missing references) //IL_0710: Expected O, but got Unknown //IL_06e6: Unknown result type (might be due to invalid IL or missing references) //IL_06eb: Unknown result type (might be due to invalid IL or missing references) //IL_06f1: Expected O, but got Unknown //IL_0746: Unknown result type (might be due to invalid IL or missing references) //IL_076a: Unknown result type (might be due to invalid IL or missing references) //IL_0770: Unknown result type (might be due to invalid IL or missing references) //IL_077a: Expected O, but got Unknown //IL_0798: Unknown result type (might be due to invalid IL or missing references) //IL_079e: Unknown result type (might be due to invalid IL or missing references) //IL_07a8: Expected O, but got Unknown //IL_07c6: Unknown result type (might be due to invalid IL or missing references) //IL_07cc: Unknown result type (might be due to invalid IL or missing references) //IL_07d6: Expected O, but got Unknown //IL_07f4: Unknown result type (might be due to invalid IL or missing references) //IL_07fa: Unknown result type (might be due to invalid IL or missing references) //IL_0804: Expected O, but got Unknown //IL_0822: Unknown result type (might be due to invalid IL or missing references) //IL_0828: Unknown result type (might be due to invalid IL or missing references) //IL_0832: Expected O, but got Unknown //IL_0850: Unknown result type (might be due to invalid IL or missing references) //IL_0856: Unknown result type (might be due to invalid IL or missing references) //IL_0860: Expected O, but got Unknown //IL_087e: Unknown result type (might be due to invalid IL or missing references) //IL_0884: Unknown result type (might be due to invalid IL or missing references) //IL_088e: Expected O, but got Unknown //IL_089a: Unknown result type (might be due to invalid IL or missing references) //IL_08be: Unknown result type (might be due to invalid IL or missing references) //IL_08c4: Unknown result type (might be due to invalid IL or missing references) //IL_08ce: Expected O, but got Unknown //IL_08ec: Unknown result type (might be due to invalid IL or missing references) //IL_08f2: Unknown result type (might be due to invalid IL or missing references) //IL_08fc: Expected O, but got Unknown //IL_091a: Unknown result type (might be due to invalid IL or missing references) //IL_0920: Unknown result type (might be due to invalid IL or missing references) //IL_092a: Expected O, but got Unknown //IL_0948: Unknown result type (might be due to invalid IL or missing references) //IL_094e: Unknown result type (might be due to invalid IL or missing references) //IL_0958: Expected O, but got Unknown //IL_0976: Unknown result type (might be due to invalid IL or missing references) //IL_097c: Unknown result type (might be due to invalid IL or missing references) //IL_0986: Expected O, but got Unknown //IL_09a4: Unknown result type (might be due to invalid IL or missing references) //IL_09aa: Unknown result type (might be due to invalid IL or missing references) //IL_09b4: Expected O, but got Unknown //IL_09d2: Unknown result type (might be due to invalid IL or missing references) //IL_09d8: Unknown result type (might be due to invalid IL or missing references) //IL_09e2: Expected O, but got Unknown //IL_0a00: Unknown result type (might be due to invalid IL or missing references) //IL_0a06: Unknown result type (might be due to invalid IL or missing references) //IL_0a10: Expected O, but got Unknown //IL_0a2e: Unknown result type (might be due to invalid IL or missing references) //IL_0a34: Unknown result type (might be due to invalid IL or missing references) //IL_0a3e: Expected O, but got Unknown //IL_0a5c: Unknown result type (might be due to invalid IL or missing references) //IL_0a62: Unknown result type (might be due to invalid IL or missing references) //IL_0a6c: Expected O, but got Unknown //IL_0a8a: Unknown result type (might be due to invalid IL or missing references) //IL_0a90: Unknown result type (might be due to invalid IL or missing references) //IL_0a9a: Expected O, but got Unknown //IL_0ab8: Unknown result type (might be due to invalid IL or missing references) //IL_0abe: Unknown result type (might be due to invalid IL or missing references) //IL_0ac8: Expected O, but got Unknown //IL_0ae6: Unknown result type (might be due to invalid IL or missing references) //IL_0aec: Unknown result type (might be due to invalid IL or missing references) //IL_0af6: Expected O, but got Unknown //IL_0b14: Unknown result type (might be due to invalid IL or missing references) //IL_0b1a: Unknown result type (might be due to invalid IL or missing references) //IL_0b24: Expected O, but got Unknown //IL_0b42: Unknown result type (might be due to invalid IL or missing references) //IL_0b48: Unknown result type (might be due to invalid IL or missing references) //IL_0b52: Expected O, but got Unknown //IL_0b70: Unknown result type (might be due to invalid IL or missing references) //IL_0b76: Unknown result type (might be due to invalid IL or missing references) //IL_0b80: Expected O, but got Unknown //IL_0b9e: Unknown result type (might be due to invalid IL or missing references) //IL_0ba4: Unknown result type (might be due to invalid IL or missing references) //IL_0bae: Expected O, but got Unknown //IL_0bcc: Unknown result type (might be due to invalid IL or missing references) //IL_0bd2: Unknown result type (might be due to invalid IL or missing references) //IL_0bdc: Expected O, but got Unknown //IL_0bfa: Unknown result type (might be due to invalid IL or missing references) //IL_0c00: Unknown result type (might be due to invalid IL or missing references) //IL_0c0a: Expected O, but got Unknown //IL_0c1b: Unknown result type (might be due to invalid IL or missing references) //IL_0c25: Expected O, but got Unknown //IL_0c34: Unknown result type (might be due to invalid IL or missing references) //IL_0c3e: Expected O, but got Unknown //IL_0c48: Unknown result type (might be due to invalid IL or missing references) //IL_0c52: Expected O, but got Unknown //IL_0729: Unknown result type (might be due to invalid IL or missing references) //IL_072e: Unknown result type (might be due to invalid IL or missing references) //IL_0734: Expected O, but got Unknown //IL_0c6b: Unknown result type (might be due to invalid IL or missing references) //IL_0c70: Unknown result type (might be due to invalid IL or missing references) //IL_0c76: Expected O, but got Unknown if (config != null) { return; } config = PluginConfigurator.Create("Archipelago", "trpg.archipelagoultrakill"); string text = Path.Combine(Core.workingDir, "icon.png"); if (File.Exists(text)) { config.SetIconWithURL(text); } new ConfigHeader(config.rootPanel, "ARCHIPELAGO", 24); playerPanel = new ConfigPanel(config.rootPanel, "PLAYER SETTINGS", "playerPanel"); logPanel = new ConfigPanel(config.rootPanel, "LOG SETTINGS", "logPanel"); colorPanel = new ConfigPanel(config.rootPanel, "COLOR SETTINGS", "colorPanel"); hintsPanel = new ConfigPanel(config.rootPanel, "HINTS", "hintsPanel"); isConnected = new BoolField(playerPanel, "CONNECTED TO SERVER?", "isConnected", false, false); ((ConfigField)isConnected).interactable = false; playerName = new StringField(playerPanel, "NAME", "playerName", "V1", false, true); serverAddress = new StringField(playerPanel, "ADDRESS", "serverAddress", "archipelago.gg", false, true); serverPassword = new StringField(playerPanel, "PASSWORD", "serverPassword", "", true, true); hintMode = new BoolField(playerPanel, "HINT MODE", "hintMode", false, false); new ConfigHeader(playerPanel, "Hint mode disables all randomization, and allows connecting to other games' slots to unlock hints while playing The Cyber Grind.", 12, (TextAnchor)0); connectionInfo = new ConfigHeader(playerPanel, "", 16, (TextAnchor)1); connectButton = new ButtonField(playerPanel, "CONNECT", "connectButton"); ButtonField obj = connectButton; object obj2 = <>c.<>9__65_0; if (obj2 == null) { OnClick val = delegate { if (Multiworld.Authenticated) { connectionInfo.text = "Already connected to server."; } else if (SceneHelper.CurrentScene != "Main Menu") { connectionInfo.text = "Can only connect to an Archipelago server on the main menu."; } else if ((GameProgressSaver.GetTutorial() || GameProgressSaver.GetIntro()) && !Core.DataExists() && !hintMode.value) { connectionInfo.text = "No Archipelago data found. Start a new save file before connecting."; } else if (Core.DataExists() && hintMode.value) { connectionInfo.text = "Can't use hint mode on a save file that already has randomizer data."; } else if (!Multiworld.Authenticated) { Core.data.slot_name = playerName.value; Core.data.host_name = serverAddress.value; Core.data.password = serverPassword.value; if (Core.data.password == "") { Core.data.password = null; } if (hintMode.value) { Multiworld.ConnectBK(); } else { Multiworld.Connect(); } } }; <>c.<>9__65_0 = val; obj2 = (object)val; } obj.onClick += (OnClick)obj2; disconnectButton = new ButtonField(playerPanel, "DISCONNECT", "disconnectButton"); ButtonField obj3 = disconnectButton; object obj4 = <>c.<>9__65_1; if (obj4 == null) { OnClick val2 = delegate { //IL_003f: Unknown result type (might be due to invalid IL or missing references) if (Multiworld.Authenticated) { Multiworld.Disconnect(); connectionInfo.text = "Disconnected from server."; if (SceneHelper.CurrentScene == "Main Menu") { ((Graphic)UIManager.menuIcon.GetComponent<Image>()).color = Colors.Red; } } }; <>c.<>9__65_1 = val2; obj4 = (object)val2; } obj3.onClick += (OnClick)obj4; deathLinkOnButton = new ButtonField(playerPanel, "ENABLE DEATH LINK", "deathLinkOnButton"); ButtonField obj5 = deathLinkOnButton; object obj6 = <>c.<>9__65_2; if (obj6 == null) { OnClick val3 = delegate { if (Multiworld.Authenticated) { Core.data.deathLink = true; Multiworld.EnableDeathLink(); } }; <>c.<>9__65_2 = val3; obj6 = (object)val3; } obj5.onClick += (OnClick)obj6; deathLinkOffButton = new ButtonField(playerPanel, "DISABLE DEATH LINK", "deathLinkOffButton"); ButtonField obj7 = deathLinkOffButton; object obj8 = <>c.<>9__65_3; if (obj8 == null) { OnClick val4 = delegate { if (Multiworld.Authenticated) { Core.data.deathLink = false; Multiworld.DisableDeathLink(); } }; <>c.<>9__65_3 = val4; obj8 = (object)val4; } obj7.onClick += (OnClick)obj8; chat = new StringField(playerPanel, "CHAT", "chat", "", true, false) { interactable = false }; StringField obj9 = chat; object obj10 = <>c.<>9__65_4; if (obj10 == null) { PostStringValueChangeEvent val5 = delegate(string value) { //IL_0024: 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_0036: Expected O, but got Unknown if (Multiworld.Authenticated) { if (value != "") { Multiworld.Session.Socket.SendPacket((ArchipelagoPacketBase)new SayPacket { Text = value }); } chat.value = ""; } }; <>c.<>9__65_4 = val5; obj10 = (object)val5; } obj9.postValueChangeEvent += (PostStringValueChangeEvent)obj10; new ConfigHeader(playerPanel, "-----", 24); goal = new StringField(playerPanel, "GOAL", "goal", "?", false, false) { interactable = false }; goalProgress = new StringField(playerPanel, "LEVELS COMPLETED", "goalProgress", "?", false, false) { interactable = false }; locationsChecked = new StringField(playerPanel, "LOCATIONS CHECKED", "locationsChecked", "?", false, false) { interactable = false }; EnumField<BossOptions> obj11 = new EnumField<BossOptions>(playerPanel, "BOSS REWARDS", "bossRewards", BossOptions.Disabled, false); ((ConfigField)obj11).interactable = false; bossRewards = obj11; bossRewards.SetEnumDisplayName(BossOptions.Disabled, "DISABLED"); bossRewards.SetEnumDisplayName(BossOptions.Standard, "STANDARD"); bossRewards.SetEnumDisplayName(BossOptions.Extended, "EXTENDED"); challengeRewards = new BoolField(playerPanel, "CHALLENGE REWARDS", "challengeRewards", false, false) { interactable = false }; pRankRewards = new BoolField(playerPanel, "P RANK REWARDS", "pRankRewards", false, false) { interactable = false }; fishRewards = new BoolField(playerPanel, "FISH REWARDS", "fishRewards", false, false) { interactable = false }; randomizeFire2 = new BoolField(playerPanel, "RANDOMIZE SECONDARY FIRE", "randomizeFire2", false, false) { interactable = false }; randomizeSkulls = new BoolField(playerPanel, "RANDOMIZE SKULLS", "randomizeSkulls", false, false) { interactable = false }; musicRandomizer = new BoolField(playerPanel, "MUSIC RANDOMIZER", "musicRandomizer", false, false) { interactable = false }; cybergrindHints = new BoolField(playerPanel, "UNLOCK HINTS IN CYBERGRIND", "cybergrindHints", false, false) { interactable = false }; deathLink = new BoolField(playerPanel, "DEATH LINK", "deathLink", false, false) { interactable = false }; showLog = new BoolField(logPanel, "SHOW LOG", "showLog", true, true); BoolField obj12 = showLog; object obj13 = <>c.<>9__65_5; if (obj13 == null) { BoolValueChangeEventDelegate val6 = delegate(BoolValueChangeEvent e) { ((Component)UIManager.log).gameObject.SetActive(e.value); }; <>c.<>9__65_5 = val6; obj13 = (object)val6; } obj12.onValueChange += (BoolValueChangeEventDelegate)obj13; logLines = new IntField(logPanel, "NUMBER OF MESSAGES", "logLines", 5, 1, 16, true, true); IntField obj14 = logLines; object obj15 = <>c.<>9__65_6; if (obj15 == null) { IntValueChangeEventDelegate val7 = delegate(IntValueChangeEvent e) { UIManager.lines = e.value; while (Multiworld.messages.Count > e.value) { Multiworld.messages.RemoveAt(0); } }; <>c.<>9__65_6 = val7; obj15 = (object)val7; } obj14.onValueChange += (IntValueChangeEventDelegate)obj15; logFontSize = new IntField(logPanel, "FONT SIZE", "logFontSize", 16, 1, 32, true, true); IntField obj16 = logFontSize; object obj17 = <>c.<>9__65_7; if (obj17 == null) { IntValueChangeEventDelegate val8 = delegate(IntValueChangeEvent e) { ((TMP_Text)UIManager.log).fontSize = e.value; }; <>c.<>9__65_7 = val8; obj17 = (object)val8; } obj16.onValueChange += (IntValueChangeEventDelegate)obj17; logClear = new ButtonField(logPanel, "CLEAR LOG", "logClear"); ButtonField obj18 = logClear; object obj19 = <>c.<>9__65_8; if (obj19 == null) { OnClick val9 = delegate { UIManager.SetLogText(""); Multiworld.messages.Clear(); }; <>c.<>9__65_8 = val9; obj19 = (object)val9; } obj18.onClick += (OnClick)obj19; uiColorRandomizer = new EnumField<ColorOptions>(colorPanel, "UI COLOR RANDOMIZER", "uiColorRandomizer", ColorOptions.Off, true); uiColorRandomizer.SetEnumDisplayName(ColorOptions.Off, "DISABLED"); uiColorRandomizer.SetEnumDisplayName(ColorOptions.Once, "ONCE"); uiColorRandomizer.SetEnumDisplayName(ColorOptions.EveryLoad, "EVERY NEW LEVEL LOADED"); gunColorRandomizer = new EnumField<ColorOptions>(colorPanel, "GUN COLOR RANDOMIZER", "gunColorRandomizer", ColorOptions.Off, true); gunColorRandomizer.SetEnumDisplayName(ColorOptions.Off, "DISABLED"); gunColorRandomizer.SetEnumDisplayName(ColorOptions.Once, "ONCE"); gunColorRandomizer.SetEnumDisplayName(ColorOptions.EveryLoad, "EVERY NEW LEVEL LOADED"); enableCustomButton = new ButtonField(colorPanel, "ENABLE ALL CUSTOM WEAPON COLORS", "enableCustomButton"); ButtonField obj20 = enableCustomButton; object obj21 = <>c.<>9__65_9; if (obj21 == null) { OnClick val10 = delegate { MonoSingleton<PrefsManager>.Instance.SetBool("gunColorType.1", true); MonoSingleton<PrefsManager>.Instance.SetBool("gunColorType.1.a", true); MonoSingleton<PrefsManager>.Instance.SetBool("gunColorType.2", true); MonoSingleton<PrefsManager>.Instance.SetBool("gunColorType.3", true); MonoSingleton<PrefsManager>.Instance.SetBool("gunColorType.3.a", true); MonoSingleton<PrefsManager>.Instance.SetBool("gunColorType.4", true); MonoSingleton<PrefsManager>.Instance.SetBool("gunColorType.5", true); }; <>c.<>9__65_9 = val10; obj21 = (object)val10; } obj20.onClick += (OnClick)obj21; disableCustomButton = new ButtonField(colorPanel, "DISABLE ALL CUSTOM WEAPON COLORS", "disableCustomButton"); ButtonField obj22 = disableCustomButton; object obj23 = <>c.<>9__65_10; if (obj23 == null) { OnClick val11 = delegate { MonoSingleton<PrefsManager>.Instance.SetBool("gunColorType.1", false); MonoSingleton<PrefsManager>.Instance.SetBool("gunColorType.1.a", false); MonoSingleton<PrefsManager>.Instance.SetBool("gunColorType.2", false); MonoSingleton<PrefsManager>.Instance.SetBool("gunColorType.3", false); MonoSingleton<PrefsManager>.Instance.SetBool("gunColorType.3.a", false); MonoSingleton<PrefsManager>.Instance.SetBool("gunColorType.4", false); MonoSingleton<PrefsManager>.Instance.SetBool("gunColorType.5", false); }; <>c.<>9__65_10 = val11; obj23 = (object)val11; } obj22.onClick += (OnClick)obj23; new ConfigHeader(colorPanel, "ARCHIPELAGO COLORS", 24); APPlayerSelf = new ColorField(colorPanel, "PLAYER (YOU)", "APPlayerSelf", new Color(0.93f, 0f, 0.93f), true); APPlayerOther = new ColorField(colorPanel, "PLAYER (OTHERS)", "APPlayerOther", new Color(0.98f, 0.98f, 0.82f), true); APItemFiller = new ColorField(colorPanel, "ITEM (FILLER)", "APItemFiller", new Color(0f, 0.93f, 0.93f), true); APItemNeverExclude = new ColorField(colorPanel, "ITEM (USEFUL)", "APItemNeverExclude", new Color(0.43f, 0.55f, 0.91f), true); APItemAdvancement = new ColorField(colorPanel, "ITEM (PROGRESSION)", "APItemAdvancement", new Color(0.69f, 0.6f, 0.94f), true); APItemTrap = new ColorField(colorPanel, "ITEM (TRAP)", "APItemTrap", new Color(0.98f, 0.5f, 0.45f), true); APLocation = new ColorField(colorPanel, "LOCATION", "APLocation", new Color(0f, 1f, 0.5f), true); new ConfigHeader(colorPanel, "POPUP COLORS", 24); layer0Color = new ColorField(colorPanel, "LAYER 0", "layer0Color", new Color(1f, 0.5f, 0.25f), true); layer1Color = new ColorField(colorPanel, "LAYER 1", "layer1Color", new Color(0.2667f, 1f, 0.2706f), true); layer2Color = new ColorField(colorPanel, "LAYER 2", "layer2Color", new Color(0.765f, 0.25f, 1f), true); layer3Color = new ColorField(colorPanel, "LAYER 3", "layer3Color", new Color(1f, 0.9479f, 0.8566f), true); layer4Color = new ColorField(colorPanel, "LAYER 4", "layer4Color", new Color(1f, 1f, 0.25f), true); layer5Color = new ColorField(colorPanel, "LAYER 5", "layer5Color", new Color(0.251f, 0.9059f, 1f), true); layer6Color = new ColorField(colorPanel, "LAYER 6", "layer6Color", new Color(1f, 0.2353f, 0.2353f), true); layer7Color = new ColorField(colorPanel, "LAYER 7", "layer7Color", new Color(0.8f, 0.8f, 0.8f), true); primeColor = new ColorField(colorPanel, "PRIME SANCTUMS", "primeColor", new Color(1f, 0.2353f, 0.2353f), true); altColor = new ColorField(colorPanel, "ALTERNATE WEAPON", "altColor", new Color(1f, 0.65f, 0f), true); arm0Color = new ColorField(colorPanel, "FEEDBACKER", "arm0Color", new Color(0.251f, 0.9059f, 1f), true); arm1Color = new ColorField(colorPanel, "KNUCKLEBLASTER", "arm1Color", new Color(1f, 0.2353f, 0.2353f), true); arm2Color = new ColorField(colorPanel, "WHIPLASH", "arm2Color", new Color(0.2667f, 1f, 0.2706f), true); blueSkullColor = new ColorField(colorPanel, "BLUE SKULL", "blueSkullColor", new Color(0.251f, 0.9059f, 1f), true); redSkullColor = new ColorField(colorPanel, "RED SKULL", "redSkullColor", new Color(1f, 0.2353f, 0.2353f), true); pointsColor = new ColorField(colorPanel, "POINTS", "pointsColor", new Color(1f, 0.65f, 0f), true); dualwieldColor = new ColorField(colorPanel, "DUAL WIELD", "dualwieldColor", new Color(1f, 1f, 0.25f), true); doublejumpColor = new ColorField(colorPanel, "AIR JUMP", "doublejumpColor", new Color(1f, 1f, 0.6f), true); trapColor = new ColorField(colorPanel, "TRAP", "trapColor", new Color(0.7f, 0.7f, 0.7f), true); hintAdvancementOnly = new BoolField(hintsPanel, "PROGRESSION ITEM HINTS ONLY", "hintAdvancementOnly", true, true); hintRefresh = new ButtonField(hintsPanel, "REFRESH LIST", "hintRefresh"); hintList = new ConfigDivision(hintsPanel, "hintList"); ButtonField obj24 = hintRefresh; object obj25 = <>c.<>9__65_11; if (obj25 == null) { OnClick val12 = delegate { //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Expected O, but got Unknown //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Invalid comparison between Unknown and I4 //IL_013e: Unknown result type (might be due to invalid IL or missing references) //IL_0183: Unknown result type (might be due to invalid IL or missing references) //IL_01c8: Unknown result type (might be due to invalid IL or missing references) //IL_020d: Unknown result type (might be due to invalid IL or missing references) //IL_0242: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) if (Multiworld.Authenticated) { Object.Destroy((Object)(object)Traverse.Create((object)hintList).Field("panelObject").GetValue<GameObject>()); Traverse.Create((object)hintsPanel).Field("fieldObjects").GetValue<List<List<Transform>>>() .RemoveAt(2); Traverse.Create((object)hintsPanel).Field("fields").GetValue<List<ConfigField>>() .RemoveAt(2); hintList = null; hintList = new ConfigDivision(hintsPanel, "hintList"); Hint[] hints = Multiworld.Session.DataStorage.GetHints((int?)null, (int?)null); Hint[] array = hints; foreach (Hint val13 in array) { if (!hintAdvancementOnly.value || (int)val13.ItemFlags == 1) { if (Array.IndexOf(hints, val13) != 0) { new ConfigHeader((ConfigPanel)(object)hintList, "-----", 24); } ((ConfigField)new StringField((ConfigPanel)(object)hintList, "ITEM", $"hint{Array.IndexOf(hints, val13)}_item", Multiworld.Session.Items.GetItemName(val13.ItemId), true, false)).interactable = false; ((ConfigField)new StringField((ConfigPanel)(object)hintList, "RECEIVING PLAYER", $"hint{Array.IndexOf(hints, val13)}_receiving_player", Multiworld.Session.Players.GetPlayerAlias(val13.ReceivingPlayer), true, false)).interactable = false; ((ConfigField)new StringField((ConfigPanel)(object)hintList, "LOCATION", $"hint{Array.IndexOf(hints, val13)}_location", Multiworld.Session.Locations.GetLocationNameFromId(val13.LocationId), true, false)).interactable = false; ((ConfigField)new StringField((ConfigPanel)(object)hintList, "SENDING PLAYER", $"hint{Array.IndexOf(hints, val13)}_sending_player", Multiworld.Session.Players.GetPlayerAlias(val13.FindingPlayer), true, false)).interactable = false; ((ConfigField)new BoolField((ConfigPanel)(object)hintList, "FOUND", $"hint{Array.IndexOf(hints, val13)}_found", val13.Found, false)).interactable = false; } } } }; <>c.<>9__65_11 = val12; obj25 = (object)val12; } obj24.onClick += (OnClick)obj25; } public static void LoadConnectionInfo() { if (Core.data.slot_name != null) { playerName.value = Core.data.slot_name; } if (Core.data.host_name != null) { serverAddress.value = Core.data.host_name; } if (Core.data.password != null) { serverPassword.value = Core.data.password; } } public static void LoadStats() { goal.value = Core.data.goal; goalProgress.value = $"{Core.data.completedLevels.Count} / {Core.data.goalRequirement}"; string arg = ((LocationManager.locations.Count == 0) ? "?" : LocationManager.locations.Count.ToString()); locationsChecked.value = $"{[email protected]} / {arg}"; bossRewards.value = Core.data.bossRewards; challengeRewards.value = Core.data.challengeRewards; pRankRewards.value = Core.data.pRankRewards; fishRewards.value = Core.data.fishRewards; randomizeFire2.value = Core.data.randomizeFire2; randomizeSkulls.value = Core.data.randomizeSkulls; musicRandomizer.value = Core.data.musicRandomizer; cybergrindHints.value = Core.data.cybergrindHints; deathLink.value = Core.data.deathLink; } public static void ResetStatsDefaults() { goal.value = "?"; goalProgress.value = "?"; locationsChecked.value = "?"; bossRewards.value = BossOptions.Disabled; challengeRewards.value = false; pRankRewards.value = false; fishRewards.value = false; randomizeFire2.value = false; randomizeSkulls.value = false; musicRandomizer.value = false; cybergrindHints.value = false; deathLink.value = false; } } public static class LevelManager { public static Dictionary<string, GameObject> skulls = new Dictionary<string, GameObject>(); public static void FindSkulls() { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Invalid comparison between Unknown and I4 //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_0047: 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_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Invalid comparison between Unknown and I4 skulls.Clear(); int num = 0; ItemIdentifier[] array = Resources.FindObjectsOfTypeAll<ItemIdentifier>(); foreach (ItemIdentifier val in array) { if ((int)val.itemType != 1 && (int)val.itemType != 2) { continue; } Scene val2 = ((Component)val).gameObject.scene; string name = ((Scene)(ref val2)).name; val2 = SceneManager.GetActiveScene(); if (name == ((Scene)(ref val2)).name) { if (skulls.ContainsKey(((object)(ItemType)(ref val.itemType)).ToString())) { num++; skulls[((object)(ItemType)(ref val.itemType)).ToString() + num] = ((Component)val).gameObject; } else { skulls[((object)(ItemType)(ref val.itemType)).ToString()] = ((Component)val).gameObject; } } } for (int j = 0; j < skulls.Count; j++) { KeyValuePair<string, GameObject> keyValuePair = skulls.ElementAt(j); string text = Core.CurrentLevelInfo.Id.ToString(); if (Core.CurrentLevelInfo.Name == "0-S") { text = "S"; } string currentScene = SceneHelper.CurrentScene; string text2 = currentScene; if (!(text2 == "Level 1-4")) { if (text2 == "Level 5-1") { if (j + 1 > Core.data.unlockedSkulls5_1) { keyValuePair.Value.SetActive(false); } } else if (((Object)keyValuePair.Value).name.Contains("Blue")) { if (!Core.data.unlockedSkulls.Contains(text + "_b")) { keyValuePair.Value.SetActive(false); } } else if (((Object)keyValuePair.Value).name.Contains("Red") && !Core.data.unlockedSkulls.Contains(text + "_r")) { keyValuePair.Value.SetActive(false); } } else if (j + 1 > Core.data.unlockedSkulls1_4) { keyValuePair.Value.SetActive(false); } } } public static void UpdateShopVariation(VariationInfo variation) { //IL_024a: Unknown result type (might be due to invalid IL or missing references) //IL_032e: Unknown result type (might be due to invalid IL or missing references) //IL_0333: Unknown result type (might be due to invalid IL or missing references) //IL_0374: Unknown result type (might be due to invalid IL or missing references) //IL_03b0: Unknown result type (might be due to invalid IL or missing references) //IL_03b6: Invalid comparison between Unknown and I4 //IL_02a7: Unknown result type (might be due to invalid IL or missing references) //IL_03df: Unknown result type (might be due to invalid IL or missing references) //IL_03e5: Invalid comparison between Unknown and I4 //IL_03c5: Unknown result type (might be due to invalid IL or missing references) //IL_040e: Unknown result type (might be due to invalid IL or missing references) //IL_0414: Invalid comparison between Unknown and I4 //IL_03f4: Unknown result type (might be due to invalid IL or missing references) //IL_07a4: Unknown result type (might be due to invalid IL or missing references) //IL_0442: Unknown result type (might be due to invalid IL or missing references) //IL_0423: Unknown result type (might be due to invalid IL or missing references) //IL_06ce: Unknown result type (might be due to invalid IL or missing references) //IL_0676: Unknown result type (might be due to invalid IL or missing references) //IL_06a0: Unknown result type (might be due to invalid IL or missing references) if (variation.weaponName == "arm0" && !Core.data.hasArm) { variation.costText.text = "<color=red>UNAVAILABLE</color>"; ((TMP_Text)((Component)((Component)variation.buyButton).gameObject.transform.GetChild(0)).GetComponent<TextMeshProUGUI>()).text = "UNAVAILABLE"; ((Component)variation.equipButton).gameObject.SetActive(false); Core.Logger.LogInfo((object)("Shop - Weapon: \"" + variation.weaponName + "\" - Is not unlocked")); return; } if (variation.weaponName == "arm0" && Core.data.hasArm) { variation.costText.text = "ALREADY OWNED"; ((TMP_Text)((Component)((Component)variation.buyButton).gameObject.transform.GetChild(0)).GetComponent<TextMeshProUGUI>()).text = "ALREADY OWNED"; ((Component)variation.equipButton).gameObject.SetActive(true); Core.Logger.LogInfo((object)("Shop - Weapon: \"" + variation.weaponName + "\" - Is unlocked")); return; } if (variation.weaponName == "arm1" || variation.weaponName == "arm2" || variation.weaponName == "sho2" || variation.weaponName == "nai2" || variation.weaponName == "rock2") { Core.Logger.LogInfo((object)("Shop - Weapon: \"" + variation.weaponName + "\" - Skipping")); return; } if (!variation.weaponName.Contains("0")) { string text = "[Purchase to unlock: "; if (LocationManager.locations.ContainsKey("shop_" + variation.weaponName)) { if (LocationManager.locations["shop_" + variation.weaponName].item is UKItem uKItem) { text = text + "<color=#" + ColorUtility.ToHtmlStringRGB(LocationManager.GetUKMessageColor(uKItem.itemName)) + "FF>" + uKItem.itemName + "</color>"; if (uKItem.playerName != Core.data.slot_name) { text = text + "for <color=#" + ColorUtility.ToHtmlStringRGB(Colors.PlayerOther) + "FF>" + uKItem.playerName + "</color>"; } text += "]\n\n"; } else if (LocationManager.locations["shop_" + variation.weaponName].item is APItem aPItem) { text = "<color=#" + ColorUtility.ToHtmlStringRGB(LocationManager.GetAPMessageColor(aPItem.type)) + "FF>" + aPItem.itemName + "</color>"; text = text + " for <color=#" + ColorUtility.ToHtmlStringRGB(Colors.PlayerOther) + "FF>" + aPItem.playerName + "</color>"; text += "]\n\n"; text = (((int)aPItem.type == 1) ? (text + "You don't know what this is, but it seems <color=#" + ColorUtility.ToHtmlStringRGB(Colors.ItemAdvancement) + "FF>important.</color>") : (((int)aPItem.type == 2) ? (text + "You don't know what this is, but it seems like it could be <color=#" + ColorUtility.ToHtmlStringRGB(Colors.ItemNeverExclude) + "FF>useful.</color>") : (((int)aPItem.type != 4) ? (text + "You don't know what this is, but it seems like you could probably <color=#" + ColorUtility.ToHtmlStringRGB(Colors.ItemFiller) + "FF>skip this</color> if you wanted to.") : (text + "You don't know what this is, but it seems like they're probably <color=#" + ColorUtility.ToHtmlStringRGB(Colors.ItemTrap) + "FF>better off without it.</color>")))); } } else { text = "???"; } ((TMP_Text)((Component)variation.varPage.transform.Find("Description")).GetComponent<TextMeshProUGUI>()).text = text; } GameProgressMoneyAndGear generalProgress = GameProgressSaver.GetGeneralProgress(); FieldInfo field = typeof(GameProgressMoneyAndGear).GetField(variation.weaponName, BindingFlags.Instance | BindingFlags.Public); bool flag = int.Parse(field.GetValue(generalProgress).ToString()) == 1; if (flag && !variation.weaponName.Contains("0") && !Core.data.purchasedItems.Contains(variation.weaponName)) { bool flag2 = false; if (GameProgressSaver.GetMoney() >= Core.shopPrices[variation.weaponName]) { flag2 = true; } string text2 = ((!flag2) ? ("<color=red>" + MoneyText.DivideMoney(Core.shopPrices[variation.weaponName]) + "P</color>") : (MoneyText.DivideMoney(Core.shopPrices[variation.weaponName]) + "<color=orange>P</color>")); variation.costText.text = text2; ((Component)((Component)variation.equipButton).transform.GetChild(0)).GetComponent<Image>().sprite = variation.equipSprites[MonoSingleton<PrefsManager>.Instance.GetInt("weapon." + variation.weaponName, 1)]; variation.orderButtons.SetActive(true); Traverse val = Traverse.Create((object)variation); val.Field<int>("equipStatus").Value = MonoSingleton<PrefsManager>.Instance.GetInt("weapon." + variation.weaponName, 1); val.Field<int>("money").Value = GameProgressSaver.GetMoney(); variation.varPage.GetComponentInChildren<MoneyText>().UpdateMoney(); ((TMP_Text)((Component)((Component)variation.buyButton).gameObject.transform.GetChild(0)).GetComponent<TextMeshProUGUI>()).text = text2; if (flag2) { ((Graphic)((Component)((Component)variation.buyButton).gameObject.transform.GetChild(0)).GetComponent<TextMeshProUGUI>()).color = new Color(1f, 1f, 1f); ((Graphic)((Component)variation.buyButton).gameObject.GetComponent<Image>()).color = new Color(1f, 1f, 1f); } else { ((Graphic)((Component)variation.buyButton).gameObject.GetComponent<Image>()).color = new Color(1f, 0f, 0f); } Core.Logger.LogInfo((object)("Shop - Weapon: \"" + variation.weaponName + "\" - Is unlocked, is not purchased")); } else if (!flag && !variation.weaponName.Contains("0") && Core.data.purchasedItems.Contains(variation.weaponName)) { variation.costText.text = "ALREADY OWNED"; variation.buyButton.deactivated = true; ((TMP_Text)((Component)((Component)variation.buyButton).gameObject.transform.GetChild(0)).GetComponent<TextMeshProUGUI>()).text = "ALREADY OWNED"; ((Graphic)((Component)((Component)variation.buyButton).gameObject.transform.GetChild(0)).GetComponent<TextMeshProUGUI>()).color = new Color(0.5882f, 0.5882f, 0.5882f); ((Component)variation.equipButton).gameObject.SetActive(false); Core.Logger.LogInfo((object)("Shop - Weapon: \"" + variation.weaponName + "\" - Is unlocked, is purchased")); } else if (!flag && variation.weaponName.Contains("0")) { variation.costText.text = "<color=red>UNAVAILABLE</color>"; ((TMP_Text)((Component)((Component)variation.buyButton).gameObject.transform.GetChild(0)).GetComponent<TextMeshProUGUI>()).text = "UNAVAILABLE"; ((Component)variation.equipButton).gameObject.SetActive(false); Core.Logger.LogInfo((object)("Shop - Weapon: \"" + variation.weaponName + "\" - Is not unlocked")); } } public static void AddDoorClosers() { ItemPlaceZone[] array = Resources.FindObjectsOfTypeAll<ItemPlaceZone>(); foreach (ItemPlaceZone val in array) { if (SceneHelper.CurrentScene == "Level 1-1") { if ((Object)(object)((Component)val).transform.parent.parent != (Object)null && ((Object)((Component)val).transform.parent.parent).name == "11 Nonstuff" && !Object.op_Implicit((Object)(object)((Component)((Component)val).transform.parent.parent.parent).gameObject.GetComponent<ReverseDoorCloser>())) { ((Component)((Component)val).transform.parent.parent.parent).gameObject.AddComponent<ReverseDoorCloser>(); } } else if (SceneHelper.CurrentScene == "Level 1-2") { if ((Object)(object)((Component)val).transform.parent.parent != (Object)null && ((Object)((Component)val).transform.parent.parent).name == "3 Nonstuff" && !Object.op_Implicit((Object)(object)((Component)((Component)val).transform.parent.parent.parent).gameObject.GetComponent<ReverseDoorCloser>())) { ((Component)((Component)val).transform.parent.parent.parent).gameObject.AddComponent<ReverseDoorCloser>(); } } else if (SceneHelper.CurrentScene == "Level 2-3") { if ((Object)(object)((Component)val).transform.parent != (Object)null && (((Object)((Component)val).transform.parent).name == "Altar" || ((Object)((Component)val).transform.parent).name == "Altar (1)") && !Object.op_Implicit((Object)(object)((Component)((Component)val).transform.parent).gameObject.GetComponent<ReverseDoorCloser>())) { ((Component)((Component)val).transform.parent).gameObject.AddComponent<ReverseDoorCloser>(); } } else if (SceneHelper.CurrentScene == "Level 4-4") { if ((Object)(object)((Component)val).transform.parent.parent != (Object)null && ((Object)((Component)val).transform.parent.parent).name == "Secret Hall" && !Object.op_Implicit((Object)(object)((Component)((Component)val).transform.parent.parent.parent).gameObject.GetComponent<ReverseDoorCloser>())) { ((Component)((Component)val).transform.parent.parent.parent).gameObject.AddComponent<ReverseDoorCloser>(); } } else if (SceneHelper.CurrentScene == "Level 5-2") { if ((Object)(object)((Component)val).transform.parent.parent != (Object)null && (((Object)((Component)val).transform.parent.parent).name == "6" || ((Object)((Component)val).transform.parent.parent).name == "7B") && !Object.op_Implicit((Object)(object)((Component)((Component)val).transform.parent.parent).gameObject.GetComponent<ReverseDoorCloser>())) { ((Component)((Component)val).transform.parent.parent).gameObject.AddComponent<ReverseDoorCloser>(); } } else if (SceneHelper.CurrentScene == "Level 5-3") { if ((Object)(object)((Component)val).transform.parent.parent != (Object)null && ((Object)((Component)val).transform.parent.parent).name == "2A4 - Skullway" && !Object.op_Implicit((Object)(object)((Component)((Component)val).transform.parent.parent).gameObject.GetComponent<ReverseDoorCloser>())) { ((Component)((Component)val).transform.parent.parent).gameObject.AddComponent<ReverseDoorCloser>(); } } else if (SceneHelper.CurrentScene == "Level 6-1" && (Object)(object)((Component)val).transform.parent.parent != (Object)null && ((Object)((Component)val).transform.parent.parent).name == "3 - Crossroads" && !Object.op_Implicit((Object)(object)((Component)((Component)val).transform.parent.parent).gameObject.GetComponent<ReverseDoorCloser>())) { ((Component)((Component)val).transform.parent.parent).gameObject.AddComponent<ReverseDoorCloser>(); } } } public static void DeactivateNailgun() { GearCheckEnabler[] array = Resources.FindObjectsOfTypeAll<GearCheckEnabler>(); foreach (GearCheckEnabler val in array) { if (((Object)((Component)val).transform.parent).name == "1 - First Room") { ((Component)val).gameObject.SetActive(false); } } } public static void AddGlassComponents() { if (!Core.CurrentLevelHasInfo || Core.CurrentLevelInfo.Id != 1) { return; } Glass[] array = Resources.FindObjectsOfTypeAll<Glass>(); foreach (Glass val in array) { string name = ((Object)((Component)val).transform.parent.parent).name; switch (name) { default: if (!(name == "11 Content(Clone)")) { continue; } break; case "5 Stuff": case "5 Stuff(Clone)": case "11 Content": break; } GameObject gameObject = ((Component)((Component)val).transform.parent.parent).gameObject; if (!Object.op_Implicit((Object)(object)gameObject.GetComponent<GlassDisabler>())) { gameObject.AddComponent<GlassDisabler>(); } } } } public static class Multiworld { public static int[] AP_VERSION = new int[3] { 0, 4, 4 }; public static DeathLinkService DeathLinkService = null; public static bool DeathLinkKilling = false; public static bool Authenticated; public static bool HintMode = false; public static ArchipelagoSession Session; public static List<string> messages = new List<string>(); public static void TryGetGoal(ref string goal, Dictionary<string, object> slotData, string defaultValue) { try { switch (int.Parse(slotData["goal"].ToString())) { case 0: goal = "1-4"; break; case 1: goal = "2-4"; break; case 2: goal = "3-2"; break; case 3: goal = "4-4"; break; case 4: goal = "5-4"; break; case 6: goal = "P-1"; break; case 7: goal = "P-2"; break; case 8: goal = "7-4"; break; default: goal = "6-2"; break; } } catch (Exception) { Core.Logger.LogError((object)("Couldn't parse goal. Something has gone very wrong. Using default value (" + defaultValue + ")")); goal = defaultValue; } } public static void TryGetSlotDataValue(ref int option, Dictionary<string, object> slotData, string key, int defaultValue) { try { option = int.Parse(slotData[key].ToString()); } catch (KeyNotFoundException) { Core.Logger.LogWarning((object)$"No key found for option \"{key}\". Using default value ({defaultValue})"); option = defaultValue; } } public static void TryGetSlotDataValue(ref bool option, Dictionary<string, object> slotData, string key, bool defaultValue) { try { option = bool.Parse(slotData[key].ToString()); } catch (KeyNotFoundException) { Core.Logger.LogWarning((object)$"No key found for option \"{key}\". Using default value ({defaultValue})"); option = defaultValue; } } public static void TryGetSlotDataValue(ref BossOptions option, Dictionary<string, object> slotData, string key, BossOptions defaultValue) { try { option = (BossOptions)int.Parse(slotData[key].ToString()); } catch (KeyNotFoundException) { Core.Logger.LogWarning((object)$"No key found for option \"{key}\". Using default value ({defaultValue})"); option = defaultValue; } } public static bool Connect() { //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Expected O, but got Unknown //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Expected O, but got Unknown //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Expected O, but got Unknown //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Expected O, but got Unknown //IL_0834: Unknown result type (might be due to invalid IL or missing references) //IL_0525: Unknown result type (might be due to invalid IL or missing references) //IL_05b2: Unknown result type (might be due to invalid IL or missing references) //IL_072b: Unknown result type (might be due to invalid IL or missing references) if (Authenticated) { return true; } Session = ArchipelagoSessionFactory.CreateSession(Core.data.host_name, 38281); Session.Socket.SocketClosed += new SocketClosedHandler(SocketClosed); Session.Socket.ErrorReceived += new ErrorReceivedHandler(ErrorReceived); Session.Socket.PacketReceived += new PacketReceivedHandler(PacketReceived); Session.Items.ItemReceived += new ItemReceivedHandler(ItemReceived); LoginResult val = Session.TryConnectAndLogin("ULTRAKILL", Core.data.slot_name, (ItemsHandlingFlags)5, new Version(AP_VERSION[0], AP_VERSION[1], AP_VERSION[2]), (string[])null, (string)null, (Core.data.password == "") ? null : Core.data.password, true); LoginSuccessful val2 = (LoginSuccessful)(object)((val is LoginSuccessful) ? val : null); if (val2 != null) { Authenticated = true; ConfigManager.isConnected.value = true; ((ConfigField)ConfigManager.playerName).interactable = false; ((ConfigField)ConfigManager.serverAddress).interactable = false; ((ConfigField)ConfigManager.serverPassword).interactable = false; ((ConfigField)ConfigManager.hintMode).interactable = false; ((ConfigField)ConfigManager.chat).interactable = true; TryGetGoal(ref Core.data.goal, val2.SlotData, "6-2"); TryGetSlotDataValue(ref Core.data.goalRequirement, val2.SlotData, "goal_requirement", 15); TryGetSlotDataValue(ref Core.data.bossRewards, val2.SlotData, "boss_rewards", BossOptions.Disabled); TryGetSlotDataValue(ref Core.data.challengeRewards, val2.SlotData, "challenge_rewards", defaultValue: false); TryGetSlotDataValue(ref Core.data.pRankRewards, val2.SlotData, "p_rank_rewards", defaultValue: false); TryGetSlotDataValue(ref Core.data.fishRewards, val2.SlotData, "fish_rewards", defaultValue: false); TryGetSlotDataValue(ref Core.data.randomizeFire2, val2.SlotData, "randomize_secondary_fire", defaultValue: false); TryGetSlotDataValue(ref Core.data.randomizeSkulls, val2.SlotData, "randomize_skulls", defaultValue: false); if (Core.data.randomizeSkulls && UIManager.skullIcons.Count == 0) { UIManager.CreateSkullIcons(); } if (!Core.DataExists()) { TryGetSlotDataValue(ref Core.data.hasArm, val2.SlotData, "start_with_arm", defaultValue: true); TryGetSlotDataValue(ref Core.data.dashes, val2.SlotData, "starting_stamina", 3); TryGetSlotDataValue(ref Core.data.walljumps, val2.SlotData, "starting_walljumps", 3); TryGetSlotDataValue(ref Core.data.canSlide, val2.SlotData, "start_with_slide", defaultValue: true); TryGetSlotDataValue(ref Core.data.canSlam, val2.SlotData, "start_with_slam", defaultValue: true); TryGetSlotDataValue(ref Core.data.multiplier, val2.SlotData, "point_multiplier", 1); TryGetSlotDataValue(ref Core.data.musicRandomizer, val2.SlotData, "music_randomizer", defaultValue: false); if (Core.data.musicRandomizer) { Core.data.music = JsonConvert.DeserializeObject<Dictionary<string, string>>(val2.SlotData["music"].ToString()); } TryGetSlotDataValue(ref Core.data.cybergrindHints, val2.SlotData, "cybergrind_hints", defaultValue: true); try { ConfigManager.uiColorRandomizer.value = (ColorOptions)Enum.Parse(typeof(ColorOptions), val2.SlotData["ui_color_randomizer"].ToString()); } catch (KeyNotFoundException) { ConfigManager.uiColorRandomizer.value = ColorOptions.Off; } try { ConfigManager.gunColorRandomizer.value = (ColorOptions)Enum.Parse(typeof(ColorOptions), val2.SlotData["gun_color_randomizer"].ToString()); } catch (KeyNotFoundException) { ConfigManager.gunColorRandomizer.value = ColorOptions.Off; } MonoSingleton<PrefsManager>.Instance.SetInt("difficulty", 4); MonoSingleton<PrefsManager>.Instance.SetInt("weapon.arm0", 1); GameProgressSaver.SetIntro(true); GameProgressSaver.SetTutorial(true); GameProgressSaver.UnlockWeaponCustomization((WeaponCustomizationType)0); GameProgressSaver.UnlockWeaponCustomization((WeaponCustomizationType)1); GameProgressSaver.UnlockWeaponCustomization((WeaponCustomizationType)2); GameProgressSaver.UnlockWeaponCustomization((WeaponCustomizationType)3); GameProgressSaver.UnlockWeaponCustomization((WeaponCustomizationType)4); GameProgressSaver.SaveProgress(30); GameProgressSaver.SetPrime(1, 1); GameProgressSaver.SetPrime(2, 1); Core.SaveData(); if (ConfigManager.uiColorRandomizer.value != 0) { ColorRandomizer.RandomizeUIColors(); } if (ConfigManager.gunColorRandomizer.value != 0) { ColorRandomizer.RandomizeGunColors(); } Core.data.deathLink = bool.Parse(val2.SlotData["death_link"].ToString()); } if (Core.data.deathLink) { EnableDeathLink(); } MonoSingleton<PrefsManager>.Instance.SetInt("weapon.arm0", 1); LocationManager.locations.Clear(); RawLocationData[] array = ((JToken)(JArray)val2.SlotData["locations"]).ToObject<RawLocationData[]>(); foreach (RawLocationData rawLocationData in array) { AItem item = ((!rawLocationData.ukitem) ? ((AItem)new APItem { itemName = rawLocationData.item_name, playerName = rawLocationData.player_name, type = (ItemFlags)int.Parse(rawLocationData.item_type) }) : ((AItem)new UKItem { itemName = rawLocationData.item_name, playerName = rawLocationData.player_name, type = (UKType)int.Parse(rawLocationData.item_type) })); LocationManager.locations.Add(rawLocationData.id, new Location { id = rawLocationData.id, ap_id = rawLocationData.ap_id, item = item, @checked = Core.data.@checked.Contains(rawLocationData.id) }); } if (Core.DataExists() && Core.data.@checked.Count > 0) { foreach (string item2 in Core.data.@checked) { LocationManager.CheckLocation(item2); if (LocationManager.locations[item2].item is UKItem uKItem && LocationManager.ShouldGetItemAgain(uKItem.type)) { LocationManager.GetUKItem(uKItem, null, silent: true, save: false); } } Core.SaveData(); } ConfigManager.LoadStats(); Core.Logger.LogInfo((object)("Successfully connected to server as player \"" + Core.data.slot_name + "\".")); ConfigManager.connectionInfo.text = "Successfully connected to server as player \"" + Core.data.slot_name + "\"."; ((Graphic)UIManager.menuIcon.GetComponent<Image>()).color = Colors.Green; string text = ((LocationManager.locations.Count == 0) ? "?" : LocationManager.locations.Count.ToString()); ((TMP_Text)UIManager.menuText).text = "Archipelago\n2.0.7\nSlot " + (GameProgressSaver.currentSlot + 1) + "\n" + Core.data.@checked.Count + "/" + text; } else { LoginFailure val3 = (LoginFailure)(object)((val is LoginFailure) ? val : null); if (val3 != null) { Authenticated = false; Core.Logger.LogError((object)string.Join("\n", val3.Errors)); ConfigManager.connectionInfo.text = string.Join("\n", val3.Errors); Session.Socket.DisconnectAsync(); Session = null; ((Graphic)UIManager.menuIcon.GetComponent<Image>()).color = Colors.Red; } } return val.Successful; } public static bool ConnectBK() { //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Expected O, but got Unknown //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Expected O, but got Unknown //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Expected O, but got Unknown //IL_01a2: Unknown result type (might be due to invalid IL or missing references) //IL_0255: Unknown result type (might be due to invalid IL or missing references) if (Authenticated) { return true; } Session = ArchipelagoSessionFactory.CreateSession(Core.data.host_name, 38281); Session.Socket.SocketClosed += new SocketClosedHandler(SocketClosed); Session.Socket.ErrorReceived += new ErrorReceivedHandler(ErrorReceived); Session.Socket.PacketReceived += new PacketReceivedHandler(PacketReceived); LoginResult val = Session.TryConnectAndLogin("", Core.data.slot_name, (ItemsHandlingFlags)0, new Version(AP_VERSION[0], AP_VERSION[1], AP_VERSION[2]), new string[1] { "TextOnly" }, (string)null, (Core.data.password == "") ? null : Core.data.password, false); LoginSuccessful val2 = (LoginSuccessful)(object)((val is LoginSuccessful) ? val : null); if (val2 != null) { Authenticated = true; HintMode = true; ConfigManager.isConnected.value = true; ((ConfigField)ConfigManager.playerName).interactable = false; ((ConfigField)ConfigManager.serverAddress).interactable = false; ((ConfigField)ConfigManager.serverPassword).interactable = false; ((ConfigField)ConfigManager.hintMode).interactable = false; ((ConfigField)ConfigManager.chat).interactable = true; Core.Logger.LogInfo((object)("Successfully connected to server in hint mode as player \"" + Core.data.slot_name + "\".")); ConfigManager.connectionInfo.text = "Successfully connected to server in hint mode as player \"" + Core.data.slot_name + "\"."; ((Graphic)UIManager.menuIcon.GetComponent<Image>()).color = Colors.Green; ((TMP_Text)UIManager.menuText).text = "Archipelago\n2.0.7\nSlot " + (GameProgressSaver.currentSlot + 1) + "\n<color=yellow>Hint Mode</color>"; } else { LoginFailure val3 = (LoginFailure)(object)((val is LoginFailure) ? val : null); if (val3 != null) { Authenticated = false; HintMode = false; Core.Logger.LogError((object)string.Join("\n", val3.Errors)); ConfigManager.connectionInfo.text = string.Join("\n", val3.Errors); Session.Socket.DisconnectAsync(); Session = null; ((Graphic)UIManager.menuIcon.GetComponent<Image>()).color = Colors.Red; } } return val.Successful; } public static void Disconnect() { //IL_0091: Unknown result type (might be due to invalid IL or missing references) ConfigManager.isConnected.value = false; ((ConfigField)ConfigManager.playerName).interactable = true; ((ConfigField)ConfigManager.serverAddress).interactable = true; ((ConfigField)ConfigManager.serverPassword).interactable = true; ((ConfigField)ConfigManager.hintMode).interactable = true; ((ConfigField)ConfigManager.chat).interactable = false; if (Session != null && Session.Socket != null) { Session.Socket.DisconnectAsync(); } if (SceneHelper.CurrentScene == "Main Menu") { ((Graphic)UIManager.menuIcon.GetComponent<Image>()).color = Colors.Red; } UIManager.SetLogText(""); messages.Clear(); Session = null; DeathLinkService = null; Authenticated = false; HintMode = false; } public static void SocketClosed(string reason) { Core.Logger.LogError((object)("Lost connection to Archipelago server. " + reason)); Disconnect(); } public static void ErrorReceived(Exception e, string message) { Core.Logger.LogError((object)message); if (e != null) { Core.Logger.LogError((object)e.ToString()); } Disconnect(); } public static void PacketReceived(ArchipelagoPacketBase packet) { //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_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_000c: Invalid comparison between Unknown and I4 //IL_0053: 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) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Expected I4, but got Unknown //IL_02ef: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_024b: Unknown result type (might be due to invalid IL or missing references) //IL_01cd: Unknown result type (might be due to invalid IL or missing references) //IL_01d2: Unknown result type (might be due to invalid IL or missing references) //IL_01d4: Unknown result type (might be due to invalid IL or missing references) //IL_01d7: Unknown result type (might be due to invalid IL or missing references) //IL_01ed: Expected I4, but got Unknown //IL_01f4: Unknown result type (might be due to invalid IL or missing references) //IL_0211: Unknown result type (might be due to invalid IL or missing references) //IL_022e: Unknown result type (might be due to invalid IL or missing references) ArchipelagoPacketType packetType = packet.PacketType; ArchipelagoPacketType val = packetType; if ((int)val != 6) { return; } if (messages.Count >= UIManager.lines) { messages.RemoveAt(0); } PrintJsonPacket val2 = (PrintJsonPacket)(object)((packet is PrintJsonPacket) ? packet : null); string text = ""; string text2 = ""; string text3 = "<color=#" + ColorUtility.ToHtmlStringRGB(Colors.White) + "FF>"; JsonMessagePart[] data = val2.Data; foreach (JsonMessagePart val3 in data) { switch (val3.Type) { case 0L: { text3 = ((!(Session.Players.GetPlayerName(int.Parse(val3.Text)) == Core.data.slot_name)) ? ("<color=#" + ColorUtility.ToHtmlStringRGB(Colors.PlayerOther) + "FF>") : ("<color=#" + ColorUtility.ToHtmlStringRGB(Colors.PlayerSelf) + "FF>")); if (int.TryParse(val3.Text, out var result3)) { string text6 = Session.Players.GetPlayerAlias(result3) ?? $"Slot: {result3}"; text = text + text3 + text6 + "</color>"; text2 += text6; } else { text = text + text3 + val3.Text + "</color>"; text2 += val3.Text; } break; } case 2L: { text3 = val3.Flags switch { 0L => "<color=#" + ColorUtility.ToHtmlStringRGB(Colors.ItemAdvancement) + "FF>", 1L => "<color=#" + ColorUtility.ToHtmlStringRGB(Colors.ItemNeverExclude) + "FF>", 3L => "<color=#" + ColorUtility.ToHtmlStringRGB(Colors.ItemTrap) + "FF>", _ => "<color=#" + ColorUtility.ToHtmlStringRGB(Colors.ItemFiller) + "FF>", }; if (long.TryParse(val3.Text, out var result2)) { string text5 = Session.Items.GetItemName(result2) ?? $"Item: {result2}"; text = text + text3 + text5 + "</color>"; text2 += text5; } else { text = text + text3 + val3.Text + "</color>"; text2 += val3.Text; } break; } case 4L: { text3 = "<color=#" + ColorUtility.ToHtmlStringRGB(Colors.Location) + "FF>"; if (long.TryParse(val3.Text, out var result)) { string text4 = Session.Locations.GetLocationNameFromId(result) ?? $"Location: {result}"; text = text + text3 + text4 + "</color>"; text2 += text4; } else { text = text + text3 + val3.Text + "</color>"; text2 += val3.Text; } break; } default: text += val3.Text; text2 += val3.Text; break; } } messages.Add(text); UIManager.SetLogText(string.Join("\n", messages.ToArray())); } public static void ItemReceived(ReceivedItemsHelper helper) { //IL_01b2: Unknown result type (might be due to invalid IL or missing references) //IL_005a: 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_0084: 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) bool flag = LocationManager.ShouldGetItemAgain(LocationManager.GetTypeFromName(helper.PeekItemName())); bool silent = helper.Index <= Core.data.index &&
websocket-sharp.dll
Decompiled 2 weeks 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.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: AssemblyVersion("1.0.2.34775")] 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); CopyTo(stream, deflateStream, 1024); deflateStream.Close(); memoryStream.Write(_last, 0, 1); memoryStream.Position = 0L; return memoryStream; } private static byte[] compressToArray(this Stream stream) { using MemoryStream memoryStream = stream.compress(); memoryStream.Close(); return memoryStream.ToArray(); } private static byte[] decompress(this byte[] data) { if (data.LongLength == 0) { return data; } using MemoryStream stream = new MemoryStream(data); return stream.decompressToArray(); } private static MemoryStream decompress(this Stream stream) { MemoryStream memoryStream = new MemoryStream(); if (stream.Length == 0) { return memoryStream; } stream.Position = 0L; using DeflateStream source = new DeflateStream(stream, CompressionMode.Decompress, leaveOpen: true); CopyTo(source, memoryStream, 1024); memoryStream.Position = 0L; return memoryStream; } private static byte[] decompressToArray(this Stream stream) { using MemoryStream memoryStream = stream.decompress(); memoryStream.Close(); return memoryStream.ToArray(); } private static 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; CopyTo(stream, 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 source = new MemoryStream(bytes); CopyTo(source, stream, bufferLength); } internal static void WriteBytesAsync(this Stream stream, byte[] bytes, int bufferLength, Action completed, Action<Exception> error) { MemoryStream 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 ((object)typeFromHandle == typeof(bool)) ? ((T)(object)BitConverter.ToBoolean(value, 0)) : (((object)typeFromHandle == typeof(char)) ? ((T)(object)BitConverter.ToChar(value, 0)) : (((object)typeFromHandle == typeof(double)) ? ((T)(object)BitConverter.ToDouble(value, 0)) : (((object)typeFromHandle == typeof(short)) ? ((T)(object)BitConverter.ToInt16(value, 0)) : (((object)typeFromHandle == typeof(int)) ? ((T)(object)BitConverter.ToInt32(value, 0)) : (((object)typeFromHandle == typeof(long)) ? ((T)(object)BitConverter.ToInt64(value, 0)) : (((object)typeFromHandle == typeof(float)) ? ((T)(object)BitConverter.ToSingle(value, 0)) : (((object)typeFromHandle == typeof(ushort)) ? ((T)(object)BitConverter.ToUInt16(value, 0)) : (((object)typeFromHandle == typeof(uint)) ? ((T)(object)BitConverter.ToUInt32(value, 0)) : (((object)typeFromHandle == typeof(ulong)) ? ((T)(object)BitConverter.ToUInt64(value, 0)) : default(T)))))))))); } [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 = (((object)typeFromHandle == typeof(bool)) ? BitConverter.GetBytes((bool)(object)value) : (((object)typeFromHandle != typeof(byte)) ? (((object)typeFromHandle == typeof(char)) ? BitConverter.GetBytes((char)(object)value) : (((object)typeFromHandle == typeof(double)) ? BitConverter.GetBytes((double)(object)value) : (((object)typeFromHandle == typeof(short)) ? BitConverter.GetBytes((short)(object)value) : (((object)typeFromHandle == typeof(int)) ? BitConverter.GetBytes((int)(object)value) : (((object)typeFromHandle == typeof(long)) ? BitConverter.GetBytes((long)(object)value) : (((object)typeFromHandle == typeof(float)) ? BitConverter.GetBytes((float)(object)value) : (((object)typeFromHandle == typeof(ushort)) ? BitConverter.GetBytes((ushort)(object)value) : (((object)typeFromHandle == typeof(uint)) ? BitConverter.GetBytes((uint)(object)value) : (((object)typeFromHandle == typeof(ulong)) ? BitConverter.GetBytes((ulong)(object)value) : WebSocket.EmptyBytes))))))))) : 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);