The BepInEx console will not appear when launching like it does for other games on Thunderstore (you can turn it back on in your BepInEx.cfg file). If your PEAK crashes on startup, add -dx12 to your launch parameters.
Decompiled source of So Fly v1.3.1
tony4twentys-So Fly.dll
Decompiled a week agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using ExitGames.Client.Photon; using HarmonyLib; using Photon.Pun; using Photon.Realtime; using TMPro; using UnityEngine; using UnityEngine.TextCore; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("So Fly")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("So Fly")] [assembly: AssemblyCopyright("Copyright © 2025")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("be90c841-fb92-42ee-80b7-fcedee6eb28f")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [BepInPlugin("tony4twentys.So_Fly", "So Fly", "1.3.1")] public class SoFlyPlugin : BaseUnityPlugin, IInRoomCallbacks, IMatchmakingCallbacks { [HarmonyPatch(typeof(CharacterMovement), "Start")] public class CharacterMovement_Start_Patch { private static void Postfix(CharacterMovement __instance) { if ((Object)(object)((Component)__instance).gameObject.GetComponent<FlyController>() == (Object)null) { ((Component)__instance).gameObject.AddComponent<FlyController>(); } } } [HarmonyPatch(typeof(CharacterMovement), "CheckFallDamage")] public class CharacterMovement_CheckFallDamage_Patch { private static bool Prefix(CharacterMovement __instance) { FlyController component = ((Component)__instance).GetComponent<FlyController>(); if ((Object)(object)component != (Object)null && component.NoFallDamageActive) { ManualLogSource loggerInstance = LoggerInstance; if (loggerInstance != null) { loggerInstance.LogInfo((object)"Fall damage prevented: post-fly immunity active."); } return false; } return true; } } public class FlyController : MonoBehaviour { private GameObject canvasObject; private GameObject currentTextObj; private Character character; private bool isFlying = false; private float[] flySpeeds; private int currentSpeedIndex = 0; private KeyCode flyToggleModifierKey; private KeyCode flyToggleKey; private KeyCode speedCycleKey; private float noFallDamageUntil = 0f; private float CurrentFlySpeed => flySpeeds[currentSpeedIndex]; public bool NoFallDamageActive => Time.time < noFallDamageUntil; private void Start() { InitializeFlySpeeds(); character = ((Component)this).GetComponent<Character>(); SetupNotificationCanvas(); InitializeControls(); } private void InitializeFlySpeeds() { flySpeeds = (from s in SpeedConfig.Value.Split(new char[1] { ',' }) select float.TryParse(s.Trim(), out var result) ? result : 0f into f where f > 0f select f).ToArray(); if (flySpeeds.Length == 0) { flySpeeds = new float[5] { 25f, 50f, 75f, 100f, 200f }; LoggerInstance.LogWarning((object)"No valid fly speeds found in config. Using defaults."); } } private void InitializeControls() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) flyToggleModifierKey = FlyToggleModifier.Value; flyToggleKey = FlyToggleKey.Value; speedCycleKey = FlySpeedCycleKey.Value; } private void Update() { //IL_002b: 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_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) if (!character.IsLocal || !HostHasMod) { return; } if (Input.GetKey(flyToggleModifierKey) && Input.GetKeyDown(flyToggleKey)) { bool flag = isFlying; isFlying = !isFlying; LoggerInstance.LogInfo((object)(isFlying ? "Fly mode ENABLED" : "Fly mode DISABLED")); ShowPopup(isFlying ? "SO FLY ON" : "SO FLY OFF", ParseHexColor(isFlying ? SoFlyOnTextColor.Value : SoFlyOffTextColor.Value)); ApplyFlyingPhysics(); if (flag && !isFlying) { ArmNoFallDamage(NoFallDamageDuration.Value); } } if (isFlying && Input.GetKeyDown(speedCycleKey)) { currentSpeedIndex = (currentSpeedIndex + 1) % flySpeeds.Length; LoggerInstance.LogInfo((object)$"Fly speed set to {CurrentFlySpeed} m/s"); } } private void ApplyFlyingPhysics() { //IL_0063: Unknown result type (might be due to invalid IL or missing references) foreach (Bodypart part in character.refs.ragdoll.partList) { part.Rig.useGravity = !isFlying; part.Rig.isKinematic = isFlying; if (!isFlying) { part.Rig.linearVelocity = Vector3.zero; } } } private void FixedUpdate() { if (isFlying) { ApplyFlyingMovement(); } } private void ApplyFlyingMovement() { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0012: 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_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_002d: 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_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: 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_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: 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) Vector3 val = Vector3.zero; Vector3 lookDirection = character.data.lookDirection; Vector3 val2 = Vector3.Cross(Vector3.up, lookDirection); Vector3 normalized = ((Vector3)(ref val2)).normalized; val += lookDirection * character.input.movementInput.y; val += normalized * character.input.movementInput.x; if (character.input.crouchIsPressed) { val += Vector3.down; } if (Input.GetKey((KeyCode)32)) { val += Vector3.up; } val = ((Vector3)(ref val)).normalized * CurrentFlySpeed; Transform transform = ((Component)character).transform; transform.position += val * Time.fixedDeltaTime; } private void ArmNoFallDamage(float seconds) { //IL_003a: Unknown result type (might be due to invalid IL or missing references) noFallDamageUntil = Time.time + seconds; LoggerInstance.LogInfo((object)$"No-fall-damage window armed for {seconds} seconds."); ShowPopup("SO FLY OFF", ParseHexColor(SoFlyOffTextColor.Value)); } private void SetupNotificationCanvas() { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Expected O, but got Unknown if (!((Object)(object)canvasObject != (Object)null)) { canvasObject = new GameObject("FlyNotificationCanvas"); Canvas val = canvasObject.AddComponent<Canvas>(); val.renderMode = (RenderMode)0; val.sortingOrder = 999; canvasObject.AddComponent<CanvasScaler>(); canvasObject.AddComponent<GraphicRaycaster>(); Object.DontDestroyOnLoad((Object)(object)canvasObject); } } private void ShowPopup(string message, Color color) { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Expected O, but got Unknown //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) if (!HideAllNotifications.Value) { if ((Object)(object)currentTextObj != (Object)null) { Object.Destroy((Object)(object)currentTextObj); } currentTextObj = new GameObject("FlyText"); currentTextObj.transform.SetParent(canvasObject.transform); TextMeshProUGUI val = currentTextObj.AddComponent<TextMeshProUGUI>(); SetupTextMeshPro(val, message, TextSize.Value, (TextAlignmentOptions)514, color); RectTransform component = ((Component)val).GetComponent<RectTransform>(); component.sizeDelta = new Vector2(800f, 200f); component.anchoredPosition = new Vector2(0f, -200f); component.anchorMin = new Vector2(0.5f, 0.5f); component.anchorMax = new Vector2(0.5f, 0.5f); component.pivot = new Vector2(0.5f, 0.5f); Object.Destroy((Object)(object)currentTextObj, 5f); } } private void SetupTextMeshPro(TextMeshProUGUI tmp, string message, int fontSize, TextAlignmentOptions alignment, Color color) { //IL_0018: 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) ((TMP_Text)tmp).text = message.ToUpper(); ((TMP_Text)tmp).fontSize = fontSize; ((TMP_Text)tmp).alignment = alignment; ((Graphic)tmp).color = color; ((Graphic)tmp).raycastTarget = false; ((TMP_Text)tmp).textWrappingMode = (TextWrappingModes)0; ((TMP_Text)tmp).fontStyle = (FontStyles)1; if ((Object)(object)GameFont != (Object)null) { ((TMP_Text)tmp).font = GameFont; return; } ManualLogSource loggerInstance = LoggerInstance; if (loggerInstance != null) { loggerInstance.LogWarning((object)"Game font not available, using default font"); } } private Color ParseHexColor(string hexColor) { //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) try { string text = hexColor.TrimStart(new char[1] { '#' }); int num = Convert.ToInt32(text.Substring(0, 2), 16); int num2 = Convert.ToInt32(text.Substring(2, 2), 16); int num3 = Convert.ToInt32(text.Substring(4, 2), 16); return new Color((float)num / 255f, (float)num2 / 255f, (float)num3 / 255f, 1f); } catch { ManualLogSource loggerInstance = LoggerInstance; if (loggerInstance != null) { loggerInstance.LogWarning((object)("Failed to parse hex color '" + hexColor + "', using cyan as fallback")); } return Color.cyan; } } } private const string ROOM_CFG_KEY = "SOFLY_CFG_V1"; public static ConfigEntry<KeyCode> FlyToggleKey; public static ConfigEntry<KeyCode> FlyToggleModifier; public static ConfigEntry<KeyCode> FlySpeedCycleKey; public static ConfigEntry<string> SpeedConfig; public static ConfigEntry<bool> HideAllNotifications; public static ConfigEntry<int> TextSize; public static ConfigEntry<string> SoFlyOnTextColor; public static ConfigEntry<string> SoFlyOffTextColor; public static ConfigEntry<int> NoFallDamageDuration; public static ManualLogSource LoggerInstance; private static TMP_FontAsset _gameFontAsset; private static bool _fontSearchAttempted; public static bool HostHasMod { get; private set; } public static bool IsHost { get; private set; } public static TMP_FontAsset GameFont { get { if ((Object)(object)_gameFontAsset == (Object)null && !_fontSearchAttempted) { _gameFontAsset = FindGameFont(); _fontSearchAttempted = true; } return _gameFontAsset; } } private static TMP_FontAsset FindGameFont() { //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) try { TMP_FontAsset[] array = Resources.FindObjectsOfTypeAll<TMP_FontAsset>(); ManualLogSource loggerInstance = LoggerInstance; if (loggerInstance != null) { loggerInstance.LogInfo((object)$"Found {array.Length} TMP fonts in resources"); } TMP_FontAsset val = ((IEnumerable<TMP_FontAsset>)array).FirstOrDefault((Func<TMP_FontAsset, bool>)delegate(TMP_FontAsset fontAsset) { //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) FaceInfo faceInfo2 = ((TMP_Asset)fontAsset).faceInfo; return ((FaceInfo)(ref faceInfo2)).familyName == "Daruma Drop One"; }); if ((Object)(object)val != (Object)null) { ManualLogSource loggerInstance2 = LoggerInstance; if (loggerInstance2 != null) { loggerInstance2.LogInfo((object)("Found game font by family name: " + ((Object)val).name)); } return val; } ManualLogSource loggerInstance3 = LoggerInstance; if (loggerInstance3 != null) { loggerInstance3.LogWarning((object)"Available fonts:"); } foreach (TMP_FontAsset item in array.Where((TMP_FontAsset f) => ((Object)f).name.Contains("SDF"))) { ManualLogSource loggerInstance4 = LoggerInstance; if (loggerInstance4 != null) { string[] obj = new string[5] { " - ", ((Object)item).name, " (Family: ", null, null }; FaceInfo faceInfo = ((TMP_Asset)item).faceInfo; obj[3] = ((FaceInfo)(ref faceInfo)).familyName; obj[4] = ")"; loggerInstance4.LogWarning((object)string.Concat(obj)); } } return null; } catch (Exception ex) { ManualLogSource loggerInstance5 = LoggerInstance; if (loggerInstance5 != null) { loggerInstance5.LogWarning((object)("Error finding game font: " + ex.Message)); } return null; } } private void Awake() { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Expected O, but got Unknown LoggerInstance = ((BaseUnityPlugin)this).Logger; InitializeConfiguration(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"So Fly loaded!"); Harmony val = new Harmony("tony4twentys.So_Fly"); val.PatchAll(); } private void OnEnable() { PhotonNetwork.AddCallbackTarget((object)this); } private void OnDisable() { PhotonNetwork.RemoveCallbackTarget((object)this); } public void OnJoinedRoom() { if (PhotonNetwork.IsMasterClient) { ManualLogSource loggerInstance = LoggerInstance; if (loggerInstance != null) { loggerInstance.LogInfo((object)"So Fly: Joined room as HOST"); } PublishConfig(); } else { ManualLogSource loggerInstance2 = LoggerInstance; if (loggerInstance2 != null) { loggerInstance2.LogInfo((object)"So Fly: Joined room as CLIENT; reading config"); } TryReadConfigFromRoom(); } } public void OnCreatedRoom() { } public void OnCreateRoomFailed(short returnCode, string message) { } public void OnFriendListUpdate(List<FriendInfo> friendList) { } public void OnJoinRandomFailed(short returnCode, string message) { } public void OnJoinRoomFailed(short returnCode, string message) { } public void OnLeftRoom() { } void IInRoomCallbacks.OnPlayerEnteredRoom(Player newPlayer) { if (PhotonNetwork.IsMasterClient) { PublishConfig(); } } void IInRoomCallbacks.OnPlayerLeftRoom(Player otherPlayer) { } void IInRoomCallbacks.OnRoomPropertiesUpdate(Hashtable propertiesThatChanged) { if (propertiesThatChanged != null && ((Dictionary<object, object>)(object)propertiesThatChanged).ContainsKey((object)"SOFLY_CFG_V1")) { HostHasMod = true; IsHost = false; ManualLogSource loggerInstance = LoggerInstance; if (loggerInstance != null) { loggerInstance.LogInfo((object)"So Fly: Host handshake completed - fly mode enabled"); } } } void IInRoomCallbacks.OnPlayerPropertiesUpdate(Player targetPlayer, Hashtable changedProps) { } void IInRoomCallbacks.OnMasterClientSwitched(Player newMasterClient) { if (PhotonNetwork.IsMasterClient) { PublishConfig(); } } private void TryReadConfigFromRoom() { Room currentRoom = PhotonNetwork.CurrentRoom; if (currentRoom != null && ((RoomInfo)currentRoom).CustomProperties != null && ((Dictionary<object, object>)(object)((RoomInfo)currentRoom).CustomProperties).TryGetValue((object)"SOFLY_CFG_V1", out object _)) { HostHasMod = true; IsHost = false; ManualLogSource loggerInstance = LoggerInstance; if (loggerInstance != null) { loggerInstance.LogInfo((object)"So Fly: Host handshake completed - fly mode enabled"); } } } private void PublishConfig() { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Expected O, but got Unknown Room currentRoom = PhotonNetwork.CurrentRoom; if (currentRoom != null) { HostHasMod = true; IsHost = true; Hashtable val = new Hashtable { [(object)"SOFLY_CFG_V1"] = "SOFLY_ENABLED" }; currentRoom.SetCustomProperties(val, (Hashtable)null, (WebFlags)null); ManualLogSource loggerInstance = LoggerInstance; if (loggerInstance != null) { loggerInstance.LogInfo((object)"So Fly: Host published config - fly mode enabled"); } } } private void InitializeConfiguration() { FlyToggleModifier = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Hotkey", "FlyToggleModifier", (KeyCode)308, "Modifier key to toggle fly mode"); FlyToggleKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Hotkey", "FlyToggleKey", (KeyCode)102, "Key to toggle fly mode"); FlySpeedCycleKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Hotkey", "FlySpeedCycleKey", (KeyCode)118, "Key to cycle fly speed"); SpeedConfig = ((BaseUnityPlugin)this).Config.Bind<string>("General", "FlySpeeds", "25,50,75,100,200", "Comma-separated list of fly speeds (m/s)"); NoFallDamageDuration = ((BaseUnityPlugin)this).Config.Bind<int>("General", "NoFallDamageDuration", 30, "Duration of fall damage immunity after leaving fly mode (seconds)"); HideAllNotifications = ((BaseUnityPlugin)this).Config.Bind<bool>("UI", "HideAllNotifications", false, "Hide all on-screen notifications"); TextSize = ((BaseUnityPlugin)this).Config.Bind<int>("UI", "TextSize", 60, "Size of notification text"); SoFlyOnTextColor = ((BaseUnityPlugin)this).Config.Bind<string>("UI", "SoFlyOnTextColor", "#00FF00", "Color of 'SO FLY ON' notification text (hex format, e.g. #00FF00)"); SoFlyOffTextColor = ((BaseUnityPlugin)this).Config.Bind<string>("UI", "SoFlyOffTextColor", "#00FFFF", "Color of 'SO FLY OFF' notification text (hex format, e.g. #00FFFF)"); } }