Decompiled source of PeaksOfArchipelago v1.0.5
Archipelago.MultiClient.Net.dll
Decompiled a day ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Net.WebSockets; using System.Numerics; 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.ConcurrentCollection; using Archipelago.MultiClient.Net.Converters; using Archipelago.MultiClient.Net.DataPackage; 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(".NETStandard,Version=v2.0", FrameworkDisplayName = ".NET Standard 2.0")] [assembly: AssemblyCompany("Jarno Westhof, Hussein Farran, Zach Parks")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyCopyright("Copyright © 2025")] [assembly: AssemblyDescription("A client library for use with .NET based prog-langs for interfacing with Archipelago hosts.")] [assembly: AssemblyFileVersion("6.5.0.0")] [assembly: AssemblyInformationalVersion("6.5.0+85e5c9f7199bf77adbab527815a79a7818b3f441")] [assembly: AssemblyProduct("Archipelago.MultiClient.Net")] [assembly: AssemblyTitle("Archipelago.MultiClient.Net")] [assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/ArchipelagoMW/Archipelago.MultiClient.Net")] [assembly: AssemblyVersion("6.5.0.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 interface IArchipelagoSession : IArchipelagoSessionActions { IArchipelagoSocketHelper Socket { get; } IReceivedItemsHelper Items { get; } ILocationCheckHelper Locations { get; } IPlayerHelper Players { get; } IDataStorageHelper DataStorage { get; } IConnectionInfoProvider ConnectionInfo { get; } IRoomStateHelper RoomState { get; } IMessageLogHelper MessageLog { get; } Task<RoomInfoPacket> ConnectAsync(); Task<LoginResult> LoginAsync(string game, string name, ItemsHandlingFlags itemsHandlingFlags, Version version = null, string[] tags = null, string uuid = null, string password = null, bool requestSlotData = true); LoginResult TryConnectAndLogin(string game, string name, ItemsHandlingFlags itemsHandlingFlags, Version version = null, string[] tags = null, string uuid = null, string password = null, bool requestSlotData = true); } public class ArchipelagoSession : IArchipelagoSession, IArchipelagoSessionActions { private const int ArchipelagoConnectionTimeoutInSeconds = 4; private ConnectionInfoHelper connectionInfo; private TaskCompletionSource<LoginResult> loginResultTask = new TaskCompletionSource<LoginResult>(); private TaskCompletionSource<RoomInfoPacket> roomInfoPacketTask = new TaskCompletionSource<RoomInfoPacket>(); public IArchipelagoSocketHelper Socket { get; } public IReceivedItemsHelper Items { get; } public ILocationCheckHelper Locations { get; } public IPlayerHelper Players { get; } public IDataStorageHelper DataStorage { get; } public IConnectionInfoProvider ConnectionInfo => connectionInfo; public IRoomStateHelper RoomState { get; } public IMessageLogHelper MessageLog { get; } internal ArchipelagoSession(IArchipelagoSocketHelper socket, IReceivedItemsHelper items, ILocationCheckHelper locations, IPlayerHelper players, IRoomStateHelper roomState, ConnectionInfoHelper connectionInfoHelper, IDataStorageHelper dataStorage, IMessageLogHelper messageLog) { Socket = socket; Items = items; Locations = locations; Players = players; RoomState = roomState; connectionInfo = connectionInfoHelper; 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 + ":NETSTANDARD2_0", 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.TrySetResult(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.TrySetResult(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 void Say(string message) { Socket.SendPacket(new SayPacket { Text = message }); } public void SetClientState(ArchipelagoClientState state) { Socket.SendPacket(new StatusUpdatePacket { Status = state }); } public void SetGoalAchieved() { SetClientState(ArchipelagoClientState.ClientGoal); } } public interface IArchipelagoSessionActions { void Say(string message); void SetClientState(ArchipelagoClientState state); void SetGoalAchieved(); } public static class ArchipelagoSessionFactory { public static ArchipelagoSession CreateSession(Uri uri) { ArchipelagoSocketHelper socket = new ArchipelagoSocketHelper(uri); DataPackageCache cache = new DataPackageCache(socket); ConnectionInfoHelper connectionInfoHelper = new ConnectionInfoHelper(socket); PlayerHelper playerHelper = new PlayerHelper(socket, connectionInfoHelper); ItemInfoResolver itemInfoResolver = new ItemInfoResolver(cache, connectionInfoHelper); LocationCheckHelper locationCheckHelper = new LocationCheckHelper(socket, itemInfoResolver, connectionInfoHelper, playerHelper); ReceivedItemsHelper items = new ReceivedItemsHelper(socket, locationCheckHelper, itemInfoResolver, connectionInfoHelper, playerHelper); RoomStateHelper roomState = new RoomStateHelper(socket, locationCheckHelper); DataStorageHelper dataStorage = new DataStorageHelper(socket, connectionInfoHelper); MessageLogHelper messageLog = new MessageLogHelper(socket, itemInfoResolver, playerHelper, connectionInfoHelper); return new ArchipelagoSession(socket, items, locationCheckHelper, playerHelper, 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}.", }; } } internal class TwoWayLookup<TA, TB> : IEnumerable<KeyValuePair<TB, TA>>, IEnumerable { private readonly Dictionary<TA, TB> aToB = new Dictionary<TA, TB>(); private readonly Dictionary<TB, TA> bToA = new Dictionary<TB, TA>(); public TA this[TB b] => bToA[b]; public TB this[TA a] => aToB[a]; public void Add(TA a, TB b) { aToB[a] = b; bToA[b] = a; } public void Add(TB b, TA a) { Add(a, b); } public bool TryGetValue(TA a, out TB b) { return aToB.TryGetValue(a, out b); } public bool TryGetValue(TB b, out TA a) { return bToA.TryGetValue(b, out a); } public IEnumerator<KeyValuePair<TB, TA>> GetEnumerator() { return bToA.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } } } 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 Archipelago.MultiClient.Net.Models.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 int 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("generator_version")] public NetworkVersion GeneratorVersion { 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; } [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; } [JsonExtensionData] public Dictionary<string, JToken> AdditionalArguments { get; set; } [OnDeserialized] internal void OnDeserializedMethod(StreamingContext context) { AdditionalArguments?.Remove("cmd"); } } public class SetReplyPacket : SetPacket { public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.SetReply; [JsonProperty("value")] public JToken Value { get; set; } [JsonProperty("original_value")] public JToken OriginalValue { 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; internal Dictionary<string, JToken> AdditionalArguments = new Dictionary<string, JToken>(0); 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(); Callbacks = source.Callbacks; AdditionalArguments = source.AdditionalArguments; Operations.Add(new OperationSpecification { OperationType = operationType, Value = value }); } internal DataStorageElement(DataStorageElement source, Callback callback) : this(source.Context) { Operations = source.Operations.ToList(); Callbacks = source.Callbacks; AdditionalArguments = source.AdditionalArguments; Callbacks = (DataStorageHelper.DataStorageUpdatedHandler)Delegate.Combine(Callbacks, callback.Method); } internal DataStorageElement(DataStorageElement source, AdditionalArgument additionalArgument) : this(source.Context) { Operations = source.Operations.ToList(); Callbacks = source.Callbacks; AdditionalArguments = source.AdditionalArguments; AdditionalArguments[additionalArgument.Key] = additionalArgument.Value; } 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, int b) { return new DataStorageElement(a, OperationType.Add, JToken.op_Implicit(b)); } public static DataStorageElement operator +(DataStorageElement a, long b) { return new DataStorageElement(a, OperationType.Add, JToken.op_Implicit(b)); } public static DataStorageElement operator +(DataStorageElement a, float b) { return new DataStorageElement(a, OperationType.Add, JToken.op_Implicit(b)); } public static DataStorageElement operator +(DataStorageElement a, double b) { return new DataStorageElement(a, OperationType.Add, JToken.op_Implicit(b)); } public static DataStorageElement operator +(DataStorageElement a, decimal b) { return new DataStorageElement(a, OperationType.Add, JToken.op_Implicit(b)); } public static DataStorageElement operator +(DataStorageElement a, string b) { return new DataStorageElement(a, OperationType.Add, JToken.op_Implicit(b)); } 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, AdditionalArgument arg) { return new DataStorageElement(a, arg); } public static DataStorageElement operator *(DataStorageElement a, int b) { return new DataStorageElement(a, OperationType.Mul, JToken.op_Implicit(b)); } public static DataStorageElement operator *(DataStorageElement a, long b) { return new DataStorageElement(a, OperationType.Mul, JToken.op_Implicit(b)); } public static DataStorageElement operator *(DataStorageElement a, float b) { return new DataStorageElement(a, OperationType.Mul, JToken.op_Implicit(b)); } public static DataStorageElement operator *(DataStorageElement a, double b) { return new DataStorageElement(a, OperationType.Mul, JToken.op_Implicit(b)); } public static DataStorageElement operator *(DataStorageElement a, decimal b) { return new DataStorageElement(a, OperationType.Mul, JToken.op_Implicit(b)); } public static DataStorageElement operator %(DataStorageElement a, int b) { return new DataStorageElement(a, OperationType.Mod, JToken.op_Implicit(b)); } public static DataStorageElement operator %(DataStorageElement a, long b) { return new DataStorageElement(a, OperationType.Mod, JToken.op_Implicit(b)); } public static DataStorageElement operator %(DataStorageElement a, float b) { return new DataStorageElement(a, OperationType.Mod, JToken.op_Implicit(b)); } public static DataStorageElement operator %(DataStorageElement a, double b) { return new DataStorageElement(a, OperationType.Mod, JToken.op_Implicit(b)); } public static DataStorageElement operator %(DataStorageElement a, decimal b) { return new DataStorageElement(a, OperationType.Mod, JToken.op_Implicit(b)); } public static DataStorageElement operator ^(DataStorageElement a, int b) { return new DataStorageElement(a, OperationType.Pow, JToken.op_Implicit(b)); } public static DataStorageElement operator ^(DataStorageElement a, long b) { return new DataStorageElement(a, OperationType.Pow, JToken.op_Implicit(b)); } public static DataStorageElement operator ^(DataStorageElement a, float b) { return new DataStorageElement(a, OperationType.Pow, JToken.op_Implicit(b)); } public static DataStorageElement operator ^(DataStorageElement a, double b) { return new DataStorageElement(a, OperationType.Pow, JToken.op_Implicit(b)); } public static DataStorageElement operator ^(DataStorageElement a, decimal b) { return new DataStorageElement(a, OperationType.Pow, JToken.op_Implicit(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, float b) { return new DataStorageElement(a, OperationType.Add, JToken.FromObject((object)(0f - 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, decimal b) { return new DataStorageElement(a, OperationType.Add, JToken.FromObject((object)(-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, float b) { return new DataStorageElement(a, OperationType.Mul, JToken.FromObject((object)(1.0 / (double)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, decimal b) { return new DataStorageElement(a, OperationType.Mul, JToken.FromObject((object)(1m / 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 float(DataStorageElement e) { return RetrieveAndReturnDecimalValue<float>(e); } public static implicit operator float?(DataStorageElement e) { return RetrieveAndReturnDecimalValue<float?>(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 decimal(DataStorageElement e) { return RetrieveAndReturnDecimalValue<decimal>(e); } public static implicit operator decimal?(DataStorageElement e) { return RetrieveAndReturnDecimalValue<decimal?>(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 static DataStorageElement operator +(DataStorageElement a, BigInteger b) { return new DataStorageElement(a, OperationType.Add, JToken.Parse(b.ToString())); } public static DataStorageElement operator *(DataStorageElement a, BigInteger b) { return new DataStorageElement(a, OperationType.Mul, JToken.Parse(b.ToString())); } public static DataStorageElement operator %(DataStorageElement a, BigInteger b) { return new DataStorageElement(a, OperationType.Mod, JToken.Parse(b.ToString())); } public static DataStorageElement operator ^(DataStorageElement a, BigInteger b) { return new DataStorageElement(a, OperationType.Pow, JToken.Parse(b.ToString())); } public static DataStorageElement operator -(DataStorageElement a, BigInteger b) { return new DataStorageElement(a, OperationType.Add, JToken.Parse((-b).ToString())); } public static DataStorageElement operator /(DataStorageElement a, BigInteger b) { throw new InvalidOperationException("DataStorage[Key] / BigInterger is not supported, due to loss of precision when using integer division"); } public static implicit operator DataStorageElement(BigInteger bi) { return new DataStorageElement(OperationType.Replace, JToken.Parse(bi.ToString())); } public static implicit operator BigInteger(DataStorageElement e) { return RetrieveAndReturnBigIntegerValue<BigInteger>(e); } public static implicit operator BigInteger?(DataStorageElement e) { return RetrieveAndReturnBigIntegerValue<BigInteger?>(e); } private static T RetrieveAndReturnBigIntegerValue<T>(DataStorageElement e) { if (e.cachedValue != null) { if (!BigInteger.TryParse(((object)e.cachedValue).ToString(), out var result)) { return default(T); } return (T)Convert.ChangeType(result, IsNullable<T>() ? Nullable.GetUnderlyingType(typeof(T)) : typeof(T)); } BigInteger result2; BigInteger? bigInteger = (BigInteger.TryParse(((object)e.Context.GetData(e.Context.Key)).ToString(), out result2) ? new BigInteger?(result2) : null); if (!bigInteger.HasValue && !IsNullable<T>()) { bigInteger = Activator.CreateInstance<BigInteger>(); } foreach (OperationSpecification operation in e.Operations) { if (operation.OperationType == OperationType.Floor || operation.OperationType == OperationType.Ceil) { continue; } if (!BigInteger.TryParse(((object)operation.Value).ToString(), NumberStyles.AllowLeadingSign, null, out var result3)) { throw new InvalidOperationException($"DataStorage[Key] cannot be converted to BigInterger as its value its not an integer number, value: {operation.Value}"); } switch (operation.OperationType) { case OperationType.Replace: bigInteger = result3; break; case OperationType.Add: bigInteger += result3; break; case OperationType.Mul: bigInteger *= result3; break; case OperationType.Mod: bigInteger %= result3; break; case OperationType.Pow: bigInteger = BigInteger.Pow(bigInteger.Value, (int)operation.Value); break; case OperationType.Max: { BigInteger value = result3; BigInteger? bigInteger2 = bigInteger; if (value > bigInteger2) { bigInteger = result3; } break; } case OperationType.Min: { BigInteger value = result3; BigInteger? bigInteger2 = bigInteger; if (value < bigInteger2) { bigInteger = result3; } break; } case OperationType.Xor: bigInteger ^= result3; break; case OperationType.Or: bigInteger |= result3; break; case OperationType.And: bigInteger &= result3; break; case OperationType.LeftShift: bigInteger <<= (int)operation.Value; break; case OperationType.RightShift: bigInteger >>= (int)operation.Value; break; } } e.cachedValue = JToken.Parse(bigInteger.ToString()); if (!bigInteger.HasValue) { return default(T); } return (T)Convert.ChangeType(bigInteger.Value, IsNullable<T>() ? Nullable.GetUnderlyingType(typeof(T)) : typeof(T)); } 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; case OperationType.Floor: num = Math.Floor(num.Value); break; case OperationType.Ceil: num = Math.Ceiling(num.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; } [JsonProperty("status")] public HintStatus Status { get; set; } } public class ItemInfo { private readonly IItemInfoResolver itemInfoResolver; public long ItemId { get; } public long LocationId { get; } public PlayerInfo Player { get; } public ItemFlags Flags { get; } public string ItemName => itemInfoResolver.GetItemName(ItemId, ItemGame); public string ItemDisplayName => ItemName ?? $"Item: {ItemId}"; public string LocationName => itemInfoResolver.GetLocationName(LocationId, LocationGame); public string LocationDisplayName => LocationName ?? $"Location: {LocationId}"; public string ItemGame { get; } public string LocationGame { get; } public ItemInfo(NetworkItem item, string receiverGame, string senderGame, IItemInfoResolver itemInfoResolver, PlayerInfo player) { this.itemInfoResolver = itemInfoResolver; ItemGame = receiverGame; LocationGame = senderGame; ItemId = item.Item; LocationId = item.Location; Flags = item.Flags; Player = player; } public SerializableItemInfo ToSerializable() { return new SerializableItemInfo { IsScout = (GetType() == typeof(ScoutedItemInfo)), ItemId = ItemId, LocationId = LocationId, PlayerSlot = Player, Player = Player, Flags = Flags, ItemGame = ItemGame, ItemName = ItemName, LocationGame = LocationGame, LocationName = LocationName }; } } public class ScoutedItemInfo : ItemInfo { public new PlayerInfo Player => base.Player; public bool IsReceiverRelatedToActivePlayer { get; } public ScoutedItemInfo(NetworkItem item, string receiverGame, string senderGame, IItemInfoResolver itemInfoResolver, IPlayerHelper players, PlayerInfo player) : base(item, receiverGame, senderGame, itemInfoResolver, player) { IsReceiverRelatedToActivePlayer = (players.ActivePlayer ?? new PlayerInfo()).IsRelatedTo(player); } } 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; } [JsonProperty("hint_status")] public HintStatus? HintStatus { 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(int i) { return new OperationSpecification { OperationType = OperationType.Min, Value = JToken.op_Implicit(i) }; } public static OperationSpecification Min(long i) { return new OperationSpecification { OperationType = OperationType.Min, Value = JToken.op_Implicit(i) }; } public static OperationSpecification Min(float i) { return new OperationSpecification { OperationType = OperationType.Min, Value = JToken.op_Implicit(i) }; } public static OperationSpecification Min(double i) { return new OperationSpecification { OperationType = OperationType.Min, Value = JToken.op_Implicit(i) }; } public static OperationSpecification Min(decimal i) { return new OperationSpecification { OperationType = OperationType.Min, Value = JToken.op_Implicit(i) }; } public static OperationSpecification Min(JToken i) { return new OperationSpecification { OperationType = OperationType.Min, Value = i }; } public static OperationSpecification Min(BigInteger i) { return new OperationSpecification { OperationType = OperationType.Min, Value = JToken.Parse(i.ToString()) }; } public static OperationSpecification Max(int i) { return new OperationSpecification { OperationType = OperationType.Max, Value = JToken.op_Implicit(i) }; } public static OperationSpecification Max(long i) { return new OperationSpecification { OperationType = OperationType.Max, Value = JToken.op_Implicit(i) }; } public static OperationSpecification Max(float i) { return new OperationSpecification { OperationType = OperationType.Max, Value = JToken.op_Implicit(i) }; } public static OperationSpecification Max(double i) { return new OperationSpecification { OperationType = OperationType.Max, Value = JToken.op_Implicit(i) }; } public static OperationSpecification Max(decimal i) { return new OperationSpecification { OperationType = OperationType.Max, Value = JToken.op_Implicit(i) }; } public static OperationSpecification Max(JToken i) { return new OperationSpecification { OperationType = OperationType.Max, Value = i }; } public static OperationSpecification Max(BigInteger i) { return new OperationSpecification { OperationType = OperationType.Max, Value = JToken.Parse(i.ToString()) }; } public static OperationSpecification Remove(JToken value) { return new OperationSpecification { OperationType = OperationType.Remove, Value = value }; } public static OperationSpecification Pop(int value) { return new OperationSpecification { OperationType = OperationType.Pop, Value = JToken.op_Implicit(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 OperationSpecification Floor() { return new OperationSpecification { OperationType = OperationType.Floor, Value = null }; } public static OperationSpecification Ceiling() { return new OperationSpecification { OperationType = OperationType.Ceil, Value = null }; } } public static class Bitwise { public static OperationSpecification Xor(long i) { return new OperationSpecification { OperationType = OperationType.Xor, Value = JToken.op_Implicit(i) }; } public static OperationSpecification Xor(BigInteger i) { return new OperationSpecification { OperationType = OperationType.Xor, Value = JToken.Parse(i.ToString()) }; } public static OperationSpecification Or(long i) { return new OperationSpecification { OperationType = OperationType.Or, Value = JToken.op_Implicit(i) }; } public static OperationSpecification Or(BigInteger i) { return new OperationSpecification { OperationType = OperationType.Or, Value = JToken.Parse(i.ToString()) }; } public static OperationSpecification And(long i) { return new OperationSpecification { OperationType = OperationType.And, Value = JToken.op_Implicit(i) }; } public static OperationSpecification And(BigInteger i) { return new OperationSpecification { OperationType = OperationType.And, Value = JToken.Parse(i.ToString()) }; } 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 }; } } public class AdditionalArgument { internal string Key { get; set; } internal JToken Value { get; set; } private AdditionalArgument() { } public static AdditionalArgument Add(string name, JToken value) { return new AdditionalArgument { Key = name, Value = value }; } } public class MinimalSerializableItemInfo { public long ItemId { get; set; } public long LocationId { get; set; } public int PlayerSlot { get; set; } public ItemFlags Flags { get; set; } public string ItemGame { get; set; } public string LocationGame { get; set; } } public class SerializableItemInfo : MinimalSerializableItemInfo { public bool IsScout { get; set; } public PlayerInfo Player { get; set; } public string ItemName { get; set; } public string LocationName { get; set; } [JsonIgnore] public string ItemDisplayName => ItemName ?? $"Item: {base.ItemId}"; [JsonIgnore] public string LocationDisplayName => LocationName ?? $"Location: {base.LocationId}"; public string ToJson(bool full = false) { //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Expected O, but got Unknown MinimalSerializableItemInfo minimalSerializableItemInfo = this; if (!full) { minimalSerializableItemInfo = new MinimalSerializableItemInfo { ItemId = base.ItemId, LocationId = base.LocationId, PlayerSlot = base.PlayerSlot, Flags = base.Flags }; if (IsScout) { minimalSerializableItemInfo.ItemGame = base.ItemGame; } else { minimalSerializableItemInfo.LocationGame = base.LocationGame; } } JsonSerializerSettings val = new JsonSerializerSettings { NullValueHandling = (NullValueHandling)1, Formatting = (Formatting)0 }; return JsonConvert.SerializeObject((object)minimalSerializableItemInfo, val); } public static SerializableItemInfo FromJson(string json, IArchipelagoSession session = null) { //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Expected O, but got Unknown ItemInfoStreamingContext additional = ((session != null) ? new ItemInfoStreamingContext { Items = session.Items, Locations = session.Locations, PlayerHelper = session.Players, ConnectionInfo = session.ConnectionInfo } : null); JsonSerializerSettings val = new JsonSerializerSettings { Context = new StreamingContext(StreamingContextStates.Other, additional) }; return JsonConvert.DeserializeObject<SerializableItemInfo>(json, val); } [OnDeserialized] internal void OnDeserializedMethod(StreamingContext streamingContext) { if (base.ItemGame == null && base.LocationGame != null) { IsScout = false; } else if (base.ItemGame != null && base.LocationGame == null) { IsScout = true; } if (streamingContext.Context is ItemInfoStreamingContext itemInfoStreamingContext) { if (IsScout && base.LocationGame == null) { base.LocationGame = itemInfoStreamingContext.ConnectionInfo.Game; } else if (!IsScout && base.ItemGame == null) { base.ItemGame = itemInfoStreamingContext.ConnectionInfo.Game; } if (ItemName == null) { ItemName = itemInfoStreamingContext.Items.GetItemName(base.ItemId, base.ItemGame); } if (LocationName == null) { LocationName = itemInfoStreamingContext.Locations.GetLocationNameFromId(base.LocationId, base.LocationGame); } if (Player == null) { Player = itemInfoStreamingContext.PlayerHelper.GetPlayerInfo(base.PlayerSlot); } } } } internal class ItemInfoStreamingContext { public IReceivedItemsHelper Items { get; set; } public ILocationCheckHelper Locations { get; set; } public IPlayerHelper PlayerHelper { get; set; } public IConnectionInfoProvider ConnectionInfo { get; set; } } } 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 HintStatusMessagePart : MessagePart { internal HintStatusMessagePart(JsonMessagePart messagePart) : base(MessagePartType.HintStatus, messagePart) { base.Text = messagePart.Text; HintStatus? hintStatus = messagePart.HintStatus; if (hintStatus.HasValue) { switch (hintStatus.GetValueOrDefault()) { case HintStatus.Found: base.Color = Color.Green; break; case HintStatus.Unspecified: base.Color = Color.White; break; case HintStatus.NoPriority: base.Color = Color.SlateBlue; break; case HintStatus.Avoid: base.Color = Color.Salmon; break; case HintStatus.Priority: base.Color = Color.Plum; break; } } } } public class ItemMessagePart : MessagePart { public ItemFlags Flags { get; } public long ItemId { get; } public int Player { get; } internal ItemMessagePart(IPlayerHelper players, IItemInfoResolver items, JsonMessagePart part) : base(MessagePartType.Item, part) { Flags = part.Flags.GetValueOrDefault(); base.Color = GetColor(Flags); Player = part.Player.GetValueOrDefault(); string game = (players.GetPlayerInfo(Player) ?? new PlayerInfo()).Game; JsonMessagePartType? type = part.Type; if (type.HasValue) { switch (type.GetValueOrDefault()) { case JsonMessagePartType.ItemId: ItemId = long.Parse(part.Text); base.Text = items.GetItemName(ItemId, game) ?? $"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; } public int Player { get; } internal LocationMessagePart(IPlayerHelper players, IItemInfoResolver itemInfoResolver, JsonMessagePart part) : base(MessagePartType.Location, part, Color.Green) { Player = part.Player.GetValueOrDefault(); string game = (players.GetPlayerInfo(Player) ?? new PlayerInfo()).Game; JsonMessagePartType? type = part.Type; if (type.HasValue) { switch (type.GetValueOrDefault()) { case JsonMessagePartType.LocationId: LocationId = long.Parse(part.Text); base.Text = itemInfoResolver.GetLocationName(LocationId, game) ?? $"Location: {LocationId}"; break; case JsonMessagePartType.LocationName: LocationId = itemInfoResolver.GetLocationId(part.Text, game); 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, HintStatus } 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, int team, int slot, string message) : base(parts, players, team, slot) { Message = message; } } public class CollectLogMessage : PlayerSpecificLogMessage { internal CollectLogMessage(MessagePart[] parts, IPlayerHelper players, int team, int slot) : base(parts, players, 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, int team, int slot) : base(parts, players, team, slot) { } } public class HintItemSendLogMessage : ItemSendLogMessage { public bool IsFound { get; } internal HintItemSendLogMessage(MessagePart[] parts, IPlayerHelper players, int receiver, int sender, NetworkItem item, bool found, IItemInfoResolver itemInfoResolver) : base(parts, players, receiver, sender, item, itemInfoResolver) { IsFound = found; } } public class ItemCheatLogMessage : ItemSendLogMessage { internal ItemCheatLogMessage(MessagePart[] parts, IPlayerHelper players, int team, int slot, NetworkItem item, IItemInfoResolver itemInfoResolver) : base(parts, players, slot, 0, item, team, itemInfoResolver) { } } public class ItemSendLogMessage : LogMessage { private PlayerInfo ActivePlayer { get; } public PlayerInfo Receiver { get; } public PlayerInfo Sender { get; } public bool IsReceiverTheActivePlayer => Receiver == ActivePlayer; public bool IsSenderTheActivePlayer => Sender == ActivePlayer; public bool IsRelatedToActivePlayer { get { if (!ActivePlayer.IsRelatedTo(Receiver)) { return ActivePlayer.IsRelatedTo(Sender); } return true; } } public ItemInfo Item { get; } internal ItemSendLogMessage(MessagePart[] parts, IPlayerHelper players, int receiver, int sender, NetworkItem item, IItemInfoResolver itemInfoResolver) : this(parts, players, receiver, sender, item, players.ActivePlayer.Team, itemInfoResolver) { } internal ItemSendLogMessage(MessagePart[] parts, IPlayerHelper players, int receiver, int sender, NetworkItem item, int team, IItemInfoResolver itemInfoResolver) : base(parts) { ActivePlayer = players.ActivePlayer ?? new PlayerInfo(); Receiver = players.GetPlayerInfo(team, receiver) ?? new PlayerInfo(); Sender = players.GetPlayerInfo(team, sender) ?? new PlayerInfo(); PlayerInfo player = players.GetPlayerInfo(team, item.Player) ?? new PlayerInfo(); Item = new ItemInfo(item, Receiver.Game, Sender.Game, itemInfoResolver, player); } } public class JoinLogMessage : PlayerSpecificLogMessage { public string[] Tags { get; } internal JoinLogMessage(MessagePart[] parts, IPlayerHelper players, int team, int slot, string[] tags) : base(parts, players, team, slot) { Tags = tags; } } public class LeaveLogMessage : PlayerSpecificLogMessage { internal LeaveLogMessage(MessagePart[] parts, IPlayerHelper players, int team, int slot) : base(parts, players, 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 { private PlayerInfo ActivePlayer { get; } public PlayerInfo Player { get; } public bool IsActivePlayer => Player == ActivePlayer; public bool IsRelatedToActivePlayer => ActivePlayer.IsRelatedTo(Player); internal PlayerSpecificLogMessage(MessagePart[] parts, IPlayerHelper players, int team, int slot) : base(parts) { ActivePlayer = players.ActivePlayer ?? new PlayerInfo(); Player = players.GetPlayerInfo(team, slot) ?? new PlayerInfo(); } } public class ReleaseLogMessage : PlayerSpecificLogMessage { internal ReleaseLogMessage(MessagePart[] parts, IPlayerHelper players, int team, int slot) : base(parts, players, 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, int team, int slot, string[] tags) : base(parts, players, team, slot) { Tags = tags; } } public class TutorialLogMessage : LogMessage { internal TutorialLogMessage(MessagePart[] parts) : base(parts) { } } } namespace Archipelago.MultiClient.Net.Helpers { public class ArchipelagoSocketHelper : BaseArchipelagoSocketHelper<ClientWebSocket>, IArchipelagoSocketHelper { public Uri Uri { get; } internal ArchipelagoSocketHelper(Uri hostUri) : base(CreateWebSocket(), 1024) { Uri = hostUri; } private static ClientWebSocket CreateWebSocket() { return new ClientWebSocket(); } public async Task ConnectAsync() { await ConnectToProvidedUri(Uri); StartPolling(); } private async Task ConnectToProvidedUri(Uri uri) { if (uri.Scheme != "unspecified") { try { await Socket.ConnectAsync(uri, CancellationToken.None); return; } catch (Exception e) { OnError(e); throw; } } List<Exception> errors = new List<Exception>(0); try { await Socket.ConnectAsync(uri.AsWss(), CancellationToken.None); if (Socket.State == WebSocketState.Open) { return; } } catch (Exception item) { errors.Add(item); Socket = CreateWebSocket(); } try { await Socket.ConnectAsync(uri.AsWs(), CancellationToken.None); } catch (Exception item2) { errors.Add(item2); OnError(new AggregateException(errors)); throw; } } } public class BaseArchipelagoSocketHelper<T> where T : WebSocket { private static readonly ArchipelagoPacketConverter Converter = new ArchipelagoPacketConverter(); private readonly BlockingCollection<Tuple<ArchipelagoPacketBase, TaskCompletionSource<bool>>> sendQueue = new BlockingCollection<Tuple<ArchipelagoPacketBase, TaskCompletionSource<bool>>>(); internal T Socket; private readonly int bufferSize; public bool Connected { get { if (Socket.State != WebSocketState.Open) { return Socket.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 BaseArchipelagoSocketHelper(T socket, int bufferSize = 1024) { Socket = socket; this.bufferSize = bufferSize; } internal void StartPolling() { if (this.SocketOpened != null) { this.SocketOpened(); } Task.Run((Func<Task?>)PollingLoop); Task.Run((Func<Task?>)SendLoop); } private async Task PollingLoop() { byte[] buffer = new byte[bufferSize]; while (Socket.State == WebSocketState.Open) { string message = null; try { message = await ReadMessageAsync(buffer); } catch (Exception e) { OnError(e); } OnMessageReceived(message); await Task.Delay(20); } } private async Task SendLoop() { while (Socket.State == WebSocketState.Open) { try { await HandleSendBuffer(); } catch (Exception e) { OnError(e); } await Task.Delay(20); } } private async Task<string> ReadMessageAsync(byte[] buffer) { using MemoryStream readStream = new MemoryStream(buffer.Length); WebSocketReceiveResult result; do { result = await Socket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None); if (result.MessageType == WebSocketMessageType.Close) { try { await Socket.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None); } catch { } OnSocketClosed(); } else { readStream.Write(buffer, 0, result.Count); } } while (!result.EndOfMessage); return Encoding.UTF8.GetString(readStream.ToArray()); } public async Task DisconnectAsync() { await Socket.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 (Socket.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 / (double)bufferSize); for (int i = 0; i < messagesCount; i++) { int num = bufferSize * i; int num2 = bufferSize; bool endOfMessage = i + 1 == messagesCount; if (num2 * (i + 1) > messageBuffer.Length) { num2 = messageBuffer.Length - num; } await Socket.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 = null; try { list = JsonConvert.DeserializeObject<List<ArchipelagoPacketBase>>(message, (JsonConverter[])(object)new JsonConverter[1] { Converter }); } catch (Exception e) { OnError(e); } if (list == null) { return; } foreach (ArchipelagoPacketBase item in list) { this.PacketReceived(item); } } catch (Exception e2) { OnError(e2); } } protected 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); } } } public 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(); } return; } Team = connectedPacket.Team; Slot = connectedPacket.Slot; if (connectedPacket.SlotInfo != null && connectedPacket.SlotInfo.ContainsKey(Slot)) { Game = connectedPacket.SlotInfo[Slot].Game; } } 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 interface IDataStorageHelper : IDataStorageWrapper { DataStorageElement this[Scope scope, string key] { get; set; } DataStorageElement this[string key] { get; set; } } public class DataStorageHelper : IDataStorageHelper, IDataStorageWrapper { public delegate void DataStorageUpdatedHandler(JToken originalValue, JToken newValue, Dictionary<string, JToken> additionalArguments); 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) { //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Invalid comparison between Unknown and I4 if (!(packet is RetrievedPacket retrievedPacket)) { if (packet is SetReplyPacket setReplyPacket) { if (setReplyPacket.AdditionalArguments != null && setReplyPacket.AdditionalArguments.ContainsKey("Reference") && (int)setReplyPacket.AdditionalArguments["Reference"].Type == 15 && operationSpecificCallbacks.TryGetValue((Guid)setReplyPacket.AdditionalArguments["Reference"], out var value)) { value(setReplyPacket.OriginalValue, setReplyPacket.Value, setReplyPacket.AdditionalArguments); operationSpecificCallbacks.Remove((Guid)setReplyPacket.AdditionalArguments["Reference"]); } if (onValueChangedEventHandlers.TryGetValue(setReplyPacket.Key, out var value2)) { value2(setReplyPacket.OriginalValue, setReplyPacket.Value, setReplyPacket.AdditionalArguments); } } return; } foreach (KeyValuePair<string, JToken> datum in retrievedPacket.Data) { if (asyncRetrievalTasks.TryGetValue(datum.Key, out var value3)) { value3.TrySetResult(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) }); } Dictionary<string, JToken> dictionary = e.AdditionalArguments ?? new Dictionary<string, JToken>(0); if (e.Callbacks != null) { Guid guid = Guid.NewGuid(); operationSpecificCallbacks[guid] = e.Callbacks; dictionary["Reference"] = JToken.FromObject((object)guid); socket.SendPacketAsync(new SetPacket { Key = key, Operations = e.Operations.ToArray(), WantReply = true, AdditionalArguments = dictionary }); } else { socket.SendPacketAsync(new SetPacket { Key = key, Operations = e.Operations.ToArray(), AdditionalArguments = dictionary }); } } 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)]; } private DataStorageElement GetLocationNameGroupsElement(string game = null) { return this[Scope.ReadOnly, "location_name_groups_" + (game ?? connectionInfoProvider.Game)]; } private DataStorageElement GetClientStatusElement(int? slot = null, int? team = null) { return this[Scope.ReadOnly, $"client_status_{team ?? connectionInfoProvider.Team}_{slot ?? connectionInfoProvider.Slot}"]; } private DataStorageElement GetRaceModeElement() { return this[Scope.ReadOnly, "race_mode"]; } 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, Dictionary<string, JToken> x) { 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 GetSlotData<Dictionary<string, object>>(slot); } public T GetSlotData<T>(int? slot = null) where T : class { return GetSlotDataElement(slot).To<T>(); } public Task<Dictionary<string, object>> GetSlotDataAsync(int? slot = null) { return GetSlotDataAsync<Dictionary<string, object>>(slot); } public Task<T> GetSlotDataAsync<T>(int? slot = null) where T : class { return GetSlotDataElement(slot).GetAsync<T>(); } 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 Dictionary<string, string[]> GetLocationNameGroups(string game = null) { return GetLocationNameGroupsElement(game).To<Dictionary<string, string[]>>(); } public Task<Dictionary<string, string[]>> GetLocationNameGroupsAsync(string game = null) { return GetLocationNameGroupsElement(game).GetAsync<Dictionary<string, string[]>>(); } public ArchipelagoClientState GetClientStatus(int? slot = null, int? team = null) { return GetClientStatusElement(slot, team).To<ArchipelagoClientState?>().GetValueOrDefault(); } public Task<ArchipelagoClientState> GetClientStatusAsync(int? slo
PeaksOfArchipelago.dll
Decompiled a day agousing System; using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Threading.Tasks; 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 BepInEx; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using Newtonsoft.Json; using POKModManager; using PeaksOfArchipelago; using Steamworks; using UnityEngine; using UnityEngine.Events; using UnityEngine.SceneManagement; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = "")] [assembly: AssemblyCompany("PeaksOfArchipelago")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.0.5.0")] [assembly: AssemblyInformationalVersion("1.0.5+e92937e62b4c239e5207cfe39f972dbda2229d49")] [assembly: AssemblyProduct("Peaks Of Archipelago")] [assembly: AssemblyTitle("PeaksOfArchipelago")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.5.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } internal static class UnityUtils { public static void SetRopeText(string message) { GameObject obj = GameObject.Find("RopeCollectedTxt"); Text val = ((obj != null) ? obj.GetComponentInChildren<Text>() : null); GameObject obj2 = GameObject.Find("NPCRopeCollectedTxt"); Text val2 = ((obj2 != null) ? obj2.GetComponentInChildren<Text>() : null); if ((Object)(object)val != (Object)null) { val.text = message; } else { Debug.LogWarning((object)"didnt find RopeCollectedText"); } if ((Object)(object)val2 != (Object)null) { val2.text = message; } else { Debug.LogWarning((object)"didnt find NPCRopeCollectedText"); } } internal static void SetArtefactText(string message) { GameObject obj = GameObject.Find("ArtefactCollected"); Text val = ((obj != null) ? obj.GetComponentInChildren<Text>() : null); if ((Object)(object)val != (Object)null) { val.text = message; } else { Debug.LogWarning((object)"didnt find artefactcollectedtext"); } } public static void UndoRopeProgress(RopeCollectable ropeCollectable) { RopeAnchor component = GameObject.FindGameObjectWithTag("Player").GetComponent<RopeAnchor>(); if (ropeCollectable.isSingleRope) { GameManager control = GameManager.control; control.ropesCollected--; component.anchorsInBackpack--; component.UpdateRopesCollected(); } else { GameManager control2 = GameManager.control; control2.ropesCollected -= 2; component.anchorsInBackpack -= 2; component.UpdateRopesCollected(); } } public static void SetGameManagerArtefactCollected(Artefacts artefact, bool value) { string text = "hasArtefact_" + Utils.artefactToVariableName[artefact]; FieldInfo field = typeof(GameManager).GetField(text, BindingFlags.Instance | BindingFlags.Public); if (field != null && field.FieldType == typeof(bool)) { field.SetValue(GameManager.control, value); return; } throw new Exception("No boolean field " + text + "found in GameManager"); } public static void SetGameManagerArtefactDirty(Artefacts artefact, bool value) { string text = "artefact_" + Utils.artefactToVariableName[artefact] + "_IsDirty"; FieldInfo field = typeof(GameManager).GetField(text, BindingFlags.Instance | BindingFlags.Public); if (field != null && field.FieldType == typeof(bool)) { field.SetValue(GameManager.control, value); return; } throw new Exception("No boolean field " + text + "found in GameManager"); } public static bool GetGameManagerArtefactCollected(Artefacts artefact) { string text = "hasArtefact_" + Utils.artefactToVariableName[artefact]; FieldInfo field = typeof(GameManager).GetField(text, BindingFlags.Instance | BindingFlags.Public); if (field != null && field.FieldType == typeof(bool)) { return (bool)field.GetValue(GameManager.control); } throw new Exception("No boolean field " + text + "found in GameManager"); } internal static void SetSeedText(string message) { GameObject obj = GameObject.Find("BirdSeedCollectedTxt"); Text val = ((obj != null) ? obj.GetComponentInChildren<Text>() : null); if ((Object)(object)val != (Object)null) { val.text = message; } else { Debug.LogWarning((object)"didnt find BirdSeedCollectedTxt"); } } } namespace Archipelago.MultiClient.Net { [AttributeUsage(AttributeTargets.Field, Inherited = false, AllowMultiple = false)] internal sealed class DataStoragePropertyAttribute : Attribute { public string? SessionVariable { get; } public Scope Scope { get; } public string Key { get; } public DataStoragePropertyAttribute(string sessionVariable, Scope scope, string key) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) SessionVariable = sessionVariable; Scope = scope; Key = key; } public DataStoragePropertyAttribute(string sessionVariable, string key) : this(sessionVariable, (Scope)0, key) { } } } namespace PeaksOfArchipelago { public static class ModInfo { public const string MOD_GUID = "PeaksOfArchipelago"; public const string MOD_NAME = "Peaks Of Archipelago"; public const string MOD_DESC = "An Archipelago Implementation for Peaks Of Yore!"; public const string MOD_VERSION = "1.0.5"; } [BepInPlugin("PeaksOfArchipelago", "Peaks Of Archipelago", "1.0.5")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class PeaksOfArchipelago : BaseUnityPlugin { internal static ManualLogSource Logger; private void Awake() { Logger = ((BaseUnityPlugin)this).Logger; Logger.LogInfo((object)"Plugin PeaksOfArchipelago is loaded!"); POKManager.RegisterMod((ModClass)(object)new PeaksOfArchipelagoMod(), "Peaks Of Archipelago", "1.0.5", "An Archipelago Implementation for Peaks Of Yore!", true); Logger.LogInfo((object)"Plugin PeaksOfArchipelago is loaded2!"); } } public class PeaksOfArchipelagoMod : ModClass { [HarmonyPatch(typeof(StamperPeakSummit), "StampJournal")] public class PeakSummitedPatch { private static void Postfix(StamperPeakSummit __instance) { Peaks peaks = session.CompletePeakCheck(__instance); } } [HarmonyPatch(typeof(ArtefactOnPeak), "PickUpItem")] public class ArtefactOnPeakPatch { private static void Postfix(ArtefactOnPeak __instance) { Artefacts artefact = session.CompleteArtefactCheck(__instance); SimpleItemInfo locationDetails = session.GetLocationDetails(Utils.ArtefactToId(artefact)); UnityUtils.SetArtefactText("Found " + locationDetails.playerName + "'s " + locationDetails.itemName); } } [HarmonyPatch(typeof(RopeCollectable), "PickUpRope")] public class RopeCollectablePatch { private static void Prefix(RopeCollectable __instance) { Ropes rope = session.CompleteRopeCheck(__instance); SimpleItemInfo locationDetails = session.GetLocationDetails(Utils.RopeToId(rope)); UnityUtils.SetRopeText("Found " + locationDetails.playerName + "'s " + locationDetails.itemName); } private static void Postfix(ref IEnumerator __result, RopeCollectable __instance) { __result = MyWrapper(__result, __instance); } private static IEnumerator MyWrapper(IEnumerator original, RopeCollectable __instance) { while (original.MoveNext()) { yield return original.Current; } UnityUtils.UndoRopeProgress(__instance); yield return null; } } [HarmonyPatch(typeof(BirdSeedCollectable), "PickUpBirdSeed")] public class BirdSeedCollectablePatch { private static void Prefix(BirdSeedCollectable __instance) { BirdSeeds birdSeed = session.CompleteSeedCheck(__instance); SimpleItemInfo locationDetails = session.GetLocationDetails(Utils.BirdSeedToId(birdSeed)); UnityUtils.SetSeedText("Found " + locationDetails.playerName + "'s " + locationDetails.itemName); GameManager control = GameManager.control; control.extraBirdSeedUses--; } private static void Postfix(ref IEnumerator __result, RopeCollectable __instance) { __result = MyWrapper(__result, __instance); } private static IEnumerator MyWrapper(IEnumerator original, RopeCollectable __instance) { while (original.MoveNext()) { yield return original.Current; } yield return null; } } [HarmonyPatch(typeof(FallingEvent), "FellToDeath")] public class FellToDeathPatch { private static void Postfix() { session.HandleDeath(); } } [HarmonyPatch(typeof(ArtefactLoaderCabin), "LoadArtefacts")] public class ArtefactLoaderPatch { private static CheckList<Artefacts> savestate = new CheckList<Artefacts>(); public static void Prefix(ArtefactLoaderCabin __instance) { foreach (Artefacts value in Enum.GetValues(typeof(Artefacts))) { savestate.SetCheck(value, UnityUtils.GetGameManagerArtefactCollected(value)); UnityUtils.SetGameManagerArtefactCollected(value, session.playerData.items.artefacts.IsChecked(value)); UnityUtils.SetGameManagerArtefactDirty(value, value: false); } } public static void Postfix() { foreach (Artefacts value in Enum.GetValues(typeof(Artefacts))) { UnityUtils.SetGameManagerArtefactCollected(value, savestate.IsChecked(value)); } } } [HarmonyPatch(typeof(NPCEvents), "CheckProgress")] public class CheckProgressPatch { public static void Postfix(NPCEvents __instance) { session.SetFundamentalsBookActive(session.playerData.items.books.IsChecked(Books.Fundamentals)); GameManager.control.monocular = session.playerData.items.monocular; if (!ItemEventsPatch.isCustomEvent && __instance.runningEvent) { switch (__instance.eventName) { case "Rope": case "RopesUpgrade": case "ArtefactMap": case "Pocketwatch": case "Crampons": case "CramponsUpgrade": case "Chalkbag": case "AllArtefacts": case "TimeAttack_Event1": case "Category_2": case "Category_3": case "Category_4": case "Phonograph": __instance.runningEvent = false; Debug.Log((object)("Blocking event: " + __instance.eventName)); ((MonoBehaviour)__instance).StopCoroutine("GlowDoorEvent"); break; } } ItemEventsPatch.isCustomEvent = false; session.CheckWin(); session.UpdateRecievedItems(); if (session.uncollectedItems.Count != 0 && !__instance.runningEvent && session.currentScene != "TitleScreen") { Debug.Log((object)"starting custom event"); ItemEventsPatch.isCustomEvent = true; __instance.eventName = "AllArtefacts"; ((MonoBehaviour)__instance.npcParcelDeliverySystem).StartCoroutine("FadeScreenAndStartUnpackEvent"); } } } [HarmonyPatch(typeof(NPCSystem), "GivePlayerMonocular")] public class GivePlayerMonocularPatch { public static void Postfix() { GameManager.control.monocular = session.playerData.items.monocular; GameManager.control.Save(); } } [HarmonyPatch(typeof(NPCSystem), "GivePlayerRope")] public class GivePlayerRopePatch { public static void Postfix(NPCEvents __instance) { bool flag = (bool)typeof(NPCEvents).GetField("isStHaelga", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(__instance); bool flag2 = (bool)typeof(NPCEvents).GetField("isGreatGaol", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(__instance); if (flag) { session.CompleteRopeCheck(Ropes.StHaelgaGiven); GameManager control = GameManager.control; control.ropesCollected--; RopeAnchor component = GameObject.FindGameObjectWithTag("Player").GetComponent<RopeAnchor>(); component.anchorsInBackpack--; } if (flag2) { session.CompleteRopeCheck(Ropes.StHaelgaGiven); GameManager control2 = GameManager.control; control2.ropesCollected--; RopeAnchor component2 = GameObject.FindGameObjectWithTag("Player").GetComponent<RopeAnchor>(); component2.anchorsInBackpack--; } } } [HarmonyPatch(typeof(NPCEvents), "ItemEvents")] public class ItemEventsPatch { public static bool isCustomEvent; private static bool hasAllArtefacts = false; private static string tempText = ""; private static Text textElement; private static void Prefix(NPCEvents __instance) { hasAllArtefacts = GameManager.control.allArtefactsUnlocked; Text componentInChildren = __instance.allArtefactsInfo.GetComponentInChildren<Text>(); tempText = componentInChildren.text; textElement = componentInChildren; string text = "You got: "; session.UpdateRecievedItems(); SimpleItemInfo simpleItemInfo = session.uncollectedItems.Last(); foreach (SimpleItemInfo uncollectedItem in session.uncollectedItems) { text += uncollectedItem.itemName; if (uncollectedItem.id != simpleItemInfo.id || uncollectedItem.itemName != simpleItemInfo.itemName || uncollectedItem.playerName != simpleItemInfo.playerName) { text += ", "; } } componentInChildren.text = text; } private static void Postfix(ref IEnumerator __result, NPCEvents __instance) { __result = MyWrapper(__result, __instance); } private static IEnumerator MyWrapper(IEnumerator original, NPCEvents __instance) { while (original.MoveNext()) { yield return original.Current; } if (isCustomEvent) { isCustomEvent = false; GameManager.control.allArtefactsUnlocked = hasAllArtefacts; GameManager control = GameManager.control; control.ropesCollected -= 5; GameManager control2 = GameManager.control; control2.extraCoffeeUses -= 999999999; GameManager control3 = GameManager.control; control3.extraChalkUses -= 999999999; textElement.text = tempText; session.UpdateRecievedItems(); List<SimpleItemInfo> items = session.uncollectedItems; session.uncollectedItems = new List<SimpleItemInfo>(); foreach (SimpleItemInfo item in items) { session.UnlockById(item.id); } RopeCabinDescription[] array = Object.FindObjectsOfType<RopeCabinDescription>(); foreach (RopeCabinDescription ropeCabinDescription in array) { ropeCabinDescription.UpdateCoffeeChalk(); } ArtefactLoaderCabin obj = Object.FindObjectOfType<ArtefactLoaderCabin>(); if (obj != null) { obj.LoadArtefacts(); } RopeCabinDescription obj2 = Object.FindObjectOfType<RopeCabinDescription>(); if (obj2 != null) { obj2.CheckCabinItems(); } } yield return null; } } [HarmonyPatch(typeof(EnterPeakScene), "Awake")] public class EnterPeakScenePatch { private static void Postfix(EnterPeakScene __instance) { string text = ((object)(PeakNames)(ref GameObject.FindGameObjectWithTag("SummitBox").GetComponent<StamperPeakSummit>().peakNames)).ToString(); Debug.Log((object)("Entering peak: " + text)); } } [HarmonyPatch(typeof(StatsAndAchievements), "SetAchievement")] [HarmonyPatch(typeof(StatsAndAchievements), "SetStatFloat")] [HarmonyPatch(typeof(StatsAndAchievements), "SetStatInt")] [HarmonyPatch(typeof(StatsAndAchievements), "ResetStatsAndAchievements")] public class SetAchievementPatch { private static bool Prefix() { Debug.Log((object)"Game wants to do something with achievements, but we blocking that shit"); return false; } } [HarmonyPatch(typeof(SteamUserStats), "SetAchievement")] [HarmonyPatch(typeof(SteamUserStats), "StoreStats")] public class SetSteamAchievementPatch { private static bool Prefix(ref bool __result) { Debug.Log((object)"Game wants to do something with achievements, but we blocking that shit"); __result = true; return false; } } [HarmonyPatch(typeof(RopeAnchor), "Start")] public class StartTranspiler { private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions) { List<CodeInstruction> codes = new List<CodeInstruction>(instructions); for (int i = 0; i < codes.Count; i++) { if (i != 76 && i != 77 && i != 78) { yield return codes[i]; } } } } [HarmonyPatch(/*Could not decode attribute arguments.*/)] public class DetachThenAttachToNewTranspiler { private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions) { List<CodeInstruction> codes = new List<CodeInstruction>(instructions); for (int i = 0; i < codes.Count; i++) { if (i != 120 && i != 121 && i != 122 && i != 123) { yield return codes[i]; } } } } [HarmonyPatch(/*Could not decode attribute arguments.*/)] public class PullOutAnchorTranspiler { private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions) { List<CodeInstruction> codes = new List<CodeInstruction>(instructions); for (int i = 0; i < codes.Count; i++) { if (i != 79 && i != 80 && i != 81 && i != 82) { yield return codes[i]; } } } } [HarmonyPatch(typeof(RopeCollectable), "CheckRope")] public class CheckRopeTranspiler { private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions) { List<CodeInstruction> codes = new List<CodeInstruction>(instructions); for (int i = 0; i < codes.Count; i++) { if (i != 267 && i != 268 && i != 269 && i != 270) { yield return codes[i]; } } } } private bool justConnected = false; private Harmony harmony = new Harmony("PeaksOfArchipelago"); private PlayerData playerData; private static POASession session; [Editable] public string Hostname { get; set; } = "archipelago.gg"; [Editable] public string Port { get; set; } = "123456"; [Editable] public string SlotName { get; set; } = ""; [Editable] public string Password { get; set; } = ""; [Editable] public bool AutoConnect { get; set; } = false; [Editable] public UnityEvent Connect { get; set; } = new UnityEvent(); public override void OnEnabled() { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Expected O, but got Unknown playerData = new PlayerData(); session = new POASession(playerData); harmony.PatchAll(); Connect.AddListener(new UnityAction(OnConnect)); if (AutoConnect) { OnConnect(); } Debug.Log((object)"Loaded Peaks of Archipelago!"); } public override void OnDisabled() { harmony.UnpatchSelf(); } public override void Start() { //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) if (session.currentScene == "TitleScreen" && justConnected) { justConnected = false; Debug.Log((object)"entering cabin from main menu, resetting ropes, coffee, chalk and bird uses to zero"); GameManager.control.ropesCollected = 0; GameManager.control.extraCoffeeUses = 0; GameManager.control.extraChalkUses = 0; GameManager.control.extraBirdSeedUses = 0; } POASession pOASession = session; Scene activeScene = SceneManager.GetActiveScene(); pOASession.currentScene = ((Scene)(ref activeScene)).name; Debug.Log((object)session.currentScene); if (session.currentScene == "Cabin") { session.fundamentalsBook = GameObject.Find("PEAKJOURNAL"); } } private string GetUri() { return Hostname + ":" + Port; } private void OnConnect() { justConnected = true; session.Connect(GetUri(), SlotName, Password); } } public enum Ropes { WaltersCrag, WalkersPillar, GreatGaol, StHaelga, ExtraFirst, ExtraSecond, ExtraThird, ExtraFourth, Extra5, Extra6, Extra7, Extra8, Extra9, Extra10, Extra11, Extra12, GreatGaolGiven, StHaelgaGiven } public enum Artefacts { Hat1, Hat2, Helmet, Shoe, Shovel, Sleepingbag, Backpack, Coffebox_1, Coffebox_2, Chalkbox_1, Chalkbox_2, ClimberStatue1, ClimberStatue2, ClimberStatue3, Photograph_1, Photograph_2, Photograph_3, Photograph_4, PhotographFrame, ClimberStatue0 } public enum BirdSeeds { ExtraSeed1, ExtraSeed2, ExtraSeed3, ExtraSeed4, ExtraSeed5 } public enum Peaks { GreenhornsTop, PaltryPeak, OldMill, GrayGully, Lighthouse, OldManOfSjor, GiantsShelf, EvergreensEnd, TheTwins, OldGrovesSkelf, LandsEnd, HangmansLeap, OldLangr, AldrGrotto, ThreeBrothers, WaltersCrag, GreatCrevice, OldHagger, UgsomeStorr, WutheringCrest, PortersBoulders, JotunnsThumb, OldSkerry, HamarrStone, GiantsNose, WaltersBoulder, SunderedSons, OldWealdsBoulder, LeaningSpire, Cromlech, WalkersPillar, Eldenhorn, GreatGaol, StHaelga, YmirsShadow, GreatBulwark, SolemnTempest } public enum Books { Fundamentals, Intermediate, Advanced, Expert } public enum Tools { Pipe, RopeLengthUpgrade, Barometer, ProgressiveCrampons, Monocular, Phonograph, Pocketwatch, Chalkbag, Rope } public enum ExtraItems { ExtraRope, ExtraChalk, ExtraCoffee, ExtraSeed } internal struct SimpleItemInfo { public string playerName; public string itemName; public long id; } internal class CheckList<T> where T : struct, Enum { private readonly Dictionary<T, bool> checks; public CheckList(bool value = false) { checks = new Dictionary<T, bool>(); foreach (T value2 in Enum.GetValues(typeof(T))) { checks.Add(value2, value); } } public void SetCheck(T value, bool check) { checks[value] = check; } public bool IsChecked(T value) { return checks[value]; } public T[] GetUncheckedValues() { List<T> list = new List<T>(); foreach (T value in Enum.GetValues(typeof(T))) { if (!checks[value]) { list.Add(value); } } return list.ToArray(); } public T[] GetCheckedValues() { List<T> list = new List<T>(); foreach (T value in Enum.GetValues(typeof(T))) { if (checks[value]) { list.Add(value); } } return list.ToArray(); } public Dictionary<T, bool> GetChecks() { return checks; } } public static class Utils { private struct Location { public string name; public string type; public int id; public int region; } private struct Item { public string name; public string type; public int id; } private struct Data { public Location[] locations; public Item[] items; } public const int peakOffset = 1; public const int ropeOffset = 100; public const int artefactOffset = 200; public const int bookOffset = 300; public const int birdSeedOffset = 400; public const int toolOffset = 500; public const int extraItemOffset = 600; public static readonly Dictionary<Artefacts, string> artefactToVariableName = new Dictionary<Artefacts, string> { { Artefacts.Hat1, "Hat1" }, { Artefacts.Hat2, "Hat2" }, { Artefacts.Helmet, "Helmet" }, { Artefacts.Shoe, "Shoe" }, { Artefacts.Shovel, "Shovel" }, { Artefacts.Sleepingbag, "Sleepingbag" }, { Artefacts.Backpack, "Backpack" }, { Artefacts.Coffebox_1, "Coffeebox1" }, { Artefacts.Coffebox_2, "Coffeebox2" }, { Artefacts.Chalkbox_1, "Chalkbox1" }, { Artefacts.Chalkbox_2, "Chalkbox2" }, { Artefacts.ClimberStatue1, "Statue1" }, { Artefacts.ClimberStatue2, "Statue2" }, { Artefacts.ClimberStatue3, "Statue3" }, { Artefacts.Photograph_1, "Photograph1" }, { Artefacts.Photograph_2, "Photograph2" }, { Artefacts.Photograph_3, "Photograph3" }, { Artefacts.Photograph_4, "Photograph4" }, { Artefacts.PhotographFrame, "PhotographFrame" }, { Artefacts.ClimberStatue0, "Statue0" } }; public static Peaks GetPeakFromCollectable(StamperPeakSummit peakStamper) { //IL_0002: 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_000a: Expected I4, but got Unknown //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Expected I4, but got Unknown int num = peakStamper.peakNames - 1; if (num >= 36) { num--; } return (Peaks)(peakStamper.peakNames - 1); } public static Ropes GetRopeFromCollectable(RopeCollectable ropeCollectable) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Expected I4, but got Unknown if (!ropeCollectable.isSingleRope) { return (Ropes)(ropeCollectable.extraRopeNumber + 4); } if (ropeCollectable.isWaltersCrag) { return Ropes.WaltersCrag; } if (ropeCollectable.isWalkersPillar) { return Ropes.WalkersPillar; } if (ropeCollectable.isGreatGaol) { return Ropes.GreatGaol; } if (ropeCollectable.isStHaelga) { return Ropes.StHaelga; } throw new Exception("unknown rope"); } public static Artefacts GetArtefactFromCollectable(ArtefactOnPeak artefactOnPeak) { //IL_0002: 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_000a: Expected I4, but got Unknown //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Invalid comparison between Unknown and I4 int num = artefactOnPeak.peakArtefact - 1; if ((int)artefactOnPeak.peakArtefact >= 20) { num -= 3; } return (Artefacts)num; } public static int ArtefactToId(Artefacts artefact) { return (int)(artefact + 200); } public static int RopeToId(Ropes rope) { return (int)(rope + 100); } public static int PeakToId(Peaks peak) { return (int)(peak + 1); } public static int BookToId(Books book) { return (int)(book + 300); } public static int BirdSeedToId(BirdSeeds birdSeed) { return (int)(birdSeed + 400); } public static int ToolToId(Tools tool) { return (int)(tool + 500); } public static int ExtraItemToId(ExtraItems extraItem) { return (int)(extraItem + 600); } public static Peaks IdtoPeak(long id) { return (Peaks)(id - 1); } public static Ropes IdtoRope(long id) { return (Ropes)(id - 100); } public static Artefacts IdtoArtefact(long id) { return (Artefacts)(id - 200); } public static Books IdToBook(long id) { return (Books)(id - 300); } public static BirdSeeds IdToBirdSeed(long id) { return (BirdSeeds)(id - 400); } public static Tools IdToTool(long id) { return (Tools)(id - 500); } public static ExtraItems IdToExtraItem(long id) { return (ExtraItems)(id - 600); } public static string GetNameById(long id) { if (id < 200) { return IdtoRope(id).ToString(); } if (id < 300) { return IdtoArtefact(id).ToString(); } if (id < 600) { return IdToBook(id).ToString(); } return IdToExtraItem(id).ToString(); } public static string GetDataAsJson() { Data data = default(Data); data.locations = Array.Empty<Location>(); data.items = Array.Empty<Item>(); List<Location> list = new List<Location>(); List<Item> list2 = new List<Item>(); foreach (Peaks value in Enum.GetValues(typeof(Peaks))) { int id = PeakToId(value); string name = value.ToString(); string type = "Peak"; Location location = default(Location); location.name = name; location.type = type; location.id = id; location.region = 0; Location item = location; list.Add(item); } foreach (Ropes value2 in Enum.GetValues(typeof(Ropes))) { int id2 = RopeToId(value2); string name2 = value2.ToString(); string type2 = "Rope"; Location location = default(Location); location.name = name2; location.type = type2; location.id = id2; location.region = 0; Location item2 = location; Item item3 = default(Item); item3.name = name2; item3.type = type2; item3.id = id2; Item item4 = item3; list.Add(item2); list2.Add(item4); } foreach (Artefacts value3 in Enum.GetValues(typeof(Artefacts))) { int id3 = ArtefactToId(value3); string name3 = value3.ToString(); string type3 = "Artefact"; Location location = default(Location); location.name = name3; location.type = type3; location.id = id3; location.region = 0; Location item5 = location; Item item3 = default(Item); item3.name = name3; item3.type = type3; item3.id = id3; Item item6 = item3; list.Add(item5); list2.Add(item6); } foreach (Books value4 in Enum.GetValues(typeof(Books))) { int id4 = BookToId(value4); string name4 = value4.ToString(); string type4 = "Book"; Item item3 = default(Item); item3.name = name4; item3.type = type4; item3.id = id4; Item item7 = item3; list2.Add(item7); } foreach (BirdSeeds value5 in Enum.GetValues(typeof(BirdSeeds))) { int id5 = BirdSeedToId(value5); string name5 = value5.ToString(); string type5 = "Bird Seed"; Location location = default(Location); location.name = name5; location.type = type5; location.id = id5; location.region = 0; Location item8 = location; Item item3 = default(Item); item3.name = name5; item3.type = type5; item3.id = id5; Item item9 = item3; list.Add(item8); list2.Add(item9); } foreach (Tools value6 in Enum.GetValues(typeof(Tools))) { int id6 = ToolToId(value6); string name6 = value6.ToString(); string type6 = "Tool"; Item item3 = default(Item); item3.name = name6; item3.type = type6; item3.id = id6; Item item10 = item3; list2.Add(item10); } foreach (ExtraItems value7 in Enum.GetValues(typeof(ExtraItems))) { int id7 = ExtraItemToId(value7); string name7 = value7.ToString(); string type7 = "Extra Item"; Item item3 = default(Item); item3.name = name7; item3.type = type7; item3.id = id7; Item item11 = item3; list2.Add(item11); } data.locations = list.ToArray(); data.items = list2.ToArray(); return JsonConvert.SerializeObject((object)data); } public static Type GetTypeById(long id) { if (id >= 600) { return typeof(ExtraItems); } if (id >= 500) { return typeof(Tools); } if (id >= 400) { return typeof(BirdSeeds); } if (id >= 300) { return typeof(Books); } if (id >= 200) { return typeof(Artefacts); } if (id >= 100) { return typeof(Ropes); } if (id >= 1) { return typeof(Peaks); } return null; } public static BirdSeeds GetSeedFromCollectable(BirdSeedCollectable seedCollectable) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Expected I4, but got Unknown return (BirdSeeds)seedCollectable.extraBirdSeedNumber; } } internal class PlayerData { public class Locations { public CheckList<Ropes> ropes = new CheckList<Ropes>(); public CheckList<Artefacts> artefacts = new CheckList<Artefacts>(); public CheckList<Peaks> peaks = new CheckList<Peaks>(); public CheckList<BirdSeeds> seeds = new CheckList<BirdSeeds>(); public int progressiveCrampons; public bool pipe; public bool ropeLengthUpgrade; public bool barometer; public bool monocular; public bool phonograph; public bool pocketwatch; public bool chalkbag; public bool rope; } public class Items { public CheckList<Ropes> ropes = new CheckList<Ropes>(); public CheckList<Artefacts> artefacts = new CheckList<Artefacts>(); public CheckList<Books> books = new CheckList<Books>(); public CheckList<BirdSeeds> seeds = new CheckList<BirdSeeds>(); public int extraropeItemCount = 0; public int extraChalkItemCount = 0; public int extraCoffeeItemCount = 0; public int extraSeedItemCount = 0; public int progressiveCrampons; public bool pipe; public bool ropeLengthUpgrade; public bool barometer; public bool monocular; public bool phonograph; public bool pocketwatch; public bool chalkbag; public bool rope; } public Locations locations = new Locations(); public Items items = new Items(); } internal class POASession { [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static ItemReceivedHandler <>9__11_0; public static Func<ItemInfo, SimpleItemInfo> <>9__12_0; internal void <Connect>b__11_0(ReceivedItemsHelper helper) { Debug.Log((object)"Recieved item"); } internal SimpleItemInfo <UpdateRecievedItems>b__12_0(ItemInfo item) { SimpleItemInfo result = default(SimpleItemInfo); result.playerName = item.Player.Name; result.id = item.ItemId; result.itemName = item.ItemName; return result; } } private ArchipelagoSession session; private DeathLinkService deathLinkService; private bool playerKilled = false; private Dictionary<long, ScoutedItemInfo> scoutedItems; public readonly PlayerData playerData; private int itemcount; public List<SimpleItemInfo> uncollectedItems; public string currentScene; public GameObject fundamentalsBook; private LoginSuccessful loginSuccessful; public POASession(PlayerData playerData) { this.playerData = playerData; itemcount = 0; uncollectedItems = new List<SimpleItemInfo>(); base..ctor(); } public async Task<bool> Connect(string uri, string SlotName, string Password) { Debug.Log((object)("Connecting to " + uri)); session = ArchipelagoSessionFactory.CreateSession(uri, 38281); Debug.Log((object)"Created session!"); LoginResult result = session.TryConnectAndLogin("Peaks of Yore", SlotName, (ItemsHandlingFlags)7, (Version)null, (string[])null, (string)null, Password, true); Debug.Log((object)("Login result: " + result.Successful)); if (!result.Successful) { Debug.LogError((object)"unsuccessful connect, aborting"); Debug.LogError((object)"Something went wrong and you are not connected"); string[] errors = ((LoginFailure)result).Errors; foreach (string error in errors) { Debug.LogError((object)error); } return false; } IReceivedItemsHelper items = session.Items; object obj = <>c.<>9__11_0; if (obj == null) { ItemReceivedHandler val = delegate { Debug.Log((object)"Recieved item"); }; <>c.<>9__11_0 = val; obj = (object)val; } items.ItemReceived += (ItemReceivedHandler)obj; session.SetClientState((ArchipelagoClientState)5); loginSuccessful = (LoginSuccessful)result; if (loginSuccessful.SlotData.TryGetValue("deathLink", out var enableDeathLink) && Convert.ToBoolean(enableDeathLink)) { deathLinkService = DeathLinkProvider.CreateDeathLinkService(session); deathLinkService.EnableDeathLink(); deathLinkService.OnDeathLinkReceived += (DeathLinkReceivedHandler)delegate(DeathLink deathLinkObject) { Debug.Log((object)(deathLinkObject.Source + deathLinkObject.Cause)); KillPlayer(); }; } await LoadLocationDetails(); UpdateRecievedItems(); return result.Successful; } public void UpdateRecievedItems() { if (session != null && session.Items.AllItemsReceived.Count != itemcount) { List<SimpleItemInfo> list = session.Items.AllItemsReceived.Select(delegate(ItemInfo item) { SimpleItemInfo result = default(SimpleItemInfo); result.playerName = item.Player.Name; result.id = item.ItemId; result.itemName = item.ItemName; return result; }).ToList(); Debug.Log((object)$"total item count {list.Count}"); Debug.Log((object)$"old item count {itemcount}"); uncollectedItems = uncollectedItems.Concat(list.Skip(itemcount)).ToList(); Debug.Log((object)($"Recieved {uncollectedItems.Count} items " + uncollectedItems.ToString())); itemcount = list.Count; } } public async Task LoadLocationDetails() { ILocationCheckHelper locations = session.Locations; ReadOnlyCollection<long> allLocations = session.Locations.AllLocations; int num = 0; long[] array = new long[allLocations.Count]; foreach (long item in allLocations) { array[num] = item; num++; } scoutedItems = await locations.ScoutLocationsAsync((HintCreationPolicy)0, array); } public void HandleDeath() { //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Expected O, but got Unknown if (deathLinkService == null) { return; } if (playerKilled) { playerKilled = false; return; } Debug.Log((object)"Sending Deathlink"); if (session != null) { deathLinkService.SendDeathLink(new DeathLink(session.Players.GetPlayerAliasAndName(session.ConnectionInfo.Slot), "Fell off.")); } } public void CheckWin() { if (session == null || !loginSuccessful.SlotData.TryGetValue("goal", out var value)) { return; } string text = value.ToString(); bool flag = text == "0" || text == "2"; bool flag2 = text == "1" || text == "2"; bool flag3 = text == "3"; ReadOnlyCollection<long> allMissingLocations = session.Locations.AllMissingLocations; if (flag3) { if (allMissingLocations.Count() == 0) { Debug.Log((object)"Win condition achieved, unlocking items!"); session.SetClientState((ArchipelagoClientState)30); session.SetGoalAchieved(); } return; } foreach (long item in allMissingLocations) { Type typeById = Utils.GetTypeById(item); if ((typeById == typeof(Peaks) && flag) || (typeById == typeof(Artefacts) && flag2)) { return; } } Debug.Log((object)"Win condition achieved, unlocking items!"); session.SetClientState((ArchipelagoClientState)30); session.SetGoalAchieved(); } public void KillPlayer() { FallingEvent[] array = Object.FindObjectsOfType<FallingEvent>(); FallingEvent[] array2 = array; foreach (FallingEvent obj in array2) { MethodInfo method = typeof(FallingEvent).GetMethod("FellToDeath", BindingFlags.Instance | BindingFlags.NonPublic); if (method == null) { break; } Debug.Log((object)"killing player"); playerKilled = true; method.Invoke(obj, null); } } public SimpleItemInfo GetLocationDetails(long loc) { SimpleItemInfo result; if (scoutedItems == null) { result = default(SimpleItemInfo); result.playerName = "NoPlayer"; result.itemName = "NoItem"; return result; } result = default(SimpleItemInfo); result.playerName = scoutedItems[loc].Player.Name; result.itemName = ((ItemInfo)scoutedItems[loc]).ItemDisplayName; return result; } public Ropes CompleteRopeCheck(Ropes rope) { playerData.locations.ropes.SetCheck(rope, check: true); Debug.Log((object)("Completing rope " + rope)); if (session == null) { return (Ropes)(-1); } session.Locations.CompleteLocationChecks(new long[1] { Utils.RopeToId(rope) }); return rope; } public Ropes CompleteRopeCheck(RopeCollectable ropeCollectable) { Ropes ropeFromCollectable = Utils.GetRopeFromCollectable(ropeCollectable); CompleteRopeCheck(ropeFromCollectable); return ropeFromCollectable; } public Artefacts CompleteArtefactCheck(ArtefactOnPeak artefactOnPeak) { Artefacts artefactFromCollectable = Utils.GetArtefactFromCollectable(artefactOnPeak); Debug.Log((object)("Completing artefact " + artefactFromCollectable)); playerData.locations.artefacts.SetCheck(artefactFromCollectable, check: true); if (session == null) { return (Artefacts)(-1); } session.Locations.CompleteLocationChecks(new long[1] { Utils.ArtefactToId(artefactFromCollectable) }); return artefactFromCollectable; } public BirdSeeds CompleteSeedCheck(BirdSeedCollectable seedCollectable) { BirdSeeds seedFromCollectable = Utils.GetSeedFromCollectable(seedCollectable); Debug.Log((object)("Completing seed " + seedFromCollectable)); playerData.locations.seeds.SetCheck(seedFromCollectable, check: true); if (session == null) { return (BirdSeeds)(-1); } session.Locations.CompleteLocationChecks(new long[1] { Utils.BirdSeedToId(seedFromCollectable) }); return seedFromCollectable; } public Peaks CompletePeakCheck(StamperPeakSummit peakStamper) { if (session == null) { return (Peaks)(-1); } Peaks peakFromCollectable = Utils.GetPeakFromCollectable(peakStamper); session.Locations.CompleteLocationChecks(new long[1] { Utils.PeakToId(peakFromCollectable) }); playerData.locations.peaks.SetCheck(peakFromCollectable, check: true); Debug.Log((object)("Completing peak " + peakFromCollectable)); return peakFromCollectable; } internal void LoadArtefacts(ArtefactLoaderCabin instance) { CheckList<Artefacts> checkList = new CheckList<Artefacts>(); foreach (Artefacts value in Enum.GetValues(typeof(Artefacts))) { checkList.SetCheck(value, UnityUtils.GetGameManagerArtefactCollected(value)); UnityUtils.SetGameManagerArtefactCollected(value, playerData.items.artefacts.IsChecked(value)); UnityUtils.SetGameManagerArtefactDirty(value, value: false); } instance.LoadArtefacts(); foreach (Artefacts value2 in Enum.GetValues(typeof(Artefacts))) { UnityUtils.SetGameManagerArtefactCollected(value2, checkList.IsChecked(value2)); } } internal string UnlockById(long id) { if (id < 200) { Ropes rope = Utils.IdtoRope(id); UnlockRope(rope); return rope.ToString(); } if (id < 300) { Artefacts artefact = Utils.IdtoArtefact(id); UnlockArtefact(artefact); return artefact.ToString(); } if (id < 400) { Books book = Utils.IdToBook(id); UnlockBook(book); return book.ToString(); } if (id < 500) { BirdSeeds birdSeed = Utils.IdToBirdSeed(id); UnlockBirdSeed(birdSeed); } if (id < 600) { Tools tool = Utils.IdToTool(id); UnlockTool(tool); } ExtraItems extraItem = Utils.IdToExtraItem(id); UnlockExtraItem(extraItem); return extraItem.ToString(); } private void UnlockRope(Ropes rope) { playerData.items.ropes.SetCheck(rope, check: true); if (rope < Ropes.ExtraFirst) { GameManager control = GameManager.control; control.ropesCollected++; } else { GameManager control2 = GameManager.control; control2.ropesCollected += 2; } GameManager.control.Save(); } private void UnlockArtefact(Artefacts artefact) { playerData.items.artefacts.SetCheck(artefact, check: true); switch (artefact) { case Artefacts.Coffebox_1: case Artefacts.Coffebox_2: { GameManager.control.coffee = true; GameManager control2 = GameManager.control; control2.extraCoffeeUses += 2; break; } case Artefacts.Chalkbox_1: case Artefacts.Chalkbox_2: { GameManager control = GameManager.control; control.extraChalkUses += 2; break; } } } private void UnlockBook(Books book) { playerData.items.books.SetCheck(book, check: true); NPCEvents val = Object.FindObjectOfType<NPCEvents>(); switch (book) { case Books.Fundamentals: SetFundamentalsBookActive(enabled: true); break; case Books.Intermediate: GameManager.control.category_2_unlocked = true; val.cabin_Category2.SetActive(true); break; case Books.Advanced: GameManager.control.category_3_unlocked = true; val.cabin_Category3.SetActive(true); break; case Books.Expert: GameManager.control.category_4_unlocked = true; val.cabinIceaxes.SetActive(true); GameManager.control.iceAxes = true; ((MonoBehaviour)val.category4Ticket).StartCoroutine("GlowTicket"); break; } GameManager.control.Save(); } public void SetFundamentalsBookActive(bool enabled) { fundamentalsBook.SetActive(enabled); } private void UnlockBirdSeed(BirdSeeds birdSeed) { switch (birdSeed) { case BirdSeeds.ExtraSeed1: GameManager.control.hasExtraSeed1 = true; break; case BirdSeeds.ExtraSeed2: GameManager.control.hasExtraSeed2 = true; break; case BirdSeeds.ExtraSeed3: GameManager.control.hasExtraSeed3 = true; break; case BirdSeeds.ExtraSeed4: GameManager.control.hasExtraSeed4 = true; break; case BirdSeeds.ExtraSeed5: GameManager.control.hasExtraSeed5 = true; break; } playerData.items.seeds.SetCheck(birdSeed, check: true); } private void UnlockTool(Tools tool) { switch (tool) { case Tools.Pipe: GameManager.control.smokingpipe = true; playerData.items.pipe = true; break; case Tools.RopeLengthUpgrade: GameManager.control.ropesUpgrade = true; playerData.items.ropeLengthUpgrade = true; break; case Tools.Barometer: GameManager.control.barometer = true; GameManager.control.artefactMap = true; playerData.items.barometer = true; break; case Tools.ProgressiveCrampons: if (playerData.items.progressiveCrampons == 0) { playerData.items.progressiveCrampons++; GameManager.control.crampons = true; } else { playerData.items.progressiveCrampons++; GameManager.control.cramponsUpgrade = true; } break; case Tools.Monocular: GameManager.control.monocular = true; playerData.items.monocular = true; break; case Tools.Phonograph: GameManager.control.phonograph = true; playerData.items.phonograph = true; break; case Tools.Pocketwatch: GameManager.control.pocketwatch = true; playerData.items.pocketwatch = true; break; case Tools.Chalkbag: { GameManager control = GameManager.control; control.extraChalkUses++; playerData.items.chalkbag = true; break; } case Tools.Rope: GameManager.control.rope = true; playerData.items.rope = true; break; } GameManager.control.Save(); } private void UnlockExtraItem(ExtraItems extraItem) { switch (extraItem) { case ExtraItems.ExtraRope: { playerData.items.extraropeItemCount++; GameManager control4 = GameManager.control; control4.ropesCollected++; break; } case ExtraItems.ExtraCoffee: { GameManager.control.coffee = true; playerData.items.extraCoffeeItemCount++; GameManager control3 = GameManager.control; control3.extraCoffeeUses++; break; } case ExtraItems.ExtraChalk: { playerData.items.extraChalkItemCount++; GameManager control2 = GameManager.control; control2.extraChalkUses++; break; } case ExtraItems.ExtraSeed: { playerData.items.extraSeedItemCount++; GameManager control = GameManager.control; control.extraBirdSeedUses++; break; } } GameManager.control.Save(); } } public static class MyPluginInfo { public const string PLUGIN_GUID = "PeaksOfArchipelago"; public const string PLUGIN_NAME = "Peaks Of Archipelago"; public const string PLUGIN_VERSION = "1.0.5"; } }