Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of Silksong BingoSync v1.2.1
plugins/Silksong.BingoSync.dll
Decompiled 3 weeks agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Serialization; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Threading; using System.Threading.Tasks; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using BingoAPI.Conditions; using BingoAPI.Events; using BingoAPI.Goals; using BingoAPI.Helpers; using BingoAPI.Models; using BingoAPI.Models.Settings; using BingoAPI.Networking; using HarmonyLib; using Microsoft.CodeAnalysis; using Newtonsoft.Json; using Newtonsoft.Json.Converters; using Silksong.BingoSync.Configurations; using Silksong.BingoSync.Data; using Silksong.BingoSync.Exceptions; using Silksong.BingoSync.Extensions; using Silksong.BingoSync.Helpers; using Silksong.BingoSync.Patches; using Silksong.BingoSync.UI.Components; using Silksong.BingoSync.UI.Constants; using Silksong.BingoSync.UI.Containers; using Silksong.BingoSync.UI.Items; using Silksong.BingoSync.UI.Menus; using Silksong.ModMenu.Elements; using Silksong.ModMenu.Plugin; using Silksong.ModMenu.Screens; using UnityEngine; using UnityEngine.Events; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("WarperSan")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("Connects Silksong to BingoSync, letting you play bingo directly in-game")] [assembly: AssemblyFileVersion("1.2.1.0")] [assembly: AssemblyInformationalVersion("1.2.1+ba48522cc26b3a1d273431498be59bf018289fee")] [assembly: AssemblyProduct("Silksong.BingoSync")] [assembly: AssemblyTitle("Silksong.BingoSync")] [assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/WarperSan/Silksong.BingoSync")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace BepInEx { [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] [Conditional("CodeGeneration")] internal sealed class BepInAutoPluginAttribute : Attribute { public BepInAutoPluginAttribute(string? id = null, string? name = null, string? version = null) { } } } namespace BepInEx.Preloader.Core.Patching { [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] [Conditional("CodeGeneration")] internal sealed class PatcherAutoPluginAttribute : Attribute { public PatcherAutoPluginAttribute(string? id = null, string? name = null, string? version = null) { } } } namespace Silksong.BingoSync { internal class Controller : IDisposable { public delegate void CardCallback(Card? card); public GoalPool Pool = new GoalPool(); public readonly EventDispatcher Events; private readonly Session _session; private Card? _card; private Task<Card?>? _runningCardUpdate; private readonly GoalTracker _tracker; public Team Team => _session.Team; public bool IsConnected => _session.IsInRoom; public event CardCallback? OnCardUpdated; public Controller() { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Expected O, but got Unknown //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Expected O, but got Unknown //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Expected O, but got Unknown //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Expected O, but got Unknown //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Expected O, but got Unknown Events = new EventDispatcher(); SubscribeToEvents(Events); _tracker = new GoalTracker(); _tracker.OnGoalMarked += new GoalChangedCallback(OnGoalMarked); _tracker.OnGoalCleared += new GoalChangedCallback(OnGoalCleared); _session = new Session(Events); } private void SubscribeToEvents(EventDispatcher events) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Expected O, but got Unknown //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Expected O, but got Unknown //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Expected O, but got Unknown //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Expected O, but got Unknown //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Expected O, but got Unknown //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Expected O, but got Unknown //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Expected O, but got Unknown events.OnSelfConnected += new ConnectionCallback(OnConnected); events.OnSelfSquareMarked += new MarkCallback(OnSquareMarked); events.OnOtherSquareMarked += new MarkCallback(OnSquareMarked); events.OnSelfSquareCleared += new ClearCallback(OnSquareCleared); events.OnOtherSquareCleared += new ClearCallback(OnSquareCleared); events.OnSelfCardGenerated += new GenerateCallback(OnCardGenerated); events.OnOtherCardGenerated += new GenerateCallback(OnCardGenerated); } private void UnsubscribeFromEvents(EventDispatcher events) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Expected O, but got Unknown //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Expected O, but got Unknown //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Expected O, but got Unknown //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Expected O, but got Unknown //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Expected O, but got Unknown //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Expected O, but got Unknown //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Expected O, but got Unknown events.OnSelfConnected -= new ConnectionCallback(OnConnected); events.OnSelfSquareMarked -= new MarkCallback(OnSquareMarked); events.OnOtherSquareMarked -= new MarkCallback(OnSquareMarked); events.OnSelfSquareCleared -= new ClearCallback(OnSquareCleared); events.OnOtherSquareCleared -= new ClearCallback(OnSquareCleared); events.OnSelfCardGenerated -= new GenerateCallback(OnCardGenerated); events.OnOtherCardGenerated -= new GenerateCallback(OnCardGenerated); } private void OnConnected(Player player) { UpdateCard(); } private void OnGoalMarked(Goal goal) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) if (_card == null) { return; } int[] array = _card.FindByGoal(goal); int[] array2 = array; foreach (int num in array2) { if (!_card.IsMarkedBy(num, _session.Team)) { _session.MarkSquare(num, default(CancellationToken)); } } } private void OnGoalCleared(Goal goal) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) if (_card == null) { return; } int[] array = _card.FindByGoal(goal); int[] array2 = array; foreach (int num in array2) { if (_card.IsMarkedBy(num, _session.Team)) { _session.ClearSquare(num, default(CancellationToken)); } } } private void OnSquareMarked(Player player, Square square, Team team) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) Card? card = _card; if (card != null) { card.Mark(square.Slot.Index, team); } this.OnCardUpdated?.Invoke(_card); } private void OnSquareCleared(Player player, Square square, Team team) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) Card? card = _card; if (card != null) { card.Unmark(square.Slot.Index, team); } this.OnCardUpdated?.Invoke(_card); } private void OnCardGenerated(Player player, bool isHidden) { UpdateCard(); } public Task<bool> Join(JoinRoomSettings settings) { return _session.JoinRoom(settings, default(CancellationToken)); } public Task<bool> Exit() { return _session.LeaveRoom(default(CancellationToken)); } public Task<bool> SetTeam(Team team) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) return _session.ChangeTeam(team, default(CancellationToken)); } private void UpdateCard() { if (_runningCardUpdate != null && !_runningCardUpdate.IsCompleted) { Log.Warning("An update of 'Card' is already pending."); return; } _runningCardUpdate = Task.Run(() => _session.GetCard(Pool, default(CancellationToken))); _runningCardUpdate.ContinueWith(delegate(Task<Card?> task) { Card result = task.Result; _tracker.Clear(); if (result != null) { Goal[] allGoals = result.GetAllGoals(); foreach (Goal val in allGoals) { _tracker.TryAdd(val); } } _card = result; this.OnCardUpdated?.Invoke(_card); }); } public void Evaluate() { _tracker.Evaluate(); } public void Dispose() { UnsubscribeFromEvents(Events); _session.Dispose(); } } internal static class ConfigMenu { public static AbstractMenuScreen Create(Configuration configuration) { //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Expected O, but got Unknown //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Expected O, but got Unknown AbstractMenuScreen[] array = (AbstractMenuScreen[])(object)new AbstractMenuScreen[4] { CreateGeneralConfig(configuration.General), CreateJoinConfig(configuration.Join), CreateBoardConfig(configuration.Board), CreateExperimentalConfig(configuration.Experimental) }; PaginatedMenuScreenBuilder val = new PaginatedMenuScreenBuilder(LocalizedText.op_Implicit(Plugin.Name), 8); AbstractMenuScreen[] array2 = array; foreach (AbstractMenuScreen val2 in array2) { TextButton val3 = new TextButton(val2); val.Add((MenuElement)(object)val3); } return (AbstractMenuScreen)(object)val.Build(); } private static AbstractMenuScreen CreateGeneralConfig(GeneralConfig config) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown PaginatedMenuScreenBuilder val = new PaginatedMenuScreenBuilder(LocalizedText.op_Implicit("General"), 8); MenuElement val2 = default(MenuElement); if (ConfigEntryFactory.GenerateBoolElement((ConfigEntryBase)(object)config.UseAdvancedTeams, ref val2)) { val.Add(val2); } return (AbstractMenuScreen)(object)val.Build(); } private static AbstractMenuScreen CreateJoinConfig(JoinConfig config) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown PaginatedMenuScreenBuilder val = new PaginatedMenuScreenBuilder(LocalizedText.op_Implicit("Join"), 8); MenuElement val2 = default(MenuElement); if (ConfigEntryFactory.GenerateStringElement((ConfigEntryBase)(object)config.Nickname, ref val2)) { val.Add(val2); } MenuElement val3 = default(MenuElement); if (ConfigEntryFactory.GenerateKeyCodeElement((ConfigEntryBase)(object)config.ToggleUI, ref val3)) { val.Add(val3); } return (AbstractMenuScreen)(object)val.Build(); } private static AbstractMenuScreen CreateBoardConfig(BoardConfig config) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown PaginatedMenuScreenBuilder val = new PaginatedMenuScreenBuilder(LocalizedText.op_Implicit("Board"), 8); MenuElement val2 = default(MenuElement); if (ConfigEntryFactory.GenerateKeyCodeElement((ConfigEntryBase)(object)config.ToggleUI, ref val2)) { val.Add(val2); } return (AbstractMenuScreen)(object)val.Build(); } private static AbstractMenuScreen CreateExperimentalConfig(ExperimentalConfig config) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Expected O, but got Unknown //IL_0027: Unknown result type (might be due to invalid IL or missing references) PaginatedMenuScreenBuilder val = new PaginatedMenuScreenBuilder(LocalizedText.op_Implicit("Experimental"), 8); TextLabel val2 = new TextLabel(LocalizedText.op_Implicit("Theses settings are experimental and can cause performance issues")); ((Graphic)val2.Text).color = Color.yellow; val2.Text.fontSize = 30; val.Add((MenuElement)(object)val2); MenuElement val3 = default(MenuElement); if (ConfigEntryFactory.GenerateBoolElement((ConfigEntryBase)(object)config.EvaluateOnHeroUpdate, ref val3)) { val.Add(val3); } return (AbstractMenuScreen)(object)val.Build(); } } [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInPlugin("dev.warpersan.silksong.bingosync", "Silksong.BingoSync", "1.2.1")] public class Plugin : BaseUnityPlugin, IModMenuCustomMenu, IModMenuInterface { internal static readonly Controller Controller = new Controller(); public const string Id = "dev.warpersan.silksong.bingosync"; public static string Name => "Silksong.BingoSync"; public static string Version => "1.2.1"; public AbstractMenuScreen BuildCustomMenu() { return ConfigMenu.Create(Configuration.SafeInstance); } private void Awake() { Log.Logger = Log.LogCore; Configuration.Load(((BaseUnityPlugin)this).Config); Patch.ApplyAll(); Log.Info("dev.warpersan.silksong.bingosync v" + Version + " has loaded!"); } private void Start() { ConditionAttribute.AddAll(); string absolutePath = Silksong.BingoSync.Helpers.Path.GetAbsolutePath("Goals/"); GoalPool val = GoalLoader.LoadPoolFromFolder(absolutePath); List<object> list = new List<object>(); foreach (Goal item in val) { list.Add(new { name = item.Name }); } Log.Info(JsonConvert.SerializeObject((object)list)); Controller.Pool = val; Log.Info($"Loaded '{val.Count}' goals."); } } } namespace Silksong.BingoSync.UI.Menus { internal class ConnectionMenu : MonoBehaviour { private enum State { Offline, Connecting, Online, Disconnecting } private State _state; private CanvasGroup? _canvasGroup; private Button? _actionButton; private JoinForm? _joinForm; private TeamPicker? _teamPicker; private void SetOnline() { //IL_003c: Unknown result type (might be due to invalid IL or missing references) _state = State.Online; _joinForm?.DisableInputs(); if ((Object)(object)_teamPicker != (Object)null) { _teamPicker.EnableInputs(); _teamPicker.SetTeam(Plugin.Controller.Team); } } private void SetOffline() { _state = State.Offline; _joinForm?.EnableInputs(); if ((Object)(object)_teamPicker != (Object)null) { _teamPicker.DisableInputs(); _teamPicker.SetTeam((Team)0); } } private void OnActionClicked() { State state = _state; if ((state == State.Connecting || state == State.Disconnecting) ? true : false) { Log.Warning($"State '{_state}' has no action assigned."); } else if (_state == State.Offline) { JoinRoom(); } else if (_state == State.Online) { LeaveRoom(); } } private void OnTeamSelected(Team team) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) if (_state != State.Online) { Log.Warning("Cannot change team without being online."); } else { ChangeTeam(team); } } private void ToggleVisibility() { if (!((Object)(object)_canvasGroup == (Object)null)) { bool flag = _canvasGroup.alpha > 0f; _canvasGroup.alpha = (flag ? 0f : 1f); } } private void Update() { switch (_state) { case State.Offline: _actionButton?.SetText("Join"); break; case State.Connecting: _actionButton?.SetText("Connecting..."); break; case State.Online: _actionButton?.SetText("Leave"); break; case State.Disconnecting: _actionButton?.SetText("Disconnecting..."); break; default: throw new ArgumentOutOfRangeException(); } } private async Task JoinRoom() { if (_state != State.Offline) { throw new InvalidOperationException(); } if ((Object)(object)_joinForm == (Object)null) { throw new NullReferenceException("No 'JoinForm' assigned."); } _joinForm.DisableInputs(); JoinRoomSettings settings = _joinForm.GetSettings(); try { _state = State.Connecting; if (!(await Plugin.Controller.Join(settings))) { SetOffline(); Log.Error("Failed to join the room '" + settings.Code + "'."); } else { SetOnline(); } } catch (Exception arg) { SetOffline(); Log.Error($"Error while joining the room '{settings.Code}': {arg}"); } } private async Task LeaveRoom() { if (_state != State.Online) { throw new InvalidOperationException(); } _teamPicker?.DisableInputs(); try { _state = State.Disconnecting; if (!(await Plugin.Controller.Exit())) { SetOnline(); Log.Error("Failed to exit the room."); } else { SetOffline(); } } catch (Exception arg) { SetOnline(); Log.Error($"Error while joining the room: {arg}"); } } private async Task ChangeTeam(Team team) { //IL_0016: 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) if (_state != State.Online) { throw new InvalidOperationException(); } Controller controller = Plugin.Controller; if (controller == null) { throw new NullReferenceException("No 'Controller' assigned."); } if ((Object)(object)_teamPicker == (Object)null) { throw new NullReferenceException("No 'TeamPicker' assigned."); } _teamPicker.DisableInputs(); try { if (!(await controller.SetTeam(team))) { Log.Error("Failed to change team."); } } catch (Exception arg) { Log.Error($"Error while joining the room: {arg}"); } _teamPicker.SetTeam(controller.Team); _teamPicker.EnableInputs(); } public static ConnectionMenu Create(JoinRoomSettings settings) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("ConnectionMenu"); ConnectionMenu connectionMenu = val.AddComponent<ConnectionMenu>(); RectTransform val2 = val.AddComponent<RectTransform>(); val2.anchorMin = Vector2.zero; val2.anchorMax = Vector2.one; val2.offsetMin = Vector2.zero; val2.offsetMax = Vector2.zero; VerticalLayoutGroup val3 = val.AddComponent<VerticalLayoutGroup>(); ((HorizontalOrVerticalLayoutGroup)val3).spacing = 10f; ((LayoutGroup)val3).childAlignment = (TextAnchor)7; ((HorizontalOrVerticalLayoutGroup)val3).childControlWidth = true; ((HorizontalOrVerticalLayoutGroup)val3).childForceExpandWidth = true; ((HorizontalOrVerticalLayoutGroup)val3).childControlHeight = false; ((HorizontalOrVerticalLayoutGroup)val3).childForceExpandHeight = false; connectionMenu._canvasGroup = val.AddComponent<CanvasGroup>(); JoinForm joinForm = JoinForm.Create(); ((Component)joinForm).transform.SetParent(((Component)val3).transform, false); joinForm.SetSettings(settings); connectionMenu._joinForm = joinForm; TeamPicker teamPicker = TeamPicker.Create(connectionMenu.OnTeamSelected); ((Component)teamPicker).transform.SetParent(((Component)val3).transform, false); connectionMenu._teamPicker = teamPicker; Button button = Button.Create(connectionMenu.OnActionClicked); ((Component)button).transform.SetParent(val.transform, false); connectionMenu._actionButton = button; CallOnInput callOnInput = val.AddComponent<CallOnInput>(); callOnInput.SetInput(Configuration.SafeInstance.Join.ToggleUI, connectionMenu.ToggleVisibility); connectionMenu.SetOffline(); return connectionMenu; } } } namespace Silksong.BingoSync.UI.Items { internal class BingoCell : MonoBehaviour { private Text? _text; private Dictionary<Team, Image>? _teamMarks; public void SetSquare(Goal goal, Team teams) { //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) Text? text = _text; if (text != null) { text.text = goal.Name; } if (_teamMarks == null) { return; } foreach (KeyValuePair<Team, Image> teamMark in _teamMarks) { teamMark.Deconstruct(out var key, out var value); Team val = key; Image val2 = value; bool active = ((Enum)teams).HasFlag((Enum)(object)val); ((Component)val2).gameObject.SetActive(active); } } public void AddTeam(Team team) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) if (_teamMarks != null && _teamMarks.TryGetValue(team, out Image value)) { ((Component)value).gameObject.SetActive(true); } } public void RemoveTeam(Team team) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) if (_teamMarks != null && _teamMarks.TryGetValue(team, out Image value)) { ((Component)value).gameObject.SetActive(false); } } public static BingoCell Create() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Expected O, but got Unknown //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Expected O, but got Unknown //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Expected O, but got Unknown //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_0154: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Expected O, but got Unknown //IL_0179: Unknown result type (might be due to invalid IL or missing references) //IL_0185: Unknown result type (might be due to invalid IL or missing references) //IL_0191: Unknown result type (might be due to invalid IL or missing references) //IL_019b: Unknown result type (might be due to invalid IL or missing references) //IL_01a7: Unknown result type (might be due to invalid IL or missing references) //IL_01ac: Unknown result type (might be due to invalid IL or missing references) //IL_01b6: Unknown result type (might be due to invalid IL or missing references) //IL_01e8: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("BingoCell"); val.AddComponent<RectTransform>(); BingoCell bingoCell = val.AddComponent<BingoCell>(); GameObject val2 = new GameObject("Background"); val2.transform.SetParent(val.transform, false); Image val3 = val2.AddComponent<Image>(); ((Graphic)val3).color = new Color(0.1f, 0.1f, 0.1f, 1f); VerticalLayoutGroup val4 = val2.AddComponent<VerticalLayoutGroup>(); ((LayoutGroup)val4).childAlignment = (TextAnchor)4; Dictionary<Team, Image> dictionary = new Dictionary<Team, Image>(); foreach (Team value in Enum.GetValues(typeof(Team))) { if ((int)value != 0) { GameObject val6 = new GameObject(((object)value/*cast due to .constrained prefix*/).ToString()); val6.transform.SetParent(((Component)val4).transform, false); Image val7 = val6.AddComponent<Image>(); ((Graphic)val7).color = Colors.GetColor(value); dictionary.Add(value, val7); } } GameObject val8 = new GameObject("Darkener"); val8.transform.SetParent(val.transform, false); Image val9 = val8.AddComponent<Image>(); ((Graphic)val9).color = new Color(0f, 0f, 0f, 0.4f); GameObject val10 = new GameObject("Text"); val10.transform.SetParent(val.transform, false); RectTransform val11 = val10.AddComponent<RectTransform>(); val11.anchorMin = Vector2.zero; val11.anchorMax = Vector2.one; val11.offsetMin = Vector2.one * 5f; val11.offsetMax = -Vector2.one * 5f; Text val12 = val10.AddComponent<Text>(); val12.fontSize = 12; val12.text = "OwO"; val12.alignment = (TextAnchor)3; ((Graphic)val12).color = Color.white; val12.font = Fonts.Normal; bingoCell._text = val12; bingoCell._teamMarks = dictionary; return bingoCell; } } internal class TeamPickerButton : MonoBehaviour { private Outline? _outline; private Action<Team>? _onClick; public Team Team { get; private set; } public void Select() { //IL_0014: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_outline != (Object)null) { ((Shadow)_outline).effectColor = Color.white; } } public void Unselect() { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_outline != (Object)null) { ((Shadow)_outline).effectColor = Team.GetColor(); } } private void OnClick() { //IL_000c: Unknown result type (might be due to invalid IL or missing references) _onClick?.Invoke(Team); } public static TeamPickerButton Create(Team team, Action<Team> onClick) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //IL_001a: Unknown result type (might be due to invalid IL or missing references) //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_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Expected O, but got Unknown //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Expected O, but got Unknown //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("TeamPickerButton"); val.AddComponent<RectTransform>(); TeamPickerButton teamPickerButton = val.AddComponent<TeamPickerButton>(); teamPickerButton.Team = team; teamPickerButton._onClick = onClick; Image val2 = val.AddComponent<Image>(); Color black = Color.black; black.a = 0.6f; ((Graphic)val2).color = black; Button val3 = val.AddComponent<Button>(); ((Selectable)val3).targetGraphic = (Graphic)(object)val2; ((UnityEvent)val3.onClick).AddListener(new UnityAction(teamPickerButton.OnClick)); ColorBlock colors = ((Selectable)val3).colors; ((ColorBlock)(ref colors)).disabledColor = new Color(0.3f, 0.3f, 0.3f, 1f); ((Selectable)val3).colors = colors; Outline outline = ((Component)val3).gameObject.AddComponent<Outline>(); GameObject val4 = new GameObject("Text"); val4.transform.SetParent(val.transform, false); RectTransform val5 = val4.AddComponent<RectTransform>(); val5.anchorMin = Vector2.zero; val5.anchorMax = Vector2.one; val5.offsetMin = Vector2.zero; val5.offsetMax = Vector2.zero; Text val6 = val4.AddComponent<Text>(); val6.font = Fonts.Normal; val6.fontSize = 17; ((Graphic)val6).color = Color.white; val6.alignment = (TextAnchor)4; val6.text = team.GetDisplayName(); teamPickerButton._outline = outline; teamPickerButton.Unselect(); return teamPickerButton; } } } namespace Silksong.BingoSync.UI.Containers { public class BingoBoard : MonoBehaviour { private BingoCell[]? _cells; private void Awake() { Subscribe(Plugin.Controller); } private void DisplayCard(Card? card) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) if (card != null && _cells != null) { for (int i = 0; i < _cells.Length; i++) { Goal goalAt = card.GetGoalAt(i); Team teamsAt = card.GetTeamsAt(i); _cells[i].SetSquare(goalAt, teamsAt); } } } private void Subscribe(Controller controller) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Expected O, but got Unknown //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Expected O, but got Unknown //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Expected O, but got Unknown //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Expected O, but got Unknown controller.OnCardUpdated += DisplayCard; EventDispatcher events = controller.Events; events.OnSelfSquareMarked += new MarkCallback(OnSquareMarked); events.OnOtherSquareMarked += new MarkCallback(OnSquareMarked); events.OnSelfSquareCleared += new ClearCallback(OnSquareCleared); events.OnOtherSquareCleared += new ClearCallback(OnSquareCleared); } private void OnSquareMarked(Player player, Square square, Team team) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) BingoCell[]? cells = _cells; if (cells != null) { cells[square.Slot.Index].AddTeam(team); } } private void OnSquareCleared(Player player, Square square, Team team) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) BingoCell[]? cells = _cells; if (cells != null) { cells[square.Slot.Index].RemoveTeam(team); } } public static BingoBoard Create() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("BingoBoard"); RectTransform val2 = val.AddComponent<RectTransform>(); val2.anchorMax = Vector2.one; val2.anchorMin = Vector2.one; val2.pivot = Vector2.one; ContentSizeFitter val3 = val.AddComponent<ContentSizeFitter>(); val3.horizontalFit = (FitMode)2; val3.verticalFit = (FitMode)2; Image val4 = val.AddComponent<Image>(); ((Graphic)val4).color = Color.black; BingoBoard bingoBoard = val.AddComponent<BingoBoard>(); GridLayoutGroup val5 = val.AddComponent<GridLayoutGroup>(); val5.cellSize = Vector2.one * 100f; val5.constraint = (Constraint)1; val5.constraintCount = 5; ((LayoutGroup)val5).childAlignment = (TextAnchor)0; val5.spacing = Vector2.one * 5f; BingoCell[] array = new BingoCell[25]; for (int i = 0; i < array.Length; i++) { BingoCell bingoCell = BingoCell.Create(); ((Component)bingoCell).transform.SetParent(((Component)val5).transform, false); array[i] = bingoCell; } bingoBoard._cells = array; CanvasGroup val6 = val.AddComponent<CanvasGroup>(); val6.blocksRaycasts = false; return bingoBoard; } } internal class BoardContainer : MonoBehaviour { private BingoBoard? _board; private CallOnInput? _toggleInput; private void Awake() { Subscribe(Plugin.Controller.Events); } private void ToggleVisibility() { if (!((Object)(object)_board == (Object)null)) { bool activeInHierarchy = ((Component)_board).gameObject.activeInHierarchy; SetVisibility(!activeInHierarchy); } } private void SetVisibility(bool isVisible) { if (!((Object)(object)_board == (Object)null)) { ((Component)_board).gameObject.SetActive(isVisible); } } private void EnableVisibility() { if ((Object)(object)_toggleInput != (Object)null) { ((Behaviour)_toggleInput).enabled = true; } SetVisibility(isVisible: true); } private void DisableVisibility() { if ((Object)(object)_toggleInput != (Object)null) { ((Behaviour)_toggleInput).enabled = false; } SetVisibility(isVisible: false); } private void Subscribe(EventDispatcher dispatcher) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Expected O, but got Unknown //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Expected O, but got Unknown dispatcher.OnSelfConnected += (ConnectionCallback)delegate { EnableVisibility(); }; dispatcher.OnSelfDisconnected += (DisconnectionCallback)delegate { DisableVisibility(); }; } public static BoardContainer Create() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("BoardContainer"); BoardContainer boardContainer = val.AddComponent<BoardContainer>(); RectTransform val2 = val.AddComponent<RectTransform>(); val2.anchorMin = Vector2.zero; val2.anchorMax = Vector2.one; val2.offsetMin = Vector2.zero; val2.offsetMax = Vector2.zero; CallOnInput callOnInput = val.AddComponent<CallOnInput>(); callOnInput.SetInput(Configuration.SafeInstance.Board.ToggleUI, boardContainer.ToggleVisibility); boardContainer._toggleInput = callOnInput; BingoBoard bingoBoard = BingoBoard.Create(); ((Component)bingoBoard).transform.SetParent((Transform)(object)val2, false); boardContainer._board = bingoBoard; boardContainer.DisableVisibility(); return boardContainer; } } internal class JoinForm : MonoBehaviour { private CanvasGroup? _canvasGroup; private TextField? _roomCodeInput; private TextField? _nicknameInput; private TextField? _passwordInput; public void SetSettings(JoinRoomSettings settings) { if ((Object)(object)_roomCodeInput != (Object)null) { _roomCodeInput.Text = settings.Code; } if ((Object)(object)_nicknameInput != (Object)null) { _nicknameInput.Text = settings.Nickname; } if ((Object)(object)_passwordInput != (Object)null) { _passwordInput.Text = settings.Password; } } public JoinRoomSettings GetSettings() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Expected O, but got Unknown JoinRoomSettings val = new JoinRoomSettings(); if ((Object)(object)_roomCodeInput != (Object)null) { string text = _roomCodeInput.Text; string text2 = default(string); if (Network.TryGetRoomCode(text, ref text2)) { text = text2; } val.Code = text; } if ((Object)(object)_nicknameInput != (Object)null) { val.Nickname = _nicknameInput.Text; } if ((Object)(object)_passwordInput != (Object)null) { val.Password = _passwordInput.Text; } return val; } public void EnableInputs() { if (!((Object)(object)_canvasGroup == (Object)null)) { _canvasGroup.interactable = true; } } public void DisableInputs() { if (!((Object)(object)_canvasGroup == (Object)null)) { _canvasGroup.interactable = false; } } public static JoinForm Create() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //IL_0024: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("JoinForm"); JoinForm joinForm = val.AddComponent<JoinForm>(); RectTransform val2 = val.AddComponent<RectTransform>(); val2.pivot = new Vector2(0.5f, 0f); ContentSizeFitter val3 = val.AddComponent<ContentSizeFitter>(); val3.verticalFit = (FitMode)2; VerticalLayoutGroup val4 = val.AddComponent<VerticalLayoutGroup>(); ((HorizontalOrVerticalLayoutGroup)val4).childControlWidth = true; ((HorizontalOrVerticalLayoutGroup)val4).childForceExpandWidth = true; ((HorizontalOrVerticalLayoutGroup)val4).childControlHeight = false; ((HorizontalOrVerticalLayoutGroup)val4).childForceExpandHeight = false; ((HorizontalOrVerticalLayoutGroup)val4).spacing = 10f; joinForm._canvasGroup = val.AddComponent<CanvasGroup>(); TextField textField = TextField.Create("Room Code / Link", (ContentType)0); ((Component)textField).transform.SetParent(val.transform, false); joinForm._roomCodeInput = textField; TextField textField2 = TextField.Create("Nickname", (ContentType)0); ((Component)textField2).transform.SetParent(val.transform, false); joinForm._nicknameInput = textField2; TextField textField3 = TextField.Create("Password", (ContentType)7); ((Component)textField3).transform.SetParent(val.transform, false); joinForm._passwordInput = textField3; return joinForm; } } internal class TeamPicker : MonoBehaviour { private CanvasGroup? _canvasGroup; private Dictionary<Team, TeamPickerButton>? _buttons; private Action<Team>? _onTeamSelected; private Team _team; public void SetTeam(Team team) { //IL_0002: 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_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) if (TryGetButton(_team, out TeamPickerButton button)) { button.Unselect(); } if (TryGetButton(team, out TeamPickerButton button2)) { button2.Select(); } _team = team; } public void EnableInputs() { if (!((Object)(object)_canvasGroup == (Object)null)) { _canvasGroup.interactable = true; } } public void DisableInputs() { if (!((Object)(object)_canvasGroup == (Object)null)) { _canvasGroup.interactable = false; } } private bool TryGetButton(Team team, [NotNullWhen(true)] out TeamPickerButton? button) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) if (_buttons == null) { button = null; return false; } return _buttons.TryGetValue(team, out button); } private void OnTeamSelected(Team team) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) _onTeamSelected?.Invoke(team); } public static TeamPicker Create(Action<Team> onTeamSelected) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //IL_0024: 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_0052: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("TeamPicker"); TeamPicker teamPicker = val.AddComponent<TeamPicker>(); RectTransform val2 = val.AddComponent<RectTransform>(); val2.pivot = new Vector2(0.5f, 0f); GridLayoutGroup val3 = val.AddComponent<GridLayoutGroup>(); ((LayoutGroup)val3).childAlignment = (TextAnchor)4; val3.cellSize = new Vector2(125f, 50f); val3.spacing = Vector2.one * 10f; ContentSizeFitter val4 = val.AddComponent<ContentSizeFitter>(); val4.verticalFit = (FitMode)2; teamPicker._canvasGroup = val.AddComponent<CanvasGroup>(); Dictionary<Team, TeamPickerButton> dictionary = new Dictionary<Team, TeamPickerButton>(); List<Team> list = new List<Team>(4) { (Team)2, (Team)128, (Team)32, (Team)16 }; if (Configuration.SafeInstance.General.UseAdvancedTeams.Value) { list.Add((Team)512); list.Add((Team)256); list.Add((Team)1); list.Add((Team)8); } foreach (Team item in list) { TeamPickerButton teamPickerButton = TeamPickerButton.Create(item, teamPicker.OnTeamSelected); ((Component)teamPickerButton).transform.SetParent(val.transform, false); dictionary[item] = teamPickerButton; } teamPicker._buttons = dictionary; teamPicker._onTeamSelected = onTeamSelected; return teamPicker; } } } namespace Silksong.BingoSync.UI.Constants { internal static class Colors { public static Color GetColor(this Team team) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Invalid comparison between Unknown and I4 //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Invalid comparison between Unknown and I4 //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Expected I4, but got Unknown //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Invalid comparison between Unknown and I4 //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Invalid comparison between Unknown and I4 //IL_016e: Unknown result type (might be due to invalid IL or missing references) //IL_0173: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_0154: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_017b: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Invalid comparison between Unknown and I4 //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_010f: 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: Invalid comparison between Unknown and I4 //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_0126: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Invalid comparison between Unknown and I4 //IL_0188: Unknown result type (might be due to invalid IL or missing references) //IL_0166: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Invalid comparison between Unknown and I4 //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) if ((int)team <= 32) { switch ((int)team) { default: if ((int)team != 16) { if ((int)team != 32) { break; } return new Color(0.22f, 0.75f, 0.47f); } return new Color(0.89f, 0.63f, 0f); case 4: return new Color(0.96f, 0.6f, 0.2f); case 2: return new Color(1f, 0.28f, 0.27f); case 8: return new Color(0.37f, 0.29f, 0.27f); case 1: return new Color(0.93f, 0.52f, 0.67f); case 0: return Color.black; case 3: case 5: case 6: case 7: break; } } else if ((int)team <= 128) { if ((int)team == 64) { return new Color(0.71f, 0.71f, 0.71f); } if ((int)team == 128) { return new Color(0f, 0.71f, 1f); } } else { if ((int)team == 256) { return new Color(0.16f, 0.33f, 0.53f); } if ((int)team == 512) { return new Color(0.51f, 0.17f, 0.75f); } } throw new ArgumentOutOfRangeException("team", team, null); } public static string GetDisplayName(this Team team) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Invalid comparison between Unknown and I4 //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Invalid comparison between Unknown and I4 //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Expected I4, but got Unknown //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Invalid comparison between Unknown and I4 //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Invalid comparison between Unknown and I4 //IL_00c4: 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_0032: Invalid comparison between Unknown and I4 //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Invalid comparison between Unknown and I4 //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Invalid comparison between Unknown and I4 //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Invalid comparison between Unknown and I4 if ((int)team <= 32) { switch ((int)team) { default: if ((int)team != 16) { if ((int)team != 32) { break; } return "Mossberry"; } return "Flintgem"; case 2: return "Rosary"; case 4: return "Flintstone"; case 1: return "Voltridian"; case 8: return "Pilgrim"; case 0: return "???"; case 3: case 5: case 6: case 7: break; } } else if ((int)team <= 128) { if ((int)team == 64) { return "Growstone"; } if ((int)team == 128) { return "Plasmium"; } } else { if ((int)team == 256) { return "Magnetite"; } if ((int)team == 512) { return "Pollip"; } } throw new ArgumentOutOfRangeException("team", team, null); } } internal static class Fonts { private static readonly Lazy<(Font? Bold, Font? Normal)> TrajanFonts = new Lazy<(Font, Font)>(delegate { Font item = null; Font item2 = null; Font[] array = Resources.FindObjectsOfTypeAll<Font>(); foreach (Font val in array) { if (!((Object)(object)val == (Object)null)) { string name = ((Object)val).name; if (!(name == "TrajanPro-Bold")) { if (name == "TrajanPro-Regular") { item2 = val; } } else { item = val; } } } return (Bold: item, Normal: item2); }); public static Font? Normal => TrajanFonts.Value.Normal; public static Font? Bold => TrajanFonts.Value.Bold; } } namespace Silksong.BingoSync.UI.Components { internal class Button : MonoBehaviour { private Action? _onClick; private Text? _label; public void SetText(string text) { Text? label = _label; if (label != null) { label.text = text; } } private void OnClick() { _onClick?.Invoke(); } public static Button Create(Action onClick) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Expected O, but got Unknown //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: 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_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Expected O, but got Unknown GameObject val = new GameObject("Button"); RectTransform val2 = val.AddComponent<RectTransform>(); val2.anchorMin = Vector2.zero; val2.anchorMax = Vector2.one; val2.sizeDelta = new Vector2(300f, 50f); Image val3 = val.AddComponent<Image>(); ((Graphic)val3).color = new Color(0f, 0f, 0f, 0.6f); Button val4 = val.AddComponent<Button>(); ((Selectable)val4).targetGraphic = (Graphic)(object)val3; GameObject val5 = new GameObject("Text"); val5.transform.SetParent(val.transform, false); RectTransform val6 = val5.AddComponent<RectTransform>(); val6.anchorMin = Vector2.zero; val6.anchorMax = Vector2.one; val6.offsetMin = Vector2.zero; val6.offsetMax = Vector2.zero; Text val7 = val5.AddComponent<Text>(); val7.font = Fonts.Normal; val7.fontSize = 18; ((Graphic)val7).color = Color.white; val7.alignment = (TextAnchor)4; Button button = val.AddComponent<Button>(); button._onClick = onClick; button._label = val7; ((UnityEvent)val4.onClick).AddListener(new UnityAction(button.OnClick)); return button; } } internal class CallOnInput : MonoBehaviour { private Func<KeyCode>? _key; private Action? _onInput; public void SetInput(ConfigEntry<KeyCode> entry, Action? onInput) { _key = () => entry.Value; _onInput = onInput; } private void Update() { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) if (_key != null) { KeyCode val = _key(); if (Input.GetKeyDown(val)) { _onInput?.Invoke(); } } } } internal class TextField : MonoBehaviour { private InputField? _inputField; public string Text { get { if ((Object)(object)_inputField == (Object)null) { return string.Empty; } return _inputField.text; } set { if (!((Object)(object)_inputField == (Object)null)) { _inputField.text = value; } } } public static TextField Create(string placeholder = "", ContentType type = (ContentType)0) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Expected O, but got Unknown //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Expected O, but got Unknown //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_015a: Unknown result type (might be due to invalid IL or missing references) //IL_0170: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Unknown result type (might be due to invalid IL or missing references) //IL_01cb: Unknown result type (might be due to invalid IL or missing references) //IL_0211: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("TextField"); TextField textField = val.AddComponent<TextField>(); RectTransform val2 = val.AddComponent<RectTransform>(); val2.anchorMin = new Vector2(0f, 0.5f); val2.anchorMax = new Vector2(1f, 0.5f); val2.sizeDelta = new Vector2(300f, 40f); Image val3 = val.AddComponent<Image>(); ((Graphic)val3).color = new Color(0f, 0f, 0f, 0.6f); GameObject val4 = new GameObject("Text"); val4.transform.SetParent(val.transform, false); RectTransform val5 = val4.AddComponent<RectTransform>(); val5.anchorMin = Vector2.zero; val5.anchorMax = Vector2.one; val5.offsetMin = new Vector2(10f, 5f); val5.offsetMax = new Vector2(-10f, 5f); Text val6 = val4.AddComponent<Text>(); val6.font = Fonts.Normal; val6.fontSize = 18; ((Graphic)val6).color = Color.white; val6.alignment = (TextAnchor)3; val6.supportRichText = false; GameObject val7 = new GameObject("Placeholder"); val7.transform.SetParent(val.transform, false); RectTransform val8 = val7.AddComponent<RectTransform>(); val8.anchorMin = Vector2.zero; val8.anchorMax = Vector2.one; val8.offsetMin = new Vector2(10f, 0f); val8.offsetMax = new Vector2(-10f, 0f); Text val9 = val7.AddComponent<Text>(); val9.font = val6.font; val9.fontSize = val6.fontSize; ((Graphic)val9).color = new Color(1f, 1f, 1f, 0.5f); val9.alignment = (TextAnchor)3; val9.text = placeholder; val9.fontStyle = (FontStyle)2; InputField val10 = val.AddComponent<InputField>(); val10.textComponent = val6; val10.placeholder = (Graphic)(object)val9; ((Selectable)val10).targetGraphic = (Graphic)(object)val3; val10.contentType = type; textField._inputField = val10; return textField; } } } namespace Silksong.BingoSync.Patches { [HarmonyPatch(typeof(HeroController))] internal class HeroController_Patches { [HarmonyPrefix] [HarmonyPatch("FixedUpdate")] private static void FixedUpdate_Prefix(HeroController __instance) { Configuration instance = Configuration.Instance; if (instance != null && instance.Experimental.EvaluateOnHeroUpdate.Value) { Plugin.Controller.Evaluate(); } } } [HarmonyPatch(typeof(PlayerData))] internal class PlayerData_Patches { [HarmonyPostfix] [HarmonyPatch("SetBool")] private static void SetBool_Postfix() { Plugin.Controller.Evaluate(); } } [HarmonyPatch(typeof(ToolItemManager))] internal class ToolItemManager_Patches { [HarmonyPostfix] [HarmonyPatch("ReportCrestUnlocked")] private static void ReportCrestUnlocked_Postfix() { Plugin.Controller.Evaluate(); } } [HarmonyPatch(typeof(UIManager))] internal class UIManager_Patches { private static Canvas? _bingoCanvas; [HarmonyPostfix] [HarmonyPatch("Awake")] private static void Awake_Postfix(UIManager __instance) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Expected O, but got Unknown //IL_003b: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_bingoCanvas != (Object)null)) { GameObject val = new GameObject("BingoSync.Canvas"); Object.DontDestroyOnLoad((Object)(object)val); Canvas val2 = val.AddComponent<Canvas>(); val2.renderMode = (RenderMode)0; CanvasScaler val3 = val.AddComponent<CanvasScaler>(); val3.referenceResolution = __instance.canvasScaler.referenceResolution; val3.uiScaleMode = (ScaleMode)1; val3.screenMatchMode = (ScreenMatchMode)1; val.AddComponent<GraphicRaycaster>(); _bingoCanvas = val2; CreateConnectionMenu(val.transform); BoardContainer boardContainer = BoardContainer.Create(); ((Component)boardContainer).transform.SetParent(val.transform, false); } } private static void CreateConnectionMenu(Transform parent) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //IL_002a: 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_0054: 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_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Expected O, but got Unknown GameObject val = new GameObject("ConnectionMenu-Container"); val.transform.SetParent(parent, false); RectTransform val2 = val.AddComponent<RectTransform>(); val2.anchorMin = new Vector2(0.75f, 0f); val2.anchorMax = new Vector2(1f, 0.5f); val2.offsetMin = new Vector2(-20f, 0f); val2.offsetMax = new Vector2(0f, 20f); val2.pivot = new Vector2(1f, 0f); JoinRoomSettings settings = new JoinRoomSettings { Nickname = (Configuration.Instance?.Join.Nickname.Value ?? "") }; ConnectionMenu connectionMenu = ConnectionMenu.Create(settings); ((Component)connectionMenu).transform.SetParent(val.transform, false); RectTransform val3 = default(RectTransform); if (((Component)connectionMenu).TryGetComponent<RectTransform>(ref val3)) { Canvas.ForceUpdateCanvases(); LayoutRebuilder.ForceRebuildLayoutImmediate(val3); } } } } namespace Silksong.BingoSync.Helpers { internal static class GoalLoader { public static GoalPool LoadPoolFromFolder(string folder) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Expected O, but got Unknown GoalPool val = new GoalPool(); if (!Directory.Exists(folder)) { Log.Warning("Folder '" + folder + "' does not exist."); return val; } string[] files = Directory.GetFiles(folder, "*.json", SearchOption.AllDirectories); string[] array = files; foreach (string text in array) { try { GoalSet val2 = LoadSetFromFile(text); Goal[] goals = val2.Goals; foreach (Goal val3 in goals) { val.TryAdd(val3); } } catch (Exception arg) { Log.Error($"Error while loading '{text}': {arg}"); } } return val; } public static GoalSet LoadSetFromFile(string file) { string text = File.ReadAllText(file); GoalSet val = JsonConvert.DeserializeObject<GoalSet>(text); if (val == (GoalSet)null) { throw new InvalidOperationException("Must parse a valid 'GoalSet'."); } return val; } } internal static class Log { private static readonly Lazy<ManualLogSource> Logger = new Lazy<ManualLogSource>((Func<ManualLogSource>)(() => Logger.CreateLogSource("dev.warpersan.silksong.bingosync"))); public static void LogCore(LogLevel level, string message) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Expected I4, but got Unknown switch ((int)level) { case 0: Debug(message); break; case 2: Warning(message); break; case 3: Error(message); break; default: Info(message); break; } } public static void Debug(string? message) { Logger.Value.LogDebug((object)message); } public static void Info(string? message) { Logger.Value.LogInfo((object)message); } public static void Warning(string? message) { Logger.Value.LogWarning((object)message); } public static void Error(string? message) { Logger.Value.LogError((object)message); } } internal static class Patch { public static void ApplyAll() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown Harmony val = new Harmony("dev.warpersan.silksong.bingosync"); val.PatchAll(typeof(UIManager_Patches)); val.PatchAll(typeof(PlayerData_Patches)); val.PatchAll(typeof(ToolItemManager_Patches)); val.PatchAll(typeof(HeroController_Patches)); Log.Debug("All patches applied."); } } internal static class Path { public static string GetPluginFolder() { string location = Assembly.GetExecutingAssembly().Location; string directoryName = System.IO.Path.GetDirectoryName(location); return directoryName ?? string.Empty; } public static string GetAbsolutePath(string relativePath) { string pluginFolder = GetPluginFolder(); return System.IO.Path.Combine(pluginFolder, relativePath); } } } namespace Silksong.BingoSync.Extensions { public static class PlayerDataExtensions { public static bool HasAncestralArt(this PlayerData data, AncestralArt art) { return art switch { AncestralArt.SwiftStep => data.hasDash, AncestralArt.ClingGrip => data.hasWalljump, AncestralArt.Needolin => data.hasNeedolin, AncestralArt.Clawline => data.hasHarpoonDash, AncestralArt.SilkSoar => data.hasSuperJump, AncestralArt.Sylphsong => data.HasSeenEvaHeal, _ => throw new InvalidCheckException<AncestralArt>(art), }; } public static bool IsBossKilled(this PlayerData data, Boss boss) { return boss switch { Boss.BellBeast => data.defeatedBellBeast, Boss.FourthChorus => data.defeatedSongGolem, Boss.GreatConchflies => data.defeatedCoralDrillers, Boss.Lace1 => data.defeatedLace1, Boss.LastJudge => data.defeatedLastJudge, Boss.Moorwing => data.defeatedVampireGnatBoss, Boss.MossMother => data.defeatedMossMother, Boss.MossMothers => data.HasJournalEntry(Boss.MossMothers), Boss.Phantom => data.defeatedPhantom, Boss.SavageBeastfly1 => data.defeatedBoneFlyerGiant, Boss.SisterSplinter => data.defeatedSplinterQueen, Boss.SkullTyrant1 => data.skullKingDefeated, Boss.SkullTyrant2 => data.HasJournalEntry(Boss.SkullTyrant2), Boss.Widow => data.spinnerDefeated, Boss.Broodmother => data.defeatedBroodMother, Boss.CogworkDancers => data.defeatedCogworkDancers, Boss.DisgracedChefLugoli => data.defeatedRoachkeeperChef, Boss.FatherOfTheFlame => data.defeatedWispPyreEffigy, Boss.FirstSinner => data.defeatedFirstWeaver, Boss.Forebrothers => data.defeatedDockForemen, Boss.Garmond => data.HasJournalEntry(Boss.Garmond), Boss.GrandMotherSilk => data.IsEndingCompleted(Ending.WeaverQueen) || data.IsEndingCompleted(Ending.SnaredSilk) || data.IsEndingCompleted(Ending.TwistedChild), Boss.Groal => data.DefeatedSwampShaman, Boss.Lace2 => data.defeatedLaceTower, Boss.RagingConchfly => data.defeatedCoralDrillerSolo, Boss.SavageBeastfly2 => data.defeatedBoneFlyerGiantGolemScene, Boss.SecondSentinel => data.defeatedSongChevalierBoss, Boss.Shakra => data.HasJournalEntry(Boss.Shakra), Boss.TheUnravelled => data.wardBossDefeated, Boss.Trobbio => data.defeatedTrobbio, Boss.Voltvyrm => data.defeatedZapCoreEnemy, Boss.BellEater => data.HasJournalEntry(Boss.BellEater), Boss.CloverDancers => data.defeatedCloverDancers, Boss.Crawfather => data.defeatedCrowCourt, Boss.CrustKingKhann => data.defeatedCoralKing, Boss.GurrTheOutcast => data.defeatedAntTrapper, Boss.LostGarmond => data.garmondBlackThreadDefeated, Boss.LostLace => data.IsEndingCompleted(Ending.SisterOfTheVoid), Boss.Nyleth => data.defeatedFlowerQueen, Boss.Palestag => data.defeatedWhiteCloverstag, Boss.Pinstress => data.HasJournalEntry(Boss.Pinstress), Boss.PlasmifiedZango => data.BlueScientistDead, Boss.ShrineGuardianSeth => data.defeatedSeth, Boss.SkarrsingerKarmelita => data.defeatedAntQueen, Boss.TormentedTrobbio => data.defeatedTormentedTrobbio, Boss.Watcher => data.defeatedGreyWarrior, _ => throw new InvalidCheckException<Boss>(boss), }; } private static string GetCrestId(Crest crest) { return crest switch { Crest.Hunter => "Hunter", Crest.HunterEvolved => "Hunter_v2", Crest.HunterFullyEvolved => "Hunter_v3", Crest.Reaper => "Reaper", Crest.Wanderer => "Wanderer", Crest.Beast => "Warrior", Crest.Cursed => "Cursed", Crest.Witch => "Witch", Crest.Architect => "Toolmaster", Crest.Shaman => "Spell", Crest.Cloakless => "Cloakless", _ => throw new InvalidCheckException<Crest>(crest), }; } private static Data? GetCrestData(this PlayerData data, Crest crest) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) string crestId = GetCrestId(crest); return ((SerializableNamedList<Data, NamedData>)(object)data.ToolEquips).GetData(crestId); } public static bool HasCrest(this PlayerData data, Crest crest) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) Data? crestData = data.GetCrestData(crest); if (!crestData.HasValue) { return false; } return crestData.Value.IsUnlocked; } public static bool IsEndingCompleted(this PlayerData data, Ending ending) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) return ending switch { Ending.WeaverQueen => ((Enum)data.CompletedEndings).HasFlag((Enum)(object)(CompletionState)1), Ending.SnaredSilk => ((Enum)data.CompletedEndings).HasFlag((Enum)(object)(CompletionState)4), Ending.TwistedChild => ((Enum)data.CompletedEndings).HasFlag((Enum)(object)(CompletionState)2), Ending.SisterOfTheVoid => ((Enum)data.CompletedEndings).HasFlag((Enum)(object)(CompletionState)8), Ending.PassingOfTheAge => data.MushroomQuestCompleted, _ => throw new InvalidCheckException<Ending>(ending), }; } private static KillData GetKillData(this PlayerData data, string key) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) return data.EnemyJournalKillData.GetKillData(key); } private static int GetKillCount(this PlayerData data, string key) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) return data.GetKillData(key).Kills; } private static bool HasJournalEntry(this PlayerData data, string key) { return data.GetKillCount(key) > 0; } public static bool HasJournalEntry(this PlayerData data, Boss boss) { return boss switch { Boss.Shakra => data.HasJournalEntry("Shakra"), Boss.BellBeast => throw new NotImplementedException(), Boss.FourthChorus => throw new NotImplementedException(), Boss.GreatConchflies => throw new NotImplementedException(), Boss.Lace1 => throw new NotImplementedException(), Boss.LastJudge => throw new NotImplementedException(), Boss.Moorwing => throw new NotImplementedException(), Boss.MossMother => data.HasJournalEntry("Mossbone Mother"), Boss.MossMothers => data.GetKillCount("Mossbone Mother") >= 3, Boss.Phantom => throw new NotImplementedException(), Boss.SavageBeastfly1 => throw new NotImplementedException(), Boss.SisterSplinter => throw new NotImplementedException(), Boss.SkullTyrant1 => data.HasJournalEntry("Skull King"), Boss.SkullTyrant2 => data.GetKillCount("Skull King") >= 2, Boss.Widow => throw new NotImplementedException(), Boss.Broodmother => throw new NotImplementedException(), Boss.CogworkDancers => throw new NotImplementedException(), Boss.DisgracedChefLugoli => throw new NotImplementedException(), Boss.FatherOfTheFlame => throw new NotImplementedException(), Boss.FirstSinner => throw new NotImplementedException(), Boss.Forebrothers => throw new NotImplementedException(), Boss.Garmond => data.HasJournalEntry("Garmond"), Boss.GrandMotherSilk => throw new NotImplementedException(), Boss.Groal => throw new NotImplementedException(), Boss.Lace2 => throw new NotImplementedException(), Boss.RagingConchfly => throw new NotImplementedException(), Boss.SavageBeastfly2 => throw new NotImplementedException(), Boss.SecondSentinel => throw new NotImplementedException(), Boss.TheUnravelled => throw new NotImplementedException(), Boss.Trobbio => throw new NotImplementedException(), Boss.Voltvyrm => throw new NotImplementedException(), Boss.BellEater => data.HasJournalEntry("Giant Centipede"), Boss.CloverDancers => throw new NotImplementedException(), Boss.Crawfather => throw new NotImplementedException(), Boss.CrustKingKhann => throw new NotImplementedException(), Boss.GurrTheOutcast => throw new NotImplementedException(), Boss.LostGarmond => throw new NotImplementedException(), Boss.LostLace => throw new NotImplementedException(), Boss.Nyleth => throw new NotImplementedException(), Boss.Palestag => throw new NotImplementedException(), Boss.Pinstress => data.HasJournalEntry("Pinstress Boss"), Boss.PlasmifiedZango => throw new NotImplementedException(), Boss.ShrineGuardianSeth => throw new NotImplementedException(), Boss.SkarrsingerKarmelita => throw new NotImplementedException(), Boss.TormentedTrobbio => throw new NotImplementedException(), Boss.Watcher => throw new NotImplementedException(), _ => throw new InvalidCheckException<Boss>(boss), }; } private static string GetMementoId(Memento memento) { return memento switch { Memento.Sprintmaster => "Sprintmaster Memento", Memento.Guardian => "Memento Seth", Memento.Hero => "Memento Garmond", Memento.Hunter => "Hunter Memento", Memento.Grey => "Grey Memento", Memento.Surface => "Memento Surface", Memento.Craw => "Crowman Memento", Memento.EncrustedHeart => "Coral Heart", Memento.PollenHeart => "Flower Heart", Memento.HunterHeart => "Hunter Heart", Memento.ConjoinedHeart => "Clover Heart", _ => throw new InvalidCheckException<Memento>(memento), }; } private static Data? GetMementoData(this PlayerData data, Memento memento) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) string mementoId = GetMementoId(memento); return ((SerializableNamedList<Data, NamedData>)(object)data.MementosDeposited).GetData(mementoId); } public static bool HasMemento(this PlayerData data, Memento memento) { return memento switch { Memento.Sprintmaster => data.CollectedMementoSprintmaster, Memento.Guardian => data.FleaGamesMementoGiven, Memento.Hero => throw new NotImplementedException(), Memento.Hunter => data.nuuMementoAwarded, Memento.Grey => data.CollectedMementoGrey, Memento.Surface => throw new NotImplementedException(), Memento.Craw => data.PickedUpCrowMemento, Memento.EncrustedHeart => data.CollectedHeartCoral, Memento.PollenHeart => data.CollectedHeartFlower, Memento.HunterHeart => data.CollectedHeartHunter, Memento.ConjoinedHeart => data.CollectedHeartClover, _ => throw new InvalidCheckException<Memento>(memento), }; } public static bool HasDepositedMemento(this PlayerData data, Memento memento) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) Data? mementoData = data.GetMementoData(memento); if (!mementoData.HasValue) { return false; } return mementoData.Value.IsDeposited; } private static int GetNeedleUpgradeIndex(Needle needle) { return needle switch { Needle.Needle => 0, Needle.SharpenedNeedle => 1, Needle.ShiningNeedle => 2, Needle.HivesteelNeedle => 3, Needle.PaleSteelNeedle => 4, _ => throw new InvalidCheckException<Needle>(needle), }; } public static bool HasObtainedNeedle(this PlayerData data, Needle needle) { int needleUpgradeIndex = GetNeedleUpgradeIndex(needle); return data.nailUpgrades >= needleUpgradeIndex; } private static string GetSilkSkillId(SilkSkill skill) { return skill switch { SilkSkill.Silkspear => "Silk Spear", SilkSkill.ThreadStorm => "Thread Sphere", SilkSkill.CrossStitch => "Parry", SilkSkill.Sharpdart => "Silk Charge", SilkSkill.RuneRage => "Silk Bomb", SilkSkill.PaleNails => "Silk Boss Needle", _ => throw new InvalidCheckException<SilkSkill>(skill), }; } private static Data? GetSilkSkillData(this PlayerData data, SilkSkill skill) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) string silkSkillId = GetSilkSkillId(skill); return ((SerializableNamedList<Data, NamedData>)(object)data.Tools).GetData(silkSkillId); } public static bool HasSilkSkill(this PlayerData data, SilkSkill skill) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) Data? silkSkillData = data.GetSilkSkillData(skill); if (!silkSkillData.HasValue) { return false; } return silkSkillData.Value.IsUnlocked; } private static string GetToolId(Tool tool) { return tool switch { Tool.StraightPin => "Straight Pin", Tool.ThreefoldPin => "Tri Pin", Tool.StingShard => "Sting Shard", Tool.Tacks => "Tack", Tool.Longpin => "Harpoon", Tool.Curveclaw => "Curve Claws", Tool.Curvesickle => "Curve Claws Upgraded", Tool.ThrowingRing => "Shakra Ring", Tool.Pimpillo => "Pimpilo", Tool.Conchcutter => "Conch Drill", Tool.WeaverSilkshot => "WebShot Weaver", Tool.ForgeSilkshot => "WebShot Forge", Tool.ArchitectSilkshot => "WebShot Architect", Tool.DelversDrill => "Screw Attack", Tool.CogworkWheel => "Cogwork Saw", Tool.Cogfly => "Cogwork Flier", Tool.RosaryCannon => "Rosary Cannon", Tool.Voltvessels => "Lightning Rod", Tool.Flintslate => "Flintstone", Tool.SnareSetter => "Silk Snare", Tool.FleaBrew => "Flea Brew", Tool.PlasmiumPhial => "Lifeblood Syringe", Tool.NeedlePhial => "Extractor", Tool.DruidsEye => "Mosscreep Tool 1", Tool.DruidsEyes => "Mosscreep Tool 2", Tool.MagmaBell => "Lava Charm", Tool.WardingBell => "Bell Bind", Tool.PollipPouch => "Poison Pouch", Tool.FracturedMask => "Fractured Mask", Tool.Multibinder => "Multibind", Tool.Weavelight => "White Ring", Tool.SawtoothCirclet => "Brolly Spike", Tool.InjectorBand => "Quickbind", Tool.SpoolExtender => "Spool Extender", Tool.ReserveBind => "Reserve Bind", Tool.ClawMirror => "Dazzle Bind", Tool.ClawMirrors => "Dazzle Bind Upgraded", Tool.MemoryCrystal => "Revenge Crystal", Tool.SnitchPick => "Thief Claw", Tool.VoltFilament => "Zap Imbuement", Tool.QuickSling => "Quick Sling", Tool.WreathOfPurity => "Maggot Charm", Tool.Longclaw => "Longneedle", Tool.WispfireLantern => "Wisp Lantern", Tool.EggOfFlealia => "Flea Charm", Tool.PinBadge => "Pinstress Tool", Tool.Compass => "Compass", Tool.ShardPendant => "Bone Necklace", Tool.MagnetiteBrooch => "Rosary Magnet", Tool.WeightedBelt => "Weighted Anklet", Tool.BarbedBracelet => "Barbed Wire", Tool.DeadBugsPurse => "Dead Mans Purse", Tool.ShellSatchel => "Shell Satchel", Tool.MagnetiteDice => "Magnetite Dice", Tool.Scuttlebrace => "Scuttlebrace", Tool.AscendantsGrip => "Wallcling", Tool.SpiderStrings => "Musician Charm", Tool.SilkspeedAnklets => "Sprintmaster", Tool.ThiefsMark => "Thief Charm", _ => throw new InvalidCheckException<Tool>(tool), }; } private static Data? GetToolData(this PlayerData data, Tool tool) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) string toolId = GetToolId(tool); return ((SerializableNamedList<Data, NamedData>)(object)data.Tools).GetData(toolId); } public static bool HasTool(this PlayerData data, Tool tool) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) Data? toolData = data.GetToolData(tool); if (!toolData.HasValue) { return false; } return toolData.Value.IsUnlocked; } public static bool HasVesticrest(this PlayerData data, Vesticrest vesticrest) { return vesticrest switch { Vesticrest.Basic => data.UnlockedExtraYellowSlot, Vesticrest.Upgraded => data.UnlockedExtraBlueSlot, _ => throw new InvalidCheckException<Vesticrest>(vesticrest), }; } } } namespace Silksong.BingoSync.Exceptions { public class InvalidCheckException<T> : InvalidOperationException { public InvalidCheckException(T data) : base($"No {typeof(T)} check is implemented for the value '{data}'.") { } } } namespace Silksong.BingoSync.Data { [JsonConverter(typeof(StringEnumConverter))] public enum AncestralArt { [EnumMember(Value = "swift_step")] SwiftStep, [EnumMember(Value = "cling_grip")] ClingGrip, [EnumMember(Value = "needolin")] Needolin, [EnumMember(Value = "clawline")] Clawline, [EnumMember(Value = "silk_soar")] SilkSoar, [EnumMember(Value = "sylphsong")] Sylphsong } [JsonConverter(typeof(StringEnumConverter))] public enum Boss { [EnumMember(Value = "bell_beast")] BellBeast, [EnumMember(Value = "fourth_chorus")] FourthChorus, [EnumMember(Value = "great_conchflies")] GreatConchflies, [EnumMember(Value = "lace_1")] Lace1, [EnumMember(Value = "last_judge")] LastJudge, [EnumMember(Value = "moorwing")] Moorwing, [EnumMember(Value = "moss_mother")] MossMother, [EnumMember(Value = "moss_mothers")] MossMothers, [EnumMember(Value = "phantom")] Phantom, [EnumMember(Value = "savage_beastfly_1")] SavageBeastfly1, [EnumMember(Value = "sister_splinter")] SisterSplinter, [EnumMember(Value = "skull_tyrant_1")] SkullTyrant1, [EnumMember(Value = "skull_tyrant_2")] SkullTyrant2, [EnumMember(Value = "widow")] Widow, [EnumMember(Value = "broodmother")] Broodmother, [EnumMember(Value = "cogwork_dancers")] CogworkDancers, [EnumMember(Value = "disgraced_chef_lugoli")] DisgracedChefLugoli, [EnumMember(Value = "father_of_the_flame")] FatherOfTheFlame, [EnumMember(Value = "first_sinner")] FirstSinner, [EnumMember(Value = "forebrothers")] Forebrothers, [EnumMember(Value = "garmond")] Garmond, [EnumMember(Value = "grand_mother_silk")] GrandMotherSilk, [EnumMember(Value = "groal_the_great")] Groal, [EnumMember(Value = "lace_2")] Lace2, [EnumMember(Value = "raging_conchfly")] RagingConchfly, [EnumMember(Value = "savage_beastfly_2")] SavageBeastfly2, [EnumMember(Value = "second_sentinel")] SecondSentinel, [EnumMember(Value = "shakra")] Shakra, [EnumMember(Value = "the_unravelled")] TheUnravelled, [EnumMember(Value = "trobbio")] Trobbio, [EnumMember(Value = "voltvyrm")] Voltvyrm, [EnumMember(Value = "bell_eater")] BellEater, [EnumMember(Value = "clover_dancers")] CloverDancers, [EnumMember(Value = "crawfather")] Crawfather, [EnumMember(Value = "crust_king_khann")] CrustKingKhann, [EnumMember(Value = "gurr_the_outcast")] GurrTheOutcast, [EnumMember(Value = "lost_garmond")] LostGarmond, [EnumMember(Value = "lost_lace")] LostLace, [EnumMember(Value = "nyleth")] Nyleth, [EnumMember(Value = "palestag")] Palestag, [EnumMember(Value = "pinstress")] Pinstress, [EnumMember(Value = "plasmified_zango")] PlasmifiedZango, [EnumMember(Value = "shrine_guardian_seth")] ShrineGuardianSeth, [EnumMember(Value = "skarrsinger_karmelita")] SkarrsingerKarmelita, [EnumMember(Value = "tormented_trobbio")] TormentedTrobbio, [EnumMember(Value = "watcher_at_the_edge")] Watcher } [JsonConverter(typeof(StringEnumConverter))] public enum Crest { [EnumMember(Value = "hunter")] Hunter, [EnumMember(Value = "hunter_evolved")] HunterEvolved, [EnumMember(Value = "hunter_fully_evolved")] HunterFullyEvolved, [EnumMember(Value = "reaper")] Reaper, [EnumMember(Value = "wanderer")] Wanderer, [EnumMember(Value = "beast")] Beast, [EnumMember(Value = "cursed")] Cursed, [EnumMember(Value = "witch")] Witch, [EnumMember(Value = "architect")] Architect, [EnumMember(Value = "shaman")] Shaman, [EnumMember(Value = "cloakless")] Cloakless } [JsonConverter(typeof(StringEnumConverter))] public enum Ending { [EnumMember(Value = "weaver_queen")] WeaverQueen, [EnumMember(Value = "snared_silk")] SnaredSilk, [EnumMember(Value = "twisted_child")] TwistedChild, [EnumMember(Value = "sister_of_the_void")] SisterOfTheVoid, [EnumMember(Value = "passing_of_the_age")] PassingOfTheAge } [JsonConverter(typeof(StringEnumConverter))] public enum Memento { [EnumMember(Value = "sprintmaster")] Sprintmaster, [EnumMember(Value = "guardian")] Guardian, [EnumMember(Value = "hero")] Hero, [EnumMember(Value = "hunter")] Hunter, [EnumMember(Value = "grey")] Grey, [EnumMember(Value = "surface")] Surface, [EnumMember(Value = "craw")] Craw, [EnumMember(Value = "encrusted_heart")] EncrustedHeart, [EnumMember(Value = "pollen_heart")] PollenHeart, [EnumMember(Value = "hunter_heart")] HunterHeart, [EnumMember(Value = "conjoined_heart")] ConjoinedHeart } [JsonConverter(typeof(StringEnumConverter))] public enum Needle { [EnumMember(Value = "needle")] Needle, [EnumMember(Value = "sharpened_needle")] SharpenedNeedle, [EnumMember(Value = "shining_needle")] ShiningNeedle, [EnumMember(Value = "hivesteel_needle")] HivesteelNeedle, [EnumMember(Value = "pale_steel_needle")] PaleSteelNeedle } [JsonConverter(typeof(StringEnumConverter))] public enum SilkSkill { [EnumMember(Value = "silkspear")] Silkspear, [EnumMember(Value = "thread_storm")] ThreadStorm, [EnumMember(Value = "cross_stitch")] CrossStitch, [EnumMember(Value = "sharpdart")] Sharpdart, [EnumMember(Value = "rune_rage")] RuneRage, [EnumMember(Value = "pale_nails")] PaleNails } [JsonConverter(typeof(StringEnumConverter))] public enum Tool { [EnumMember(Value = "straight_pin")] StraightPin, [EnumMember(Value = "threefold_pin")] ThreefoldPin, [EnumMember(Value = "sting_shard")] StingShard, [EnumMember(Value = "tacks")] Tacks, [EnumMember(Value = "longpin")] Longpin, [EnumMember(Value = "curveclaw")] Curveclaw, [EnumMember(Value = "curvesickle")] Curvesickle, [EnumMember(Value = "throwing_ring")] ThrowingRing, [EnumMember(Value = "pimpillo")] Pimpillo, [EnumMember(Value = "conchcutter")] Conchcutter, [EnumMember(Value = "weaver_silkshot")] WeaverSilkshot, [EnumMember(Value = "architect_silkshot")] ArchitectSilkshot, [EnumMember(Value = "forge_silkshot")] ForgeSilkshot, [EnumMember(Value = "delvers_drill")] DelversDrill, [EnumMember(Value = "cogwork_wheel")] CogworkWheel, [EnumMember(Value = "cogfly")] Cogfly, [EnumMember(Value = "rosary_cannon")] RosaryCannon, [EnumMember(Value = "voltvessels")] Voltvessels, [EnumMember(Value = "flintslate")] Flintslate, [EnumMember(Value = "snare_setter")] SnareSetter, [EnumMember(Value = "flea_brew")] FleaBrew, [EnumMember(Value = "plasmium_phial")] PlasmiumPhial, [EnumMember(Value = "needle_phial")] NeedlePhial, [EnumMember(Value = "druids_eye")] DruidsEye, [EnumMember(Value = "druids_eyes")] DruidsEyes, [EnumMember(Value = "magma_bell")] MagmaBell, [EnumMember(Value = "warding_bell")] WardingBell, [EnumMember(Value = "pollip_pouch")] PollipPouch, [EnumMember(Value = "fractured_mask")] FracturedMask, [EnumMember(Value = "multibinder")] Multibinder, [EnumMember(Value = "weavelight")] Weavelight, [EnumMember(Value = "sawtooth_circlet")] SawtoothCirclet, [EnumMember(Value = "injector_band")] InjectorBand, [EnumMember(Value = "spool_extender")] SpoolExtender, [EnumMember(Value = "reserve_bind")] ReserveBind, [EnumMember(Value = "claw_mirror")] ClawMirror, [EnumMember(Value = "claw_mirrors")] ClawMirrors, [EnumMember(Value = "memory_crystal")] MemoryCrystal, [EnumMember(Value = "snitch_pick")] SnitchPick, [EnumMember(Value = "volt_filament")] VoltFilament, [EnumMember(Value = "quick_sling")] QuickSling, [EnumMember(Value = "wreath_of_purity")] WreathOfPurity, [EnumMember(Value = "longclaw")] Longclaw, [EnumMember(Value = "wispfire_lantern")] WispfireLantern, [EnumMember(Value = "egg_of_flealia")] EggOfFlealia, [EnumMember(Value = "pin_badge")] PinBadge, [EnumMember(Value = "compass")] Compass, [EnumMember(Value = "shard_pendant")] ShardPendant, [EnumMember(Value = "magnetite_brooch")] MagnetiteBrooch, [EnumMember(Value = "weighted_belt")] WeightedBelt, [EnumMember(Value = "barbed_bracelet")] BarbedBracelet, [EnumMember(Value = "dead_bugs_purse")] DeadBugsPurse, [EnumMember(Value = "shell_satchel")] ShellSatchel, [EnumMember(Value = "magnetite_dice")] MagnetiteDice, [EnumMember(Value = "scuttlebrace")] Scuttlebrace, [EnumMember(Value = "ascendants_grip")] AscendantsGrip, [EnumMember(Value = "spider_strings")] SpiderStrings, [EnumMember(Value = "silkspeed_anklets")] SilkspeedAnklets, [EnumMember(Value = "thiefs_mark")] ThiefsMark } [JsonConverter(typeof(StringEnumConverter))] public enum Vesticrest { [EnumMember(Value = "basic")] Basic, [EnumMember(Value = "upgraded")] Upgraded } } namespace Silksong.BingoSync.Configurations { internal class BoardConfig { private const string SECTION = "Board"; public readonly ConfigEntry<KeyCode> ToggleUI; public BoardConfig(ConfigFile cfg) { ToggleUI = cfg.Bind<KeyCode>("Board", "ToggleBoard", (KeyCode)98, "Defines the keybind to toggle the board"); } } internal class Configuration { public readonly GeneralConfig General; public readonly BoardConfig Board; public readonly JoinConfig Join; public readonly ExperimentalConfig Experimental; public static Configuration? Instance { get; private set; } public static Configuration SafeInstance { get { if (Instance == null) { throw new InvalidOperationException("Tried to access 'Configuration' before it was loaded."); } return Instance; } } private Configuration(ConfigFile cfg) { General = new GeneralConfig(cfg); Board = new BoardConfig(cfg); Join = new JoinConfig(cfg); Experimental = new ExperimentalConfig(cfg); } public static void Load(ConfigFile cfg) { Instance = new Configuration(cfg); } } internal class ExperimentalConfig { private const string SECTION = "Experimental"; public readonly ConfigEntry<bool> EvaluateOnHeroUpdate; public ExperimentalConfig(ConfigFile cfg) { EvaluateOnHeroUpdate = cfg.Bind<bool>("Experimental", "evaluateOnHeroUpdate", false, "Defines if the goals should be checked on each frame the player is loaded"); } } internal class GeneralConfig { private const string SECTION = "General"; public readonly ConfigEntry<bool> UseAdvancedTeams; public GeneralConfig(ConfigFile cfg) { UseAdvancedTeams = cfg.Bind<bool>("General", "AddMoreTeams", false, "Defines if 4 extra teams are added upon loading"); } } internal class JoinConfig { private const string SECTION = "Join"; public readonly ConfigEntry<string> Nickname; public readonly ConfigEntry<KeyCode> ToggleUI; public JoinConfig(ConfigFile cfg) { Nickname = cfg.Bind<string>("Join", "DefaultNickname", "", "Defines the default nickname in the join panel"); ToggleUI = cfg.Bind<KeyCode>("Join", "ToggleJoinUI", (KeyCode)104, "Defines the keybind to toggle the join panel"); } } } namespace Silksong.BingoSync.Conditions { internal sealed class HasCompletedEndingCondition : ICondition { private readonly Ending _ending; [Condition("has_completed_ending")] public HasCompletedEndingCondition(ConditionData data) { _ending = data.GetRequiredParameter<Ending>("ending"); } public bool IsMet() { return PlayerData.instance.IsEndingCompleted(_ending); } } internal sealed class HasDepositedMementoCondition : ICondition { private readonly Memento _memento; [Condition("has_deposited_memento")] public HasDepositedMementoCondition(ConditionData data) { _memento = data.GetRequiredParameter<Memento>("memento"); } public bool IsMet() { return PlayerData.instance.HasDepositedMemento(_memento); } } internal sealed class HasKilledBossCondition : ICondition { private readonly Boss _boss; [Condition("has_killed_boss")] public HasKilledBossCondition(ConditionData data) { _boss = data.GetRequiredParameter<Boss>("boss"); } public bool IsMet() { return PlayerData.instance.IsBossKilled(_boss); } } internal sealed class HasObtainedAncestralArt : ICondition { private readonly AncestralArt _art; [Condition("has_obtained_ancestral_art")] public HasObtainedAncestralArt(ConditionData data) { _art = data.GetRequiredParameter<AncestralArt>("art"); } public bool IsMet() { return PlayerData.instance.HasAncestralArt(_art); } } internal sealed class HasObtainedCrestCondition : ICondition { private readonly Crest _crest; [Condition("has_obtained_crest")] public HasObtainedCrestCondition(ConditionData data) { _crest = data.GetRequiredParameter<Crest>("crest"); } public bool IsMet() { return PlayerData.instance.HasCrest(_crest); } } internal sealed class HasObtainedMementoCondition : ICondition { private readonly Memento _memento; [Condition("has_obtained_memento")] public HasObtainedMementoCondition(ConditionData data) { _memento = data.GetRequiredParameter<Memento>("memento"); } public bool IsMet() { return PlayerData.instance.HasMemento(_memento); } } internal sealed class HasObtainedNeedleCondition : ICondition { private readonly Needle _needle; [Condition("has_obtained_needle")] public HasObtainedNeedleCondition(ConditionData data) { _needle = data.GetRequiredParameter<Needle>("needle"); } public bool IsMet() { return PlayerData.instance.HasObtainedNeedle(_needle); } } internal sealed class HasObtainedSilkSkillCondition : ICondition { private readonly SilkSkill _skill; [Condition("has_obtained_silk_skill")] public HasObtainedSilkSkillCondition(ConditionData data) { _skill = data.GetRequiredParameter<SilkSkill>("skill"); } public bool IsMet() { return PlayerData.instance.HasSilkSkill(_skill); } } internal sealed class HasObtainedToolCondition : ICondition { private readonly Tool _tool; [Condition("has_obtained_tool")] public HasObtainedToolCondition(ConditionData data) { _tool = data.GetRequiredParameter<Tool>("tool"); } public bool IsMet() { return PlayerData.instance.HasTool(_tool); } } internal sealed class HasObtainedVesticrestCondition : ICondition { private readonly Vesticrest _vesticrest; [Condition("has_obtained_vesticrest")] public HasObtainedVesticrestCondition(ConditionData data) { _vesticrest = data.GetRequiredParameter<Vesticrest>("vesticrest"); } public bool IsMet() { return PlayerData.instance.HasVesticrest(_vesticrest); } } }
plugins/BingoAPI.dll
Decompiled 3 weeks agousing System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; using System.Net; using System.Net.Http; using System.Net.Http.Headers; using System.Net.WebSockets; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Serialization; using System.Runtime.Versioning; using System.Text; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; using BingoAPI.Conditions; using BingoAPI.Events; using BingoAPI.Events.BuiltIn; using BingoAPI.Goals; using BingoAPI.Helpers; using BingoAPI.Models; using BingoAPI.Models.Settings; using BingoAPI.Networking.Clients; using BingoAPI.Networking.Converters; using BingoAPI.Networking.DTOs; using Microsoft.CodeAnalysis; using Newtonsoft.Json; using Newtonsoft.Json.Linq; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = ".NET Standard 2.0")] [assembly: AssemblyCompany("WarperSan")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("Library that allows to communicate with BingoSync's servers through code")] [assembly: AssemblyFileVersion("0.1.3.0")] [assembly: AssemblyInformationalVersion("0.1.3-alpha+05041a50d4823d4c32c4fcae9420886e16396084")] [assembly: AssemblyProduct("BingoAPI")] [assembly: AssemblyTitle("BingoAPI")] [assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/WarperSan/BingoAPI")] [assembly: AssemblyVersion("0.0.0.0")] [module: RefSafetyRules(11)] namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] internal sealed class IsReadOnlyAttribute : Attribute { } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace System { [ExcludeFromCodeCoverage] [Embedded] internal readonly struct Range : IEquatable<Range> { private static class HashHelpers { public static int Combine(int h1, int h2) { uint num = (uint)((h1 << 5) | (h1 >>> 27)); return ((int)num + h1) ^ h2; } } private static class ThrowHelper { [DoesNotReturn] public static void ThrowArgumentOutOfRangeException() { throw new ArgumentOutOfRangeException("length"); } } public Index Start { get; } public Index End { get; } public static Range All => Index.Start..Index.End; public Range(Index start, Index end) { Start = start; End = end; } public override bool Equals([NotNullWhen(true)] object? value) { if (value is Range { Start: var start } range && start.Equals(Start)) { return range.End.Equals(End); } return false; } public bool Equals(Range other) { if (other.Start.Equals(Start)) { return other.End.Equals(End); } return false; } public override int GetHashCode() { return HashHelpers.Combine(Start.GetHashCode(), End.GetHashCode()); } public override string ToString() { return Start.ToString() + ".." + End; } public static Range StartAt(Index start) { return start..Index.End; } public static Range EndAt(Index end) { return Index.Start..end; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public (int Offset, int Length) GetOffsetAndLength(int length) { Index start = Start; int num = ((!start.IsFromEnd) ? start.Value : (length - start.Value)); Index end = End; int num2 = ((!end.IsFromEnd) ? end.Value : (length - end.Value)); if ((uint)num2 > (uint)length || (uint)num > (uint)num2) { ThrowHelper.ThrowArgumentOutOfRangeException(); } return (Offset: num, Length: num2 - num); } } [ExcludeFromCodeCoverage] [Embedded] internal readonly struct Index : IEquatable<Index> { private static class ThrowHelper { [DoesNotReturn] public static void ThrowValueArgumentOutOfRange_NeedNonNegNumException() { throw new ArgumentOutOfRangeException("value", "Non-negative number required."); } } private readonly int _value; public static Index Start => new Index(0); public static Index End => new Index(-1); public int Value { get { if (_value < 0) { return ~_value; } return _value; } } public bool IsFromEnd => _value < 0; [MethodImpl(MethodImplOptions.AggressiveInlining)] public Index(int value, bool fromEnd = false) { if (value < 0) { ThrowHelper.ThrowValueArgumentOutOfRange_NeedNonNegNumException(); } if (fromEnd) { _value = ~value; } else { _value = value; } } private Index(int value) { _value = value; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Index FromStart(int value) { if (value < 0) { ThrowHelper.ThrowValueArgumentOutOfRange_NeedNonNegNumException(); } return new Index(value); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Index FromEnd(int value) { if (value < 0) { ThrowHelper.ThrowValueArgumentOutOfRange_NeedNonNegNumException(); } return new Index(~value); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public int GetOffset(int length) { int num = _value; if (IsFromEnd) { num += length + 1; } return num; } public override bool Equals([NotNullWhen(true)] object? value) { if (value is Index) { return _value == ((Index)value)._value; } return false; } public bool Equals(Index other) { return _value == other._value; } public override int GetHashCode() { return _value; } public static implicit operator Index(int value) { return FromStart(value); } public override string ToString() { if (IsFromEnd) { return ToStringFromEnd(); } return ((uint)Value).ToString(); } private string ToStringFromEnd() { return "^" + Value; } } } namespace System.Runtime.Versioning { [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Module | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Interface | AttributeTargets.Delegate, Inherited = false)] [ExcludeFromCodeCoverage] [Embedded] internal sealed class RequiresPreviewFeaturesAttribute : Attribute { public string? Message { get; } public string? Url { get; set; } public RequiresPreviewFeaturesAttribute() { } public RequiresPreviewFeaturesAttribute(string? message) { Message = message; } } } namespace System.Runtime.CompilerServices { [EditorBrowsable(EditorBrowsableState.Never)] [ExcludeFromCodeCoverage] [Embedded] internal static class IsExternalInit { } [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, Inherited = false, AllowMultiple = false)] [ExcludeFromCodeCoverage] [Embedded] internal sealed class AsyncMethodBuilderAttribute : Attribute { public Type BuilderType { get; } public AsyncMethodBuilderAttribute(Type builderType) { BuilderType = builderType; } } [EditorBrowsable(EditorBrowsableState.Never)] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Interface | AttributeTargets.Delegate, Inherited = false)] [ExcludeFromCodeCoverage] [Embedded] internal sealed class ExtensionMarkerAttribute : Attribute { public string Name { get; } public ExtensionMarkerAttribute(string name) { Name = name; } } [AttributeUsage(AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] [Embedded] internal sealed class OverloadResolutionPriorityAttribute : Attribute { public int Priority { get; } public OverloadResolutionPriorityAttribute(int priority) { Priority = priority; } } [AttributeUsage(AttributeTargets.Method, Inherited = false)] [ExcludeFromCodeCoverage] [Embedded] internal sealed class ModuleInitializerAttribute : Attribute { } [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] [EditorBrowsable(EditorBrowsableState.Never)] [ExcludeFromCodeCoverage] [Embedded] internal sealed class RequiresLocationAttribute : Attribute { } [AttributeUsage(AttributeTargets.Class, Inherited = false)] [ExcludeFromCodeCoverage] [Embedded] internal sealed class CompilerLoweringPreserveAttribute : Attribute { } [AttributeUsage(AttributeTargets.Module | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Event | AttributeTargets.Interface, Inherited = false)] [ExcludeFromCodeCoverage] [Embedded] internal sealed class SkipLocalsInitAttribute : Attribute { } [AttributeUsage(AttributeTargets.Parameter, Inherited = true, AllowMultiple = false)] [ExcludeFromCodeCoverage] [Embedded] internal sealed class ParamCollectionAttribute : Attribute { } [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface, Inherited = false)] [ExcludeFromCodeCoverage] [Embedded] internal sealed class CollectionBuilderAttribute : Attribute { public Type BuilderType { get; } public string MethodName { get; } public CollectionBuilderAttribute(Type builderType, string methodName) { BuilderType = builderType; MethodName = methodName; } } [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] [Embedded] internal sealed class RequiredMemberAttribute : Attribute { } [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] [Embedded] internal sealed class InterpolatedStringHandlerAttribute : Attribute { } [AttributeUsage(AttributeTargets.All, AllowMultiple = true, Inherited = false)] [ExcludeFromCodeCoverage] [Embedded] internal sealed class CompilerFeatureRequiredAttribute : Attribute { public const string RefStructs = "RefStructs"; public const string RequiredMembers = "RequiredMembers"; public string FeatureName { get; } public bool IsOptional { get; set; } public CompilerFeatureRequiredAttribute(string featureName) { FeatureName = featureName; } } [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] [Embedded] internal sealed class CallerArgumentExpressionAttribute : Attribute { public string ParameterName { get; } public CallerArgumentExpressionAttribute(string parameterName) { ParameterName = parameterName; } } [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] [Embedded] internal sealed class InterpolatedStringHandlerArgumentAttribute : Attribute { public string[] Arguments { get; } public InterpolatedStringHandlerArgumentAttribute(string argument) { Arguments = new string[1] { argument }; } public InterpolatedStringHandlerArgumentAttribute(params string[] arguments) { Arguments = arguments; } } } namespace System.Diagnostics.CodeAnalysis { [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] [ExcludeFromCodeCoverage] [Embedded] internal sealed class DoesNotReturnIfAttribute : Attribute { public bool ParameterValue { get; } public DoesNotReturnIfAttribute(bool parameterValue) { ParameterValue = parameterValue; } } [AttributeUsage(AttributeTargets.Property | AttributeTargets.Parameter | AttributeTargets.ReturnValue, AllowMultiple = true, Inherited = false)] [ExcludeFromCodeCoverage] [Embedded] internal sealed class NotNullIfNotNullAttribute : Attribute { public string ParameterName { get; } public NotNullIfNotNullAttribute(string parameterName) { ParameterName = parameterName; } } [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, Inherited = false)] [ExcludeFromCodeCoverage] [Embedded] internal sealed class AllowNullAttribute : Attribute { } [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] [ExcludeFromCodeCoverage] [Embedded] internal sealed class MaybeNullWhenAttribute : Attribute { public bool ReturnValue { get; } public MaybeNullWhenAttribute(bool returnValue) { ReturnValue = returnValue; } } [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] [Embedded] internal sealed class UnscopedRefAttribute : Attribute { } [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.ReturnValue, Inherited = false)] [ExcludeFromCodeCoverage] [Embedded] internal sealed class MaybeNullAttribute : Attribute { } [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] [ExcludeFromCodeCoverage] [Embedded] internal sealed class ConstantExpectedAttribute : Attribute { public object? Min { get; set; } public object? Max { get; set; } } [AttributeUsage(AttributeTargets.Method, Inherited = false)] [ExcludeFromCodeCoverage] [Embedded] internal sealed class DoesNotReturnAttribute : Attribute { } [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, Inherited = false)] [ExcludeFromCodeCoverage] [Embedded] internal sealed class DisallowNullAttribute : Attribute { } [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Module | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Interface | AttributeTargets.Delegate, Inherited = false)] [ExcludeFromCodeCoverage] [Embedded] internal sealed class ExperimentalAttribute : Attribute { public string DiagnosticId { get; } public string? UrlFormat { get; set; } public ExperimentalAttribute(string diagnosticId) { DiagnosticId = diagnosticId; } } [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)] [ExcludeFromCodeCoverage] [Embedded] internal sealed class MemberNotNullAttribute : Attribute { public string[] Members { get; } public MemberNotNullAttribute(string member) { Members = new string[1] { member }; } public MemberNotNullAttribute(params string[] members) { Members = members; } } [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.ReturnValue, Inherited = false)] [ExcludeFromCodeCoverage] [Embedded] internal sealed class NotNullAttribute : Attribute { } [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)] [ExcludeFromCodeCoverage] [Embedded] internal sealed class MemberNotNullWhenAttribute : Attribute { public bool ReturnValue { get; } public string[] Members { get; } public MemberNotNullWhenAttribute(bool returnValue, string member) { ReturnValue = returnValue; Members = new string[1] { member }; } public MemberNotNullWhenAttribute(bool returnValue, params string[] members) { ReturnValue = returnValue; Members = members; } } [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] [Embedded] internal sealed class StringSyntaxAttribute : Attribute { public const string CompositeFormat = "CompositeFormat"; public const string DateOnlyFormat = "DateOnlyFormat"; public const string DateTimeFormat = "DateTimeFormat"; public const string EnumFormat = "EnumFormat"; public const string GuidFormat = "GuidFormat"; public const string Json = "Json"; public const string NumericFormat = "NumericFormat"; public const string Regex = "Regex"; public const string TimeOnlyFormat = "TimeOnlyFormat"; public const string TimeSpanFormat = "TimeSpanFormat"; public const string Uri = "Uri"; public const string Xml = "Xml"; public string Syntax { get; } public object?[] Arguments { get; } public StringSyntaxAttribute(string syntax) { Syntax = syntax; Arguments = new object[0]; } public StringSyntaxAttribute(string syntax, params object?[] arguments) { Syntax = syntax; Arguments = arguments; } } [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] [ExcludeFromCodeCoverage] [Embedded] internal sealed class NotNullWhenAttribute : Attribute { public bool ReturnValue { get; } public NotNullWhenAttribute(bool returnValue) { ReturnValue = returnValue; } } [AttributeUsage(AttributeTargets.Constructor, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] [Embedded] internal sealed class SetsRequiredMembersAttribute : Attribute { } } namespace Microsoft.CodeAnalysis { [Embedded] [AttributeUsage(AttributeTargets.All)] [ExcludeFromCodeCoverage] internal sealed class EmbeddedAttribute : Attribute { } } namespace BingoAPI.Networking { internal class LoggingHandler : DelegatingHandler { public LoggingHandler(HttpMessageHandler innerHandler) : base(innerHandler) { } protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { string arg = ""; if (request.Content != null) { arg = await request.Content.ReadAsStringAsync(); } Log.Debug($"Request:\n{request}\n{arg}"); HttpResponseMessage response = await base.SendAsync(request, cancellationToken); string arg2 = ""; if (response.Content != null) { arg2 = await response.Content.ReadAsStringAsync(); } Log.Debug($"Response:\n{response}\n{arg2}"); return response; } } internal sealed class RequestBuilder { private HttpMethod _method = HttpMethod.Get; private string? _endpoint; private HttpContent? _content; private RequestBuilder WithMethod(HttpMethod method) { _method = method; return this; } public RequestBuilder Get() { return WithMethod(HttpMethod.Get); } public RequestBuilder Post() { return WithMethod(HttpMethod.Post); } public RequestBuilder Put() { return WithMethod(HttpMethod.Put); } public RequestBuilder ToEndpoint(string endpoint) { _endpoint = endpoint; return this; } public RequestBuilder WithJson(object json) { string content = JsonConvert.SerializeObject(json); _content = new StringContent(content, Encoding.UTF8, "application/json"); return this; } public RequestBuilder WithForm(object form) { List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>(); var enumerable = from m in form.GetType().GetMembers(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).Where(delegate(MemberInfo m) { MemberTypes memberType = m.MemberType; return (memberType == MemberTypes.Field || memberType == MemberTypes.Property) ? true : false; }) select new { Member = m, Attribute = m.GetCustomAttribute<DataMemberAttribute>() } into m where m.Attribute != null select m; foreach (var item in enumerable) { string key = item.Attribute?.Name ?? item.Member.Name; MemberInfo member = item.Member; string text = ((member is FieldInfo fieldInfo) ? fieldInfo.GetValue(form)?.ToString() : ((!(member is PropertyInfo propertyInfo)) ? null : propertyInfo.GetValue(form)?.ToString())); string text2 = text; if (text2 == null) { text2 = ""; } list.Add(new KeyValuePair<string, string>(key, text2)); } _content = new FormUrlEncodedContent(list); return this; } public HttpRequestMessage Build() { HttpRequestMessage httpRequestMessage = new HttpRequestMessage { Method = _method, Content = _content }; if (_endpoint != null) { httpRequestMessage.RequestUri = new Uri(_endpoint, UriKind.Relative); } return httpRequestMessage; } } public sealed class Session : IDisposable { private readonly HttpClient _client; private readonly BingoApiClient _api; private readonly BingoSocketClient _socket = new BingoSocketClient(); private readonly EventDispatcher _dispatcher; private string? _roomCode; public Team Team { get; private set; } [MemberNotNullWhen(true, "_roomCode")] public bool IsInRoom { [MemberNotNullWhen(true, "_roomCode")] get { return _roomCode != null; } } public Session(EventDispatcher dispatcher) { _dispatcher = dispatcher; _client = new HttpClient(new LoggingHandler(new HttpClientHandler())); _client.Timeout = TimeSpan.FromSeconds(30.0); _client.DefaultRequestHeaders.UserAgent.Add(new ProductInfoHeaderValue("BingoAPI", "1.0.0")); _client.BaseAddress = new Uri("https://bingosync.com"); _api = new BingoApiClient(_client); } public async Task<bool> CreateRoom(CreateRoomSettings settings, CancellationToken ct = default(CancellationToken)) { throw new NotImplementedException(); } public async Task<bool> JoinRoom(JoinRoomSettings settings, CancellationToken ct = default(CancellationToken)) { if (IsInRoom) { Log.Error("Tried to join a room while being connected."); return false; } Log.Info("Joining room '" + settings.Code + "'..."); try { string socketKey = await _api.JoinRoom(settings, ct); await _socket.Connect(socketKey, OnMessageReceived, ct); GetSocketInformationResponse getSocketInformationResponse = await _api.GetSocketInformation(socketKey, ct); _roomCode = getSocketInformationResponse.Code; Team = Team.Red; Player player = new Player { Name = settings.Nickname, Team = Team, UUID = getSocketInformationResponse.PlayerUUID }; _dispatcher.DispatchConnect(player); Log.Info("Room '" + settings.Code + "' was joined."); return true; } catch (Exception arg) { Log.Error($"Failed to join the room '{settings.Code}': {arg}"); return false; } } public async Task<bool> LeaveRoom(CancellationToken ct = default(CancellationToken)) { if (!IsInRoom) { Log.Error("Tried to leave the room before being connected."); return false; } string room = _roomCode; Log.Info("Leaving the room '" + room + "'..."); try { await _socket.Disconnect(ct); _roomCode = null; _dispatcher.DispatchDisconnect(); Log.Info("Left the room '" + room + "'."); return true; } catch (Exception arg) { Log.Error($"Failed to leave the room '{room}: {arg}"); return false; } } public async Task<bool> SendMessage(string message, CancellationToken ct = default(CancellationToken)) { if (!IsInRoom) { Log.Error("Tried to send a message before being connected."); return false; } Log.Info("Sending the following chat message: '" + message + "'..."); try { await _api.SendMessage(_roomCode, message, ct); Log.Info("Sent the following chat message: '" + message + "'."); return true; } catch (Exception arg) { Log.Error($"Failed to sent the chat message: {arg}"); return false; } } public async Task<bool> ChangeTeam(Team team, CancellationToken ct = default(CancellationToken)) { if (!IsInRoom) { Log.Error("Tried to change team before being connected."); return false; } if (team == Team) { Log.Error("Tried to change to the same team."); return false; } Log.Info($"Changing team to '{team}'..."); try { await _api.ChangeTeam(_roomCode, team, ct); Team = team; Log.Info($"Changed team to '{team}'."); return true; } catch (Exception arg) { Log.Error($"Failed to change the team: {arg}"); return false; } } public async Task<Card?> GetCard(GoalPool pool, CancellationToken ct = default(CancellationToken)) { if (!IsInRoom) { Log.Error("Tried to get the squares before being connected."); return null; } Log.Info("Getting the squares of the room '" + _roomCode + "'..."); try { Square[] array = await _api.GetSquares(_roomCode, ct); Log.Info($"Got {array.Length} squares for room '{_roomCode}'."); return new Card(array, pool); } catch (Exception arg) { Log.Error($"Failed to get squares for room '{_roomCode}': {arg}"); return null; } } public async Task<Square[]?> GetSquares(CancellationToken ct = default(CancellationToken)) { if (!IsInRoom) { Log.Error("Tried to get the squares before being connected."); return null; } Log.Info("Getting the squares of the room '" + _roomCode + "'..."); try { Square[] array = await _api.GetSquares(_roomCode, ct); Log.Info($"Got {array.Length} squares for room '{_roomCode}'."); return array; } catch (Exception arg) { Log.Error($"Failed to get squares for room '{_roomCode}': {arg}"); return null; } } public async Task<bool> MarkSquare(int index, CancellationToken ct = default(CancellationToken)) { if (!IsInRoom) { Log.Error("Tried to mark a square before being connected."); return false; } if (Team == Team.None) { Log.Error("Tried to clear a square without being in a team."); return false; } Log.Info($"Marking the square #{index} for the team '{Team}'..."); try { await _api.MarkSquare(_roomCode, Team, index, ct); Log.Info($"Marked the square #{index} for the team '{Team}'."); return true; } catch (Exception arg) { Log.Error($"Failed to mark the square #{index} for the team '{Team}': {arg}"); return false; } } public async Task<bool> ClearSquare(int index, CancellationToken ct = default(CancellationToken)) { if (!IsInRoom) { Log.Error("Tried to clear a square before being connected."); return false; } if (Team == Team.None) { Log.Error("Tried to clear a square without being in a team."); return false; } Log.Info($"Clearing the square #{index} for the team '{Team}'..."); try { await _api.ClearSquare(_roomCode, Team, index, ct); Log.Info($"Cleared the square #{index} for the team '{Team}'."); return true; } catch (Exception arg) { Log.Error($"Failed to clear the square #{index} for the team '{Team}': {arg}"); return false; } } public async Task<bool> RevealCard(CancellationToken ct = default(CancellationToken)) { if (!IsInRoom) { Log.Error("Tried to reveal the card before being connected."); return false; } Log.Info("Revealing the card for the room '" + _roomCode + "'..."); try { await _api.RevealCard(_roomCode, ct); Log.Info("Revealed the card for the room '" + _roomCode + "'."); return true; } catch (Exception arg) { Log.Error($"Failed to reveal the card for the room '{_roomCode}': {arg}"); return false; } } private void OnMessageReceived(string message) { IEvent obj = JsonConvert.DeserializeObject<IEvent>(message); if (obj == null) { Log.Warning($"Failed to deserialize the message into a '{typeof(IEvent)}': {message}"); } else { _dispatcher.Dispatch(obj); } } public void Dispose() { _client.Dispose(); _socket.Dispose(); } } } namespace BingoAPI.Networking.DTOs { internal record ChangeTeamRequest { [JsonProperty("room")] public required string Code { get; init; } [JsonProperty("color")] public required Team Team { get; init; } [CompilerGenerated] [SetsRequiredMembers] protected ChangeTeamRequest(ChangeTeamRequest original) { Code = original.Code; Team = original.Team; } public ChangeTeamRequest() { } } internal record ClearSquareRequest { [JsonProperty("room")] public required string Code { get; init; } [JsonProperty("color")] public required Team Team { get; init; } [JsonProperty("slot")] public required string Index { get; init; } [JsonProperty("remove_color")] public bool RemoveColor => true; [CompilerGenerated] [SetsRequiredMembers] protected ClearSquareRequest(ClearSquareRequest original) { Code = original.Code; Team = original.Team; Index = original.Index; } public ClearSquareRequest() { } } internal record CreateRoomRequest { [DataMember(Name = "game_type")] public int GameType => 18; [DataMember(Name = "lockout_mode")] private int LockoutMode { get { if (!IsLockout) { return 1; } return 2; } } [DataMember(Name = "is_spectator")] public bool IsSpectator => false; [DataMember(Name = "variant_type")] private int VariantType { get { if (!IsRandomized) { return 18; } return 172; } } [DataMember(Name = "hide_card")] public bool HideCard => false; private const int RANDOMIZED_VARIANT_TYPE = 172; private const int FIXED_BOARD_VARIANT_TYPE = 18; private const int LOCKOUT_MODE = 2; private const int NON_LOCKOUT_MODE = 1; [DataMember(Name = "room_name")] public required string RoomName; [DataMember(Name = "passphrase")] public required string Password; [DataMember(Name = "nickname")] public required string Nickname; public required bool IsLockout; [DataMember(Name = "seed")] public required string Seed; public required bool IsRandomized; [DataMember(Name = "custom_json")] public required string Board; [DataMember(Name = "csrfmiddlewaretoken")] public required string CreationToken; [CompilerGenerated] protected virtual bool PrintMembers(StringBuilder builder) { RuntimeHelpers.EnsureSufficientExecutionStack(); builder.Append("RoomName = "); builder.Append((object?)RoomName); builder.Append(", Password = "); builder.Append((object?)Password); builder.Append(", Nickname = "); builder.Append((object?)Nickname); builder.Append(", GameType = "); builder.Append(GameType.ToString()); builder.Append(", IsLockout = "); builder.Append(IsLockout.ToString()); builder.Append(", Seed = "); builder.Append((object?)Seed); builder.Append(", IsSpectator = "); builder.Append(IsSpectator.ToString()); builder.Append(", IsRandomized = "); builder.Append(IsRandomized.ToString()); builder.Append(", Board = "); builder.Append((object?)Board); builder.Append(", HideCard = "); builder.Append(HideCard.ToString()); builder.Append(", CreationToken = "); builder.Append((object?)CreationToken); return true; } [CompilerGenerated] [SetsRequiredMembers] protected CreateRoomRequest(CreateRoomRequest original) { RoomName = original.RoomName; Password = original.Password; Nickname = original.Nickname; IsLockout = original.IsLockout; Seed = original.Seed; IsRandomized = original.IsRandomized; Board = original.Board; CreationToken = original.CreationToken; } public CreateRoomRequest() { } } internal record GetSocketInformationResponse { [JsonProperty("room")] [JsonRequired] public required string Code { get; init; } [JsonProperty("player")] [JsonRequired] public required string PlayerUUID { get; init; } [CompilerGenerated] [SetsRequiredMembers] protected GetSocketInformationResponse(GetSocketInformationResponse original) { Code = original.Code; PlayerUUID = original.PlayerUUID; } public GetSocketInformationResponse() { } } internal record JoinRoomRequest { [JsonProperty("room")] public required string Code { get; init; } [JsonProperty("password")] public required string Password { get; init; } [JsonProperty("nickname")] public required string Username { get; init; } [JsonProperty("is_spectator")] public bool IsSpectator => false; [CompilerGenerated] [SetsRequiredMembers] protected JoinRoomRequest(JoinRoomRequest original) { Code = original.Code; Password = original.Password; Username = original.Username; } public JoinRoomRequest() { } } internal record JoinRoomResponse { [JsonProperty("socket_key")] [JsonRequired] public required string SocketKey { get; init; } [CompilerGenerated] [SetsRequiredMembers] protected JoinRoomResponse(JoinRoomResponse original) { SocketKey = original.SocketKey; } public JoinRoomResponse() { } } internal record MarkSquareRequest { [JsonProperty("room")] public required string Code { get; init; } [JsonProperty("color")] public required Team Team { get; init; } [JsonProperty("slot")] public required string Index { get; init; } [JsonProperty("remove_color")] public bool RemoveColor => false; [CompilerGenerated] [SetsRequiredMembers] protected MarkSquareRequest(MarkSquareRequest original) { Code = original.Code; Team = original.Team; Index = original.Index; } public MarkSquareRequest() { } } internal record RevealCardRequest { [JsonProperty("room")] public required string Code { get; init; } [CompilerGenerated] [SetsRequiredMembers] protected RevealCardRequest(RevealCardRequest original) { Code = original.Code; } public RevealCardRequest() { } } internal record SendMessageRequest { [JsonProperty("room")] public required string Code { get; init; } [JsonProperty("text")] public required string Message { get; init; } [CompilerGenerated] [SetsRequiredMembers] protected SendMessageRequest(SendMessageRequest original) { Code = original.Code; Message = original.Message; } public SendMessageRequest() { } } [JsonConverter(typeof(SlotIndexConverter))] public record SlotIndex { public readonly int Index; internal SlotIndex(int index) { Index = index; } } internal record Tokens { public required string PublicToken { get; init; } public required string CreationToken { get; init; } [CompilerGenerated] [SetsRequiredMembers] protected Tokens(Tokens original) { PublicToken = original.PublicToken; CreationToken = original.CreationToken; } public Tokens() { } } } namespace BingoAPI.Networking.Converters { internal class ConditionConverter : JsonConverter<ICondition> { private const string ACTION_KEY = "action"; public override bool CanWrite => false; public override void WriteJson(JsonWriter writer, ICondition? value, JsonSerializer serializer) { throw new NotImplementedException(); } public override ICondition ReadJson(JsonReader reader, Type objectType, ICondition? existingValue, bool hasExistingValue, JsonSerializer serializer) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) JObject val = JObject.Load(reader); string text = ((JToken)val).Value<string>((object)"action"); if (text == null) { throw new JsonException(string.Format("Expected '{0}' property: {1}", "action", val)); } ConditionData data = new ConditionData(val); return ConditionRegistry.Create(text, data); } } internal class EventConverter : JsonConverter { public override bool CanWrite => false; public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) { throw new InvalidOperationException(); } public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) { JObject val = JObject.Load(reader); string text = ((JToken)val).Value<string>((object)"type"); return text switch { "chat" => ((JToken)val).ToObject<ChatEvent>(), "goal" => ((JToken)val).ToObject<GoalEvent>(), "color" => ((JToken)val).ToObject<ColorEvent>(), "revealed" => ((JToken)val).ToObject<CardRevealedEvent>(), "new-card" => ((JToken)val).ToObject<CardGeneratedEvent>(), "connection" => ((JToken)val).ToObject<ConnectionEvent>(), _ => throw new InvalidOperationException($"No event was found of type '{text}': {val}"), }; } public override bool CanConvert(Type objectType) { return objectType == typeof(IEvent); } } internal class SlotIndexConverter : JsonConverter<SlotIndex> { private const string PREFIX = "slot"; public override void WriteJson(JsonWriter writer, SlotIndex? value, JsonSerializer serializer) { int num = 0; if (value != null) { num = value.Index + 1; } writer.WriteValue(string.Format("{0}{1}", "slot", num)); } public override SlotIndex ReadJson(JsonReader reader, Type objectType, SlotIndex? existingValue, bool hasExistingValue, JsonSerializer serializer) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) if (!(reader.Value is string text)) { throw new JsonException(string.Format("Expected a '{0}', but got '{1}'.", "String", reader.ValueType)); } if (!text.StartsWith("slot")) { throw new JsonException("Expected value starting with 'slot'."); } string text2 = text.Substring("slot".Length); if (!int.TryParse(text2, out var result)) { throw new JsonException("Could not parse index from '" + text2 + "'."); } if (result <= 0) { throw new JsonException("Index must be greater than 0."); } return new SlotIndex(result - 1); } } internal class StringEqualConverter : JsonConverter<bool> { private readonly string _value; public override bool CanWrite => false; public StringEqualConverter(string value) { _value = value; } public override void WriteJson(JsonWriter writer, bool value, JsonSerializer serializer) { throw new InvalidOperationException(string.Format("Class '{0}' cannot write a '{1}' as '{2}'.", "StringEqualConverter", typeof(bool), typeof(string))); } public override bool ReadJson(JsonReader reader, Type objectType, bool existingValue, bool hasExistingValue, JsonSerializer serializer) { if (!(reader.Value is string a)) { return false; } return string.Equals(a, _value); } } internal class TeamConverter : JsonConverter<Team> { private static readonly Dictionary<string, Team> TeamMappings = new Dictionary<string, Team>(StringComparer.OrdinalIgnoreCase) { ["pink"] = Team.Pink, ["red"] = Team.Red, ["orange"] = Team.Orange, ["brown"] = Team.Brown, ["yellow"] = Team.Yellow, ["green"] = Team.Green, ["teal"] = Team.Teal, ["blue"] = Team.Blue, ["navy"] = Team.Navy, ["purple"] = Team.Purple, ["blank"] = Team.None }; public override void WriteJson(JsonWriter writer, Team value, JsonSerializer serializer) { List<string> list = new List<string>(); foreach (KeyValuePair<string, Team> teamMapping in TeamMappings) { if (teamMapping.Value != Team.None && value.HasFlag(teamMapping.Value)) { list.Add(teamMapping.Key); } } writer.WriteValue(string.Join(" ", list)); } public override Team ReadJson(JsonReader reader, Type objectType, Team existingValue, bool hasExistingValue, JsonSerializer serializer) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) if (!(reader.Value is string text)) { throw new JsonException($"Expected a '{typeof(string)}', but got '{reader.ValueType}'."); } Team team = Team.None; string[] array = text.Split(new char[1] { ' ' }, StringSplitOptions.RemoveEmptyEntries); foreach (string text2 in array) { if (!TeamMappings.TryGetValue(text2, out var value)) { throw new InvalidOperationException("Unknown team '" + text2 + "'"); } team |= value; } return team; } } } namespace BingoAPI.Networking.Clients { internal sealed class BingoApiClient { public const Team DEFAULT_TEAM = Team.Red; private readonly HttpClient _client; public BingoApiClient(HttpClient client) { _client = client; } private Task<HttpResponseMessage> Send(HttpRequestMessage request, CancellationToken ct) { return _client.SendAsync(request, ct); } private async Task SendAsync(HttpRequestMessage request, CancellationToken ct) { using HttpResponseMessage httpResponseMessage = await Send(request, ct); httpResponseMessage.EnsureSuccessStatusCode(); } private async Task<T> SendAndParse<T>(HttpRequestMessage request, CancellationToken ct) { using HttpResponseMessage response = await _client.SendAsync(request, ct); response.EnsureSuccessStatusCode(); T val = JsonConvert.DeserializeObject<T>(await response.Content.ReadAsStringAsync()); if (val == null) { throw new InvalidOperationException("Failed to deserialize response to " + typeof(T).Name); } return val; } private async Task<Tokens> GetTokens(CancellationToken ct) { using HttpRequestMessage request = new RequestBuilder().Get().ToEndpoint("").Build(); using HttpResponseMessage response = await Send(request, ct); response.EnsureSuccessStatusCode(); CookieContainer cookieContainer = new CookieContainer(); IEnumerable<string> values = response.Headers.GetValues("Set-Cookie"); foreach (string item in values) { cookieContainer.SetCookies(_client.BaseAddress, item); } CookieCollection cookies = cookieContainer.GetCookies(_client.BaseAddress); Cookie publicTokenCookie = cookies["csrftoken"]; if (publicTokenCookie == null) { throw new KeyNotFoundException("No cookie was set for 'csrftoken'."); } Match match = Regex.Match(await response.Content.ReadAsStringAsync(), "<input[^>]*name=\"csrfmiddlewaretoken\"[^>]*value=\"(.*?)\"[^>]*>"); if (!match.Success) { throw new KeyNotFoundException("Could not find any input with 'csrfmiddlewaretoken'."); } return new Tokens { PublicToken = publicTokenCookie.Value, CreationToken = match.Groups[1].Value }; } public async Task<string> CreateRoom(CreateRoomSettings settings, CancellationToken ct) { throw new NotImplementedException(); } public async Task<string> JoinRoom(JoinRoomSettings settings, CancellationToken ct) { JoinRoomRequest json = new JoinRoomRequest { Code = settings.Code, Password = settings.Password, Username = settings.Nickname }; using HttpRequestMessage request = new RequestBuilder().Post().ToEndpoint("/api/join-room").WithJson(json) .Build(); return (await SendAndParse<JoinRoomResponse>(request, ct)).SocketKey; } public async Task MarkSquare(string room, Team team, int index, CancellationToken ct) { MarkSquareRequest json = new MarkSquareRequest { Code = room, Team = team, Index = (index + 1).ToString() }; using HttpRequestMessage request = new RequestBuilder().Put().ToEndpoint("/api/select").WithJson(json) .Build(); await SendAsync(request, ct); } public async Task ClearSquare(string room, Team team, int index, CancellationToken ct) { ClearSquareRequest json = new ClearSquareRequest { Code = room, Team = team, Index = (index + 1).ToString() }; using HttpRequestMessage request = new RequestBuilder().Put().ToEndpoint("/api/select").WithJson(json) .Build(); await SendAsync(request, ct); } public async Task SendMessage(string room, string message, CancellationToken ct) { SendMessageRequest json = new SendMessageRequest { Code = room, Message = message }; using HttpRequestMessage request = new RequestBuilder().Put().ToEndpoint("/api/chat").WithJson(json) .Build(); await SendAsync(request, ct); } public async Task ChangeTeam(string room, Team team, CancellationToken ct) { ChangeTeamRequest json = new ChangeTeamRequest { Code = room, Team = team }; using HttpRequestMessage request = new RequestBuilder().Put().ToEndpoint("/api/color").WithJson(json) .Build(); await SendAsync(request, ct); } public async Task<Square[]> GetSquares(string room, CancellationToken ct) { using HttpRequestMessage request = new RequestBuilder().Get().ToEndpoint("/room/" + room + "/board").Build(); return await SendAndParse<Square[]>(request, ct); } public async Task RevealCard(string room, CancellationToken ct) { RevealCardRequest json = new RevealCardRequest { Code = room }; using HttpRequestMessage request = new RequestBuilder().Put().ToEndpoint("/api/revealed").WithJson(json) .Build(); await SendAsync(request, ct); } public async Task<GetSocketInformationResponse> GetSocketInformation(string socketKey, CancellationToken ct) { using HttpRequestMessage request = new RequestBuilder().Get().ToEndpoint("/api/socket/" + socketKey).Build(); return await SendAndParse<GetSocketInformationResponse>(request, ct); } } internal sealed class BingoSocketClient : IDisposable { private WebSocket? _socket; private CancellationTokenSource? _cts; private Task? _socketReceiveTask; public async Task Connect(string socketKey, Action<string> onMessageReceived, CancellationToken ct) { if (_socket != null) { throw new InvalidOperationException("Socket is already connected."); } ClientWebSocket socket = new ClientWebSocket(); try { await socket.ConnectAsync(new Uri("wss://sockets.bingosync.com/broadcast"), ct); string s = JsonConvert.SerializeObject((object)new { socket_key = socketKey }); await socket.SendAsync(new ArraySegment<byte>(Encoding.UTF8.GetBytes(s)), WebSocketMessageType.Text, endOfMessage: true, ct); _socket = socket; _cts = new CancellationTokenSource(); _socketReceiveTask = ReceiveLoop(_socket, onMessageReceived, _cts.Token); } catch { socket.Dispose(); throw; } } public async Task Disconnect(CancellationToken ct) { if (_socket == null) { return; } _cts?.Cancel(); try { if (_socket.State == WebSocketState.Open) { await _socket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Client disconnecting", ct); } } catch (Exception ex) { Log.Error("Error closing WebSocket: " + ex.Message); } if (_socketReceiveTask != null) { try { await _socketReceiveTask; } catch (OperationCanceledException) { } catch (ObjectDisposedException) { } catch (Exception ex4) { Log.Error("Receive loop failed during disconnect: " + ex4.Message); } } CleanUp(); } private static async Task ReceiveLoop(WebSocket socket, Action<string> onReceive, CancellationToken ct) { byte[] buffer = new byte[1024]; using MemoryStream ms = new MemoryStream(); while (!ct.IsCancellationRequested && socket.State == WebSocketState.Open) { WebSocketReceiveResult webSocketReceiveResult; do { webSocketReceiveResult = await socket.ReceiveAsync(new ArraySegment<byte>(buffer), ct); ms.Write(buffer, 0, webSocketReceiveResult.Count); } while (!webSocketReceiveResult.EndOfMessage); if (webSocketReceiveResult.MessageType == WebSocketMessageType.Close) { Log.Debug("Close message was received."); break; } if (webSocketReceiveResult.MessageType == WebSocketMessageType.Text) { string text = Encoding.UTF8.GetString(ms.ToArray()); Log.Debug("Message received:\n" + text); try { onReceive(text); } catch (Exception arg) { Log.Error($"Error handling socket message: {arg}"); } } ms.Seek(0L, SeekOrigin.Begin); ms.SetLength(0L); } } private void CleanUp() { _socket?.Dispose(); _cts?.Dispose(); _socket = null; _cts = null; _socketReceiveTask = null; } public void Dispose() { CleanUp(); } } } namespace BingoAPI.Models { public sealed class Card { private struct CardSquare { public readonly Goal Goal; public Team Teams { get; set; } public CardSquare(Square square, Goal goal) { Goal = goal; Teams = square.Teams; } } private readonly CardSquare[] _squares; internal Card(Square[] squares, GoalPool pool) { _squares = new CardSquare[squares.Length]; foreach (Square square in squares) { int index = square.Slot.Index; if (index < 0 || index >= _squares.Length) { throw new ArgumentOutOfRangeException("square"); } if (!pool.TryGet(square, out Goal goal)) { throw new KeyNotFoundException("Failed to find a goal under the name '" + square.Text + "'."); } _squares[index] = new CardSquare(square, goal); } } public Goal GetGoalAt(int index) { return _squares[index].Goal; } public Goal[] GetAllGoals() { HashSet<Goal> hashSet = new HashSet<Goal>(); CardSquare[] squares = _squares; for (int i = 0; i < squares.Length; i++) { CardSquare cardSquare = squares[i]; hashSet.Add(cardSquare.Goal); } return hashSet.ToArray(); } public int[] FindByGoal(Goal goal) { List<int> list = new List<int>(); for (int i = 0; i < _squares.Length; i++) { if (!(GetGoalAt(i) != goal)) { list.Add(i); } } return list.ToArray(); } public Team GetTeamsAt(int index) { return _squares[index].Teams; } public bool IsMarkedBy(int index, Team team) { return GetTeamsAt(index).HasFlag(team); } public void Mark(int index, Team team) { _squares[index].Teams |= team; } public void Unmark(int index, Team team) { _squares[index].Teams &= (Team)(ushort)(~(int)team); } } public record Player { [JsonProperty("uuid")] [JsonRequired] public required string UUID { get; init; } [JsonProperty("name")] [JsonRequired] public required string Name { get; init; } [JsonProperty("color")] [JsonRequired] public required Team Team { get; init; } [CompilerGenerated] [SetsRequiredMembers] protected Player(Player original) { UUID = original.UUID; Name = original.Name; Team = original.Team; } public Player() { } } public record Square { [JsonProperty("name")] [JsonRequired] public required string Text { get; init; } [JsonProperty("slot")] [JsonRequired] public required SlotIndex Slot { get; init; } [JsonProperty("colors")] [JsonRequired] public required Team Teams { get; init; } [CompilerGenerated] [SetsRequiredMembers] protected Square(Square original) { Text = original.Text; Slot = original.Slot; Teams = original.Teams; } public Square() { } } [Flags] [JsonConverter(typeof(TeamConverter))] public enum Team : ushort { None = 0, Pink = 1, Red = 2, Orange = 4, Brown = 8, Yellow = 0x10, Green = 0x20, Teal = 0x40, Blue = 0x80, Navy = 0x100, Purple = 0x200 } } namespace BingoAPI.Models.Settings { public record CreateRoomSettings { public string Name { get; set; } = string.Empty; public string Password { get; set; } = string.Empty; public string Nickname { get; set; } = string.Empty; public bool IsRandomized { get; set; } public bool IsLockout { get; set; } public string Seed { get; set; } = string.Empty; } public record JoinRoomSettings { public string Code { get; set; } = string.Empty; public string Password { get; set; } = string.Empty; public string Nickname { get; set; } = string.Empty; } } namespace BingoAPI.Helpers { public static class Log { public enum LogLevel { Debug, Info, Warning, Error } public static Action<LogLevel, string>? Logger { private get; set; } private static void LogMessage(LogLevel level, string? message) { Logger?.Invoke(level, message ?? string.Empty); } internal static void Debug(string? message) { LogMessage(LogLevel.Debug, message); } internal static void Info(string? message) { LogMessage(LogLevel.Info, message); } internal static void Warning(string? message) { LogMessage(LogLevel.Warning, message); } internal static void Error(string? message) { LogMessage(LogLevel.Error, message); } } public static class Network { public static bool TryGetRoomCode(string url, [NotNullWhen(true)] out string? code) { Match match = Regex.Match(url, "(?<=/room/)[a-zA-Z\\d-_]+"); if (!match.Success) { code = null; return false; } code = match.Value; return true; } } } namespace BingoAPI.Goals { public sealed record Goal { [JsonProperty("name")] [JsonRequired] public required string Name { get; init; } [JsonProperty("condition")] [JsonRequired] public required ICondition Condition { get; init; } [CompilerGenerated] [SetsRequiredMembers] private Goal(Goal original) { Name = original.Name; Condition = original.Condition; } public Goal() { } } public sealed class GoalPool : IEnumerable<Goal>, IEnumerable { private readonly Dictionary<string, Goal> _goals = new Dictionary<string, Goal>(StringComparer.OrdinalIgnoreCase); public int Count => _goals.Count; public void Add(Goal goal) { if (!TryAdd(goal)) { throw new ArgumentException("The goal has already been added.", "goal"); } } public bool TryAdd(Goal goal) { if (_goals.ContainsKey(goal.Name)) { return false; } _goals.Add(goal.Name, goal); return true; } public bool TryGet(Square square, [NotNullWhen(true)] out Goal? goal) { return _goals.TryGetValue(square.Text, out goal); } public IEnumerator<Goal> GetEnumerator() { return _goals.Values.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } } public sealed record GoalSet { [JsonProperty("name")] public string Name { get; init; } = string.Empty; [JsonProperty("description")] public string Description { get; init; } = string.Empty; [JsonProperty("goals")] [JsonRequired] public required Goal[] Goals { get; init; } [CompilerGenerated] [SetsRequiredMembers] private GoalSet(GoalSet original) { Name = original.Name; Description = original.Description; Goals = original.Goals; } public GoalSet() { } } public sealed class GoalTracker { public delegate void GoalChangedCallback(Goal goal); private readonly HashSet<Goal> _trackedGoals = new HashSet<Goal>(); private readonly HashSet<Goal> _metGoals = new HashSet<Goal>(); public event GoalChangedCallback? OnGoalMarked; public event GoalChangedCallback? OnGoalCleared; public bool TryAdd(Goal goal) { return _trackedGoals.Add(goal); } public void Clear() { _trackedGoals.Clear(); _metGoals.Clear(); } public void Evaluate() { foreach (Goal trackedGoal in _trackedGoals) { bool wasInitiallyMet = _metGoals.Contains(trackedGoal); bool isCurrentlyMet; try { isCurrentlyMet = trackedGoal.Condition.IsMet(); } catch (Exception arg) { Log.Error($"Error while evaluating '{trackedGoal.Name}': {arg}"); isCurrentlyMet = false; } DispatchChange(wasInitiallyMet, isCurrentlyMet, trackedGoal); } } private void DispatchChange(bool wasInitiallyMet, bool isCurrentlyMet, Goal goal) { if (wasInitiallyMet != isCurrentlyMet) { if (isCurrentlyMet) { _metGoals.Add(goal); this.OnGoalMarked?.Invoke(goal); } else { _metGoals.Remove(goal); this.OnGoalCleared?.Invoke(goal); } } } } } namespace BingoAPI.Events { public sealed class EventDispatcher { public delegate void ConnectionCallback(Player player); public delegate void DisconnectionCallback(Player player); public delegate void MarkCallback(Player player, Square square, Team team); public delegate void ClearCallback(Player player, Square square, Team team); public delegate void ChatCallback(Player player, string message, ulong timestamp); public delegate void TeamCallback(Player player, Team newTeam); public delegate void RevealCallback(Player player); public delegate void GenerateCallback(Player player, bool isHidden); private Player? _localPlayer; public event ConnectionCallback? OnSelfConnected; public event DisconnectionCallback? OnSelfDisconnected; public event MarkCallback? OnSelfSquareMarked; public event ClearCallback? OnSelfSquareCleared; public event ChatCallback? OnSelfMessageSent; public event TeamCallback? OnSelfTeamChanged; public event RevealCallback? OnSelfCardRevealed; public event GenerateCallback? OnSelfCardGenerated; public event ConnectionCallback? OnOtherConnected; public event DisconnectionCallback? OnOtherDisconnected; public event MarkCallback? OnOtherSquareMarked; public event ClearCallback? OnOtherSquareCleared; public event ChatCallback? OnOtherMessageSent; public event TeamCallback? OnOtherTeamChanged; public event RevealCallback? OnOtherCardRevealed; public event GenerateCallback? OnOtherCardGenerated; private bool IsLocal(Player player) { return player.UUID == _localPlayer?.UUID; } internal void DispatchConnect(Player player) { _localPlayer = player; this.OnSelfConnected?.Invoke(player); } internal void DispatchDisconnect() { if (!(_localPlayer == null)) { this.OnSelfDisconnected?.Invoke(_localPlayer); _localPlayer = null; } } internal void Dispatch(IEvent evt) { if (!(evt is ConnectionEvent connectionEvent)) { if (!(evt is ChatEvent evt2)) { if (!(evt is ColorEvent evt3)) { if (!(evt is GoalEvent goalEvent)) { if (!(evt is CardRevealedEvent evt4)) { if (evt is CardGeneratedEvent evt5) { DispatchCardGenerated(evt5); } } else { DispatchCardRevealed(evt4); } } else if (goalEvent.HasBeenCleared) { DispatchGoalCleared(goalEvent); } else { DispatchGoalMarked(goalEvent); } } else { DispatchColorEvent(evt3); } } else { DispatchChatEvent(evt2); } } else if (connectionEvent.IsConnected) { DispatchConnectedEvent(connectionEvent); } else { DispatchDisconnectedEvent(connectionEvent); } } private void DispatchConnectedEvent(ConnectionEvent evt) { if (!IsLocal(evt.Player)) { this.OnOtherConnected?.Invoke(evt.Player); } } private void DispatchDisconnectedEvent(ConnectionEvent evt) { if (!IsLocal(evt.Player)) { this.OnOtherDisconnected?.Invoke(evt.Player); } } private void DispatchChatEvent(ChatEvent evt) { if (IsLocal(evt.Player)) { this.OnSelfMessageSent?.Invoke(evt.Player, evt.Text, evt.Timestamp); } else { this.OnOtherMessageSent?.Invoke(evt.Player, evt.Text, evt.Timestamp); } } private void DispatchColorEvent(ColorEvent evt) { if (IsLocal(evt.Player)) { this.OnSelfTeamChanged?.Invoke(evt.Player, evt.NewColor); } else { this.OnOtherTeamChanged?.Invoke(evt.Player, evt.NewColor); } } private void DispatchGoalMarked(GoalEvent evt) { if (IsLocal(evt.Player)) { this.OnSelfSquareMarked?.Invoke(evt.Player, evt.Square, evt.Team); } else { this.OnOtherSquareMarked?.Invoke(evt.Player, evt.Square, evt.Team); } } private void DispatchGoalCleared(GoalEvent evt) { if (IsLocal(evt.Player)) { this.OnSelfSquareCleared?.Invoke(evt.Player, evt.Square, evt.Team); } else { this.OnOtherSquareCleared?.Invoke(evt.Player, evt.Square, evt.Team); } } private void DispatchCardRevealed(CardRevealedEvent evt) { if (IsLocal(evt.Player)) { this.OnSelfCardRevealed?.Invoke(evt.Player); } else { this.OnOtherCardRevealed?.Invoke(evt.Player); } } private void DispatchCardGenerated(CardGeneratedEvent evt) { if (IsLocal(evt.Player)) { this.OnSelfCardGenerated?.Invoke(evt.Player, evt.IsCardHidden); } else { this.OnOtherCardGenerated?.Invoke(evt.Player, evt.IsCardHidden); } } } internal interface IEvent { } } namespace BingoAPI.Events.BuiltIn { internal record CardGeneratedEvent : IEvent { [JsonProperty("player")] [JsonRequired] public required Player Player { get; init; } [JsonProperty("hide_card")] [JsonRequired] public required bool IsCardHidden { get; init; } [JsonProperty("timestamp")] [JsonRequired] public required ulong Timestamp { get; init; } [CompilerGenerated] [SetsRequiredMembers] protected CardGeneratedEvent(CardGeneratedEvent original) { Player = original.Player; IsCardHidden = original.IsCardHidden; Timestamp = original.Timestamp; } public CardGeneratedEvent() { } } internal record CardRevealedEvent : IEvent { [JsonProperty("player")] [JsonRequired] public required Player Player { get; init; } [JsonProperty("timestamp")] [JsonRequired] public required ulong Timestamp { get; init; } [CompilerGenerated] [SetsRequiredMembers] protected CardRevealedEvent(CardRevealedEvent original) { Player = original.Player; Timestamp = original.Timestamp; } public CardRevealedEvent() { } } internal record ChatEvent : IEvent { [JsonProperty("player")] [JsonRequired] public required Player Player { get; init; } [JsonProperty("timestamp")] [JsonRequired] public required ulong Timestamp { get; init; } [JsonProperty("text")] [JsonRequired] public required string Text { get; init; } [CompilerGenerated] [SetsRequiredMembers] protected ChatEvent(ChatEvent original) { Player = original.Player; Timestamp = original.Timestamp; Text = original.Text; } public ChatEvent() { } } internal record ColorEvent : IEvent { [JsonProperty("player")] [JsonRequired] public required Player Player { get; init; } [JsonProperty("player_color")] [JsonRequired] public required Team PreviousColor { get; init; } [JsonProperty("color")] [JsonRequired] public required Team NewColor { get; init; } [JsonProperty("timestamp")] [JsonRequired] public required ulong Timestamp { get; init; } [CompilerGenerated] [SetsRequiredMembers] protected ColorEvent(ColorEvent original) { Player = original.Player; PreviousColor = original.PreviousColor; NewColor = original.NewColor; Timestamp = original.Timestamp; } public ColorEvent() { } } internal record ConnectionEvent : IEvent { [JsonProperty("player")] [JsonRequired] public required Player Player { get; init; } [JsonProperty("room")] [JsonRequired] public required string RoomId { get; init; } [JsonProperty("timestamp")] [JsonRequired] public required ulong Timestamp { get; init; } [JsonProperty("event_type")] [JsonConverter(typeof(StringEqualConverter), new object[] { "connected" })] public required bool IsConnected { get; init; } [CompilerGenerated] [SetsRequiredMembers] protected ConnectionEvent(ConnectionEvent original) { Player = original.Player; RoomId = original.RoomId; Timestamp = original.Timestamp; IsConnected = original.IsConnected; } public ConnectionEvent() { } } internal record GoalEvent : IEvent { [JsonProperty("player")] [JsonRequired] public required Player Player { get; init; } [JsonProperty("timestamp")] [JsonRequired] public required ulong Timestamp { get; init; } [JsonProperty("square")] [JsonRequired] public required Square Square { get; init; } [JsonProperty("color")] [JsonRequired] public required Team Team { get; init; } [JsonProperty("remove")] [JsonRequired] public required bool HasBeenCleared { get; init; } [CompilerGenerated] [SetsRequiredMembers] protected GoalEvent(GoalEvent original) { Player = original.Player; Timestamp = original.Timestamp; Square = original.Square; Team = original.Team; HasBeenCleared = original.HasBeenCleared; } public GoalEvent() { } } } namespace BingoAPI.Conditions { [AttributeUsage(AttributeTargets.Constructor | AttributeTargets.Method)] public class ConditionAttribute : Attribute { private record FactoryEntry { public required string Action { get; init; } public required Func<ConditionData, ICondition> Factory { get; init; } public required string SourceName { get; init; } [CompilerGenerated] [SetsRequiredMembers] protected FactoryEntry(FactoryEntry original) { Action = original.Action; Factory = original.Factory; SourceName = original.SourceName; } public FactoryEntry() { } } public readonly string Action; public ConditionAttribute(string action) { Action = action; } public static void AddAll() { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { AddAll(assembly); } } public static void AddAll(Assembly assembly) { IEnumerable<Type> types; try { types = assembly.GetTypes(); } catch (ReflectionTypeLoadException ex) { types = ex.Types; } foreach (Type item in types) { if (!(item == null)) { AddAll(item); } } } public static void AddAll(Type type) { IEnumerable<FactoryEntry> enumerable = GetFactoryMethods(type).Concat(GetFactoryConstructors(type)); foreach (FactoryEntry item in enumerable) { Log.Debug("Trying to add '" + item.Action + "' from '" + item.SourceName + "'."); ConditionRegistry.TryAdd(item.Action, item.Factory); } } private static IEnumerable<FactoryEntry> GetFactoryMethods(Type type) { MethodInfo[] methods = type.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); MethodInfo[] array = methods; foreach (MethodInfo method in array) { ConditionAttribute customAttribute = method.GetCustomAttribute<ConditionAttribute>(); if (customAttribute == null) { continue; } if (!typeof(ICondition).IsAssignableFrom(method.ReturnType)) { Log.Warning("Method '" + method.Name + "' must return 'ICondition'."); continue; } ParameterInfo[] parameters = method.GetParameters(); if (parameters.Length != 1 || parameters[0].ParameterType != typeof(ConditionData)) { Log.Warning("Method '" + method.Name + "' must only take 'ConditionData'."); continue; } yield return new FactoryEntry { Action = customAttribute.Action, Factory = (ConditionData data) => (ICondition)method.Invoke(null, new object[1] { data }), SourceName = method.Name }; } } private static IEnumerable<FactoryEntry> GetFactoryConstructors(Type type) { ConstructorInfo[] constructors = type.GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); ConstructorInfo[] array = constructors; foreach (ConstructorInfo ctor in array) { ConditionAttribute customAttribute = ctor.GetCustomAttribute<ConditionAttribute>(); if (customAttribute == null || !typeof(ICondition).IsAssignableFrom(type)) { continue; } ParameterInfo[] parameters = ctor.GetParameters(); if (parameters.Length != 1 || parameters[0].ParameterType != typeof(ConditionData)) { Log.Warning("Constructor '" + type.Name + "' must only take 'ConditionData'."); continue; } yield return new FactoryEntry { Action = customAttribute.Action, Factory = (ConditionData data) => (ICondition)ctor.Invoke(new object[1] { data }), SourceName = (type.FullName ?? type.Name) }; } } } public sealed class ConditionData { private readonly JObject _json; internal ConditionData(JObject json) { _json = json; } private bool TryGetParameter<T>(string key, out T? value) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Invalid comparison between Unknown and I4 value = default(T); JToken obj = _json["params"]; JObject val = (JObject)(object)((obj is JObject) ? obj : null); if (val == null) { return false; } JToken val2 = default(JToken); if (!val.TryGetValue(key, ref val2)) { return false; } if ((int)val2.Type == 10) { return false; } value = val2.ToObject<T>(); return value != null; } public T GetRequiredParameter<T>(string key) where T : notnull { //IL_0028: Unknown result type (might be due to invalid IL or missing references) if (!TryGetParameter<T>(key, out T value) || value == null) { throw new JsonException($"Failed to find '{key}' of type '{typeof(T)}'."); } return value; } public T GetOptionalParameter<T>(string key, T defaultValue) where T : notnull { if (!TryGetParameter<T>(key, out T value)) { return defaultValue; } T val = value; if (val == null) { return defaultValue; } return val; } } public static class ConditionRegistry { private static readonly Dictionary<string, Func<ConditionData, ICondition>> Factories = new Dictionary<string, Func<ConditionData, ICondition>>(StringComparer.OrdinalIgnoreCase); public static void TryAdd(string action, Func<ConditionData, ICondition> factory) { if (!Factories.ContainsKey(action)) { Factories.Add(action, factory); } } internal static ICondition Create(string action, ConditionData data) { if (!Factories.TryGetValue(action, out Func<ConditionData, ICondition> value)) { throw new InvalidOperationException("No condition registered under the action '" + action + "'."); } return value(data); } } [JsonConverter(typeof(ConditionConverter))] public interface ICondition { bool IsMet(); } } namespace BingoAPI.Conditions.BuiltIn { internal sealed class AndCondition : ICondition { private readonly ICondition[] _conditions; [Condition("AND")] public AndCondition(ConditionData data) { _conditions = data.GetRequiredParameter<ICondition[]>("conditions"); } public bool IsMet() { return _conditions.All((ICondition condition) => condition.IsMet()); } } internal sealed class NotCondition : ICondition { private readonly ICondition _condition; [Condition("NOT")] public NotCondition(ConditionData data) { _condition = data.GetRequiredParameter<ICondition>("condition"); } public bool IsMet() { return !_condition.IsMet(); } } internal sealed class OrCondition : ICondition { private readonly ICondition[] _conditions; [Condition("OR")] public OrCondition(ConditionData data) { _conditions = data.GetRequiredParameter<ICondition[]>("conditions"); } public bool IsMet() { return _conditions.Any((ICondition condition) => condition.IsMet()); } } internal sealed class SomeCondition : ICondition { private readonly ICondition[] _conditions; private readonly uint _amount; [Condition("SOME")] public SomeCondition(ConditionData data) { _conditions = data.GetRequiredParameter<ICondition[]>("conditions"); _amount = data.GetOptionalParameter("amount", 1u); } public bool IsMet() { if (_conditions.Length < _amount) { return false; } int num = 0; ICondition[] conditions = _conditions; foreach (ICondition condition in conditions) { if (condition.IsMet()) { num++; if (num >= _amount) { return true; } } } return false; } } }