

using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Threading.Tasks;
using Archipelago.MultiClient.Net;
using Archipelago.MultiClient.Net.Enums;
using Archipelago.MultiClient.Net.Helpers;
using Archipelago.MultiClient.Net.Models;
using Archipelago.MultiClient.Net.Packets;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using ContentWarningArchipelago.Core;
using ContentWarningArchipelago.Data;
using ContentWarningArchipelago.Patches;
using ContentWarningArchipelago.UI;
using ExitGames.Client.Photon;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using MyceliumNetworking;
using Newtonsoft.Json;
using Photon.Pun;
using Photon.Realtime;
using Steamworks;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;
using Zorro.Core;
using pworld.Scripts.Extensions;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("ContentWarningArchipelago")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Archipelago Randomizer for Content Warning")]
[assembly: AssemblyFileVersion("0.1.0.0")]
[assembly: AssemblyInformationalVersion("0.1.0+d5a1c89490f6c458788e6ad9cf7614c79d7b34be")]
[assembly: AssemblyProduct("Content Warning Archipelago")]
[assembly: AssemblyTitle("ContentWarningArchipelago")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.1.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
internal sealed class NullableAttribute : Attribute
{
public readonly byte[] NullableFlags;
public NullableAttribute(byte P_0)
{
NullableFlags = new byte[1] { P_0 };
}
public NullableAttribute(byte[] P_0)
{
NullableFlags = P_0;
}
}
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
internal sealed class NullableContextAttribute : Attribute
{
public readonly byte Flag;
public NullableContextAttribute(byte P_0)
{
Flag = P_0;
}
}
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
internal sealed class RefSafetyRulesAttribute : Attribute
{
public readonly int Version;
public RefSafetyRulesAttribute(int P_0)
{
Version = P_0;
}
}
}
namespace ContentWarningArchipelago
{
[BepInPlugin("automagic.cw-archipelago", "Content Warning Archipelago", "0.1.0")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public class Plugin : BaseUnityPlugin
{
internal static ManualLogSource Logger;
public static ArchipelagoClient connection;
internal const uint MyceliumModId = 2718281828u;
public static APConfig APConfig { get; private set; }
public static string apAddress => APConfig?.address.Value ?? "archipelago.gg";
public static int apPort => APConfig?.port.Value ?? 38281;
public static string apPassword => APConfig?.password.Value ?? "";
public static string apSlot => APConfig?.slot.Value ?? "";
public static Plugin Instance { get; private set; }
public static bool isConnecting { get; private set; }
private void Awake()
{
//IL_006c: Unknown result type (might be due to invalid IL or missing references)
Instance = this;
Logger = ((BaseUnityPlugin)this).Logger;
Logger.LogInfo((object)"[CWArch] automagic.cw-archipelago v0.1.0 loading…");
APConfig = new APConfig(((BaseUnityPlugin)this).Config);
Logger.LogInfo((object)$"[CWArch] Config loaded. AP address: {apAddress}:{APConfig.port.Value}");
ItemData.Init();
LocationData.Init();
new Harmony("automagic.cw-archipelago").PatchAll();
MyceliumNetwork.RegisterNetworkObject((object)this, 2718281828u, 0);
Logger.LogInfo((object)"[CWArch] Harmony patches applied.");
}
private void Start()
{
connection = new ArchipelagoClient();
Logger.LogInfo((object)"[CWArch] ArchipelagoClient created. Waiting for connection.");
}
private void OnDestroy()
{
MyceliumNetwork.DeregisterNetworkObject((object)this, 2718281828u, 0);
}
private void Update()
{
if (connection.connected)
{
connection.checkItemsReceived?.MoveNext();
connection.incomingItemHandler?.MoveNext();
connection.outgoingCheckHandler?.MoveNext();
}
}
[CustomRPC]
internal void LocationFound(string locName, RPCInfo info)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
if (info.SenderSteamID != SteamUser.GetSteamID())
{
Logger.LogDebug((object)("[CWArch] Received remote location-found notification: '" + locName + "'"));
APNotificationUI.ShowLocationFound(locName);
}
}
public static async void Connect()
{
if (isConnecting || connection.connected)
{
return;
}
isConnecting = true;
try
{
await connection.TryConnect(apAddress, apPort, apPassword, apSlot);
}
finally
{
isConnecting = false;
}
}
public static void Disconnect()
{
connection.TryDisconnect();
}
public static void SendCheck(long locationId)
{
connection.ActivateCheck(locationId);
}
}
public static class MyPluginInfo
{
public const string PLUGIN_GUID = "automagic.cw-archipelago";
public const string PLUGIN_NAME = "Content Warning Archipelago";
public const string PLUGIN_VERSION = "0.1.0";
}
}
namespace ContentWarningArchipelago.UI
{
public class APConnectionPanelUI : MonoBehaviour
{
private TMP_InputField _addressField;
private TMP_InputField _slotField;
private TMP_InputField _passwordField;
private Button _connectButton;
private Button _disconnectButton;
private TextMeshProUGUI _statusLabel;
private static readonly Color ColDisconnected = new Color(0.9f, 0.22f, 0.22f);
private static readonly Color ColConnecting = new Color(1f, 0.85f, 0.1f);
private static readonly Color ColConnected = new Color(0.2f, 0.88f, 0.2f);
private void Awake()
{
BuildUI();
PopulateFromConfig();
}
private void Update()
{
//IL_0026: Unknown result type (might be due to invalid IL or missing references)
//IL_007b: Unknown result type (might be due to invalid IL or missing references)
//IL_005a: Unknown result type (might be due to invalid IL or missing references)
if (_statusLabel != null)
{
if (Plugin.isConnecting)
{
((TMP_Text)_statusLabel).text = "○ Connecting…";
((Graphic)_statusLabel).color = ColConnecting;
}
else if (Plugin.connection != null && Plugin.connection.connected)
{
((TMP_Text)_statusLabel).text = "● Connected!";
((Graphic)_statusLabel).color = ColConnected;
}
else
{
((TMP_Text)_statusLabel).text = "● Disconnected";
((Graphic)_statusLabel).color = ColDisconnected;
}
}
}
public void PopulateFromConfig()
{
if (Plugin.APConfig != null)
{
if (_addressField != null)
{
_addressField.text = $"{Plugin.APConfig.address.Value}:{Plugin.APConfig.port.Value}";
}
if (_slotField != null)
{
_slotField.text = Plugin.APConfig.slot.Value;
}
if (_passwordField != null)
{
_passwordField.text = Plugin.APConfig.password.Value;
}
}
}
private void OnAddressChanged(string value)
{
if (Plugin.APConfig == null)
{
return;
}
int num = value.LastIndexOf(':');
if (num > 0 && num < value.Length - 1)
{
string value2 = value.Substring(0, num);
string s = value.Substring(num + 1);
Plugin.APConfig.address.Value = value2;
if (int.TryParse(s, out var result) && result > 0 && result <= 65535)
{
Plugin.APConfig.port.Value = result;
}
}
else if (num < 0)
{
Plugin.APConfig.address.Value = value.Trim();
}
Plugin.Logger.LogDebug((object)$"[APPanel] Address updated: {Plugin.APConfig.address.Value}:{Plugin.APConfig.port.Value}");
}
private void OnSlotChanged(string value)
{
if (Plugin.APConfig != null)
{
Plugin.APConfig.slot.Value = value;
Plugin.Logger.LogDebug((object)("[APPanel] Slot updated: " + value));
}
}
private void OnPasswordChanged(string value)
{
if (Plugin.APConfig != null)
{
Plugin.APConfig.password.Value = value;
Plugin.Logger.LogDebug((object)"[APPanel] Password updated.");
}
}
private void OnConnectClicked()
{
if (!Plugin.isConnecting)
{
ArchipelagoClient connection = Plugin.connection;
if (connection == null || !connection.connected)
{
Plugin.Logger.LogInfo((object)"[APPanel] Connect button clicked.");
Plugin.Connect();
}
}
}
private void OnDisconnectClicked()
{
Plugin.Logger.LogInfo((object)"[APPanel] Disconnect button clicked.");
Plugin.Disconnect();
}
private void BuildUI()
{
//IL_0043: Unknown result type (might be due to invalid IL or missing references)
//IL_004d: Expected O, but got Unknown
//IL_0099: Unknown result type (might be due to invalid IL or missing references)
//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
if (((Component)this).gameObject.GetComponent<RectTransform>() == null)
{
((Component)this).gameObject.AddComponent<RectTransform>();
}
ContentSizeFitter obj = ((Component)this).gameObject.AddComponent<ContentSizeFitter>();
obj.verticalFit = (FitMode)2;
obj.horizontalFit = (FitMode)0;
VerticalLayoutGroup obj2 = ((Component)this).gameObject.AddComponent<VerticalLayoutGroup>();
((LayoutGroup)obj2).padding = new RectOffset(10, 10, 8, 8);
((HorizontalOrVerticalLayoutGroup)obj2).spacing = 5f;
((LayoutGroup)obj2).childAlignment = (TextAnchor)0;
((HorizontalOrVerticalLayoutGroup)obj2).childControlWidth = true;
((HorizontalOrVerticalLayoutGroup)obj2).childControlHeight = false;
((HorizontalOrVerticalLayoutGroup)obj2).childForceExpandWidth = true;
((HorizontalOrVerticalLayoutGroup)obj2).childForceExpandHeight = false;
((Graphic)((Component)this).gameObject.AddComponent<Image>()).color = new Color(0.05f, 0.05f, 0.05f, 0.72f);
CreateLabel(((Component)this).transform, "── Archipelago Connection ──", 16f, (FontStyles)1, (TextAlignmentOptions)514, 26f, new Color(1f, 0.92f, 0.016f));
_addressField = CreateLabeledField(((Component)this).transform, "Address : Port", $"{Plugin.apAddress}:{Plugin.apPort}", isPassword: false);
_slotField = CreateLabeledField(((Component)this).transform, "Slot Name", Plugin.apSlot, isPassword: false);
_passwordField = CreateLabeledField(((Component)this).transform, "Password", Plugin.apPassword, isPassword: true);
((UnityEvent<string>)(object)_addressField.onEndEdit).AddListener((UnityAction<string>)OnAddressChanged);
((UnityEvent<string>)(object)_slotField.onEndEdit).AddListener((UnityAction<string>)OnSlotChanged);
((UnityEvent<string>)(object)_passwordField.onEndEdit).AddListener((UnityAction<string>)OnPasswordChanged);
CreateButtonRow(((Component)this).transform);
}
private static TMP_InputField CreateLabeledField(Transform parent, string labelText, string initialValue, bool isPassword)
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
//IL_0011: Expected O, but got Unknown
//IL_0066: Unknown result type (might be due to invalid IL or missing references)
//IL_006b: Unknown result type (might be due to invalid IL or missing references)
//IL_007d: Unknown result type (might be due to invalid IL or missing references)
//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
GameObject val = new GameObject("APRow_" + labelText);
val.transform.SetParent(parent, false);
val.AddComponent<LayoutElement>().preferredHeight = 28f;
HorizontalLayoutGroup obj = val.AddComponent<HorizontalLayoutGroup>();
((HorizontalOrVerticalLayoutGroup)obj).spacing = 6f;
((LayoutGroup)obj).childAlignment = (TextAnchor)3;
((HorizontalOrVerticalLayoutGroup)obj).childControlWidth = false;
((HorizontalOrVerticalLayoutGroup)obj).childControlHeight = true;
((HorizontalOrVerticalLayoutGroup)obj).childForceExpandWidth = false;
((HorizontalOrVerticalLayoutGroup)obj).childForceExpandHeight = false;
GameObject val2 = new GameObject("Label");
val2.transform.SetParent(val.transform, false);
LayoutElement obj2 = val2.AddComponent<LayoutElement>();
obj2.preferredWidth = 110f;
obj2.preferredHeight = 28f;
TextMeshProUGUI obj3 = val2.AddComponent<TextMeshProUGUI>();
((TMP_Text)obj3).text = labelText;
((TMP_Text)obj3).fontSize = 13f;
((TMP_Text)obj3).alignment = (TextAlignmentOptions)4100;
((Graphic)obj3).color = new Color(0.85f, 0.85f, 0.85f);
TMP_InputField val3 = CreateInputField(val.transform, labelText, isPassword);
LayoutElement obj4 = ((Component)val3).gameObject.GetComponent<LayoutElement>() ?? ((Component)val3).gameObject.AddComponent<LayoutElement>();
obj4.flexibleWidth = 1f;
obj4.preferredHeight = 28f;
val3.text = initialValue;
return val3;
}
private void CreateButtonRow(Transform parent)
{
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
//IL_000b: Expected O, but got Unknown
//IL_0076: Unknown result type (might be due to invalid IL or missing references)
//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
//IL_00d5: Expected O, but got Unknown
//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
//IL_00f1: Expected O, but got Unknown
//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
//IL_00fc: Expected O, but got Unknown
//IL_016b: Unknown result type (might be due to invalid IL or missing references)
GameObject val = new GameObject("APButtonRow");
val.transform.SetParent(parent, false);
val.AddComponent<LayoutElement>().preferredHeight = 32f;
HorizontalLayoutGroup obj = val.AddComponent<HorizontalLayoutGroup>();
((HorizontalOrVerticalLayoutGroup)obj).spacing = 8f;
((LayoutGroup)obj).childAlignment = (TextAnchor)3;
((HorizontalOrVerticalLayoutGroup)obj).childControlWidth = false;
((HorizontalOrVerticalLayoutGroup)obj).childControlHeight = true;
((HorizontalOrVerticalLayoutGroup)obj).childForceExpandWidth = false;
((HorizontalOrVerticalLayoutGroup)obj).childForceExpandHeight = false;
_connectButton = CreateButton(val.transform, "Connect", new Color(0.16f, 0.56f, 0.16f), 88f);
_disconnectButton = CreateButton(val.transform, "Disconnect", new Color(0.5f, 0.13f, 0.13f), 100f);
((UnityEvent)_connectButton.onClick).AddListener(new UnityAction(OnConnectClicked));
((UnityEvent)_disconnectButton.onClick).AddListener(new UnityAction(OnDisconnectClicked));
GameObject val2 = new GameObject("StatusLabel");
val2.transform.SetParent(val.transform, false);
LayoutElement obj2 = val2.AddComponent<LayoutElement>();
obj2.flexibleWidth = 1f;
obj2.preferredHeight = 32f;
_statusLabel = val2.AddComponent<TextMeshProUGUI>();
((TMP_Text)_statusLabel).fontSize = 13f;
((TMP_Text)_statusLabel).alignment = (TextAlignmentOptions)4097;
((TMP_Text)_statusLabel).text = "● Disconnected";
((Graphic)_statusLabel).color = ColDisconnected;
}
private static TextMeshProUGUI CreateLabel(Transform parent, string text, float fontSize, FontStyles style, TextAlignmentOptions alignment, float height, Color color = default(Color))
{
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
//IL_000a: Unknown result type (might be due to invalid IL or missing references)
//IL_0017: 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_003f: Unknown result type (might be due to invalid IL or missing references)
//IL_0047: Unknown result type (might be due to invalid IL or missing references)
//IL_004b: 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_005d: Unknown result type (might be due to invalid IL or missing references)
//IL_0059: Unknown result type (might be due to invalid IL or missing references)
GameObject val = new GameObject("APLabel");
val.transform.SetParent(parent, false);
val.AddComponent<LayoutElement>().preferredHeight = height;
TextMeshProUGUI obj = val.AddComponent<TextMeshProUGUI>();
((TMP_Text)obj).text = text;
((TMP_Text)obj).fontSize = fontSize;
((TMP_Text)obj).fontStyle = style;
((TMP_Text)obj).alignment = alignment;
((Graphic)obj).color = ((color == default(Color)) ? Color.white : color);
return obj;
}
private static TMP_InputField CreateInputField(Transform parent, string placeholder, bool isPassword)
{
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
//IL_000b: Expected O, but got Unknown
//IL_0039: 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_0055: Expected O, but got Unknown
//IL_006f: Unknown result type (might be due to invalid IL or missing references)
//IL_007a: Unknown result type (might be due to invalid IL or missing references)
//IL_008f: 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_00ba: Unknown result type (might be due to invalid IL or missing references)
//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
//IL_0133: Unknown result type (might be due to invalid IL or missing references)
//IL_015e: Unknown result type (might be due to invalid IL or missing references)
//IL_0163: Unknown result type (might be due to invalid IL or missing references)
//IL_0175: Unknown result type (might be due to invalid IL or missing references)
//IL_017c: Unknown result type (might be due to invalid IL or missing references)
//IL_0187: Unknown result type (might be due to invalid IL or missing references)
//IL_0192: Unknown result type (might be due to invalid IL or missing references)
//IL_019c: 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)
GameObject val = new GameObject("InputField");
val.transform.SetParent(parent, false);
val.AddComponent<RectTransform>();
((Graphic)val.AddComponent<Image>()).color = new Color(0.12f, 0.12f, 0.12f, 0.95f);
TMP_InputField val2 = val.AddComponent<TMP_InputField>();
GameObject val3 = new GameObject("Text Area");
val3.transform.SetParent(val.transform, false);
RectTransform val4 = val3.AddComponent<RectTransform>();
val4.anchorMin = Vector2.zero;
val4.anchorMax = Vector2.one;
val4.offsetMin = new Vector2(5f, 2f);
val4.offsetMax = new Vector2(-5f, -2f);
val3.AddComponent<RectMask2D>();
GameObject val5 = new GameObject("Placeholder");
val5.transform.SetParent(val3.transform, false);
RectTransform obj = val5.AddComponent<RectTransform>();
obj.anchorMin = Vector2.zero;
obj.anchorMax = Vector2.one;
obj.offsetMin = Vector2.zero;
obj.offsetMax = Vector2.zero;
TextMeshProUGUI val6 = val5.AddComponent<TextMeshProUGUI>();
((TMP_Text)val6).text = placeholder;
((TMP_Text)val6).fontSize = 13f;
((Graphic)val6).color = new Color(0.65f, 0.65f, 0.65f, 0.65f);
((TMP_Text)val6).alignment = (TextAlignmentOptions)4097;
((TMP_Text)val6).fontStyle = (FontStyles)2;
((Graphic)val6).raycastTarget = false;
GameObject val7 = new GameObject("Text");
val7.transform.SetParent(val3.transform, false);
RectTransform obj2 = val7.AddComponent<RectTransform>();
obj2.anchorMin = Vector2.zero;
obj2.anchorMax = Vector2.one;
obj2.offsetMin = Vector2.zero;
obj2.offsetMax = Vector2.zero;
TextMeshProUGUI val8 = val7.AddComponent<TextMeshProUGUI>();
((TMP_Text)val8).fontSize = 13f;
((Graphic)val8).color = Color.white;
((TMP_Text)val8).alignment = (TextAlignmentOptions)4097;
((Graphic)val8).raycastTarget = false;
val2.textViewport = val4;
val2.textComponent = (TMP_Text)(object)val8;
val2.placeholder = (Graphic)(object)val6;
if (isPassword)
{
val2.contentType = (ContentType)7;
val2.inputType = (InputType)2;
}
else
{
val2.contentType = (ContentType)0;
}
return val2;
}
private static Button CreateButton(Transform parent, string label, Color bgColor, float width)
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
//IL_0011: Expected O, but got Unknown
//IL_003d: 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_0052: Unknown result type (might be due to invalid IL or missing references)
//IL_005a: Unknown result type (might be due to invalid IL or missing references)
//IL_0060: Unknown result type (might be due to invalid IL or missing references)
//IL_006c: Unknown result type (might be due to invalid IL or missing references)
//IL_0072: Unknown result type (might be due to invalid IL or missing references)
//IL_008d: Unknown result type (might be due to invalid IL or missing references)
//IL_0098: Unknown result type (might be due to invalid IL or missing references)
//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
//IL_00af: Unknown result type (might be due to invalid IL or missing references)
//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
//IL_00de: Unknown result type (might be due to invalid IL or missing references)
//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
//IL_011c: Unknown result type (might be due to invalid IL or missing references)
GameObject val = new GameObject("Btn_" + label);
val.transform.SetParent(parent, false);
LayoutElement obj = val.AddComponent<LayoutElement>();
obj.preferredWidth = width;
obj.preferredHeight = 28f;
Image val2 = val.AddComponent<Image>();
((Graphic)val2).color = bgColor;
Button obj2 = val.AddComponent<Button>();
ColorBlock colors = ((Selectable)obj2).colors;
((ColorBlock)(ref colors)).normalColor = bgColor;
((ColorBlock)(ref colors)).highlightedColor = bgColor * 1.25f;
((ColorBlock)(ref colors)).pressedColor = bgColor * 0.75f;
((ColorBlock)(ref colors)).disabledColor = new Color(0.35f, 0.35f, 0.35f);
((Selectable)obj2).colors = colors;
((Selectable)obj2).targetGraphic = (Graphic)(object)val2;
GameObject val3 = new GameObject("Text");
val3.transform.SetParent(val.transform, false);
RectTransform obj3 = val3.AddComponent<RectTransform>();
obj3.anchorMin = Vector2.zero;
obj3.anchorMax = Vector2.one;
obj3.offsetMin = Vector2.zero;
obj3.offsetMax = Vector2.zero;
TextMeshProUGUI obj4 = val3.AddComponent<TextMeshProUGUI>();
((TMP_Text)obj4).text = label;
((TMP_Text)obj4).fontSize = 13f;
((TMP_Text)obj4).fontStyle = (FontStyles)1;
((TMP_Text)obj4).alignment = (TextAlignmentOptions)514;
((Graphic)obj4).color = Color.white;
((Graphic)obj4).raycastTarget = false;
return obj2;
}
}
internal class APNotificationDriver : MonoBehaviour
{
[CompilerGenerated]
private sealed class <AnimateRoutine>d__2 : IEnumerator<object>, IEnumerator, IDisposable
{
private int <>1__state;
private object <>2__current;
public APNotificationDriver <>4__this;
public string line2;
public string line1;
public float duration;
private float <elapsed>5__2;
object IEnumerator<object>.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
object IEnumerator.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
[DebuggerHidden]
public <AnimateRoutine>d__2(int <>1__state)
{
this.<>1__state = <>1__state;
}
[DebuggerHidden]
void IDisposable.Dispose()
{
<>1__state = -2;
}
private bool MoveNext()
{
//IL_00c7: 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_00d3: Unknown result type (might be due to invalid IL or missing references)
//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
//IL_00df: Unknown result type (might be due to invalid IL or missing references)
//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
//IL_0130: Unknown result type (might be due to invalid IL or missing references)
//IL_0140: Unknown result type (might be due to invalid IL or missing references)
//IL_0150: Unknown result type (might be due to invalid IL or missing references)
//IL_015f: Unknown result type (might be due to invalid IL or missing references)
//IL_0188: Unknown result type (might be due to invalid IL or missing references)
//IL_0192: Expected O, but got Unknown
//IL_01c7: Unknown result type (might be due to invalid IL or missing references)
//IL_01cc: Unknown result type (might be due to invalid IL or missing references)
//IL_01d4: Unknown result type (might be due to invalid IL or missing references)
//IL_01db: Unknown result type (might be due to invalid IL or missing references)
//IL_01e2: Unknown result type (might be due to invalid IL or missing references)
//IL_0200: Unknown result type (might be due to invalid IL or missing references)
//IL_008c: Unknown result type (might be due to invalid IL or missing references)
int num = <>1__state;
APNotificationDriver aPNotificationDriver = <>4__this;
float num2;
switch (num)
{
default:
return false;
case 0:
<>1__state = -1;
if (aPNotificationDriver.label == null)
{
return false;
}
((TMP_Text)aPNotificationDriver.label).text = (string.IsNullOrEmpty(line2) ? line1 : (line1 + "\n<size=70%>" + line2 + "</size>"));
((Graphic)aPNotificationDriver.label).color = new Color(1f, 0.92f, 0.016f, 0f);
((Behaviour)aPNotificationDriver.label).enabled = true;
<elapsed>5__2 = 0f;
goto IL_0117;
case 1:
<>1__state = -1;
goto IL_0117;
case 2:
<>1__state = -1;
<elapsed>5__2 = 0f;
break;
case 3:
{
<>1__state = -1;
break;
}
IL_0117:
if (<elapsed>5__2 < 0.3f)
{
<elapsed>5__2 += Time.deltaTime;
Color color = ((Graphic)aPNotificationDriver.label).color;
((Graphic)aPNotificationDriver.label).color = new Color(color.r, color.g, color.b, Mathf.Clamp01(<elapsed>5__2 / 0.3f));
<>2__current = null;
<>1__state = 1;
return true;
}
((Graphic)aPNotificationDriver.label).color = new Color(((Graphic)aPNotificationDriver.label).color.r, ((Graphic)aPNotificationDriver.label).color.g, ((Graphic)aPNotificationDriver.label).color.b, 1f);
num2 = Mathf.Max(0f, duration - 0.3f - 0.6f);
<>2__current = (object)new WaitForSeconds(num2);
<>1__state = 2;
return true;
}
if (<elapsed>5__2 < 0.6f)
{
<elapsed>5__2 += Time.deltaTime;
Color color2 = ((Graphic)aPNotificationDriver.label).color;
((Graphic)aPNotificationDriver.label).color = new Color(color2.r, color2.g, color2.b, Mathf.Clamp01(1f - <elapsed>5__2 / 0.6f));
<>2__current = null;
<>1__state = 3;
return true;
}
Object.Destroy((Object)(object)((Component)aPNotificationDriver).gameObject);
return false;
}
bool IEnumerator.MoveNext()
{
//ILSpy generated this explicit interface implementation from .override directive in MoveNext
return this.MoveNext();
}
[DebuggerHidden]
void IEnumerator.Reset()
{
throw new NotSupportedException();
}
}
internal TextMeshProUGUI label;
internal void Show(string line1, string line2, float duration = 3.5f)
{
((MonoBehaviour)this).StartCoroutine(AnimateRoutine(line1, line2, duration));
}
[IteratorStateMachine(typeof(<AnimateRoutine>d__2))]
private IEnumerator AnimateRoutine(string line1, string line2, float duration)
{
//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
return new <AnimateRoutine>d__2(0)
{
<>4__this = this,
line1 = line1,
line2 = line2,
duration = duration
};
}
}
public static class APNotificationUI
{
private const float Duration = 3.5f;
public static void ShowItemReceived(string itemName, string senderName = "")
{
string text = "Received: " + itemName;
string text2 = (string.IsNullOrEmpty(senderName) ? "" : ("from " + senderName));
try
{
UserInterface.ShowMoneyNotification(text, text2, (MoneyCellType)2);
}
catch (Exception ex)
{
Plugin.Logger.LogWarning((object)("[APNotif] ShowMoneyNotification (MetaCoins) failed: " + ex.Message + " — using fallback label."));
SpawnHUDLabel(text, text2);
}
}
public static void ShowLocationFound(string locationName)
{
try
{
UserInterface.ShowMoneyNotification("Location Found!", locationName, (MoneyCellType)1);
}
catch (Exception ex)
{
Plugin.Logger.LogWarning((object)("[APNotif] ShowMoneyNotification (Revenue) failed: " + ex.Message + " — using fallback label."));
SpawnHUDLabel("Location Found!", locationName);
}
}
public static void ShowMoneyReceived(string displayLabel, int amount, MoneyCellType cellType)
{
//IL_0008: Unknown result type (might be due to invalid IL or missing references)
try
{
UserInterface.ShowMoneyNotification(displayLabel, amount.ToString(), cellType);
}
catch (Exception ex)
{
Plugin.Logger.LogWarning((object)("[APNotif] UserInterface.ShowMoneyNotification failed: " + ex.Message));
SpawnHUDLabel("[AP] Currency Received!", $"+{amount} {displayLabel}");
}
}
private static void SpawnHUDLabel(string line1, string line2)
{
//IL_002e: Unknown result type (might be due to invalid IL or missing references)
//IL_0033: Unknown result type (might be due to invalid IL or missing references)
//IL_0045: Unknown result type (might be due to invalid IL or missing references)
//IL_0056: Unknown result type (might be due to invalid IL or missing references)
//IL_006b: Unknown result type (might be due to invalid IL or missing references)
//IL_0080: Unknown result type (might be due to invalid IL or missing references)
//IL_0095: Unknown result type (might be due to invalid IL or missing references)
//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
try
{
Canvas val = FindHUDCanvas();
if (val == null)
{
Plugin.Logger.LogDebug((object)("[APNotif] No HUD canvas — logging instead: " + line1 + " | " + line2));
return;
}
GameObject val2 = new GameObject("AP_Notification");
val2.transform.SetParent(((Component)val).transform, false);
RectTransform obj = val2.AddComponent<RectTransform>();
obj.anchorMin = new Vector2(0.5f, 1f);
obj.anchorMax = new Vector2(0.5f, 1f);
obj.pivot = new Vector2(0.5f, 1f);
obj.anchoredPosition = new Vector2(0f, -120f);
obj.sizeDelta = new Vector2(700f, 80f);
TextMeshProUGUI val3 = val2.AddComponent<TextMeshProUGUI>();
((TMP_Text)val3).alignment = (TextAlignmentOptions)514;
((TMP_Text)val3).fontSize = 26f;
((TMP_Text)val3).fontStyle = (FontStyles)1;
((Graphic)val3).raycastTarget = false;
((Behaviour)val3).enabled = false;
APNotificationDriver aPNotificationDriver = val2.AddComponent<APNotificationDriver>();
aPNotificationDriver.label = val3;
aPNotificationDriver.Show(line1, line2);
}
catch (Exception ex)
{
Plugin.Logger.LogWarning((object)("[APNotif] SpawnHUDLabel failed: " + ex.Message));
}
}
private static Canvas FindHUDCanvas()
{
//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
if (Player.localPlayer != null)
{
string[] array = new string[4] { "HUD", "PlayerHUD", "Canvas_HUD", "UI" };
foreach (string text in array)
{
Transform val = ((Component)Player.localPlayer).transform.Find(text);
if (val != null)
{
Canvas component = ((Component)val).GetComponent<Canvas>();
if (component != null)
{
return component;
}
}
}
}
Canvas[] array2 = Object.FindObjectsOfType<Canvas>();
Canvas[] array3 = array2;
foreach (Canvas val2 in array3)
{
string text2 = ((Object)val2).name.ToLowerInvariant();
if (text2.Contains("hud") || text2.Contains("playerhud"))
{
return val2;
}
}
array3 = array2;
foreach (Canvas val3 in array3)
{
if ((int)val3.renderMode == 0)
{
return val3;
}
}
return null;
}
}
}
namespace ContentWarningArchipelago.Patches
{
[HarmonyPatch]
internal static class ChorbySpawnPatch
{
private static object? _chorbyItem;
private static MethodBase? TargetMethod()
{
Type type = AccessTools.TypeByName("RoundArtifactSpawner");
if (type == null)
{
Plugin.Logger.LogWarning((object)"[ChorbySpawnPatch] RoundArtifactSpawner type not found — Chorby spawn-cap disabled.");
return null;
}
MethodInfo methodInfo = AccessTools.Method(type, "GetArtifactsToSpawn", (Type[])null, (Type[])null);
if (methodInfo == null)
{
Plugin.Logger.LogWarning((object)"[ChorbySpawnPatch] GetArtifactsToSpawn method not found — Chorby spawn-cap disabled.");
return null;
}
Plugin.Logger.LogInfo((object)("[ChorbySpawnPatch] Patching " + type.Name + "." + methodInfo.Name));
return methodInfo;
}
[HarmonyPostfix]
private static void Postfix(object __instance, object __result)
{
try
{
if (!(__result is IList list))
{
Plugin.Logger.LogWarning((object)"[ChorbySpawnPatch] GetArtifactsToSpawn returned a non-IList — Chorby skipped this dive.");
return;
}
if (_chorbyItem == null)
{
_chorbyItem = ResolveChorby(__instance);
}
if (_chorbyItem == null)
{
Plugin.Logger.LogWarning((object)"[ChorbySpawnPatch] Chorby Item not found in possibleSpawns — Chorby skipped this dive.");
return;
}
int num = 0;
for (int num2 = list.Count - 1; num2 >= 0; num2--)
{
if (list[num2] == _chorbyItem)
{
list.RemoveAt(num2);
num++;
}
}
list.Insert(0, _chorbyItem);
Plugin.Logger.LogInfo((object)("[ChorbySpawnPatch] Forced 1 Chorby into the artifact list " + string.Format("(removed {0} vanilla pick{1}, ", num, (num == 1) ? "" : "s") + $"final count={list.Count})."));
}
catch (Exception arg)
{
Plugin.Logger.LogError((object)$"[ChorbySpawnPatch] Postfix failed: {arg}");
}
}
private static object? ResolveChorby(object spawnerInstance)
{
FieldInfo fieldInfo = AccessTools.Field(spawnerInstance.GetType(), "possibleSpawns");
if (fieldInfo == null)
{
return null;
}
if (!(fieldInfo.GetValue(spawnerInstance) is IEnumerable enumerable))
{
return null;
}
foreach (object item in enumerable)
{
Object val = (Object)((item is Object) ? item : null);
if (val != null && string.Equals(val.name, "Chorby", StringComparison.Ordinal))
{
return item;
}
}
return null;
}
}
[HarmonyPatch]
internal static class ChorbyPickupPatch
{
private static MethodBase? TargetMethod()
{
Type type = AccessTools.TypeByName("Pickup");
if (type == null)
{
Plugin.Logger.LogWarning((object)"[ChorbyPickupPatch] Pickup type not found — Chorby pickup intercept disabled.");
return null;
}
MethodInfo methodInfo = AccessTools.Method(type, "RPC_RequestPickup", (Type[])null, (Type[])null);
if (methodInfo == null)
{
Plugin.Logger.LogWarning((object)"[ChorbyPickupPatch] Pickup.RPC_RequestPickup not found — Chorby pickup intercept disabled.");
return null;
}
Plugin.Logger.LogInfo((object)("[ChorbyPickupPatch] Patching " + type.Name + "." + methodInfo.Name));
return methodInfo;
}
[HarmonyPrefix]
private static bool Prefix(object __instance)
{
try
{
if (!IsChorby(__instance, out string itemName))
{
return true;
}
if (!PhotonNetwork.IsMasterClient)
{
Plugin.Logger.LogDebug((object)"[ChorbyPickupPatch] Non-master client received RPC_RequestPickup — letting vanilla handle it.");
return true;
}
Plugin.Logger.LogInfo((object)("[ChorbyPickupPatch] Chorby pickup intercepted (" + itemName + ")."));
if (Plugin.connection.connected && APSave.saveData.chorbiesFound >= APSave.saveData.quotaCount)
{
if (!APSave.saveData.allChorbyChecksFoundNotified)
{
BroadcastAllChorbyChecksFound();
APSave.saveData.allChorbyChecksFoundNotified = true;
APSave.Flush();
}
DestroyPickup(__instance);
return false;
}
if (Plugin.connection.connected)
{
APSave.saveData.chorbiesFound++;
int chorbiesFound = APSave.saveData.chorbiesFound;
string text = "Found Chorby " + chorbiesFound;
long id = LocationData.GetId(text);
if (id > 0)
{
Plugin.Logger.LogInfo((object)$"[ChorbyPickupPatch] Chorby #{chorbiesFound} picked up → {text}");
Plugin.SendCheck(id);
}
else
{
Plugin.Logger.LogDebug((object)$"[ChorbyPickupPatch] Chorby #{chorbiesFound} above the 21-check ceiling — no AP check sent.");
}
APSave.Flush();
}
DestroyPickup(__instance);
return false;
}
catch (Exception arg)
{
Plugin.Logger.LogError((object)$"[ChorbyPickupPatch] Prefix failed: {arg}");
return true;
}
}
private static bool IsChorby(object pickupInstance, out string itemName)
{
itemName = string.Empty;
FieldInfo fieldInfo = AccessTools.Field(pickupInstance.GetType(), "m_itemID");
if (fieldInfo == null)
{
return false;
}
if (!(fieldInfo.GetValue(pickupInstance) is byte b))
{
return false;
}
Type type = AccessTools.TypeByName("ItemDatabase");
MethodInfo methodInfo = ((type != null) ? AccessTools.Method(type, "TryGetItemFromID", (Type[])null, (Type[])null) : null);
if (methodInfo == null)
{
return false;
}
object[] array = new object[2] { b, null };
if ((bool)(methodInfo.Invoke(null, array) ?? ((object)false)))
{
object obj = array[1];
Object val = (Object)((obj is Object) ? obj : null);
if (val != null)
{
itemName = val.name ?? string.Empty;
return string.Equals(itemName, "Chorby", StringComparison.Ordinal);
}
}
return false;
}
private static void DestroyPickup(object pickupInstance)
{
try
{
object? obj = AccessTools.Field(pickupInstance.GetType(), "m_photonView")?.GetValue(pickupInstance);
PhotonView val = (PhotonView)((obj is PhotonView) ? obj : null);
if (val != null)
{
val.RPC("RPC_Remove", (RpcTarget)2, Array.Empty<object>());
}
}
catch (Exception ex)
{
Plugin.Logger.LogWarning((object)("[ChorbyPickupPatch] DestroyPickup failed: " + ex.Message));
}
}
private static void BroadcastAllChorbyChecksFound()
{
string text = "All Chorby checks found";
APNotificationUI.ShowLocationFound(text);
Plugin.Logger.LogInfo((object)("[ChorbyPickupPatch] " + text + " (post-quota Chorby pickup)."));
if (PhotonNetwork.InRoom && PhotonNetwork.CurrentRoom.PlayerCount > 1)
{
try
{
MyceliumNetwork.RPC(2718281828u, "LocationFound", (ReliableType)1, new object[1] { text });
}
catch (Exception ex)
{
Plugin.Logger.LogWarning((object)("[ChorbyPickupPatch] Mycelium broadcast failed: " + ex.Message));
}
}
}
}
[HarmonyPatch(typeof(DivingBellSuitCellUI))]
internal static class DivingBellAPStatusPatch
{
internal static string LastItemName = "";
[HarmonyPostfix]
[HarmonyPatch("Set")]
private static void Set(Player player, float dst, DivingBellSuitCellUI __instance)
{
if (!player.IsLocal)
{
return;
}
try
{
bool connected = Plugin.connection.connected;
string text = (connected ? "<size=70%><color=#00FF88>[AP] Connected</color></size>" : "<size=70%><color=#FF4444>[AP] Disconnected</color></size>");
if (connected && !string.IsNullOrEmpty(LastItemName))
{
text = text + "\n<size=60%>Last item: " + LastItemName + "</size>";
}
if (connected)
{
APSaveData saveData = APSave.saveData;
if (saveData.viewsChecks || saveData.viewsGoal || saveData.viralSensationGoal)
{
text += $"\n<size=60%>Lifetime views: {saveData.lifetimeViews:N0}";
if (saveData.viewsGoal && saveData.viewsGoalTarget > 0)
{
text += $" / {saveData.viewsGoalTarget:N0}";
}
text += "</size>";
if (saveData.viralSensationGoal)
{
text += $"\n<size=60%>This quota: {saveData.currentQuotaViews:N0} / 1,000,000</size>";
}
}
}
string text2 = ((TMP_Text)__instance.m_oxygenText).text;
int num = text2.IndexOf("\n<size=70%><color=#");
if (num >= 0)
{
text2 = text2.Substring(0, num);
}
((TMP_Text)__instance.m_oxygenText).text = text2 + "\n" + text;
}
catch (Exception ex)
{
Plugin.Logger.LogDebug((object)("[DiveBellAPStatus] Postfix exception: " + ex.Message));
}
}
}
[HarmonyPatch(typeof(Player), "Update")]
internal static class DivingBellRechargePatch
{
private const float ChargeRatePerSecond = 0.05f;
[HarmonyPostfix]
private static void Postfix(Player __instance)
{
//IL_0064: Unknown result type (might be due to invalid IL or missing references)
//IL_007b: Unknown result type (might be due to invalid IL or missing references)
//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
PlayerInventory val = default(PlayerInventory);
if (!__instance.IsLocal || !Plugin.connection.connected || !APSave.saveData.diveBellChargerUnlocked || !__instance.data.isInDiveBell || !__instance.TryGetInventory(ref val))
{
return;
}
float num = 0.05f * Time.deltaTime;
InventorySlot[] slots = val.slots;
BatteryEntry val3 = default(BatteryEntry);
foreach (InventorySlot val2 in slots)
{
if (val2 != null && !((Object)(object)val2.ItemInSlot.item == (Object)null))
{
ItemInstanceData data = val2.ItemInSlot.data;
if (data != null && data.TryGetEntry<BatteryEntry>(ref val3) && !(val3.m_maxCharge <= val3.m_charge))
{
val3.AddCharge(num * val3.m_maxCharge);
Plugin.Logger.LogDebug((object)("[DiveBellCharger] Charged " + ((Object)val2.ItemInSlot.item).name + ": " + $"{val3.m_charge:F1}/{val3.m_maxCharge:F1} " + $"({val3.GetPercentage() * 100f:F0}%)"));
}
}
}
}
}
[HarmonyPatch(typeof(HatShop), "RPCA_StockShop")]
internal static class HatShopFixedSeedPatch
{
[HarmonyPrefix]
private static void Prefix(ref int seed)
{
if (Plugin.connection.connected)
{
ArchipelagoSession? session = Plugin.connection.session;
string text = ((session != null) ? session.RoomState.Seed : null);
if (!string.IsNullOrEmpty(text))
{
int num = TryGetCurrentDay();
seed = $"{text}:{num}".GetHashCode();
Plugin.Logger.LogInfo((object)("[HatShopFixedSeedPatch] Hat shop seed overridden " + $"(apSeed + day {num}): {seed}"));
}
}
}
private static int TryGetCurrentDay()
{
Type type = AccessTools.TypeByName("GameAPI");
if (type != null)
{
PropertyInfo propertyInfo = AccessTools.Property(type, "CurrentDay");
if (propertyInfo != null && propertyInfo.GetValue(null) is int num && num > 0)
{
return num;
}
}
Type type2 = AccessTools.TypeByName("SurfaceNetworkHandler");
if (type2 != null)
{
PropertyInfo propertyInfo2 = AccessTools.Property(type2, "RoomStats");
if (propertyInfo2 != null)
{
object value = propertyInfo2.GetValue(null);
if (value != null)
{
PropertyInfo propertyInfo3 = AccessTools.Property(value.GetType(), "CurrentDay");
if (propertyInfo3 != null && propertyInfo3.GetValue(value) is int num2 && num2 > 0)
{
return num2;
}
}
}
}
return 0;
}
}
[HarmonyPatch(typeof(HatShop), "Restock")]
internal static class HatShopFilterRestockPatch
{
[HarmonyPrefix]
private static bool Prefix(HatShop __instance)
{
//IL_0227: Unknown result type (might be due to invalid IL or missing references)
//IL_005f: Unknown result type (might be due to invalid IL or missing references)
//IL_0064: Unknown result type (might be due to invalid IL or missing references)
if (!Plugin.connection.connected)
{
return true;
}
if ((Object)(object)HatDatabase.instance == (Object)null || HatDatabase.instance.hats == null)
{
return true;
}
FieldInfo fieldInfo = AccessTools.Field(typeof(HatShop), "savedSeed");
if (fieldInfo == null)
{
return true;
}
int num = (int)(fieldInfo.GetValue(__instance) ?? ((object)0));
State state = Random.state;
Random.InitState(num);
try
{
ArchipelagoSession? session = Plugin.connection.session;
ReadOnlyCollection<long> checkedLocs = ((session != null) ? session.Locations.AllLocationsChecked : null);
List<Hat> list = new List<Hat>();
Hat[] hats = HatDatabase.instance.hats;
foreach (Hat val in hats)
{
if (!((Object)(object)val == (Object)null) && !IsHatLocationChecked(val, checkedLocs))
{
list.Add(val);
}
}
int count = __instance.hatBuyInteractables.Count;
int num2 = Math.Min(count, list.Count);
List<Hat> list2 = ((num2 > 0) ? ExtCollections.GetRandomNoDuplicates<Hat>((IEnumerable<Hat>)list, num2) : new List<Hat>());
for (int j = 0; j < count; j++)
{
HatBuyInteractable val2 = __instance.hatBuyInteractables[j];
if ((Object)(object)val2 == (Object)null)
{
continue;
}
if (j < list2.Count)
{
Hat val3 = list2[j];
int num3 = Mathf.RoundToInt((float)val3.GetBasePrice() * Random.Range(0.5f, 2f) / 10f) * 10;
val2.LoadHat(((Component)val3).gameObject, num3);
continue;
}
val2.ClearHat();
if ((Object)(object)val2.nameText != (Object)null)
{
((TMP_Text)val2.nameText).text = string.Empty;
}
if ((Object)(object)val2.priceText != (Object)null)
{
((TMP_Text)val2.priceText).text = string.Empty;
}
}
Plugin.Logger.LogInfo((object)("[HatShopFilterRestockPatch] Filtered restock: " + $"{num2}/{count} slots filled, " + $"{list.Count} unbought hats in pool."));
}
catch (Exception arg)
{
Plugin.Logger.LogError((object)$"[HatShopFilterRestockPatch] Exception: {arg}");
}
finally
{
Random.state = state;
}
return false;
}
private static bool IsHatLocationChecked(Hat hat, IReadOnlyCollection<long>? checkedLocs)
{
if (checkedLocs == null || checkedLocs.Count == 0)
{
return false;
}
string text = null;
if (!string.IsNullOrEmpty(hat.displayName) && HatShopAPLabelPatch.HatNameToLocation.TryGetValue(hat.displayName, out string value))
{
text = value;
}
else
{
string name = hat.GetName();
if (!string.IsNullOrEmpty(name) && HatShopAPLabelPatch.HatNameToLocation.TryGetValue(name, out string value2))
{
text = value2;
}
}
if (string.IsNullOrEmpty(text))
{
return false;
}
long id = LocationData.GetId(text);
if (id < 0)
{
return false;
}
return checkedLocs.Contains(id);
}
}
[HarmonyPatch(typeof(HatShop), "Restock")]
internal static class HatShopAPLabelPatch
{
internal static readonly Dictionary<string, string> HatNameToLocation = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
{
{ "Beanie", "Bought Beanie" },
{ "Bucket Hat", "Bought Bucket Hat" },
{ "Floppy Hat", "Bought Floppy Hat" },
{ "Homburg", "Bought Homburg" },
{ "Bowler Hat", "Bought Bowler Hat" },
{ "Cap", "Bought Cap" },
{ "News Cap", "Bought News Cap" },
{ "Newsboy Cap", "Bought News Cap" },
{ "Sports Helmet", "Bought Sports Helmet" },
{ "Hard Hat", "Bought Hard Hat" },
{ "Chefs Hat", "Bought Chefs Hat" },
{ "Chef's Hat", "Bought Chefs Hat" },
{ "Propeller Hat", "Bought Propeller Hat" },
{ "Cowboy Hat", "Bought Cowboy Hat" },
{ "Horns", "Bought Horns" },
{ "Hotdog Hat", "Bought Hotdog Hat" },
{ "Hot Dog Hat", "Bought Hotdog Hat" },
{ "Milk Hat", "Bought Milk Hat" },
{ "Pirate Hat", "Bought Pirate Hat" },
{ "Top Hat", "Bought Top Hat" },
{ "Party Hat", "Bought Party Hat" },
{ "Ushanka", "Bought Ushanka" },
{ "Balaclava", "Bought Balaclava" },
{ "Cat Ears", "Bought Cat Ears" },
{ "Curly Hair", "Bought Curly Hair" },
{ "Clown Hair", "Bought Clown Hair" },
{ "Crown", "Bought Crown" },
{ "Halo", "Bought Halo" },
{ "Jesters Hat", "Bought Jesters Hat" },
{ "Jester's Hat", "Bought Jesters Hat" },
{ "Ghost Hat", "Bought Ghost Hat" },
{ "Tooop Hat", "Bought Tooop Hat" },
{ "Shroom Hat", "Bought Shroom Hat" },
{ "Witch Hat", "Bought Witch Hat" },
{ "Savannah Hair", "Bought Savannah Hair" }
};
[HarmonyPostfix]
private static void Postfix(HatShop __instance)
{
if (Plugin.connection.connected && PhotonNetwork.IsMasterClient)
{
(((Component)__instance).GetComponent<HatShopAPSyncBehaviour>() ?? ((Component)__instance).gameObject.AddComponent<HatShopAPSyncBehaviour>()).LaunchScout(__instance);
}
}
}
internal static class HatShopRestockLabelPatch
{
internal static readonly Dictionary<HatBuyInteractable, string> ScoutedNames = new Dictionary<HatBuyInteractable, string>();
internal static readonly Dictionary<HatBuyInteractable, string> ScoutedAPItemNames = new Dictionary<HatBuyInteractable, string>();
}
internal class HatShopAPSyncBehaviour : MonoBehaviour
{
[CompilerGenerated]
private sealed class <ScoutAndLabelCoroutine>d__7 : IEnumerator<object>, IEnumerator, IDisposable
{
private int <>1__state;
private object <>2__current;
public HatShop hatShop;
private Dictionary<HatBuyInteractable, long> <slotToLocId>5__2;
private Task<Dictionary<long, string>> <scoutTask>5__3;
object IEnumerator<object>.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
object IEnumerator.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
[DebuggerHidden]
public <ScoutAndLabelCoroutine>d__7(int <>1__state)
{
this.<>1__state = <>1__state;
}
[DebuggerHidden]
void IDisposable.Dispose()
{
<slotToLocId>5__2 = null;
<scoutTask>5__3 = null;
<>1__state = -2;
}
private bool MoveNext()
{
switch (<>1__state)
{
default:
return false;
case 0:
{
<>1__state = -1;
<slotToLocId>5__2 = new Dictionary<HatBuyInteractable, long>();
List<long> list = new List<long>();
foreach (HatBuyInteractable hatBuyInteractable in hatShop.hatBuyInteractables)
{
if ((Object)(object)hatBuyInteractable == (Object)null || hatBuyInteractable.IsEmpty || (Object)(object)hatBuyInteractable.ihat == (Object)null)
{
continue;
}
string text = ResolveLocationName(hatBuyInteractable.ihat);
if (text != null)
{
long id = LocationData.GetId(text);
if (id < 0)
{
Plugin.Logger.LogDebug((object)("[HatShopAPSyncBehaviour] '" + text + "' not in LocationData table."));
continue;
}
<slotToLocId>5__2[hatBuyInteractable] = id;
list.Add(id);
}
}
if (list.Count == 0)
{
Plugin.Logger.LogDebug((object)"[HatShopAPSyncBehaviour] No valid hat AP locations to scout.");
return false;
}
Plugin.Logger.LogInfo((object)$"[HatShopAPSyncBehaviour] Scouting {list.Count} hat location(s)…");
<scoutTask>5__3 = Plugin.connection.ScoutLocationsAsync(list);
break;
}
case 1:
<>1__state = -1;
break;
}
if (!<scoutTask>5__3.IsCompleted)
{
<>2__current = null;
<>1__state = 1;
return true;
}
Dictionary<long, string> dictionary;
try
{
dictionary = <scoutTask>5__3.Result ?? new Dictionary<long, string>();
}
catch (Exception ex)
{
Plugin.Logger.LogWarning((object)("[HatShopAPSyncBehaviour] Scout task threw: " + ex.Message));
return false;
}
HatShopRestockLabelPatch.ScoutedNames.Clear();
HatShopRestockLabelPatch.ScoutedAPItemNames.Clear();
string[] array = new string[hatShop.hatBuyInteractables.Count];
for (int i = 0; i < hatShop.hatBuyInteractables.Count; i++)
{
HatBuyInteractable val = hatShop.hatBuyInteractables[i];
array[i] = string.Empty;
if (!((Object)(object)val == (Object)null) && !val.IsEmpty && !((Object)(object)val.ihat == (Object)null) && <slotToLocId>5__2.TryGetValue(val, out var value) && dictionary.TryGetValue(value, out var value2) && !string.IsNullOrEmpty(value2))
{
string name = val.ihat.GetName();
string text2 = name + " [" + value2 + "]";
if ((Object)(object)val.nameText != (Object)null)
{
((TMP_Text)val.nameText).text = text2;
ApplyAutoSizing(val.nameText);
}
HatShopRestockLabelPatch.ScoutedNames[val] = text2;
HatShopRestockLabelPatch.ScoutedAPItemNames[val] = value2;
array[i] = text2;
Plugin.Logger.LogInfo((object)$"[HatShopAPSyncBehaviour] Labelled slot {i}: '{name}' → '{value2}'");
}
}
Plugin.Logger.LogInfo((object)$"[HatShopAPSyncBehaviour] Applied {HatShopRestockLabelPatch.ScoutedNames.Count} label(s).");
if (PhotonNetwork.CurrentRoom != null && PhotonNetwork.CurrentRoom.PlayerCount > 1)
{
PhotonView component = ((Component)hatShop).GetComponent<PhotonView>();
if ((Object)(object)component != (Object)null)
{
component.RPC("RPCA_SyncArchipelagoLabels", (RpcTarget)1, new object[1] { array });
Plugin.Logger.LogInfo((object)"[HatShopAPSyncBehaviour] Broadcast hat labels to other clients.");
}
else
{
Plugin.Logger.LogWarning((object)"[HatShopAPSyncBehaviour] HatShop has no PhotonView — cannot broadcast labels.");
}
}
return false;
}
bool IEnumerator.MoveNext()
{
//ILSpy generated this explicit interface implementation from .override directive in MoveNext
return this.MoveNext();
}
[DebuggerHidden]
void IEnumerator.Reset()
{
throw new NotSupportedException();
}
}
internal static HatShopAPSyncBehaviour? Instance { get; private set; }
private void Awake()
{
Instance = this;
}
private void OnDestroy()
{
if ((Object)(object)Instance == (Object)(object)this)
{
Instance = null;
}
}
internal void LaunchScout(HatShop hatShop)
{
((MonoBehaviour)this).StopAllCoroutines();
((MonoBehaviour)this).StartCoroutine(ScoutAndLabelCoroutine(hatShop));
}
[IteratorStateMachine(typeof(<ScoutAndLabelCoroutine>d__7))]
private IEnumerator ScoutAndLabelCoroutine(HatShop hatShop)
{
//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
return new <ScoutAndLabelCoroutine>d__7(0)
{
hatShop = hatShop
};
}
[PunRPC]
public void RPCA_SyncArchipelagoLabels(string[] labels)
{
if ((Object)(object)HatShop.instance == (Object)null)
{
Plugin.Logger.LogWarning((object)"[HatShopAPSyncBehaviour] RPCA_SyncArchipelagoLabels: HatShop.instance is null.");
return;
}
List<HatBuyInteractable> hatBuyInteractables = HatShop.instance.hatBuyInteractables;
for (int i = 0; i < labels.Length && i < hatBuyInteractables.Count; i++)
{
string text = labels[i];
if (string.IsNullOrEmpty(text))
{
continue;
}
HatBuyInteractable val = hatBuyInteractables[i];
if ((Object)(object)val == (Object)null || val.IsEmpty || (Object)(object)val.ihat == (Object)null)
{
continue;
}
if ((Object)(object)val.nameText != (Object)null)
{
((TMP_Text)val.nameText).text = text;
ApplyAutoSizing(val.nameText);
}
HatShopRestockLabelPatch.ScoutedNames[val] = text;
int num = text.LastIndexOf('[');
int num2 = text.LastIndexOf(']');
if (num >= 0 && num2 > num)
{
string value = text.Substring(num + 1, num2 - num - 1);
if (!string.IsNullOrEmpty(value))
{
HatShopRestockLabelPatch.ScoutedAPItemNames[val] = value;
}
}
}
Plugin.Logger.LogInfo((object)$"[HatShopAPSyncBehaviour] RPCA_SyncArchipelagoLabels: applied {labels.Length} label(s).");
}
private static void ApplyAutoSizing(TextMeshPro tmp)
{
if (!((Object)(object)tmp == (Object)null))
{
((TMP_Text)tmp).enableWordWrapping = true;
((TMP_Text)tmp).enableAutoSizing = true;
((TMP_Text)tmp).fontSizeMax = Mathf.Max(((TMP_Text)tmp).fontSize, (((TMP_Text)tmp).fontSizeMax > 0f) ? ((TMP_Text)tmp).fontSizeMax : ((TMP_Text)tmp).fontSize);
((TMP_Text)tmp).fontSizeMin = 8f;
((TMP_Text)tmp).overflowMode = (TextOverflowModes)3;
}
}
private static string? ResolveLocationName(Hat hat)
{
if (!string.IsNullOrEmpty(hat.displayName) && HatShopAPLabelPatch.HatNameToLocation.TryGetValue(hat.displayName, out string value))
{
return value;
}
string name = hat.GetName();
if (!string.IsNullOrEmpty(name) && HatShopAPLabelPatch.HatNameToLocation.TryGetValue(name, out string value2))
{
return value2;
}
Plugin.Logger.LogDebug((object)("[HatShopAPSyncBehaviour] No location mapping for hat displayName='" + hat.displayName + "' / GetName()='" + hat.GetName() + "'."));
return null;
}
}
[HarmonyPatch(typeof(HatShop), "RPCA_BuyHat")]
internal static class HatShopBuyAPCheckPatch
{
[HarmonyPrefix]
private static void Prefix(HatShop __instance, int hatBuyIndex)
{
if (!Plugin.connection.connected || !PhotonNetwork.IsMasterClient)
{
return;
}
try
{
if (hatBuyIndex < 0 || hatBuyIndex >= __instance.hatBuyInteractables.Count)
{
return;
}
HatBuyInteractable val = __instance.hatBuyInteractables[hatBuyIndex];
if ((Object)(object)val == (Object)null || val.IsEmpty || (Object)(object)val.ihat == (Object)null)
{
return;
}
string text = null;
if (!string.IsNullOrEmpty(val.ihat.displayName) && HatShopAPLabelPatch.HatNameToLocation.TryGetValue(val.ihat.displayName, out string value))
{
text = value;
}
else
{
string name = val.ihat.GetName();
if (!string.IsNullOrEmpty(name) && HatShopAPLabelPatch.HatNameToLocation.TryGetValue(name, out string value2))
{
text = value2;
}
}
if (text == null)
{
string text2 = ((!string.IsNullOrEmpty(val.ihat.displayName)) ? val.ihat.displayName : val.ihat.GetName());
if (!string.IsNullOrEmpty(text2))
{
text = "Bought " + text2;
}
}
if (!string.IsNullOrEmpty(text))
{
long id = LocationData.GetId(text);
if (id < 0)
{
Plugin.Logger.LogDebug((object)("[HatShopBuyAPCheckPatch] '" + text + "' not in AP location table."));
return;
}
Plugin.Logger.LogInfo((object)("[HatShopBuyAPCheckPatch] Hat purchase → sending check: " + text));
Plugin.SendCheck(id);
}
}
catch (Exception ex)
{
Plugin.Logger.LogWarning((object)("[HatShopBuyAPCheckPatch] Exception: " + ex.Message));
}
}
}
[HarmonyPatch(typeof(HatShop), "Restock")]
internal static class HatShopRestockPatch
{
private static readonly Dictionary<string, int> HatStagePrices = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase)
{
{ "Beanie", 500 },
{ "Bucket Hat", 500 },
{ "Floppy Hat", 500 },
{ "Homburg", 500 },
{ "Bowler Hat", 500 },
{ "Cap", 500 },
{ "News Cap", 500 },
{ "Newsboy Cap", 500 },
{ "Sports Helmet", 500 },
{ "Hard Hat", 500 },
{ "Chefs Hat", 1000 },
{ "Chef's Hat", 1000 },
{ "Propeller Hat", 1000 },
{ "Cowboy Hat", 1000 },
{ "Horns", 1000 },
{ "Hotdog Hat", 1000 },
{ "Hot Dog Hat", 1000 },
{ "Milk Hat", 1000 },
{ "Pirate Hat", 1000 },
{ "Top Hat", 1000 },
{ "Party Hat", 1000 },
{ "Ushanka", 1000 },
{ "Balaclava", 2000 },
{ "Cat Ears", 2000 },
{ "Curly Hair", 2000 },
{ "Clown Hair", 2000 },
{ "Crown", 2000 },
{ "Halo", 2000 },
{ "Jesters Hat", 2000 },
{ "Jester's Hat", 2000 },
{ "Ghost Hat", 2000 },
{ "Tooop Hat", 2000 },
{ "Shroom Hat", 2000 },
{ "Witch Hat", 2000 },
{ "Savannah Hair", 2000 }
};
private static int RarityFallbackPrice(RARITY rarity)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0006: Invalid comparison between Unknown and I4
//IL_001f: Unknown result type (might be due to invalid IL or missing references)
//IL_0025: Invalid comparison between Unknown and I4
//IL_0008: Unknown result type (might be due to invalid IL or missing references)
//IL_000b: Invalid comparison between Unknown and I4
//IL_0027: Unknown result type (might be due to invalid IL or missing references)
//IL_002d: Invalid comparison between Unknown and I4
//IL_000d: Unknown result type (might be due to invalid IL or missing references)
//IL_0013: Invalid comparison between Unknown and I4
//IL_002f: Unknown result type (might be due to invalid IL or missing references)
//IL_0035: Invalid comparison between Unknown and I4
//IL_0015: Unknown result type (might be due to invalid IL or missing references)
//IL_001b: Invalid comparison between Unknown and I4
if ((int)rarity <= 10000)
{
if ((int)rarity == 100 || (int)rarity == 1000)
{
return 500;
}
if ((int)rarity == 10000)
{
goto IL_003f;
}
}
else
{
if ((int)rarity == 100000)
{
goto IL_003f;
}
if ((int)rarity == 1000000 || (int)rarity == 10000000)
{
return 2000;
}
}
return 500;
IL_003f:
return 1000;
}
[HarmonyPostfix]
private static void Postfix(HatShop __instance)
{
//IL_0082: 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)
foreach (HatBuyInteractable hatBuyInteractable in __instance.hatBuyInteractables)
{
if ((Object)(object)hatBuyInteractable == (Object)null || hatBuyInteractable.IsEmpty || (Object)(object)hatBuyInteractable.ihat == (Object)null)
{
continue;
}
bool flag = true;
if (!HatStagePrices.TryGetValue(hatBuyInteractable.ihat.displayName, out var value))
{
string name = hatBuyInteractable.ihat.GetName();
if (!HatStagePrices.TryGetValue(name, out value))
{
value = RarityFallbackPrice(hatBuyInteractable.ihat.rarity);
flag = false;
Plugin.Logger.LogDebug((object)("[HatShopRestockPatch] No stage mapping for '" + hatBuyInteractable.ihat.displayName + "' / '" + name + "' " + $"(rarity: {hatBuyInteractable.ihat.rarity}) — fallback {value} MC."));
}
}
hatBuyInteractable.ihat.priceToday = value;
((TMP_Text)hatBuyInteractable.priceText).text = value + " MC";
Plugin.Logger.LogDebug((object)("[HatShopRestockPatch] '" + hatBuyInteractable.ihat.GetName() + "' → " + string.Format("{0} MC ({1})", value, flag ? "table" : "rarity fallback")));
}
}
}
[HarmonyPatch(/*Could not decode attribute arguments.*/)]
internal static class HatBuyInteractableHoverTextPatch
{
[HarmonyPostfix]
private static void Postfix(HatBuyInteractable __instance, ref string __result)
{
if (!string.IsNullOrEmpty(__result) && !((Object)(object)__instance == (Object)null) && HatShopRestockLabelPatch.ScoutedAPItemNames.TryGetValue(__instance, out string value) && !string.IsNullOrEmpty(value))
{
__result = __result + " [" + value + "]";
}
}
}
[HarmonyPatch]
public static class ShopBuyPatch
{
private static readonly Dictionary<string, string> _shopNameOverrides = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
{
{ "AncientGestures3", "Bought Ancient Gestures 3" },
{ "Ancient Gestures 3", "Bought Ancient Gestures 3" },
{ "AncientGestures2", "Bought Ancient Gestures 2" },
{ "Ancient Gestures 2", "Bought Ancient Gestures 2" },
{ "AncientGestures1", "Bought Ancient Gestures 1" },
{ "Ancient Gestures 1", "Bought Ancient Gestures 1" },
{ "Backflip", "Bought Backflip" },
{ "Backflip_Emote", "Bought Backflip" },
{ "HalfFlip", "Bought Backflip" },
{ "Half_Flip", "Bought Backflip" },
{ "Emote_HalfBackflip", "Bought Backflip" },
{ "Emote_HalfBackflip_01", "Bought Backflip" },
{ "Dance101", "Bought Dance 101" },
{ "Dance 101", "Bought Dance 101" },
{ "Dance102", "Bought Dance 102" },
{ "Dance 102", "Bought Dance 102" },
{ "Dance103", "Bought Dance 103" },
{ "Dance 103", "Bought Dance 103" },
{ "Workout1", "Bought Workout 1" },
{ "Workout 1", "Bought Workout 1" },
{ "Workout2", "Bought Workout 2" },
{ "Workout 2", "Bought Workout 2" },
{ "Thumbnail1", "Bought Thumbnail 1" },
{ "Thumbnail 1", "Bought Thumbnail 1" },
{ "Thumbnail2", "Bought Thumbnail 2" },
{ "Thumbnail 2", "Bought Thumbnail 2" },
{ "Gymnastics", "Bought Gymnastics" },
{ "Caring", "Bought Caring" },
{ "Yoga", "Bought Yoga" },
{ "PartyPopper", "Bought Party Popper" }
};
private static MethodBase? TargetMethod()
{
Type type = AccessTools.TypeByName("ShopHandler");
if (type == null)
{
Plugin.Logger.LogWarning((object)"[ShopBuyPatch] Could not find type 'ShopHandler'. Patch skipped.");
return null;
}
MethodInfo methodInfo = AccessTools.Method(type, "RPCA_SpawnDrone", (Type[])null, (Type[])null);
if (methodInfo != null)
{
Plugin.Logger.LogInfo((object)("[ShopBuyPatch] Patching " + type.Name + "." + methodInfo.Name));
return methodInfo;
}
Plugin.Logger.LogWarning((object)"[ShopBuyPatch] Could not find 'RPCA_SpawnDrone' on ShopHandler. Patch skipped.");
return null;
}
[HarmonyPostfix]
private static void Postfix(object __instance, byte[] itemIDs)
{
if (!Plugin.connection.connected || !PhotonNetwork.IsMasterClient)
{
return;
}
try
{
foreach (byte b in itemIDs)
{
TryGetItemDisplayName(b, out string displayName, out string assetName);
string text = null;
if (!string.IsNullOrEmpty(assetName) && _shopNameOverrides.TryGetValue(assetName, out string value))
{
text = value;
}
if (text == null && !string.IsNullOrEmpty(displayName) && _shopNameOverrides.TryGetValue(displayName, out string value2))
{
text = value2;
}
if (text == null && !string.IsNullOrEmpty(displayName))
{
text = "Bought " + displayName;
}
if (text == null && !string.IsNullOrEmpty(assetName))
{
text = "Bought " + assetName;
}
if (string.IsNullOrEmpty(text))
{
Plugin.Logger.LogDebug((object)$"[ShopBuyPatch] Could not resolve any name for item ID {b}.");
continue;
}
long id = LocationData.GetId(text);
if (id < 0)
{
Plugin.Logger.LogDebug((object)("[ShopBuyPatch] '" + text + "' is not an AP location (non-AP item)."));
continue;
}
Plugin.Logger.LogInfo((object)("[ShopBuyPatch] Purchase confirmed → sending check: " + text));
Plugin.SendCheck(id);
}
}
catch (Exception arg)
{
Plugin.Logger.LogError((object)$"[ShopBuyPatch] Exception in postfix: {arg}");
}
}
private static void TryGetItemDisplayName(byte itemId, out string? displayName, out string? assetName)
{
displayName = null;
assetName = null;
Type type = AccessTools.TypeByName("ItemDatabase");
if (type == null)
{
return;
}
MethodInfo methodInfo = AccessTools.Method(type, "TryGetItemFromID", (Type[])null, (Type[])null);
if (methodInfo == null)
{
return;
}
object[] array = new object[2] { itemId, null };
if (!(bool)(methodInfo.Invoke(null, array) ?? ((object)false)) || array[1] == null)
{
return;
}
object obj = array[1];
Object val = (Object)((obj is Object) ? obj : null);
if (val != null && !string.IsNullOrWhiteSpace(val.name))
{
assetName = val.name;
}
FieldInfo fieldInfo = AccessTools.Field(obj.GetType(), "displayName");
if (fieldInfo != null)
{
string text = fieldInfo.GetValue(obj)?.ToString();
if (!string.IsNullOrWhiteSpace(text))
{
displayName = text;
}
}
}
}
[HarmonyPatch]
public static class PickupPatch
{
private static MethodBase? TargetMethod()
{
Type type = AccessTools.TypeByName("Pickup");
if (type == null)
{
Plugin.Logger.LogWarning((object)"[PickupPatch] Could not find type 'Pickup'. Patch skipped.");
return null;
}
MethodInfo methodInfo = AccessTools.Method(type, "RPC_RequestPickup", (Type[])null, (Type[])null);
if (methodInfo == null)
{
Plugin.Logger.LogWarning((object)"[PickupPatch] Could not find 'RPC_RequestPickup' on Pickup. Patch skipped.");
return null;
}
Plugin.Logger.LogInfo((object)("[PickupPatch] Patching " + type.Name + "." + methodInfo.Name));
return methodInfo;
}
[HarmonyPostfix]
private static void Postfix(object __instance)
{
if (!Plugin.connection.connected)
{
return;
}
try
{
string text = TryGetPickupName(__instance);
Plugin.Logger.LogDebug((object)("[PickupPatch] Item picked up: " + (text ?? "(unknown)")));
}
catch (Exception arg)
{
Plugin.Logger.LogError((object)$"[PickupPatch] Exception in postfix: {arg}");
}
}
private static string? TryGetPickupName(object instance)
{
FieldInfo fieldInfo = AccessTools.Field(instance.GetType(), "itemInstance");
if (fieldInfo != null)
{
object value = fieldInfo.GetValue(instance);
if (value != null)
{
FieldInfo fieldInfo2 = AccessTools.Field(value.GetType(), "item");
if (fieldInfo2 != null)
{
object value2 = fieldInfo2.GetValue(value);
if (value2 != null)
{
FieldInfo fieldInfo3 = AccessTools.Field(value2.GetType(), "displayName");
if (fieldInfo3 != null)
{
string text = fieldInfo3.GetValue(value2)?.ToString();
if (!string.IsNullOrEmpty(text))
{
return text;
}
}
Object val = (Object)((value2 is Object) ? value2 : null);
if (val != null)
{
return val.name;
}
}
}
}
}
Component val2 = (Component)((instance is Component) ? instance : null);
if (val2 != null)
{
return ((Object)val2.gameObject).name;
}
return null;
}
}
[HarmonyPatch]
public static class ContentEvaluatorPatch
{
private static readonly HashSet<string> _monstersFilmedThisDay = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
private static MethodBase? TargetMethod()
{
string[] array = new string[1] { "ContentEvaluator" };
for (int i = 0; i < array.Length; i++)
{
Type type = AccessTools.TypeByName(array[i]);
if (!(type == null))
{
MethodInfo methodInfo = AccessTools.Method(type, "EvaluateRecording", (Type[])null, (Type[])null);
if (methodInfo != null)
{
Plugin.Logger.LogInfo((object)("[ContentEvaluatorPatch] Patching " + type.Name + "." + methodInfo.Name));
return methodInfo;
}
}
}
Plugin.Logger.LogWarning((object)"[ContentEvaluatorPatch] Could not find ContentEvaluator.EvaluateRecording. Extraction and filming checks will not fire. Verify the class name in Assembly-CSharp.");
return null;
}
[HarmonyPostfix]
private static void Postfix(bool __result)
{
if (!__result || !Plugin.connection.connected || !PhotonNetwork.IsMasterClient)
{
return;
}
try
{
long id = LocationData.GetId("Any Extraction");
if (id >= 0)
{
Plugin.Logger.LogInfo((object)"[ContentEvaluatorPatch] Sending check: Any Extraction");
Plugin.SendCheck(id);
BroadcastAPCheckNotification("Any Extraction");
}
int num = TryGetCurrentDay();
if (num > 0 && num <= 63)
{
string text = "Extracted Footage on Day " + num;
long id2 = LocationData.GetId(text);
if (id2 >= 0)
{
Plugin.Logger.LogInfo((object)$"[ContentEvaluatorPatch] Day {num} extraction → sending check: {text}");
Plugin.SendCheck(id2);
BroadcastAPCheckNotification(text);
}
}
}
catch (Exception arg)
{
Plugin.Logger.LogError((object)$"[ContentEvaluatorPatch] Exception in extraction postfix: {arg}");
}
}
[HarmonyPostfix]
private static void FilmingPostfix(bool __result, object buffer)
{
if (!__result || !Plugin.connection.connected || buffer == null)
{
return;
}
try
{
int viewsMultiplierLevel = APSave.saveData.viewsMultiplierLevel;
if (viewsMultiplierLevel > 0)
{
float num = 1f + (float)viewsMultiplierLevel * 0.1f;
if (AccessTools.Field(buffer.GetType(), "buffer")?.GetValue(buffer) is IList list)
{
foreach (object item in list)
{
if (item != null)
{
FieldInfo fieldInfo = AccessTools.Field(item.GetType(), "score");
if (!(fieldInfo == null))
{
float num2 = (float)(fieldInfo.GetValue(item) ?? ((object)0f));
fieldInfo.SetValue(item, num2 * num);
}
}
}
Plugin.Logger.LogInfo((object)($"[ContentEvaluatorPatch] Progressive Views: applied {num:F1}× " + $"score multiplier (level {viewsMultiplierLevel}) to {list.Count} buffer entries."));
}
}
if (PhotonNetwork.IsMasterClient)
{
FireFilmingChecks(buffer);
}
}
catch (Exception arg)
{
Plugin.Logger.LogError((object)$"[ContentEvaluatorPatch] Exception in filming postfix: {arg}");
}
}
public static void ResetDailyFilmingState()
{
int count = _monstersFilmedThisDay.Count;
_monstersFilmedThisDay.Clear();
Plugin.Logger.LogInfo((object)("[ContentEvaluatorPatch] Daily filming state reset " + string.Format("({0} entr{1} cleared).", count, (count == 1) ? "y" : "ies")));
}
private static void FireFilmingChecks(object contentBuffer)
{
HashSet<string> fired = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
FieldInfo fieldInfo = AccessTools.Field(contentBuffer.GetType(), "buffer");
if (fieldInfo == null)
{
Plugin.Logger.LogWarning((object)"[ContentEvaluatorPatch] Could not find 'buffer' field on ContentBuffer. Filming checks skipped.");
}
else
{
if (!(fieldInfo.GetValue(contentBuffer) is IEnumerable enumerable))
{
return;
}
foreach (object item in enumerable)
{
if (item == null)
{
continue;
}
FieldInfo fieldInfo2 = AccessTools.Field(item.GetType(), "frame");
if (fieldInfo2 == null)
{
continue;
}
object value = fieldInfo2.GetValue(item);
if (value == null)
{
continue;
}
FieldInfo fieldInfo3 = AccessTools.Field(value.GetType(), "contentEvent");
if (fieldInfo3 == null)
{
continue;
}
object value2 = fieldInfo3.GetValue(value);
if (value2 == null)
{
continue;
}
Type type = value2.GetType();
ushort num = 0;
MethodInfo method = type.GetMethod("GetID", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
if (method != null)
{
object obj = method.Invoke(value2, null);
if (obj != null)
{
try
{
num = Convert.ToUInt16(obj);
}
catch
{
}
}
}
string arg = string.Empty;
MethodInfo method2 = type.GetMethod("GetName", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
if (method2 != null)
{
arg = method2.Invoke(value2, null)?.ToString() ?? string.Empty;
}
string name = type.Name;
Plugin.Logger.LogInfo((object)("[ContentEvaluatorPatch] Buffer scan — type='" + name + "', " + $"GetName()='{arg}', GetID()={num}"));
if (name.IndexOf("artifact", StringComparison.OrdinalIgnoreCase) >= 0 || name.IndexOf("prop", StringComparison.OrdinalIgnoreCase) >= 0)
{
Plugin.Logger.LogInfo((object)"[ContentEvaluatorPatch] >> Artifact/prop event — dumping all fields:");
Type type2 = type;
while (type2 != null && type2 != typeof(object))
{
FieldInfo[] fields = type2.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
foreach (FieldInfo fieldInfo4 in fields)
{
try
{
object value3 = fieldInfo4.GetValue(value2);
Object val = (Object)((value3 is Object) ? value3 : null);
string text = ((val != null) ? ("UnityObject(name='" + val.name + "', type='" + ((object)val).GetType().Name + "')") : (value3?.ToString() ?? "null"));
Plugin.Logger.LogInfo((object)("[ContentEvaluatorPatch] [" + type2.Name + "]." + fieldInfo4.Name + " = " + text));
}
catch (Exception ex)
{
Plugin.Logger.LogInfo((object)("[ContentEvaluatorPatch] [" + type2.Name + "]." + fieldInfo4.Name + " = <error: " + ex.Message + ">"));
}
}
type2 = type2.BaseType;
}
}
string text2 = null;
if (name.Equals("ArtifactContentEvent", StringComparison.Ordinal))
{
FieldInfo fieldInfo5 = null;
string text3 = null;
string[] array = new string[3] { "artifact", "content", "item" };
foreach (string text4 in array)
{
fieldInfo5 = AccessTools.Field(type, text4);
if (fieldInfo5 != null)
{
text3 = text4;
break;
}
}
if (fieldInfo5 != null)
{
Plugin.Logger.LogInfo((object)("[ContentEvaluatorPatch] ArtifactContentEvent: resolved field name = '" + text3 + "'"));
object value4 = fieldInfo5.GetValue(value2);
Object val2 = (Object)((value4 is Object) ? value4 : null);
if (val2 != null)
{
text2 = val2.name;
Plugin.Logger.LogInfo((object)("[ContentEvaluatorPatch] ArtifactContentEvent: " + $"assetName='{text2}', ID={num}"));
}
else
{
Plugin.Logger.LogInfo((object)("[ContentEvaluatorPatch] ArtifactContentEvent: field '" + text3 + "' value is not UnityEngine.Object (actual type: '" + (value4?.GetType().Name ?? "null") + "')"));
}
}
else
{
FieldInfo[] fields2 = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
string text5 = string.Join(", ", Array.ConvertAll(fields2, (FieldInfo f) => f.Name));
Plugin.Logger.LogWarning((object)("[ContentEvaluatorPatch] ArtifactContentEvent: could not find 'content'/'item'/'artifact' field. Available fields: [" + text5 + "]"));
}
}
TryFireEntityCheck(name, num, text2, fired);
}
}
}
private static void TryFireEntityCheck(string rawName, ushort id, string? artifactDisplayName, HashSet<string> fired)
{
string text = null;
if (id != 0)
{
text = FilmingLocationData.TryGetLocationById(id);
}
if (text == null && !string.IsNullOrEmpty(artifactDisplayName))
{
text = FilmingLocationData.TryGetLocationByTypeName(artifactDisplayName);
}
if (text == null)
{
text = FilmingLocationData.TryGetLocationByTypeName(rawName);
}
if (text == null && rawName.EndsWith("ContentEvent", StringComparison.OrdinalIgnoreCase))
{
text = FilmingLocationData.TryGetLocationByTypeName(rawName.Substring(0, rawName.Length - "ContentEvent".Length));
}
if (text == null)
{
Plugin.Logger.LogDebug((object)($"[ContentEvaluatorPatch] No AP location for: class='{rawName}', ID={id}, " + "artifactName='" + (artifactDisplayName ?? "n/a") + "'. Add to FilmingLocationData if this is a new monster/artifact."));
}
else
{
if (fired.Contains(text))
{
return;
}
fired.Add(text);
string text2 = text;
if (_monstersFilmedThisDay.Contains(text2))
{
Plugin.Logger.LogDebug((object)("[ContentEvaluatorPatch] '" + text2 + "' already filmed this dive — skipping tier advancement."));
return;
}
_monstersFilmedThisDay.Add(text2);
bool monsterTiersEnabled = APSave.saveData.monsterTiersEnabled;
long id2 = LocationData.GetId(text2);
long num = (monsterTiersEnabled ? LocationData.GetId(text2 + " 2") : (-1));
long num2 = (monsterTiersEnabled ? LocationData.GetId(text2 + " 3") : (-1));
string text3 = null;
if (id2 >= 0 && !APSave.IsLocationChecked(id2))
{
text3 = text2;
}
else if (num >= 0 && !APSave.IsLocationChecked(num))
{
text3 = text2 + " 2";
}
else if (num2 >= 0 && !APSave.IsLocationChecked(num2))
{
text3 = text2 + " 3";
}
if (text3 == null)
{
Plugin.Logger.LogDebug((object)("[ContentEvaluatorPatch] All tiers for '" + text2 + "' already checked."));
return;
}
long id3 = LocationData.GetId(text3);
if (id3 < 0)
{
Plugin.Logger.LogDebug((object)("[ContentEvaluatorPatch] '" + text3 + "' not in AP location table."));
return;
}
Plugin.Logger.LogInfo((object)("[ContentEvaluatorPatch] Filming check → " + text3));
Plugin.SendCheck(id3);
BroadcastAPCheckNotification(text3);
}
}
private static void BroadcastAPCheckNotification(string locationName)
{
if (string.IsNullOrEmpty(locationName))
{
return;
}
try
{
SurfaceNetworkHandler instance = SurfaceNetworkHandler.Instance;
if (!((Object)(object)instance == (Object)null))
{
if ((Object)(object)((Component)instance).GetComponent<SurfaceAPNotificationBroadcaster>() == (Object)null)
{
((Component)instance).gameObject.AddComponent<SurfaceAPNotificationBroadcaster>();
}
((MonoBehaviourPun)instance).photonView.RPC("RPCA_BroadcastAPCheckNotification", (RpcTarget)0, new object[1] { locationName });
Plugin.Logger.LogDebug((object)("[ContentEvaluatorPatch] Broadcast AP notification RPC: '" + locationName + "'"));
}
}
catch (Exception ex)
{
Plugin.Logger.LogWarning((object)("[ContentEvaluatorPatch] BroadcastAPCheckNotification failed: " + ex.Message));
}
}
private static int TryGetCurrentDay()
{
Type type = AccessTools.TypeByName("GameAPI");
if (type != null)
{
PropertyInfo propertyInfo = AccessTools.Property(type, "CurrentDay");
if (propertyInfo != null && propertyInfo.GetValue(null) is int num && num > 0)
{
return num;
}
}
Type type2 = AccessTools.TypeByName("SurfaceNetworkHandler");
if (type2 != null)
{
PropertyInfo propertyInfo2 = AccessTools.Property(type2, "RoomStats");
if (propertyInfo2 != null)
{
object value = propertyInfo2.GetValue(null);
if (value != null)
{
PropertyInfo propertyInfo3 = AccessTools.Property(value.GetType(), "CurrentDay");
if (propertyInfo3 != null && propertyInfo3.GetValue(value) is int num2 && num2 > 0)
{
return num2;
}
}
}
}
return 0;
}
}
internal class SurfaceAPNotificationBroadcaster : MonoBehaviour
{
[PunRPC]
public void RPCA_BroadcastAPCheckNotification(string locationName)
{
if (!string.IsNullOrEmpty(locationName) && !PhotonNetwork.IsMasterClient)
{
Plugin.Logger.LogInfo((object)("[SurfaceAPNotificationBroadcaster] Showing AP check notification: '" + locationName + "'"));
APNotificationUI.ShowLocationFound(locationName);
}
}
}
[HarmonyPatch(typeof(PlayerHandler))]
[HarmonyPriority(400)]
internal static class LateJoinSyncPatch
{
internal const string KeyDiveBellCharger = "AP_DBC";
internal const string KeyDiveBellO2 = "AP_O2";
internal const string KeyPendingMoney = "AP_PM";
[HarmonyPostfix]
[HarmonyPatch("AddPlayer")]
private static void AddPlayerPostfix(Player player)
{
if (PhotonNetwork.IsMasterClient && !player.IsLocal && Plugin.connection.connected)
{
Player controller = player.refs.view.Controller;
Plugin.Logger.LogInfo((object)("[LateJoinSync] New player '" + controller.NickName + "' joined — broadcasting AP world state."));
BroadcastWorldState();
SyncHatLabelsToPlayer(controller);
}
}
private static void SyncHatLabelsToPlayer(Player photonPlayer)
{
try
{
if ((Object)(object)HatShopAPSyncBehaviour.Instance == (Object)null)
{
Plugin.Logger.LogDebug((object)"[LateJoinSync] SyncHatLabelsToPlayer: HatShopAPSyncBehaviour not ready — skipping targeted sync.");
return;
}
Type type = AccessTools.TypeByName("HatShop");
object obj = ((type != null) ? AccessTools.Field(type, "instance") : null)?.GetValue(null);
if (obj == null)
{
Plugin.Logger.LogDebug((object)"[LateJoinSync] SyncHatLabelsToPlayer: HatShop.instance is null — skipping targeted sync.");
return;
}
if (!(AccessTools.Field(obj.GetType(), "hatBuyInteractables")?.GetValue(obj) is List<HatBuyInteractable> list) || list.Count == 0)
{
Plugin.Logger.LogDebug((object)"[LateJoinSync] SyncHatLabelsToPlayer: hatBuyInteractables empty — skipping targeted sync.");
return;
}
string[] array = new string[list.Count];
for (int i = 0; i < list.Count; i++)
{
HatBuyInteractable val = list[i];
string value = string.Empty;
if ((Object)(object)val != (Object)null)
{
HatShopRestockLabelPatch.ScoutedNames.TryGetValue(val, out value);
}
array[i] = value;
}
object? obj2 = AccessTools.Field(obj.GetType(), "view")?.GetValue(obj);
PhotonView val2 = (PhotonView)((obj2 is PhotonView) ? obj2 : null);
if ((Object)(object)val2 == (Object)null)
{
Plugin.Logger.LogWarning((object)"[LateJoinSync] SyncHatLabelsToPlayer: HatShop PhotonView is null — cannot send targeted label sync.");
return;
}
val2.RPC("RPCA_SyncArchipelagoLabels", photonPlayer, new object[1] { array });
Plugin.Logger.LogInfo((object)$"[LateJoinSync] Sent {array.Length} hat label(s) directly to '{photonPlayer.NickName}'.");
}
catch (Exception ex)
{
Plugin.Logger.LogWarning((object)("[LateJoinSync] SyncHatLabelsToPlayer exception: " + ex.Message));
}
}
internal static void BroadcastWorldState()
{
//IL_0008: Unknown result type (might be due to invalid IL or missing references)
//IL_0013: Unknown result type (might be due to invalid IL or missing references)
//IL_002f: Unknown result type (might be due to invalid IL or missing references)
//IL_004b: Unknown result type (might be due to invalid IL or missing references)
//IL_0062: Expected O, but got Unknown
if (PhotonNetwork.IsMasterClient)
{
Hashtable val = new Hashtable
{
[(object)"AP_DBC"] = APSave.saveData.diveBellChargerUnlocked,
[(object)"AP_O2"] = APSave.saveData.diveBellO2Unlocked,
[(object)"AP_PM"] = APSave.saveData.pendingMoney
};
Room currentRoom = PhotonNetwork.CurrentRoom;
if (currentRoom != null)
{
currentRoom.SetCustomProperties(val, (Hashtable)null, (WebFlags)null);
}
Plugin.Logger.LogDebug((object)"[LateJoinSync] Room properties updated with AP world state.");
}
}
internal static void ApplyRoomProperties()
{
Room currentRoom = PhotonNetwork.CurrentRoom;
Hashtable val = ((currentRoom != null) ? ((RoomInfo)currentRoom).CustomProperties : null);
if (val != null)
{
if (((Dictionary<object, object>)(object)val).TryGetValue((object)"AP_DBC", out object value) && value is bool && (bool)value && !APSave.saveData.diveBellChargerUnlocked)
{
APSave.saveData.diveBellChargerUnlocked = true;
Plugin.Logger.LogInfo((object)"[LateJoinSync] Applied DiveBellCharger from room properties.");
}
if (((Dictionary<object, object>)(object)val).TryGetValue((object)"AP_O2", out object value2) && value2 is bool && (bool)value2 && !APSave.saveData.diveBellO2Unlocked)
{
APSave.saveData.diveBellO2Unlocked = true;
Plugin.Logger.LogInfo((object)"[LateJoinSync] Applied DiveBellO2 from room properties.");
}
if (((Dictionary<object, object>)(object)val).TryGetValue((object)"AP_PM", out object value3) && value3 is int num && num > 0)
{
Plugin.Logger.LogDebug((object)$"[LateJoinSync] Room has {num} pending AP money (master will apply).");
}
APSave.Flush();
}
}
}
[HarmonyPatch(typeof(SurfaceNetworkHandler))]
[HarmonyPriority(400)]
internal static class SurfaceApplyRoomPropsPatch
{
[HarmonyPostfix]
[HarmonyPatch("RPCM_StartGame")]
private static void RPCM_StartGamePostfix()
{
ContentEvaluatorPatch.ResetDailyFilmingState();
if (Plugin.connection.connected)
{
LateJoinSyncPatch.ApplyRoomProperties();
if (PhotonNetwork.IsMasterClient)
{
LateJoinSyncPatch.BroadcastWorldState();
}
}
}
}
[HarmonyPatch(typeof(SurfaceNetworkHandler), "RPCA_Sleep")]
[HarmonyPriority(400)]
internal static class SurfaceSleepResetPatch
{
[HarmonyPostfix]
private static void Postfix()
{
ContentEvaluatorPatch.ResetDailyFilmingState();
}
}
[HarmonyPatch(typeof(MainMenuHandler), "Start")]
internal static class MainMenuAPPatch
{
[CompilerGenerated]
private sealed class <InjectPanelDelayed>d__1 : IEnumerator<object>, IEnumerator, IDisposable
{
private int <>1__state;
private object <>2__current;
public MainMenuHandler menu;
object IEnumerator<object>.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
object IEnumerator.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
[DebuggerHidden]
public <InjectPanelDelayed>d__1(int <>1__state)
{
this.<>1__state = <>1__state;
}
[DebuggerHidden]
void IDisposable.Dispose()
{
<>1__state = -2;
}
private bool MoveNext()
{
//IL_001d: Unknown result type (might be due to invalid IL or missing references)
//IL_0027: Expected O, but got Unknown
switch (<>1__state)
{
default:
return false;
case 0:
<>1__state = -1;
<>2__current = (object)new WaitForSeconds(3f);
<>1__state = 1;
return true;
case 1:
<>1__state = -1;
if ((Object)(object)GameObject.Find("AP_ConnectionPanel") != (Object)null)
{
return false;
}
InjectPanel(menu);
return false;
}
}
bool IEnumerator.MoveNext()
{
//ILSpy generated this explicit interface implementation from .override directive in MoveNext
return this.MoveNext();
}
[DebuggerHidden]
void IEnumerator.Reset()
{
throw new NotSupportedException();
}
}
private static void Postfix(MainMenuHandler __instance)
{
if (!((Object)(object)GameObject.Find("AP_ConnectionPanel") != (Object)null))
{
Plugin.Logger.LogDebug((object)"[MainMenuAPPatch] MainMenuHandler.Start() completed — starting 3-second coroutine before injecting AP panel.");
((MonoBehaviour)__instance).StartCoroutine(InjectPanelDelayed(__instance));
}
}
[IteratorStateMachine(typeof(<InjectPanelDelayed>d__1))]
private static IEnumerator InjectPanelDelayed(MainMenuHandler menu)
{
//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
return new <InjectPanelDelayed>d__1(0)
{
menu = menu
};
}
private static void InjectPanel(MainMenuHandler menu)
{
//IL_0075: Unknown result type (might be due to invalid IL or missing references)
//IL_007b: Expected O, but got Unknown
//IL_008e: Unknown result type (might be due to invalid IL or missing references)
//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
//IL_0106: Unknown result type (might be due to invalid IL or missing references)
try
{
Plugin.Logger.LogInfo((object)"[MainMenuAPPatch] Injecting AP panel into main-menu UI.");
Transform val = (((Object)(object)menu.UIHandler != (Object)null) ? ((Component)menu.UIHandler).transform : ((Component)menu).transform);
Plugin.Logger.LogDebug((object)("[MainMenuAPPatch] Using parent: " + ((Object)val).name + " (full path: " + GetPath(val) + ")"));
GameObject val2 = new GameObject("AP_ConnectionPanel");
val2.transform.SetParent(val, false);
val2.transform.localScale = Vector3.one;
RectTransform obj = val2.GetComponent<RectTransform>() ?? val2.AddComponent<RectTransform>();
obj.anchorMin = new Vector2(1f, 1f);
obj.anchorMax = new Vector2(1f, 1f);
obj.pivot = new Vector2(1f, 1f);
obj.anchoredPosition = new Vector2(-10f, -10f);
obj.sizeDelta = new Vector2(350f, 0f);
val2.AddComponent<APConnectionPanelUI>();
val2.SetActive(true);
Transform val3 = val;
while ((Object)(object)val3 != (Object)null)
{
if (!((Component)val3).gameObject.activeSelf)
{
Plugin.Logger.LogDebug((object)("[MainMenuAPPatch] Activating inactive ancestor: " + GetPath(val3)));
((Component)val3).gameObject.SetActive(true);
}
val3 = val3.parent;
}
val2.transform.SetAsLastSibling();
Plugin.Logger.LogInfo((object)"[MainMenuAPPatch] AP connection panel successfully injected into main-menu UI.");
}
catch (Exception arg)
{
Plugin.Logger.LogError((object)$"[MainMenuAPPatch] Exception while injecting AP panel: {arg}");
}
}
private static string GetPath(Transform t)
{
if ((Object)(object)t.parent == (Object)null)
{
return ((Object)t).name;
}
return GetPath(t.parent) + "/" + ((Object)t).name;
}
}
[HarmonyPatch(typeof(MetaProgressionHandler), "GetUnlockedHats")]
internal static class GetUnlockedHatsPatch
{
[HarmonyPostfix]
private static void Postfix(ref int[] __result)
{
if (Plugin.connection.connected)
{
int[] array = new int[APSave.saveData.sessionUnlockedHats.Count];
APSave.saveData.sessionUnlockedHats.CopyTo(array);
__result = array;
Plugin.Logger.LogDebug((object)$"[GetUnlockedHatsPatch] AP active — returning {array.Length} session hat(s).");
}
}
}
[HarmonyPatch(typeof(MetaProgressionHandler), "UnlockHat")]
internal static class UnlockHatPatch
{
[HarmonyPrefix]
private static bool Prefix(int hat)
{
if (!Plugin.connection.connected)
{
return true;
}
if (APSave.saveData.sessionUnlockedHats.Add(hat))
{
Plugin.Logger.LogInfo((object)$"[UnlockHatPatch] AP active — hat {hat} added to session (no disk write).");
}
return false;
}
}
[HarmonyPatch(typeof(MetaProgressionHandler), "AddMetaCoins")]
internal static class AddMetaCoinsPatch
{
[HarmonyPrefix]
private static bool Prefix(int amount)
{
if (!Plugin.connection.connected)
{
return true;
}
Plugin.Logger.LogDebug((object)$"[AddMetaCoinsPatch] AP active — vanilla AddMetaCoins({amount}) suppressed.");
return false;
}
}
[HarmonyPatch(typeof(MetaProgressionHandler), "RemoveMetaCoins")]
internal static class RemoveMetaCoinsPatch
{
[HarmonyPrefix]
private static bool Prefix(int amount)
{
if (!Plugin.connection.connected)
{
return true;
}
if (PhotonNetwork.IsMasterClient)
{
Plugin.connection.AddMetaCoinsDelta(-amount);
Plugin.Logger.LogInfo((object)$"[RemoveMetaCoinsPatch] AP active — sent -{amount} MC to DataStorage.");
}
else
{
Plugin.Logger.LogDebug((object)("[RemoveMetaCoinsPatch] AP active — non-master client " + $"swallowing local RemoveMetaCoins({amount}); listener will sync."));
}
return false;
}
}
[HarmonyPatch(typeof(MetaProgressionHandler), "UpdateAndSave")]
internal static class UpdateAndSavePatch
{
[HarmonyPrefix]
private static bool Prefix()
{
return !Plugin.connection.connected;
}
}
internal static class ModManagerAPPatch
{
internal static void TryApplyPatch(Harmony harmony)
{
//IL_005b: Unknown result type (might be due to invalid IL or missing references)
//IL_0061: Expected O, but got Unknown
Type type = AccessTools.TypeByName("ModManagerUI");
if (type == null)
{
Plugin.Logger.LogWarning((object)"[ModManagerAPPatch] ModManagerUI type not found in any loaded assembly. The AP connection panel will not be injected into the Mod Manager. This is expected if the game's built-in Mod Manager is absent.");
return;
}
MethodInfo methodInfo = AccessTools.Method(type, "OnEnable", (Type[])null, (Type[])null);
if (methodInfo == null)
{
Plugin.Logger.LogWarning((object)"[ModManagerAPPatch] Could not find ModManagerUI.OnEnable() — skipping patch.");
return;
}
HarmonyMethod val = new HarmonyMethod(typeof(ModManagerAPPatch), "OnEnable_Postfix", (Type[])null);
harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, val, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
Plugin.Logger.LogInfo((object)"[ModManagerAPPatch] Successfully patched ModManagerUI.OnEnable() with AP panel injector.");
}
private static void OnEnable_Postfix(MonoBehaviour __instance)
{
//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
//IL_00de: Unknown result type (might be due to invalid IL or missing references)
try
{
Plugin.Logger.LogInfo((object)"[ModManagerAPPatch] OnEnable_Postfix fired — checking for existing AP panel.");
if ((Object)(object)GameObject.Find("AP_ConnectionPanel") != (Object)null)
{
Plugin.Logger.LogDebug((object)"[ModManagerAPPatch] AP_ConnectionPanel already exists in scene — skipping.");
return;
}
Transform transform = ((Component)__instance).transform;
FieldInfo fieldInfo = AccessTools.Field(((object)__instance).GetType(), "modlist");
if (fieldInfo != null)
{
object? value = fieldInfo.GetValue(__instance);
Object val = (Object)((value is Object) ? value : null);
Component val2 = (Component)(object)((val is Component) ? val : null);
if (val2 != null)
{
transform = val2.transform;
}
else
{
GameObject val3 = (GameObject)(object)((val is GameObject) ? val : null);
if (val3 != null)
{
transform = val3.transform;
}
else
{
Plugin.Logger.LogWarning((object)"[ModManagerAPPatch] 'modlist' field found but could not be cast to Component or GameObject — falling back to root transform.");
}
}
}
else
{
Plugin.Logger.LogWarning((object)"[ModManagerAPPatch] Could not find 'modlist' field on ModManagerUI — falling back to root transform.");
}
GameObject val4 = new GameObject("AP_ConnectionPanel");
val4.transform.SetParent(transform, false);
LayoutElement obj = val4.AddComponent<LayoutElement>();
obj.preferredWidth = -1f;
obj.preferredHeight = 155f;
val4.AddComponent<APConnectionPanelUI>();
val4.transform.SetAsLastSibling();
Plugin.Logger.LogInfo((object)"[ModManagerAPPatch] AP connection panel successfully injected into ModManagerUI.");
}
catch (Exception arg)
{
Plugin.Logger.LogError((object)$"[ModManagerAPPatch] Exception while injecting AP panel: {arg}");
}
}
}
[HarmonyPatch(typeof(ShopHandler))]
internal static class MoneyPatch
{
[HarmonyPatch("InitShop")]
[HarmonyPostfix]
private static void InitShopPostfix(ShopHandler __instance)
{
if (PhotonNetwork.IsMasterClient)
{
int pendingMoney = APSave.saveData.pendingMoney;
if (pendingMoney > 0)
{
Plugin.Logger.LogInfo((object)$"[MoneyPatch] Draining {pendingMoney} pending AP money
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net.WebSockets;
using System.Numerics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Runtime.Versioning;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Archipelago.MultiClient.Net.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 Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: ComVisible(false)]
[assembly: Guid("35a803ad-85ed-42e9-b1e3-c6b72096f0c1")]
[assembly: InternalsVisibleTo("Archipelago.MultiClient.Net.Tests")]
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]
[assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = ".NET Standard 2.0")]
[assembly: AssemblyCompany("Jarno Westhof, Hussein Farran, Zach Parks")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("Copyright © 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 ((StringEnumConverter)this).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, JToken.op_Implicit(1));
}
public static DataStorageElement operator --(DataStorageElement a)
{
return new DataStorageElement(a, OperationType.Add, JToken.op_Implicit(-1));
}
public static DataStorageElement operator +(DataStorageElement a, int b)
{
return new DataStorageElement(a, OperationType.Add, JToken.op_Implicit(b));
}
public static DataStorageElement operator +(DataStorageElement a, long b)
{
return new DataStorageElement(a, OperationType.Add, JToken.op_Implicit(b));
}
public static DataStorageElement operator +(DataStorageElement a, float b)
{
return new DataStorageElement(a, OperationType.Add, JToken.op_Implicit(b));
}
public static DataStorageElement operator +(DataStorageElement a, double b)
{
return new DataStorageElement(a, OperationType.Add, JToken.op_Implicit(b));
}
public static DataStorageElement operator +(DataStorageElement a, decimal b)
{
return new DataStorageElement(a, OperationType.Add, JToken.op_Implicit(b));
}
public static DataStorageElement operator +(DataStorageElement a, string b)
{
return new DataStorageElement(a, OperationType.Add, JToken.op_Implicit(b));
}
public static DataStorageElement operator +(DataStorageElement a, JToken b)
{
return new DataStorageElement(a, OperationType.Add, b);
}
public static DataStorageElement operator +(DataStorageElement a, IEnumerable b)
{
return new DataStorageElement(a, OperationType.Add, (JToken)(object)JArray.FromObject((object)b));
}
public static DataStorageElement operator +(DataStorageElement a, OperationSpecification s)
{
return new DataStorageElement(a, s.OperationType, s.Value);
}
public static DataStorageElement operator +(DataStorageElement a, Callback c)
{
return new DataStorageElement(a, c);
}
public static DataStorageElement operator +(DataStorageElement a, AdditionalArgument arg)
{
return new DataStorageElement(a, arg);
}
public static DataStorageElement operator *(DataStorageElement a, int b)
{
return new DataStorageElement(a, OperationType.Mul, JToken.op_Implicit(b));
}
public static DataStorageElement operator *(DataStorageElement a, long b)
{
return new DataStorageElement(a, OperationType.Mul, JToken.op_Implicit(b));
}
public static DataStorageElement operator *(DataStorageElement a, float b)
{
return new DataStorageElement(a, OperationType.Mul, JToken.op_Implicit(b));
}
public static DataStorageElement operator *(DataStorageElement a, double b)
{
return new DataStorageElement(a, OperationType.Mul, JToken.op_Implicit(b));
}
public static DataStorageElement operator *(DataStorageElement a, decimal b)
{
return new DataStorageElement(a, OperationType.Mul, JToken.op_Implicit(b));
}
public static DataStorageElement operator %(DataStorageElement a, int b)
{
return new DataStorageElement(a, OperationType.Mod, JToken.op_Implicit(b));
}
public static DataStorageElement operator %(DataStorageElement a, long b)
{
return new DataStorageElement(a, OperationType.Mod, JToken.op_Implicit(b));
}
public static DataStorageElement operator %(DataStorageElement a, float b)
{
return new DataStorageElement(a, OperationType.Mod, JToken.op_Implicit(b));
}
public static DataStorageElement operator %(DataStorageElement a, double b)
{
return new DataStorageElement(a, OperationType.Mod, JToken.op_Implicit(b));
}
public static DataStorageElement operator %(DataStorageElement a, decimal b)
{
return new DataStorageElement(a, OperationType.Mod, JToken.op_Implicit(b));
}
public static DataStorageElement operator ^(DataStorageElement a, int b)
{
return new DataStorageElement(a, OperationType.Pow, JToken.op_Implicit(b));
}
public static DataStorageElement operator ^(DataStorageElement a, long b)
{
return new DataStorageElement(a, OperationType.Pow, JToken.op_Implicit(b));
}
public static DataStorageElement operator ^(DataStorageElement a, float b)
{
return new DataStorageElement(a, OperationType.Pow, JToken.op_Implicit(b));
}
public static DataStorageElement operator ^(DataStorageElement a, double b)
{
return new DataStorageElement(a, OperationType.Pow, JToken.op_Implicit(b));
}
public static DataStorageElement operator ^(DataStorageElement a, decimal b)
{
return new DataStorageElement(a, OperationType.Pow, JToken.op_Implicit(b));
}
public static DataStorageElement operator -(DataStorageElement a, int b)
{
return new DataStorageElement(a, OperationType.Add, JToken.FromObject((object)(-b)));
}
public static DataStorageElement operator -(DataStorageElement a, long b)
{
return new DataStorageElement(a, OperationType.Add, JToken.FromObject((object)(-b)));
}
public static DataStorageElement operator -(DataStorageElement a, float b)
{
return new DataStorageElement(a, OperationType.Add, JToken.FromObject((object)(0f - b)));
}
public static DataStorageElement operator -(DataStorageElement a, double b)
{
return new DataStorageElement(a, OperationType.Add, JToken.FromObject((object)(0.0 - b)));
}
public static DataStorageElement operator -(DataStorageElement a, decimal b)
{
return new DataStorageElement(a, OperationType.Add, JToken.FromObject((object)(-b)));
}
public static DataStorageElement operator /(DataStorageElement a, int b)
{
return new DataStorageElement(a, OperationType.Mul, JToken.FromObject((object)(1m / (decimal)b)));
}
public static DataStorageElement operator /(DataStorageElement a, long b)
{
return new DataStorageElement(a, OperationType.Mul, JToken.FromObject((object)(1m / (decimal)b)));
}
public static DataStorageElement operator /(DataStorageElement a, float b)
{
return new DataStorageElement(a, OperationType.Mul, JToken.FromObject((object)(1.0 / (double)b)));
}
public static DataStorageElement operator /(DataStorageElement a, double b)
{
return new DataStorageElement(a, OperationType.Mul, JToken.FromObject((object)(1.0 / b)));
}
public static DataStorageElement operator /(DataStorageElement a, decimal b)
{
return new DataStorageElement(a, OperationType.Mul, JToken.FromObject((object)(1m / b)));
}
public static implicit operator DataStorageElement(bool b)
{
return new DataStorageElement(OperationType.Replace, JToken.op_Implicit(b));
}
public static implicit operator DataStorageElement(int i)
{
return new DataStorageElement(OperationType.Replace, JToken.op_Implicit(i));
}
public static implicit operator DataStorageElement(long l)
{
return new DataStorageElement(OperationType.Replace, JToken.op_Implicit(l));
}
public static implicit operator DataStorageElement(decimal m)
{
return new DataStorageElement(OperationType.Replace, JToken.op_Implicit(m));
}
public static implicit operator DataStorageElement(double d)
{
return new DataStorageElement(OperationType.Replace, JToken.op_Implicit(d));
}
public static implicit operator DataStorageElement(float f)
{
return new DataStorageElement(OperationType.Replace, JToken.op_Implicit(f));
}
public static implicit operator DataStorageElement(string s)
{
if (s != null)
{
return new DataStorageElement(OperationType.Replace, JToken.op_Implicit(s));
}
return new DataStorageElement(OperationType.Replace, (JToken)(object)JValue.CreateNull());
}
public static implicit operator DataStorageElement(JToken o)
{
return new DataStorageElement(OperationType.Replace, o);
}
public static implicit operator DataStorageElement(Array a)
{
return new DataStorageElement(OperationType.Replace, (JToken)(object)JArray.FromObject((object)a));
}
public static implicit operator DataStorageElement(List<bool> l)
{
return new DataStorageElement(OperationType.Replace, (JToken)(object)JArray.FromObject((object)l));
}
public static implicit operator DataStorageElement(List<int> l)
{
return new DataStorageElement(OperationType.Replace, (JToken)(object)JArray.FromObject((object)l));
}
public static implicit operator DataStorageElement(List<long> l)
{
return new DataStorageElement(OperationType.Replace, (JToken)(object)JArray.FromObject((object)l));
}
public static implicit operator DataStorageElement(List<decimal> l)
{
return new DataStorageElement(OperationType.Replace, (JToken)(object)JArray.FromObject((object)l));
}
public static implicit operator DataStorageElement(List<double> l)
{
return new DataStorageElement(OperationType.Replace, (JToken)(object)JArray.FromObject((object)l));
}
public static implicit operator DataStorageElement(List<float> l)
{
return new DataStorageElement(OperationType.Replace, (JToken)(object)JArray.FromObject((object)l));
}
public static implicit operator DataStorageElement(List<string> l)
{
return new DataStorageElement(OperationType.Replace, (JToken)(object)JArray.FromObject((object)l));
}
public static implicit operator DataStorageElement(List<object> l)
{
return new DataStorageElement(OperationType.Replace, (JToken)(object)JArray.FromObject((object)l));
}
public static implicit operator bool(DataStorageElement e)
{
return RetrieveAndReturnBoolValue<bool>(e);
}
public static implicit operator bool?(DataStorageElement e)
{
return RetrieveAndReturnBoolValue<bool?>(e);
}
public static implicit operator int(DataStorageElement e)
{
return RetrieveAndReturnDecimalValue<int>(e);
}
public static implicit operator int?(DataStorageElement e)
{
return RetrieveAndReturnDecimalValue<int?>(e);
}
public static implicit operator long(DataStorageElement e)
{
return RetrieveAndReturnDecimalValue<long>(e);
}
public static implicit operator long?(DataStorageElement e)
{
return RetrieveAndReturnDecimalValue<long?>(e);
}
public static implicit operator float(DataStorageElement e)
{
return RetrieveAndReturnDecimalValue<float>(e);
}
public static implicit operator float?(DataStorageElement e)
{
return RetrieveAndReturnDecimalValue<float?>(e);
}
public static implicit operator double(DataStorageElement e)
{
return RetrieveAndReturnDecimalValue<double>(e);
}
public static implicit operator double?(DataStorageElement e)
{
return RetrieveAndReturnDecimalValue<double?>(e);
}
public static implicit operator decimal(DataStorageElement e)
{
return RetrieveAndReturnDecimalValue<decimal>(e);
}
public static implicit operator decimal?(DataStorageElement e)
{
return RetrieveAndReturnDecimalValue<decimal?>(e);
}
public static implicit operator string(DataStorageElement e)
{
return RetrieveAndReturnStringValue(e);
}
public static implicit operator bool[](DataStorageElement e)
{
return RetrieveAndReturnArrayValue<bool[]>(e);
}
public static implicit operator int[](DataStorageElement e)
{
return RetrieveAndReturnArrayValue<int[]>(e);
}
public static implicit operator long[](DataStorageElement e)
{
return RetrieveAndReturnArrayValue<long[]>(e);
}
public static implicit operator decimal[](DataStorageElement e)
{
return RetrieveAndReturnArrayValue<decimal[]>(e);
}
public static implicit operator double[](DataStorageElement e)
{
return RetrieveAndReturnArrayValue<double[]>(e);
}
public static implicit operator float[](DataStorageElement e)
{
return RetrieveAndReturnArrayValue<float[]>(e);
}
public static implicit operator string[](DataStorageElement e)
{
return RetrieveAndReturnArrayValue<string[]>(e);
}
public static implicit operator object[](DataStorageElement e)
{
return RetrieveAndReturnArrayValue<object[]>(e);
}
public static implicit operator List<bool>(DataStorageElement e)
{
return RetrieveAndReturnArrayValue<List<bool>>(e);
}
public static implicit operator List<int>(DataStorageElement e)
{
return RetrieveAndReturnArrayValue<List<int>>(e);
}
public static implicit operator List<long>(DataStorageElement e)
{
return RetrieveAndReturnArrayValue<List<long>>(e);
}
public static implicit operator List<decimal>(DataStorageElement e)
{
return RetrieveAndReturnArrayValue<List<decimal>>(e);
}
public static implicit operator List<double>(DataStorageElement e)
{
return RetrieveAndReturnArrayValue<List<double>>(e);
}
public static implicit operator List<float>(DataStorageElement e)
{
return RetrieveAndReturnArrayValue<List<float>>(e);
}
public static implicit operator List<string>(DataStorageElement e)
{
return RetrieveAndReturnArrayValue<List<string>>(e);
}
public static implicit operator List<object>(DataStorageElement e)
{
return RetrieveAndReturnArrayValue<List<object>>(e);
}
public static implicit operator Array(DataStorageElement e)
{
return RetrieveAndReturnArrayValue<Array>(e);
}
public static implicit operator JArray(DataStorageElement e)
{
return RetrieveAndReturnArrayValue<JArray>(e);
}
public static implicit operator JToken(DataStorageElement e)
{
return e.Context.GetData(e.Context.Key);
}
public static DataStorageElement operator +(DataStorageElement a, BigInteger b)
{
return new DataStorageElement(a, OperationType.Add, JToken.Parse(b.ToString()));
}
public static DataStorageElement operator *(DataStorageElement a, BigInteger b)
{
return new DataStorageElement(a, OperationType.Mul, JToken.Parse(b.ToString()));
}
public static DataStorageElement operator %(DataStorageElement a, BigInteger b)
{
return new DataStorageElement(a, OperationType.Mod, JToken.Parse(b.ToString()));
}
public static DataStorageElement operator ^(DataStorageElement a, BigInteger b)
{
return new DataStorageElement(a, OperationType.Pow, JToken.Parse(b.ToString()));
}
public static DataStorageElement operator -(DataStorageElement a, BigInteger b)
{
return new DataStorageElement(a, OperationType.Add, JToken.Parse((-b).ToString()));
}
public static DataStorageElement operator /(DataStorageElement a, BigInteger b)
{
throw new InvalidOperationException("DataStorage[Key] / BigInterger is not supported, due to loss of precision when using integer division");
}
public static implicit operator DataStorageElement(BigInteger bi)
{
return new DataStorageElement(OperationType.Replace, JToken.Parse(bi.ToString()));
}
public static implicit operator BigInteger(DataStorageElement e)
{
return RetrieveAndReturnBigIntegerValue<BigInteger>(e);
}
public static implicit operator BigInteger?(DataStorageElement e)
{
return RetrieveAndReturnBigIntegerValue<BigInteger?>(e);
}
private static T RetrieveAndReturnBigIntegerValue<T>(DataStorageElement e)
{
if (e.cachedValue != null)
{
if (!BigInteger.TryParse(((object)e.cachedValue).ToString(), out var result))
{
return default(T);
}
return (T)Convert.ChangeType(result, IsNullable<T>() ? Nullable.GetUnderlyingType(typeof(T)) : typeof(T));
}
BigInteger result2;
BigInteger? bigInteger = (BigInteger.TryParse(((object)e.Context.GetData(e.Context.Key)).ToString(), out result2) ? new BigInteger?(result2) : null);
if (!bigInteger.HasValue && !IsNullable<T>())
{
bigInteger = Activator.CreateInstance<BigInteger>();
}
foreach (OperationSpecification operation in e.Operations)
{
if (operation.OperationType == OperationType.Floor || operation.OperationType == OperationType.Ceil)
{
continue;
}
if (!BigInteger.TryParse(((object)operation.Value).ToString(), NumberStyles.AllowLeadingSign, null, out var result3))
{
throw new InvalidOperationException($"DataStorage[Key] cannot be converted to BigInterger as its value its not an integer number, value: {operation.Value}");
}
switch (operation.OperationType)
{
case OperationType.Replace:
bigInteger = result3;
break;
case OperationType.Add:
bigInteger += result3;
break;
case OperationType.Mul:
bigInteger *= result3;
break;
case OperationType.Mod:
bigInteger %= result3;
break;
case OperationType.Pow:
bigInteger = BigInteger.Pow(bigInteger.Value, (int)operation.Value);
break;
case OperationType.Max:
{
BigInteger value = result3;
BigInteger? bigInteger2 = bigInteger;
if (value > bigInteger2)
{
bigInteger = result3;
}
break;
}
case OperationType.Min:
{
BigInteger value = result3;
BigInteger? bigInteger2 = bigInteger;
if (value < bigInteger2)
{
bigInteger = result3;
}
break;
}
case OperationType.Xor:
bigInteger ^= result3;
break;
case OperationType.Or:
bigInteger |= result3;
break;
case OperationType.And:
bigInteger &= result3;
break;
case OperationType.LeftShift:
bigInteger <<= (int)operation.Value;
break;
case OperationType.RightShift:
bigInteger >>= (int)operation.Value;
break;
}
}
e.cachedValue = JToken.Parse(bigInteger.ToString());
if (!bigInteger.HasValue)
{
return default(T);
}
return (T)Convert.ChangeType(bigInteger.Value, IsNullable<T>() ? Nullable.GetUnderlyingType(typeof(T)) : typeof(T));
}
public void Initialize(JToken value)
{
Context.Initialize(Context.Key, value);
}
public void Initialize(IEnumerable value)
{
Context.Initialize(Context.Key, (JToken)(object)JArray.FromObject((object)value));
}
public Task<T> GetAsync<T>()
{
return GetAsync().ContinueWith((Task<JToken> r) => r.Result.ToObject<T>());
}
public Task<JToken> GetAsync()
{
return Context.GetAsync(Context.Key);
}
private static T RetrieveAndReturnArrayValue<T>(DataStorageElement e)
{
//IL_000e: Unknown result type (might be due to invalid IL or missing references)
//IL_003d: Unknown result type (might be due to invalid IL or missing references)
//IL_0073: Unknown result type (might be due to invalid IL or missing references)
//IL_0079: Invalid comparison between Unknown and I4
//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
//IL_00b1: Invalid comparison between Unknown and I4
//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
if (e.cachedValue != null)
{
return ((JToken)(JArray)e.cachedValue).ToObject<T>();
}
JArray val = (JArray)(((object)e.Context.GetData(e.Context.Key).ToObject<JArray>()) ?? ((object)new JArray()));
foreach (OperationSpecification operation in e.Operations)
{
switch (operation.OperationType)
{
case OperationType.Add:
if ((int)operation.Value.Type != 2)
{
throw new InvalidOperationException($"Cannot perform operation {OperationType.Add} on Array value, with a non Array value: {operation.Value}");
}
((JContainer)val).Merge((object)operation.Value);
break;
case OperationType.Replace:
if ((int)operation.Value.Type != 2)
{
throw new InvalidOperationException($"Cannot replace Array value, with a non Array value: {operation.Value}");
}
val = (JArray)(((object)operation.Value.ToObject<JArray>()) ?? ((object)new JArray()));
break;
default:
throw new InvalidOperationException($"Cannot perform operation {operation.OperationType} on Array value");
}
}
e.cachedValue = (JToken)(object)val;
return ((JToken)val).ToObject<T>();
}
private static string RetrieveAndReturnStringValue(DataStorageElement e)
{
//IL_0031: Unknown result type (might be due to invalid IL or missing references)
//IL_0038: Invalid comparison between Unknown and I4
//IL_009e: Unknown result type (might be due to invalid IL or missing references)
//IL_00a4: Invalid comparison between Unknown and I4
if (e.cachedValue != null)
{
return (string)e.cachedValue;
}
JToken val = e.Context.GetData(e.Context.Key);
string text = (((int)val.Type == 10) ? null : ((object)val).ToString());
foreach (OperationSpecification operation in e.Operations)
{
switch (operation.OperationType)
{
case OperationType.Add:
text += (string)operation.Value;
break;
case OperationType.Mul:
if ((int)operation.Value.Type != 6)
{
throw new InvalidOperationException($"Cannot perform operation {OperationType.Mul} on string value, with a non interger value: {operation.Value}");
}
text = string.Concat(Enumerable.Repeat(text, (int)operation.Value));
break;
case OperationType.Replace:
text = (string)operation.Value;
break;
default:
throw new InvalidOperationException($"Cannot perform operation {operation.OperationType} on string value");
}
}
if (text == null)
{
e.cachedValue = (JToken)(object)JValue.CreateNull();
}
else
{
e.cachedValue = JToken.op_Implicit(text);
}
return (string)e.cachedValue;
}
private static T RetrieveAndReturnBoolValue<T>(DataStorageElement e)
{
if (e.cachedValue != null)
{
return e.cachedValue.ToObject<T>();
}
bool? flag = e.Context.GetData(e.Context.Key).ToObject<bool?>() ?? ((bool?)Activator.CreateInstance(typeof(T)));
foreach (OperationSpecification operation in e.Operations)
{
if (operation.OperationType == OperationType.Replace)
{
flag = (bool?)operation.Value;
continue;
}
throw new InvalidOperationException($"Cannot perform operation {operation.OperationType} on boolean value");
}
e.cachedValue = JToken.op_Implicit(flag);
if (!flag.HasValue)
{
return default(T);
}
return (T)Convert.ChangeType(flag.Value, IsNullable<T>() ? Nullable.GetUnderlyingType(typeof(T)) : typeof(T));
}
private static T RetrieveAndReturnDecimalValue<T>(DataStorageElement e)
{
if (e.cachedValue != null)
{
return e.cachedValue.ToObject<T>();
}
decimal? num = e.Context.GetData(e.Context.Key).ToObject<decimal?>();
if (!num.HasValue && !IsNullable<T>())
{
num = Activator.CreateInstance<decimal>();
}
foreach (OperationSpecification operation in e.Operations)
{
switch (operation.OperationType)
{
case OperationType.Replace:
num = (decimal)operation.Value;
break;
case OperationType.Add:
num += (decimal?)(decimal)operation.Value;
break;
case OperationType.Mul:
num *= (decimal?)(decimal)operation.Value;
break;
case OperationType.Mod:
num %= (decimal?)(decimal)operation.Value;
break;
case OperationType.Pow:
num = (decimal)Math.Pow((double)num.Value, (double)operation.Value);
break;
case OperationType.Max:
num = Math.Max(num.Value, (decimal)operation.Value);
break;
case OperationType.Min:
num = Math.Min(num.Value, (decimal)operation.Value);
break;
case OperationType.Xor:
num = (long)num.Value ^ (long)operation.Value;
break;
case OperationType.Or:
num = (long)num.Value | (long)operation.Value;
break;
case OperationType.And:
num = (long)num.Value & (long)operation.Value;
break;
case OperationType.LeftShift:
num = (long)num.Value << (int)operation.Value;
break;
case OperationType.RightShift:
num = (long)num.Value >> (int)operation.Value;
break;
case OperationType.Floor:
num = Math.Floor(num.Value);
break;
case OperationType.Ceil:
num = Math.Ceiling(num.Value);
break;
}
}
e.cachedValue = JToken.op_Implicit(num);
if (!num.HasValue)
{
return default(T);
}
return (T)Convert.ChangeType(num.Value, IsNullable<T>() ? Nullable.GetUnderlyingType(typeof(T)) : typeof(T));
}
private static bool IsNullable<T>()
{
if (typeof(T).IsGenericType)
{
return typeof(T).GetGenericTypeDefinition() == typeof(Nullable<>).GetGenericTypeDefinition();
}
return false;
}
public T To<T>()
{
if (Operations.Count != 0)
{
throw new InvalidOperationException("DataStorageElement.To<T>() cannot be used together with other operations on the DataStorageElement");
}
return Context.GetData(Context.Key).ToObject<T>();
}
public override string ToString()
{
return (Context?.ToString() ?? "(null)") + ", (" + ListOperations() + ")";
}
private string ListOperations()
{
if (Operations != null)
{
return string.Join(", ", Operations.Select((OperationSpecification o) => o.ToString()).ToArray());
}
return "none";
}
}
internal class DataStorageElementContext
{
internal string Key { get; set; }
internal Action<string, DataStorageHelper.DataStorageUpdatedHandler> AddHandler { get; set; }
internal Action<string, DataStorageHelper.DataStorageUpdatedHandler> RemoveHandler { get; set; }
internal Func<string, JToken> GetData { get; set; }
internal Action<string, JToken> Initialize { get; set; }
internal Func<string, Task<JToken>> GetAsync { get; set; }
public override string ToString()
{
return "Key: " + Key;
}
}
public class GameData
{
[JsonProperty("location_name_to_id")]
public Dictionary<string, long> LocationLookup { get; set; } = new Dictionary<string, long>();
[JsonProperty("item_name_to_id")]
public Dictionary<string, long> ItemLookup { get; set; } = new Dictionary<string, long>();
[Obsolete("use Checksum instead")]
[JsonProperty("version")]
public int Version { get; set; }
[JsonProperty("checksum")]
public string Checksum { get; set; }
}
public class Hint
{
[JsonProperty("receiving_player")]
public int ReceivingPlayer { get; set; }
[JsonProperty("finding_player")]
public int FindingPlayer { get; set; }
[JsonProperty("item")]
public long ItemId { get; set; }
[JsonProperty("location")]
public long LocationId { get; set; }
[JsonProperty("item_flags")]
public ItemFlags ItemFlags { get; set; }
[JsonProperty("found")]
public bool Found { get; set; }
[JsonProperty("entrance")]
public string Entrance { get; set; }
[JsonProperty("status")]
public HintStatus Status { get; set; }
}
public class ItemInfo
{
private readonly IItemInfoResolver itemInfoResolver;
public long ItemId { get; }
public long LocationId { get; }
public PlayerInfo Player { get; }
public ItemFlags Flags { get; }
public string ItemName => itemInfoResolver.GetItemName(ItemId, ItemGame);
public string ItemDisplayName => ItemName ?? $"Item: {ItemId}";
public string LocationName => itemInfoResolver.GetLocationName(LocationId, LocationGame);
public string LocationDisplayName => LocationName ?? $"Location: {LocationId}";
public string ItemGame { get; }
public string LocationGame { get; }
public ItemInfo(NetworkItem item, string receiverGame, string senderGame, IItemInfoResolver itemInfoResolver, PlayerInfo player)
{
this.itemInfoResolver = itemInfoResolver;
ItemGame = receiverGame;
LocationGame = senderGame;
ItemId = item.Item;
LocationId = item.Location;
Flags = item.Flags;
Player = player;
}
public SerializableItemInfo ToSerializable()
{
return new SerializableItemInfo
{
IsScout = (GetType() == typeof(ScoutedItemInfo)),
ItemId = ItemId,
LocationId = LocationId,
PlayerSlot = Player,
Player = Player,
Flags = Flags,
ItemGame = ItemGame,
ItemName = ItemName,
LocationGame = LocationGame,
LocationName = LocationName
};
}
}
public class ScoutedItemInfo : ItemInfo
{
public new PlayerInfo Player => base.Player;
public bool IsReceiverRelatedToActivePlayer { get; }
public ScoutedItemInfo(NetworkItem item, string receiverGame, string senderGame, IItemInfoResolver itemInfoResolver, IPlayerHelper players, PlayerInfo player)
: base(item, receiverGame, senderGame, itemInfoResolver, player)
{
IsReceiverRelatedToActivePlayer = (players.ActivePlayer ?? new PlayerInfo()).IsRelatedTo(player);
}
}
public class JsonMessagePart
{
[JsonProperty("type")]
[JsonConverter(typeof(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 = JToken.op_Implicit(i)
};
}
public static OperationSpecification Min(long i)
{
return new OperationSpecification
{
OperationType = OperationType.Min,
Value = JToken.op_Implicit(i)
};
}
public static OperationSpecification Min(float i)
{
return new OperationSpecification
{
OperationType = OperationType.Min,
Value = JToken.op_Implicit(i)
};
}
public static OperationSpecification Min(double i)
{
return new OperationSpecification
{
OperationType = OperationType.Min,
Value = JToken.op_Implicit(i)
};
}
public static OperationSpecification Min(decimal i)
{
return new OperationSpecification
{
OperationType = OperationType.Min,
Value = JToken.op_Implicit(i)
};
}
public static OperationSpecification Min(JToken i)
{
return new OperationSpecification
{
OperationType = OperationType.Min,
Value = i
};
}
public static OperationSpecification Min(BigInteger i)
{
return new OperationSpecification
{
OperationType = OperationType.Min,
Value = JToken.Parse(i.ToString())
};
}
public static OperationSpecification Max(int i)
{
return new OperationSpecification
{
OperationType = OperationType.Max,
Value = JToken.op_Implicit(i)
};
}
public static OperationSpecification Max(long i)
{
return new OperationSpecification
{
OperationType = OperationType.Max,
Value = JToken.op_Implicit(i)
};
}
public static OperationSpecification Max(float i)
{
return new OperationSpecification
{
OperationType = OperationType.Max,
Value = JToken.op_Implicit(i)
};
}
public static OperationSpecification Max(double i)
{
return new OperationSpecification
{
OperationType = OperationType.Max,
Value = JToken.op_Implicit(i)
};
}
public static OperationSpecification Max(decimal i)
{
return new OperationSpecification
{
OperationType = OperationType.Max,
Value = JToken.op_Implicit(i)
};
}
public static OperationSpecification Max(JToken i)
{
return new OperationSpecification
{
OperationType = OperationType.Max,
Value = i
};
}
public static OperationSpecification Max(BigInteger i)
{
return new OperationSpecification
{
OperationType = OperationType.Max,
Value = JToken.Parse(i.ToString())
};
}
public static OperationSpecification Remove(JToken value)
{
return new OperationSpecification
{
OperationType = OperationType.Remove,
Value = value
};
}
public static OperationSpecification Pop(int value)
{
return new OperationSpecification
{
OperationType = OperationType.Pop,
Value = JToken.op_Implicit(value)
};
}
public static OperationSpecification Pop(JToken value)
{
return new OperationSpecification
{
OperationType = OperationType.Pop,
Value = value
};
}
public static OperationSpecification Update(IDictionary dictionary)
{
return new OperationSpecification
{
OperationType = OperationType.Update,
Value = (JToken)(object)JObject.FromObject((object)dictionary)
};
}
public static OperationSpecification Floor()
{
return new OperationSpecification
{
OperationType = OperationType.Floor,
Value = null
};
}
public static OperationSpecification Ceiling()
{
return new OperationSpecification
{
OperationType = OperationType.Ceil,
Value = null
};
}
}
public static class Bitwise
{
public static OperationSpecification Xor(long i)
{
return new OperationSpecification
{
OperationType = OperationType.Xor,
Value = JToken.op_Implicit(i)
};
}
public static OperationSpecification Xor(BigInteger i)
{
return new OperationSpecification
{
OperationType = OperationType.Xor,
Value = JToken.Parse(i.ToString())
};
}
public static OperationSpecification Or(long i)
{
return new OperationSpecification
{
OperationType = OperationType.Or,
Value = JToken.op_Implicit(i)
};
}
public static OperationSpecification Or(BigInteger i)
{
return new OperationSpecification
{
OperationType = OperationType.Or,
Value = JToken.Parse(i.ToString())
};
}
public static OperationSpecification And(long i)
{
return new OperationSpecification
{
OperationType = OperationType.And,
Value = JToken.op_Implicit(i)
};
}
public static OperationSpecification And(BigInteger i)
{
return new OperationSpecification
{
OperationType = OperationType.And,
Value = JToken.Parse(i.ToString())
};
}
public static OperationSpecification LeftShift(long i)
{
return new OperationSpecification
{
OperationType = OperationType.LeftShift,
Value = JToken.op_Implicit(i)
};
}
public static OperationSpecification RightShift(long i)
{
return new OperationSpecification
{
OperationType = OperationType.RightShift,
Value = JToken.op_Implicit(i)
};
}
}
public class Callback
{
internal DataStorageHelper.DataStorageUpdatedHandler Method { get; set; }
private Callback()
{
}
public static Callback Add(DataStorageHelper.DataStorageUpdatedHandler callback)
{
return new Callback
{
Method = callback
};
}
}
public class AdditionalArgument
{
internal string Key { get; set; }
internal JToken Value { get; set; }
private AdditionalArgument()
{
}
public static AdditionalArgument Add(string name, JToken value)
{
return new AdditionalArgument
{
Key = name,
Value = value
};
}
}
public class MinimalSerializableItemInfo
{
public long ItemId { get; set; }
public long LocationId { get; set; }
public int PlayerSlot { get; set; }
public ItemFlags Flags { get; set; }
public string ItemGame { get; set; }
public string LocationGame { get; set; }
}
public class SerializableItemInfo : MinimalSerializableItemInfo
{
public bool IsScout { get; set; }
public PlayerInfo Player { get; set; }
public string ItemName { get; set; }
public string LocationName { get; set; }
[JsonIgnore]
public string ItemDisplayName => ItemName ?? $"Item: {base.ItemId}";
[JsonIgnore]
public string LocationDisplayName => LocationName ?? $"Location: {base.LocationId}";
public string ToJson(bool full = false)
{
//IL_005d: Unknown result type (might be due to invalid IL or missing references)
//IL_0062: Unknown result type (might be due to invalid IL or missing references)
//IL_0069: Unknown result type (might be due to invalid IL or missing references)
//IL_0071: Expected O, but got Unknown
MinimalSerializableItemInfo minimalSerializableItemInfo = this;
if (!full)
{
minimalSerializableItemInfo = new MinimalSerializableItemInfo
{
ItemId = base.ItemId,
LocationId = base.LocationId,
PlayerSlot = base.PlayerSlot,
Flags = base.Flags
};
if (IsScout)
{
minimalSerializableItemInfo.ItemGame = base.ItemGame;
}
else
{
minimalSerializableItemInfo.LocationGame = base.LocationGame;
}
}
JsonSerializerSettings val = new JsonSerializerSettings
{
NullValueHandling = (NullValueHandling)1,
Formatting = (Formatting)0
};
return JsonConvert.SerializeObject((object)minimalSerializableItemInfo, val);
}
public static SerializableItemInfo FromJson(string json, IArchipelagoSession session = null)
{
//IL_003c: Unknown result type (might be due to invalid IL or missing references)
//IL_0041: Unknown result type (might be due to invalid IL or missing references)
//IL_0050: Expected O, but got Unknown
ItemInfoStreamingContext additional = ((session != null) ? new ItemInfoStreamingContext
{
Items = session.Items,
Locations = session.Locations,
PlayerHelper = session.Players,
ConnectionInfo = session.ConnectionInfo
} : null);
JsonSerializerSettings val = new JsonSerializerSettings
{
Context = new StreamingContext(StreamingContextStates.Other, additional)
};
return JsonConvert.DeserializeObject<SerializableItemInfo>(json, val);
}
[OnDeserialized]
internal void OnDeserializedMethod(StreamingContext streamingContext)
{
if (base.ItemGame == null && base.LocationGame != null)
{
IsScout = false;
}
else if (base.ItemGame != null && base.LocationGame == null)
{
IsScout = true;
}
if (streamingContext.Context is ItemInfoStreamingContext itemInfoStreamingContext)
{
if (IsScout && base.LocationGame == null)
{
base.LocationGame = itemInfoStreamingContext.ConnectionInfo.Game;
}
else if (!IsScout && base.ItemGame == null)
{
base.ItemGame = itemInfoStreamingContext.ConnectionInfo.Game;
}
if (ItemName == null)
{
ItemName = itemInfoStreamingContext.Items.GetItemName(base.ItemId, base.ItemGame);
}
if (LocationName == null)
{
LocationName = itemInfoStreamingContext.Locations.GetLocationNameFromId(base.LocationId, base.LocationGame);
}
if (Player == null)
{
Player = itemInfoStreamingContext.PlayerHelper.GetPlayerInfo(base.PlayerSlot);
}
}
}
}
internal class ItemInfoStreamingContext
{
public IReceivedItemsHelper Items { get; set; }
public ILocationCheckHelper Locations { get; set; }
public IPlayerHelper PlayerHelper { get; set; }
public IConnectionInfoProvider ConnectionInfo { get; set; }
}
}
namespace Archipelago.MultiClient.Net.MessageLog.Parts
{
public class EntranceMessagePart : MessagePart
{
internal EntranceMessagePart(JsonMessagePart messagePart)
: base(MessagePartType.Entrance, messagePart, 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((object)packets);
byte[] messageBuffer = Encoding.UTF8.GetBytes(s);
int messagesCount = (int)Math.Ceiling((double)messageBuffer.Length / (double)bufferSize);
for (int i = 0; i < messagesCount; i++)
{
int num = bufferSize * i;
int num2 = bufferSize;
bool endOfMessage = i + 1 == messagesCount;
if (num2 * (i + 1) > messageBuffer.Length)
{
num2 = messageBuffer.Length - num;
}
await Socket.SendAsync(new ArraySegment<byte>(messageBuffer, num, num2), WebSocketMessageType.Text, endOfMessage, CancellationToken.None);
}
foreach (TaskCompletionSource<bool> item2 in tasks)
{
item2.TrySetResult(result: true);
}
OnPacketSend(packets);
}
private void OnPacketSend(ArchipelagoPacketBase[] packets)
{
try
{
if (this.PacketsSent != null)
{
this.PacketsSent(packets);
}
}
catch (Exception e)
{
OnError(e);
}
}
private void OnSocketClosed()
{
try
{
if (this.SocketClosed != null)
{
this.SocketClosed("");
}
}
catch (Exception e)
{
OnError(e);
}
}
private void OnMessageReceived(string message)
{
try
{
if (string.IsNullOrEmpty(message) || this.PacketReceived == null)
{
return;
}
List<ArchipelagoPacketBase> list = null;
try
{
list = JsonConvert.DeserializeObject<List<ArchipelagoPacketBase>>(message, (JsonConverter[])(object)new JsonConverter[1] { Converter });
}
catch (Exception e)
{
OnError(e);
}
if (list == null)
{
return;
}
foreach (ArchipelagoPacketBase item in list)
{
this.PacketReceived(item);
}
}
catch (Exception e2)
{
OnError(e2);
}
}
protected void OnError(Exception e)
{
try
{
if (this.ErrorReceived != null)
{
this.ErrorReceived(e, e.Message);
}
}
catch (Exception ex)
{
Console.Out.WriteLine("Error occured during reporting of errorOuter Errror: " + e.Message + " " + e.StackTrace + "Inner Errror: " + ex.Message + " " + ex.StackTrace);
}
}
}
public interface IConnectionInfoProvider
{
string Game { get; }
int Team { get; }
int Slot { get; }
string[] Tags { get; }
ItemsHandlingFlags ItemsHandlingFlags { get; }
string Uuid { get; }
void UpdateConnectionOptions(string[] tags);
void UpdateConnectionOptions(ItemsHandlingFlags itemsHandlingFlags);
void UpdateConnectionOptions(string[] tags, ItemsHandlingFlags itemsHandlingFlags);
}
public class ConnectionInfoHelper : IConnectionInfoProvider
{
private readonly IArchipelagoSocketHelper socket;
public string Game { get; private set; }
public int Team { get; private set; }
public int Slot { get; private set; }
public string[] Tags { get; internal set; }
public ItemsHandlingFlags ItemsHandlingFlags { get; internal set; }
public string Uuid { get; private set; }
internal ConnectionInfoHelper(IArchipelagoSocketHelper socket)
{
this.socket = socket;
Reset();
socket.PacketReceived += PacketReceived;
}
private void PacketReceived(ArchipelagoPacketBase packet)
{
if (!(packet is ConnectedPacket connectedPacket))
{
if (packet is ConnectionRefusedPacket)
{
Reset();
}
return;
}
Team = connectedPacket.Team;
Slot = connectedPacket.Slot;
if (connectedPacket.SlotInfo != null && connectedPacket.SlotInfo.ContainsKey(Slot))
{
Game = connectedPacket.SlotInfo[Slot].Game;
}
}
internal void SetConnectionParameters(string game, string[] tags, ItemsHandlingFlags itemsHandlingFlags, string uuid)
{
Game = game;
Tags = tags ?? new string[0];
ItemsHandlingFlags = itemsHandlingFlags;
Uuid = uuid ?? Guid.NewGuid().ToString();
}
private void Reset()
{
Game = null;
Team = -1;
Slot = -1;
Tags = new string[0];
ItemsHandlingFlags = ItemsHandlingFlags.NoItems;
Uuid = null;
}
public void UpdateConnectionOptions(string[] tags)
{
UpdateConnectionOptions(tags, ItemsHandlingFlags);
}
public void UpdateConnectionOptions(ItemsHandlingFlags itemsHandlingFlags)
{
UpdateConnectionOptions(Tags, itemsHandlingFlags);
}
public void UpdateConnectionOptions(string[] tags, ItemsHandlingFlags itemsHandlingFlags)
{
SetConnectionParameters(Game, tags, itemsHandlingFlags, Uuid);
socket.SendPacket(new ConnectUpdatePacket
{
Tags = Tags,
ItemsHandling = ItemsHandlingFlags
});
}
}
public interface IDataStorageHelper : IDataStorageWrapper
{
DataStorageElement this[Scope scope, string key] { get; set; }
DataStorageElement this[string key] { get; set; }
}
public class DataStorageHelper : IDataStorageHelper, IDataStorageWrapper
{
public delegate void DataStorageUpdatedHandler(JToken originalValue, JToken newValue, Dictionary<string, JToken> additionalArguments);
private readonly Dictionary<string, DataStorageUpdatedHandler> onValueChangedEventHandlers = new Dictionary<string, DataStorageUpdatedHandler>();
private readonly Dictionary<Guid, DataStorageUpdatedHandler> operationSpecificCallbacks = new Dictionary<Guid, DataStorageUpdatedHandler>();
private readonly Dictionary<string, TaskCompletionSource<JToken>> asyncRetrievalTasks = new Dictionary<string, TaskCompletionSource<JToken>>();
private readonly IArchipelagoSocketHelper socket;
private readonly IConnectionInfoProvider connectionInfoProvider;
public DataStorageElement this[Scope scope, string key]
{
get
{
return this[AddScope(scope, key)];
}
set
{
this[AddScope(scope, key)] = value;
}
}
public DataStorageElement this[string key]
{
get
{
return new DataStorageElement(GetContextForKey(key));
}
set
{
SetValue(key, value);
}
}
internal DataStorageHelper(IArchipelagoSocketHelper socket, IConnectionInfoProvider connectionInfoProvider)
{
this.socket = socket;
this.connectionInfoProvider = connectionInfoProvider;
socket.PacketReceived += OnPacketReceived;
}
private void OnPacketReceived(ArchipelagoPacketBase packet)
{
//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
//IL_00b9: Invalid comparison between Unknown and I4
if (!(packet is RetrievedPacket retrievedPacket))
{
if (packet is SetReplyPacket setReplyPacket)
{
if (setReplyPacket.AdditionalArguments != null && setReplyPacket.AdditionalArguments.ContainsKey("Reference") && (int)setReplyPacket.AdditionalArguments["Reference"].Type == 8 && ((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, (JToken)(object)JValue.CreateNull());
}
if (e.Context == null)
{
e.Context = GetContextForKey(key);
}
else if (e.Context.Key != key)
{
e.Operations.Insert(0, new OperationSpecification
{
OperationType = OperationType.Replace,
Value = GetValue(e.Context.Key)
});
}
Dictionary<string, JToken> dictionary = e.AdditionalArguments ?? new Dictionary<string, JToken>(0);
if (e.Callbacks != null)
{
Guid key2 = Guid.NewGuid();
operationSpecificCallbacks[key2] = e.Callbacks;
dictionary["Reference"] = JToken.op_Implicit(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>());