Decompiled source of Online Crawl v1.0.0
CrawlOnline/CrawlOnline.dll
Decompiled 14 hours ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; using System.Globalization; using System.IO; using System.Net; using System.Net.Sockets; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Security; using System.Security.Permissions; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using CrawlOnline.Client; using CrawlOnline.Dev; using CrawlOnline.Host; using CrawlOnline.Net; using CrawlOnline.UI; using CrawlOnline.Util; using HarmonyLib; using InControl; using Microsoft.CodeAnalysis; using Steamworks; using UnityEngine; using UnityEngine.SceneManagement; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [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 CrawlOnline { internal static class Boot { public static void Init() { Online.Init(); Overlay.Init(); Splash.Init(); OnlineMenu.Init(); DevCommands.Init(); } } public static class Online { public static string Status = ""; public static string LastError = ""; private static Action s_pendingJoin; private static float s_nextLobbyData; private static string s_pendingJoinLabel; private static bool s_steamCallbacksReady; private static bool s_commandLineChecked; private static int s_savedTargetFrameRate = int.MinValue; private static bool s_inviteWhenReady; public static HostSession Host { get; private set; } public static ClientSession Client { get; private set; } public static SteamLobby Lobby { get; private set; } public static bool IsHost => Host != null; public static bool IsClient => Client != null; public static bool InSession { get { if (Host == null) { return Client != null; } return true; } } public static void Init() { Runner.OnUpdate += Update; Runner.OnLateUpdate += LateUpdate; Runner.OnEndOfFrame += EndOfFrame; Runner.OnQuit += delegate { Stop("game closed"); }; SteamLobby.OnJoinRequested += delegate(ulong lobby) { JoinSteamLobby(lobby); }; } private static void Update() { //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) if (!s_steamCallbacksReady && SteamLobby.SteamReady) { s_steamCallbacksReady = true; SteamLobby.InitGlobalCallbacks(); } if (s_steamCallbacksReady && !s_commandLineChecked) { Scene activeScene = SceneManager.GetActiveScene(); if (((Scene)(ref activeScene)).name == "SceneMenuMain") { s_commandLineChecked = true; ulong num = SteamLobby.LobbyFromCommandLine(); if (num != 0L) { JoinSteamLobby(num); } } } if (s_pendingJoin != null && !InSession && CanStartClientNow()) { Action action = s_pendingJoin; s_pendingJoin = null; action(); } if (Host != null) { try { Host.Update(); } catch (Exception ex) { Plugin.Log.LogError((object)("[Host] update failed: " + ex)); } if (Lobby != null && Time.realtimeSinceStartup >= s_nextLobbyData) { s_nextLobbyData = Time.realtimeSinceStartup + 2f; try { int max = 1 + Mathf.Min(Host.MaxConnections, 3); string state = (SystemMain.GetIsGameLevel() ? "In game" : "In menu"); Lobby.UpdateHostData(1 + Host.ClientCount, max, state); } catch (Exception ex2) { Plugin.Log.LogWarning((object)("[Host] lobby data: " + ex2.Message)); } } } LobbyBrowser.Tick(); if (Client != null) { Client.Update(); if (Client != null && Client.State == ClientSession.States.Closed) { EndClient(); } } } private static void LateUpdate() { if (Client != null) { Client.LateUpdate(); } } private static void EndOfFrame() { if (Host != null) { try { Host.EndOfFrame(); } catch (Exception ex) { Plugin.Log.LogError((object)("[Host] end of frame failed: " + ex)); } } } private static string LocalName() { try { if (SteamLobby.SteamReady) { return SteamFriends.GetPersonaName(); } } catch { } return Environment.UserName; } private static void ApplySessionSettings() { Application.runInBackground = true; if (IsClient && Plugin.CfgClientFpsLimit.Value > 0) { if (s_savedTargetFrameRate == int.MinValue) { s_savedTargetFrameRate = Application.targetFrameRate; } Application.targetFrameRate = Plugin.CfgClientFpsLimit.Value; } } private static void RestoreSessionSettings() { Application.runInBackground = Plugin.CfgRunInBackground.Value; if (s_savedTargetFrameRate != int.MinValue) { Application.targetFrameRate = s_savedTargetFrameRate; s_savedTargetFrameRate = int.MinValue; } } public static bool StartHostSteam() { //IL_000a: Unknown result type (might be due to invalid IL or missing references) return StartHostSteam(ParseLobbyType(Plugin.CfgLobbyType.Value)); } public static ELobbyType ParseLobbyType(string s) { string text = (s ?? "").ToLowerInvariant(); if (!(text == "friends")) { if (text == "invite") { return (ELobbyType)0; } return (ELobbyType)2; } return (ELobbyType)1; } public static string LobbyTypeKey(ELobbyType t) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Invalid comparison between Unknown and I4 //IL_0004: Unknown result type (might be due to invalid IL or missing references) if ((int)t != 1) { if ((int)t != 0) { return "public"; } return "invite"; } return "friends"; } public static string LobbyName() { string value = Plugin.CfgLobbyName.Value; if (!string.IsNullOrEmpty(value) && value.Trim().Length > 0) { return value.Trim(); } return LocalName() + "'s game"; } public static bool StartHostSteam(ELobbyType type) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0013: 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) Plugin.CfgLobbyType.Value = LobbyTypeKey(type); if (InSession) { return false; } if (!SteamLobby.SteamReady) { LastError = "Steam is not available"; return false; } try { BeginHost(new SteamTransport { AcceptFilter = (ulong id) => true }, LocalName()); Lobby = new SteamLobby(); Status = "Creating Steam lobby..."; Lobby.Create(8, type, LobbyName(), delegate(bool ok, string err) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) if (ok) { Status = "Hosting (Steam, " + SteamLobby.TypeName(type) + " lobby)"; Plugin.Log.LogInfo((object)("[Host] Steam lobby " + Lobby.LobbyId.m_SteamID)); if (s_inviteWhenReady) { s_inviteWhenReady = false; Lobby.Invite(); } } else { LastError = err; Status = "Hosting (Steam, lobby failed - friends can still join via Steam profile)"; Plugin.Log.LogWarning((object)("[Host] " + err)); } }); return true; } catch (Exception ex) { LastError = "Host failed: " + ex.Message; Plugin.Log.LogError((object)ex); Stop("error"); return false; } } public static bool StartHostUdp(int port) { if (InSession) { return false; } try { UdpTransport udpTransport = new UdpTransport(port, null, 0); BeginHost(udpTransport, LocalName()); Status = "Hosting (UDP port " + udpTransport.LocalPort + ")"; return true; } catch (Exception ex) { LastError = "UDP host failed: " + ex.Message; Plugin.Log.LogError((object)ex); return false; } } private static void BeginHost(ITransport transport, string name) { Host = new HostSession(transport) { HostName = name, MaxConnections = Mathf.Clamp(Plugin.CfgMaxConnections.Value, 1, 7), SendRate = Plugin.CfgSendRate.Value }; Host.OnInfo += delegate(string s) { Status = s; }; LastError = ""; ApplySessionSettings(); Plugin.Log.LogInfo((object)("[Host] started on " + transport.Name)); } public static void InviteFriends() { if (Lobby != null && Lobby.InLobby) { Lobby.Invite(); } else if (IsHost) { s_inviteWhenReady = true; } } private static bool CanStartClientNow() { if (ClientStage.LocalGameBusy) { if (SystemMain.GetIsGameLevel() && !SystemMain.GetDeloadInProgress()) { Status = "Leaving local game..."; try { SystemMain.SaveAndQuitLevel(); } catch (Exception ex) { Plugin.Log.LogError((object)ex); } } return false; } return true; } private static void QueueJoin(string label, Action a) { if (InSession) { LastError = "Leave the current session first"; return; } s_pendingJoin = a; s_pendingJoinLabel = label; Status = "Joining " + label + "..."; } public static void JoinUdp(string address, int port) { QueueJoin(address + ":" + port, delegate { try { BeginClient(new UdpTransport(0, address, port), 1uL); } catch (Exception ex) { LastError = "Connect failed: " + ex.Message; Status = ""; } }); } public static void JoinSteamLobby(ulong lobby) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) if (IsClient && Lobby != null && Lobby.LobbyId.m_SteamID == lobby) { return; } if (InSession) { LastError = "Already in a session - disconnect first to accept the invite"; return; } QueueJoin("Steam lobby", delegate { if (!SteamLobby.SteamReady) { LastError = "Steam is not available"; } else { Lobby = new SteamLobby(); Status = "Entering Steam lobby..."; Lobby.Join(lobby, delegate(bool ok, ulong owner, string err) { if (!ok) { LastError = err; Status = ""; Lobby.Leave(); Lobby = null; } else { JoinSteamUser(owner); } }); } }); } public static void JoinSteamUser(ulong hostId) { try { BeginClient(new SteamTransport { AcceptFilter = (ulong id) => id == hostId }, hostId); } catch (Exception ex) { LastError = "Connect failed: " + ex.Message; } } private static void BeginClient(ITransport transport, ulong hostPeer) { Client = new ClientSession(transport, hostPeer, LocalName()); Status = "Connecting to host..."; LastError = ""; ApplySessionSettings(); } private static void EndClient() { if (Client != null) { if (!string.IsNullOrEmpty(Client.CloseReason) && Client.CloseReason != "left") { LastError = Client.CloseReason; } Client = null; if (Lobby != null) { Lobby.Leave(); Lobby = null; } Status = ""; RestoreSessionSettings(); } } public static void Stop(string reason) { s_pendingJoin = null; if (Host != null) { try { Host.Shutdown(reason); } catch (Exception ex) { Plugin.Log.LogError((object)ex); } Host = null; } if (Client != null) { try { Client.Close(reason, notifyHost: true); } catch (Exception ex2) { Plugin.Log.LogError((object)ex2); } EndClient(); } if (Lobby != null) { Lobby.Leave(); Lobby = null; } Status = ""; RestoreSessionSettings(); } } [HarmonyPatch(typeof(exSprite), "UpdateMesh")] internal static class Patch_exSprite_UpdateMesh { private static void Postfix(Mesh _mesh) { SceneCapture.OnMeshUpdated(_mesh); } } [HarmonyPatch(typeof(exSpriteFont), "UpdateMesh")] internal static class Patch_exSpriteFont_UpdateMesh { private static void Postfix(Mesh _mesh) { SceneCapture.OnMeshUpdated(_mesh); } } [HarmonyPatch(typeof(exSpriteBorder), "UpdateMesh")] internal static class Patch_exSpriteBorder_UpdateMesh { private static void Postfix(Mesh _mesh) { SceneCapture.OnMeshUpdated(_mesh); } } [HarmonyPatch(typeof(exPlane), "OnEnable")] internal static class Patch_exPlane_OnEnable { private static void Postfix(exPlane __instance) { SceneCapture.OnPlaneEnabled((Component)(object)__instance); } } [HarmonyPatch(typeof(ColorSwapper), "Apply")] internal static class Patch_ColorSwapper_Apply { private static void Postfix(ColorSwapper __instance) { TextureVersions.Bump((Texture)(object)__instance.m_texture); } } [HarmonyPatch(typeof(InputManager), "UpdateDevices")] internal static class Patch_InputManager_UpdateDevices { private static void Postfix(float deltaTime) { if (DeviceView.Active) { DeviceView.Sync(); DeviceView.UpdateVirtual(InputManager.currentTick, deltaTime); } } } [HarmonyPatch(typeof(InputManager), "CommitDevices")] internal static class Patch_InputManager_CommitDevices { private static void Postfix(float deltaTime) { if (DeviceView.Active) { DeviceView.CommitVirtual(InputManager.currentTick, deltaTime); } } } [HarmonyPatch(typeof(SystemInput), "GetAngleSmoothingEnabledImpl")] internal static class Patch_SystemInput_AngleSmoothing { private static void Postfix(eController controllerId, ref bool __result) { //IL_000b: 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_001a: Expected I4, but got Unknown if (!__result && DeviceView.Active && SystemInput.IsController(controllerId)) { NetGamepad netGamepad = DeviceView.FindByDeviceIndex((int)controllerId); if (netGamepad != null && netGamepad.FromKeyboard && !netGamepad.MouseMode) { __result = true; } } } } [HarmonyPatch(typeof(MenuTextMenu), "Initialise")] internal static class Patch_MenuTextMenu_Initialise { private static void Postfix(MenuTextMenu __instance) { try { OnlineMenu.TryAttach(__instance); } catch (Exception ex) { Plugin.Log.LogError((object)("ONLINE menu entry failed: " + ex)); } } } internal static class MenuMouseContext { public static void Enter(int playerId) { RemoteMouse.Context = (Online.IsHost ? RemoteMouse.ForPlayer(playerId) : null); RemoteMouse.ContextPlayer = ((RemoteMouse.Context != null) ? playerId : (-1)); } public static void Exit() { RemoteMouse.Context = null; RemoteMouse.ContextPlayer = -1; } } [HarmonyPatch(typeof(MenuTextMenu), "Update")] internal static class Patch_MenuTextMenu_Update { private static void Prefix(MenuTextMenu __instance) { MenuMouseContext.Enter(__instance.m_playerId); } private static void Postfix() { MenuMouseContext.Exit(); } } [HarmonyPatch(typeof(MenuButtonMenu), "Update")] internal static class Patch_MenuButtonMenu_Update { private static void Prefix(MenuButtonMenu __instance) { MenuMouseContext.Enter(__instance.m_playerId); } private static void Postfix() { MenuMouseContext.Exit(); } } [HarmonyPatch(typeof(SystemPlayers), "GetPlayerWithController")] internal static class Patch_SystemPlayers_GetPlayerWithController { private static void Postfix(eController controller, ref PlayerData __result) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Invalid comparison between Unknown and I4 if ((int)controller == 8 && RemoteMouse.Context != null) { __result = SystemPlayers.GetPlayer(RemoteMouse.ContextPlayer); } } } [HarmonyPatch(typeof(SystemInput), "GetMouseOver")] internal static class Patch_SystemInput_GetMouseOver { private static bool Prefix(Rect rect, int playerId, ref bool __result) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) if (!Online.IsHost) { return true; } NetGamepad netGamepad = RemoteMouse.ForPlayer(playerId); if (netGamepad == null) { return true; } __result = ((Rect)(ref rect)).Contains(RemoteMouse.MenuWorldPos(netGamepad)); return false; } } [HarmonyPatch(typeof(SystemInput), "GetMousePos")] internal static class Patch_SystemInput_GetMousePos { private static bool Prefix(ref Vector2 __result) { //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) if (RemoteMouse.Context == null) { return true; } __result = RemoteMouse.MenuWorldPos(RemoteMouse.Context); return false; } } [HarmonyPatch(typeof(SystemInput), "InputDown", new Type[] { typeof(eInput), typeof(eController) })] internal static class Patch_SystemInput_InputDownController { private static bool Prefix(eInput input, eController controllerId, ref bool __result) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Invalid comparison between Unknown and I4 //IL_000e: Unknown result type (might be due to invalid IL or missing references) if ((int)controllerId != 8 || RemoteMouse.Context == null) { return true; } __result = SystemInput.InputDown(input, (eController)RemoteMouse.Context.DeviceIndex); return false; } } [HarmonyPatch(typeof(SystemPlayers), "AssignPlayer", new Type[] { typeof(eController) })] internal static class Patch_SystemPlayers_AssignPlayerController { private static bool Prefix(SystemPlayers __instance, eController controllerId, ref int __result) { //IL_000e: 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_0038: 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) if (!Online.IsHost) { return true; } int num = Online.Host.ReservedPlayerFor(controllerId); if (num < 0) { return true; } PlayerData player = SystemPlayers.GetPlayer(num); if (player == null) { return true; } if (player.IsActiveNonTemporary && !player.IsBot && player.ControllerId != controllerId) { return true; } __instance.AssignPlayer(num, controllerId); __result = num; return false; } } [HarmonyPatch(typeof(SystemPlayers), "FindUnassignedPlayer")] internal static class Patch_SystemPlayers_FindUnassignedPlayer { private static bool Prefix(SystemPlayers __instance, ref int __result) { if (!Online.IsHost) { return true; } PlayerData[] players = __instance.m_players; if (players == null) { return true; } for (int i = 0; i < players.Length; i++) { PlayerData val = players[i]; if ((!val.IsActiveNonTemporary || val.IsBot) && !Online.Host.IsReserved(i)) { __result = i; return false; } } return true; } } [HarmonyPatch(typeof(SystemInput), "UpdateInternal")] internal static class Patch_SystemInput_UpdateInternal { private static void Postfix(SystemInput __instance) { //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) DevInput.Apply(__instance); if (LocalInput.Capturing) { LocalInput.AfterSystemInputUpdate(__instance); } else { if (!Overlay.WantsKeyboard) { return; } ControllerInput[] controllerInput = __instance.m_controllerInput; if (controllerInput == null) { return; } for (int i = 4; i <= 7 && i < controllerInput.Length; i++) { ControllerInput val = controllerInput[i]; if (val != null) { ((BitMask)(ref val.m_input)).Clear(); ((BitMask)(ref val.m_inputDown)).Clear(); ((BitMask)(ref val.m_inputUp)).Clear(); val.m_axes = Vector2.zero; } } } } } [HarmonyPatch(typeof(SystemInput), "UpdateMouseInput")] internal static class Patch_SystemInput_UpdateMouseInput { private static bool Prefix() { return !Overlay.Visible; } private static void Postfix(SystemInput __instance) { if (Online.IsClient) { if ((Object)(object)__instance.m_mouseCursor != (Object)null && __instance.m_mouseCursor.activeSelf) { __instance.m_mouseCursor.SetActive(false); } if ((Object)(object)__instance.m_mouseDirectionIndicator != (Object)null && ((Component)__instance.m_mouseDirectionIndicator).gameObject.activeSelf) { ((Component)__instance.m_mouseDirectionIndicator).gameObject.SetActive(false); } } } } [HarmonyPatch(typeof(SystemLevel), "OnApplicationFocus")] internal static class Patch_SystemLevel_OnApplicationFocus { private static bool Prefix() { return !Online.IsHost; } } [HarmonyPatch(typeof(SystemAudio), "OnApplicationFocus")] internal static class Patch_SystemAudio_OnApplicationFocus { private static bool Prefix(SystemAudio __instance) { if (!Online.IsHost) { return true; } __instance.m_hasFocus = true; return false; } } [HarmonyPatch(typeof(SystemMain), "LoadLevel", new Type[] { typeof(string) })] internal static class Patch_SystemMain_LoadLevelName { private static bool Prefix(string levelName) { if (!ClientStage.Active) { return true; } Plugin.Log.LogInfo((object)("[Client] blocked local scene load: " + levelName)); return false; } } [HarmonyPatch(typeof(SystemMain), "LoadLevel", new Type[] { typeof(int) })] internal static class Patch_SystemMain_LoadLevelIndex { private static bool Prefix() { return !ClientStage.Active; } } [HarmonyPatch(typeof(SceneManager), "LoadScene", new Type[] { typeof(string), typeof(LoadSceneMode) })] internal static class Patch_SceneManager_LoadSceneName { private static bool Prefix() { return !ClientStage.Active; } } [HarmonyPatch(typeof(SceneManager), "LoadScene", new Type[] { typeof(int), typeof(LoadSceneMode) })] internal static class Patch_SceneManager_LoadSceneIndex { private static bool Prefix() { return !ClientStage.Active; } } [HarmonyPatch(typeof(SceneManager), "LoadScene", new Type[] { typeof(string) })] internal static class Patch_SceneManager_LoadSceneName1 { private static bool Prefix() { return !ClientStage.Active; } } [HarmonyPatch(typeof(SceneManager), "LoadScene", new Type[] { typeof(int) })] internal static class Patch_SceneManager_LoadSceneIndex1 { private static bool Prefix() { return !ClientStage.Active; } } [HarmonyPatch(typeof(SystemSave), "SaveAllUsers")] internal static class Patch_SystemSave_SaveAllUsers { private static bool Prefix(ref Coroutine __result) { if (!ClientStage.Active) { return true; } __result = null; return false; } } [HarmonyPatch(typeof(SystemMenu), "StartAttractMode")] internal static class Patch_SystemMenu_StartAttractMode { private static bool Prefix() { if (!ClientStage.Active) { return !Online.IsHost; } return false; } } [HarmonyPatch(/*Could not decode attribute arguments.*/)] internal static class Patch_SystemAudio_PlayCue { private static bool Prefix(ref AudioSource __result) { if (!ClientStage.Active) { return true; } __result = null; return false; } } [HarmonyPatch(typeof(SystemAudio), "Play", new Type[] { typeof(AudioClip), typeof(int), typeof(Transform), typeof(bool), typeof(float), typeof(float), typeof(int) })] internal static class Patch_SystemAudio_PlayClip { private static bool Prefix(ref AudioSource __result) { if (!ClientStage.Active) { return true; } __result = null; return false; } } [BepInPlugin("crawl.online", "Crawl Online", "0.4.1")] public class Plugin : BaseUnityPlugin { public const string Guid = "crawl.online"; public const string Name = "Crawl Online"; public const string Version = "0.4.1"; internal static ManualLogSource Log; internal static Plugin Instance; internal static Harmony HarmonyInstance; internal static ConfigEntry<bool> CfgDevCommands; internal static ConfigEntry<bool> CfgRunInBackground; internal static ConfigEntry<KeyCode> CfgOverlayKey; internal static ConfigEntry<bool> CfgShowStatus; internal static ConfigEntry<bool> CfgShowCursors; internal static ConfigEntry<bool> CfgUnlockAll; internal static ConfigEntry<int> CfgUdpPort; internal static ConfigEntry<string> CfgLastAddress; internal static ConfigEntry<int> CfgMaxConnections; internal static ConfigEntry<int> CfgSendRate; internal static ConfigEntry<string> CfgLobbyType; internal static ConfigEntry<string> CfgLobbyName; internal static ConfigEntry<float> CfgClientVolume; internal static ConfigEntry<bool> CfgClientVibration; internal static ConfigEntry<int> CfgClientFpsLimit; internal static ConfigEntry<bool> CfgClientPrediction; private void Awake() { //IL_027e: Unknown result type (might be due to invalid IL or missing references) //IL_0288: Expected O, but got Unknown Instance = this; Log = ((BaseUnityPlugin)this).Logger; CfgOverlayKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("General", "MenuKey", (KeyCode)282, "Key that opens the Crawl Online menu"); CfgShowStatus = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ShowStatusLine", true, "Show a small status line while in an online session"); CfgShowCursors = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ShowPlayerCursors", true, "Show the mouse pointers of the other players (coloured like their characters)"); CfgUnlockAll = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "UnlockEverything", true, "Everything is available without unlocking it first (and the prologue is skipped). Your save keeps your real progress: set to false to get it back"); CfgRunInBackground = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "AlwaysRunInBackground", false, "Keep the game running when the window is not focused (always forced on during a session)"); CfgUdpPort = ((BaseUnityPlugin)this).Config.Bind<int>("Network", "UdpPort", 27015, "Port for direct (non-Steam) connections"); CfgLastAddress = ((BaseUnityPlugin)this).Config.Bind<string>("Network", "LastJoinAddress", "127.0.0.1", "Last address used for a direct connection"); CfgMaxConnections = ((BaseUnityPlugin)this).Config.Bind<int>("Network", "MaxConnections", 3, "Maximum remote connections when hosting (the game has 4 player slots; one connection may bring several controllers; extra connections just spectate)"); CfgSendRate = ((BaseUnityPlugin)this).Config.Bind<int>("Network", "SendRate", 60, "Host screen updates per second (30-120)"); CfgLobbyType = ((BaseUnityPlugin)this).Config.Bind<string>("Network", "LobbyType", "public", "Steam lobby visibility when hosting: public (listed in the server list), friends, invite"); CfgLobbyName = ((BaseUnityPlugin)this).Config.Bind<string>("Network", "LobbyName", "", "Name shown in the server list (empty = \"<your name>'s game\")"); CfgClientVolume = ((BaseUnityPlugin)this).Config.Bind<float>("Client", "Volume", 1f, "Volume multiplier for the host's sounds (your in-game volume settings also apply)"); CfgClientVibration = ((BaseUnityPlugin)this).Config.Bind<bool>("Client", "Vibration", true, "Forward controller rumble from the host"); CfgClientFpsLimit = ((BaseUnityPlugin)this).Config.Bind<int>("Client", "FpsLimit", 144, "Frame rate cap while connected as a client (0 = unlimited)"); CfgClientPrediction = ((BaseUnityPlugin)this).Config.Bind<bool>("Client", "Prediction", true, "Move your own character at once (client-side prediction) instead of waiting for the host"); ClientPrediction.Enabled = CfgClientPrediction.Value; CfgClientPrediction.SettingChanged += delegate { ClientPrediction.Enabled = CfgClientPrediction.Value; }; CfgDevCommands = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "DevCommands", false, "Poll BepInEx/crawlonline_cmd.txt for debug commands"); if (CfgRunInBackground.Value) { Application.runInBackground = true; } try { HarmonyInstance = new Harmony("crawl.online"); HarmonyInstance.PatchAll(typeof(Plugin).Assembly); } catch (Exception ex) { Log.LogError((object)("Harmony patching failed: " + ex)); } Runner.Create(); Boot.Init(); Log.LogInfo((object)"Crawl Online 0.4.1 loaded"); } } public class Runner : MonoBehaviour { public const int NoPauseLayer = 23; public static Runner Instance { get; private set; } public static event Action OnUpdate; public static event Action OnLateUpdate; public static event Action OnEndOfFrame; public static event Action OnGuiDraw; public static event Action OnQuit; internal static void Create() { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: 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_0026: Expected O, but got Unknown if (!((Object)(object)Instance != (Object)null)) { GameObject val = new GameObject("CrawlOnline") { layer = 23 }; Object.DontDestroyOnLoad((Object)val); Instance = val.AddComponent<Runner>(); } } private void Start() { ((MonoBehaviour)this).StartCoroutine(EndOfFrameLoop()); } private void Update() { Invoke(Runner.OnUpdate, "Update"); } private void LateUpdate() { Invoke(Runner.OnLateUpdate, "LateUpdate"); } private void OnGUI() { Invoke(Runner.OnGuiDraw, "OnGUI"); } private void OnApplicationQuit() { Invoke(Runner.OnQuit, "Quit"); } private IEnumerator EndOfFrameLoop() { WaitForEndOfFrame wait = new WaitForEndOfFrame(); while (true) { yield return wait; Invoke(Runner.OnEndOfFrame, "EndOfFrame"); } } private static void Invoke(Action a, string what) { if (a == null) { return; } Delegate[] invocationList = a.GetInvocationList(); for (int i = 0; i < invocationList.Length; i++) { Action action = (Action)invocationList[i]; try { action(); } catch (Exception ex) { Plugin.Log.LogError((object)(what + " handler failed: " + ex)); } } } } internal static class Unlocks { private static HashSet<string> s_platformLocked; public static bool Enabled { get { if (Plugin.CfgUnlockAll != null) { return Plugin.CfgUnlockAll.Value; } return false; } } public static bool IsPlatformLocked(string unlockName) { if (s_platformLocked == null) { HashSet<string> hashSet = new HashSet<string>(); try { UnlockAdditional[] platformLockedObjectsPC = Singleton<Constants>.Get.m_platformLockedObjectsPC; if (platformLockedObjectsPC != null) { UnlockAdditional[] array = platformLockedObjectsPC; foreach (UnlockAdditional val in array) { if (val != null) { hashSet.Add(SystemUnlocks.GetUnlockName(val.m_prefab, val.m_type)); } } } } catch { return false; } s_platformLocked = hashSet; } return s_platformLocked.Contains(unlockName); } } [HarmonyPatch(typeof(SystemUnlocks), "GetLocked", new Type[] { typeof(string) })] internal static class Patch_SystemUnlocks_GetLocked { private static bool Prefix(string unlockName, ref bool __result) { if (!Unlocks.Enabled) { return true; } __result = Unlocks.IsPlatformLocked(unlockName); return false; } } [HarmonyPatch(typeof(SystemTutorial), "GetShouldStartTutorial")] internal static class Patch_SystemTutorial_GetShouldStartTutorial { private static void Postfix(ref bool __result) { if (Unlocks.Enabled) { __result = false; } } } } namespace CrawlOnline.Util { [StructLayout(LayoutKind.Explicit)] internal struct FloatBits { [FieldOffset(0)] public float F; [FieldOffset(0)] public uint U; } public sealed class ByteWriter { private byte[] m_buf; private int m_pos; public byte[] Buffer => m_buf; public int Length => m_pos; public int Position { get { return m_pos; } set { Ensure(value); m_pos = value; } } public ByteWriter(int capacity = 1024) { m_buf = new byte[Math.Max(16, capacity)]; } public void Reset() { m_pos = 0; } private void Ensure(int needed) { if (needed > m_buf.Length) { int num; for (num = m_buf.Length * 2; num < needed; num *= 2) { } byte[] array = new byte[num]; System.Buffer.BlockCopy(m_buf, 0, array, 0, m_pos); m_buf = array; } } public void U8(int v) { Ensure(m_pos + 1); m_buf[m_pos++] = (byte)v; } public void Bool(bool v) { U8(v ? 1 : 0); } public void U16(int v) { Ensure(m_pos + 2); m_buf[m_pos++] = (byte)v; m_buf[m_pos++] = (byte)(v >> 8); } public void U32(uint v) { Ensure(m_pos + 4); m_buf[m_pos++] = (byte)v; m_buf[m_pos++] = (byte)(v >> 8); m_buf[m_pos++] = (byte)(v >> 16); m_buf[m_pos++] = (byte)(v >> 24); } public void I32(int v) { U32((uint)v); } public void U64(ulong v) { U32((uint)v); U32((uint)(v >> 32)); } public void F32(float f) { FloatBits floatBits = new FloatBits { F = f }; U32(floatBits.U); } public void VarU(uint v) { Ensure(m_pos + 5); while (v >= 128) { m_buf[m_pos++] = (byte)(v | 0x80); v >>= 7; } m_buf[m_pos++] = (byte)v; } public void VarI(int v) { VarU((uint)((v << 1) ^ (v >> 31))); } public void Str(string s) { if (s == null) { VarU(0u); return; } int byteCount = Encoding.UTF8.GetByteCount(s); VarU((uint)(byteCount + 1)); Ensure(m_pos + byteCount); Encoding.UTF8.GetBytes(s, 0, s.Length, m_buf, m_pos); m_pos += byteCount; } public void Bytes(byte[] data, int offset, int count) { Ensure(m_pos + count); System.Buffer.BlockCopy(data, offset, m_buf, m_pos, count); m_pos += count; } public void Vec2(Vector2 v) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) F32(v.x); F32(v.y); } public void Vec3(Vector3 v) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) F32(v.x); F32(v.y); F32(v.z); } public void Vec4(Vector4 v) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0019: 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) F32(v.x); F32(v.y); F32(v.z); F32(v.w); } public void Quat(Quaternion q) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0019: 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) F32(q.x); F32(q.y); F32(q.z); F32(q.w); } public void Col(Color c) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0019: 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) F32(c.r); F32(c.g); F32(c.b); F32(c.a); } public void Col32(Color32 c) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) Ensure(m_pos + 4); m_buf[m_pos++] = c.r; m_buf[m_pos++] = c.g; m_buf[m_pos++] = c.b; m_buf[m_pos++] = c.a; } public void Rect(Rect r) { F32(((Rect)(ref r)).x); F32(((Rect)(ref r)).y); F32(((Rect)(ref r)).width); F32(((Rect)(ref r)).height); } public byte[] ToArray() { byte[] array = new byte[m_pos]; System.Buffer.BlockCopy(m_buf, 0, array, 0, m_pos); return array; } } public sealed class ByteReader { private byte[] m_buf; private int m_pos; private int m_end; public int Remaining => m_end - m_pos; public int Position => m_pos; public byte[] Buffer => m_buf; public ByteReader() { } public ByteReader(byte[] buf, int offset, int count) { Set(buf, offset, count); } public void Set(byte[] buf, int offset, int count) { m_buf = buf; m_pos = offset; m_end = offset + count; } private void Need(int n) { if (m_pos + n > m_end) { throw new IndexOutOfRangeException("ByteReader underflow"); } } public int U8() { Need(1); return m_buf[m_pos++]; } public bool Bool() { return U8() != 0; } public int U16() { Need(2); int result = m_buf[m_pos] | (m_buf[m_pos + 1] << 8); m_pos += 2; return result; } public uint U32() { Need(4); int result = m_buf[m_pos] | (m_buf[m_pos + 1] << 8) | (m_buf[m_pos + 2] << 16) | (m_buf[m_pos + 3] << 24); m_pos += 4; return (uint)result; } public int I32() { return (int)U32(); } public ulong U64() { long num = U32(); ulong num2 = U32(); return (ulong)num | (num2 << 32); } public float F32() { FloatBits floatBits = new FloatBits { U = U32() }; return floatBits.F; } public uint VarU() { uint num = 0u; int num2 = 0; while (true) { int num3 = U8(); num |= (uint)((num3 & 0x7F) << num2); if ((num3 & 0x80) == 0) { break; } num2 += 7; if (num2 > 35) { throw new FormatException("VarU too long"); } } return num; } public int VarI() { uint num = VarU(); return (int)((num >> 1) ^ (0 - (num & 1))); } public string Str() { uint num = VarU(); if (num == 0) { return null; } int num2 = (int)(num - 1); Need(num2); string result = Encoding.UTF8.GetString(m_buf, m_pos, num2); m_pos += num2; return result; } public void Bytes(byte[] dst, int offset, int count) { Need(count); System.Buffer.BlockCopy(m_buf, m_pos, dst, offset, count); m_pos += count; } public void Skip(int n) { Need(n); m_pos += n; } public Vector2 Vec2() { //IL_000c: Unknown result type (might be due to invalid IL or missing references) return new Vector2(F32(), F32()); } public Vector3 Vec3() { //IL_0012: Unknown result type (might be due to invalid IL or missing references) return new Vector3(F32(), F32(), F32()); } public Vector4 Vec4() { //IL_0018: Unknown result type (might be due to invalid IL or missing references) return new Vector4(F32(), F32(), F32(), F32()); } public Quaternion Quat() { //IL_0018: Unknown result type (might be due to invalid IL or missing references) return new Quaternion(F32(), F32(), F32(), F32()); } public Color Col() { //IL_0018: Unknown result type (might be due to invalid IL or missing references) return new Color(F32(), F32(), F32(), F32()); } public Color32 Col32() { //IL_0041: Unknown result type (might be due to invalid IL or missing references) Need(4); Color32 result = new Color32(m_buf[m_pos], m_buf[m_pos + 1], m_buf[m_pos + 2], m_buf[m_pos + 3]); m_pos += 4; return result; } public Rect Rect() { //IL_0018: Unknown result type (might be due to invalid IL or missing references) return new Rect(F32(), F32(), F32(), F32()); } } public struct Hash64 { private const ulong Offset = 14695981039346656037uL; private const ulong Prime = 1099511628211uL; private ulong m_h; private bool m_init; public ulong Value { get { if (!m_init) { return 14695981039346656037uL; } return m_h; } } public void Add(uint v) { if (!m_init) { m_h = 14695981039346656037uL; m_init = true; } for (int i = 0; i < 4; i++) { m_h ^= (byte)(v >> i * 8); m_h *= 1099511628211uL; } } public void Add(int v) { Add((uint)v); } public void Add(float f) { FloatBits floatBits = new FloatBits { F = f }; Add(floatBits.U); } } } namespace CrawlOnline.UI { public static class OnlineMenu { private const string MsgOnline = "MsgCrawlOnline"; private static MenuTextMenu s_mainMenu; private static MenuTextMenuItem s_item; private static string s_itemText; private static GameObject s_prompt; private static GameObject s_lastPrompt; private static GUIText s_promptText; private static string s_promptBody; private static TextMesh s_panel; private static string s_panelText; private static float s_nextRefresh; private static float s_selectAt; private const int PageSize = 4; private static GameObject s_searchPrompt; private static int s_searchGen; private static int s_page; public static void Init() { Runner.OnUpdate += Update; } public static void TryAttach(MenuTextMenu menu) { //IL_0057: 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_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Expected O, but got Unknown GameObject owner = menu.m_owner; if ((Object)(object)owner == (Object)null) { return; } MenuMain component = owner.GetComponent<MenuMain>(); if (!((Object)(object)component == (Object)null) && !((Object)(object)component.m_menuMain != (Object)(object)menu)) { if ((Object)(object)owner.GetComponent<OnlineMenuReceiver>() == (Object)null) { owner.AddComponent<OnlineMenuReceiver>(); } s_mainMenu = menu; s_itemText = ItemText(); s_item = menu.InsertItem(1, new MenuTextMenuItemData { m_text = s_itemText, m_enabled = true, m_visible = true, m_message = "MsgCrawlOnline" }); Plugin.Log.LogInfo((object)"[UI] ONLINE entry added to the main menu"); } } private static string ItemText() { if (!Online.IsHost) { return "ONLINE"; } return "ONLINE LOBBY"; } public static void OnOnlineSelected() { if (Online.IsHost) { ShowLobby(); } else { ShowPlayOnline(); } } private static void ShowPlayOnline() { bool steamReady = SteamLobby.SteamReady; string body = (steamReady ? "Find a game or host your own.\nHost is P1, others join as P2-P4." : "Steam is not available. Use the F1 menu for a direct (IP) connection."); List<KeyValuePair<string, Action>> list = new List<KeyValuePair<string, Action>>(); if (steamReady) { list.Add(new KeyValuePair<string, Action>("Server list", delegate { ShowServerList(refresh: true); })); list.Add(new KeyValuePair<string, Action>("Host lobby", ShowHostType)); list.Add(new KeyValuePair<string, Action>("Join a friend", delegate { try { SteamFriends.ActivateGameOverlay("friends"); } catch { } })); } list.Add(new KeyValuePair<string, Action>("Back", null)); ShowPrompt("Play online", body, list, liveLobby: false); } private static void ShowHostType() { Action<ELobbyType> host = delegate(ELobbyType t) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Invalid comparison between Unknown and I4 if (Online.StartHostSteam(t)) { if ((int)t != 2) { Online.InviteFriends(); } ContinueToCharacterSelect(); } else { ShowError(Online.LastError); } }; List<KeyValuePair<string, Action>> buttons = new List<KeyValuePair<string, Action>> { new KeyValuePair<string, Action>("Public", delegate { host((ELobbyType)2); }), new KeyValuePair<string, Action>("Friends only", delegate { host((ELobbyType)1); }), new KeyValuePair<string, Action>("Invite only", delegate { host((ELobbyType)0); }), new KeyValuePair<string, Action>("Back", ShowPlayOnline) }; ShowPrompt("Host lobby", "Who can join \"" + Short(Online.LobbyName(), 24) + "\"?", buttons, liveLobby: false); } public static void ContinueToCharacterSelect() { s_selectAt = Time.realtimeSinceStartup + 0.3f; } private static void TickCharacterSelect() { if (s_selectAt <= 0f || Time.realtimeSinceStartup < s_selectAt) { return; } if (!Online.IsHost) { s_selectAt = 0f; return; } Object obj = Object.FindObjectOfType(typeof(MenuPrompt)); MenuPrompt val = (MenuPrompt)(object)((obj is MenuPrompt) ? obj : null); if ((Object)(object)val != (Object)null && ((Component)val).gameObject.activeInHierarchy && Time.realtimeSinceStartup - s_selectAt < 3f) { return; } s_selectAt = 0f; Object obj2 = Object.FindObjectOfType(typeof(MenuMain)); MenuMain val2 = (MenuMain)(object)((obj2 is MenuMain) ? obj2 : null); if (!((Object)(object)val2 == (Object)null) && !((Object)(object)val2.m_states == (Object)null)) { string stateName = val2.m_states.GetStateName(); if (!(stateName != "MenuLoop") || !(stateName != "MenuIntro")) { Plugin.Log.LogInfo((object)"[UI] lobby created: continuing to character select"); val2.m_states.SetState("Outro"); } } } private static void ShowServerList(bool refresh) { if (refresh || LobbyBrowser.Generation == 0) { s_page = 0; LobbyBrowser.Refresh(); if (LobbyBrowser.Error != null) { ShowError(LobbyBrowser.Error); return; } s_searchGen = LobbyBrowser.Generation; List<KeyValuePair<string, Action>> buttons = new List<KeyValuePair<string, Action>> { new KeyValuePair<string, Action>("Back", ShowPlayOnline) }; ShowPrompt("Server list", "Searching for games...", buttons, liveLobby: false); s_searchPrompt = s_lastPrompt; } else { ShowServerListResults(); } } private static string Short(string s, int n) { if (string.IsNullOrEmpty(s)) { return "?"; } if (s.Length > n) { return s.Substring(0, n - 1) + "."; } return s; } private static void ShowServerListResults() { List<LobbyEntry> results = LobbyBrowser.Results; int pages = Mathf.Max(1, (results.Count + 4 - 1) / 4); s_page = Mathf.Clamp(s_page, 0, pages - 1); StringBuilder stringBuilder = new StringBuilder(); List<KeyValuePair<string, Action>> list = new List<KeyValuePair<string, Action>>(); if (results.Count == 0) { stringBuilder.Append(LobbyBrowser.Error ?? "No games found."); } else { stringBuilder.Append(results.Count + ((results.Count == 1) ? " game" : " games") + ((pages > 1) ? (" - page " + (s_page + 1) + "/" + pages) : "")); if (LobbyBrowser.Results.Exists((LobbyEntry x) => x.Friend)) { stringBuilder.Append("\n* = friend"); } for (int num = s_page * 4; num < Mathf.Min(results.Count, (s_page + 1) * 4); num++) { LobbyEntry lobbyEntry = results[num]; string text = ((!lobbyEntry.Compatible) ? " OLD" : (lobbyEntry.Full ? " FULL" : (" " + lobbyEntry.Players + "/" + lobbyEntry.Max))); LobbyEntry entry = lobbyEntry; list.Add(new KeyValuePair<string, Action>((lobbyEntry.Friend ? "*" : "") + Short(lobbyEntry.Name, 13) + text, delegate { JoinEntry(entry); })); } } if (pages > 1) { list.Add(new KeyValuePair<string, Action>("Next page", delegate { s_page = (s_page + 1) % pages; ShowServerListResults(); })); } list.Add(new KeyValuePair<string, Action>("Refresh", delegate { ShowServerList(refresh: true); })); list.Add(new KeyValuePair<string, Action>("Back", ShowPlayOnline)); ShowPrompt("Server list", stringBuilder.ToString(), list, liveLobby: false); } private static void JoinEntry(LobbyEntry e) { if (!e.Compatible) { ShowError("This game runs Crawl Online " + e.Version + ", you have 0.4.1. Everybody needs the same version."); } else if (e.Full) { ShowError("This lobby is full."); } else { Online.JoinSteamLobby(e.Id); } } private static void ShowLobby() { //IL_004d: Unknown result type (might be due to invalid IL or missing references) List<KeyValuePair<string, Action>> buttons = new List<KeyValuePair<string, Action>> { new KeyValuePair<string, Action>("Invite friends", delegate { Online.InviteFriends(); }), new KeyValuePair<string, Action>("Visibility: " + ((Online.Lobby != null) ? SteamLobby.TypeName(Online.Lobby.Type) : "-"), CycleVisibility), new KeyValuePair<string, Action>("Close lobby", ConfirmCloseLobby), new KeyValuePair<string, Action>("Back", null) }; ShowPrompt("Online lobby", LobbyText(rich: false), buttons, liveLobby: true); } private static void CycleVisibility() { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Invalid comparison between Unknown and I4 //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Invalid comparison between Unknown and I4 //IL_0022: 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_002f: Unknown result type (might be due to invalid IL or missing references) SteamLobby lobby = Online.Lobby; if (lobby != null) { ELobbyType val = (ELobbyType)(((int)lobby.Type == 2) ? 1 : (((int)lobby.Type != 1) ? 2 : 0)); lobby.SetType(val); Plugin.CfgLobbyType.Value = Online.LobbyTypeKey(val); } ShowLobby(); } private static void ConfirmCloseLobby() { List<KeyValuePair<string, Action>> buttons = new List<KeyValuePair<string, Action>> { new KeyValuePair<string, Action>("Close lobby", delegate { Online.Stop("the host closed the lobby"); }), new KeyValuePair<string, Action>("Cancel", ShowLobby) }; ShowPrompt("Close the lobby?", "Everybody will be disconnected.", buttons, liveLobby: false); } public static void ShowError(string message) { if (!string.IsNullOrEmpty(message)) { List<KeyValuePair<string, Action>> buttons = new List<KeyValuePair<string, Action>> { new KeyValuePair<string, Action>("OK", null) }; ShowPrompt("Online", message, buttons, liveLobby: false); } } private static void ShowPrompt(string title, string body, List<KeyValuePair<string, Action>> buttons, bool liveLobby) { //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_0110: 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_012e: 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_0157: Expected O, but got Unknown //IL_0194: Unknown result type (might be due to invalid IL or missing references) //IL_01a0: Unknown result type (might be due to invalid IL or missing references) //IL_01b2: Unknown result type (might be due to invalid IL or missing references) SystemMenu get = Singleton<SystemMenu>.Get; if ((Object)(object)get == (Object)null || buttons.Count == 0) { return; } KeyValuePair<string, Action> keyValuePair = buttons[0]; KeyValuePair<string, Action> keyValuePair2 = ((buttons.Count > 1) ? buttons[1] : default(KeyValuePair<string, Action>)); GameObject val = (s_lastPrompt = get.ShowPrompt(title, body, keyValuePair.Key, keyValuePair.Value, (buttons.Count > 1) ? keyValuePair2.Key : null, keyValuePair2.Value, -1, (MenuPrompt)null)); if ((Object)(object)val == (Object)null) { return; } MenuPrompt component = val.GetComponent<MenuPrompt>(); if ((Object)(object)component != (Object)null && buttons.Count > 2) { OnlinePromptReceiver onlinePromptReceiver = (((Object)(object)component.m_menu.m_owner != (Object)null) ? component.m_menu.m_owner : val).AddComponent<OnlinePromptReceiver>(); onlinePromptReceiver.Prompt = component; float heightApprox = component.m_menu.GetHeightApprox(); for (int i = 2; i < buttons.Count; i++) { onlinePromptReceiver.Actions.Add(buttons[i].Value); component.m_menu.AddItem(new MenuTextMenuItemData { m_text = buttons[i].Key, m_enabled = true, m_visible = true, m_message = "OnOnlineButton" + (i - 2) }); } float num = 0.5f * (component.m_menu.GetHeightApprox() - heightApprox); Transform transform = component.m_background.transform; transform.localScale = new Vector3(transform.localScale.x, transform.localScale.y + num, 1f); } if ((Object)(object)component != (Object)null) { FitOnScreen(component); } if (liveLobby && (Object)(object)component != (Object)null) { s_prompt = val; s_promptText = component.m_textText; s_promptBody = body; } else { s_prompt = null; } } private static void FitOnScreen(MenuPrompt prompt) { //IL_0047: 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_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: 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_0100: 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_0146: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Unknown result type (might be due to invalid IL or missing references) try { Camera camera = SystemMenu.GetCamera(); List<MenuTextMenuItem> items = prompt.m_menu.m_items; if ((Object)(object)camera == (Object)null || items == null || items.Count == 0) { return; } float num = 0.5f * prompt.m_menu.m_itemSpacing * ((Component)prompt.m_menu).transform.lossyScale.y; float num2 = float.MaxValue; foreach (MenuTextMenuItem item in items) { if ((Object)(object)item != (Object)null) { num2 = Mathf.Min(num2, ((Component)item).transform.position.y - num); } } float y = camera.ViewportToWorldPoint(new Vector3(0f, 0.03f, 0f)).y; if (!(num2 >= y)) { float y2 = camera.ViewportToWorldPoint(new Vector3(0f, 0.99f, 0f)).y; float num3 = ((Component)prompt.m_textTitle).transform.position.y + num * 2f; float num4 = Mathf.Min(y - num2, Mathf.Max(0f, y2 - num3)); Transform transform = ((Component)prompt).transform; transform.position += new Vector3(0f, num4, 0f); } } catch (Exception ex) { Plugin.Log.LogWarning((object)("[UI] prompt fit failed: " + ex.Message)); } } private static string LobbyText(bool rich) { //IL_011e: 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_012c: 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_0139: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) StringBuilder stringBuilder = new StringBuilder(); HostSession host = Online.Host; int num = Mathf.Min(4, SystemPlayers.GetMaxPlayers()); for (int i = 0; i < num; i++) { string text = null; string text2 = ""; if (i == 0) { text = ((host != null) ? host.HostName : "you"); text2 = (rich ? "" : " (host)"); } else if (host != null) { HostSession.Client[] clients = host.Clients; foreach (HostSession.Client client in clients) { if (client != null && client.PlayerSlot == i) { text = client.Name; text2 = " " + Mathf.RoundToInt(client.Rtt * 1000f) + "ms"; } } } string text3 = "P" + (i + 1) + " " + (text ?? "waiting...") + ((text != null) ? text2 : ""); if (rich) { PlayerData player = SystemPlayers.GetPlayer(i); Color val = ((player != null && player.Setup != null) ? player.Setup.m_colour : Color.white); if (text == null) { ((Color)(ref val))..ctor(val.r, val.g, val.b, 0.45f); } text3 = "<color=#" + ColorToHex(val) + ">" + text3 + "</color>"; } stringBuilder.Append(text3); if (i < num - 1) { stringBuilder.Append('\n'); } } return stringBuilder.ToString(); } private static string ColorToHex(Color c) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) Color32 val = Color32.op_Implicit(c); return val.r.ToString("x2") + val.g.ToString("x2") + val.b.ToString("x2") + val.a.ToString("x2"); } private static void Update() { TickCharacterSelect(); if (Time.realtimeSinceStartup < s_nextRefresh) { return; } s_nextRefresh = Time.realtimeSinceStartup + 0.25f; if ((Object)(object)s_item != (Object)null) { string text = ItemText(); if (text != s_itemText) { s_itemText = text; s_item.SetText(text); } } else { s_mainMenu = null; } if ((Object)(object)s_searchPrompt != (Object)null && !LobbyBrowser.Searching && LobbyBrowser.Generation != s_searchGen) { MenuPrompt component = s_searchPrompt.GetComponent<MenuPrompt>(); s_searchPrompt = null; if ((Object)(object)component != (Object)null) { component.Dismiss(); } ShowServerListResults(); } if ((Object)(object)s_prompt != (Object)null && (Object)(object)s_promptText != (Object)null) { string text2 = LobbyText(rich: false); if (text2 != s_promptBody) { s_promptBody = text2; s_promptText.SetText(text2); } } UpdatePanel(); } private static void UpdatePanel() { //IL_015d: Unknown result type (might be due to invalid IL or missing references) //IL_0179: 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_0183: Unknown result type (might be due to invalid IL or missing references) //IL_018f: Unknown result type (might be due to invalid IL or missing references) //IL_0196: Unknown result type (might be due to invalid IL or missing references) //IL_019f: Unknown result type (might be due to invalid IL or missing references) if (!Online.IsHost || !((Object)(object)s_item != (Object)null) || !((Object)(object)s_mainMenu != (Object)null) || !((Component)s_mainMenu).gameObject.activeInHierarchy) { if ((Object)(object)s_panel != (Object)null) { ((Component)s_panel).gameObject.SetActive(false); } return; } if ((Object)(object)s_panel == (Object)null) { Object obj = Object.FindObjectOfType(typeof(MenuBuildNumber)); MenuBuildNumber val = (MenuBuildNumber)(object)((obj is MenuBuildNumber) ? obj : null); TextMesh val2 = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponentInChildren<TextMesh>() : null); if ((Object)(object)val2 == (Object)null) { return; } GameObject val3 = Object.Instantiate<GameObject>(((Component)val2).gameObject); MonoBehaviour[] componentsInChildren = val3.GetComponentsInChildren<MonoBehaviour>(true); for (int i = 0; i < componentsInChildren.Length; i++) { Object.DestroyImmediate((Object)(object)componentsInChildren[i]); } ((Object)val3).name = "Online Lobby Panel"; val3.transform.parent = ((Component)s_mainMenu).transform.root; s_panel = val3.GetComponentInChildren<TextMesh>(); s_panel.richText = true; s_panel.anchor = (TextAnchor)2; s_panel.alignment = (TextAlignment)2; s_panelText = null; } if (!((Component)s_panel).gameObject.activeSelf) { ((Component)s_panel).gameObject.SetActive(true); } Camera cameraMenu = SystemMain.GetCameraMenu(); if ((Object)(object)cameraMenu != (Object)null) { float z = ((Component)s_panel).transform.position.z; Vector3 val4 = cameraMenu.ViewportToWorldPoint(new Vector3(0.98f, 0.97f, 0f)); ((Component)s_panel).transform.position = new Vector3(val4.x, val4.y, z); } string text = "<color=#e8d8b0ff>ONLINE LOBBY</color>\n" + LobbyText(rich: true); if (text != s_panelText) { s_panelText = text; s_panel.text = text; } } } public class OnlineMenuReceiver : MonoBehaviour { private void MsgCrawlOnline() { OnlineMenu.OnOnlineSelected(); } } public class OnlinePromptReceiver : MonoBehaviour { public MenuPrompt Prompt; public readonly List<Action> Actions = new List<Action>(); private void Invoke(int i) { Action action = ((i < Actions.Count) ? Actions[i] : null); if ((Object)(object)Prompt != (Object)null) { Prompt.Dismiss(); } action?.Invoke(); } private void OnOnlineButton0() { Invoke(0); } private void OnOnlineButton1() { Invoke(1); } private void OnOnlineButton2() { Invoke(2); } private void OnOnlineButton3() { Invoke(3); } private void OnOnlineButton4() { Invoke(4); } private void OnOnlineButton5() { Invoke(5); } private void OnOnlineButton6() { Invoke(6); } private void OnOnlineButton7() { Invoke(7); } private void OnOnlineButton8() { Invoke(8); } private void OnOnlineButton9() { Invoke(9); } } public static class Overlay { [CompilerGenerated] private static class <>O { public static Action <0>__Update; public static Action <1>__Draw; public static WindowFunction <2>__DrawWindow; } private static Rect s_window = new Rect(20f, 20f, 560f, 10f); private static Vector2 s_listScroll; private static string s_lobbyName; private static string s_address; private static string s_port; private static string s_hostPort; private static GUIStyle s_title; private static GUIStyle s_error; private static GUIStyle s_small; private static GUIStyle s_status; private static bool s_stylesReady; public static bool Visible { get; private set; } public static bool WantsKeyboard { get { if (Visible) { return GUIUtility.keyboardControl != 0; } return false; } } public static void Init() { s_address = Plugin.CfgLastAddress.Value; s_lobbyName = Plugin.CfgLobbyName.Value; s_port = Plugin.CfgUdpPort.Value.ToString(); s_hostPort = Plugin.CfgUdpPort.Value.ToString(); Runner.OnUpdate += Update; Runner.OnGuiDraw += Draw; } public static void Toggle() { Visible = !Visible; if (Visible) { Cursor.visible = true; Cursor.lockState = (CursorLockMode)0; } else { GUIUtility.keyboardControl = 0; Cursor.visible = false; } } private static void Update() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) if (Input.GetKeyDown(Plugin.CfgOverlayKey.Value)) { Toggle(); } LocalInput.Suppress = Visible; if (Visible) { if ((int)Cursor.lockState != 0) { Cursor.lockState = (CursorLockMode)0; } if (!Cursor.visible) { Cursor.visible = true; } } } private static void EnsureStyles() { //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_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Expected O, but got Unknown //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Expected O, but got Unknown //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_0079: 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_0086: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Expected O, but got Unknown //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: 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_00b5: Expected O, but got Unknown //IL_00ce: Unknown result type (might be due to invalid IL or missing references) if (!s_stylesReady) { s_stylesReady = true; s_title = new GUIStyle(GUI.skin.label) { fontSize = 18, fontStyle = (FontStyle)1 }; s_error = new GUIStyle(GUI.skin.label) { wordWrap = true }; s_error.normal.textColor = new Color(1f, 0.45f, 0.4f); s_small = new GUIStyle(GUI.skin.label) { fontSize = 11, wordWrap = true }; s_status = new GUIStyle(GUI.skin.label) { fontSize = 13, fontStyle = (FontStyle)1 }; s_status.normal.textColor = new Color(1f, 0.9f, 0.6f); } } private static void Draw() { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0033: 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_0090: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: 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_00e7: 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_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Expected O, but got Unknown //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) EnsureStyles(); float num = Mathf.Max(1f, (float)Screen.height / 900f); Matrix4x4 matrix = GUI.matrix; GUI.matrix = Matrix4x4.TRS(Vector3.zero, Quaternion.identity, new Vector3(num, num, 1f)); if (!Visible) { if (Plugin.CfgShowStatus.Value && Online.InSession) { GUI.Label(new Rect(8f, 4f, 900f, 24f), StatusLine(), s_status); } GUI.matrix = matrix; return; } Rect val = s_window; object obj = <>O.<2>__DrawWindow; if (obj == null) { WindowFunction val2 = DrawWindow; <>O.<2>__DrawWindow = val2; obj = (object)val2; } s_window = GUILayout.Window(3082, val, (WindowFunction)obj, "Crawl Online 0.4.1 [" + ((object)Plugin.CfgOverlayKey.Value/*cast due to .constrained prefix*/).ToString() + "]", (GUILayoutOption[])(object)new GUILayoutOption[0]); GUI.matrix = matrix; } private static string StatusLine() { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0082: 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) if (Online.IsHost) { return "ONLINE HOST | " + Online.Host.ClientCount + " connected | " + ((object)Plugin.CfgOverlayKey.Value/*cast due to .constrained prefix*/).ToString() + " - menu"; } if (Online.IsClient) { ClientSession client = Online.Client; if (client.State == ClientSession.States.Connecting) { return "Connecting... | " + ((object)Plugin.CfgOverlayKey.Value/*cast due to .constrained prefix*/).ToString() + " - menu"; } return "ONLINE | host: " + client.HostName + " | " + Mathf.RoundToInt(client.Rtt * 1000f) + " ms" + (client.Link.Relay ? " (Steam relay)" : "") + " | " + ((object)Plugin.CfgOverlayKey.Value/*cast due to .constrained prefix*/).ToString() + " - menu"; } return ""; } private static void DrawWindow(int id) { if (Online.IsHost) { DrawHost(); } else if (Online.IsClient) { DrawClient(); } else { DrawIdle(); } if (!Online.IsClient) { bool flag = GUILayout.Toggle(Plugin.CfgUnlockAll.Value, " Unlock everything (weapons, monsters, gods...; your save is not changed)", (GUILayoutOption[])(object)new GUILayoutOption[0]); if (flag != Plugin.CfgUnlockAll.Value) { Plugin.CfgUnlockAll.Value = flag; } } if (!string.IsNullOrEmpty(Online.Status)) { GUILayout.Label(Online.Status, s_small, (GUILayoutOption[])(object)new GUILayoutOption[0]); } GUILayout.Label("Online-Fix co-op mods series · online-fix.me", s_small, (GUILayoutOption[])(object)new GUILayoutOption[0]); if (!string.IsNullOrEmpty(Online.LastError)) { GUILayout.Label(Online.LastError, s_error, (GUILayoutOption[])(object)new GUILayoutOption[0]); } GUILayout.Space(4f); if (GUILayout.Button("Close menu", (GUILayoutOption[])(object)new GUILayoutOption[0])) { Toggle(); } GUI.DragWindow(); } private static void DrawIdle() { //IL_00e4: 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_0282: Unknown result type (might be due to invalid IL or missing references) //IL_029a: Unknown result type (might be due to invalid IL or missing references) //IL_029f: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_01a0: Unknown result type (might be due to invalid IL or missing references) //IL_01a5: 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_01b0: Unknown result type (might be due to invalid IL or missing references) //IL_01b3: Invalid comparison between Unknown and I4 GUILayout.Label("Play online", s_title, (GUILayoutOption[])(object)new GUILayoutOption[0]); GUILayout.Label("The host runs the game; everyone else sees the host's screen and plays with their own controllers/keyboard.", s_small, (GUILayoutOption[])(object)new GUILayoutOption[0]); GUILayout.Space(6f); GUILayout.Label("Host a Steam lobby", s_status, (GUILayoutOption[])(object)new GUILayoutOption[0]); GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]); GUILayout.Label("Lobby name", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(90f) }); s_lobbyName = GUILayout.TextField(s_lobbyName ?? "", 32, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(220f) }); GUILayout.Label(string.IsNullOrEmpty(s_lobbyName) ? ("(" + Online.LobbyName() + ")") : "", s_small, (GUILayoutOption[])(object)new GUILayoutOption[0]); GUILayout.EndHorizontal(); ELobbyType val = Online.ParseLobbyType(Plugin.CfgLobbyType.Value); GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]); ELobbyType[] array = (ELobbyType[])(object)new ELobbyType[3] { (ELobbyType)2, (ELobbyType)1, default(ELobbyType) }; foreach (ELobbyType val2 in array) { if (GUILayout.Toggle(val == val2, SteamLobby.TypeName(val2), GUI.skin.button, (GUILayoutOption[])(object)new GUILayoutOption[0]) && val != val2) { Plugin.CfgLobbyType.Value = Online.LobbyTypeKey(val2); } } GUILayout.EndHorizontal(); if (GUILayout.Button("Host lobby", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(32f) })) { Online.LastError = ""; Plugin.CfgLobbyName.Value = (s_lobbyName ?? "").Trim(); ELobbyType val3 = Online.ParseLobbyType(Plugin.CfgLobbyType.Value); if (Online.StartHostSteam(val3)) { if ((int)val3 != 2) { Online.InviteFriends(); } OnlineMenu.ContinueToCharacterSelect(); } } GUILayout.Space(8f); GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]); GUILayout.Label("Server list", s_status, (GUILayoutOption[])(object)new GUILayoutOption[0]); if (GUILayout.Button(LobbyBrowser.Searching ? "Searching..." : "Refresh", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(110f) })) { LobbyBrowser.Refresh(); } if (GUILayout.Button("Join a friend (Steam)", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(160f) })) { try { SteamFriends.ActivateGameOverlay("friends"); } catch { } } GUILayout.EndHorizontal(); if (LobbyBrowser.Generation == 0 && !LobbyBrowser.Searching) { LobbyBrowser.Refresh(); } if (!string.IsNullOrEmpty(LobbyBrowser.Error)) { GUILayout.Label(LobbyBrowser.Error, s_error, (GUILayoutOption[])(object)new GUILayoutOption[0]); } s_listScroll = GUILayout.BeginScrollView(s_listScroll, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(170f) }); if (LobbyBrowser.Results.Count == 0) { GUILayout.Label(LobbyBrowser.Searching ? "Searching..." : "No games found. Host one or ask a friend to invite you.", s_small, (GUILayoutOption[])(object)new GUILayoutOption[0]); } foreach (LobbyEntry result3 in LobbyBrowser.Results) { GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]); GUILayout.Label((result3.Friend ? "[friend] " : "") + result3.Name + " " + result3.Players + "/" + result3.Max + " " + result3.State + (result3.Compatible ? "" : (" v" + result3.Version + " (incompatible)")) + ((result3.Full && result3.Compatible) ? " full" : ""), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(400f) }); GUI.enabled = result3.CanJoin; if (GUILayout.Button("Join", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(70f) })) { Online.JoinSteamLobby(result3.Id); } GUI.enabled = true; GUILayout.EndHorizontal(); } GUILayout.EndScrollView(); GUILayout.Space(8f); GUILayout.Label("Direct connection (LAN / port forwarding)", (GUILayoutOption[])(object)new GUILayoutOption[0]); GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]); GUILayout.Label("Host on UDP port", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(130f) }); s_hostPort = GUILayout.TextField(s_hostPort, 6, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(70f) }); if (GUILayout.Button("Host (UDP)", (GUILayoutOption[])(object)new GUILayoutOption[0])) { Online.LastError = ""; if (int.TryParse(s_hostPort, out var result) && result > 0 && result < 65536) { Plugin.CfgUdpPort.Value = result; Online.StartHostUdp(result); } else { Online.LastError = "Invalid port"; } } GUILayout.EndHorizontal(); GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]); GUILayout.Label("Join address", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(130f) }); s_address = GUILayout.TextField(s_address, 64, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(170f) }); GUILayout.Label(":", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(8f) }); s_port = GUILayout.TextField(s_port, 6, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(60f) }); if (GUILayout.Button("Join", (GUILayoutOption[])(object)new GUILayoutOption[0])) { Online.LastError = ""; if (!int.TryParse(s_port, out var result2) || result2 <= 0 || result2 > 65535) { Online.LastError = "Invalid port"; } else if (string.IsNullOrEmpty(s_address)) { Online.LastError = "Enter the host address"; } else { Plugin.CfgLastAddress.Value = s_address.Trim(); Online.JoinUdp(s_address.Trim(), result2); } } GUILayout.EndHorizontal(); } private static void DrawHost() { //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) HostSession host = Online.Host; GUILayout.Label("Hosting", s_title, (GUILayoutOption[])(object)new GUILayoutOption[0]); if (Online.Lobby != null && Online.Lobby.InLobby) { GUILayout.Label("Lobby \"" + Online.Lobby.Name + "\"", (GUILayoutOption[])(object)new GUILayoutOption[0]); GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]); ELobbyType[] array = (ELobbyType[])(object)new ELobbyType[3] { (ELobbyType)2, (ELobbyType)1, default(ELobbyType) }; foreach (ELobbyType val in array) { if (GUILayout.Toggle(Online.Lobby.Type == val, SteamLobby.TypeName(val), GUI.skin.button, (GUILayoutOption[])(object)new GUILayoutOption[0]) && Online.Lobby.Type != val) { Online.Lobby.SetType(val); Plugin.CfgLobbyType.Value = Online.LobbyTypeKey(val); } } GUILayout.EndHorizontal(); if (GUILayout.Button("Invite friends (Steam overlay)", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(30f) })) { Online.InviteFriends(); } } GUILayout.Space(4f); GUILayout.Label("Connected players: " + host.ClientCount + " / " + host.MaxConnections, (GUILayoutOption[])(object)new GUILayoutOption[0]); HostSession.Client[] clients = host.Clients; foreach (HostSession.Client client in clients) { if (client == null) { continue; } GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]); int num = 0; NetGamepad[] pads = client.Pads; for (int j = 0; j < pads.Length; j++) { if (pads[j] != null) { num++; } } GUILayout.Label(((client.PlayerSlot >= 0) ? ("P" + (client.PlayerSlot + 1) + " ") : "spectator ") + client.Name + " " + Mathf.RoundToInt(client.Rtt * 1000f) + " ms" + (client.Link.Relay ? " relay" : "") + " " + (client.BwOut / 1024f).ToString("F0") + " KB/s controllers: " + num, (GUILayoutOption[])(object)new GUILayoutOption[0]); if (GUILayout.Button("Kick", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(50f) })) { host.Kick(client.Slot); } GUILayout.EndHorizontal(); } GUILayout.Label("Remote players join like local ones: press a button on the character select screen.", s_small, (GUILayoutOption[])(object)new GUILayoutOption[0]); SceneCapture capture = host.Capture; GUILayout.Label("entities " + capture.EntityCount + ", visible sprites " + capture.VisibleRenderers + ", meshes " + capture.Defs.GeomCount + ", capture " + capture.LastCaptureMs.ToString("F2") + " ms", s_small, (GUILayoutOption[])(object)new GUILayoutOption[0]); GUILayout.Space(6f); if (GUILayout.Button("Stop hosting", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(28f) })) { Online.Stop("host stopped the session"); } } private static void DrawClient() { ClientSession client = Online.Client; if (client.State == ClientSession.States.Connecting) { GUILayout.Label("Connecting...", s_title, (GUILayoutOption[])(object)new GUILayoutOption[0]); if (GUILayout.Button("Cancel", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(28f) })) { Online.Stop("cancelled"); } return; } GUILayout.Label("Connected to " + client.HostName, s_title, (GUILayoutOption[])(object)new GUILayoutOption[0]); GUILayout.Label((client.MyPlayerSlot >= 0) ? ("You play as P" + (client.MyPlayerSlot + 1)) : "All player slots are taken - you are spectating", (GUILayoutOption[])(object)new GUILayoutOption[0]); GUILayout.Label("Ping " + Mathf.RoundToInt(client.Rtt * 1000f) + " ms download " + (client.BwIn / 1024f).ToString("F0") + " KB/s lost packets " + client.LostPackets, (GUILayoutOption[])(object)new GUILayoutOption[0]); GUILayout.Label("Connection: " + client.Transport.Name + (client.Link.Relay ? " via Steam relay servers" : " (direct)") + " max frame gap " + Mathf.RoundToInt(client.Jitter * 1000f) + " ms send queue " + client.Link.QueuedBytes + " B", s_small, (GUILayoutOption[])(object)new GUILayoutOption[0]); foreach (string item in client.Roster) { GUILayout.Label(" " + item, s_small, (GUILayoutOption[])(object)new GUILayoutOption[0]); } bool flag = GUILayout.Toggle(Plugin.CfgClientPrediction.Value, " Move my character instantly (prediction: hides the ping for your own movement)", (GUILayoutOption[])(object)new GUILayoutOption[0]); if (flag != Plugin.CfgClientPrediction.Value) { Plugin.CfgClientPrediction.Value = flag; } GUILayout.Label("Your controllers and keyboard are sent to the host. On the character select screen press Action (A / X / Space) to join. Enter = Start/Pause, Escape = Back.", s_small, (GUILayoutOption[])(object)new GUILayoutOption[0]); if (GUILayout.Button("Disconnect", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(28f) })) { Online.Stop("left"); } } } public static class Splash { private const float Dur = 3.2f; private static readonly Color Bg = Color32.op_Implicit(new Color32((byte)21, (byte)17, (byte)30, byte.MaxValue)); private static Texture2D s_logo; private static Texture2D s_title; private static Texture2D s_sub; private static Texture2D s_url; private static Texture2D s_white; private static AudioSource s_audio; private static float s_start = -1f; private static bool s_done; private static GUIStyle s_credit; public static void Init() { try { s_logo = LoadTexture("splash.logo.png", (FilterMode)1); s_title = LoadTexture("splash.title.png", (FilterMode)0); s_sub = LoadTexture("splash.sub.png", (FilterMode)0); s_url = LoadTexture("splash.url.png", (FilterMode)0); s_white = Texture2D.whiteTexture; AudioClip val = LoadWav("splash.splash.wav"); if ((Object)(object)val != (Object)null) { s_audio = ((Component)Runner.Instance).gameObject.AddComponent<AudioSource>(); s_audio.clip = val; s_audio.playOnAwake = false; s_audio.ignoreListenerPause = true; s_audio.ignoreListenerVolume = true; s_audio.volume = 0.8f; s_audio.spatialBlend = 0f; } } catch (Exception ex) { Plugin.Log.LogWarning((object)("splash: " + ex.Message)); s_done = true; } Runner.OnGuiDraw += Draw; } private static Stream Resource(string name) { return typeof(Splash).Assembly.GetManifestResourceStream(name); } private static byte[] ReadAll(string name) { using Stream stream = Resource(name); if (stream == null) { throw new Exception("missing resource " + name); } byte[] array = new byte[stream.Length]; int num; for (int i = 0; i < array.Length; i += num) { num = stream.Read(array, i, array.Length - i); if (num <= 0) { break; } } return array; } private static Texture2D LoadTexture(string name, FilterMode filter) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0017: 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_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Expected O, but got Unknown Texture2D val = new Texture2D(2, 2, (TextureFormat)5, false); val.LoadImage(ReadAll(name)); ((Texture)val).filterMode = filter; ((Texture)val).wrapMode = (TextureWrapMode)1; ((Object)val).hideFlags = (HideFlags)61; return val; } private static AudioClip LoadWav(string name) { byte[] array = ReadAll(name); int num = BitConverter.ToInt16(array, 22); int num2 = BitConverter.ToInt32(array, 24); int num3; for (int i = 12; i + 8 <= array.Length; i += 8 + num3) { string text = Encoding.ASCII.GetString(array, i, 4); num3 = BitConverter.ToInt32(array, i + 4); if (text == "data") { int num4 = Math.Min(num3, array.Length - i - 8) / 2; float[] array2 = new float[num4]; for (int j = 0; j < num4; j++) { array2[j] = (float)BitConverter.ToInt16(array, i + 8 + j * 2) / 32768f; } AudioClip obj = AudioClip.Create("OnlineFixSplash", num4 / num, num, num2, false); obj.SetData(array2, 0); return obj; } } return null; } private static void Draw() { if (!s_done) { DrawSplash(); } else { DrawCredit(); } } private static void DrawSplash() { //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Invalid comparison between Unknown and I4 //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Invalid comparison between Unknown and I4 //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_0134: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_016a: Unknown result type (might be due to invalid IL or missing references) //IL_0218: Unknown result type (might be due to invalid IL or missing references) //IL_0222: Unknown result type (might be due to invalid IL or missing references) //IL_029c: Unknown result type (might be due to invalid IL or missing references) //IL_02b7: Unknown result type (might be due to invalid IL or missing references) //IL_02fb: Unknown result type (might be due to invalid IL or missing references) if (s_start < 0f) { s_start = Time.realtimeSinceStartup; if ((Object)(object)s_audio != (Object)null) { s_audio.Play(); } } float num = Time.realtimeSinceStartup - s_start; if (((int)Event.current.type == 4 || (int)Event.current.type == 0) && num < 2.7f) { s_start = Time.realtimeSinceStartup - 2.7f; num = 2.7f; } if (num >= 3.2f) { s_done = true; } else if ((int)Event.current.type == 7) { float num2 = Screen.width; float num3 = Screen.height; float num4 = Mathf.Min(num2 / 1920f, num3 / 1080f); float num5 = (num3 - 1080f * num4) * 0.5f; float num6 = ((num > 2.7f) ? Mathf.Max(0f, (3.2f - num) / 0.5f) : 1f); float num7 = Mathf.Min(1f, num / 0.35f) * num6; Color color = GUI.color; int depth = GUI.depth; GUI.depth = -10000; GUI.color = new Color(Bg.r, Bg.g, Bg.b, num6); GUI.DrawTexture(new Rect(0f, 0f, num2, num3), (Texture)(object)s_white); GUI.color = new Color(1f, 1f, 1f, num7); int num8 = (int)(num / 0.04f) % 25; float num9 = 1f - Mathf.Pow(1f - Mathf.Min(1f, num / 0.5f), 3f); float num10 = 360f * num4 * (0.3f + 0.7f * num9); Rect val = default(Rect); ((Rect)(ref val))..ctor((float)(num8 % 5) / 5f, 1f - (float)(num8 / 5 + 1) / 5f, 0.2f, 0.2f); GUI.DrawTextureWithTexCoords(new Rect(num2 * 0.5f - num10 * 0.5f, num5 + 430f * num4 - num10 * 0.5f, num10, num10), (Texture)(object)s_logo, val); int num11 = (int)Mathf.Max(0f, (num - 0.45f) / 0.06f); if (num11 > 0) { float num12 = Mathf.Min(1f, (float)num11 / 10f); float num13 = (float)((Texture)s_title).width * num4; float num14 = (float)((Texture)s_title).height * num4; GUI.DrawTextureWithTexCoords(new Rect(num2 * 0.5f - num13 * 0.5f, num5 + 640f * num4, num13 * num12, num14), (Texture)(object)s_title, new Rect(0f, 0f, num12, 1f)); } if (num > 1.2f) { DrawCentred(s_sub, num5 + 800f * num4, num4); } if (num > 1.5f) { DrawCentred(s_url, num5 + 890f * num4, num4); } GUI.color = color; GUI.depth = depth; } } private static void DrawCentred(Texture2D tex, float top, float s) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) float num = (float)((Texture)tex).width * s; float num2 = (float)((Texture)tex).height * s; GUI.DrawTexture(new Rect((float)Screen.width * 0.5f - num * 0.5f, top, num, num2), (Texture)(object)tex); } private static void DrawCredit() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Invalid comparison between Unknown and I4 //IL_000e: 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_00b0: 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_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Expected O, but got Unknown //IL_008b: Unknown result type (might be due to invalid IL or missing references) if ((int)Event.current.type != 7) { return; } Scene activeScene = SceneManager.GetActiveScene(); if (!(((Scene)(ref activeScene)).name != "SceneMenuMain") && !Online.InSession && !Overlay.Visible) { if (s_credit == null) { s_credit = new GUIStyle(GUI.skin.label) { alignment = (TextAnchor)8, fontSize = Mathf.Max(11, Screen.height / 60) }; s_credit.normal.textColor = new Color(0.47f, 0.77f, 1f, 0.85f); } GUI.Label(new Rect(0f, 0f, (float)(Screen.width - 10), (float)(Screen.height - 6)), "Online-Fix co-op mods · online-fix.me", s_credit); } } } } namespace CrawlOnline.Net { public sealed class GeomDef { public Vector3[] Pos; public Vector2[] Uv; public int[][] Tris; public Color32[] Colors; public bool HasZ; public void Write(ByteWriter w) { //IL_00f4: Unknown result type (might be due to invalid IL or missing references) int num = Pos.Length; w.VarU((uint)num); int num2 = (int)((HasZ ? 1u : 0u) | (uint)((Colors != null) ? 2 : 0)) | ((Uv != null && Uv.Length == num) ? 4 : 0); w.U8(num2); for (int i = 0; i < num; i++) { w.F32(Pos[i].x); w.F32(Pos[i].y); if (HasZ) { w.F32(Pos[i].z); } } if ((num2 & 4) != 0) { for (int j = 0; j < num; j++) { w.F32(Uv[j].x); w.F32(Uv[j].y); } } if (Colors != null) { for (int k = 0; k < num; k++) { w.Col32(Colors[k]); } } w.U8(Tris.Length); for (int l = 0; l < Tris.Length; l++) { int[] array = Tris[l]; w.VarU((uint)array.Length); for (int m = 0; m < array.Length; m++) { w.U16(array[m]); } } } public static GeomDef Read(ByteReader r) { //IL_0079: 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_00b8: 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_00ec: 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) GeomDef geomDef = new GeomDef(); int num = (int)r.VarU(); if (num > 65535) { throw new FormatException("geom too large"); } int num2 = r.U8(); geomDef.HasZ = (num2 & 1) != 0; geomDef.Pos = (Vector3[])(object)new Vector3[num]; for (int i = 0; i < num; i++) { float num3 = r.F32(); float num4 = r.F32(); float num5 = (geomDef.HasZ ? r.F32() : 0f); geomDef.Pos[i] = new Vector3(num3, num4, num5); } geomDef.Uv = (Vector2[])(object)new Vector2[num]; if ((num2 & 4) != 0) { for (int j = 0; j < num; j++) { geomDef.Uv[j] = new Vector2(r.F32(), r.F32()); } } if ((num2 & 2) != 0) { geomDef.Colors = (Color32[])(object)new Color32[num]; for (int k = 0; k < num; k++) { geomDef.Colors[k] = r.Col32(); } } int num6 = r.U8(); geomDef.Tris = new int[num6][]; for (int l = 0; l < num6; l++) { int num7 = (int)r.VarU(); if (num7 > 1048576) { throw new FormatException("too many indices"); } int[] array = new int[num7]; for (int m = 0; m < num7; m++) { array[m] = r.U16(); } geomDef.Tris[l] = array; } return geomDef; } } public sealed class TextureDef { public string Name; public int Width; public int Height; public string FontName; public int Filter; public void Write(ByteWriter w) { w.Str(Name); w.U16(Width); w.U16(Height); w.Str(FontName); w.U8(Filter); } public static TextureDef Read(ByteReader r) { return new TextureDef { Name = r.Str(), Width = r.U16(), Height = r.U16(), FontName = r.Str(), Filter = r.U8() }; } } public sealed class NamedDef { public string Name; public float Length; public void Write(ByteWriter w, bool withLength) { w.Str(Name); if (withLength) { w.F32(Length); } } public static NamedDef Read(ByteReader r, bool withLength) { NamedDef namedDef = new NamedDef { Name = r.Str() }; if (withLength) { namedDef.Length = r.F32(); } return namedDef; } } public static class FxCodec { public const byte TNull = 0; public const byte TBool = 1; public const byte TInt = 2; public const byte TFloat = 3; public const byte TEnum = 4; public const byte TString = 5; public const byte TVec2 = 6; public const byte TVec3 = 7; public const byte TVec4 = 8; public const byte TColor = 9; public const byte TRect = 10; public const byte TCurve = 11; public const byte TShader = 12; public const byte TTexture = 13; private static readonly Dictionary<Type, bool> s_isFx = new Dictionary<Type, bool>(); private static readonly Dictionary<Type, FieldInfo[]> s_fields = new Dictionary<Type, FieldInfo[]>(); public static bool IsImageEffect(Type t) { if (s_isFx.TryGetValue(t, out var value)) { return value; } value = (object)t.GetMethod("OnRenderImage", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) != null; s_isFx[t] = value; return value; } public static FieldInfo[] GetFields(Type t) { if (s_fields.TryGetValue(t, out var value)) { return value; } List<FieldInfo> list = new List<FieldInfo>(); Type type = t; while ((object)type != null && (object)type != typeof(MonoBehaviour) && (object)type != typeof(object)) { FieldInfo[] fields = type.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (FieldInfo fieldInfo in fields) { if (((fieldInfo.IsPublic && !fieldInfo.IsNotSerialized) || fieldInfo.GetCustomAttributes(typeof(SerializeField), inherit: true).Length != 0) && TypeCode(fieldInfo.FieldType) != 0) { list.Add(fieldInfo); } } type = type.BaseType; } value = list.ToArray(); s_fields[t] = value; return value; } public static byte TypeCode(Type t) { if ((object)t == typeof(bool)) { return 1; } if ((object)t == typeof(int)) { return 2; } if ((object)t == typeof(float)) { return 3; } if (t.IsEnum) { return 4; } if ((object)t == typeof(string)) { return 5; } if ((object)t == typeof(Vector2)) { return 6; } if ((object)t == typeof(Vector3)) { return 7; } if ((object)t == typeof(Vector4)) { return 8; } if ((object)t == typeof(Color)) { return 9; } if ((object)t == typeof(Rect)) { return 10; } if ((object)t == typeof(AnimationCurve)) { return 11; } if (typeof(Shader).IsAssignableFrom(t)) { return 12; } if (typeof(Texture).IsAssignableFrom(t) && !typeof(RenderTexture).IsAssignableFrom(t)) { return 13; } return 0; } public static void WriteValue(ByteWriter w, byte code, object v, Func<Shader, int> shaderId, Func<Texture, int> textureId) { //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Expected I4, but got Unknown //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Expected I4, but got Unknown w.U8(code); switch (code) { case 1: w.Bool((bool)v); break; case 2: w.VarI((int)v); break; case 3: w.F32((float)v); break; case 4: w.VarI(Convert.ToInt32(v))