Decompiled source of CrashoutCrewArchipelagoClient v1.0.4
AggroButtonSetting.dll
Decompiled 18 minutes agousing System; using System.CodeDom.Compiler; using System.ComponentModel; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using Aggro.Core; using TMPro; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyVersion("0.0.0.0")] public sealed class ButtonSetting : AggroSettingBase { private Action _onPressed; private string _buttonLabel; public Action GetOnPressed() { return _onPressed; } public string GetButtonLabel() { return _buttonLabel; } public void SetButtonLabel(string buttonLabel) { _buttonLabel = buttonLabel; } public ButtonSetting(string buttonLabel, Action onPressed) { _onPressed = onPressed; _buttonLabel = buttonLabel; } public override void SetToDefault() { } protected override void SaveToPrefs(string preferencesKey) { } protected override void LoadFromPrefs(string preferencesKey) { } } public class ButtonSettingUI : AggroSettingUI { private ButtonSetting _setting; public TextMeshProUGUI buttonLabel; public override void Set(AggroSettingBase setting) { if (setting is ButtonSetting setting2) { _setting = setting2; ((AggroSettingUI)this).Refresh(); } else { Debug.LogWarning((object)"[SETTINGS] Invalid setting type for ButtonSettingUI!"); } } public override void Refresh() { ((TMP_Text)buttonLabel).text = LocalizedText.GetText(_setting.GetButtonLabel(), true); } public void OnPressed() { _setting.GetOnPressed()?.Invoke(); } } [CompilerGenerated] [EditorBrowsable(EditorBrowsableState.Never)] [GeneratedCode("Unity.MonoScriptGenerator.MonoScriptInfoGenerator", null)] internal class UnitySourceGeneratedAssemblyMonoScriptTypes_v1 { private struct MonoScriptData { public byte[] FilePathsData; public byte[] TypesData; public int TotalTypes; public int TotalFiles; public bool IsEditorOnly; } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static MonoScriptData Get() { return new MonoScriptData { FilePathsData = new byte[146] { 0, 0, 0, 1, 0, 0, 0, 64, 92, 65, 115, 115, 101, 116, 115, 92, 67, 117, 115, 116, 111, 109, 92, 66, 117, 116, 116, 111, 110, 83, 101, 116, 116, 105, 110, 103, 92, 65, 103, 103, 114, 111, 66, 117, 116, 116, 111, 110, 83, 101, 116, 116, 105, 110, 103, 92, 66, 117, 116, 116, 111, 110, 83, 101, 116, 116, 105, 110, 103, 46, 99, 115, 0, 0, 0, 1, 0, 0, 0, 66, 92, 65, 115, 115, 101, 116, 115, 92, 67, 117, 115, 116, 111, 109, 92, 66, 117, 116, 116, 111, 110, 83, 101, 116, 116, 105, 110, 103, 92, 65, 103, 103, 114, 111, 66, 117, 116, 116, 111, 110, 83, 101, 116, 116, 105, 110, 103, 92, 66, 117, 116, 116, 111, 110, 83, 101, 116, 116, 105, 110, 103, 85, 73, 46, 99, 115 }, TypesData = new byte[40] { 0, 0, 0, 0, 14, 124, 66, 117, 116, 116, 111, 110, 83, 101, 116, 116, 105, 110, 103, 0, 0, 0, 0, 16, 124, 66, 117, 116, 116, 111, 110, 83, 101, 116, 116, 105, 110, 103, 85, 73 }, TotalFiles = 2, TotalTypes = 2, IsEditorOnly = false }; } }
AggroTextSetting.dll
Decompiled 18 minutes agousing System; using System.CodeDom.Compiler; using System.ComponentModel; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using Aggro.Core; using TMPro; using UnityEngine; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyVersion("0.0.0.0")] public sealed class TextSetting : AggroSettingBase { private Action<string> _onSaved; public string defaultText { get; private set; } public string text { get; private set; } public bool isPassword { get; private set; } public TextSetting(string defaultText, string text, bool isPassword) { this.defaultText = defaultText; this.text = text; this.isPassword = isPassword; } public override void SetToDefault() { text = defaultText; } public void SetText(string newText) { text = newText; } protected override void SaveToPrefs(string preferencesKey) { PlayerPrefs.SetString(preferencesKey, text); _onSaved?.Invoke(text); } protected override void LoadFromPrefs(string preferencesKey) { text = PlayerPrefs.GetString(preferencesKey, defaultText); } } public class TextSettingUI : AggroSettingUI { public TMP_InputField _text; private TextSetting _setting; public override void Set(AggroSettingBase setting) { if (setting is TextSetting setting2) { _setting = setting2; ((AggroSettingUI)this).Refresh(); } else { Debug.LogWarning((object)"[SETTINGS] Invalid setting type for TextSettingUI!"); } } public override void Refresh() { _text.text = _setting.text; Graphic placeholder = _text.placeholder; TMP_Text val = (TMP_Text)(object)((placeholder is TMP_Text) ? placeholder : null); if ((Object)(object)val != (Object)null) { val.text = _setting.defaultText; } if (_setting.isPassword) { _text.contentType = (ContentType)7; } } public void OnEndEdit() { _setting.SetText(_text.text); ((AggroSettingBase)_setting).Save(); } } [CompilerGenerated] [EditorBrowsable(EditorBrowsableState.Never)] [GeneratedCode("Unity.MonoScriptGenerator.MonoScriptInfoGenerator", null)] internal class UnitySourceGeneratedAssemblyMonoScriptTypes_v1 { private struct MonoScriptData { public byte[] FilePathsData; public byte[] TypesData; public int TotalTypes; public int TotalFiles; public bool IsEditorOnly; } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static MonoScriptData Get() { return new MonoScriptData { FilePathsData = new byte[134] { 0, 0, 0, 1, 0, 0, 0, 58, 92, 65, 115, 115, 101, 116, 115, 92, 67, 117, 115, 116, 111, 109, 92, 84, 101, 120, 116, 83, 101, 116, 116, 105, 110, 103, 92, 65, 103, 103, 114, 111, 84, 101, 120, 116, 83, 101, 116, 116, 105, 110, 103, 92, 84, 101, 120, 116, 83, 101, 116, 116, 105, 110, 103, 46, 99, 115, 0, 0, 0, 1, 0, 0, 0, 60, 92, 65, 115, 115, 101, 116, 115, 92, 67, 117, 115, 116, 111, 109, 92, 84, 101, 120, 116, 83, 101, 116, 116, 105, 110, 103, 92, 65, 103, 103, 114, 111, 84, 101, 120, 116, 83, 101, 116, 116, 105, 110, 103, 92, 84, 101, 120, 116, 83, 101, 116, 116, 105, 110, 103, 85, 73, 46, 99, 115 }, TypesData = new byte[36] { 0, 0, 0, 0, 12, 124, 84, 101, 120, 116, 83, 101, 116, 116, 105, 110, 103, 0, 0, 0, 0, 14, 124, 84, 101, 120, 116, 83, 101, 116, 116, 105, 110, 103, 85, 73 }, TotalFiles = 2, TotalTypes = 2, IsEditorOnly = false }; } }
Archipelago.Multiclient.Net.dll
Decompiled 18 minutes ago
The result has been truncated due to the large size, download it to view full contents!
#define DEBUG using System; using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.IO; using System.Linq; using System.Linq.Expressions; 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.Serialization.Formatters; using System.Runtime.Versioning; using System.Security; using System.Text; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; using System.Xml; using Archipelago.MultiClient.Net.Colors; 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 Microsoft.CodeAnalysis; using Newtonsoft.Json; using Newtonsoft.Json.Bson; using Newtonsoft.Json.Converters; using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq.JsonPath; using Newtonsoft.Json.Schema; using Newtonsoft.Json.Serialization; using Newtonsoft.Json.Utilities; [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 © 2026")] [assembly: AssemblyDescription("A client library for use with .NET based prog-langs for interfacing with Archipelago hosts.")] [assembly: AssemblyFileVersion("6.7.1.0")] [assembly: AssemblyInformationalVersion("6.7.1+0c57591db30f2497b0b4fef87164aa2bbe2e51b2")] [assembly: AssemblyProduct("Archipelago.MultiClient.Net")] [assembly: AssemblyTitle("Archipelago.MultiClient.Net")] [assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/ArchipelagoMW/Archipelago.MultiClient.Net")] [assembly: AssemblyVersion("6.7.1.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); } public class AttemptingStringEnumConverter : StringEnumConverter { public AttemptingStringEnumConverter() { } public AttemptingStringEnumConverter(Type namingStrategyType) : base(namingStrategyType) { } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { try { return base.ReadJson(reader, objectType, existingValue, serializer); } catch (JsonSerializationException) { return objectType.IsValueType ? Activator.CreateInstance(objectType) : null; } } } 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; } IHintsHelper Hints { 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; } public IHintsHelper Hints { get; } internal ArchipelagoSession(IArchipelagoSocketHelper socket, IReceivedItemsHelper items, ILocationCheckHelper locations, IPlayerHelper players, IRoomStateHelper roomState, ConnectionInfoHelper connectionInfoHelper, IDataStorageHelper dataStorage, IMessageLogHelper messageLog, IHintsHelper createHints) { Socket = socket; Items = items; Locations = locations; Players = players; RoomState = roomState; connectionInfo = connectionInfoHelper; DataStorage = dataStorage; MessageLog = messageLog; Hints = createHints; 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); } } else { loginResultTask.TrySetResult(LoginResult.FromPacket(packet)); } } 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, 6, 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 roomStateHelper = new RoomStateHelper(socket, locationCheckHelper); DataStorageHelper dataStorageHelper = new DataStorageHelper(socket, connectionInfoHelper); MessageLogHelper messageLog = new MessageLogHelper(socket, itemInfoResolver, playerHelper, connectionInfoHelper); HintsHelper createHints = new HintsHelper(socket, playerHelper, locationCheckHelper, roomStateHelper, dataStorageHelper); return new ArchipelagoSession(socket, items, locationCheckHelper, playerHelper, roomStateHelper, connectionInfoHelper, dataStorageHelper, messageLog, createHints); } 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(AttemptingStringEnumConverter))] 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 CreateHintsPacket : ArchipelagoPacketBase { public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.CreateHints; [JsonProperty("locations")] public long[] Locations { get; set; } [JsonProperty("player")] public int Player { get; set; } [JsonProperty("status")] public HintStatus Status { 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(AttemptingStringEnumConverter))] 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; } public class UpdateHintPacket : ArchipelagoPacketBase { public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.UpdateHint; [JsonProperty("player")] public int Player { get; set; } [JsonProperty("location")] public long Location { get; set; } [JsonProperty("status")] public HintStatus Status { get; set; } } } 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, 1); } public static DataStorageElement operator --(DataStorageElement a) { return new DataStorageElement(a, OperationType.Add, -1); } public static DataStorageElement operator +(DataStorageElement a, int b) { return new DataStorageElement(a, OperationType.Add, b); } public static DataStorageElement operator +(DataStorageElement a, long b) { return new DataStorageElement(a, OperationType.Add, b); } public static DataStorageElement operator +(DataStorageElement a, float b) { return new DataStorageElement(a, OperationType.Add, b); } public static DataStorageElement operator +(DataStorageElement a, double b) { return new DataStorageElement(a, OperationType.Add, b); } public static DataStorageElement operator +(DataStorageElement a, decimal b) { return new DataStorageElement(a, OperationType.Add, b); } public static DataStorageElement operator +(DataStorageElement a, string b) { return new DataStorageElement(a, OperationType.Add, 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, JArray.FromObject(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, b); } public static DataStorageElement operator *(DataStorageElement a, long b) { return new DataStorageElement(a, OperationType.Mul, b); } public static DataStorageElement operator *(DataStorageElement a, float b) { return new DataStorageElement(a, OperationType.Mul, b); } public static DataStorageElement operator *(DataStorageElement a, double b) { return new DataStorageElement(a, OperationType.Mul, b); } public static DataStorageElement operator *(DataStorageElement a, decimal b) { return new DataStorageElement(a, OperationType.Mul, b); } public static DataStorageElement operator %(DataStorageElement a, int b) { return new DataStorageElement(a, OperationType.Mod, b); } public static DataStorageElement operator %(DataStorageElement a, long b) { return new DataStorageElement(a, OperationType.Mod, b); } public static DataStorageElement operator %(DataStorageElement a, float b) { return new DataStorageElement(a, OperationType.Mod, b); } public static DataStorageElement operator %(DataStorageElement a, double b) { return new DataStorageElement(a, OperationType.Mod, b); } public static DataStorageElement operator %(DataStorageElement a, decimal b) { return new DataStorageElement(a, OperationType.Mod, b); } public static DataStorageElement operator ^(DataStorageElement a, int b) { return new DataStorageElement(a, OperationType.Pow, b); } public static DataStorageElement operator ^(DataStorageElement a, long b) { return new DataStorageElement(a, OperationType.Pow, b); } public static DataStorageElement operator ^(DataStorageElement a, float b) { return new DataStorageElement(a, OperationType.Pow, b); } public static DataStorageElement operator ^(DataStorageElement a, double b) { return new DataStorageElement(a, OperationType.Pow, b); } public static DataStorageElement operator ^(DataStorageElement a, decimal b) { return new DataStorageElement(a, OperationType.Pow, b); } public static DataStorageElement operator -(DataStorageElement a, int b) { return new DataStorageElement(a, OperationType.Add, JToken.FromObject(-b)); } public static DataStorageElement operator -(DataStorageElement a, long b) { return new DataStorageElement(a, OperationType.Add, JToken.FromObject(-b)); } public static DataStorageElement operator -(DataStorageElement a, float b) { return new DataStorageElement(a, OperationType.Add, JToken.FromObject(0f - b)); } public static DataStorageElement operator -(DataStorageElement a, double b) { return new DataStorageElement(a, OperationType.Add, JToken.FromObject(0.0 - b)); } public static DataStorageElement operator -(DataStorageElement a, decimal b) { return new DataStorageElement(a, OperationType.Add, JToken.FromObject(-b)); } public static DataStorageElement operator /(DataStorageElement a, int b) { return new DataStorageElement(a, OperationType.Mul, JToken.FromObject(1m / (decimal)b)); } public static DataStorageElement operator /(DataStorageElement a, long b) { return new DataStorageElement(a, OperationType.Mul, JToken.FromObject(1m / (decimal)b)); } public static DataStorageElement operator /(DataStorageElement a, float b) { return new DataStorageElement(a, OperationType.Mul, JToken.FromObject(1.0 / (double)b)); } public static DataStorageElement operator /(DataStorageElement a, double b) { return new DataStorageElement(a, OperationType.Mul, JToken.FromObject(1.0 / b)); } public static DataStorageElement operator /(DataStorageElement a, decimal b) { return new DataStorageElement(a, OperationType.Mul, JToken.FromObject(1m / b)); } public static implicit operator DataStorageElement(bool b) { return new DataStorageElement(OperationType.Replace, b); } public static implicit operator DataStorageElement(int i) { return new DataStorageElement(OperationType.Replace, i); } public static implicit operator DataStorageElement(long l) { return new DataStorageElement(OperationType.Replace, l); } public static implicit operator DataStorageElement(decimal m) { return new DataStorageElement(OperationType.Replace, m); } public static implicit operator DataStorageElement(double d) { return new DataStorageElement(OperationType.Replace, d); } public static implicit operator DataStorageElement(float f) { return new DataStorageElement(OperationType.Replace, f); } public static implicit operator DataStorageElement(string s) { if (s != null) { return new DataStorageElement(OperationType.Replace, s); } return new DataStorageElement(OperationType.Replace, 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, JArray.FromObject(a)); } public static implicit operator DataStorageElement(List<bool> l) { return new DataStorageElement(OperationType.Replace, JArray.FromObject(l)); } public static implicit operator DataStorageElement(List<int> l) { return new DataStorageElement(OperationType.Replace, JArray.FromObject(l)); } public static implicit operator DataStorageElement(List<long> l) { return new DataStorageElement(OperationType.Replace, JArray.FromObject(l)); } public static implicit operator DataStorageElement(List<decimal> l) { return new DataStorageElement(OperationType.Replace, JArray.FromObject(l)); } public static implicit operator DataStorageElement(List<double> l) { return new DataStorageElement(OperationType.Replace, JArray.FromObject(l)); } public static implicit operator DataStorageElement(List<float> l) { return new DataStorageElement(OperationType.Replace, JArray.FromObject(l)); } public static implicit operator DataStorageElement(List<string> l) { return new DataStorageElement(OperationType.Replace, JArray.FromObject(l)); } public static implicit operator DataStorageElement(List<object> l) { return new DataStorageElement(OperationType.Replace, JArray.FromObject(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(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(e.Context.GetData(e.Context.Key).ToString(), out result2) ? new BigInteger?(result2) : ((BigInteger?)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(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, JArray.FromObject(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) { if (e.cachedValue != null) { return ((JArray)e.cachedValue).ToObject<T>(); } JArray jArray = e.Context.GetData(e.Context.Key).ToObject<JArray>() ?? new JArray(); foreach (OperationSpecification operation in e.Operations) { switch (operation.OperationType) { case OperationType.Add: if (operation.Value.Type != JTokenType.Array) { throw new InvalidOperationException($"Cannot perform operation {OperationType.Add} on Array value, with a non Array value: {operation.Value}"); } jArray.Merge(operation.Value); break; case OperationType.Replace: if (operation.Value.Type != JTokenType.Array) { throw new InvalidOperationException($"Cannot replace Array value, with a non Array value: {operation.Value}"); } jArray = operation.Value.ToObject<JArray>() ?? new JArray(); break; default: throw new InvalidOperationException($"Cannot perform operation {operation.OperationType} on Array value"); } } e.cachedValue = jArray; return jArray.ToObject<T>(); } private static string RetrieveAndReturnStringValue(DataStorageElement e) { if (e.cachedValue != null) { return (string?)e.cachedValue; } JToken jToken = e.Context.GetData(e.Context.Key); string text = ((jToken.Type == JTokenType.Null) ? null : jToken.ToString()); foreach (OperationSpecification operation in e.Operations) { switch (operation.OperationType) { case OperationType.Add: text += (string?)operation.Value; break; case OperationType.Mul: if (operation.Value.Type != JTokenType.Integer) { 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 = JValue.CreateNull(); } else { e.cachedValue = 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 = 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 = 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(AttemptingStringEnumConverter), new object[] { typeof(SnakeCaseNamingStrategy) })] public JsonMessagePartType? Type { get; set; } [JsonProperty("color")] [JsonConverter(typeof(AttemptingStringEnumConverter), 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(AttemptingStringEnumConverter), 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 = i }; } public static OperationSpecification Min(long i) { return new OperationSpecification { OperationType = OperationType.Min, Value = i }; } public static OperationSpecification Min(float i) { return new OperationSpecification { OperationType = OperationType.Min, Value = i }; } public static OperationSpecification Min(double i) { return new OperationSpecification { OperationType = OperationType.Min, Value = i }; } public static OperationSpecification Min(decimal i) { return new OperationSpecification { OperationType = OperationType.Min, Value = 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 = i }; } public static OperationSpecification Max(long i) { return new OperationSpecification { OperationType = OperationType.Max, Value = i }; } public static OperationSpecification Max(float i) { return new OperationSpecification { OperationType = OperationType.Max, Value = i }; } public static OperationSpecification Max(double i) { return new OperationSpecification { OperationType = OperationType.Max, Value = i }; } public static OperationSpecification Max(decimal i) { return new OperationSpecification { OperationType = OperationType.Max, Value = 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 = 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 = JObject.FromObject(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 = 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 = 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 = 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 = i }; } public static OperationSpecification RightShift(long i) { return new OperationSpecification { OperationType = OperationType.RightShift, Value = 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) { 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 settings = new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore, Formatting = Newtonsoft.Json.Formatting.None }; return JsonConvert.SerializeObject(minimalSerializableItemInfo, settings); } public static SerializableItemInfo FromJson(string json, IArchipelagoSession session = null) { ItemInfoStreamingContext additional = ((session != null) ? new ItemInfoStreamingContext { Items = session.Items, Locations = session.Locations, PlayerHelper = session.Players, ConnectionInfo = session.ConnectionInfo } : null); JsonSerializerSettings settings = new JsonSerializerSettings { Context = new StreamingContext(StreamingContextStates.Other, additional) }; return JsonConvert.DeserializeObject<SerializableItemInfo>(json, settings); } [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, Archipelago.MultiClient.Net.Colors.PaletteColor.Blue) { base.Text = messagePart.Text; } } public class HintStatusMessagePart : MessagePart { internal HintStatusMessagePart(JsonMessagePart messagePart) : base(MessagePartType.HintStatus, messagePart) { base.Text = messagePart.Text; if (messagePart.HintStatus.HasValue) { base.PaletteColor = ColorUtils.GetColor(messagePart.HintStatus.Value); } } } 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.PaletteColor = ColorUtils.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; } } } } public class LocationMessagePart : MessagePart { public long LocationId { get; } public int Player { get; } internal LocationMessagePart(IPlayerHelper players, IItemInfoResolver itemInfoResolver, JsonMessagePart part) : base(MessagePartType.Location, part, Archipelago.MultiClient.Net.Colors.PaletteColor.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 => GetColor(BuiltInPalettes.Dark); public PaletteColor? PaletteColor { get; protected set; } public bool IsBackgroundColor { get; internal set; } internal MessagePart(MessagePartType type, JsonMessagePart messagePart, PaletteColor? color = null) { Type = type; Text = messagePart.Text; if (color.HasValue) { PaletteColor = color.Value; } else if (messagePart.Color.HasValue) { PaletteColor = ColorUtils.GetColor(messagePart.Color.Value); IsBackgroundColor = messagePart.Color.Value >= JsonMessagePartColor.BlackBg; } else { PaletteColor = null; } } public T GetColor<T>(Palette<T> palette) { return palette[PaletteColor]; } 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.PaletteColor = (IsActivePlayer ? Archipelago.MultiClient.Net.Colors.PaletteColor.Magenta : Archipelago.MultiClient.Net.Colors.PaletteColor.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); } } 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(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, 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) { if (!(packet is RetrievedPacket retrievedPacket)) { if (packet is SetReplyPacket setReplyPacket) { if (setReplyPacket.AdditionalArguments != null && setReplyPacket.AdditionalArguments.ContainsKey("Reference") && setReplyPacket.AdditionalArguments["Reference"].Type == JTokenType.String && ((string?)setReplyPacket.AdditionalArguments["Reference"]).TryParseNGuid(out var g) && operationSpecificCallbacks.TryGetValue(g, out var value)) { value(setReplyPacket.OriginalValue, setReplyPacket.Value, setReplyPacket.AdditionalArguments); operationSpecificCallbacks.Remove(g); } 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, 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 key2 = Guid.NewGuid(); operationSpecificCallbacks[key2] = e.Callbacks; dictionary["Reference"] = key2.ToString("N"); 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? slot = null, int? team = null) { return GetClientStatusElement(slot, team).GetAsync<ArchipelagoClientState?>().ContinueWith((Task<ArchipelagoClientState?> r) => r.Result.GetValueOrDefault()); } public void TrackClientStatus(Action<ArchipelagoClientState> onStatusUpdated, bool retrieveCurrentClientStatus = true, int? slot = null, int? team = null) { GetClientStatusElement(slot, team).OnValueChanged += delegate(JToken _, JToken newValue, Dictionary<string, JToken> x) { onStatusUpdated(newValue.ToObject<ArchipelagoClientState>()); }; if (retrieveCurrentClientStatus) { GetClientStatusAsync(slot, team).ContinueWith(delegate(Task<ArchipelagoClientState> t) { onStatusUpdated(t.Result); }); } } public bool GetRaceMode() { return GetRaceModeElement().To<int?>().GetValueOrDefault() > 0; } public Task<bool> GetRaceModeAsync() { return GetRaceModeElement().GetAsync<int?>().ContinueWith((Task<int?> t) => t.Result.GetValueOrDefault() > 0); } } public interface IDataStorageWrapper { Hint[] GetHints(int? slot = null, int? team = null); Task<Hint[]> GetHintsAsync(int? slot = null, int? team = null); void TrackHints(Action<Hint[]> onHintsUpdated, bool retrieveCurrentlyUnlockedHints = true, int? slot = null, int? team = null); Dictionary<string, object> GetSlotData(int? slot = null); T GetSlotData<T>(int? slot = null) where T : class; Task<Dictionary<string, object>> GetSlotDataAsync(int? slot = null); Task<T> GetSlotDataAsync<T>(int? slot = null) where T : class; Dictionary<string, string[]> GetItemNameGroups(string game = null); Task<Dictionary<string, string[]>> GetItemNameGroupsAsync(string game = null); Dictionary<string, string[]> GetLocationNameGroups(string game = null); Task<Dictionary<string, string[]>> GetLocationNameGroupsAsync(string game = null); ArchipelagoClientState GetClientStatus(int? slot = null, int? team = null); Task<ArchipelagoClientState> GetClientStatusAsync(int? slot = null, int? team = null); void TrackClientStatus(Action<ArchipelagoClientState> onStatusUpdated, bool retrieveCurrentClientStatus = true, int? slot = null, int? team = null); bool GetRaceMode(); Task<bool> GetRaceModeAsync(); } public interface IHintsHelper { void CreateHints(int player, HintStatus hintStatus = HintStatus.Unspecified, params long[] locationIds); void CreateHints(HintStatus hintStatus = HintStatus.Unspecified, params long[] locationIds); void UpdateHintStatus(int player, long locationId, HintStatus newHintStatus); Hint[] GetHints(int? slot = null, int? team = null); Task<Hint[]> GetHintsAsync(int? slot = null, int? team = null); void TrackHints(Action<Hint[]> onHintsUpdated, bool retrieveCurrentlyUnlockedHints = true, int? slot = null, int? team = null); } public class HintsHelper : IHintsHelper { private readonly IArchipelagoSocketHelper socket; private readonly ILocationCheckHelper locationCheckHelper; private readonly IRoomStateHelper roomStateHelper; private readonly IPlayerHelper players; private readonly IDataStorageHelper dataStorageHelper; int
CrashoutCrew_APClient.dll
Decompiled 18 minutes 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.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Net.Sockets; using System.Net.WebSockets; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; using Aggro.Core; using Archipelago.MultiClient.Net; using Archipelago.MultiClient.Net.Converters; using Archipelago.MultiClient.Net.Enums; 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 BepInEx; using BepInEx.Logging; using CrashoutCrew_APClient.Patches; using CrashoutCrew_LobbyEnforcer; using CrashoutCrew_SkysTheLimit; using FMODUnity; using HarmonyLib; using Microsoft.CodeAnalysis; using Mirror; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using TMPro; using Unity.Mathematics; using UnityEngine; using UnityEngine.Events; using UnityEngine.InputSystem; using UnityEngine.InputSystem.Controls; using UnityEngine.SceneManagement; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: IgnoresAccessChecksTo("aggro.core")] [assembly: IgnoresAccessChecksTo("febjam")] [assembly: AssemblyCompany("CrashoutCrew_APClient")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+31a39948addc7464f2936539789d70ab6d2b2486")] [assembly: AssemblyProduct("CrashoutCrew_APClient")] [assembly: AssemblyTitle("CrashoutCrew_APClient")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [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] [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] [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; } } } namespace TemplatePlugin { internal static class TemplatePluginInfo { public const string PLUGIN_GUID = "crashout_crew_ap_client"; public const string PLUGIN_NAME = "CrashoutCrew_APClient"; public const string GAME_NAME = "CrashoutCrew"; } } namespace CrashoutCrew_APClient { public class APConsole : MonoBehaviour { private enum ConsoleAnchorCorner { BottomLeft, BottomRight, TopLeft, TopRight } [Serializable] public class LogEntry(string msg) { public enum State { SlideIn, Hold, FadeOut } public State state; public float stateTimer; public float offsetY; public float baseY; public float animatedY; public TextMeshProUGUI? text; public Image? background; public string message = msg; public string colorizedMessage = msg; public float height = 28f; } private static readonly Dictionary<string, string> KeywordColors = new Dictionary<string, string> { { "Bell", "#C325FA" }, { "Shop", "#FFE552" }, { "Charge Pad", "#FF8C52" }, { "Lock In Protocol", "#F21F1F" }, { "Fire Extinguisher", "#F21F1F" }, { "Super Scrubber", "#72A5ED" }, { "Scrubbie", "#72A5ED" }, { "Standard Shelf", "#6FDE62" }, { "Small Fire Sprinkler", "#00B7FF" }, { "Sturdy Shelf", "#4252FF" }, { "Teleporter", "#00FFFB" }, { "Trash Compactor", "#D3E3E3" }, { "Vacuum Cleaner", "#FFDB00" }, { "Leaf Blower", "#00FF08" }, { "Giga Sprinkler", "#00B7FF" }, { "Water Balloon Pump", "#F21F1F" }, { "Wild Card Station", "#FF00E6" }, { "Nitro Canisters", "#FC8242" }, { "Aromatherapy", "#CE6CF0" }, { "Racing Tires", "#B2ACE8" }, { "Blast Shields", "#D3E3E3" }, { "Tire Chains", "#D3E3E3" }, { "Cup Holder", "#CE6CF0" }, { "Personal Fan", "#9EF0E1" }, { "The Grippers", "#F5EB1D" }, { "Sick-ass Spoiler", "#FFCD00" }, { "Speed Upgrade", "#9355F2" }, { "Strength Upgrade", "#9355F2" }, { "Boost Upgrade", "#9355F2" }, { "Stress Upgrade", "#9355F2" }, { "Random Cosmetic", "#E0C38D" }, { "Contract", "#ffffff" }, { "Shift", "#ffffff" }, { "Delivery", "#ffffff" } }; private const string FontName = "ChelseaMarket-Regular SDF"; private readonly Color _textColor = new Color(0.85f, 0.85f, 0.85f, 1f); private readonly Color _backColor = new Color(0f, 0f, 0f, 0.8f); private const int MaxHistoryEntries = 1000; private const KeyCode LogToggleKey = (KeyCode)288; private const KeyCode HistoryToggleKey = (KeyCode)289; private const CursorLockMode DefaultCursorMode = (CursorLockMode)1; private const bool DefaultCursorVisible = false; private const float DefaultMessageHeight = 28f; private const float DefaultConsoleHeight = 250f; private const float DefaultConsoleWidth = 600f; public float slideInTime = 0.25f; public float holdTime = 2.5f; public float fadeOutTime = 0.4f; private const float SlideInOffset = -50f; private const float FadeUpOffset = 20f; private const float PaddingX = 25f; private const float PaddingY = 25f; private const float MessageSpacing = 2f; private readonly ConsoleAnchorCorner AnchorCorner; private const float ConsoleWidth = 600f; private const float ConsoleHeight = 250f; private const float MessageHeight = 28f; private bool _rebuildHistoryDirty; private int _historyBuiltCount; private static TMP_FontAsset? _font; private readonly ConcurrentQueue<Image> _backgroundPool = new ConcurrentQueue<Image>(); private ConcurrentQueue<LogEntry> _cachedEntries = new ConcurrentQueue<LogEntry>(); private readonly ConcurrentQueue<TextMeshProUGUI> _textPool = new ConcurrentQueue<TextMeshProUGUI>(); private readonly List<LogEntry> _visibleEntries = new List<LogEntry>(); private readonly List<LogEntry> _historyEntries = new List<LogEntry>(); private GameObject? _historyPanel; private RectTransform? _historyContent; private bool _showHistory; private ScrollRect? _historyScrollRect; private RectTransform? _historyViewport; private Transform? _messageParent; private bool _showConsole = true; private static APConsole? _instance; public static APConsole Instance { get { if ((Object)(object)_instance == (Object)null) { Create(); } return _instance; } } private static void Create() { //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Expected O, but got Unknown if ((Object)(object)_instance != (Object)null) { return; } _font = ((IEnumerable<TMP_FontAsset>)Resources.FindObjectsOfTypeAll<TMP_FontAsset>()).FirstOrDefault((Func<TMP_FontAsset, bool>)((TMP_FontAsset x) => ((Object)x).name == "ChelseaMarket-Regular SDF")); GameObject val = new GameObject("ArchipelagoConsoleUI"); Object.DontDestroyOnLoad((Object)val); _instance = val.AddComponent<APConsole>(); _instance.BuildUI(); _instance.slideInTime = PluginMain.MessageInTime; _instance.holdTime = PluginMain.MessageHoldTime; _instance.fadeOutTime = PluginMain.MessageOutTime; _instance.Log("Welcome to Crashout Crew Archipelago!"); _instance.Log("by xMcacutt"); _instance.Log($"Press {(object)(KeyCode)288} to Toggle log & {(object)(KeyCode)289} to toggle history"); _instance.DebugLog("Colour Test"); foreach (string key in KeywordColors.Keys) { _instance.DebugLog(key); } } private void Update() { UpdateMessages(Time.deltaTime); TryAddNewMessages(); if (((ButtonControl)Keyboard.current.f7Key).wasPressedThisFrame) { ToggleConsole(); } if (((ButtonControl)Keyboard.current.f8Key).wasPressedThisFrame) { ToggleHistory(); } if (_showHistory) { Cursor.lockState = (CursorLockMode)0; Cursor.visible = true; } if (_showHistory && _rebuildHistoryDirty) { _rebuildHistoryDirty = false; RebuildHistory(); } } private void UpdateMessages(float delta) { for (int num = _visibleEntries.Count - 1; num >= 0; num--) { LogEntry entry = _visibleEntries[num]; if (AnimateEntry(entry, delta)) { RecycleEntry(entry); _visibleEntries.RemoveAt(num); RecalculateBaseY(); } else { UpdateEntryVisual(entry); } } } private void RecalculateBaseY() { float num = 0f; for (int num2 = _visibleEntries.Count - 1; num2 >= 0; num2--) { LogEntry logEntry = _visibleEntries[num2]; logEntry.baseY = num; num += logEntry.height + 2f; } } private bool AnimateEntry(LogEntry entry, float delta) { //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_0156: Unknown result type (might be due to invalid IL or missing references) entry.stateTimer += delta; switch (entry.state) { case LogEntry.State.SlideIn: { float num3 = Mathf.Clamp01(entry.stateTimer / slideInTime); entry.offsetY = Mathf.Lerp(-50f, 0f, EaseOutQuad(num3)); if (num3 >= 1f) { entry.state = LogEntry.State.Hold; entry.stateTimer = 0f; } break; } case LogEntry.State.Hold: entry.offsetY = 0f; if (entry.stateTimer >= holdTime) { entry.state = LogEntry.State.FadeOut; entry.stateTimer = 0f; } break; case LogEntry.State.FadeOut: { float num = Mathf.Clamp01(entry.stateTimer / fadeOutTime); entry.offsetY = Mathf.Lerp(0f, 20f, num); float num2 = 1f - num; if ((Object)(object)entry.text != (Object)null) { ((Graphic)entry.text).color = new Color(_textColor.r, _textColor.g, _textColor.b, num2); } if ((Object)(object)entry.background != (Object)null) { ((Graphic)entry.background).color = new Color(_backColor.r, _backColor.g, _backColor.b, num2); } if (num >= 1f) { return true; } break; } } return false; } private static float EaseOutQuad(float x) { return 1f - (1f - x) * (1f - x); } private void TryAddNewMessages() { if (_showHistory || !_cachedEntries.Any()) { return; } int num = Mathf.FloorToInt(8.928572f); if (_visibleEntries.Count < num) { _cachedEntries.TryDequeue(out LogEntry result); if (result != null) { result.state = LogEntry.State.SlideIn; result.stateTimer = 0f; result.offsetY = -50f; result.animatedY = result.baseY + result.offsetY; CreateEntryVisual(result); _visibleEntries.Add(result); RecalculateBaseY(); result.animatedY = result.baseY + result.offsetY; } } } private void ApplyRectSettings(RectTransform rt, Vector2 min, Vector2 max, Vector2 pivot, Vector2 pos, Vector2 size) { //IL_0001: 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_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) rt.anchorMin = min; rt.anchorMax = max; rt.pivot = pivot; rt.anchoredPosition = pos; rt.sizeDelta = size; } private void PositionMessageContainer(RectTransform rect) { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) Vector2 val = default(Vector2); Vector2 min; Vector2 val2 = default(Vector2); Vector2 pos = default(Vector2); switch (AnchorCorner) { case ConsoleAnchorCorner.BottomLeft: ((Vector2)(ref val))..ctor(0f, 0f); min = (val2 = val); ((Vector2)(ref pos))..ctor(25f, 25f); break; case ConsoleAnchorCorner.BottomRight: ((Vector2)(ref val2))..ctor(1f, 0f); min = val2; ((Vector2)(ref val))..ctor(1f, 0f); ((Vector2)(ref pos))..ctor(-25f, 25f); break; case ConsoleAnchorCorner.TopLeft: ((Vector2)(ref val2))..ctor(0f, 1f); min = val2; ((Vector2)(ref val))..ctor(0f, 1f); ((Vector2)(ref pos))..ctor(25f, -25f); break; case ConsoleAnchorCorner.TopRight: ((Vector2)(ref val2))..ctor(1f, 1f); min = val2; ((Vector2)(ref val))..ctor(1f, 1f); ((Vector2)(ref pos))..ctor(-25f, -25f); break; default: ((Vector2)(ref val))..ctor(0f, 0f); min = (val2 = val); ((Vector2)(ref pos))..ctor(25f, 25f); break; } ApplyRectSettings(rect, min, val2, val, pos, new Vector2(600f, 250f)); } private void PositionHistoryPanel(RectTransform rect) { PositionMessageContainer(rect); } private void AddHistoryEntryVisual(LogEntry entry) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) Image background = GetBackground(); ((Component)background).transform.SetParent((Transform)(object)_historyContent, false); RectTransform rectTransform = ((Graphic)background).rectTransform; ApplyRectSettings(rectTransform, new Vector2(0f, 1f), new Vector2(1f, 1f), new Vector2(0.5f, 1f), Vector2.zero, new Vector2(600f, 28f)); TextMeshProUGUI text = GetText(); RectTransform rectTransform2 = ((TMP_Text)text).rectTransform; ((Transform)rectTransform2).SetParent(((Component)background).transform, false); rectTransform2.anchorMin = new Vector2(0f, 0f); rectTransform2.anchorMax = new Vector2(1f, 1f); rectTransform2.pivot = new Vector2(0f, 0.5f); rectTransform2.offsetMin = new Vector2(8f, 4f); rectTransform2.offsetMax = new Vector2(-8f, -4f); entry.text = text; entry.background = background; ((Graphic)text).color = _textColor; ((Graphic)background).color = _backColor; ((TMP_Text)text).text = entry.msg; Canvas.ForceUpdateCanvases(); LayoutRebuilder.ForceRebuildLayoutImmediate(rectTransform2); float preferredHeight = Mathf.Max(28f, ((TMP_Text)text).preferredHeight + 8f); (((Component)background).GetComponent<LayoutElement>() ?? ((Component)background).gameObject.AddComponent<LayoutElement>()).preferredHeight = preferredHeight; } private void CreateEntryVisual(LogEntry entry) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) Image background = GetBackground(); ((Component)background).transform.SetParent(_messageParent, false); RectTransform rectTransform = ((Graphic)background).rectTransform; ApplyRectSettings(rectTransform, Vector2.zero, Vector2.zero, Vector2.zero, Vector2.zero, new Vector2(600f, 28f)); TextMeshProUGUI text = GetText(); RectTransform rectTransform2 = ((TMP_Text)text).rectTransform; ((Transform)rectTransform2).SetParent(((Component)background).transform, false); rectTransform2.anchorMin = new Vector2(0f, 0f); rectTransform2.anchorMax = new Vector2(1f, 1f); rectTransform2.pivot = new Vector2(0f, 0.5f); rectTransform2.offsetMin = new Vector2(8f, 4f); rectTransform2.offsetMax = new Vector2(-8f, -4f); entry.text = text; entry.background = background; ((Graphic)text).color = _textColor; ((Graphic)background).color = _backColor; UpdateEntryVisual(entry); } private void UpdateEntryVisual(LogEntry entry) { //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)entry.text != (Object)null) { ((TMP_Text)entry.text).text = entry.msg; float preferredHeight = ((TMP_Text)entry.text).preferredHeight; entry.height = Mathf.Max(28f, preferredHeight + 8f); if ((Object)(object)entry.background != (Object)null) { ((Graphic)entry.background).rectTransform.sizeDelta = new Vector2(600f, entry.height); } } float num = entry.baseY + entry.offsetY; entry.animatedY = Mathf.Lerp(entry.animatedY, num, Time.deltaTime * 12f); if ((Object)(object)entry.background != (Object)null) { ((Graphic)entry.background).rectTransform.anchoredPosition = new Vector2(0f, entry.animatedY); } } private TextMeshProUGUI GetText() { //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) if (_textPool.TryDequeue(out TextMeshProUGUI result) && (Object)(object)result != (Object)null) { ((Component)result).gameObject.SetActive(true); return result; } TextMeshProUGUI component = new GameObject("LogText", new Type[3] { typeof(RectTransform), typeof(CanvasRenderer), typeof(TextMeshProUGUI) }).GetComponent<TextMeshProUGUI>(); ((TMP_Text)component).fontSize = 15f; ((Graphic)component).color = _textColor; ((TMP_Text)component).font = _font; ((TMP_Text)component).wordSpacing = 20f; ((TMP_Text)component).alignment = (TextAlignmentOptions)4097; return component; } private Image GetBackground() { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) if (_backgroundPool.TryDequeue(out Image result) && (Object)(object)result != (Object)null) { ((Component)result).gameObject.SetActive(true); return result; } Image obj = new GameObject("LogBG").AddComponent<Image>(); ((Graphic)obj).color = _backColor; obj.type = (Type)1; return obj; } private void RecycleEntry(LogEntry entry) { if ((Object)(object)entry.text != (Object)null) { ((Component)entry.text).gameObject.SetActive(false); _textPool.Enqueue(entry.text); entry.text = null; } if ((Object)(object)entry.background != (Object)null) { ((Component)entry.background).gameObject.SetActive(false); _backgroundPool.Enqueue(entry.background); entry.background = null; } } private string Colorize(string input) { if (string.IsNullOrEmpty(input)) { return input; } List<string> list = Tokenize(input); ApplyMultiWordColoring(list); ApplySingleWordColoring(list); return string.Concat(list); } private List<string> Tokenize(string input) { if (!string.IsNullOrEmpty(input)) { return Regex.Split(input, "(\\s+)").ToList(); } return new List<string>(); } private void ApplySingleWordColoring(List<string> tokens) { Dictionary<string, string> dictionary = KeywordColors.Where<KeyValuePair<string, string>>((KeyValuePair<string, string> kvp) => !kvp.Key.Contains(" ")).ToDictionary((KeyValuePair<string, string> k) => k.Key.ToLowerInvariant(), (KeyValuePair<string, string> v) => v.Value); for (int num = 0; num < tokens.Count; num++) { string text = tokens[num]; if (IsWord(text)) { string key = Regex.Replace(text.ToLowerInvariant(), "[^a-z0-9]", ""); if (dictionary.TryGetValue(key, out var value)) { tokens[num] = "<color=" + value + ">" + text + "</color>"; } } } } private void ApplyMultiWordColoring(List<string> tokens) { List<KeyValuePair<string, string>> list = (from k in KeywordColors where k.Key.Contains(" ") orderby k.Key.Length descending select k).ToList(); if (list.Count == 0) { return; } for (int num = 0; num < tokens.Count; num++) { if (!IsWord(tokens[num])) { continue; } string text = string.Concat(tokens.Skip(num)).ToLowerInvariant(); foreach (KeyValuePair<string, string> item in list) { if (!text.StartsWith(item.Key.ToLowerInvariant())) { continue; } int num2 = 0; string text2 = ""; for (int num3 = num; num3 < tokens.Count; num3++) { if (text2.Length >= item.Key.Length) { break; } text2 += tokens[num3]; num2++; } tokens[num] = "<color=" + item.Value + ">" + text2 + "</color>"; for (int num4 = 1; num4 < num2; num4++) { tokens[num + num4] = ""; } num += num2 - 1; break; } } } private bool IsWord(string token) { return !string.IsNullOrWhiteSpace(token); } public void Log(string text) { ManualLogSource? logger = PluginMain.logger; if (logger != null) { logger.LogInfo((object)text); } string colorizedMessage = Colorize(text); LogEntry item = new LogEntry(text) { msg = colorizedMessage }; _historyEntries.Add(item); if (_historyEntries.Count > 1000) { _historyEntries.RemoveAt(0); _historyBuiltCount = Mathf.Max(0, _historyBuiltCount - 1); } if (_showHistory) { _rebuildHistoryDirty = true; } else { _cachedEntries.Enqueue(item); } } public void DebugLog(string text) { if (PluginMain.EnableDebugLogging) { Log(text); } } private void ToggleHistory() { _showHistory = !_showHistory; if ((Object)(object)_messageParent == (Object)null || (Object)(object)_historyPanel == (Object)null) { return; } ((Component)_messageParent).gameObject.SetActive(!_showHistory); _historyPanel.SetActive(_showHistory); if (_showHistory) { foreach (LogEntry visibleEntry in _visibleEntries) { if ((Object)(object)visibleEntry.text != (Object)null) { ((Component)visibleEntry.text).gameObject.SetActive(false); _textPool.Enqueue(visibleEntry.text); } if ((Object)(object)visibleEntry.background != (Object)null) { ((Component)visibleEntry.background).gameObject.SetActive(false); _backgroundPool.Enqueue(visibleEntry.background); } } _visibleEntries.Clear(); _cachedEntries = new ConcurrentQueue<LogEntry>(); RebuildHistory(); } else { Cursor.lockState = (CursorLockMode)1; Cursor.visible = false; ((Component)_messageParent).gameObject.SetActive(_showConsole); } } private void ToggleConsole() { _showConsole = !_showConsole; if ((Object)(object)_messageParent == (Object)null || (Object)(object)_historyPanel == (Object)null) { return; } foreach (LogEntry visibleEntry in _visibleEntries) { if ((Object)(object)visibleEntry.background != (Object)null) { ((Component)visibleEntry.background).gameObject.SetActive(_showConsole); } if ((Object)(object)visibleEntry.text != (Object)null) { ((Component)visibleEntry.text).gameObject.SetActive(_showConsole); } } ((Component)_messageParent).gameObject.SetActive(_showConsole); if (!_showConsole) { _showHistory = false; _historyPanel.SetActive(false); } } private void BuildUI() { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Expected O, but got Unknown //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Expected O, but got Unknown //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Expected O, but got Unknown //IL_018c: Unknown result type (might be due to invalid IL or missing references) //IL_0193: Expected O, but got Unknown //IL_01be: Unknown result type (might be due to invalid IL or missing references) //IL_01ce: Unknown result type (might be due to invalid IL or missing references) //IL_01e4: Unknown result type (might be due to invalid IL or missing references) //IL_01e9: Unknown result type (might be due to invalid IL or missing references) //IL_01ea: Unknown result type (might be due to invalid IL or missing references) //IL_01f1: Unknown result type (might be due to invalid IL or missing references) //IL_0201: Unknown result type (might be due to invalid IL or missing references) //IL_0268: Unknown result type (might be due to invalid IL or missing references) //IL_026d: Unknown result type (might be due to invalid IL or missing references) //IL_0290: Unknown result type (might be due to invalid IL or missing references) //IL_02a6: Unknown result type (might be due to invalid IL or missing references) //IL_02bc: Unknown result type (might be due to invalid IL or missing references) //IL_02c8: Unknown result type (might be due to invalid IL or missing references) //IL_02de: Unknown result type (might be due to invalid IL or missing references) //IL_02e8: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("APConsoleCanvas", new Type[3] { typeof(Canvas), typeof(CanvasScaler), typeof(GraphicRaycaster) }); val.transform.SetParent(((Component)this).transform); Canvas component = val.GetComponent<Canvas>(); component.renderMode = (RenderMode)0; component.sortingOrder = 2000; CanvasScaler component2 = val.GetComponent<CanvasScaler>(); component2.uiScaleMode = (ScaleMode)1; component2.referenceResolution = new Vector2(1920f, 1080f); GameObject val2 = new GameObject("Messages", new Type[1] { typeof(RectTransform) }); RectTransform component3 = val2.GetComponent<RectTransform>(); ((Transform)component3).SetParent(val.transform, false); _messageParent = val2.transform; PositionMessageContainer(component3); _historyPanel = new GameObject("HistoryPanel", new Type[1] { typeof(RectTransform) }); RectTransform component4 = _historyPanel.GetComponent<RectTransform>(); ((Transform)component4).SetParent(val.transform, false); PositionHistoryPanel(component4); _historyPanel.SetActive(false); _historyScrollRect = _historyPanel.AddComponent<ScrollRect>(); _historyScrollRect.horizontal = false; _historyScrollRect.vertical = true; _historyScrollRect.scrollSensitivity = 5f; _historyScrollRect.movementType = (MovementType)2; GameObject val3 = new GameObject("Viewport", new Type[3] { typeof(RectTransform), typeof(Image), typeof(Mask) }); _historyViewport = val3.GetComponent<RectTransform>(); val3.transform.SetParent(_historyPanel.transform, false); _historyViewport.anchorMin = Vector2.zero; _historyViewport.anchorMax = Vector2.one; RectTransform? historyViewport = _historyViewport; Vector2 offsetMin = (_historyViewport.offsetMax = Vector2.zero); historyViewport.offsetMin = offsetMin; Image component5 = val3.GetComponent<Image>(); ((Graphic)component5).color = _backColor; component5.type = (Type)0; ((Graphic)component5).raycastTarget = true; val3.GetComponent<Mask>().showMaskGraphic = false; _historyScrollRect.viewport = _historyViewport; GameObject val4 = new GameObject("Content", new Type[3] { typeof(RectTransform), typeof(VerticalLayoutGroup), typeof(ContentSizeFitter) }); RectTransform component6 = val4.GetComponent<RectTransform>(); ((Transform)component6).SetParent(val3.transform, false); component6.anchorMin = new Vector2(0f, 1f); component6.anchorMax = new Vector2(1f, 1f); component6.pivot = new Vector2(0.5f, 1f); component6.anchoredPosition = Vector2.zero; component6.sizeDelta = new Vector2(0f, 0f); VerticalLayoutGroup component7 = val4.GetComponent<VerticalLayoutGroup>(); ((HorizontalOrVerticalLayoutGroup)component7).childForceExpandHeight = false; ((HorizontalOrVerticalLayoutGroup)component7).childForceExpandWidth = true; ((HorizontalOrVerticalLayoutGroup)component7).childControlHeight = true; ((HorizontalOrVerticalLayoutGroup)component7).childControlWidth = true; ((HorizontalOrVerticalLayoutGroup)component7).spacing = 2f; ((LayoutGroup)component7).childAlignment = (TextAnchor)0; ContentSizeFitter component8 = val4.GetComponent<ContentSizeFitter>(); component8.verticalFit = (FitMode)2; component8.horizontalFit = (FitMode)0; _historyScrollRect.content = component6; _historyContent = component6; } private void RebuildHistory() { if (!((Object)(object)_historyContent == (Object)null)) { for (int i = _historyBuiltCount; i < _historyEntries.Count; i++) { AddHistoryEntryVisual(_historyEntries[i]); } _historyBuiltCount = _historyEntries.Count; Canvas.ForceUpdateCanvases(); LayoutRebuilder.ForceRebuildLayoutImmediate(_historyContent); Canvas.ForceUpdateCanvases(); if ((Object)(object)_historyScrollRect != (Object)null) { _historyScrollRect.verticalNormalizedPosition = 0f; } } } } public class ArchipelagoHandler : MonoBehaviour { public static ArchipelagoHandler Instance; private ArchipelagoSession? _session; public SlotData? slotData; public static Action? OnDisconnect; private ConcurrentQueue<long> _locationsToCheck = new ConcurrentQueue<long>(); public volatile bool connectionFinished = true; public volatile bool connectionSucceeded; private readonly bool _queueBreak; private bool _shouldDisconnect; private string? _lastDeath; private DateTime _lastDeathTime = DateTime.Now; public string? Server { get; set; } public string? Slot { get; set; } public string? Password { get; set; } public string? Seed { get; set; } public bool IsConnected { get { ArchipelagoSession? session = _session; if (session == null) { return false; } return session.Socket.Connected; } } public event Action<string, string>? OnConnected; public event Action<string>? OnConnectionFailed; private void Awake() { if ((Object)(object)Instance != (Object)null && (Object)(object)Instance != (Object)(object)this) { Object.Destroy((Object)(object)((Component)this).gameObject); } else { Instance = this; } } private void Update() { if (_shouldDisconnect) { _shouldDisconnect = false; Disconnect(); } } public bool CreateSession(string server, string slot, string password) { //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Expected O, but got Unknown //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Expected O, but got Unknown //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Expected O, but got Unknown //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Expected O, but got Unknown //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Expected O, but got Unknown Server = server; Slot = slot; Password = password; _locationsToCheck = new ConcurrentQueue<long>(); _shouldDisconnect = false; connectionSucceeded = false; connectionFinished = false; try { _session = ArchipelagoSessionFactory.CreateSession(Server, 38281); } catch (Exception) { return false; } _session.MessageLog.OnMessageReceived += new MessageReceivedHandler(OnMessageReceived); _session.Socket.ErrorReceived += new ErrorReceivedHandler(OnError); _session.Socket.SocketClosed += new SocketClosedHandler(OnSocketClosed); _session.Items.ItemReceived += new ItemReceivedHandler(ItemReceived); _session.Socket.PacketReceived += new PacketReceivedHandler(OnPacketReceived); return true; } private IEnumerator ConnectRoutine() { APConsole.Instance.Log("Logging in to " + Server + " as " + Slot + "..."); Task<RoomInfoPacket> connectTask = _session.ConnectAsync(); yield return (object)new WaitUntil((Func<bool>)(() => connectTask.IsCompleted)); if (connectTask.IsFaulted || connectTask.IsCanceled) { string text = connectTask.Exception?.InnerException?.Message ?? "Took too long..."; Debug.Log((object)("Connection Error: " + text)); connectionSucceeded = false; connectionFinished = true; this.OnConnectionFailed?.Invoke(text); yield break; } Seed = connectTask.Result.SeedName; Task<LoginResult> loginTask = _session.LoginAsync("Crashout Crew", Slot, (ItemsHandlingFlags)7, new Version(0, 6, 7), Array.Empty<string>(), (string)null, Password, true); yield return (object)new WaitUntil((Func<bool>)(() => loginTask.IsCompleted)); if (loginTask.IsFaulted || loginTask.IsCanceled) { string text2 = loginTask.Exception?.InnerException?.Message ?? "Took too long..."; APConsole.Instance.Log("Login Error: " + text2); connectionSucceeded = false; connectionFinished = true; yield break; } if (loginTask.Result.Successful) { APConsole.Instance.Log("Successfully connected to " + Server + "!"); LoginSuccessful val = (LoginSuccessful)loginTask.Result; slotData = new SlotData(val.SlotData); ((MonoBehaviour)Instance).StartCoroutine(RunCheckQueue()); connectionSucceeded = true; connectionFinished = true; this.OnConnected?.Invoke(Seed, Slot); yield break; } connectionSucceeded = false; connectionFinished = true; if (loginTask.Result != null) { LoginFailure val2 = (LoginFailure)loginTask.Result; string seed = "Failed to connect to " + Server + " with " + Slot + "."; seed = val2.Errors.Aggregate(seed, (string current, string error) => current + "\n " + error); seed = val2.ErrorCodes.Aggregate(seed, (string current, ConnectionRefusedError error) => current + $"\n {error}"); this.OnConnectionFailed?.Invoke(seed); APConsole.Instance.Log(seed); } APConsole.Instance.Log("Attempting to reconnect..."); } private void OnDestroy() { Disconnect(); } public void Connect() { ((MonoBehaviour)this).StartCoroutine(ConnectRoutine()); } public void Disconnect() { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Expected O, but got Unknown //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Expected O, but got Unknown //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Expected O, but got Unknown //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Expected O, but got Unknown //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Expected O, but got Unknown if (_session != null) { _session.MessageLog.OnMessageReceived -= new MessageReceivedHandler(OnMessageReceived); _session.Socket.ErrorReceived -= new ErrorReceivedHandler(OnError); _session.Socket.SocketClosed -= new SocketClosedHandler(OnSocketClosed); _session.Items.ItemReceived -= new ItemReceivedHandler(ItemReceived); _session.Socket.PacketReceived -= new PacketReceivedHandler(OnPacketReceived); ItemHandler.Instance.Reset(); PluginMain.SaveDataHandler?.Reset(); try { _session.Socket.DisconnectAsync(); } catch (Exception ex) { Debug.LogWarning((object)("Error during async disconnect: " + ex.Message)); } _session = null; ((MonoBehaviour)this).StopAllCoroutines(); OnDisconnect?.Invoke(); APConsole.Instance.Log("Disconnected from Archipelago!"); } } private void OnError(Exception exception, string message) { Debug.LogWarning((object)exception); APConsole.Instance.Log("Socket Error: " + message + " - " + exception.Message); if ((exception is SocketException || exception is WebSocketException) ? true : false) { _shouldDisconnect = true; } } private void OnSocketClosed(string reason) { _shouldDisconnect = true; } private void ItemReceived(ReceivedItemsHelper helper) { try { while (helper.Any()) { int index = helper.Index; ItemInfo item = helper.DequeueItem(); ItemHandler.Instance.EnqueueItem(index, item); } } catch (Exception arg) { APConsole.Instance.Log($"[Item Received ERROR] {arg}"); throw; } } public void Release() { ArchipelagoSession? session = _session; if (session != null) { session.SetGoalAchieved(); } ArchipelagoSession? session2 = _session; if (session2 != null) { session2.SetClientState((ArchipelagoClientState)30); } } public void CheckLocation(long id) { if (!IsLocationChecked(id)) { _locationsToCheck.Enqueue(id); } } public void CheckLocations(long[] ids) { ids.ToList().ForEach(delegate(long id) { _locationsToCheck.Enqueue(id); }); } private IEnumerator RunCheckQueue() { while (true) { if (_locationsToCheck.TryDequeue(out var result)) { ArchipelagoSession? session = _session; if (session != null) { session.Locations.CompleteLocationChecks(new long[1] { result }); } } if (_queueBreak) { break; } yield return (object)new WaitForSeconds(0.1f); } } private bool IsLocationChecked(long id) { ArchipelagoSession? session = _session; if (session == null) { return false; } return session.Locations.AllLocationsChecked.Contains(id); } public int CountLocationsCheckedInRange(long start, long end) { ArchipelagoSession? session = _session; if (session == null) { return 0; } return session.Locations.AllLocationsChecked.Count((long loc) => loc >= start && loc < end); } public void UpdateTags(List<string> tags) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Expected O, but got Unknown ConnectUpdatePacket val = new ConnectUpdatePacket { Tags = tags.ToArray(), ItemsHandling = (ItemsHandlingFlags)7 }; ArchipelagoSession? session = _session; if (session != null) { session.Socket.SendPacket((ArchipelagoPacketBase)(object)val); } } private void OnMessageReceived(LogMessage message) { if (PluginMain.FilterLog) { PlayerSpecificLogMessage val = (PlayerSpecificLogMessage)(object)((message is PlayerSpecificLogMessage) ? message : null); if (val != null && !val.IsRelatedToActivePlayer) { return; } } string text; if (message.Parts.Length == 1) { text = message.Parts[0].Text; } else { StringBuilder stringBuilder = new StringBuilder(); MessagePart[] parts = message.Parts; foreach (MessagePart val2 in parts) { stringBuilder.Append(val2.Text ?? ""); } text = stringBuilder.ToString(); } APConsole.Instance.Log(text); } private void OnPacketReceived(ArchipelagoPacketBase packet) { BouncePacket val = (BouncePacket)(object)((packet is BouncePacket) ? packet : null); if (val != null) { BouncePacketReceived(val); } } public ScoutedItemInfo? TryScoutLocation(long locationId, bool createHint = false) { ArchipelagoSession? session = _session; if (session == null) { return null; } return session.Locations.ScoutLocationsAsync(createHint, new long[1] { locationId })?.Result?.Values.First(); } public void SendDeath() { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Expected O, but got Unknown APConsole.Instance.Log("SendDeath called!"); SlotData? obj = slotData; if (obj == null || obj.DeathLink) { return; } BouncePacket val = new BouncePacket(); DateTime now = DateTime.Now; if (!(now - _lastDeathTime < TimeSpan.FromSeconds(2.0))) { val.Tags = new List<string>(1) { "DeathLink" }; val.Data = new Dictionary<string, JToken> { { "time", JToken.op_Implicit(UnixTimeConverter.ToUnixTimeStamp(now)) }, { "source", JToken.op_Implicit(Slot) }, { "cause", JToken.op_Implicit("Death") } }; _lastDeathTime = now; ArchipelagoSession? session = _session; if (session != null) { session.Socket.SendPacket((ArchipelagoPacketBase)(object)val); } } } private void BouncePacketReceived(BouncePacket packet) { if (_lastDeath == null) { _lastDeathTime = DateTime.Now; } SlotData? obj = slotData; if (obj != null && obj.DeathLink) { ProcessBouncePacket(packet, "DeathLink", ref _lastDeath, delegate(string source, Dictionary<string, JToken> data) { HandleDeathLink(source, ((object)data["cause"])?.ToString() ?? "Unknown"); }); } } private static void ProcessBouncePacket(BouncePacket packet, string tag, ref string lastTime, Action<string, Dictionary<string, JToken>> handler) { if (packet.Tags.Contains(tag) && packet.Data.TryGetValue("time", out var value) && !(lastTime != ((object)value).ToString())) { lastTime = ((object)value).ToString(); if (packet.Data.TryGetValue("source", out var value2)) { string arg = ((object)value2)?.ToString() ?? "Unknown"; handler(arg, packet.Data); } } } private void HandleDeathLink(string source, string cause) { SlotData? obj = slotData; if (obj != null && obj.DeathLink && !(source == Slot)) { Kill(); } } public void Kill() { APConsole.Instance.Log("Player Killed!!!"); } public void Reset() { connectionFinished = true; connectionSucceeded = false; } } public static class ContractGenerator { private static readonly List<(string, string)> Warehouses = new List<(string, string)>(10) { ("Assets/Scenes/scene-Dumbbell_1-2.unity", "Assets/Scenes/scene-Dumbbell.unity"), ("Assets/Scenes/scene-IPiece_1-2.unity", "Assets/Scenes/scene-IPiece.unity"), ("Assets/Scenes/scene-SBendMini_1-2.unity", "Assets/Scenes/scene-SBendMini.unity"), ("Assets/Scenes/scene-ConveyorBlock.unity", "Assets/Scenes/scene-ConveyorBlock.unity"), ("Assets/Scenes/scene-ConveyorHallway.unity", "Assets/Scenes/scene-ConveyorHallway.unity"), ("Assets/Scenes/scene-ConveyorLoop.unity", "Assets/Scenes/scene-ConveyorLoop.unity"), ("Assets/Scenes/scene-Figure8RaceTrackMini.unity", "Assets/Scenes/scene-Figure8RaceTrackMini.unity"), ("Assets/Scenes/scene-LBendRaceTrackMini.unity", "Assets/Scenes/scene-LBendRaceTrackMini.unity"), ("Assets/Scenes/scene-RaceTrackMini.unity", "Assets/Scenes/scene-RaceTrackMini.unity"), ("Assets/Scenes/scene-UBendMiniRacetrack.unity", "Assets/Scenes/scene-UBendMiniRacetrack.unity") }; private static readonly int[] OutboundDeliveryCount = new int[5] { 4, 5, 6, 7, 8 }; public static ContractObject[] GenerateContracts(Random random, ShiftOrderObject[] allOrders, int twoOrderContracts, int threeOrderContracts, int fourOrderContracts) { List<int> list = new List<int>(); list.AddRange(Enumerable.Repeat(2, twoOrderContracts)); list.AddRange(Enumerable.Repeat(3, threeOrderContracts)); list.AddRange(Enumerable.Repeat(4, fourOrderContracts)); List<int> list2 = list.OrderBy((int _) => random.Next()).ToList(); List<ContractObject> list3 = new List<ContractObject>(); List<ShiftOrderObject> list4 = new List<ShiftOrderObject>(); foreach (int item2 in list2) { List<ShiftOrderObject> selectedOrders = new List<ShiftOrderObject>(); while (selectedOrders.Count < item2) { if (list4.Count == 0) { list4.AddRange(allOrders.OrderBy((ShiftOrderObject _) => random.Next())); } ShiftOrderObject item = ((IEnumerable<ShiftOrderObject>)list4).FirstOrDefault((Func<ShiftOrderObject, bool>)((ShiftOrderObject o) => !selectedOrders.Contains(o))); list4.Remove(item); selectedOrders.Add(item); } list3.Add(GenerateContract(random, selectedOrders.ToArray())); } list3 = list3.OrderBy((ContractObject x) => x.orders.Length).ToList(); for (int num = 0; num < list3.Count; num++) { list3[num].bellsRequired = 5 * num; } return list3.ToArray(); } private static ContractObject GenerateContract(Random random, ShiftOrderObject[] orders) { //IL_003a: Unknown result type (might be due to invalid IL or missing references) ContractObject val = ScriptableObject.CreateInstance<ContractObject>(); val.title = orders.GenerateName(random); ((Object)val).name = val.title.Replace(' ', '_').ToUpper(); val.modifierMultiplier = 1f; val.type = (ContractType)0; val.orders = orders; (string, string) tuple = Warehouses.Random(0, -1, random); val.smallWarehouse = tuple.Item1; val.bigWarehouse = tuple.Item2; val.multiplierForOnePlayer = 0.4f; val.multiplierForTwoPlayers = 0.7f; val.multiplierForThreePlayers = 0.85f; val.shift1 = GenerateShift(random, val, orders, 0); val.shift2 = GenerateShift(random, val, orders, 1); val.shift3 = GenerateShift(random, val, orders, 2); val.shift4 = GenerateShift(random, val, orders, 3); val.shift5 = GenerateShift(random, val, orders, 4); val.shopCards = Array.Empty<DeckCard<ShopItemObject>>(); val.unlocks = Array.Empty<Unlock>(); val.demoVisualPrefabs = Array.Empty<GameObject>(); return val; } private static ContractShift GenerateShift(Random random, ContractObject contract, ShiftOrderObject[] orders, int shiftIndex) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Expected O, but got Unknown //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Expected O, but got Unknown //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Expected O, but got Unknown //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Expected O, but got Unknown ContractShift val = new ContractShift(); List<Outbound> list = new List<Outbound>(); List<Inbound> list2 = new List<Inbound>(); List<Order> list3 = new List<Order>(); val.owner = contract; val.truckPatienceDuration = random.Next(90, 110); int num = OutboundDeliveryCount[shiftIndex]; for (int i = 0; i < num; i++) { int num2 = random.Next(4, 7); list.Add(new Outbound { bayCount = 1, boxCount = num2, secondsFromPrevious = random.Next(8, 14) }); int num3 = random.Next(1, 3); int boxCount = Mathf.CeilToInt((float)(num2 + random.Next(0, 3)) / (float)num3); list2.Add(new Inbound { bayCount = num3, boxCount = boxCount, normalizedTime = (float)i * (0.75f / (float)num) }); } val.outbound = list.ToArray(); val.inbound = list2.ToArray(); val.payOutAmount = num * random.Next(75, 115); foreach (ShiftOrderObject order in orders) { int minValue = ((shiftIndex >= 4) ? 1 : 0); list3.Add(new Order { owner = contract, order = order, randomOrderIndex = 1, cardCount = random.Next(minValue, 3) }); } if (list3.All((Order x) => x.cardCount == 0)) { list3.Random(0, -1, random).cardCount = 1; } val.orders = list3.ToArray(); return val; } } public static class ContractNameGenerator { private static readonly Dictionary<string, string[]> OrderToAdjectives = new Dictionary<string, string[]> { { "order-anvil", new string[2] { "Heavy", "Hard" } }, { "order-barreloil", new string[2] { "Gloopy", "Sticky" } }, { "order-barrelooze", new string[1] { "Corrosive" } }, { "order-battery", new string[2] { "Speedy", "Powerful" } }, { "order-beehive", new string[2] { "Buzzy", "Stingy" } }, { "order-bingbong", new string[2] { "Bingy", "Bongy" } }, { "order-blueberry", new string[4] { "Blueish", "Tasty", "Fruity", "Squishy" } }, { "order-bomb", new string[2] { "Dangerous", "Bangy" } }, { "order-bull", new string[2] { "Bullish", "Horny" } }, { "order-cherry", new string[4] { "Red", "Tasty", "Fruity", "Squishy" } }, { "order-chicken", new string[2] { "Feathery", "BKAWK" } }, { "order-clownCar", new string[2] { "Fast", "Furious" } }, { "order-cubeToy", new string[2] { "Colorful", "Cubic" } }, { "order-egg", new string[2] { "Eggy", "Cracked" } }, { "order-fireworks", new string[2] { "Pretty", "Sparkly" } }, { "order-ghostBox", new string[4] { "Haunted", "Spooky", "Ghostly", "Scary" } }, { "order-grape", new string[5] { "Purple", "Grapey", "Squishy", "Fruity", "Tasty" } }, { "order-honeyPot", new string[2] { "Sweet", "Sticky" } }, { "order-kiwi", new string[5] { "Green", "Fuzzy", "Squishy", "Fruity", "Tasty" } }, { "order-lantern", new string[3] { "Bright", "Hot", "Fiery" } }, { "order-monkey", new string[2] { "Cheeky", "Sneaky" } }, { "order-snail", new string[3] { "Slimy", "Slow", "Shelly" } }, { "order-vase", new string[2] { "Fragile", "Expensive" } } }; private static readonly Dictionary<string, string[]> OrderToVerb = new Dictionary<string, string[]> { { "order-anvil", new string[2] { "Falling", "Crushing" } }, { "order-barreloil", new string[2] { "Spilling", "Oozing" } }, { "order-barrelooze", new string[2] { "Burning", "Oozing" } }, { "order-battery", new string[2] { "Energizing", "Powering" } }, { "order-beehive", new string[1] { "Buzzing" } }, { "order-bingbong", new string[2] { "Crying", "Squeaking" } }, { "order-blueberry", Array.Empty<string>() }, { "order-bomb", new string[2] { "Exploding", "Detonating" } }, { "order-bull", new string[3] { "Charging", "Bucking", "Bullying" } }, { "order-cherry", Array.Empty<string>() }, { "order-chicken", new string[2] { "Clucking", "Laying" } }, { "order-clownCar", new string[2] { "Honking", "Driving" } }, { "order-cubeToy", new string[2] { "Solving", "Scrambling" } }, { "order-egg", new string[2] { "Cracking", "Frying" } }, { "order-fireworks", new string[3] { "Exploding", "Flying", "Whistling" } }, { "order-ghostBox", new string[2] { "Spooking", "Scaring" } }, { "order-grape", Array.Empty<string>() }, { "order-honeyPot", new string[1] { "Sticking" } }, { "order-kiwi", Array.Empty<string>() }, { "order-lantern", new string[3] { "Lighting", "Flaming", "Glowing" } }, { "order-monkey", new string[2] { "Swinging", "Throwing" } }, { "order-snail", new string[1] { "Crawling" } }, { "order-vase", new string[2] { "Smashing", "Breaking" } } }; private static readonly Dictionary<string, string[]> OrderToNoun = new Dictionary<string, string[]> { { "order-anvil", new string[3] { "Anvils", "Weights", "Metal" } }, { "order-barreloil", new string[3] { "Oil", "Barrels", "Mess" } }, { "order-barrelooze", new string[3] { "Acid", "Barrels", "Waste" } }, { "order-battery", new string[3] { "Batteries", "Energy", "Power" } }, { "order-beehive", new string[3] { "Bees", "Hives", "Buzzers" } }, { "order-bingbong", new string[2] { "BingBong", "Husband" } }, { "order-blueberry", new string[2] { "Blueberries", "Fruit" } }, { "order-bomb", new string[3] { "Bombs", "Explosives", "Destruction" } }, { "order-bull", new string[3] { "Bulls", "Animals", "Horns" } }, { "order-cherry", new string[2] { "Cherries", "Fruit" } }, { "order-chicken", new string[3] { "Chickens", "Cluckers", "Feathers" } }, { "order-clownCar", new string[3] { "Cars", "Drivers", "Wheels" } }, { "order-cubeToy", new string[3] { "Cubes", "Puzzles", "Solvers" } }, { "order-egg", new string[2] { "Eggs", "Shells" } }, { "order-fireworks", new string[3] { "Fireworks", "Explosives", "Lights" } }, { "order-ghostBox", new string[3] { "Ghosts", "Ghouls", "Haunt" } }, { "order-grape", new string[2] { "Grapes", "Fruit" } }, { "order-honeyPot", new string[2] { "Honey", "Pots" } }, { "order-kiwi", new string[2] { "Kiwis", "Fruit" } }, { "order-lantern", new string[3] { "Lanterns", "Fire", "Lights" } }, { "order-monkey", new string[3] { "Monkeys", "Bananas", "Peels" } }, { "order-snail", new string[2] { "Snails", "Shells" } }, { "order-vase", new string[2] { "Vases", "Pots" } } }; public static string GenerateName(this ShiftOrderObject[] orders, Random random) { List<string> list = new List<string>(); for (int i = 0; i < orders.Length; i++) { if (i == orders.Length - 1) { list.Add(OrderToNoun[((Object)orders[i]).name].Random(0, -1, random)); break; } if (i == orders.Length - 2 && OrderToVerb[((Object)orders[i]).name].Length != 0) { list.Add(OrderToVerb[((Object)orders[i]).name].Random(0, -1, random)); } else { list.Add(OrderToAdjectives[((Object)orders[i]).name].Random(0, -1, random)); } } return string.Join(" ", list); } } public static class CostumeHandler { private static readonly Random Random = new Random(); public static void SelectRandom() { Entity val = default(Entity); if (GameUtil.TryGetLocalPlayer(ref val)) { PlayerCostumeManager val2 = ((Entity)(ref val)).GetObject<PlayerCostumeManager>(); PlayerCostumeManagerNetwork val3 = ((Entity)(ref val)).GetObject<PlayerCostumeManagerNetwork>(); val2.SetUpUnlockedIndicies(); int currentUnlockedCostumeIndex = Random.Next(val2.unlockedCostumeIndicies.Length); val2.currentUnlockedCostumeIndex = currentUnlockedCostumeIndex; val3.SetCostumeIndex(val2.unlockedCostumeIndicies[val2.currentUnlockedCostumeIndex]); val2.ResetAllCostumes(); SaveManager.data.SetCurrentCostume(val2.costumes[val3.currentCostumeID].costumeObject); } } } public enum CCItem { Bell = 1, Boost = 2, Charge = 3, Button = 4, Extinguisher = 5, Scrub = 6, Scrubbie = 7, Shelf = 8, Sprinkler = 9, Sturdy = 10, Tele = 11, Trash = 12, Vac = 13, Leaf = 14, XlSprinkler = 15, WaterBalloon = 16, Wild = 17, Nitro = 18, Aroma = 19, Drift = 20, Shield = 21, Chain = 22, Cup = 23, Fan = 24, Grip = 25, Spoiler = 26, Cosmetic = 32, SpeedUpgrade = 48, StrengthUpgrade = 49, BoostUpgrade = 50, StressUpgrade = 51 } public class ItemHandler : MonoBehaviour { public static ItemHandler Instance; private readonly ConcurrentQueue<(int, ItemInfo)> _cachedItems = new ConcurrentQueue<(int, ItemInfo)>(); private void Awake() { if ((Object)(object)Instance != (Object)null && (Object)(object)Instance != (Object)(object)this) { Object.Destroy((Object)(object)((Component)this).gameObject); } else { Instance = this; } } public void Reset() { _cachedItems.Clear(); } public void EnqueueItem(int itemIndex, ItemInfo item) { _cachedItems.Enqueue((itemIndex, item)); } private bool IsReady() { if (ArchipelagoHandler.Instance.IsConnected) { return PluginMain.SaveDataHandler?.APSaveData != null; } return false; } private void Update() { (int, ItemInfo) result; while (IsReady() && _cachedItems.TryDequeue(out result)) { HandleItem(result.Item1, result.Item2); } } private void HandleItem(int index, ItemInfo item) { //IL_0188: Unknown result type (might be due to invalid IL or missing references) //IL_018e: Invalid comparison between Unknown and I4 //IL_0203: Unknown result type (might be due to invalid IL or missing references) //IL_0209: Invalid comparison between Unknown and I4 //IL_02e3: Unknown result type (might be due to invalid IL or missing references) //IL_03fa: Unknown result type (might be due to invalid IL or missing references) //IL_03fc: Invalid comparison between I4 and Unknown //IL_0473: Unknown result type (might be due to invalid IL or missing references) //IL_0476: Unknown result type (might be due to invalid IL or missing references) //IL_0493: Unknown result type (might be due to invalid IL or missing references) //IL_0496: Unknown result type (might be due to invalid IL or missing references) //IL_04b6: Unknown result type (might be due to invalid IL or missing references) //IL_04b9: Unknown result type (might be due to invalid IL or missing references) //IL_04ba: Unknown result type (might be due to invalid IL or missing references) //IL_04dd: Unknown result type (might be due to invalid IL or missing references) //IL_04e0: Unknown result type (might be due to invalid IL or missing references) //IL_04e1: Unknown result type (might be due to invalid IL or missing references) if (index <= PluginMain.SaveDataHandler.APSaveData.ItemIndex) { return; } switch ((CCItem)item.ItemId) { case CCItem.Bell: { PluginMain.SaveDataHandler.APSaveData.Bells++; LobbyManager val = Object.FindObjectOfType<LobbyManager>(); if (!((Object)(object)val != (Object)null) || !((NetworkBehaviour)val).isServer) { break; } val.Network_syncHostTotalBells = PluginMain.SaveDataHandler.APSaveData.Bells; val._syncUnlockList.Clear(); int num = default(int); foreach (ContractObject allContract in val._allContracts) { if (allContract.isDemoLocked) { val._syncUnlockList.Add(false); } else if (val._syncHostTotalBells >= allContract.bellsRequired || ((int)allContract.type != 1 && SaveManager.data.TryGetContractBellCount(allContract, ref num) && num > 0)) { val._syncUnlockList.Add(true); } else { val._syncUnlockList.Add(false); } } LobbyContractVisualManager val2 = Object.FindObjectOfType<LobbyContractVisualManager>(); if ((Object)(object)val2 != (Object)null) { for (int i = 0; i < val2._contracts.Count; i++) { ContractObject val3 = val2._contracts[i]; int num2 = (((int)val3.type == 1) ? val3.randomBoxCount : val3.orders.Length); LobbyOrderVisualStack val4 = ((Component)val2.contractVisualGroup).GetComponentsInChildren<LobbyOrderVisualStack>()[i]; for (int j = 0; j < num2; j++) { Renderer[] componentsInChildren = ((Component)val4).GetComponentsInChildren<Renderer>(); foreach (Renderer val5 in componentsInChildren) { if (val.IsContractUnlocked(i)) { MaterialUtil.SetPropertyBlockFloat(val5, LobbyContractVisualManager.Locked, 0f); } } } } } ContractSelectionUI val6 = Object.FindObjectOfType<ContractSelectionUI>(); if (!((Object)(object)val6 != (Object)null)) { break; } int num3 = default(int); ContractScore val8 = default(ContractScore); TimeSpan zero = default(TimeSpan); for (int l = 0; l < val6._contracts.Count; l++) { ContractObject val7 = val6._contracts[l]; if (!SaveManager.data.TryGetContractBellCount(val7, ref num3)) { num3 = 0; } if (!SaveManager.data.TryGetContractScore(val7, ref val8)) { val8 = (ContractScore)0; } if (!SaveManager.data.TryGetContractTime(val7, ref zero)) { zero = TimeSpan.Zero; } ContractUI val9 = ((Component)val6.contractGroup).GetComponentsInChildren<ContractUI>()[l]; if (val7.bellsRequired <= PluginMain.SaveDataHandler.APSaveData.Bells) { val9.lockedContainer.SetActive(false); val9.unlockedContainer.SetActive(true); val9.bellsRequiredContainer.SetActive(true); ((TMP_Text)val9.bellsRequiredText).text = ""; val9.localizedText.SetIndex(val7.title); ((Component)val9.localizedText).gameObject.SetActive(true); val9.lockedText.SetActive(false); int num4 = ArchipelagoHandler.Instance.CountLocationsCheckedInRange(48 * l + 1, 48 * (l + 1) + 1); ((TMP_Text)val9.contractNumText).text = $"{num4}/{35} locations - {l + 1}"; ((Behaviour)val9.contractNumText).enabled = true; for (int m = 0; m < val9.bells.Length; m++) { val9.bells[m].SetActive(m < (int)val8); } for (int n = 0; n < val9.scoreBubbles.Length; n++) { val9.scoreBubbles[n].scoreBubble.SetActive(false); } ((Component)val9.finalGradeContainer).gameObject.SetActive(num3 > 0); val9.finalGradeImage.sprite = val9.gradeSprites[(num3 == 5) ? (val8 + 1) : 0]; val9.finalGradeDillyImage.sprite = val9.gradeDillySprites[(num3 == 5) ? (val8 + 1) : 0]; ((Graphic)val9.finalGradeImage).color = GlobalScriptableObject<AggroSettingsObject>.instance.gradeColors[(num3 == 5) ? (val8 + 1) : 0]; ((Graphic)val9.finalGradeDillyImage).color = GlobalScriptableObject<AggroSettingsObject>.instance.gradeColors[(num3 == 5) ? (val8 + 1) : 0]; if (num3 >= 5 && zero != TimeSpan.Zero) { ((TMP_Text)val9.bestTimeText).text = zero.ToString("mm\\:ss\\:ff"); } else { ((TMP_Text)val9.bestTimeText).text = "--:--:--"; } } } break; } case CCItem.Boost: PluginMain.SaveDataHandler.APSaveData.ShopUnlocks.Add("SHOPBOOST"); break; case CCItem.Charge: PluginMain.SaveDataHandler.APSaveData.ShopUnlocks.Add("SHOPCHARGE"); break; case CCItem.Button: PluginMain.SaveDataHandler.APSaveData.ShopUnlocks.Add("SHOPBT"); break; case CCItem.Extinguisher: PluginMain.SaveDataHandler.APSaveData.ShopUnlocks.Add("SHOPFE"); break; case CCItem.Scrub: PluginMain.SaveDataHandler.APSaveData.ShopUnlocks.Add("SHOPSCRUB"); break; case CCItem.Scrubbie: PluginMain.SaveDataHandler.APSaveData.ShopUnlocks.Add("SHOPROBO"); break; case CCItem.Shelf: PluginMain.SaveDataHandler.APSaveData.ShopUnlocks.Add("SHOPSHELF"); break; case CCItem.Sprinkler: PluginMain.SaveDataHandler.APSaveData.ShopUnlocks.Add("SHOPSMSPRINK"); break; case CCItem.Sturdy: PluginMain.SaveDataHandler.APSaveData.ShopUnlocks.Add("SHOPSTURDY"); break; case CCItem.Tele: PluginMain.SaveDataHandler.APSaveData.ShopUnlocks.Add("SHOPTELE"); break; case CCItem.Trash: PluginMain.SaveDataHandler.APSaveData.ShopUnlocks.Add("SHOPTRASH"); break; case CCItem.Vac: PluginMain.SaveDataHandler.APSaveData.ShopUnlocks.Add("SHOPVAC"); break; case CCItem.Leaf: PluginMain.SaveDataHandler.APSaveData.ShopUnlocks.Add("SHOPLEAF"); break; case CCItem.XlSprinkler: PluginMain.SaveDataHandler.APSaveData.ShopUnlocks.Add("SHOPXLSPRINK"); break; case CCItem.WaterBalloon: PluginMain.SaveDataHandler.APSaveData.ShopUnlocks.Add("SHOPWBP"); break; case CCItem.Wild: PluginMain.SaveDataHandler.APSaveData.ShopUnlocks.Add("SHOPCARD"); break; case CCItem.Nitro: PluginMain.SaveDataHandler.APSaveData.ShopUnlocks.Add("SHOPBOOSTP"); break; case CCItem.Aroma: PluginMain.SaveDataHandler.APSaveData.ShopUnlocks.Add("SHOPDECAYP"); break; case CCItem.Drift: PluginMain.SaveDataHandler.APSaveData.ShopUnlocks.Add("SHOPDRIFTP"); break; case CCItem.Shield: PluginMain.SaveDataHandler.APSaveData.ShopUnlocks.Add("SHOPEXPP"); break; case CCItem.Chain: PluginMain.SaveDataHandler.APSaveData.ShopUnlocks.Add("SHOPTRACP"); break; case CCItem.Cup: PluginMain.SaveDataHandler.APSaveData.ShopUnlocks.Add("SHOPSTRESSP"); break; case CCItem.Fan: PluginMain.SaveDataHandler.APSaveData.ShopUnlocks.Add("SHOPFIREP"); break; case CCItem.Grip: PluginMain.SaveDataHandler.APSaveData.ShopUnlocks.Add("SHOPGRIPP"); break; case CCItem.Spoiler: PluginMain.SaveDataHandler.APSaveData.ShopUnlocks.Add("SHOPSPEEDP"); break; case CCItem.Cosmetic: CostumeHandler.SelectRandom(); break; case CCItem.SpeedUpgrade: PluginMain.SaveDataHandler.APSaveData.SpeedUpgrades = Math.Min(PluginMain.SaveDataHandler.APSaveData.SpeedUpgrades + 1, 3); break; case CCItem.StrengthUpgrade: PluginMain.SaveDataHandler.APSaveData.StrengthUpgrades = Math.Min(PluginMain.SaveDataHandler.APSaveData.StrengthUpgrades + 1, 3); SkysTheLimitAPI.SetStackLimit(PluginMain.SaveDataHandler.APSaveData.StrengthUpgrades + 3); break; case CCItem.BoostUpgrade: PluginMain.SaveDataHandler.APSaveData.BoostUpgrades = Math.Min(PluginMain.SaveDataHandler.APSaveData.BoostUpgrades + 1, 3); break; case CCItem.StressUpgrade: PluginMain.SaveDataHandler.APSaveData.StressUpgrades = Math.Min(PluginMain.SaveDataHandler.APSaveData.StressUpgrades + 1, 3); break; } PluginMain.SaveDataHandler.APSaveData.ItemIndex = index; PluginMain.SaveDataHandler.SaveGame(); } } public class Localizer { public static void AddCustomLocalizations(string path) { Dictionary<string, List<string>> dictionary = JsonConvert.DeserializeObject<Dictionary<string, List<string>>>(File.ReadAllText(path)); if (dictionary == null) { return; } foreach (KeyValuePair<string, List<string>> item in dictionary) { LocalizedText.mainTable.Add(item.Key, item.Value); } } } [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInPlugin("crashout_crew_ap_client", "CrashoutCrew_APClient", "1.0.4")] public class PluginMain : BaseUnityPlugin { public static readonly int CONNECT_BUTTON_ID = AggroSettings.IdToHash("ap-connect"); public static string? LocalizationsPath; public static bool EnableDebugLogging; public static bool FilterLog; public const string GameName = "CrashoutCrew"; private const string Version = "1.0.4"; private readonly Harmony _harmony = new Harmony("crashout_crew_ap_client"); public static ManualLogSource? logger; public static SaveDataHandler? SaveDataHandler; public static Dictionary<string, AssetBundle> CustomBundles = new Dictionary<string, AssetBundle>(); public static float MessageInTime { get { return APConsole.Instance.slideInTime; } set { APConsole.Instance.slideInTime = value; } } public static float MessageHoldTime { get { return APConsole.Instance.holdTime; } set { APConsole.Instance.holdTime = value; } } public static float MessageOutTime { get { return APConsole.Instance.fadeOutTime; } set { APConsole.Instance.fadeOutTime = value; } } private void Awake() { Enforcer.Enforce("crashout_crew_ap_client", "1.0.4", (EnforcementDirection)2); CustomBundles = new Dictionary<string, AssetBundle>(); logger = ((BaseUnityPlugin)this).Logger; _harmony.PatchAll(); Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject); ((Component)this).gameObject.AddComponent<ArchipelagoHandler>(); ((Component)this).gameObject.AddComponent<ItemHandler>(); SaveDataHandler = ((Component)this).gameObject.AddComponent<SaveDataHandler>(); ArchipelagoHandler.OnDisconnect = (Action)Delegate.Combine(ArchipelagoHandler.OnDisconnect, (Action)delegate { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) Scene activeScene = SceneManager.GetActiveScene(); if (((Scene)(ref activeScene)).name != "scene-title") { SceneManager.LoadScene("scene-title"); } GameManager_Patches.ClearContracts(); AggroSettings.GetSetting<ButtonSetting>(CONNECT_BUTTON_ID).SetButtonLabel("Connect"); AggroSettings.RefreshSettingUIs(); }); SceneManager.sceneLoaded += delegate { if (SaveDataHandler?.APSaveData != null) { SkysTheLimitAPI.SetStackLimit(SaveDataHandler.APSaveData.StrengthUpgrades + 3); } }; string directoryName = Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location); if (directoryName == null) { throw new Exception("Mod directory not found"); } LocalizationsPath = Path.Combine(directoryName, "Localizations", "locs.json"); if (!File.Exists(LocalizationsPath)) { LocalizationsPath = Path.Combine(directoryName, "locs.json"); } string[] obj = new string[2] { "aggro-button-setting", "aggro-text-setting" }; string text = Path.Combine(directoryName, "Bundles"); if (!Directory.Exists(text)) { text = directoryName; } string[] array = obj; foreach (string text2 in array) { string text3 = Path.Combine(text, text2); if (!File.Exists(text3)) { throw new Exception("Bundle " + text2 + " not found"); } AssetBundle value = AssetBundle.LoadFromFile(text3); CustomBundles.Add(Path.GetFileNameWithoutExtension(text3), value); } SkysTheLimitAPI.SetStackLimit(3); } } public class CustomSaveData { public int ItemIndex; public readonly List<string> ShopUnlocks = new List<string>(); public int Bells; public int SpeedUpgrades; public int StrengthUpgrades; public int BoostUpgrades; public int StressUpgrades; public int HandlingUpgrades; } public class SaveDataHandler : MonoBehaviour { public CustomSaveData? APSaveData; private string _customDataPath = ""; public Action onInitialized; public void GetSave() { ArchipelagoHandler instance = ArchipelagoHandler.Instance; _customDataPath = Application.persistentDataPath + "/saves/Archipelago/" + instance.Slot + instance.Seed + ".json"; if (!Directory.Exists(Path.GetDirectoryName(_customDataPath))) { Directory.CreateDirectory(Path.GetDirectoryName(_customDataPath)); } if (File.Exists(_customDataPath)) { APSaveData = JsonConvert.DeserializeObject<CustomSaveData>(File.ReadAllText(_customDataPath)) ?? new CustomSaveData(); return; } APSaveData = new CustomSaveData(); File.WriteAllText(_customDataPath, JsonConvert.SerializeObject((object)APSaveData)); } public void SaveGame() { File.WriteAllText(_customDataPath, JsonConvert.SerializeObject((object)APSaveData)); SaveManager.SaveGameAsync(); } public void InitializeSave() { ((MonoBehaviour)this).StartCoroutine(InitializeSaveCo()); } private IEnumerator InitializeSaveCo() { if (APSaveData == null) { GetSave(); } if (SaveManager.DoesGameExist(0)) { APConsole.Instance.DebugLog("Save game exists!"); Task<LoadResult> task = SaveManager.InitializeLoadGameAsync(0); yield return (object)new WaitForTask((Task)task); if ((int)task.Result != 0) { bool doContinue = false; bool doQuit = false; AggroInputManager.Enable(); LoadResult result = task.Result; SaveError val; string text; if ((int)result != 1) { if ((int)result != 2) { throw new InvalidEnumException(); } val = (SaveError)1; text = ""; } else { val = (SaveError)0; text = new DateTime(SaveManager.data.timeStampTicks).ToString("g", CultureInfo.CurrentCulture); } PlayerMessageManager.QueueErrorMessage(val, text, (Action)delegate { doContinue = true; }, (Action)delegate { doQuit = true; }); while (!doContinue && !doQuit) { PlayerMessageManager.ProcessQueuedMessages(); yield return null; } AggroInputManager.Disable(); if (doQuit) { Application.Quit(); yield break; } if (doContinue) { result = task.Result; if ((int)result != 1) { if ((int)result != 2) { throw new InvalidEnumException(); } yield return SaveManager.DeleteGameAsync(0); SaveManager.InitializeNewGame(0); } else { yield return SaveManager.DeletePrimarySaveAsync(0); } yield return SaveManager.SaveGameAsync(); } } if (SaveManager.data.GetSaveVersion() != 1) { SaveManager.Uninitialize(); SaveManager.InitializeNewGame(0); yield return (object)new WaitForTask(SaveManager.SaveGameAsync()); } } else { APConsole.Instance.DebugLog("Save game does not exist!"); SaveManager.InitializeNewGame(0); yield return (object)new WaitForTask(SaveManager.SaveGameAsync()); } CostumeObject[] costumes = GlobalScriptableObject<CosmeticGlobalData>.instance.costumes; foreach (CostumeObject val2 in costumes) { if ((Object)(object)val2 != (Object)null && val2.startsUnlocked) { SaveManager.data.UnlockCostume(val2); } } onInitialized(); } public void Reset() { SaveGame(); APSaveData = null; } } public class SlotData { public readonly int ContractCountFour = 4; public readonly int ContractCountThree = 12; public readonly int ContractCountTwo = 4; public readonly bool DeathLink; public int ContractCount => ContractCountFour + ContractCountThree + ContractCountTwo; public SlotData(Dictionary<string, object> slotDict) { foreach (KeyValuePair<string, object> item in slotDict) { APConsole.Instance.DebugLog($"{item.Key} {item.Value}"); } if (slotDict.TryGetValue("FourOrderContracts", out object value) && value is long num) { ContractCountFour = (int)num; } if (slotDict.TryGetValue("ThreeOrderContracts", out object value2) && value2 is long num2) { ContractCountThree = (int)num2; } if (slotDict.TryGetValue("TwoOrderContracts", out object value3) && value3 is long num3) { ContractCountTwo = (int)num3; } } } public static class Utility { public static T? Random<T>(this IEnumerable<T> collection, int rangeStart = 0, int rangeEnd = -1, Random? random = null) { T[] array = (collection as T[]) ?? collection.ToArray(); if (array.Length != 0) { return array[random?.Next(0, array.Length - 1) ?? Random.Range(rangeStart, (rangeEnd == -1) ? array.Length : rangeEnd)]; } return default(T); } public static T? Random<T>(this Array collection, int rangeStart = 0, int rangeEnd = -1, Random? random = null) { if (collection.Length != 0) { return (T)collection.GetValue(random?.Next(0, collection.Length - 1) ?? Random.Range(rangeStart, (rangeEnd == -1) ? collection.Length : rangeEnd)); } return default(T); } } } namespace CrashoutCrew_APClient.Patches { [HarmonyPatch(typeof(SteamPlatform))] public class AchievementManager_Patches { [HarmonyPatch("UnlockAchievement", new Type[] { typeof(string) })] [HarmonyPrefix] public static bool UnlockAchievement(string id) { return false; } } [HarmonyPatch(typeof(AggroSettingsObject))] public static class AggroSettingsObject_Patches { [HarmonyPatch("TryGetTemplate")] [HarmonyPostfix] public static void TryGetTemplate(Type type, ref GameObject template, ref bool __result) { AssetBundle value2; if ((typeof(TextSetting).IsAssignableFrom(type) || type.Name == "TextSetting") && PluginMain.CustomBundles.TryGetValue("aggro-text-setting", out AssetBundle value)) { template = value.LoadAsset<GameObject>("prefab-aggrosetting-text"); __result = (Object)(object)template != (Object)null; } else if ((typeof(ButtonSetting).IsAssignableFrom(type) || type.Name == "ButtonSetting") && PluginMain.CustomBundles.TryGetValue("aggro-button-setting", out value2)) { template = value2.LoadAsset<GameObject>("prefab-aggrosetting-button"); __result = (Object)(object)template != (Object)null; } } [HarmonyPatch("TryGetCategoryLabel")] [HarmonyPrefix] public static bool TryGetCategoryLabel(AggroSettingsObject __instance, ref bool __result, string category, out string label) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Expected O, but got Unknown __instance.CheckInitialize(); if (!__instance._categoryToLabel.TryGetValue(category, out label)) { List<Category> list = __instance.categories.ToList(); list.Add(new Category()); list.Last().category = category; label = category.Substring(0, 1).ToUpper() + category.Substring(1, category.Length - 1); list.Last().label = label; __instance.categories = list.ToArray(); } __result = true; return false; } } [HarmonyPatch(typeof(ContractUI))] public static class ContractUI_Patches { [HarmonyPatch("SetUp")] [HarmonyPostfix] public static void SetUp(ContractUI __instance, int contractNum) { int num = ArchipelagoHandler.Instance.CountLocationsCheckedInRange(48 * (contractNum - 1) + 1, 48 * contractNum + 1); ((TMP_Text)__instance.contractNumText).text = $"{num}/{35} locations - {contractNum}"; } [HarmonyPatch("SetUp")] public static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions) { //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Expected O, but got Unknown //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Expected O, but got Unknown //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Expected O, but got Unknown List<CodeInstruction> list = new List<CodeInstruction>(instructions); MethodInfo methodInfo = AccessTools.Method(typeof(LocalizedText), "SetIndex", new Type[1] { typeof(string) }, (Type[])null); FieldInfo fieldInfo = AccessTools.Field(typeof(LocalizedText), "tmp"); MethodInfo methodInfo2 = AccessTools.Method(typeof(TMP_Text), "set_text", (Type[])null, (Type[])null); for (int i = 0; i < list.Count; i++) { if (CodeInstructionExtensions.Calls(list[i], methodInfo)) { if (i < 3 || list[i - 1].opcode != OpCodes.Ldarg_1) { throw new InvalidOperationException("ContractUI.SetUp: unexpected SetIndex IL pattern."); } list[i - 1] = new CodeInstruction(OpCodes.Ldfld, (object)fieldInfo); list.Insert(i, new CodeInstruction(OpCodes.Ldarg_1, (object)null)); list[i + 1] = new CodeInstruction(OpCodes.Callvirt, (object)methodInfo2); break; } } return list; } } [HarmonyPatch(typeof(CostumeChangeUI))] public static class CostumeChange_Patches { [HarmonyPatch("OnEntityCreated")] [HarmonyPrefix] public static bool OnEntityCreated(CostumeChangeUI __instance) { ((Component)((Component)__instance).transform.parent).gameObject.SetActive(false); return false; } } [HarmonyPatch(typeof(GameManager))] public static class GameManager_Patches { private static readonly string[] Excluded = new string[1] { "order-bingbong" }; public static DeckCard<ShopItemObject>[] ShopCards = null; private static ContractObject[]? _cachedContracts; public static void ClearContracts() { _cachedContracts = null; } [HarmonyPatch("GetContracts")] [HarmonyPrefix] public static bool GetContracts(GameManager __instance, ref ContractObject[] __result) { if (GameUtil.isDemo) { return true; } if (_cachedContracts != null) { __result = _cachedContracts; return false; } __result = Array.Empty<ContractObject>(); ShopCards = __instance.contracts.Last().shopCards.ToArray(); if (ArchipelagoHandler.Instance.Seed == null) { __result = __instance.contracts; return false; } Random random = new Random(int.Parse(ArchipelagoHandler.Instance.Seed.Substring(0, 9))); ShiftOrderObject[] allOrders = (from x in Resources.FindObjectsOfTypeAll<ShiftOrderObject>() where !Excluded.Contains(((Object)x).name) select x).ToArray(); int twoOrderContracts = ArchipelagoHandler.Instance.slotData?.ContractCountTwo ?? 5; int threeOrderContracts = ArchipelagoHandler.Instance.slotData?.ContractCountThree ?? 5; int fourOrderContracts = ArchipelagoHandler.Instance.slotData?.ContractCountFour ?? 5; _cachedContracts = ContractGenerator.GenerateContracts(random, allOrders, twoOrderContracts, threeOrderContracts, fourOrderContracts); __result = _cachedContracts; return false; } } [HarmonyPatch(typeof(GameUtil))] public class GameUtil_Patches { [HarmonyPatch("InitializeGameCo")] [HarmonyPrefix] public static bool Prefix(ref IEnumerator __result) { __result = InitializeGameCo(); return false; } private static IEnumerator InitializeGameCo() { if (!GameUtil._gameInitialized) { GameUtil._gameInitialized = true; yield return (object)new WaitForTask((Task)Platform.InitializeAsync()); AggroUtil.InitializeGlobalScrobs(); AudioManager.Initialize(); Options.Initialize(); if ((int)Platform.GetPlatformType() == 3) { AggroInputManager.ChangeMode((InputMode)2); } } } } [HarmonyPatch(typeof(LocalizedText))] public static class LocalizedText_Patches { [HarmonyPatch("LoadMainTable")] [HarmonyPostfix] public static void LoadMainTable(bool forceSerialization = true) { if (PluginMain.LocalizationsPath != null) { Localizer.AddCustomLocalizations(PluginMain.LocalizationsPath); } } } [HarmonyPatch(typeof(NitroController))] public class NitroController_Patches { [HarmonyPatch("LocalPlayerGetChargeCount")] [HarmonyPrefix] public static void OnLocalPlayerGetChargeCount(NitroController __instance) { __instance.maxNitroCharges = 1; if (PluginMain.SaveDataHandler?.APSaveData != null) { __instance.maxNitroCharges = PluginMain.SaveDataHandler.APSaveData.BoostUpgrades + 1; } } } [HarmonyPatch(typeof(NitroUI))] public class NitroUI_Patches { [HarmonyPatch("OnUpdatePresentation")] [HarmonyPrefix] public static void OnUpdatePresentation(NitroUI __instance) { if (__instance.nitroBars.Length != 5) { GameObject gameObject = ((Component)__instance.nitroBars.Last()).gameObject; Transform parent = gameObject.transform.parent; NitroBarUI component = Object.Instantiate<GameObject>(gameObject, parent).GetComponent<NitroBarUI>(); List<NitroBarUI> list = new List<NitroBarUI>(__instance.nitroBars); list.Add(component); __instance.nitroBars = list.ToArray(); } } } [HarmonyPatch(typeof(Options))] public static class Options_Patches { private static readonly int SERVER_SETTING_ID = AggroSettings.IdToHash("ap-server"); private static readonly int SLOT_SETTING_ID = AggroSettings.IdToHash("ap-slot"); private static readonly int PASS_SETTING_ID = AggroSettings.IdToHash("ap-pass"); [HarmonyPatch("AddGameSettings")] [HarmonyPrefix] public static void AddGameSettings() { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Expected O, but got Unknown //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Expected O, but got Unknown //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Expected O, but got Unknown //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Expected O, but got Unknown //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Expected O, but got Unknown //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Expected O, but got Unknown //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_0164: Unknown result type (might be due to invalid IL or missing references) //IL_016a: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Unknown result type (might be due to invalid IL or missing references) //IL_0175: Expected O, but got Unknown //IL_01b5: Unknown result type (might be due to invalid IL or missing references) //IL_01bb: Unknown result type (might be due to invalid IL or missing references) //IL_01be: Unknown result type (might be due to invalid IL or missing references) //IL_01c4: Unknown result type (might be due to invalid IL or missing references) //IL_01c5: Unknown result type (might be due to invalid IL or missing references) //IL_01cf: Expected O, but got Unknown //IL_020f: Unknown result type (might be due to invalid IL or missing references) //IL_0215: Unknown result type (might be due to invalid IL or missing references) //IL_0218: Unknown result type (might be due to invalid IL or missing references) //IL_021e: Unknown result type (might be due to invalid IL or missing references) //IL_021f: Unknown result type (might be due to invalid IL or missing references) //IL_0229: Expected O, but got Unknown //IL_025c: Unknown result type (might be due to invalid IL or missing references) //IL_0266: Expected O, but got Unknown AggroSettings.AddSetting("ap-server", "ap", "AP_Server", (AggroSettingBase)new TextSetting("archipelago.gg:38281", "", false)); AggroSettings.AddSetting("ap-slot", "ap", "AP_Slot", (AggroSettingBase)new TextSetting("Player1", "", false)); AggroSettings.AddSetting("ap-pass", "ap", "AP_Password", (AggroSettingBase)new TextSetting("", "", true)); AggroSettings.AddSetting("ap-connect", "ap", "", (AggroSettingBase)new ButtonSetting("AP_Connect", (Action)delegate { if (ArchipelagoHandler.Instance.IsConnected) { ArchipelagoHandler.Instance.Disconnect(); } else { TextSetting setting = AggroSettings.GetSetting<TextSetting>(SERVER_SETTING_ID); TextSetting setting2 = AggroSettings.GetSetting<TextSetting>(SLOT_SETTING_ID); TextSetting setting3 = AggroSettings.GetSetting<TextSetting>(PASS_SETTING_ID); if (!((Object)(object)ArchipelagoHandler.Instance == (Object)null) && ArchipelagoHandler.Instance.connectionFinished) { APConsole.Instance.Log("Connecting..."); if (string.IsNullOrWhiteSpace(setting.text)) { APConsole.Instance.Log("<color=\"red\">[ERROR] Server cannot be empty!</color>"); } else if (string.IsNullOrWhiteSpace(setting2.text)) { APConsole.Instance.Log("<color=\"red\">[ERROR] Slot cannot be empty!</color>"); } else if (!ArchipelagoHandler.Instance.CreateSession(setting.text, setting2.text, setting3.text)) { APConsole.Instance.Log("<color=\"red\">[ERROR] The server cannot be reached or your slot/password is incorrect.</color>"); } else { ArchipelagoHandler.Instance.OnConnected += Title_Patches.HandleConnected; ArchipelagoHandler.Instance.OnConnectionFailed += Title_Patches.HandleConnectionFailed; ArchipelagoHandler.Instance.Connect(); } } } })); AggroSettings.AddSetting("ap-debug", "ap", "AP_Debug_Logging", (AggroSettingBase)new ToggleSetting(false, (Action<bool>)delegate(bool b) { PluginMain.EnableDebugLogging = b; })); AggroSettings.AddSetting("ap-filter", "ap", "AP_Filter_Log_To_Self", (AggroSettingBase)new ToggleSetting(false, (Action<bool>)delegate(bool b) { PluginMain.FilterLog = b; })); AggroSettings.AddSetting("ap-message-in", "ap", "AP_Message_In_Time", (AggroSettingBase)new FloatSetting((Style)0, 0.15f, 0.5f, 0.25f, (Action<float>)delegate(float f) { PluginMain.MessageInTime = f; }, default(EventReference), default(EventReference))); AggroSettings.AddSetting("ap-message-hold", "ap", "AP_Message_Hold_Time", (AggroSettingBase)new FloatSetting((Style)0, 0.5f, 5f, 2.5f, (Action<float>)delegate(float f) { PluginMain.MessageHoldTime = f; }, default(EventReference), default(EventReference))); AggroSettings.AddSetting("ap-message-out", "ap", "AP_Message_Out_Time", (AggroSettingBase)new FloatSetting((Style)0, 0.15f, 0.5f, 0.4f, (Action<float>)delegate(float f) { PluginMain.MessageOutTime = f; }, default(EventReference), default(EventReference))); AggroSettings.AddSetting("ap-test-message", "ap", "", (AggroSettingBase)new ButtonSetting("AP_Test_Message", (Action)delegate { APConsole.Instance.Log("This is a test!"); })); } } [HarmonyPatch(typeof(PlayerColorManager))] public class PlayerColorManager_Patches { [HarmonyPatch("OnEntityCreated")] [HarmonyPrefix] public static bool OnEntityCreated(PlayerColorManager __instance) { return SaveManager.isInitialized; } } [HarmonyPatch(typeof(PlayerCostumeManager))] public class PlayerCostumeManager_Patches { [HarmonyPatch("OnEntityCreated")] [HarmonyPrefix] public static bool OnEntityCreated(PlayerCostumeManager __instance) { return SaveManager.isInitialized; } } [HarmonyPatch(typeof(PlayerEffects))] public class PlayerEffects_Patches { private static readonly Dictionary<int, int> SpeedUpgradePercentage = new Dictionary<int, int> { { 0, -10 }, { 1, 0 }, { 2, 10 }, { 3, 20 } }; [HarmonyPatch("OnUpdateSimulationEarly")] [HarmonyPostfix] public static void OnUpdateSimulationEarly(PlayerEffects __instance) { if (PluginMain.SaveDataHandler?.APSaveData != null) { __instance.AddVehicleSpeedPercentageRaw(SpeedUpgradePercentage[PluginMain.SaveDataHandler.APSaveData.SpeedUpgrades]); __instance.AddVehicleSpeedPercentageMinMax(SpeedUpgradePercentage[PluginMain.SaveDataHandler.APSaveData.SpeedUpgrades]); } } } [HarmonyPatch(typeof(PlayerStress))] public class PlayerStress_Patches { [HarmonyPatch("LocalPlayerGetStressBarAmount")] public static bool OnLocalPlayerGetStressBarAmount(PlayerStress __instance, ref float __result) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) Entity entity = ((IEntityBehaviourBase)__instance).entity; PlayerUpgrades val = ((Entity)(ref entity)).GetObject<PlayerUpgrades>(); __result = 1f; if (val.HasUpgrade((PlayerUpgrade)8)) { __result = val.stressBarUpAmount; } __result -= 0.25f; if (PluginMain.SaveDataHandler?.APSaveData != null) { __result += 0.25f * (float)PluginMain.SaveDataHandler.APSaveData.StressUpgrades; } return false; } } [HarmonyPatch(typeof(SaveData))] public class SaveData_Patches { [HarmonyPatch("GetTotalBells")] [HarmonyPrefix] public static bool GetTotalBells(SaveData __instance, out int __result) { __result = PluginMain.SaveDataHandler.APSaveData?.Bells ?? 0; return false; } [HarmonyPatch("GetUnlockedCostumes", new Type[] { })] [HarmonyPrefix] public static bool GetUnlockedCostumes(ref CostumeObject[] __result) { __result = new List<CostumeObject>(GlobalScriptableObject<CosmeticGlobalData>.instance.costumes).ToArray(); return false; } } [HarmonyPatch(typeof(SaveManager))] public class SaveManager_Patches { [HarmonyPatch("GetFilePath")] [HarmonyPrefix] public static bool GetFilePath(ref string __result, int saveIndex) { __result = Application.persistentDataPath + "/saves/Archipelago/" + ArchipelagoHandler.Instance.Slot + ArchipelagoHandler.Instance.Seed + ".sav"; return false; } [HarmonyPatch("GetBackupFilePath")] [HarmonyPrefix] public static bool GetBackupFilePath(ref string __result, int saveIndex) { __result = Application.persistentDataPath + "/saves/Archipelago/" + ArchipelagoHandler.Instance.Slot + ArchipelagoHandler.Instance.Seed + "backup.sav"; return false; } } [HarmonyPatch(typeof(SettingsUI))] public class SettingsUI_Patches { [HarmonyPatch("OpenSettings")] [HarmonyPrefix] public static bool OpenSettings(SettingsUI __instance) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) __instance.clickCatch.SetActive(true); AggroInputManager.PushController((IInputController)(object)__instance); AggroSettings.ShowSettings("ap", __instance.settingsParent, AggroInputManager.mode); return false; } } [HarmonyPatch(typeof(ShiftManager))] public class ShiftManager_Patches { [HarmonyPatch("ServerTruckCompleted")] [HarmonyPrefix] public static void OnServerTruckCompleted(ShiftManager __instance) { int trucksCompleted = __instance.GetTrucksCompleted(); int num = __instance.GetCurrentShift() - 1; int num2 = GameUtil.contract.bellsRequired / 5; APConsole.Instance.DebugLog($"Truck #{trucksCompleted + 1} | Shift #{num + 1} | Contract #{num2 + 1}"); ArchipelagoHandler.Instance.CheckLocation(48 * num2 + 9 * num + trucksCompleted + 2); } [HarmonyPatch("TransitionShiftToShiftWon")] [HarmonyPrefix] public static void OnTransitionShiftToShiftWon(ShiftManager __instance, int seed) { int num = __instance.GetCurrentShift() - 1; int num2 = GameUtil.contract.bellsRequired / 5; APConsole.Instance.DebugLog($"Shift #{num + 1} | Contract #{num2 + 1}"); ArchipelagoHandler.Instance.CheckLocation(48 * num2 + 9 * num + 1); } [HarmonyPatch("TransitionShiftToGameWon")] [HarmonyPrefix] public static void OnTransitionShiftToGameWon(int seed) { int num = GameUtil.contract.bellsRequired / 5; APConsole.Instance.DebugLog($"Shift #{5} | Contract #{num + 1}"); ArchipelagoHandler.Instance.CheckLocation(48 * num + 36 + 1); SlotData? slotData = ArchipelagoHandler.Instance.slotData; if (num == ((slotData != null) ? new int?(slotData.ContractCount - 1) : ((int?)null))) { ArchipelagoHandler.Instance.Release(); } } } [HarmonyPatch(typeof(Shop))] public static class Shop_Patches { [HarmonyPatch("OnEntityCreated")] [HarmonyPrefix] public static bool OnEntityCreated(Shop __instance) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) if (!((NetworkBehaviour)__instance).isServer || GameUtil.isTutorial) { return true; } Random random = MathUtil.GetRandom(Hash.Calculate(GameUtil.seed, Hash.Calculate(((object)__instance).GetType(), 0))); DeckCard<ShopItemObject>[] shopCards = GameManager_Patches.ShopCards; __instance._serverRandomDeck = new Deck<ShopItemObject>(((Random)(ref random)).NextInt()); DeckCard<ShopItemObject>[] array = shopCards; foreach (DeckCard<ShopItemObject> val in array) { __instance._serverRandomDeck.AddCard(val.item, val.cardCount); } __instance._serverDeck = new Deck<ShopCard>(((Random)(ref random)).NextInt()); __instance._serverDeck.AddCard(new ShopCard { type = (ItemType)1 }, __instance._serverRandomDeck.cardCount); __instance._serverDeck.Shuffle(); __instance._serverSeed = ((Random)(ref random)).NextInt(); return false; } [HarmonyPatch("CanAddShopItem")] [HarmonyPrefix] public static bool CanAddShopItem(ShopItemObject candidate) { return PluginMain.SaveDataHandler.APSaveData?.ShopUnlocks.Contains(candidate.itemName) ?? false; } } [HarmonyPatch(typeof(Title))] public class Title_Patches { private static Button? _connectButton; private static Title? _instance; private static TextMeshProUGUI? connectTmp; [HarmonyPatch("Start")] [HarmonyPrefix] public static void Start(Title __instance) { //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Expected O, but got Unknown //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Expected O, but got Unknown _instance = __instance; _connectButton = ((Component)__instance.releaseButtons[0]).GetComponent<Button>(); ((Selectable)((Component)__instance.releaseButtons[2]).GetComponent<Button>()).interactable = false; SettingsUI settingsUI = ((Component)((Component)_connectButton).transform.parent.parent).GetComponentInChildren<SettingsUI>(); GameObject gameObject = ((Component)__instance.releaseButtons[1]).gameObject; __instance.releaseButtons = __instance.releaseButtons.Where((Button x) => ((Object)x).name != "HostGame").ToArray(); gameObject.SetActive(false); Object.Destroy((Object)(object)((Component)_connectButton).GetComponentInChildren<LocalizedText>(true)); connectTmp = ((Component)_connectButton).GetComponentInChildren<TextMeshProUGUI>(true); _connectButton.onClick = new ButtonClickedEvent();