using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Threading;
using HarmonyLib;
using Il2CppCS.CorePlatform;
using Il2CppCS.CorePlatform.Utils.Data;
using Il2CppCoreNet;
using Il2CppCoreNet.Components.Client;
using Il2CppCoreNet.Contexts;
using Il2CppCostumes;
using Il2CppFemur;
using Il2CppGB.Core.Loading;
using Il2CppGB.NetworkedInput;
using Il2CppGB.Platform.Lobby;
using Il2CppGB.Platform.Lobby.Messages;
using Il2CppGB.Platform.Lobby.Utils;
using Il2CppGB.UI.Beasts;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppSystem;
using Il2CppSystem.Reflection;
using Il2CppTMPro;
using MelonLoader;
using MelonLoader.Utils;
using Microsoft.CodeAnalysis;
using ProCon;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.Networking;
using UnityEngine.SceneManagement;
using UnityEngine.TextCore.LowLevel;
using UnityEngine.UI;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: MelonInfo(typeof(ProConMod), "ProCon", "1.0.0", "AxisGames", null)]
[assembly: MelonGame("Boneloaf", "Gang Beasts")]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.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.Module, AllowMultiple = false, Inherited = false)]
internal sealed class RefSafetyRulesAttribute : Attribute
{
public readonly int Version;
public RefSafetyRulesAttribute(int P_0)
{
Version = P_0;
}
}
}
namespace ProCon
{
internal static class Badge
{
private static GameObject badge;
private static TMP_Text text;
public static void Tick()
{
string text = Session.BadgeLine();
if ((Object)(object)badge == (Object)null)
{
if (text == null || (Object)(object)MenuFont.Font == (Object)null)
{
return;
}
Build();
}
badge.SetActive(text != null);
if (text != null)
{
Badge.text.text = text;
}
}
private static void Build()
{
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
//IL_000b: Expected O, but got Unknown
//IL_0040: 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_0063: Expected O, but got Unknown
//IL_0097: Unknown result type (might be due to invalid IL or missing references)
//IL_009d: Unknown result type (might be due to invalid IL or missing references)
//IL_009e: Unknown result type (might be due to invalid IL or missing references)
//IL_009f: Unknown result type (might be due to invalid IL or missing references)
//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
//IL_00b6: 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_0124: Unknown result type (might be due to invalid IL or missing references)
GameObject val = new GameObject("ProCon Badge");
Object.DontDestroyOnLoad((Object)(object)val);
Canvas obj = val.AddComponent<Canvas>();
obj.renderMode = (RenderMode)0;
obj.sortingOrder = 5000;
CanvasScaler obj2 = val.AddComponent<CanvasScaler>();
obj2.uiScaleMode = (ScaleMode)1;
obj2.referenceResolution = new Vector2(1920f, 1080f);
obj2.matchWidthOrHeight = 0.5f;
badge = new GameObject("Badge");
badge.transform.SetParent(val.transform, false);
RectTransform obj3 = badge.AddComponent<RectTransform>();
Vector2 val2 = default(Vector2);
((Vector2)(ref val2))..ctor(0f, 1f);
obj3.pivot = val2;
Vector2 anchorMin = (obj3.anchorMax = val2);
obj3.anchorMin = anchorMin;
obj3.anchoredPosition = new Vector2(28f, -22f);
obj3.sizeDelta = new Vector2(700f, 70f);
text = (TMP_Text)(object)badge.AddComponent<TextMeshProUGUI>();
text.font = MenuFont.Font;
text.fontSharedMaterial = MenuFont.OutlinedMaterial;
text.fontSize = 40f;
((Graphic)text).color = new Color(1f, 0.78f, 0.05f);
text.alignment = (TextAlignmentOptions)513;
text.enableWordWrapping = false;
((Graphic)text).raycastTarget = false;
}
}
internal static class Clipboard
{
private const uint CF_UNICODETEXT = 13u;
[DllImport("user32.dll")]
private static extern bool OpenClipboard(IntPtr owner);
[DllImport("user32.dll")]
private static extern bool CloseClipboard();
[DllImport("user32.dll")]
private static extern IntPtr GetClipboardData(uint format);
[DllImport("user32.dll")]
private static extern bool EmptyClipboard();
[DllImport("user32.dll")]
private static extern IntPtr SetClipboardData(uint format, IntPtr h);
[DllImport("kernel32.dll")]
private static extern IntPtr GlobalLock(IntPtr h);
[DllImport("kernel32.dll")]
private static extern bool GlobalUnlock(IntPtr h);
[DllImport("kernel32.dll")]
private static extern IntPtr GlobalAlloc(uint flags, UIntPtr bytes);
public static string Get()
{
if (!OpenClipboard(IntPtr.Zero))
{
return "";
}
try
{
IntPtr clipboardData = GetClipboardData(13u);
if (clipboardData == IntPtr.Zero)
{
return "";
}
IntPtr ptr = GlobalLock(clipboardData);
try
{
return Marshal.PtrToStringUni(ptr) ?? "";
}
finally
{
GlobalUnlock(clipboardData);
}
}
finally
{
CloseClipboard();
}
}
public static void Set(string text)
{
if (!OpenClipboard(IntPtr.Zero))
{
return;
}
try
{
EmptyClipboard();
IntPtr h = GlobalAlloc(2u, (UIntPtr)(ulong)((text.Length + 1) * 2));
IntPtr destination = GlobalLock(h);
Marshal.Copy((text + "\0").ToCharArray(), 0, destination, text.Length + 1);
GlobalUnlock(h);
SetClipboardData(13u, h);
}
finally
{
CloseClipboard();
}
}
}
internal static class ConsoleFix
{
private const int STD_INPUT_HANDLE = -10;
private const uint ENABLE_QUICK_EDIT_MODE = 64u;
private const uint ENABLE_EXTENDED_FLAGS = 128u;
[DllImport("kernel32.dll")]
private static extern IntPtr GetStdHandle(int handle);
[DllImport("kernel32.dll")]
private static extern bool GetConsoleMode(IntPtr h, out uint mode);
[DllImport("kernel32.dll")]
private static extern bool SetConsoleMode(IntPtr h, uint mode);
public static void DisableQuickEdit()
{
try
{
IntPtr stdHandle = GetStdHandle(-10);
if (GetConsoleMode(stdHandle, out var mode))
{
SetConsoleMode(stdHandle, (mode & 0xFFFFFFBFu) | 0x80);
}
}
catch
{
}
}
}
internal static class LobbySync
{
private class Remote
{
public BaseUserInfo User;
public int Master;
public readonly Dictionary<int, byte[]> Beasts = new Dictionary<int, byte[]>();
public readonly HashSet<int> Spawned = new HashSet<int>();
}
public const byte Message = 6;
public static readonly ConcurrentQueue<(ulong from, byte[] data)> Incoming = new ConcurrentQueue<(ulong, byte[])>();
private static readonly Dictionary<ulong, Remote> remotes = new Dictionary<ulong, Remote>();
private static readonly Dictionary<ulong, List<(int ctrl, byte[] data)>> latest = new Dictionary<ulong, List<(int, byte[])>>();
private static float sendTimer;
private static int nextMaster;
public static bool Active;
public static void Tick(bool hosting)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
Scene activeScene = SceneManager.GetActiveScene();
bool flag = ((Scene)(ref activeScene)).name == "Menu";
if (!Active || !flag)
{
if (remotes.Count > 0)
{
Clear();
}
DrainIncoming(apply: false);
return;
}
DrainIncoming(apply: true);
sendTimer -= Time.unscaledDeltaTime;
if (sendTimer > 0f)
{
return;
}
sendTimer = 0.4f;
List<(int, byte[])> list = LocalBeasts();
if (hosting)
{
foreach (ulong item in Relay.FriendIds())
{
List<(ulong, int, byte[])> list2 = new List<(ulong, int, byte[])>();
foreach (var item2 in list)
{
list2.Add((SteamNet.MySteamId, item2.Item1, item2.Item2));
}
foreach (KeyValuePair<ulong, List<(int, byte[])>> item3 in latest)
{
if (item3.Key != item)
{
foreach (var item4 in item3.Value)
{
list2.Add((item3.Key, item4.Item1, item4.Item2));
}
}
}
Relay.SendLobby(item, Pack(list2));
}
return;
}
List<(ulong, int, byte[])> list3 = new List<(ulong, int, byte[])>();
foreach (var item5 in list)
{
list3.Add((SteamNet.MySteamId, item5.Item1, item5.Item2));
}
Relay.SendLobby(0uL, Pack(list3));
}
private static List<(int ctrl, byte[] data)> LocalBeasts()
{
//IL_0066: Unknown result type (might be due to invalid IL or missing references)
//IL_008a: Unknown result type (might be due to invalid IL or missing references)
//IL_0091: Expected O, but got Unknown
//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
List<(int, byte[])> list = new List<(int, byte[])>();
LobbyManager instance = LobbyManager.Instance;
LocalBeastSetupTracker val = ((instance != null) ? instance.LocalBeasts : null);
object obj;
if (instance == null)
{
obj = null;
}
else
{
LocalBeastMessageSender beastMessageSender = instance.BeastMessageSender;
obj = ((beastMessageSender != null) ? beastMessageSender._beastMessages : null);
}
Il2CppReferenceArray<BeastInfoMesssage> val2 = (Il2CppReferenceArray<BeastInfoMesssage>)obj;
if ((Object)(object)val == (Object)null || val2 == null)
{
return list;
}
BeastMenuState state = Object.FindObjectOfType<BeastMenuState>();
for (int i = 0; i < ((Il2CppArrayBase<BeastInfoMesssage>)(object)val2).Length && i < ((Il2CppArrayBase<LocalPlayerInfomationCache>)(object)val.PlayerInfo).Length; i++)
{
LocalPlayerInfomationCache val3 = ((Il2CppArrayBase<LocalPlayerInfomationCache>)(object)val.PlayerInfo)[i];
if (val3 == null || (int)val3.CurrentState == 0)
{
continue;
}
BeastInfoMesssage obj2 = ((Il2CppArrayBase<BeastInfoMesssage>)(object)val2)[i];
BeastInfo val4 = ((obj2 != null) ? obj2.Info : null);
if (val4 != null)
{
BeastInfo val5 = new BeastInfo();
val5.Copy(val4);
val5.SetControllerID(i);
val5.SetState(val3.CurrentState);
if (val3.ColourIndex >= 0)
{
val5.SetColour(val3.ColourIndex);
}
val5.SetTeam(val3.TeamIndex);
CostumeSaveEntry val6 = ShownCostume(state, i);
if (val6 != null)
{
val5.SetCostume(val6);
}
list.Add((i, ToBytes(val5)));
}
}
return list;
}
private static CostumeSaveEntry ShownCostume(BeastMenuState state, int playerID)
{
try
{
Il2CppReferenceArray<PointState> val = ((state != null) ? state._pointStates : null);
if (val == null)
{
return null;
}
foreach (PointState item in (Il2CppArrayBase<PointState>)(object)val)
{
if (((item != null) ? item._linkedLocal : null) != null && item._linkedLocal.PlayerID == playerID)
{
return item._costumeCache;
}
}
}
catch
{
}
return null;
}
private static void DrainIncoming(bool apply)
{
(ulong, byte[]) result;
while (Incoming.TryDequeue(out result))
{
if (apply)
{
try
{
Apply(result.Item1, result.Item2);
}
catch (Exception ex)
{
MelonLogger.Warning("Lobby sync: " + ex.Message);
}
}
}
}
private static void Apply(ulong from, byte[] data)
{
if (data.Length == 0)
{
FriendLeft(from);
return;
}
List<(ulong, int, byte[])> list = Unpack(data);
ulong mySteamId = SteamNet.MySteamId;
if (Session.IsHosting)
{
List<(int, byte[])> list2 = new List<(int, byte[])>();
foreach (var item in list)
{
if (item.Item1 == from)
{
list2.Add((item.Item2, item.Item3));
}
}
latest[from] = list2;
SyncOwner(from, list2);
return;
}
Dictionary<ulong, List<(int, byte[])>> dictionary = new Dictionary<ulong, List<(int, byte[])>>();
foreach (var item2 in list)
{
if (item2.Item1 != mySteamId)
{
if (!dictionary.TryGetValue(item2.Item1, out var value))
{
value = (dictionary[item2.Item1] = new List<(int, byte[])>());
}
value.Add((item2.Item2, item2.Item3));
}
}
foreach (KeyValuePair<ulong, List<(int, byte[])>> item3 in dictionary)
{
SyncOwner(item3.Key, item3.Value);
}
foreach (ulong item4 in new List<ulong>(remotes.Keys))
{
if (!dictionary.ContainsKey(item4))
{
RemoveOwner(item4);
}
}
}
public static void FriendLeft(ulong id)
{
latest.Remove(id);
if (remotes.ContainsKey(id))
{
RemoveOwner(id);
}
}
private static void SyncOwner(ulong owner, List<(int ctrl, byte[] data)> beasts)
{
//IL_003f: Unknown result type (might be due to invalid IL or missing references)
//IL_0049: Expected O, but got Unknown
//IL_0105: Unknown result type (might be due to invalid IL or missing references)
//IL_010c: Expected O, but got Unknown
//IL_0116: Unknown result type (might be due to invalid IL or missing references)
//IL_0120: Expected O, but got Unknown
//IL_0147: Unknown result type (might be due to invalid IL or missing references)
//IL_014d: Invalid comparison between Unknown and I4
LobbyManager instance = LobbyManager.Instance;
OnlineBeastSetupTracker val = ((instance != null) ? instance.OnlineBeasts : null);
BeastMenuManager val2 = Object.FindObjectOfType<BeastMenuManager>();
if ((Object)(object)val == (Object)null)
{
return;
}
if (!remotes.TryGetValue(owner, out var value))
{
value = new Remote
{
User = new BaseUserInfo(owner, (PlatformKeys)1, SteamNet.Name(owner)),
Master = BeastUtils.PlayerID_Lobby + 8 * (nextMaster++ % 24)
};
val.OnPlayerJoined(value.User, value.Master);
remotes[owner] = value;
MelonLogger.Msg("Lobby: " + value.User.userName + " is in the lobby.");
}
HashSet<int> hashSet = new HashSet<int>();
foreach (var (num, array) in beasts)
{
hashSet.Add(num);
if (value.Beasts.TryGetValue(num, out var value2) && Same(value2, array))
{
continue;
}
value.Beasts[num] = array;
BeastInfo val3 = new BeastInfo();
if (!val3.Deserialize(new DataReader(Il2CppStructArray<byte>.op_Implicit(array), true)))
{
continue;
}
val3.SetControllerID(num);
val.ForceUpdateBeast(value.User, val3);
int num2 = value.Master + num;
bool flag = (int)val3.State > 0;
if (flag && value.Spawned.Add(num))
{
if (val2 != null)
{
val2.SpawnBeast(num2, Math.Max(0, val3.Team));
}
}
else if (!flag && value.Spawned.Remove(num) && val2 != null)
{
val2.DespawnBeast(num2);
}
}
foreach (int item in new List<int>(value.Beasts.Keys))
{
if (!hashSet.Contains(item))
{
value.Beasts.Remove(item);
Hide(value, item, val, val2);
}
}
}
private static void Hide(Remote r, int ctrl, OnlineBeastSetupTracker tracker, BeastMenuManager menu)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0006: Expected O, but got Unknown
BeastInfo val = new BeastInfo();
val.SetControllerID(ctrl);
val.SetState((PlayerState)0);
try
{
if (tracker != null)
{
tracker.ForceUpdateBeast(r.User, val);
}
}
catch
{
}
if (r.Spawned.Remove(ctrl) && menu != null)
{
menu.DespawnBeast(r.Master + ctrl);
}
}
private static void RemoveOwner(ulong owner)
{
if (!remotes.TryGetValue(owner, out var value))
{
return;
}
LobbyManager instance = LobbyManager.Instance;
OnlineBeastSetupTracker val = ((instance != null) ? instance.OnlineBeasts : null);
BeastMenuManager val2 = Object.FindObjectOfType<BeastMenuManager>();
foreach (int item in new List<int>(value.Spawned))
{
try
{
if (val2 != null)
{
val2.DespawnBeast(value.Master + item);
}
}
catch
{
}
}
try
{
if (val != null)
{
val.OnPlayerLeft(value.User);
}
}
catch
{
}
remotes.Remove(owner);
MelonLogger.Msg("Lobby: " + value.User.userName + " left the lobby.");
}
public static void Clear()
{
foreach (ulong item in new List<ulong>(remotes.Keys))
{
RemoveOwner(item);
}
remotes.Clear();
latest.Clear();
nextMaster = 0;
}
private static byte[] Pack(List<(ulong owner, int ctrl, byte[] data)> beasts)
{
int num = 2;
foreach (var beast in beasts)
{
num += 11 + beast.data.Length;
}
byte[] array = new byte[num];
array[0] = 6;
array[1] = (byte)beasts.Count;
int num2 = 2;
foreach (var (value, num3, array2) in beasts)
{
BitConverter.GetBytes(value).CopyTo(array, num2);
num2 += 8;
array[num2++] = (byte)num3;
BitConverter.GetBytes((ushort)array2.Length).CopyTo(array, num2);
num2 += 2;
array2.CopyTo(array, num2);
num2 += array2.Length;
}
return array;
}
private static List<(ulong owner, int ctrl, byte[] data)> Unpack(byte[] buf)
{
List<(ulong, int, byte[])> list = new List<(ulong, int, byte[])>();
if (buf.Length < 2 || buf[0] != 6)
{
return list;
}
int num = buf[1];
int num2 = 2;
for (int i = 0; i < num; i++)
{
if (num2 + 11 > buf.Length)
{
break;
}
ulong item = BitConverter.ToUInt64(buf, num2);
num2 += 8;
int item2 = buf[num2++];
int num3 = BitConverter.ToUInt16(buf, num2);
num2 += 2;
if (num2 + num3 > buf.Length)
{
break;
}
byte[] array = new byte[num3];
Array.Copy(buf, num2, array, 0, num3);
num2 += num3;
list.Add((item, item2, array));
}
return list;
}
private static byte[] ToBytes(BeastInfo info)
{
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
//IL_000b: Expected O, but got Unknown
DataWriter val = new DataWriter(2048);
info.Serialize(val);
Il2CppStructArray<byte> dataBuffer = ((DataStream)val).DataBuffer;
byte[] array = new byte[Math.Min(((DataStream)val).DataSize, ((Il2CppArrayBase<byte>)(object)dataBuffer).Length)];
for (int i = 0; i < array.Length; i++)
{
array[i] = ((Il2CppArrayBase<byte>)(object)dataBuffer)[i];
}
return array;
}
private static bool Same(byte[] a, byte[] b)
{
if (a.Length != b.Length)
{
return false;
}
for (int i = 0; i < a.Length; i++)
{
if (a[i] != b[i])
{
return false;
}
}
return true;
}
}
internal static class MainMenu
{
private class Anim
{
public Button Button;
public RectTransform Rt;
public TMP_Text Text;
public float Scale = 1f;
public float Vel;
public float Hover;
public float Enter = 1f;
public float Delay;
public float Punch;
public float Seed;
}
private const string SectionPath = "Managers/Menu/Main Menu/Canvas/Main Menu/TextSection";
private static GameObject section;
private static GameObject template;
private static GameObject pcHome;
private static GameObject pcJoin;
private static GameObject current;
private static TMP_Text codeLabel;
private static TMP_Text hintLabel;
private static string typed = "";
private static float caretTimer;
private static readonly List<Anim> anims = new List<Anim>();
private static bool wasVisible;
private static Vector2 lastMouse;
public static bool InProCon
{
get
{
if ((Object)(object)current != (Object)null)
{
return (Object)(object)current != (Object)(object)section;
}
return false;
}
}
public static bool OnMainList
{
get
{
if ((Object)(object)section != (Object)null && (Object)(object)current == (Object)(object)section)
{
return section.activeInHierarchy;
}
return false;
}
}
public static void Tick()
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
Scene activeScene = SceneManager.GetActiveScene();
if (((Scene)(ref activeScene)).name != "Menu")
{
section = null;
return;
}
if ((Object)(object)section == (Object)null)
{
section = Util.FindAny("Managers/Menu/Main Menu/Canvas/Main Menu/TextSection");
if ((Object)(object)section == (Object)null)
{
return;
}
pcHome = (pcJoin = null);
current = section;
anims.Clear();
}
if ((Object)(object)pcHome == (Object)null && !Build())
{
return;
}
if (InProCon && !((Component)section.transform.parent).gameObject.activeInHierarchy)
{
Show(section);
}
int num;
if ((Object)(object)current != (Object)null)
{
num = (current.activeInHierarchy ? 1 : 0);
if (num != 0 && !wasVisible)
{
PlayEntrance();
}
}
else
{
num = 0;
}
wasVisible = (byte)num != 0;
if (num != 0)
{
if (InProCon)
{
ProConInput();
}
Animate();
}
}
private static bool Build()
{
//IL_01bd: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)MenuFont.Font == (Object)null)
{
return false;
}
MenuFont.Apply(((Component)section.transform.parent).gameObject);
Transform val = section.transform.Find("Online");
if ((Object)(object)val == (Object)null)
{
return false;
}
template = ((Component)val).gameObject;
MakeButton(section.transform, "ProCon", delegate
{
Show(pcHome);
}).transform.SetSiblingIndex(val.GetSiblingIndex() + 1);
Navigate(section);
pcHome = MakePage("ProCon Home");
MakeButton(pcHome.transform, "Host", OnHost);
MakeButton(pcHome.transform, "Join", delegate
{
Show(pcJoin);
});
MakeButton(pcHome.transform, "Back", delegate
{
Show(section);
});
hintLabel = MakeLabel(pcHome.transform, Session.StatusLine(), 0.5f);
Navigate(pcHome);
pcJoin = MakePage("ProCon Join");
MakeLabel(pcJoin.transform, "Enter code", 0.6f);
codeLabel = MakeLabel(pcJoin.transform, "", 1.25f);
((Graphic)codeLabel).color = Color.white;
codeLabel.characterSpacing = 14f;
MakeButton(pcJoin.transform, "Connect", OnConnect);
MakeButton(pcJoin.transform, "Back", delegate
{
Show(pcHome);
});
Navigate(pcJoin);
MelonLogger.Msg("ProCon added to main menu.");
return true;
}
private static GameObject MakePage(string name)
{
GameObject val = Object.Instantiate<GameObject>(section, section.transform.parent);
((Object)val).name = name;
for (int num = val.transform.childCount - 1; num >= 0; num--)
{
Object.DestroyImmediate((Object)(object)((Component)val.transform.GetChild(num)).gameObject);
}
val.SetActive(false);
return val;
}
private static GameObject Clone(Transform parent, string name, string text)
{
//IL_008b: Unknown result type (might be due to invalid IL or missing references)
GameObject val = Object.Instantiate<GameObject>(template, parent);
((Object)val).name = name;
val.SetActive(true);
foreach (Component component in val.GetComponents<Component>())
{
if (!((Object)(object)component == (Object)null))
{
switch (((MemberInfo)((Object)component).GetIl2CppType()).Name)
{
case "LocalizeStringEvent":
case "DisabledIfPlatform":
case "MainUserInteractOnly":
Object.DestroyImmediate((Object)(object)component);
break;
}
}
}
val.transform.localScale = Vector3.one;
val.GetComponent<TMP_Text>().text = text;
return val;
}
private static GameObject MakeButton(Transform parent, string text, Action onClick)
{
//IL_000f: Unknown result type (might be due to invalid IL or missing references)
//IL_0019: Expected O, but got Unknown
GameObject obj = Clone(parent, text, text);
Button component = obj.GetComponent<Button>();
component.onClick = new ButtonClickedEvent();
((UnityEvent)component.onClick).AddListener(UnityAction.op_Implicit(onClick));
return obj;
}
private static TMP_Text MakeLabel(Transform parent, string text, float sizeMul)
{
GameObject val = Clone(parent, "Label", text);
foreach (Component component2 in val.GetComponents<Component>())
{
if (!((Object)(object)component2 == (Object)null))
{
string name = ((MemberInfo)((Object)component2).GetIl2CppType()).Name;
if (name == "ButtonNavHandler" || name == "UIButtonSFX")
{
Object.DestroyImmediate((Object)(object)component2);
}
}
}
Object.DestroyImmediate((Object)(object)val.GetComponent<Button>());
TMP_Text component = val.GetComponent<TMP_Text>();
component.fontSize *= sizeMul;
((Graphic)component).raycastTarget = false;
return component;
}
private static void Navigate(GameObject page)
{
//IL_0056: Unknown result type (might be due to invalid IL or missing references)
//IL_005b: Unknown result type (might be due to invalid IL or missing references)
//IL_0062: Unknown result type (might be due to invalid IL or missing references)
//IL_007f: Unknown result type (might be due to invalid IL or missing references)
//IL_009a: Expected O, but got Unknown
List<Button> list = new List<Button>();
for (int i = 0; i < page.transform.childCount; i++)
{
Button component = ((Component)page.transform.GetChild(i)).GetComponent<Button>();
if ((Object)(object)component != (Object)null && ((Component)component).gameObject.activeSelf)
{
list.Add(component);
}
}
for (int j = 0; j < list.Count; j++)
{
((Selectable)list[j]).navigation = new Navigation
{
mode = (Mode)4,
selectOnUp = (Selectable)(object)list[(j - 1 + list.Count) % list.Count],
selectOnDown = (Selectable)(object)list[(j + 1) % list.Count]
};
}
}
private static void Show(GameObject page)
{
GameObject val = current;
section.SetActive((Object)(object)page == (Object)(object)section);
pcHome.SetActive((Object)(object)page == (Object)(object)pcHome);
pcJoin.SetActive((Object)(object)page == (Object)(object)pcJoin);
current = page;
if ((Object)(object)page == (Object)(object)pcJoin)
{
typed = "";
RefreshCode();
}
if ((Object)(object)page == (Object)(object)pcHome)
{
hintLabel.text = Session.StatusLine();
}
GameObject val2 = null;
if ((Object)(object)page == (Object)(object)section && (Object)(object)val != (Object)(object)section)
{
Transform obj = section.transform.Find("ProCon");
val2 = ((obj != null) ? ((Component)obj).gameObject : null);
}
if ((Object)(object)val2 == (Object)null)
{
Button componentInChildren = page.GetComponentInChildren<Button>();
val2 = ((componentInChildren != null) ? ((Component)componentInChildren).gameObject : null);
}
if ((Object)(object)val2 != (Object)null && (Object)(object)EventSystem.current != (Object)null)
{
EventSystem.current.SetSelectedGameObject(val2);
}
PlayEntrance();
}
private static void OnHost()
{
Transform obj = section.transform.Find("Local");
Button val = ((obj != null) ? ((Component)obj).GetComponent<Button>() : null);
Show(section);
if ((Object)(object)val != (Object)null)
{
Session.Host(val);
}
}
private static void OnConnect()
{
if (!JoinCode.IsValid(typed))
{
codeLabel.text = "<color=#ff7a9c>????????</color>";
typed = "";
return;
}
string joinCode = typed;
Transform obj = section.transform.Find("Local");
Button val = ((obj != null) ? ((Component)obj).GetComponent<Button>() : null);
Show(section);
if ((Object)(object)val != (Object)null)
{
Session.Join(joinCode, val);
}
}
private static void ProConInput()
{
//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
//IL_00f0: Invalid comparison between Unknown and I4
//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
//IL_00f4: 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_00eb: Unknown result type (might be due to invalid IL or missing references)
//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
//IL_0137: Unknown result type (might be due to invalid IL or missing references)
//IL_013b: Invalid comparison between Unknown and I4
//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
//IL_0131: Unknown result type (might be due to invalid IL or missing references)
//IL_0134: Unknown result type (might be due to invalid IL or missing references)
//IL_0135: 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_0110: Invalid comparison between Unknown and I4
//IL_0114: Unknown result type (might be due to invalid IL or missing references)
//IL_0118: Unknown result type (might be due to invalid IL or missing references)
//IL_0119: Unknown result type (might be due to invalid IL or missing references)
Keyboard val = Keyboard.current;
if (val == null || !Application.isFocused)
{
return;
}
if (((ButtonControl)val.escapeKey).wasPressedThisFrame || (((ButtonControl)val.backspaceKey).wasPressedThisFrame && (Object)(object)current == (Object)(object)pcHome))
{
Show(((Object)(object)current == (Object)(object)pcJoin) ? pcHome : section);
}
else
{
if ((Object)(object)current != (Object)(object)pcJoin)
{
return;
}
bool flag = ((ButtonControl)val.leftCtrlKey).isPressed || ((ButtonControl)val.rightCtrlKey).isPressed;
if (flag && ((ButtonControl)val.vKey).wasPressedThisFrame)
{
typed = JoinCode.Clean(Clipboard.Get());
}
else if (!flag)
{
for (Key val2 = (Key)15; (int)val2 <= 40; val2 = (Key)(val2 + 1))
{
if (((ButtonControl)val[val2]).wasPressedThisFrame)
{
typed += (char)(65 + (val2 - 15));
}
}
for (Key val3 = (Key)41; (int)val3 <= 50; val3 = (Key)(val3 + 1))
{
if (((ButtonControl)val[val3]).wasPressedThisFrame)
{
typed += (((int)val3 == 50) ? '0' : ((char)(49 + (val3 - 41))));
}
}
if (((ButtonControl)val.backspaceKey).wasPressedThisFrame && typed.Length > 0)
{
string text = typed;
typed = text.Substring(0, text.Length - 1);
}
typed = JoinCode.Clean(typed);
}
if (typed.Length > 8)
{
typed = typed.Substring(0, 8);
}
RefreshCode();
}
}
private static void RefreshCode()
{
caretTimer += Time.unscaledDeltaTime;
string text = ((caretTimer % 1f < 0.5f) ? "<color=#ffc40d>_</color>" : "<color=#00000000>_</color>");
string text2 = ((typed.Length < 8) ? (typed + text) : typed);
if (!codeLabel.text.StartsWith("<color=#ff7a9c>") || typed.Length > 0)
{
codeLabel.text = text2;
}
}
private static void CollectAnims()
{
anims.Clear();
if ((Object)(object)current == (Object)null)
{
return;
}
int num = 0;
for (int i = 0; i < current.transform.childCount; i++)
{
Transform child = current.transform.GetChild(i);
if (((Component)child).gameObject.activeSelf)
{
anims.Add(new Anim
{
Button = ((Component)child).GetComponent<Button>(),
Rt = ((Il2CppObjectBase)child).Cast<RectTransform>(),
Text = ((Component)child).GetComponent<TMP_Text>(),
Delay = (float)num++ * 0.05f,
Seed = (float)i * 1.7f
});
}
}
}
private static void PlayEntrance()
{
CollectAnims();
foreach (Anim anim in anims)
{
anim.Enter = 0f;
anim.Scale = 0.6f;
}
}
private static void Animate()
{
//IL_0266: Unknown result type (might be due to invalid IL or missing references)
//IL_02c4: Unknown result type (might be due to invalid IL or missing references)
//IL_0145: Unknown result type (might be due to invalid IL or missing references)
if (anims.Count == 0 || (Object)(object)anims[0].Rt == (Object)null)
{
CollectAnims();
}
float num = Mathf.Min(Time.unscaledDeltaTime, 0.05f);
float unscaledTime = Time.unscaledTime;
EventSystem val = EventSystem.current;
GameObject val2 = (((Object)(object)val != (Object)null) ? val.currentSelectedGameObject : null);
GameObject val3 = HoveredButton();
if ((Object)(object)val3 != (Object)null && (Object)(object)val3 != (Object)(object)val2 && (Object)(object)val != (Object)null && !Notice.IsOpen)
{
val.SetSelectedGameObject(val3);
val2 = val3;
}
foreach (Anim anim in anims)
{
if ((Object)(object)anim.Rt == (Object)null)
{
continue;
}
bool flag = (Object)(object)anim.Button != (Object)null && (Object)(object)((Component)anim.Button).gameObject == (Object)(object)val2;
if (flag && WasPressed())
{
anim.Punch = 1f;
}
anim.Hover = Mathf.MoveTowards(anim.Hover, flag ? 1f : 0f, num * 6f);
if (anim.Delay > 0f)
{
anim.Delay -= num;
((Transform)anim.Rt).localScale = Vector3.zero;
continue;
}
anim.Enter = Mathf.MoveTowards(anim.Enter, 1f, num * 3.5f);
float num2 = Mathf.Lerp(1f, 1.28f, Ease(anim.Hover)) - anim.Punch * 0.18f;
anim.Vel += (num2 - anim.Scale) * 220f * num - anim.Vel * 16f * num;
anim.Scale += anim.Vel * num;
anim.Punch = Mathf.MoveTowards(anim.Punch, 0f, num * 5f);
float num3 = 1f + Mathf.Sin(unscaledTime * 4f + anim.Seed) * 0.025f * anim.Hover;
float num4 = anim.Scale * num3 * Mathf.Lerp(0.6f, 1f, Ease(anim.Enter));
((Transform)anim.Rt).localScale = new Vector3(num4, num4, 1f);
float num5 = Mathf.Sin(unscaledTime * 6f + anim.Seed) * 3.5f * anim.Hover;
float num6 = (1f - Ease(anim.Enter)) * -25f;
((Transform)anim.Rt).localRotation = Quaternion.Euler(0f, 0f, num5 + num6);
if ((Object)(object)anim.Text != (Object)null)
{
anim.Text.characterSpacing = (((Object)(object)anim.Text == (Object)(object)codeLabel) ? 14f : Mathf.Lerp(0f, 6f, Ease(anim.Hover)));
}
}
}
private static float Ease(float x)
{
return 1f - Mathf.Pow(1f - Mathf.Clamp01(x), 3f);
}
private static bool WasPressed()
{
if (!Application.isFocused)
{
return false;
}
Keyboard val = Keyboard.current;
Mouse val2 = Mouse.current;
Gamepad val3 = Gamepad.current;
if ((val == null || (!((ButtonControl)val.enterKey).wasPressedThisFrame && !((ButtonControl)val.spaceKey).wasPressedThisFrame)) && (val2 == null || !val2.leftButton.wasPressedThisFrame))
{
if (val3 != null)
{
return val3.buttonSouth.wasPressedThisFrame;
}
return false;
}
return true;
}
private static GameObject HoveredButton()
{
//IL_0018: Unknown result type (might be due to invalid IL or missing references)
//IL_001d: 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_001f: Unknown result type (might be due to invalid IL or missing references)
//IL_0024: Unknown result type (might be due to invalid IL or missing references)
//IL_0029: Unknown result type (might be due to invalid IL or missing references)
//IL_0038: 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_0098: Unknown result type (might be due to invalid IL or missing references)
//IL_009d: Unknown result type (might be due to invalid IL or missing references)
//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
//IL_00d1: 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_00e2: Unknown result type (might be due to invalid IL or missing references)
//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
//IL_0100: 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_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_0111: Unknown result type (might be due to invalid IL or missing references)
//IL_0117: Unknown result type (might be due to invalid IL or missing references)
//IL_011e: Unknown result type (might be due to invalid IL or missing references)
//IL_012c: Unknown result type (might be due to invalid IL or missing references)
//IL_0132: Unknown result type (might be due to invalid IL or missing references)
//IL_0139: Unknown result type (might be due to invalid IL or missing references)
//IL_0147: Unknown result type (might be due to invalid IL or missing references)
//IL_014d: 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_0162: Unknown result type (might be due to invalid IL or missing references)
//IL_0168: Unknown result type (might be due to invalid IL or missing references)
//IL_016f: Unknown result type (might be due to invalid IL or missing references)
Mouse val = Mouse.current;
if (val == null || !Application.isFocused)
{
return null;
}
Vector2 val2 = ((InputControl<Vector2>)(object)((Pointer)val).position).ReadValue();
Vector2 val3 = val2 - lastMouse;
bool num = ((Vector2)(ref val3)).sqrMagnitude > 1f;
lastMouse = val2;
if (!num)
{
return null;
}
Camera main = Camera.main;
if ((Object)(object)main == (Object)null)
{
return null;
}
foreach (Anim anim in anims)
{
if (!((Object)(object)anim.Button == (Object)null) && !((Object)(object)anim.Text == (Object)null))
{
Bounds textBounds = anim.Text.textBounds;
Vector2 val4 = Vector2.op_Implicit(main.WorldToScreenPoint(((Transform)anim.Rt).TransformPoint(((Bounds)(ref textBounds)).min - new Vector3(20f, 8f, 0f))));
Vector2 val5 = Vector2.op_Implicit(main.WorldToScreenPoint(((Transform)anim.Rt).TransformPoint(((Bounds)(ref textBounds)).max + new Vector3(20f, 8f, 0f))));
if (val2.x >= Mathf.Min(val4.x, val5.x) && val2.x <= Mathf.Max(val4.x, val5.x) && val2.y >= Mathf.Min(val4.y, val5.y) && val2.y <= Mathf.Max(val4.y, val5.y))
{
return ((Component)anim.Button).gameObject;
}
}
}
return null;
}
}
internal static class MenuFont
{
private const string MenuRoot = "Managers/Menu/Main Menu";
private static TMP_FontAsset font;
private static bool loadFailed;
private static float timer;
private static readonly Dictionary<IntPtr, Material> materials = new Dictionary<IntPtr, Material>();
private static readonly HashSet<IntPtr> logged = new HashSet<IntPtr>();
private static Material outlined;
public static TMP_FontAsset Font
{
get
{
if ((Object)(object)font == (Object)null && !loadFailed)
{
Load();
}
return font;
}
}
public static Material OutlinedMaterial
{
get
{
//IL_002a: 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_003f: Expected O, but got Unknown
//IL_0080: Unknown result type (might be due to invalid IL or missing references)
//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)outlined != (Object)null || (Object)(object)Font == (Object)null)
{
return outlined;
}
outlined = new Material(((TMP_Asset)font).material)
{
name = "Yellow Banana Outlined"
};
outlined.EnableKeyword("OUTLINE_ON");
outlined.SetFloat("_OutlineWidth", 0.28f);
outlined.SetColor("_OutlineColor", new Color(0.1f, 0.06f, 0.02f, 1f));
outlined.EnableKeyword("UNDERLAY_ON");
outlined.SetColor("_UnderlayColor", new Color(0f, 0f, 0f, 0.6f));
outlined.SetFloat("_UnderlayOffsetX", 0.6f);
outlined.SetFloat("_UnderlayOffsetY", -0.6f);
Object.DontDestroyOnLoad((Object)(object)outlined);
return outlined;
}
}
private static void Load()
{
try
{
string text = Path.Combine(MelonEnvironment.UserDataDirectory, "ProCon");
Directory.CreateDirectory(text);
string text2 = Path.Combine(text, "YellowBanana.otf");
using (Stream stream = typeof(MenuFont).Assembly.GetManifestResourceStream("YellowBanana.otf"))
{
using MemoryStream memoryStream = new MemoryStream();
stream.CopyTo(memoryStream);
byte[] array = memoryStream.ToArray();
if (!File.Exists(text2) || new FileInfo(text2).Length != array.Length)
{
File.WriteAllBytes(text2, array);
}
}
font = TMP_FontAsset.CreateFontAsset(text2, 0, 90, 9, (GlyphRenderMode)4165, 2048, 2048, (AtlasPopulationMode)1, false);
if ((Object)(object)font == (Object)null)
{
throw new Exception("CreateFontAsset returned null");
}
((Object)font).name = "Yellow Banana SDF";
Object.DontDestroyOnLoad((Object)(object)font);
font.TryAddCharacters("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 .,:;!?'\"-+/()&%#", false);
MelonLogger.Msg("Yellow Banana font loaded.");
}
catch (Exception ex)
{
loadFailed = true;
MelonLogger.Error("Couldn't load Yellow Banana font: " + ex);
}
}
public static void Tick()
{
//IL_0027: Unknown result type (might be due to invalid IL or missing references)
//IL_002c: Unknown result type (might be due to invalid IL or missing references)
timer -= Time.unscaledDeltaTime;
if (timer > 0f)
{
return;
}
timer = 0.5f;
Scene activeScene = SceneManager.GetActiveScene();
if (!(((Scene)(ref activeScene)).name != "Menu"))
{
GameObject val = GameObject.Find("Managers/Menu/Main Menu");
if (!((Object)(object)val == (Object)null) && !((Object)(object)Font == (Object)null))
{
Apply(val);
}
}
}
public static void Apply(GameObject root)
{
Il2CppArrayBase<TMP_Text> componentsInChildren = root.GetComponentsInChildren<TMP_Text>(true);
for (int i = 0; i < componentsInChildren.Length; i++)
{
TMP_Text val = componentsInChildren[i];
if (!((Object)(object)val == (Object)null) && !((Object)(object)val.font == (Object)(object)font))
{
Material fontSharedMaterial = val.fontSharedMaterial;
val.font = font;
val.fontSharedMaterial = StyledMaterial(fontSharedMaterial);
if (logged.Add(((Il2CppObjectBase)val).Pointer))
{
Util.Debug($"font -> '{val.text}' ({((Object)((Component)val).gameObject).name})");
}
}
}
}
private static Material StyledMaterial(Material orig)
{
//IL_0034: 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_0050: Expected O, but got Unknown
if ((Object)(object)orig == (Object)null)
{
return ((TMP_Asset)font).material;
}
if (materials.TryGetValue(((Il2CppObjectBase)orig).Pointer, out var value) && (Object)(object)value != (Object)null)
{
return value;
}
value = new Material(orig)
{
name = ((Object)orig).name + " (Yellow Banana)"
};
value.SetTexture("_MainTex", (Texture)(object)font.atlasTexture);
value.SetFloat("_TextureWidth", (float)font.atlasWidth);
value.SetFloat("_TextureHeight", (float)font.atlasHeight);
value.SetFloat("_GradientScale", (float)(font.atlasPadding + 1));
Object.DontDestroyOnLoad((Object)(object)value);
materials[((Il2CppObjectBase)orig).Pointer] = value;
return value;
}
}
internal static class Notice
{
private const string Text = "ProCon is still a bit janky!\n\nIf your friend doesn't show up in the lobby, just start the round at the same time.";
private static bool shown;
private static GameObject root;
private static RectTransform panel;
private static GameObject okButton;
private static GameObject previousSelection;
private static float anim;
private static float pressedAt = -1f;
private static readonly Color Yellow = new Color(1f, 0.78f, 0.05f);
private static readonly Color Pink = new Color(0.96f, 0.45f, 0.66f);
private static readonly Color Ink = new Color(0.08f, 0.06f, 0.1f);
public static bool IsOpen
{
get
{
if ((Object)(object)root != (Object)null)
{
return root.activeSelf;
}
return false;
}
}
public static void Tick()
{
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_000c: Unknown result type (might be due to invalid IL or missing references)
//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
//IL_00bd: 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_0104: Unknown result type (might be due to invalid IL or missing references)
//IL_0175: Unknown result type (might be due to invalid IL or missing references)
//IL_019e: Unknown result type (might be due to invalid IL or missing references)
//IL_01c8: Unknown result type (might be due to invalid IL or missing references)
if (!shown)
{
Scene activeScene = SceneManager.GetActiveScene();
if (!(((Scene)(ref activeScene)).name != "Menu") && MainMenu.OnMainList && !((Object)(object)MenuFont.Font == (Object)null))
{
shown = true;
Show();
}
}
else if (!((Object)(object)root == (Object)null) && root.activeSelf)
{
float num = Mathf.Min(Time.unscaledDeltaTime, 0.05f);
anim = Mathf.MoveTowards(anim, 1f, num * 4f);
float num2 = 1f - Mathf.Pow(1f - anim, 3f);
((Transform)panel).localScale = Vector3.one * Mathf.Lerp(0.7f, 1f, num2) * (1f + Mathf.Sin(anim * (float)Math.PI) * 0.05f);
((Transform)panel).localRotation = Quaternion.Euler(0f, 0f, (1f - num2) * -6f);
EventSystem current = EventSystem.current;
if ((Object)(object)current != (Object)null && (Object)(object)current.currentSelectedGameObject != (Object)(object)okButton)
{
current.SetSelectedGameObject(okButton);
}
RectTransform component = okButton.GetComponent<RectTransform>();
float num3 = ((pressedAt > 0f) ? Mathf.Clamp01(1f - (Time.unscaledTime - pressedAt) * 6f) : 0f);
((Transform)component).localScale = Vector3.one * (1.06f + Mathf.Sin(Time.unscaledTime * 4f) * 0.03f - num3 * 0.12f);
((Transform)component).localRotation = Quaternion.Euler(0f, 0f, Mathf.Sin(Time.unscaledTime * 6f) * 2f);
}
}
private static void Close()
{
pressedAt = Time.unscaledTime;
root.SetActive(false);
EventSystem current = EventSystem.current;
if ((Object)(object)current != (Object)null && (Object)(object)previousSelection != (Object)null)
{
current.SetSelectedGameObject(previousSelection);
}
}
private static void Show()
{
//IL_0024: Unknown result type (might be due to invalid IL or missing references)
//IL_002e: Expected O, but got Unknown
//IL_006f: Unknown result type (might be due to invalid IL or missing references)
//IL_009d: Unknown result type (might be due to invalid IL or missing references)
//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
//IL_0102: Unknown result type (might be due to invalid IL or missing references)
//IL_0111: Unknown result type (might be due to invalid IL or missing references)
//IL_0116: Unknown result type (might be due to invalid IL or missing references)
//IL_0132: Unknown result type (might be due to invalid IL or missing references)
//IL_0146: Unknown result type (might be due to invalid IL or missing references)
//IL_0160: Unknown result type (might be due to invalid IL or missing references)
//IL_016f: Unknown result type (might be due to invalid IL or missing references)
//IL_017e: Unknown result type (might be due to invalid IL or missing references)
//IL_0199: Unknown result type (might be due to invalid IL or missing references)
//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
//IL_01b7: Unknown result type (might be due to invalid IL or missing references)
//IL_01ed: Unknown result type (might be due to invalid IL or missing references)
//IL_01fc: Unknown result type (might be due to invalid IL or missing references)
//IL_0201: Unknown result type (might be due to invalid IL or missing references)
//IL_022f: Unknown result type (might be due to invalid IL or missing references)
//IL_0243: Unknown result type (might be due to invalid IL or missing references)
//IL_02a5: Unknown result type (might be due to invalid IL or missing references)
//IL_02aa: Unknown result type (might be due to invalid IL or missing references)
//IL_02b9: Unknown result type (might be due to invalid IL or missing references)
previousSelection = (((Object)(object)EventSystem.current != (Object)null) ? EventSystem.current.currentSelectedGameObject : null);
root = new GameObject("ProCon Notice");
Object.DontDestroyOnLoad((Object)(object)root);
Canvas obj = root.AddComponent<Canvas>();
obj.renderMode = (RenderMode)0;
obj.sortingOrder = 6000;
CanvasScaler obj2 = root.AddComponent<CanvasScaler>();
obj2.uiScaleMode = (ScaleMode)1;
obj2.referenceResolution = new Vector2(1920f, 1080f);
obj2.matchWidthOrHeight = 0.5f;
root.AddComponent<GraphicRaycaster>();
RectTransform component = Rect(root.transform, "Dim", Vector2.zero, Vector2.zero, new Color(0.05f, 0.02f, 0.08f, 0.55f)).GetComponent<RectTransform>();
component.anchorMin = Vector2.zero;
component.anchorMax = Vector2.one;
Vector2 offsetMin = (component.offsetMax = Vector2.zero);
component.offsetMin = offsetMin;
GameObject obj3 = Rect(root.transform, "Panel", Vector2.zero, new Vector2(840f, 600f), Ink);
panel = obj3.GetComponent<RectTransform>();
Outline obj4 = obj3.AddComponent<Outline>();
((Shadow)obj4).effectColor = Pink;
((Shadow)obj4).effectDistance = new Vector2(8f, -8f);
Label(obj3.transform, "Heads up!", 80f, Yellow, new Vector2(0f, 210f), new Vector2(760f, 120f));
TMP_Text obj5 = Label(obj3.transform, "ProCon is still a bit janky!\n\nIf your friend doesn't show up in the lobby, just start the round at the same time.", 36f, Color.white, new Vector2(0f, 30f), new Vector2(720f, 230f));
obj5.enableWordWrapping = true;
obj5.alignment = (TextAlignmentOptions)514;
obj5.overflowMode = (TextOverflowModes)0;
okButton = Rect(obj3.transform, "OK", new Vector2(0f, -205f), new Vector2(260f, 92f), Yellow);
Shadow obj6 = okButton.AddComponent<Shadow>();
obj6.effectColor = new Color(0f, 0f, 0f, 0.6f);
obj6.effectDistance = new Vector2(0f, -6f);
Button obj7 = okButton.AddComponent<Button>();
((Selectable)obj7).targetGraphic = (Graphic)(object)okButton.GetComponent<Image>();
((UnityEvent)obj7.onClick).AddListener(UnityAction.op_Implicit((Action)Close));
Label(okButton.transform, "OK", 60f, Ink, Vector2.zero, new Vector2(260f, 92f));
anim = 0f;
}
private static GameObject Rect(Transform parent, string name, Vector2 pos, Vector2 size, Color color)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_0013: Unknown result type (might be due to invalid IL or missing references)
//IL_002d: 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_0034: Unknown result type (might be due to invalid IL or missing references)
//IL_0035: Unknown result type (might be due to invalid IL or missing references)
//IL_003b: Unknown result type (might be due to invalid IL or missing references)
//IL_0042: Unknown result type (might be due to invalid IL or missing references)
//IL_0048: 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_0054: Unknown result type (might be due to invalid IL or missing references)
//IL_005c: Expected O, but got Unknown
GameObject val = new GameObject(name);
val.transform.SetParent(parent, false);
RectTransform obj = val.AddComponent<RectTransform>();
Vector2 val2 = default(Vector2);
((Vector2)(ref val2))..ctor(0.5f, 0.5f);
obj.pivot = val2;
Vector2 anchorMin = (obj.anchorMax = val2);
obj.anchorMin = anchorMin;
obj.anchoredPosition = pos;
obj.sizeDelta = size;
((Graphic)val.AddComponent<Image>()).color = color;
return val;
}
private static TMP_Text Label(Transform parent, string text, float size, Color color, Vector2 pos, Vector2 box)
{
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
//IL_000a: Unknown result type (might be due to invalid IL or missing references)
//IL_0017: Unknown result type (might be due to invalid IL or missing references)
//IL_0030: 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_003d: Unknown result type (might be due to invalid IL or missing references)
//IL_0044: Unknown result type (might be due to invalid IL or missing references)
//IL_0075: Unknown result type (might be due to invalid IL or missing references)
GameObject val = new GameObject("Text");
val.transform.SetParent(parent, false);
RectTransform obj = val.AddComponent<RectTransform>();
Vector2 val2 = default(Vector2);
((Vector2)(ref val2))..ctor(0.5f, 0.5f);
obj.anchorMax = val2;
obj.anchorMin = val2;
obj.anchoredPosition = pos;
obj.sizeDelta = box;
TextMeshProUGUI obj2 = val.AddComponent<TextMeshProUGUI>();
((TMP_Text)obj2).font = MenuFont.Font;
((TMP_Text)obj2).fontSharedMaterial = MenuFont.OutlinedMaterial;
((TMP_Text)obj2).text = text;
((TMP_Text)obj2).fontSize = size;
((Graphic)obj2).color = color;
((TMP_Text)obj2).alignment = (TextAlignmentOptions)514;
((TMP_Text)obj2).enableWordWrapping = false;
((Graphic)obj2).raycastTarget = false;
return (TMP_Text)(object)obj2;
}
}
[HarmonyPatch(typeof(NetworkManager), "LaunchHost")]
internal static class LaunchHostToClient
{
[HarmonyPriority(800)]
private static bool Prefix(NetworkManager __instance)
{
return !Session.InterceptLaunchHost(__instance);
}
}
[HarmonyPatch(typeof(LoadScreenSystem), "HideLoadingScreen")]
internal static class NoticeLoadScreenHidden
{
private static void Prefix()
{
Session.OnHideLoadingScreen();
}
}
public class ProConMod : MelonMod
{
public override void OnInitializeMelon()
{
((MelonBase)this).LoggerInstance.Msg("ProCon loaded. Main menu -> ProCon to host or join.");
ConsoleFix.DisableQuickEdit();
}
public override void OnUpdate()
{
try
{
MenuFont.Tick();
Session.Tick();
Badge.Tick();
Notice.Tick();
}
catch (Exception ex)
{
((MelonBase)this).LoggerInstance.Error("Update: " + ex);
}
}
public override void OnLateUpdate()
{
try
{
MainMenu.Tick();
}
catch (Exception ex)
{
((MelonBase)this).LoggerInstance.Error("MainMenu: " + ex);
}
}
}
internal static class Relay
{
private const int Data = 0;
private const int Control = 1;
private const byte Hello = 1;
private const byte Welcome = 2;
private const byte WrongCode = 3;
private const byte Bye = 4;
private const byte NotYet = 5;
public static volatile bool HostReady;
public static volatile bool Welcomed;
private static Thread thread;
private static volatile bool running;
private static readonly byte[] buf = new byte[65536];
private static bool hosting;
private static byte session;
private static int gamePort;
private static readonly Dictionary<ulong, UdpClient> peers = new Dictionary<ulong, UdpClient>();
private static readonly object peersLock = new object();
private static ulong hostId;
private static UdpClient local;
private static IPEndPoint gameEndpoint;
public static volatile string ClientStatus = "";
private static readonly Dictionary<ulong, long> waiting = new Dictionary<ulong, long>();
private static readonly object waitingLock = new object();
public static int PeerCount
{
get
{
lock (peersLock)
{
return peers.Count;
}
}
}
public static int LocalPort { get; private set; }
public static void StartHost(byte sessionByte, int port)
{
Stop();
hosting = true;
session = sessionByte;
gamePort = port;
Steam();
SteamNet.SessionRequested += AcceptAnyone;
Begin(HostLoop);
MelonLogger.Msg($"Relay hosting (session {session}) -> 127.0.0.1:{gamePort}");
}
public static void StartClient(ulong host, byte sessionByte)
{
Stop();
hosting = false;
hostId = host;
session = sessionByte;
Welcomed = false;
Steam();
SteamNet.SessionRequested += AcceptHost;
local = Udp();
LocalPort = ((IPEndPoint)local.Client.LocalEndPoint).Port;
ClientStatus = "Connecting through Steam...";
Begin(ClientLoop);
MelonLogger.Msg($"Relay client -> {host}, local port {LocalPort}");
}
public static void Stop()
{
if (!running && thread == null)
{
return;
}
running = false;
thread?.Join(500);
thread = null;
SteamNet.SessionRequested -= AcceptAnyone;
SteamNet.SessionRequested -= AcceptHost;
lock (peersLock)
{
foreach (KeyValuePair<ulong, UdpClient> peer in peers)
{
try
{
peer.Value.Close();
}
catch
{
}
SteamNet.Close(peer.Key);
}
peers.Clear();
}
lock (waitingLock)
{
waiting.Clear();
}
if (local != null)
{
try
{
SteamNet.SendReliable(hostId, new byte[1] { 4 }, 1);
}
catch
{
}
SteamNet.Close(hostId);
local.Close();
local = null;
}
gameEndpoint = null;
MelonLogger.Msg("Relay stopped.");
}
private static void Steam()
{
SteamNet.AllowRelay();
SteamNet.RegisterSessionRequest();
}
private static void AcceptAnyone(ulong id)
{
if (hosting)
{
SteamNet.Accept(id);
}
}
private static void AcceptHost(ulong id)
{
if (id == hostId)
{
SteamNet.Accept(id);
}
}
private static void Begin(ThreadStart loop)
{
running = true;
thread = new Thread(loop)
{
IsBackground = true,
Name = "ProCon relay"
};
thread.Start();
}
private static UdpClient Udp()
{
UdpClient udpClient = new UdpClient(new IPEndPoint(IPAddress.Loopback, 0));
try
{
udpClient.Client.IOControl(-1744830452, new byte[1], null);
}
catch
{
}
return udpClient;
}
private static void HostLoop()
{
while (running)
{
bool flag = false;
try
{
ulong from;
int num;
while ((num = SteamNet.Read(buf, 1, out from)) > 0)
{
flag = true;
if (buf[0] == 1 && num >= 2)
{
OnHello(from, buf[1]);
}
else if (buf[0] == 4)
{
DropPeer(from);
}
else if (buf[0] == 6)
{
LobbySync.Incoming.Enqueue((from, Copy(buf, num)));
}
}
ulong from2;
while ((num = SteamNet.Read(buf, 0, out from2)) > 0)
{
flag = true;
UdpClient value;
lock (peersLock)
{
peers.TryGetValue(from2, out value);
}
value?.Send(buf, num);
}
lock (peersLock)
{
foreach (KeyValuePair<ulong, UdpClient> peer in peers)
{
while (peer.Value.Available > 0)
{
IPEndPoint remoteEP = new IPEndPoint(IPAddress.Any, 0);
byte[] array = peer.Value.Receive(ref remoteEP);
SteamNet.Send(peer.Key, array, array.Length, 0);
flag = true;
}
}
}
}
catch (Exception ex)
{
MelonLogger.Warning("Relay host: " + ex.Message);
}
if (!flag)
{
Thread.Sleep(1);
}
}
}
private static void OnHello(ulong from, byte theirSession)
{
if (theirSession != session)
{
SteamNet.SendReliable(from, new byte[1] { 3 }, 1);
return;
}
if (!HostReady)
{
lock (waitingLock)
{
waiting[from] = Environment.TickCount64;
}
SteamNet.SendReliable(from, new byte[1] { 5 }, 1);
return;
}
lock (waitingLock)
{
waiting.Remove(from);
}
lock (peersLock)
{
if (!peers.ContainsKey(from))
{
UdpClient udpClient = Udp();
udpClient.Connect(IPAddress.Loopback, gamePort);
peers[from] = udpClient;
MelonLogger.Msg($"Relay: friend {from} connected ({peers.Count} total)");
}
}
SteamNet.SendReliable(from, new byte[1] { 2 }, 1);
}
private static byte[] Copy(byte[] src, int n)
{
byte[] array = new byte[n];
Array.Copy(src, array, n);
return array;
}
public static List<ulong> FriendIds()
{
HashSet<ulong> hashSet = new HashSet<ulong>(WaitingFriends());
lock (peersLock)
{
foreach (ulong key in peers.Keys)
{
hashSet.Add(key);
}
}
return new List<ulong>(hashSet);
}
public static void SendLobby(ulong to, byte[] data)
{
if (running)
{
ulong num = ((to != 0L) ? to : hostId);
if (num != 0L)
{
SteamNet.SendReliable(num, data, 1);
}
}
}
public static List<ulong> WaitingFriends()
{
List<ulong> list = new List<ulong>();
long tickCount = Environment.TickCount64;
lock (waitingLock)
{
foreach (KeyValuePair<ulong, long> item in waiting)
{
if (tickCount - item.Value < 3000)
{
list.Add(item.Key);
}
}
return list;
}
}
private static void DropPeer(ulong from)
{
lock (peersLock)
{
if (peers.TryGetValue(from, out var value))
{
value.Close();
peers.Remove(from);
}
}
lock (waitingLock)
{
waiting.Remove(from);
}
SteamNet.Close(from);
LobbySync.Incoming.Enqueue((from, new byte[0]));
MelonLogger.Msg($"Relay: friend {from} left");
}
private static void ClientLoop()
{
Stopwatch stopwatch = Stopwatch.StartNew();
bool flag = false;
long num = -1000L;
while (running)
{
bool flag2 = false;
try
{
if (!flag && stopwatch.ElapsedMilliseconds - num > 500)
{
num = stopwatch.ElapsedMilliseconds;
SteamNet.SendReliable(hostId, new byte[2] { 1, session }, 1);
if (stopwatch.ElapsedMilliseconds > 15000)
{
ClientStatus = "Can't reach the host. Is the code right and are they hosting?";
}
}
ulong from;
int n;
while ((n = SteamNet.Read(buf, 1, out from)) > 0)
{
if (from == hostId)
{
if (buf[0] == 2 && !flag)
{
flag = true;
Welcomed = true;
ClientStatus = "";
MelonLogger.Msg("Relay: host said welcome.");
}
else if (buf[0] == 5)
{
ClientStatus = "Connected! Waiting for the host to start the round";
stopwatch.Restart();
num = 0L;
}
else if (buf[0] == 3)
{
ClientStatus = "That code is old. Ask your friend for the new one.";
}
else if (buf[0] == 4)
{
ClientStatus = "Host closed the game.";
}
else if (buf[0] == 6)
{
LobbySync.Incoming.Enqueue((from, Copy(buf, n)));
}
}
}
ulong from2;
while ((n = SteamNet.Read(buf, 0, out from2)) > 0)
{
flag2 = true;
if (from2 == hostId && gameEndpoint != null)
{
local.Send(buf, n, gameEndpoint);
}
}
while (local.Available > 0)
{
IPEndPoint remoteEP = new IPEndPoint(IPAddress.Any, 0);
byte[] array = local.Receive(ref remoteEP);
gameEndpoint = remoteEP;
SteamNet.Send(hostId, array, array.Length, 0);
flag2 = true;
}
}
catch (Exception ex)
{
if (running)
{
MelonLogger.Warning("Relay client: " + ex.Message);
}
}
if (!flag2)
{
Thread.Sleep(1);
}
}
}
}
internal static class Session
{
private enum Mode
{
None,
Hosting,
Joining,
Waiting,
Joined
}
public const int Port = 5999;
private static Mode mode;
private static string code = "";
private static bool sawActive;
private static float startedAt;
private static ulong pendingHost;
private static byte pendingSession;
private static NetworkManager waitingNet;
private static bool sameMachine;
private static float checkTimer;
private static float inputFixTimer;
private static readonly HashSet<IntPtr> fixedDrivers = new HashSet<IntPtr>();
private static float loadedFor;
private static string loadedScene = "";
private static bool hidingOurselves;
public static bool GameHidLoadScreen;
private static float joinCheck;
private static string lastBeastLog = "";
public static bool IsHosting => mode == Mode.Hosting;
public static void Host(Button localButton)
{
byte b = (byte)new Random().Next(256);
code = JoinCode.Encode(SteamNet.MyAccountId, b);
mode = Mode.Hosting;
sawActive = false;
startedAt = Time.unscaledTime;
Clipboard.Set(code);
Relay.StartHost(b, 5999);
MelonLogger.Msg("Hosting with code " + code);
((UnityEvent)localButton.onClick).Invoke();
}
public static void Join(string joinCode, Button localButton)
{
if (JoinCode.TryDecode(joinCode, out var account, out var session))
{
code = JoinCode.Clean(joinCode);
mode = Mode.Joining;
pendingHost = 76561197960265728uL + (ulong)account;
pendingSession = session;
sawActive = false;
startedAt = Time.unscaledTime;
sameMachine = pendingHost == SteamNet.MySteamId;
if (!sameMachine)
{
Relay.StartClient(pendingHost, pendingSession);
}
MelonLogger.Msg($"Join {code} -> Steam {pendingHost}. Waiting for beast select to finish.");
((UnityEvent)localButton.onClick).Invoke();
}
}
public static bool InterceptLaunchHost(NetworkManager net)
{
if (mode == Mode.Waiting)
{
return true;
}
if (mode != Mode.Joining || pendingHost == 0L)
{
return false;
}
waitingNet = net;
mode = Mode.Waiting;
MelonLogger.Msg($"Beasts ready ({NetMemberContext.PlayerCount}). Waiting for the host's round{(sameMachine ? " (same PC)" : "")}.");
return true;
}
public static void Tick()
{
LobbySync.Active = mode == Mode.Hosting || ((mode == Mode.Joining || mode == Mode.Waiting) && !sameMachine);
LobbySync.Tick(mode == Mode.Hosting);
if (mode == Mode.Hosting)
{
bool flag = false;
try
{
flag = NetworkServer.active;
}
catch
{
}
Relay.HostReady = flag;
if (flag)
{
FixRemoteInput();
}
}
if (mode == Mode.Joining)
{
AutoStartJoin();
}
else if (mode == Mode.Joined)
{
LoadScreenWatchdog();
}
else
{
if (mode != Mode.Waiting)
{
return;
}
checkTimer -= Time.unscaledDeltaTime;
if (!(checkTimer > 0f))
{
checkTimer = 0.5f;
if (sameMachine ? LocalServerUp() : Relay.Welcomed)
{
mode = Mode.Joined;
pendingHost = 0uL;
NetMemberContext.LocalHostedGame = false;
int num = (sameMachine ? 5999 : Relay.LocalPort);
MelonLogger.Msg($"Host is up. Connecting to 127.0.0.1:{num} with {NetMemberContext.PlayerCount} beast(s).");
waitingNet.LaunchClient("127.0.0.1", num);
}
}
}
}
private static void FixRemoteInput()
{
inputFixTimer -= Time.unscaledDeltaTime;
if (inputFixTimer > 0f)
{
return;
}
inputFixTimer = 0.5f;
foreach (Actor item in Object.FindObjectsOfType<Actor>())
{
if ((Object)(object)item == (Object)null || item.IsAI)
{
continue;
}
bool flag;
try
{
NetworkConnection connectionToClient = ((NetworkBehaviour)item).connectionToClient;
flag = connectionToClient != null && connectionToClient.hostId != -1;
}
catch
{
continue;
}
if (!flag)
{
continue;
}
foreach (InputDriver componentsInChild in ((Component)item).GetComponentsInChildren<InputDriver>(true))
{
if (!((Object)(object)componentsInChild == (Object)null) && fixedDrivers.Add(((Il2CppObjectBase)componentsInChild).Pointer))
{
try
{
componentsInChild.DisconnectController();
}
catch
{
}
((Behaviour)componentsInChild).enabled = false;
MelonLogger.Msg($"Remote beast '{((Object)item).name}' (player {item.playerID}): stopped reading this PC's controller.");
}
}
}
}
public static void OnHideLoadingScreen()
{
if (!hidingOurselves && mode == Mode.Joined)
{
GameHidLoadScreen = true;
}
}
private static void LoadScreenWatchdog()
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
Scene activeScene = SceneManager.GetActiveScene();
string name = ((Scene)(ref activeScene)).name;
if (name == "Menu" || name == "_bootScene")
{
loadedFor = 0f;
return;
}
if (name != loadedScene)
{
loadedScene = name;
loadedFor = 0f;
GameHidLoadScreen = false;
}
if (GameHidLoadScreen)
{
return;
}
NetClientCatchUp val = Object.FindObjectOfType<NetClientCatchUp>();
if ((Object)(object)val != (Object)null && val.CatchingUp)
{
loadedFor = 0f;
return;
}
loadedFor += Time.unscaledDeltaTime;
if (loadedFor < 6f)
{
return;
}
LoadScreenSystem val2 = Object.FindObjectOfType<LoadScreenSystem>();
if (!((Object)(object)val2 == (Object)null) && val2.LoadScreenActive && !val2.HideFadeActive)
{
MelonLogger.Msg($"Loading screen still up {loadedFor:0.0}s after '{name}' loaded - hiding it.");
hidingOurselves = true;
try
{
val2.HideLoadingScreen((Action)null, -1f, true);
}
finally
{
hidingOurselves = false;
}
loadedFor = -10f;
}
}
private static void AutoStartJoin()
{
joinCheck -= Time.unscaledDeltaTime;
if (joinCheck > 0f)
{
return;
}
joinCheck = 0.25f;
LobbyManager instance = LobbyManager.Instance;
LocalBeastSetupTracker val = ((instance != null) ? instance.LocalBeasts : null);
if ((Object)(object)val == (Object)null)
{
return;
}
int num = val.TotalInState((PlayerState)2);
int num2 = val.TotalInState((PlayerState)1);
string text = $"ready={num} designing={num2}";
if (text != lastBeastLog)
{
lastBeastLog = text;
MelonLogger.Msg("Join beast select: " + text);
}
if (num != 0 && num2 <= 0)
{
try
{
int value = val.SetupNetMemberContext(false);
MelonLogger.Msg($"SetupNetMemberContext -> {value}");
}
catch (Exception ex)
{
MelonLogger.Error("SetupNetMemberContext failed: " + ex.Message);
return;
}
NetworkManager singleton = NetworkManager.singleton;
NetworkManager val2 = ((singleton != null) ? ((Il2CppObjectBase)singleton).TryCast<NetworkManager>() : null);
if ((Object)(object)val2 != (Object)null)
{
InterceptLaunchHost(val2);
}
}
}
private static bool LocalServerUp()
{
try
{
IPEndPoint[] activeUdpListeners = IPGlobalProperties.GetIPGlobalProperties().GetActiveUdpListeners();
for (int i = 0; i < activeUdpListeners.Length; i++)
{
if (activeUdpListeners[i].Port == 5999)
{
return true;
}
}
}
catch
{
}
return false;
}
public static string StatusLine()
{
return "Friends join with your code from anywhere";
}
public static string BadgeLine()
{
//IL_0054: 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)
if (mode == Mode.None)
{
return null;
}
bool flag = false;
try
{
flag = (Object)(object)NetworkManager.singleton != (Object)null && NetworkManager.singleton.isNetworkActive;
}
catch
{
}
if (flag)
{
sawActive = true;
}
else
{
if (sawActive)
{
End();
return null;
}
if (mode == Mode.Hosting || mode == Mode.Joining)
{
Scene activeScene = SceneManager.GetActiveScene();
if (((Scene)(ref activeScene)).name == "Menu" && MainMenu.OnMainList && Time.unscaledTime - startedAt > 1f)
{
End();
return null;
}
}
}
string clientStatus = Relay.ClientStatus;
return mode switch
{
Mode.Hosting => "Hosting <color=#ffffff>" + code + "</color> <size=70%>(copied)</size>" + ((!Relay.HostReady) ? sub("Start a round so friends can join" + WaitingLine()) : ((Relay.PeerCount > 0) ? sub($"{Relay.PeerCount} friend(s) connected") : "")),
Mode.Joining => "Joining <color=#ffffff>" + code + "</color>" + sub("Join your beast and ready up - you'll connect automatically" + ((clientStatus.Length > 0) ? ("\n" + clientStatus) : "")),
Mode.Waiting => "Joining <color=#ffffff>" + code + "</color>" + sub((clientStatus.Length > 0) ? clientStatus : "Waiting for the host to start a round..."),
_ => "Joined <color=#ffffff>" + code + "</color>",
};
static string sub(string s)
{
return "\n<size=60%>" + s + "</size>";
}
}
private static string WaitingLine()
{
List<ulong> list = Relay.WaitingFriends();
if (list.Count == 0)
{
return "";
}
List<string> list2 = new List<string>();
foreach (ulong item in list)
{
list2.Add(SteamNet.Name(item));
}
return "\n<color=#ffffff>Waiting to join: " + string.Join(", ", list2) + "</color>";
}
private static void End()
{
mode = Mode.None;
pendingHost = 0uL;
waitingNet = null;
Relay.HostReady = false;
LobbySync.Active = false;
LobbySync.Clear();
Relay.Stop();
}
}
internal static class JoinCode
{
public const int Length = 8;
private const string Alphabet = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789";
private const ulong Mask = 711950999163uL;
public static string Encode(uint account, byte session)
{
ulong num = (((ulong)account << 8) | session) ^ 0xA5C3961E7BL ^ (ulong)((session * 4311810305L) & 0xFFFFFFFF00L);
char[] array = new char[8];
for (int num2 = 7; num2 >= 0; num2--)
{
array[num2] = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789"[(int)(num % 32)];
num /= 32;
}
return new string(array);
}
public static bool TryDecode(string code, out uint account, out byte session)
{
account = 0u;
session = 0;
code = Clean(code);
if (code.Length != 8)
{
return false;
}
ulong num = 0uL;
string text = code;
foreach (char value in text)
{
num = num * 32 + (ulong)"ABCDEFGHJKLMNPQRSTUVWXYZ23456789".IndexOf(value);
}
num ^= 0xA5C3961E7BL;
session = (byte)num;
num ^= (ulong)((session * 4311810305L) & 0xFFFFFFFF00L);
account = (uint)(num >> 8);
return account != 0;
}
public static bool IsValid(string code)
{
uint account;
byte session;
return TryDecode(code, out account, out session);
}
public static string Clean(string s)
{
if (string.IsNullOrEmpty(s))
{
return "";
}
StringBuilder stringBuilder = new StringBuilder();
string text = s.ToUpperInvariant();
foreach (char value in text)
{
if ("ABCDEFGHJKLMNPQRSTUVWXYZ23456789".IndexOf(value) >= 0)
{
stringBuilder.Append(value);
}
}
return stringBuilder.ToString();
}
}
internal static class SteamNet
{
[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
private delegate void RunCb(IntPtr self, IntPtr param);
[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
private delegate void RunCr(IntPtr self, IntPtr param, [MarshalAs(UnmanagedType.I1)] bool ioFailure, ulong call);
[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
private delegate int SizeCb(IntPtr self);
private const string Lib = "steam_api64";
private const int TypeUnreliable = 0;
private const int TypeReliable = 2;
private const int MaxUnreliable = 1200;
private static IntPtr net;
public const ulong IndividualBase = 76561197960265728uL;
private const int P2PSessionRequestId = 1202;
private static RunCb runCb;
private static RunCr runCr;
private static SizeCb sizeCb;
private static IntPtr callbackObj;
private static IntPtr vtable;
private static IntPtr Net
{
get
{
if (!(net != IntPtr.Zero))
{
return net = SteamAPI_SteamNetworking_v006();
}
return net;
}
}
public static ulong MySteamId => SteamAPI_ISteamUser_GetSteamID(SteamAPI_SteamUser_v023());
public static uint MyAccountId => (uint)(MySteamId - 76561197960265728L);
public static event Action<ulong> SessionRequested;
[DllImport("steam_api64")]
private static extern IntPtr SteamAPI_SteamUser_v023();
[DllImport("steam_api64")]
private static extern IntPtr SteamAPI_SteamNetworking_v006();
[DllImport("steam_api64")]
private static extern ulong SteamAPI_ISteamUser_GetSteamID(IntPtr self);
[DllImport("steam_api64")]
[return: MarshalAs(UnmanagedType.I1)]
private static extern bool SteamAPI_ISteamNetworking_SendP2PPacket(IntPtr self, ulong remote, byte[] data, uint size, int sendType, int channel);
[DllImport("steam_api64")]
[return: MarshalAs(UnmanagedType.I1)]
private static extern bool SteamAPI_ISteamNetworking_IsP2PPacketAvailable(IntPtr self, out uint size, int channel);
[DllImport("steam_api64")]
[return: MarshalAs(UnmanagedType.I1)]
private static extern bool SteamAPI_ISteamNetworking_ReadP2PPacket(IntPtr self, byte[] dest, uint destSize, out uint size, out ulong remote, int channel);
[DllImport("steam_api64")]
[return: MarshalAs(UnmanagedType.I1)]
private static extern bool SteamAPI_ISteamNetworking_AcceptP2PSessionWithUser(IntPtr self, ulong remote);
[DllImport("steam_api64")]
[return: MarshalAs(UnmanagedType.I1)]
private static extern bool SteamAPI_ISteamNetworking_CloseP2PSessionWithUser(IntPtr self, ulong remote);
[DllImport("steam_api64")]
[return: MarshalAs(UnmanagedType.I1)]
private static extern bool SteamAPI_ISteamNetworking_AllowP2PPacketRelay(IntPtr self, [MarshalAs(UnmanagedType.I1)] bool allow);
[DllImport("steam_api64")]
private static extern void SteamAPI_RegisterCallback(IntPtr callback, int id);
[DllImport("steam_api64")]
private static extern IntPtr SteamAPI_SteamFriends_v017();
[DllImport("steam_api64")]
private static extern IntPtr SteamAPI_ISteamFriends_GetFriendPersonaName(IntPtr self, ulong user);
[DllImport("steam_api64")]
[return: MarshalAs(UnmanagedType.I1)]
private static extern bool SteamAPI_ISteamFriends_RequestUserInformation(IntPtr self, ulong user, [MarshalAs(UnmanagedType.I1)] bool nameOnly);
public static string Name(ulong user)
{
try
{
IntPtr self = SteamAPI_SteamFriends_v017();
string text = Marshal.PtrToStringUTF8(SteamAPI_ISteamFriends_GetFriendPersonaName(self, user));
if (string.IsNullOrEmpty(text) || text == "[unknown]")
{
SteamAPI_ISteamFriends_RequestUserInformation(self, user, nameOnly: true);
return "a friend";
}
return text;
}
catch
{
return "a friend";
}
}
public static void AllowRelay()
{
SteamAPI_ISteamNetworking_AllowP2PPacketRelay(Net, allow: true);
}
public static bool Send(ulong to, byte[] data, int size, int channel)
{
return SteamAPI_ISteamNetworking_SendP2PPacket(Net, to, data, (uint)size, (size > 1200) ? 2 : 0, channel);
}
public static bool SendReliable(ulong to, byte[] data, int channel)
{
return SteamAPI_ISteamNetworking_SendP2PPacket(Net, to, data, (uint)data.Length, 2, channel);
}
public static int Read(byte[] buf, int channel, out ulong from)
{
from = 0uL;
if (!SteamAPI_ISteamNetworking_IsP2PPacketAvailable(Net, out var size, channel) || size == 0)
{
return -1;
}
if (size > buf.Length)
{
size = (uint)buf.Length;
}
if (!SteamAPI_ISteamNetworking_ReadP2PPacket(Net, buf, size, out var size2, out from, channel))
{
return -1;
}
return (int)size2;
}
public static void Accept(ulong user)
{
SteamAPI_ISteamNetworking_AcceptP2PSessionWithUser(Net, user);
}
public static void Close(ulong user)
{
SteamAPI_ISteamNetworking_CloseP2PSessionWithUser(Net, user);
}
public static void RegisterSessionRequest()
{
if (callbackObj != IntPtr.Zero)
{
return;
}
runCb = delegate(IntPtr self, IntPtr param)
{
try
{
SteamNet.SessionRequested?.Invoke((ulong)Marshal.ReadInt64(param));
}
catch (Exception ex)
{
MelonLogger.Error("P2P request: " + ex);
}
};
runCr = delegate(IntPtr self, IntPtr param, bool fail, ulong call)
{
runCb(self, param);
};
sizeCb = (IntPtr self) => 8;
vtable = Marshal.AllocHGlobal(IntPtr.Size * 3);
Marshal.WriteIntPtr(vtable, 0, Marshal.GetFunctionPointerForDelegate(runCr));
Marshal.WriteIntPtr(vtable, IntPtr.Size, Marshal.GetFunctionPointerForDelegate(runCb));
Marshal.WriteIntPtr(vtable, IntPtr.Size * 2, Marshal.GetFunctionPointerForDelegate(sizeCb));
callbackObj = Marshal.AllocHGlobal(16);
Marshal.WriteIntPtr(callbackObj, 0, vtable);
Marshal.WriteByte(callbackObj, 8, 0);
Marshal.WriteInt32(callbackObj, 12, 1202);
SteamAPI_RegisterCallback(callbackObj, 1202);
}
}
internal static class Util
{
public static GameObject FindAny(string path)
{
//IL_0035: Unknown result type (might be due to invalid IL or missing references)
//IL_003a: Unknown result type (might be due to invalid IL or missing references)
GameObject val = GameObject.Find(path);
if ((Object)(object)val != (Object)null)
{
return val;
}
foreach (Transform item in Resources.FindObjectsOfTypeAll<Transform>())
{
if ((Object)(object)item != (Object)null)
{
Scene scene = ((Component)item).gameObject.scene;
if (((Scene)(ref scene)).IsValid() && Path(item) == path)
{
return ((Component)item).gameObject;
}
}
}
return null;
}
public static string Path(Transform t)
{
string text = ((Object)t).name;
t = t.parent;
while ((Object)(object)t != (Object)null)
{
text = ((Object)t).name + "/" + text;
t = t.parent;
}
return text;
}
public static void Debug(string s)
{
}
}
}