diff --git a/DevourClient/ClientMain.cs b/DevourClient/ClientMain.cs index dad866d..9bccfcd 100644 --- a/DevourClient/ClientMain.cs +++ b/DevourClient/ClientMain.cs @@ -4,10 +4,13 @@ using System.Threading.Tasks; using Il2CppPhoton.Bolt; using UnityEngine; using Il2Cpp; +using System; +using System.Collections; +using System.Collections.Generic; namespace DevourClient { - public class ClientMain : MonoBehaviour + public class ClientMain : MonoBehaviour, IDisposable { public ClientMain(IntPtr ptr) : base(ptr) @@ -25,7 +28,7 @@ namespace DevourClient Players = 6 } - static Rect windowRect = new Rect(Settings.Settings.x + 10, Settings.Settings.y + 10, 700, 700); + static Rect windowRect = new Rect(Settings.Settings.x + 10, Settings.Settings.y + 10, 800, 750); static CurrentTab current_tab = CurrentTab.Visuals; static bool flashlight_toggle = false; @@ -34,13 +37,12 @@ namespace DevourClient static bool azazel_esp_colorpick = false; static bool spoofLevel = false; static float spoofLevelValue = 0; - static bool change_server_name = false; - static bool change_steam_name = false; + + // UI variables static bool fly = false; static float fly_speed = 5; static bool fastMove = false; static float _PlayerSpeedMultiplier = 1; - public static float lobbySize = 4; public static bool _IsAutoRespawn = false; public static bool unlimitedUV = false; public static bool exp_modifier = false; @@ -53,7 +55,6 @@ namespace DevourClient static bool azazel_esp = false; static bool azazel_skel_esp = false; static bool azazel_snapline = false; - static bool spam_message = false; static bool item_esp = false; static bool goat_rat_esp = false; static bool demon_esp = false; @@ -64,6 +65,12 @@ namespace DevourClient static bool should_show_start_message = true; static Texture2D crosshairTexture = default!; + private static int frameCount = 0; + private static int lastMemoryLog = 0; + private const int GC_GEN0_INTERVAL = 300; + private const int GC_FULL_INTERVAL = 3600; + private const int MEMORY_LOG_INTERVAL = 1800; + public void Start() { MelonLogger.Msg("For the Queen !"); @@ -71,21 +78,27 @@ namespace DevourClient MelonLogger.Warning("Github : https://github.com/ALittlePatate/DevourClient"); MelonLogger.Warning("Note : if you payed for this you most likely got scammed."); + long startMemory = GC.GetTotalMemory(false); + MelonLogger.Msg($"[Memory Monitor] Startup managed memory: {startMemory / 1024 / 1024} MB"); + crosshairTexture = Helpers.GUIHelper.GetCircularTexture(5, 5); - MelonCoroutines.Start(Helpers.Entities.GetLocalPlayer()); - MelonCoroutines.Start(Helpers.Entities.GetGoatsAndRats()); - MelonCoroutines.Start(Helpers.Entities.GetSurvivalInteractables()); - MelonCoroutines.Start(Helpers.Entities.GetKeys()); - MelonCoroutines.Start(Helpers.Entities.GetDemons()); - MelonCoroutines.Start(Helpers.Entities.GetSpiders()); - MelonCoroutines.Start(Helpers.Entities.GetGhosts()); - MelonCoroutines.Start(Helpers.Entities.GetBoars()); - MelonCoroutines.Start(Helpers.Entities.GetCorpses()); - MelonCoroutines.Start(Helpers.Entities.GetCrows()); - MelonCoroutines.Start(Helpers.Entities.GetLumps()); - MelonCoroutines.Start(Helpers.Entities.GetAzazels()); - MelonCoroutines.Start(Helpers.Entities.GetAllPlayers()); + Helpers.Entities.StartAllCoroutines(); + + Helpers.Entities.RegisterCoroutine(MelonCoroutines.Start(Helpers.Entities.GetLocalPlayer())); + Helpers.Entities.RegisterCoroutine(MelonCoroutines.Start(Helpers.Entities.GetGoatsAndRats())); + Helpers.Entities.RegisterCoroutine(MelonCoroutines.Start(Helpers.Entities.GetSurvivalInteractables())); + Helpers.Entities.RegisterCoroutine(MelonCoroutines.Start(Helpers.Entities.GetKeys())); + Helpers.Entities.RegisterCoroutine(MelonCoroutines.Start(Helpers.Entities.GetDemons())); + Helpers.Entities.RegisterCoroutine(MelonCoroutines.Start(Helpers.Entities.GetSpiders())); + Helpers.Entities.RegisterCoroutine(MelonCoroutines.Start(Helpers.Entities.GetGhosts())); + Helpers.Entities.RegisterCoroutine(MelonCoroutines.Start(Helpers.Entities.GetBoars())); + Helpers.Entities.RegisterCoroutine(MelonCoroutines.Start(Helpers.Entities.GetCorpses())); + Helpers.Entities.RegisterCoroutine(MelonCoroutines.Start(Helpers.Entities.GetCrows())); + Helpers.Entities.RegisterCoroutine(MelonCoroutines.Start(Helpers.Entities.GetLumps())); + Helpers.Entities.RegisterCoroutine(MelonCoroutines.Start(Helpers.Entities.GetAzazels())); + Helpers.Entities.RegisterCoroutine(MelonCoroutines.Start(Helpers.Entities.GetAllPlayers())); + Helpers.Entities.RegisterCoroutine(MelonCoroutines.Start(Helpers.Entities.GetMonkeys())); } public void Update() @@ -141,15 +154,6 @@ namespace DevourClient } else { - if (change_server_name) - { - Hacks.Misc.SetServerName("patate on top !"); - } - - if (change_steam_name) - { - Hacks.Misc.SetSteamName("patate"); - } if (crosshair && in_game_cache) { @@ -157,17 +161,6 @@ namespace DevourClient } } - if (spam_message) - { - MelonLogger.Msg("done"); - Hacks.Misc.MessageSpam(Settings.Settings.message_to_spam); - } - - if (spoofLevel) - { - Hacks.Misc.SetRank((int)spoofLevelValue); - } - if (Input.GetKeyDown(Settings.Settings.flyKey)) { fly = !fly; @@ -221,7 +214,30 @@ namespace DevourClient { Helpers.Entities.LocalPlayer_.p_GameObject.GetComponent().TimeScale = _PlayerSpeedMultiplier; } - catch { return; } + catch { return; } + } + + + frameCount++; + + if (frameCount % GC_GEN0_INTERVAL == 0) + { + GC.Collect(0, GCCollectionMode.Optimized); + } + + if (frameCount % GC_FULL_INTERVAL == 0) + { + GC.Collect(); + GC.WaitForPendingFinalizers(); + GC.Collect(); + frameCount = 0; + } + + if (frameCount - lastMemoryLog >= MEMORY_LOG_INTERVAL) + { + long memoryUsed = GC.GetTotalMemory(false); + MelonLogger.Msg($"[Memory Monitor] Current managed memory: {memoryUsed / 1024 / 1024} MB | Frame: {frameCount}"); + lastMemoryLog = frameCount; } } @@ -233,17 +249,37 @@ namespace DevourClient should_show_start_message = false; } - GUI.backgroundColor = Color.grey; + // 保存原始GUI状态 + Color originalBackgroundColor = GUI.backgroundColor; + GUISkin originalSkin = GUI.skin; - GUI.skin.button.normal.background = GUIHelper.MakeTex(2, 2, Color.black); - GUI.skin.button.normal.textColor = Color.white; + try + { + GUI.backgroundColor = Color.grey; - GUI.skin.button.hover.background = GUIHelper.MakeTex(2, 2, Color.green); - GUI.skin.button.hover.textColor = Color.black; + // 设置按钮样式 + GUI.skin.button.normal.background = GUIHelper.MakeTex(2, 2, Color.black); + GUI.skin.button.normal.textColor = Color.white; + GUI.skin.button.hover.background = GUIHelper.MakeTex(2, 2, Color.green); + GUI.skin.button.hover.textColor = Color.black; - GUI.skin.toggle.onNormal.textColor = Color.yellow; + // 设置切换按钮样式 + GUI.skin.toggle.onNormal.textColor = Color.yellow; + + // 设置文本框样式 - 这是关键修复 + GUI.skin.textField.normal.background = GUIHelper.MakeTex(2, 2, new Color(0.2f, 0.2f, 0.2f, 0.8f)); + GUI.skin.textField.normal.textColor = Color.white; + GUI.skin.textField.focused.background = GUIHelper.MakeTex(2, 2, new Color(0.3f, 0.3f, 0.3f, 0.9f)); + GUI.skin.textField.focused.textColor = Color.yellow; + GUI.skin.textField.border = new RectOffset(2, 2, 2, 2); + + // 设置标签样式 + GUI.skin.label.normal.textColor = Color.white; + + // 设置滑块样式 + GUI.skin.horizontalSlider.normal.background = GUIHelper.MakeTex(2, 2, new Color(0.3f, 0.3f, 0.3f, 0.8f)); + GUI.skin.horizontalSliderThumb.normal.background = GUIHelper.MakeTex(2, 2, Color.white); - //from https://www.unknowncheats.me/forum/unity/437277-mono-internal-optimisation-tips.html if (UnityEngine.Event.current.type == EventType.Repaint) { if (player_esp || player_snapline || player_skel_esp) @@ -361,6 +397,13 @@ namespace DevourClient Render.Render.DrawNameESP(lump.transform.position, "Lump", new Color(1.0f, 0.0f, 0.0f, 1.0f)); } } + foreach (Il2Cpp.MonkeyBehaviour monkey in Helpers.Entities.Monkeys) + { + if (monkey != null) + { + Render.Render.DrawNameESP(monkey.transform.position, "Monkey", new Color(1.0f, 0.0f, 0.0f, 1.0f)); + } + } } if (azazel_esp || azazel_snapline || azazel_skel_esp) @@ -379,7 +422,7 @@ namespace DevourClient } } - if (crosshair && in_game_cache) //&& !Player.IsPlayerCrawling()) + if (crosshair && in_game_cache) { const float crosshairSize = 4; @@ -395,10 +438,21 @@ namespace DevourClient } } - if (Settings.Settings.menu_enable) //Si on appuie sur INSERT + if (Settings.Settings.menu_enable) { windowRect = GUI.Window(0, windowRect, (GUI.WindowFunction)Tabs, "DevourClient"); } + } + catch (System.Exception ex) + { + MelonLogger.Msg($"OnGUI Error: {ex.Message}"); + } + finally + { + // 恢复原始GUI状态 + GUI.backgroundColor = originalBackgroundColor; + GUI.skin = originalSkin; + } } public static void Tabs(int windowID) @@ -517,8 +571,6 @@ namespace DevourClient GUI.Label(new Rect(Settings.Settings.x + 10, Settings.Settings.y + 150, 120, 30), "Azazel & Demons"); - // azazel - if (GUI.Button(new Rect(Settings.Settings.x + 10, Settings.Settings.y + 180, 60, 25), "Sam") && Player.IsInGameOrLobby() && BoltNetwork.IsServer) { Hacks.Misc.SpawnAzazel((PrefabId)BoltPrefabs.AzazelSam); @@ -549,7 +601,10 @@ namespace DevourClient BoltNetwork.Instantiate(BoltPrefabs.AzazelApril, Player.GetPlayer().transform.position, Quaternion.identity); } - // demon + if (GUI.Button(new Rect(Settings.Settings.x + 430, Settings.Settings.y + 180, 60, 25), "Kai") && Player.IsInGameOrLobby() && BoltNetwork.IsServer) + { + BoltNetwork.Instantiate(BoltPrefabs.AzazelKai, Player.GetPlayer().transform.position, Quaternion.identity); + } if (GUI.Button(new Rect(Settings.Settings.x + 10, Settings.Settings.y + 220, 60, 25), "Ghost") && Player.IsInGameOrLobby() && BoltNetwork.IsServer) { @@ -586,7 +641,10 @@ namespace DevourClient BoltNetwork.Instantiate(BoltPrefabs.ManorLump, Player.GetPlayer().transform.position, Quaternion.identity); } - // Animal + if (GUI.Button(new Rect(Settings.Settings.x + 500, Settings.Settings.y + 220, 60, 25), "Monkey") && BoltNetwork.IsServer && Player.IsInGameOrLobby()) + { + BoltNetwork.Instantiate(BoltPrefabs.Monkey, Player.GetPlayer().transform.position, Quaternion.identity); + } if (GUI.Button(new Rect(Settings.Settings.x + 10, Settings.Settings.y + 260, 60, 25), "Rat")) { @@ -863,41 +921,66 @@ namespace DevourClient infinite_mirrors = GUI.Toggle(new Rect(Settings.Settings.x + 370, Settings.Settings.y + 150, 150, 20), infinite_mirrors, "Infinite mirrors"); break; + + case "Carnival": + if (GUI.Button(new Rect(Settings.Settings.x + 190, Settings.Settings.y + 70, 150, 30), "TP to Azazel")) + { + try + { + Il2Cpp.NolanBehaviour nb = Player.GetPlayer(); + + nb.TeleportTo(Helpers.Map.GetAzazel().transform.position, Quaternion.identity); + } + catch + { + MelonLogger.Msg("Azazel not found !"); + } + } + + if (GUI.Button(new Rect(Settings.Settings.x + 190, Settings.Settings.y + 110, 150, 30), "Despawn Monkeys")) + { + Hacks.Misc.DespawnMonkeys(); + } + break; } - // load map GUI.Label(new Rect(Settings.Settings.x + 10, Settings.Settings.y + 210, 100, 30), "Load Map: "); - if (GUI.Button(new Rect(Settings.Settings.x + 10, Settings.Settings.y + 240, 100, 30), "Farmhouse") && BoltNetwork.IsServer) + if (GUI.Button(new Rect(Settings.Settings.x + 10, Settings.Settings.y + 240, 90, 30), "Farmhouse") && BoltNetwork.IsServer) { Helpers.Map.LoadMap("Devour"); } - if (GUI.Button(new Rect(Settings.Settings.x + 120, Settings.Settings.y + 240, 100, 30), "Asylum") && BoltNetwork.IsServer) + if (GUI.Button(new Rect(Settings.Settings.x + 110, Settings.Settings.y + 240, 90, 30), "Asylum") && BoltNetwork.IsServer) { Helpers.Map.LoadMap("Molly"); } - if (GUI.Button(new Rect(Settings.Settings.x + 230, Settings.Settings.y + 240, 100, 30), "Inn") && BoltNetwork.IsServer) + if (GUI.Button(new Rect(Settings.Settings.x + 210, Settings.Settings.y + 240, 90, 30), "Inn") && BoltNetwork.IsServer) { Helpers.Map.LoadMap("Inn"); } - if (GUI.Button(new Rect(Settings.Settings.x + 340, Settings.Settings.y + 240, 100, 30), "Town") && BoltNetwork.IsServer) + if (GUI.Button(new Rect(Settings.Settings.x + 310, Settings.Settings.y + 240, 90, 30), "Town") && BoltNetwork.IsServer) { Helpers.Map.LoadMap("Town"); } - if (GUI.Button(new Rect(Settings.Settings.x + 450, Settings.Settings.y + 240, 100, 30), "Slaughterhouse") && BoltNetwork.IsServer) + if (GUI.Button(new Rect(Settings.Settings.x + 10, Settings.Settings.y + 280, 90, 30), "Slaughterhouse") && BoltNetwork.IsServer) { Helpers.Map.LoadMap("Slaughterhouse"); } - if (GUI.Button(new Rect(Settings.Settings.x + 560, Settings.Settings.y + 240, 100, 30), "Manor") && BoltNetwork.IsServer) + if (GUI.Button(new Rect(Settings.Settings.x + 110, Settings.Settings.y + 280, 90, 30), "Manor") && BoltNetwork.IsServer) { Helpers.Map.LoadMap("Manor"); } + if (GUI.Button(new Rect(Settings.Settings.x + 210, Settings.Settings.y + 280, 90, 30), "Carnival") && BoltNetwork.IsServer) + { + Helpers.Map.LoadMap("Carnival"); + } + } private static void EspTab() @@ -1054,7 +1137,7 @@ namespace DevourClient } } - if (GUILayout.Button("Shovel")) + if (GUILayout.Button("Spade")) { if (BoltNetwork.IsServer && !Player.IsInGame()) { @@ -1077,6 +1160,29 @@ namespace DevourClient Hacks.Misc.CarryObject("SurvivalCake"); } } + if (GUILayout.Button("MusicBox")) + { + if (BoltNetwork.IsServer && !Player.IsInGame()) + { + BoltNetwork.Instantiate(BoltPrefabs.SurvivalMusicBox, Player.GetPlayer().transform.position, Quaternion.identity); + } + else + { + Hacks.Misc.CarryObject("MusicBox-Idle"); + } + } + if (GUILayout.Button("Coin")) + { + if (BoltNetwork.IsServer && !Player.IsInGame()) + { + BoltNetwork.Instantiate(BoltPrefabs.SurvivalCoin, Player.GetPlayer().transform.position, Quaternion.identity); + } + else + { + Hacks.Misc.CarryObject("SurvivalCoin"); + } + } + GUILayout.EndScrollView(); GUILayout.EndVertical(); @@ -1149,29 +1255,40 @@ namespace DevourClient } } - if (GUILayout.Button("Dirty head")) - { - if (BoltNetwork.IsServer && !Player.IsInGame()) - { - BoltNetwork.Instantiate(BoltPrefabs.SurvivalHead, Player.GetPlayer().transform.position, Quaternion.identity); - } - else - { - Hacks.Misc.CarryObject("SurvivalHead"); - } - } + // if (GUILayout.Button("Dirty head")) + // { + // if (BoltNetwork.IsServer && !Player.IsInGame()) + // { + // BoltNetwork.Instantiate(BoltPrefabs.SurvivalHead, Player.GetPlayer().transform.position, Quaternion.identity); + // } + // else + // { + // Hacks.Misc.CarryObject("SurvivalHead"); + // } + // } - if (GUILayout.Button("Clean head")) + // if (GUILayout.Button("Clean head")) + // { + // if (BoltNetwork.IsServer && !Player.IsInGame()) + // { + // BoltNetwork.Instantiate(BoltPrefabs.SurvivalCleanHead, Player.GetPlayer().transform.position, Quaternion.identity); + // } + // else + // { + // Hacks.Misc.CarryObject("SurvivalCleanHead"); + // } + // } + if (GUILayout.Button("Doll Head")) { if (BoltNetwork.IsServer && !Player.IsInGame()) { - BoltNetwork.Instantiate(BoltPrefabs.SurvivalCleanHead, Player.GetPlayer().transform.position, Quaternion.identity); + BoltNetwork.Instantiate(BoltPrefabs.SurvivalDollHead, Player.GetPlayer().transform.position, Quaternion.identity); } else { - Hacks.Misc.CarryObject("SurvivalCleanHead"); + Hacks.Misc.CarryObject("SurvivalDollHead"); } - } + } GUILayout.EndScrollView(); GUILayout.EndVertical(); @@ -1463,73 +1580,67 @@ namespace DevourClient private static void MiscTab() { - if (GUI.Button(new Rect(Settings.Settings.x + 10, Settings.Settings.y + 70, 150, 30), "Unlock Achievements")) + // === 游戏功能按钮区域 (左上) === + if (GUI.Button(new Rect(Settings.Settings.x + 10, Settings.Settings.y + 70, 140, 25), "Unlock Achievements")) { Thread AchievementsThread = new Thread(new ThreadStart(Hacks.Unlock.Achievements)); AchievementsThread.Start(); - MelonLogger.Msg("Achievements Unlocked!"); + MelonLogger.Msg("Achievements unlocked!"); + Hacks.Misc.ShowMessageBox("Achievements unlocked!"); } - if (GUI.Button(new Rect(Settings.Settings.x + 10, Settings.Settings.y + 110, 150, 30), "Unlock Doors")) + if (GUI.Button(new Rect(Settings.Settings.x + 160, Settings.Settings.y + 70, 140, 25), "Unlock Doors")) { Hacks.Unlock.Doors(); - MelonLogger.Msg("Doors Unlocked!"); + MelonLogger.Msg("Doors unlocked!"); + Hacks.Misc.ShowMessageBox("Doors unlocked!"); } - if (GUI.Button(new Rect(Settings.Settings.x + 10, Settings.Settings.y + 150, 150, 30), "TP Keys") && Player.IsInGame()) + if (GUI.Button(new Rect(Settings.Settings.x + 10, Settings.Settings.y + 105, 140, 25), "Teleport Keys") && Player.IsInGame()) { Hacks.Misc.TPKeys(); - MelonLogger.Msg("Here are your keys!"); + MelonLogger.Msg("Keys teleported!"); + Hacks.Misc.ShowMessageBox("Keys teleported!"); } - if (GUI.Button(new Rect(Settings.Settings.x + 10, Settings.Settings.y + 190, 150, 30), "Make Random Noise")) + if (GUI.Button(new Rect(Settings.Settings.x + 160, Settings.Settings.y + 105, 140, 25), "Play Random Sound")) { Hacks.Misc.PlaySound(); - MelonLogger.Msg("Playing a random sound!"); + MelonLogger.Msg("Playing random sound!"); + Hacks.Misc.ShowMessageBox("Playing random sound!"); } - spam_message = GUI.Toggle(new Rect(Settings.Settings.x + 10, Settings.Settings.y + 240, 140, 30), spam_message, "Chat spam"); - change_steam_name = GUI.Toggle(new Rect(Settings.Settings.x + 10, Settings.Settings.y + 270, 140, 30), change_steam_name, "Change Steam Name"); - change_server_name = GUI.Toggle(new Rect(Settings.Settings.x + 10, Settings.Settings.y + 300, 140, 30), change_server_name, "Change Server Name"); - _walkInLobby = GUI.Toggle(new Rect(Settings.Settings.x + 10, Settings.Settings.y + 330, 140, 30), _walkInLobby, "Walk In Lobby"); - _IsAutoRespawn = GUI.Toggle(new Rect(Settings.Settings.x + 10, Settings.Settings.y + 360, 140, 30), _IsAutoRespawn, "Auto Respawn"); + // === 基础开关区域 (左中) === + _walkInLobby = GUI.Toggle(new Rect(Settings.Settings.x + 10, Settings.Settings.y + 150, 140, 20), _walkInLobby, "Walk In Lobby"); + _IsAutoRespawn = GUI.Toggle(new Rect(Settings.Settings.x + 160, Settings.Settings.y + 150, 140, 20), _IsAutoRespawn, "Auto Respawn"); - fly = GUI.Toggle(new Rect(Settings.Settings.x + 10, Settings.Settings.y + 400, 40, 20), fly, "Fly"); - if (GUI.Button(new Rect(Settings.Settings.x + 60, Settings.Settings.y + 400, 40, 20), Settings.Settings.flyKey.ToString())) + // === 飞行控制区域 (左中下) === + fly = GUI.Toggle(new Rect(Settings.Settings.x + 10, Settings.Settings.y + 180, 40, 20), fly, "Fly"); + if (GUI.Button(new Rect(Settings.Settings.x + 60, Settings.Settings.y + 180, 50, 20), Settings.Settings.flyKey.ToString())) { Settings.Settings.flyKey = Settings.Settings.GetKey(); } + GUI.Label(new Rect(Settings.Settings.x + 120, Settings.Settings.y + 180, 80, 20), "Speed:"); + fly_speed = GUI.HorizontalSlider(new Rect(Settings.Settings.x + 170, Settings.Settings.y + 185, 80, 10), fly_speed, 5f, 20f); + GUI.Label(new Rect(Settings.Settings.x + 260, Settings.Settings.y + 180, 40, 20), ((int)fly_speed).ToString()); - fly_speed = GUI.HorizontalSlider(new Rect(Settings.Settings.x + 10, Settings.Settings.y + 430, 100, 10), fly_speed, 5f, 20f); - GUI.Label(new Rect(Settings.Settings.x + 120, Settings.Settings.y + 425, 100, 30), ((int)fly_speed).ToString()); + // === 等级欺骗区域 (左下) === + spoofLevel = GUI.Toggle(new Rect(Settings.Settings.x + 10, Settings.Settings.y + 210, 100, 20), spoofLevel, "Spoof Level"); + spoofLevelValue = GUI.HorizontalSlider(new Rect(Settings.Settings.x + 120, Settings.Settings.y + 215, 80, 10), spoofLevelValue, 0f, 666f); + GUI.Label(new Rect(Settings.Settings.x + 210, Settings.Settings.y + 210, 50, 20), ((int)spoofLevelValue).ToString()); + // === 经验修改区域 (左下) === + exp_modifier = GUI.Toggle(new Rect(Settings.Settings.x + 10, Settings.Settings.y + 240, 100, 20), exp_modifier, "Exp Modifier"); + exp = GUI.HorizontalSlider(new Rect(Settings.Settings.x + 120, Settings.Settings.y + 245, 80, 10), exp, 1000f, 6000f); + GUI.Label(new Rect(Settings.Settings.x + 210, Settings.Settings.y + 240, 50, 20), ((int)exp).ToString()); - spoofLevel = GUI.Toggle(new Rect(Settings.Settings.x + 10, Settings.Settings.y + 470, 150, 20), spoofLevel, "Spoof Level"); - spoofLevelValue = GUI.HorizontalSlider(new Rect(Settings.Settings.x + 10, Settings.Settings.y + 500, 100, 10), spoofLevelValue, 0f, 666f); - GUI.Label(new Rect(Settings.Settings.x + 120, Settings.Settings.y + 495, 100, 30), ((int)spoofLevelValue).ToString()); + // === 速度修改区域 (左下) === + fastMove = GUI.Toggle(new Rect(Settings.Settings.x + 10, Settings.Settings.y + 270, 100, 20), fastMove, "Player Speed"); + _PlayerSpeedMultiplier = GUI.HorizontalSlider(new Rect(Settings.Settings.x + 120, Settings.Settings.y + 275, 80, 10), _PlayerSpeedMultiplier, (int)1f, (int)10f); + GUI.Label(new Rect(Settings.Settings.x + 210, Settings.Settings.y + 270, 50, 20), ((int)_PlayerSpeedMultiplier).ToString()); - - exp_modifier = GUI.Toggle(new Rect(Settings.Settings.x + 10, Settings.Settings.y + 540, 150, 20), exp_modifier, "EXP Modifier"); - exp = GUI.HorizontalSlider(new Rect(Settings.Settings.x + 10, Settings.Settings.y + 570, 100, 10), exp, 1000f, 3000f); - GUI.Label(new Rect(Settings.Settings.x + 120, Settings.Settings.y + 565, 100, 30), ((int)exp).ToString()); - - - fastMove = GUI.Toggle(new Rect(Settings.Settings.x + 10, Settings.Settings.y + 610, 150, 20), fastMove, "Player Speed"); - _PlayerSpeedMultiplier = GUI.HorizontalSlider(new Rect(Settings.Settings.x + 10, Settings.Settings.y + 640, 100, 10), _PlayerSpeedMultiplier, (int)1f, (int)10f); - GUI.Label(new Rect(Settings.Settings.x + 120, Settings.Settings.y + 635, 100, 30), ((int)_PlayerSpeedMultiplier).ToString()); - - GUI.Label(new Rect(Settings.Settings.x + 295, Settings.Settings.y + 70, 150, 30), "Max players"); - lobbySize = GUI.HorizontalSlider(new Rect(Settings.Settings.x + 295, Settings.Settings.y + 90, 100, 10), lobbySize, (int)0f, (int)30f); - GUI.Label(new Rect(Settings.Settings.x + 405, Settings.Settings.y + 85, 100, 30), ((int)lobbySize).ToString()); - - if (GUI.Button(new Rect(Settings.Settings.x + 285, Settings.Settings.y + 110, 150, 30), "Create server")) - { - MelonLogger.Msg("Creating the server..."); - Hacks.Misc.CreateCustomizedLobby((int)lobbySize); - MelonLogger.Msg("Done !"); - } } private static void PlayersTab() @@ -1595,5 +1706,69 @@ namespace DevourClient } } + private void OnDestroy() + { + try + { + base.StopAllCoroutines(); + + Dispose(); + } + catch (Exception ex) + { + MelonLogger.Error($"Error in OnDestroy: {ex.Message}"); + } + } + + private void OnApplicationQuit() + { + try + { + Dispose(); + } + catch (Exception ex) + { + MelonLogger.Error($"Error in OnApplicationQuit: {ex.Message}"); + } + } + + public void Dispose() + { + try + { + MelonLogger.Msg("Starting ClientMain cleanup..."); + + long memoryBeforeCleanup = GC.GetTotalMemory(false); + MelonLogger.Msg($"[Memory Monitor] Pre-cleanup managed memory: {memoryBeforeCleanup / 1024 / 1024} MB"); + + Helpers.Entities.StopAllCoroutines(); + + if (crosshairTexture != null) + { + UnityEngine.Object.DestroyImmediate(crosshairTexture); + crosshairTexture = null; + } + + Helpers.GUIHelper.Cleanup(); + + Helpers.Entities.CleanupCachedObjects(); + + GC.Collect(); + GC.WaitForPendingFinalizers(); + GC.Collect(); + + long memoryAfterCleanup = GC.GetTotalMemory(true); + long memoryFreed = memoryBeforeCleanup - memoryAfterCleanup; + MelonLogger.Msg($"[Memory Monitor] Post-cleanup managed memory: {memoryAfterCleanup / 1024 / 1024} MB"); + MelonLogger.Msg($"[Memory Monitor] Memory freed: {memoryFreed / 1024 / 1024} MB"); + + MelonLogger.Msg("ClientMain disposed successfully."); + } + catch (Exception ex) + { + MelonLogger.Error($"Error disposing ClientMain: {ex.Message}"); + } + } } } + diff --git a/DevourClient/DevourClient.csproj b/DevourClient/DevourClient.csproj index 91b5fbf..a9a350e 100644 --- a/DevourClient/DevourClient.csproj +++ b/DevourClient/DevourClient.csproj @@ -12,4 +12,78 @@ 0 + + + E:\SteamLibrary\steamapps\common\Devour\MelonLoader\net6\0Harmony.dll + + + E:\SteamLibrary\steamapps\common\Devour\MelonLoader\Il2CppAssemblies\Assembly-CSharp.dll + + + E:\SteamLibrary\steamapps\common\Devour\MelonLoader\Il2CppAssemblies\Il2CppBehaviorDesigner.Runtime.dll + + + E:\SteamLibrary\steamapps\common\Devour\MelonLoader\Il2CppAssemblies\Il2Cppbolt.dll + + + E:\SteamLibrary\steamapps\common\Devour\MelonLoader\Il2CppAssemblies\Il2Cppbolt.user.dll + + + E:\SteamLibrary\steamapps\common\Devour\MelonLoader\Il2CppAssemblies\Il2Cppcom.rlabrecque.steamworks.net.dll + + + E:\SteamLibrary\steamapps\common\Devour\MelonLoader\net6\Il2CppInterop.Runtime.dll + + + E:\SteamLibrary\steamapps\common\Devour\MelonLoader\Il2CppAssemblies\Il2Cppmscorlib.dll + + + E:\SteamLibrary\steamapps\common\Devour\MelonLoader\Il2CppAssemblies\Il2CppOpsive.UltimateCharacterController.dll + + + E:\SteamLibrary\steamapps\common\Devour\MelonLoader\Il2CppAssemblies\Il2Cppudpkit.dll + + + E:\SteamLibrary\steamapps\common\Devour\MelonLoader\Il2CppAssemblies\Il2Cppudpkit.common.dll + + + E:\SteamLibrary\steamapps\common\Devour\MelonLoader\Il2CppAssemblies\Il2Cppudpkit.platform.photon.dll + + + E:\SteamLibrary\steamapps\common\Devour\MelonLoader\net6\MelonLoader.dll + + + E:\SteamLibrary\steamapps\common\Devour\MelonLoader\Il2CppAssemblies\UnityEngine.dll + + + E:\SteamLibrary\steamapps\common\Devour\MelonLoader\Il2CppAssemblies\UnityEngine.AnimationModule.dll + + + E:\SteamLibrary\steamapps\common\Devour\MelonLoader\Il2CppAssemblies\UnityEngine.CoreModule.dll + + + E:\SteamLibrary\steamapps\common\Devour\MelonLoader\Il2CppAssemblies\UnityEngine.HotReloadModule.dll + + + E:\SteamLibrary\steamapps\common\Devour\MelonLoader\Il2CppAssemblies\UnityEngine.IMGUIModule.dll + + + E:\SteamLibrary\steamapps\common\Devour\MelonLoader\Il2CppAssemblies\UnityEngine.InputLegacyModule.dll + + + E:\SteamLibrary\steamapps\common\Devour\MelonLoader\Il2CppAssemblies\UnityEngine.InputModule.dll + + + E:\SteamLibrary\steamapps\common\Devour\MelonLoader\Il2CppAssemblies\UnityEngine.PhysicsModule.dll + + + E:\SteamLibrary\steamapps\common\Devour\MelonLoader\Il2CppAssemblies\UnityEngine.UI.dll + + + E:\SteamLibrary\steamapps\common\Devour\MelonLoader\Il2CppAssemblies\UnityEngine.UIModule.dll + + + E:\SteamLibrary\steamapps\common\Devour\MelonLoader\Il2CppAssemblies\Unity.TextMeshPro.dll + + \ No newline at end of file diff --git a/DevourClient/Hacks/Misc.cs b/DevourClient/Hacks/Misc.cs index 4e8eff1..29c7285 100644 --- a/DevourClient/Hacks/Misc.cs +++ b/DevourClient/Hacks/Misc.cs @@ -1,575 +1,549 @@ -using UnityEngine; -using MelonLoader; -using UnityEngine.UI; -using System.Reflection; -using System.Runtime.InteropServices; -using DevourClient.Helpers; -using System.Linq; -using System.Collections.Generic; -using Il2CppOpsive.UltimateCharacterController.Character; -using Il2CppPhoton.Bolt; - -namespace DevourClient.Hacks -{ - public class Misc - { - public static void Fly(float speed) //normal speed 5f - { - Il2Cpp.NolanBehaviour nb = Player.GetPlayer(); - Vector3 pos = nb.transform.position; - Il2Cpp.RewiredHelpers helpers = UnityEngine.Object.FindObjectOfType(); - if (Input.GetKey((KeyCode)System.Enum.Parse(typeof(KeyCode), helpers.GetCurrentBinding("Move Up").ToString().Replace(" ", "")))) - { - pos += nb.transform.forward * speed * Time.deltaTime; - } - if (Input.GetKey((KeyCode)System.Enum.Parse(typeof(KeyCode), helpers.GetCurrentBinding("Move Down").ToString().Replace(" ", "")))) - { - pos += -nb.transform.forward * speed * Time.deltaTime; - } - if (Input.GetKey((KeyCode)System.Enum.Parse(typeof(KeyCode), helpers.GetCurrentBinding("Move Right").ToString().Replace(" ", "")))) - { - pos += nb.transform.right * speed * Time.deltaTime; - } - if (Input.GetKey((KeyCode)System.Enum.Parse(typeof(KeyCode), helpers.GetCurrentBinding("Move Left").ToString().Replace(" ", "")))) - { - pos += -nb.transform.right * speed * Time.deltaTime; - } - if (Input.GetKey(KeyCode.Space)) - { - pos += nb.transform.up * speed * Time.deltaTime; - } - if (Input.GetKey(KeyCode.LeftControl)) - { - pos += -nb.transform.up * speed * Time.deltaTime; - } - nb.locomotion.SetPosition(pos, false); - } - - public static void WalkInLobby(bool walk) - { - GameObject LocalPlayer = Helpers.Entities.LocalPlayer_.p_GameObject; - if (LocalPlayer == null) - { - return; - } - - //GetComponent called only once as AddComponent returns a component - UltimateCharacterLocomotionHandler cmp = Helpers.Entities.LocalPlayer_.p_GameObject.GetComponent(); - - if (cmp == null) - { - cmp = LocalPlayer.AddComponent(); - cmp.enabled = false; - } - - cmp.enabled = walk; - } - - public static void BurnRitualObj(string map, bool burnAll) - { - switch (map) - { - case "Inn": - Il2Cpp.InnMapController _innMapController = UnityEngine.Object.FindObjectOfType(); - if (!_innMapController) { - return; - } - - if (burnAll){ - _innMapController.SetProgressTo(10); - } - else{ - _innMapController.IncreaseProgress(); - } - break; - - case "Slaughterhouse": - Il2Cpp.SlaughterhouseAltarController _slaughterhouseAltarController = UnityEngine.Object.FindObjectOfType(); - if (!_slaughterhouseAltarController) { - return; - } - - if (burnAll) - { - _slaughterhouseAltarController.BurnGoat(); - } - else - { - _slaughterhouseAltarController.SkipToGoat(10); - } - break; - - case "Manor": - Il2Cpp.MapController mapc = UnityEngine.Object.FindObjectOfType(); - if (!mapc) - { - return; - } - - if (burnAll) - { - mapc.SetProgressTo(10); - } - else - { - mapc.SetProgressTo(mapc.GetMapProgress() + 1); - } - break; - - default: - Il2Cpp.SurvivalObjectBurnController _altar = UnityEngine.Object.FindObjectOfType(); - if (!_altar) { - return; - } - - if (burnAll) - { - _altar.SkipToGoat(10); - } - else - { - _altar.BurnGoat(); - } - break; - } - } - - public static void SpawnAzazel(PrefabId _azazelPrefabId) - { - if (!Il2CppPhoton.Bolt.BoltNetwork.IsServer) - { - Hacks.Misc.ShowMessageBox("You need to be host to spawn stuff !"); - return; - } - - GameObject _localPlayer = Helpers.Entities.LocalPlayer_.p_GameObject; - - if (_localPlayer != null) - { - Vector3 pos = _localPlayer.transform.position; - - GameObject _azazel; - - _azazel = BoltNetwork.Instantiate(_azazelPrefabId, new Vector3(pos.x, pos.y, pos.z + 1f), Quaternion.identity); - Il2Cpp.SurvivalAzazelBehaviour? azazelBehaviour = _azazel?.GetComponent(); - - if (_azazel != null) - { - if (azazelBehaviour != null) - { - _azazel.gameObject.GetComponent().Spawn(); - } - else - { - MelonLogger.Error("azazelBehaviour is null!"); - } - } - else - { - MelonLogger.Error("azazel is null!"); - } - } - } - - public static void CarryObject(string name) - { - Il2Cpp.NolanBehaviour nb = Helpers.Entities.LocalPlayer_.p_GameObject.GetComponent(); - - nb.StartCarry(name); - } - - public static void CleanFountain() - { - GameObject[] fountains = GameObject.FindGameObjectsWithTag("InnFountain"); - - foreach (GameObject fountain in fountains) - { - fountain.GetComponent().Clean(); - } - } - - public static void AutoRespawn() - { - Il2Cpp.NolanBehaviour nb = Player.GetPlayer(); - - Il2Cpp.SurvivalReviveInteractable _reviveInteractable = UnityEngine.Object.FindObjectOfType(); //probably can't be null - - _reviveInteractable.Interact(nb.gameObject); - } - public static void TPItems() - { - Il2Cpp.NolanBehaviour Nolan = Player.GetPlayer(); - - foreach (Il2Cpp.SurvivalInteractable item in Helpers.Entities.SurvivalInteractables) - { - item.transform.position = Nolan.transform.position + Nolan.transform.forward * UnityEngine.Random.RandomRange(1f, 3f); - } - } - - public static void CreateCustomizedLobby(int lobbySize = 4, bool isPrivate = false, Il2CppUdpKit.Platform.Photon.PhotonRegion.Regions __region = Il2CppUdpKit.Platform.Photon.PhotonRegion.Regions.BEST_REGION) - { - //TODO : make it so we can specify a password for a private lobby - - Il2CppHorror.Menu _menu = UnityEngine.Object.FindObjectOfType(); - - Il2CppUdpKit.Platform.PhotonPlatformConfig __photonPlatformConfig = new Il2CppUdpKit.Platform.PhotonPlatformConfig(); - __photonPlatformConfig.Region = Il2CppUdpKit.Platform.Photon.PhotonRegion.regions[__region]; - - BoltLauncher.SetUdpPlatform(new Il2CppUdpKit.Platform.PhotonPlatform(__photonPlatformConfig)); - - BoltConfig __config = UnityEngine.Object.FindObjectOfType().boltConfig; - Toggle __toggle = _menu.hostPrivateServer; - - __toggle.isOn = isPrivate; - __config.serverConnectionLimit = lobbySize; - - BoltLauncher.StartServer(__config, null); - - _menu.ShowCanvasGroup(_menu.loadingCanvasGroup, true); - _menu.ShowCanvasGroup(_menu.hostCanvasGroup, false); - _menu.ShowCanvasGroup(_menu.mainMenuCanvasGroup, false); - } - - public static void SetSteamName(string name) - { - Il2CppHorror.Menu Menu_ = UnityEngine.Object.FindObjectOfType(); - if (Menu_ == null) - { - return; - } - - Menu_.steamName = name; - } - public static void SetServerName(string name) - { - Il2CppHorror.Menu Menu_ = UnityEngine.Object.FindObjectOfType(); - if (Menu_ == null) - { - return; - } - - Menu_.serverNameText.text = name; - } - - public static void BigFlashlight(bool reset) - { - Il2Cpp.NolanBehaviour Nolan = Player.GetPlayer(); - if (Nolan == null) - { - return; - } - - Light flashlightSpot = Nolan.flashlightSpot; - if (flashlightSpot == null) - { - return; - } - - if (reset) - { - flashlightSpot.intensity = 1.4f; - flashlightSpot.range = 9f; - flashlightSpot.spotAngle = 70f; - } - else - { - flashlightSpot.intensity = 1.1f; - flashlightSpot.range = 200f; - flashlightSpot.spotAngle = 90f; - } - - } - - public static List GetAllBones(Animator a) - { - List Bones = new List - { - a.GetBoneTransform(HumanBodyBones.Head), // 0 - a.GetBoneTransform(HumanBodyBones.Neck), // 1 - a.GetBoneTransform(HumanBodyBones.Spine), // 2 - a.GetBoneTransform(HumanBodyBones.Hips), // 3 - - a.GetBoneTransform(HumanBodyBones.LeftShoulder), // 4 - a.GetBoneTransform(HumanBodyBones.LeftUpperArm), // 5 - a.GetBoneTransform(HumanBodyBones.LeftLowerArm), // 6 - a.GetBoneTransform(HumanBodyBones.LeftHand), // 7 - - a.GetBoneTransform(HumanBodyBones.RightShoulder), // 8 - a.GetBoneTransform(HumanBodyBones.RightUpperArm), // 9 - a.GetBoneTransform(HumanBodyBones.RightLowerArm), // 10 - a.GetBoneTransform(HumanBodyBones.RightHand), // 11 - - a.GetBoneTransform(HumanBodyBones.LeftUpperLeg), // 12 - a.GetBoneTransform(HumanBodyBones.LeftLowerLeg), // 13 - a.GetBoneTransform(HumanBodyBones.LeftFoot), // 14 - - a.GetBoneTransform(HumanBodyBones.RightUpperLeg), // 15 - a.GetBoneTransform(HumanBodyBones.RightLowerLeg), // 16 - a.GetBoneTransform(HumanBodyBones.RightFoot) // 17 - }; - - return Bones; - } - - public static void Fullbright(bool reset) - { - Il2Cpp.NolanBehaviour Nolan = Player.GetPlayer(); - if (Nolan == null) - { - return; - } - - Light flashlightSpot = Nolan.flashlightSpot; - if (flashlightSpot == null) - { - return; - } - - if (reset) - { - flashlightSpot.intensity = 1.4f; - flashlightSpot.range = 9f; - flashlightSpot.spotAngle = 70f; - flashlightSpot.type = LightType.Spot; - flashlightSpot.shadows = LightShadows.Soft; - } - else - { - flashlightSpot.intensity = 1.1f; - flashlightSpot.range = 200f; - flashlightSpot.spotAngle = 179f; - flashlightSpot.type = LightType.Point; - flashlightSpot.shadows = LightShadows.None; - } - - } - public static void FlashlightColor(Color color) - { - Il2Cpp.NolanBehaviour Nolan = Player.GetPlayer(); - Light flashlightSpot = Nolan.flashlightSpot; - - flashlightSpot.color = color; - } - - public static void TPKeys() - { - //TOFIX: spawn manually the missing key in slaughterhouse - Il2Cpp.NolanBehaviour Nolan = Player.GetPlayer(); - - foreach (Il2Cpp.KeyBehaviour keyBehaviour in Helpers.Entities.Keys) - { - if (keyBehaviour == null) - { - return; - } - keyBehaviour.transform.position = Nolan.transform.position + Nolan.transform.forward * 1.5f; - } - } - - public static void SetRank(int rank) - { - Il2Cpp.NolanRankController NolanRank = UnityEngine.Object.FindObjectOfType(); - if (NolanRank == null) - { - return; - } - NolanRank.SetRank(rank); - } - - public static void MessageSpam(string message) - { - //TOFIX : not spamming anymore :/ - if (Helpers.Player.IsInGame()) - { - Il2Cpp.GameUI game_ui_class = UnityEngine.Object.FindObjectOfType(); - - game_ui_class.textChatInput.text = message; - game_ui_class.OnChatMessageSubmit(); - } - else - { - Il2CppHorror.Menu menu_class = UnityEngine.Object.FindObjectOfType(); - menu_class.textChatInput.text = message; - menu_class.OnChatMessageSubmit(); - } - } - - public static void DespawnDemons() - { - foreach (Il2Cpp.SurvivalDemonBehaviour demon in Helpers.Entities.Demons) - { - if (demon != null) - { - demon.Despawn(); - } - } - } - - public static void DespawnSpiders() - { - foreach (Il2Cpp.SpiderBehaviour spider in Helpers.Entities.Spiders) - { - if (spider != null) - { - spider.Despawn(); - } - } - } - - public static void DespawnGhosts() - { - foreach (Il2Cpp.GhostBehaviour ghost in Helpers.Entities.Ghosts) - { - if (ghost != null) - { - ghost.Despawn(); - } - } - } - - public static void DespawnBoars() - { - foreach (Il2Cpp.BoarBehaviour boar in Helpers.Entities.Boars) - { - if (boar != null) - { - boar.Despawn(); - } - } - } - - public static void DespawnCorpses() - { - foreach (Il2Cpp.CorpseBehaviour corpse in Helpers.Entities.Corpses) - { - if (corpse != null) - { - corpse.Despawn(); - } - } - } - - public static void DespawnCrows() - { - foreach (Il2Cpp.CrowBehaviour crow in Helpers.Entities.Crows) - { - if (crow != null) - { - crow.Despawn(); - } - } - } - - public static void DespawnLumps() - { - foreach (Il2Cpp.ManorLumpController lump in Helpers.Entities.Lumps) - { - if (lump != null) - { - lump.Dissolve(); - } - } - } - - public static int ShowMessageBox(string message) - { - //not used, might be useful, some day - Il2CppHorror.Menu menu = UnityEngine.Object.FindObjectOfType(); - if (menu == null) - return 1; - menu.ShowMessageModal(message); - return 0; - } - - public static void PlaySound() - { - Il2Cpp.PlayRandomAudioClip playRandomAudioClip = UnityEngine.Object.FindObjectOfType(); - Il2Cpp.NolanVoiceOvers nolanVoiceOvers = UnityEngine.Object.FindObjectOfType(); - playRandomAudioClip.delay = 0f; - - int num = UnityEngine.Random.RandomRangeInt(0, 10); - switch (num) - { - case 0: - nolanVoiceOvers.yesClips.Play(); - return; - case 1: - nolanVoiceOvers.noClips.Play(); - return; - case 2: - nolanVoiceOvers.beckonClips.Play(); - return; - case 3: - nolanVoiceOvers.showOffClips.Play(); - return; - case 4: - nolanVoiceOvers.screamClips.Play(); - return; - case 5: - nolanVoiceOvers.pickupClips.Play(); - return; - case 6: - nolanVoiceOvers.burnGoatClips.Play(); - return; - case 7: - nolanVoiceOvers.laughClips.Play(); - return; - case 8: - nolanVoiceOvers.PlayMoan(); - return; - case 9: - nolanVoiceOvers.Scream(); - return; - default: - return; - } - } - - public static void FreezeAzazel() - { - if (Helpers.Map.GetActiveScene() == "Menu") - { - return; - } - - if (Helpers.Map.GetAzazel() == null) { - return; - } - - UltimateCharacterLocomotion _azazelLocomotion = Helpers.Map.GetAzazel().GetComponent(); - - if (_azazelLocomotion == null) - { - return; - } - - if (_azazelLocomotion.TimeScale > 0.0f) - { - _azazelLocomotion.TimeScale = 0f; //host only (?) - } - else - { - _azazelLocomotion.TimeScale = 1.0f; - } - } - - public static void InstantWin() - { - Il2Cpp.Survival survival_class = UnityEngine.Object.FindObjectOfType(); - string map_name = Map.GetMapName(Map.GetActiveScene()); - - if (map_name == "Menu") - { - return; - } - - if (map_name == "Farmhouse") - { - survival_class.PlayEnding("Win"); - return; - } - - survival_class.PlayEnding(map_name+"Win"); - } - } -} +using UnityEngine; +using MelonLoader; +using UnityEngine.UI; +using System.Reflection; +using System.Runtime.InteropServices; +using DevourClient.Helpers; +using System.Linq; +using System.Collections.Generic; +using Il2CppOpsive.UltimateCharacterController.Character; +using Il2CppPhoton.Bolt; + +namespace DevourClient.Hacks +{ + public class Misc + { + public static void Fly(float speed) //normal speed 5f + { + Il2Cpp.NolanBehaviour nb = Player.GetPlayer(); + Vector3 pos = nb.transform.position; + Il2Cpp.RewiredHelpers helpers = UnityEngine.Object.FindObjectOfType(); + if (Input.GetKey((KeyCode)System.Enum.Parse(typeof(KeyCode), helpers.GetCurrentBinding("Move Up").ToString().Replace(" ", "")))) + { + pos += nb.transform.forward * speed * Time.deltaTime; + } + if (Input.GetKey((KeyCode)System.Enum.Parse(typeof(KeyCode), helpers.GetCurrentBinding("Move Down").ToString().Replace(" ", "")))) + { + pos += -nb.transform.forward * speed * Time.deltaTime; + } + if (Input.GetKey((KeyCode)System.Enum.Parse(typeof(KeyCode), helpers.GetCurrentBinding("Move Right").ToString().Replace(" ", "")))) + { + pos += nb.transform.right * speed * Time.deltaTime; + } + if (Input.GetKey((KeyCode)System.Enum.Parse(typeof(KeyCode), helpers.GetCurrentBinding("Move Left").ToString().Replace(" ", "")))) + { + pos += -nb.transform.right * speed * Time.deltaTime; + } + if (Input.GetKey(KeyCode.Space)) + { + pos += nb.transform.up * speed * Time.deltaTime; + } + if (Input.GetKey(KeyCode.LeftControl)) + { + pos += -nb.transform.up * speed * Time.deltaTime; + } + nb.locomotion.SetPosition(pos, false); + } + + public static void WalkInLobby(bool walk) + { + GameObject LocalPlayer = Helpers.Entities.LocalPlayer_.p_GameObject; + if (LocalPlayer == null) + { + return; + } + + //GetComponent called only once as AddComponent returns a component + UltimateCharacterLocomotionHandler cmp = Helpers.Entities.LocalPlayer_.p_GameObject.GetComponent(); + + if (cmp == null) + { + cmp = LocalPlayer.AddComponent(); + cmp.enabled = false; + } + + cmp.enabled = walk; + } + + public static void BurnRitualObj(string map, bool burnAll) + { + switch (map) + { + case "Inn": + Il2Cpp.InnMapController _innMapController = UnityEngine.Object.FindObjectOfType(); + if (!_innMapController) { + return; + } + + if (burnAll){ + _innMapController.SetProgressTo(10); + } + else{ + _innMapController.IncreaseProgress(); + } + break; + + case "Slaughterhouse": + Il2Cpp.SlaughterhouseAltarController _slaughterhouseAltarController = UnityEngine.Object.FindObjectOfType(); + if (!_slaughterhouseAltarController) { + return; + } + + if (burnAll) + { + _slaughterhouseAltarController.BurnGoat(); + } + else + { + _slaughterhouseAltarController.SkipToGoat(10); + } + break; + + case "Manor": + Il2Cpp.MapController mapc = UnityEngine.Object.FindObjectOfType(); + if (!mapc) + { + return; + } + + if (burnAll) + { + mapc.SetProgressTo(10); + } + else + { + mapc.SetProgressTo(mapc.GetMapProgress() + 1); + } + break; + + default: + Il2Cpp.SurvivalObjectBurnController _altar = UnityEngine.Object.FindObjectOfType(); + if (!_altar) { + return; + } + + if (burnAll) + { + _altar.SkipToGoat(10); + } + else + { + _altar.BurnGoat(); + } + break; + } + } + + public static void SpawnAzazel(PrefabId _azazelPrefabId) + { + if (!Il2CppPhoton.Bolt.BoltNetwork.IsServer) + { + Hacks.Misc.ShowMessageBox("You need to be host to spawn stuff !"); + return; + } + + GameObject _localPlayer = Helpers.Entities.LocalPlayer_.p_GameObject; + + if (_localPlayer != null) + { + Vector3 pos = _localPlayer.transform.position; + + GameObject _azazel; + + _azazel = BoltNetwork.Instantiate(_azazelPrefabId, new Vector3(pos.x, pos.y, pos.z + 1f), Quaternion.identity); + Il2Cpp.SurvivalAzazelBehaviour? azazelBehaviour = _azazel?.GetComponent(); + + if (_azazel != null) + { + if (azazelBehaviour != null) + { + _azazel.gameObject.GetComponent().Spawn(); + } + else + { + MelonLogger.Error("azazelBehaviour is null!"); + } + } + else + { + MelonLogger.Error("azazel is null!"); + } + } + } + + public static void CarryObject(string name) + { + Il2Cpp.NolanBehaviour nb = Helpers.Entities.LocalPlayer_.p_GameObject.GetComponent(); + + nb.StartCarry(name); + } + + public static void CleanFountain() + { + GameObject[] fountains = GameObject.FindGameObjectsWithTag("InnFountain"); + + foreach (GameObject fountain in fountains) + { + fountain.GetComponent().Clean(); + } + } + + public static void AutoRespawn() + { + Il2Cpp.NolanBehaviour nb = Player.GetPlayer(); + + Il2Cpp.SurvivalReviveInteractable _reviveInteractable = UnityEngine.Object.FindObjectOfType(); //probably can't be null + + _reviveInteractable.Interact(nb.gameObject); + } + public static void TPItems() + { + Il2Cpp.NolanBehaviour Nolan = Player.GetPlayer(); + + foreach (Il2Cpp.SurvivalInteractable item in Helpers.Entities.SurvivalInteractables) + { + item.transform.position = Nolan.transform.position + Nolan.transform.forward * UnityEngine.Random.RandomRange(1f, 3f); + } + } + + public static void CreateCustomizedLobby(int lobbySize = 4, bool isPrivate = false, Il2CppUdpKit.Platform.Photon.PhotonRegion.Regions __region = Il2CppUdpKit.Platform.Photon.PhotonRegion.Regions.BEST_REGION) + { + //TODO : make it so we can specify a password for a private lobby + + Il2CppHorror.Menu _menu = UnityEngine.Object.FindObjectOfType(); + + Il2CppUdpKit.Platform.PhotonPlatformConfig __photonPlatformConfig = new Il2CppUdpKit.Platform.PhotonPlatformConfig(); + __photonPlatformConfig.Region = Il2CppUdpKit.Platform.Photon.PhotonRegion.regions[__region]; + + BoltLauncher.SetUdpPlatform(new Il2CppUdpKit.Platform.PhotonPlatform(__photonPlatformConfig)); + + BoltConfig __config = UnityEngine.Object.FindObjectOfType().boltConfig; + Toggle __toggle = _menu.hostPrivateServer; + + __toggle.isOn = isPrivate; + __config.serverConnectionLimit = lobbySize; + + BoltLauncher.StartServer(__config, null); + + _menu.ShowCanvasGroup(_menu.loadingCanvasGroup, true); + _menu.ShowCanvasGroup(_menu.hostCanvasGroup, false); + _menu.ShowCanvasGroup(_menu.mainMenuCanvasGroup, false); + } + + + public static void BigFlashlight(bool reset) + { + Il2Cpp.NolanBehaviour Nolan = Player.GetPlayer(); + if (Nolan == null) + { + return; + } + + Light flashlightSpot = Nolan.flashlightSpot; + if (flashlightSpot == null) + { + return; + } + + if (reset) + { + flashlightSpot.intensity = 1.4f; + flashlightSpot.range = 9f; + flashlightSpot.spotAngle = 70f; + } + else + { + flashlightSpot.intensity = 1.1f; + flashlightSpot.range = 200f; + flashlightSpot.spotAngle = 90f; + } + + } + + public static List GetAllBones(Animator a) + { + List Bones = new List + { + a.GetBoneTransform(HumanBodyBones.Head), // 0 + a.GetBoneTransform(HumanBodyBones.Neck), // 1 + a.GetBoneTransform(HumanBodyBones.Spine), // 2 + a.GetBoneTransform(HumanBodyBones.Hips), // 3 + + a.GetBoneTransform(HumanBodyBones.LeftShoulder), // 4 + a.GetBoneTransform(HumanBodyBones.LeftUpperArm), // 5 + a.GetBoneTransform(HumanBodyBones.LeftLowerArm), // 6 + a.GetBoneTransform(HumanBodyBones.LeftHand), // 7 + + a.GetBoneTransform(HumanBodyBones.RightShoulder), // 8 + a.GetBoneTransform(HumanBodyBones.RightUpperArm), // 9 + a.GetBoneTransform(HumanBodyBones.RightLowerArm), // 10 + a.GetBoneTransform(HumanBodyBones.RightHand), // 11 + + a.GetBoneTransform(HumanBodyBones.LeftUpperLeg), // 12 + a.GetBoneTransform(HumanBodyBones.LeftLowerLeg), // 13 + a.GetBoneTransform(HumanBodyBones.LeftFoot), // 14 + + a.GetBoneTransform(HumanBodyBones.RightUpperLeg), // 15 + a.GetBoneTransform(HumanBodyBones.RightLowerLeg), // 16 + a.GetBoneTransform(HumanBodyBones.RightFoot) // 17 + }; + + return Bones; + } + + public static void Fullbright(bool reset) + { + Il2Cpp.NolanBehaviour Nolan = Player.GetPlayer(); + if (Nolan == null) + { + return; + } + + Light flashlightSpot = Nolan.flashlightSpot; + if (flashlightSpot == null) + { + return; + } + + if (reset) + { + flashlightSpot.intensity = 1.4f; + flashlightSpot.range = 9f; + flashlightSpot.spotAngle = 70f; + flashlightSpot.type = LightType.Spot; + flashlightSpot.shadows = LightShadows.Soft; + } + else + { + flashlightSpot.intensity = 1.1f; + flashlightSpot.range = 200f; + flashlightSpot.spotAngle = 179f; + flashlightSpot.type = LightType.Point; + flashlightSpot.shadows = LightShadows.None; + } + + } + public static void FlashlightColor(Color color) + { + Il2Cpp.NolanBehaviour Nolan = Player.GetPlayer(); + Light flashlightSpot = Nolan.flashlightSpot; + + flashlightSpot.color = color; + } + + public static void TPKeys() + { + //TOFIX: spawn manually the missing key in slaughterhouse + Il2Cpp.NolanBehaviour Nolan = Player.GetPlayer(); + + foreach (Il2Cpp.KeyBehaviour keyBehaviour in Helpers.Entities.Keys) + { + if (keyBehaviour == null) + { + return; + } + keyBehaviour.transform.position = Nolan.transform.position + Nolan.transform.forward * 1.5f; + } + } + + public static void SetRank(int rank) + { + Il2Cpp.NolanRankController NolanRank = UnityEngine.Object.FindObjectOfType(); + if (NolanRank == null) + { + return; + } + NolanRank.SetRank(rank); + } + + + public static void DespawnDemons() + { + foreach (Il2Cpp.SurvivalDemonBehaviour demon in Helpers.Entities.Demons) + { + if (demon != null) + { + demon.Despawn(); + } + } + } + + public static void DespawnSpiders() + { + foreach (Il2Cpp.SpiderBehaviour spider in Helpers.Entities.Spiders) + { + if (spider != null) + { + spider.Despawn(); + } + } + } + + public static void DespawnGhosts() + { + foreach (Il2Cpp.GhostBehaviour ghost in Helpers.Entities.Ghosts) + { + if (ghost != null) + { + ghost.Despawn(); + } + } + } + + public static void DespawnBoars() + { + foreach (Il2Cpp.BoarBehaviour boar in Helpers.Entities.Boars) + { + if (boar != null) + { + boar.Despawn(); + } + } + } + + public static void DespawnCorpses() + { + foreach (Il2Cpp.CorpseBehaviour corpse in Helpers.Entities.Corpses) + { + if (corpse != null) + { + corpse.Despawn(); + } + } + } + + public static void DespawnCrows() + { + foreach (Il2Cpp.CrowBehaviour crow in Helpers.Entities.Crows) + { + if (crow != null) + { + crow.Despawn(); + } + } + } + + public static void DespawnLumps() + { + foreach (Il2Cpp.ManorLumpController lump in Helpers.Entities.Lumps) + { + if (lump != null) + { + lump.Dissolve(); + } + } + } + + public static void DespawnMonkeys() + { + foreach (Il2Cpp.MonkeyBehaviour monkey in Helpers.Entities.Monkeys) + { + if (monkey != null) + { + monkey.Despawn(); + } + } + } + + public static int ShowMessageBox(string message) + { + //not used, might be useful, some day + Il2CppHorror.Menu menu = UnityEngine.Object.FindObjectOfType(); + if (menu == null) + return 1; + menu.ShowMessageModal(message); + return 0; + } + + public static void PlaySound() + { + Il2Cpp.PlayRandomAudioClip playRandomAudioClip = UnityEngine.Object.FindObjectOfType(); + Il2Cpp.NolanVoiceOvers nolanVoiceOvers = UnityEngine.Object.FindObjectOfType(); + playRandomAudioClip.delay = 0f; + + int num = UnityEngine.Random.RandomRangeInt(0, 10); + switch (num) + { + case 0: + nolanVoiceOvers.yesClips.Play(); + return; + case 1: + nolanVoiceOvers.noClips.Play(); + return; + case 2: + nolanVoiceOvers.beckonClips.Play(); + return; + case 3: + nolanVoiceOvers.showOffClips.Play(); + return; + case 4: + nolanVoiceOvers.screamClips.Play(); + return; + case 5: + nolanVoiceOvers.pickupClips.Play(); + return; + case 6: + nolanVoiceOvers.burnGoatClips.Play(); + return; + case 7: + nolanVoiceOvers.laughClips.Play(); + return; + case 8: + nolanVoiceOvers.PlayMoan(); + return; + case 9: + nolanVoiceOvers.Scream(); + return; + default: + return; + } + } + + public static void FreezeAzazel() + { + if (Helpers.Map.GetActiveScene() == "Menu") + { + return; + } + + if (Helpers.Map.GetAzazel() == null) { + return; + } + + UltimateCharacterLocomotion _azazelLocomotion = Helpers.Map.GetAzazel().GetComponent(); + + if (_azazelLocomotion == null) + { + return; + } + + if (_azazelLocomotion.TimeScale > 0.0f) + { + _azazelLocomotion.TimeScale = 0f; //host only (?) + } + else + { + _azazelLocomotion.TimeScale = 1.0f; + } + } + + public static void InstantWin() + { + Il2Cpp.Survival survival_class = UnityEngine.Object.FindObjectOfType(); + string map_name = Map.GetMapName(Map.GetActiveScene()); + + if (map_name == "Menu") + { + return; + } + + if (map_name == "Farmhouse") + { + survival_class.PlayEnding("Win"); + return; + } + + survival_class.PlayEnding(map_name+"Win"); + } + } +} diff --git a/DevourClient/Helpers/GUIHelper.cs b/DevourClient/Helpers/GUIHelper.cs index 8d4e1aa..fd78081 100644 --- a/DevourClient/Helpers/GUIHelper.cs +++ b/DevourClient/Helpers/GUIHelper.cs @@ -1,4 +1,5 @@ using UnityEngine; +using System.Collections.Generic; namespace DevourClient.Helpers { @@ -8,6 +9,13 @@ namespace DevourClient.Helpers private static float G; private static float B; + private static Texture2D previewTexture = null; + private static Dictionary colorTextureCache = new Dictionary(); + private static Dictionary circularTextureCache = new Dictionary(); + + private static Color lastPreviewColor = Color.clear; + private static GUIStyle cachedBoxStyle = null; + public static Color ColorPick(string title, Color color) { GUI.Label(new Rect(Settings.Settings.x + 195, Settings.Settings.y + 70, 250, 30), title); @@ -24,12 +32,24 @@ namespace DevourClient.Helpers void DrawPreview(Rect position, Color color_to_draw) { - Texture2D texture = new Texture2D(1, 1); - texture.SetPixel(0, 0, color_to_draw); - texture.Apply(); - GUIStyle boxStyle = new GUIStyle(GUI.skin.box); - boxStyle.normal.background = texture; - GUI.Box(position, GUIContent.none, boxStyle); + if (previewTexture == null || lastPreviewColor != color_to_draw) + { + if (previewTexture == null) + { + previewTexture = new Texture2D(1, 1); + } + + previewTexture.SetPixel(0, 0, color_to_draw); + previewTexture.Apply(); + lastPreviewColor = color_to_draw; + } + + if (cachedBoxStyle == null) + { + cachedBoxStyle = new GUIStyle(GUI.skin.box); + } + cachedBoxStyle.normal.background = previewTexture; + GUI.Box(position, GUIContent.none, cachedBoxStyle); } DrawPreview(new Rect(Settings.Settings.x + 195, Settings.Settings.y + 100, 20, 90), color); @@ -39,6 +59,14 @@ namespace DevourClient.Helpers public static Texture2D MakeTex(int width, int height, Color col) { + if (colorTextureCache.TryGetValue(col, out Texture2D cachedTexture)) + { + if (cachedTexture != null) + { + return cachedTexture; + } + } + Color[] pix = new Color[width * height]; for (int i = 0; i < pix.Length; ++i) { @@ -47,11 +75,24 @@ namespace DevourClient.Helpers Texture2D result = new Texture2D(width, height); result.SetPixels(pix); result.Apply(); + + colorTextureCache[col] = result; + return result; } public static Texture2D GetCircularTexture(int width, int height) { + int cacheKey = width; + + if (circularTextureCache.TryGetValue(cacheKey, out Texture2D cachedTexture)) + { + if (cachedTexture != null) + { + return cachedTexture; + } + } + Texture2D texture = new Texture2D(width, height); for (int x = 0; x < texture.width; x++) { @@ -70,7 +111,36 @@ namespace DevourClient.Helpers texture.Apply(); + circularTextureCache[cacheKey] = texture; + return texture; } + + public static void Cleanup() + { + if (previewTexture != null) + { + UnityEngine.Object.Destroy(previewTexture); + previewTexture = null; + } + + foreach (var texture in colorTextureCache.Values) + { + if (texture != null) + { + UnityEngine.Object.Destroy(texture); + } + } + colorTextureCache.Clear(); + + foreach (var texture in circularTextureCache.Values) + { + if (texture != null) + { + UnityEngine.Object.Destroy(texture); + } + } + circularTextureCache.Clear(); + } } } diff --git a/DevourClient/Helpers/Map.cs b/DevourClient/Helpers/Map.cs index 8e5582a..76bc7db 100644 --- a/DevourClient/Helpers/Map.cs +++ b/DevourClient/Helpers/Map.cs @@ -11,7 +11,7 @@ { switch (sceneName) { - case "Devour": + case "Anna": return "Farmhouse"; case "Molly": return "Asylum"; @@ -23,6 +23,8 @@ return "Slaughterhouse"; case "Manor": return "Manor"; + case "Carnival": + return "Carnival"; default: return "Menu"; } diff --git a/DevourClient/Helpers/Render.cs b/DevourClient/Helpers/Render.cs index d309334..2756910 100644 --- a/DevourClient/Helpers/Render.cs +++ b/DevourClient/Helpers/Render.cs @@ -12,14 +12,32 @@ namespace DevourClient.Render { public static GUIStyle StringStyle { get; set; } = new GUIStyle(GUI.skin.label); + private static GUIContent cachedContent = new GUIContent(); + private static Dictionary sizeCache = new Dictionary(); + private static int frameCacheClearCounter = 0; + private const int CACHE_CLEAR_INTERVAL = 1800; + public static void DrawString(Vector2 position, Color color, string label, bool centered = true) { - var content = new GUIContent(label); - var size = StringStyle.CalcSize(content); + cachedContent.text = label; + + if (!sizeCache.TryGetValue(label, out Vector2 size)) + { + size = StringStyle.CalcSize(cachedContent); + sizeCache[label] = size; + + frameCacheClearCounter++; + if (frameCacheClearCounter >= CACHE_CLEAR_INTERVAL) + { + sizeCache.Clear(); + frameCacheClearCounter = 0; + } + } + var upperLeft = centered ? position - size / 2f : position; Color color2 = GUI.color; GUI.color = color; - GUI.Label(new Rect(upperLeft, size), content); + GUI.Label(new Rect(upperLeft, size), cachedContent); GUI.color = color2; } @@ -63,7 +81,7 @@ namespace DevourClient.Render } public static void DrawBones(Transform bone1, Transform bone2, Color c) { - if (!Camera.main) //fix the crash maybe + if (!Camera.main) { return; } diff --git a/DevourClient/Helpers/StateHelper.cs b/DevourClient/Helpers/StateHelper.cs index af82bb4..39d406e 100644 --- a/DevourClient/Helpers/StateHelper.cs +++ b/DevourClient/Helpers/StateHelper.cs @@ -1,374 +1,491 @@ -using UnityEngine; -using Il2CppOpsive.UltimateCharacterController.Character; -using System.Collections.Generic; -using System.Collections; -using MelonLoader; -using Il2CppPhoton.Bolt; - -namespace DevourClient.Helpers -{ - public class BasePlayer - { - public GameObject p_GameObject { get; set; } = default!; - public string Name { get; set; } = default!; - public string Id { get; set; } = default!; - - public void Kill() - { - if (p_GameObject == null) - { - return; - } - - Il2Cpp.SurvivalAzazelBehaviour sab = Il2Cpp.SurvivalAzazelBehaviour.FindObjectOfType(); - - if (sab == null) - { - return; - } - - sab.OnKnockout(sab.gameObject, p_GameObject); - } - - public void Revive() - { - if (p_GameObject == null) - { - return; - } - - Il2Cpp.NolanBehaviour nb = p_GameObject.GetComponent(); - Il2Cpp.SurvivalReviveInteractable _reviveInteractable = UnityEngine.Object.FindObjectOfType(); - - _reviveInteractable.Interact(nb.gameObject); - } - - public void Jumpscare() - { - if (!BoltNetwork.IsServer) - { - MelonLogger.Msg("You need to be server !"); - return; - } - - if (p_GameObject == null) - { - return; - } - - Il2Cpp.SurvivalAzazelBehaviour sab = Il2Cpp.SurvivalAzazelBehaviour.FindObjectOfType(); - - if (sab == null) - { - return; - } - - sab.OnPickedUpPlayer(sab.gameObject, p_GameObject, false); - - /* - MelonLogger.Msg(Name); - Il2Cpp.JumpScare _jumpscare = UnityEngine.Object.FindObjectOfType(); - _jumpscare.player = p_GameObject; - _jumpscare.Activate(p_GameObject.GetComponent()); - */ - } - - public void LockInCage() - { - if (p_GameObject == null) - { - return; - } - - BoltNetwork.Instantiate(BoltPrefabs.Cage, p_GameObject.transform.position, Quaternion.identity); - } - - public void TP() - { - if (p_GameObject == null) - { - return; - } - - Il2Cpp.NolanBehaviour nb = Player.GetPlayer(); - nb.TeleportTo(p_GameObject.transform.position, Quaternion.identity); - } - - public void TPAzazel() - { - if (p_GameObject == null) - { - return; - } - - UltimateCharacterLocomotion ucl = Helpers.Map.GetAzazel().GetComponent(); - - if (ucl) - { - ucl.SetPosition(p_GameObject.transform.position); - } - else - { - MelonLogger.Error("Azazel not found!"); - return; - } - } - - public void ShootPlayer() - { - if (!BoltNetwork.IsServer) - { - MelonLogger.Msg("You need to be server !"); - return; - } - - if (p_GameObject == null) - { - return; - } - - Il2Cpp.AzazelSamBehaviour _azazelSam = UnityEngine.Object.FindObjectOfType(); - - if (_azazelSam) - { - _azazelSam.OnShootPlayer(p_GameObject, true); - } - } - } - public class Player - { - public static bool IsInGame() - { - Il2Cpp.OptionsHelpers optionsHelpers = UnityEngine.Object.FindObjectOfType(); - return optionsHelpers.inGame; - } - - public static bool IsInGameOrLobby() - { - return GetPlayer() != null; - } - - public static Il2Cpp.NolanBehaviour GetPlayer() - { - if (Entities.LocalPlayer_.p_GameObject == null) - { - return null!; - } - - return Entities.LocalPlayer_.p_GameObject.GetComponent(); - } - - public static bool IsPlayerCrawling() - { - Il2Cpp.NolanBehaviour nb = Player.GetPlayer(); - - if (nb == null) - { - return false; - } - - return nb.IsCrawling(); - } - - } - - public class Entities - { - public static int MAX_PLAYERS = 4; //will change by calling CreateCustomizedLobby - - public static BasePlayer LocalPlayer_ = new BasePlayer(); - public static BasePlayer[] Players = default!; - public static Il2Cpp.GoatBehaviour[] GoatsAndRats = default!; - public static Il2Cpp.SurvivalInteractable[] SurvivalInteractables = default!; - public static Il2Cpp.KeyBehaviour[] Keys = default!; - public static Il2Cpp.SurvivalDemonBehaviour[] Demons = default!; - public static Il2Cpp.SpiderBehaviour[] Spiders = default!; - public static Il2Cpp.GhostBehaviour[] Ghosts = default!; - public static Il2Cpp.SurvivalAzazelBehaviour[] Azazels = default!; - public static Il2Cpp.BoarBehaviour[] Boars = default!; - public static Il2Cpp.CorpseBehaviour[] Corpses = default!; - public static Il2Cpp.CrowBehaviour[] Crows = default!; - public static Il2Cpp.ManorLumpController[] Lumps = default!; - - public static IEnumerator GetLocalPlayer() - { - while (true) - { - GameObject[] currentPlayers = GameObject.FindGameObjectsWithTag("Player"); - - for (int i = 0; i < currentPlayers.Length; i++) - { - if (currentPlayers[i].GetComponent().entity.IsOwner) - { - LocalPlayer_.p_GameObject = currentPlayers[i]; - break; - } - } - - // Wait 5 seconds before caching objects again. - yield return new WaitForSeconds(5f); - } - } - - public static IEnumerator GetAllPlayers() - { - while (true) - { - GameObject[] players = GameObject.FindGameObjectsWithTag("Player"); - Players = new BasePlayer[players.Length]; - - int i = 0; - foreach (GameObject p in players) - { - string player_name = ""; - string player_id = "-1"; - - Il2Cpp.DissonancePlayerTracking dpt = p.gameObject.GetComponent(); - if (dpt != null) - { - player_name = dpt.state.PlayerName; - player_id = dpt.state.PlayerId; - } - - if (Players[i] == null) - { - Players[i] = new BasePlayer(); - } - - Players[i].Id = player_id; - Players[i].Name = player_name; - Players[i].p_GameObject = p; - - i++; - } - - - // Wait 5 seconds before caching objects again. - yield return new WaitForSeconds(5f); - } - } - public static IEnumerator GetGoatsAndRats() - { - while (true) - { - GoatsAndRats = Il2Cpp.GoatBehaviour.FindObjectsOfType(); - - // Wait 5 seconds before caching objects again. - yield return new WaitForSeconds(5f); - } - } - - public static IEnumerator GetSurvivalInteractables() - { - while (true) - { - SurvivalInteractables = Il2Cpp.SurvivalInteractable.FindObjectsOfType(); - - // Wait 5 seconds before caching objects again. - yield return new WaitForSeconds(5f); - } - } - - public static IEnumerator GetKeys() - { - while (true) - { - Keys = Il2Cpp.KeyBehaviour.FindObjectsOfType(); - - // Wait 5 seconds before caching objects again. - yield return new WaitForSeconds(5f); - } - } - - public static IEnumerator GetDemons() - { - while (true) - { - Demons = Il2Cpp.SurvivalDemonBehaviour.FindObjectsOfType(); - - // Wait 5 seconds before caching objects again. - yield return new WaitForSeconds(5f); - } - } - - public static IEnumerator GetSpiders() - { - while (true) - { - Spiders = Il2Cpp.SpiderBehaviour.FindObjectsOfType(); - - // Wait 5 seconds before caching objects again. - yield return new WaitForSeconds(5f); - } - } - - public static IEnumerator GetGhosts() - { - while (true) - { - Ghosts = Il2Cpp.GhostBehaviour.FindObjectsOfType(); - - // Wait 5 seconds before caching objects again. - yield return new WaitForSeconds(5f); - } - } - - public static IEnumerator GetBoars() - { - while (true) - { - Boars = Il2Cpp.BoarBehaviour.FindObjectsOfType(); - - // Wait 5 seconds before caching objects again. - yield return new WaitForSeconds(5f); - } - } - - public static IEnumerator GetCorpses() - { - while (true) - { - Corpses = Il2Cpp.CorpseBehaviour.FindObjectsOfType(); - - // Wait 5 seconds before caching objects again. - yield return new WaitForSeconds(5f); - } - } - - public static IEnumerator GetCrows() - { - while (true) - { - Crows = Il2Cpp.CrowBehaviour.FindObjectsOfType(); - - // Wait 5 seconds before caching objects again. - yield return new WaitForSeconds(5f); - } - } - - public static IEnumerator GetLumps() - { - while (true) - { - Lumps = Il2Cpp.ManorLumpController.FindObjectsOfType(); - - // Wait 5 seconds before caching objects again. - yield return new WaitForSeconds(5f); - } - } - - public static IEnumerator GetAzazels() - { - /* - * ikr AzazelS, because in case we spawn multiple we want the esp to render all of them - */ - while (true) - { - Azazels = Il2Cpp.SurvivalAzazelBehaviour.FindObjectsOfType(); - - // Wait 5 seconds before caching objects again. - yield return new WaitForSeconds(5f); - } - } - } -} +using UnityEngine; +using Il2CppOpsive.UltimateCharacterController.Character; +using System.Collections.Generic; +using System.Collections; +using MelonLoader; +using Il2CppPhoton.Bolt; + +namespace DevourClient.Helpers +{ + public class BasePlayer + { + public GameObject p_GameObject { get; set; } = default!; + public string Name { get; set; } = default!; + public string Id { get; set; } = default!; + + public void Kill() + { + if (p_GameObject == null) + { + return; + } + + Il2Cpp.SurvivalAzazelBehaviour sab = Il2Cpp.SurvivalAzazelBehaviour.FindObjectOfType(); + + if (sab == null) + { + return; + } + + sab.OnKnockout(sab.gameObject, p_GameObject); + } + + public void Revive() + { + if (p_GameObject == null) + { + return; + } + + Il2Cpp.NolanBehaviour nb = p_GameObject.GetComponent(); + Il2Cpp.SurvivalReviveInteractable _reviveInteractable = UnityEngine.Object.FindObjectOfType(); + + if (_reviveInteractable.CanInteract(nb.gameObject) == true) { _reviveInteractable.Interact(nb.gameObject); } + + } + + public void Jumpscare() + { + if (!BoltNetwork.IsServer) + { + MelonLogger.Msg("You need to be server !"); + return; + } + + if (p_GameObject == null) + { + return; + } + + Il2Cpp.SurvivalAzazelBehaviour sab = Il2Cpp.SurvivalAzazelBehaviour.FindObjectOfType(); + + if (sab == null) + { + return; + } + + sab.OnPickedUpPlayer(sab.gameObject, p_GameObject, false); + + /* + MelonLogger.Msg(Name); + Il2Cpp.JumpScare _jumpscare = UnityEngine.Object.FindObjectOfType(); + _jumpscare.player = p_GameObject; + _jumpscare.Activate(p_GameObject.GetComponent()); + */ + } + + public void LockInCage() + { + if (p_GameObject == null) + { + return; + } + + BoltNetwork.Instantiate(BoltPrefabs.Cage, p_GameObject.transform.position, Quaternion.identity); + } + + public void TP() + { + if (p_GameObject == null) + { + return; + } + + Il2Cpp.NolanBehaviour nb = Player.GetPlayer(); + nb.TeleportTo(p_GameObject.transform.position, Quaternion.identity); + } + + public void TPAzazel() + { + if (p_GameObject == null) + { + return; + } + + UltimateCharacterLocomotion ucl = Helpers.Map.GetAzazel().GetComponent(); + + if (ucl) + { + ucl.SetPosition(p_GameObject.transform.position); + } + else + { + MelonLogger.Error("Azazel not found!"); + return; + } + } + + public void ShootPlayer() + { + if (!BoltNetwork.IsServer) + { + MelonLogger.Msg("You need to be server !"); + return; + } + + if (p_GameObject == null) + { + return; + } + + Il2Cpp.AzazelSamBehaviour _azazelSam = UnityEngine.Object.FindObjectOfType(); + + if (_azazelSam) + { + _azazelSam.OnShootPlayer(p_GameObject, true); + } + } + } + public class Player + { + public static bool IsInGame() + { + Il2Cpp.OptionsHelpers optionsHelpers = UnityEngine.Object.FindObjectOfType(); + return optionsHelpers.inGame; + } + + public static bool IsInGameOrLobby() + { + return GetPlayer() != null; + } + + public static Il2Cpp.NolanBehaviour GetPlayer() + { + if (Entities.LocalPlayer_.p_GameObject == null) + { + return null!; + } + + return Entities.LocalPlayer_.p_GameObject.GetComponent(); + } + + public static bool IsPlayerCrawling() + { + Il2Cpp.NolanBehaviour nb = Player.GetPlayer(); + + if (nb == null) + { + return false; + } + + return nb.IsCrawling(); + } + + } + + public class Entities + { + public static int MAX_PLAYERS = 4; //will change by calling CreateCustomizedLobby + + public static BasePlayer LocalPlayer_ = new BasePlayer(); + public static BasePlayer[] Players = default!; + public static Il2Cpp.GoatBehaviour[] GoatsAndRats = default!; + public static Il2Cpp.SurvivalInteractable[] SurvivalInteractables = default!; + public static Il2Cpp.KeyBehaviour[] Keys = default!; + public static Il2Cpp.SurvivalDemonBehaviour[] Demons = default!; + public static Il2Cpp.SpiderBehaviour[] Spiders = default!; + public static Il2Cpp.GhostBehaviour[] Ghosts = default!; + public static Il2Cpp.SurvivalAzazelBehaviour[] Azazels = default!; + public static Il2Cpp.BoarBehaviour[] Boars = default!; + public static Il2Cpp.CorpseBehaviour[] Corpses = default!; + public static Il2Cpp.CrowBehaviour[] Crows = default!; + public static Il2Cpp.ManorLumpController[] Lumps = default!; + public static Il2Cpp.MonkeyBehaviour[] Monkeys = default!; + + // 协程生命周期管理 + private static List activeCoroutines = new List(); + private static bool isRunning = false; + + public static IEnumerator GetLocalPlayer() + { + while (isRunning) + { + GameObject[] currentPlayers = GameObject.FindGameObjectsWithTag("Player"); + + for (int i = 0; i < currentPlayers.Length; i++) + { + if (currentPlayers[i].GetComponent().entity.IsOwner) + { + LocalPlayer_.p_GameObject = currentPlayers[i]; + break; + } + } + + // Wait 5 seconds before caching objects again. + yield return new WaitForSeconds(5f); + } + } + + public static IEnumerator GetAllPlayers() + { + while (isRunning) + { + GameObject[] players = GameObject.FindGameObjectsWithTag("Player"); + Players = new BasePlayer[players.Length]; + + int i = 0; + foreach (GameObject p in players) + { + string player_name = ""; + string player_id = "-1"; + + Il2Cpp.DissonancePlayerTracking dpt = p.gameObject.GetComponent(); + if (dpt != null) + { + player_name = dpt.state.PlayerName; + player_id = dpt.state.PlayerId; + } + + if (Players[i] == null) + { + Players[i] = new BasePlayer(); + } + + Players[i].Id = player_id; + Players[i].Name = player_name; + Players[i].p_GameObject = p; + + i++; + } + + + // Wait 5 seconds before caching objects again. + yield return new WaitForSeconds(5f); + } + } + public static IEnumerator GetGoatsAndRats() + { + while (isRunning) + { + GoatsAndRats = Il2Cpp.GoatBehaviour.FindObjectsOfType(); + + // Wait 5 seconds before caching objects again. + yield return new WaitForSeconds(5f); + } + } + + public static IEnumerator GetSurvivalInteractables() + { + while (isRunning) + { + SurvivalInteractables = Il2Cpp.SurvivalInteractable.FindObjectsOfType(); + + // Wait 5 seconds before caching objects again. + yield return new WaitForSeconds(5f); + } + } + + public static IEnumerator GetKeys() + { + while (isRunning) + { + Keys = Il2Cpp.KeyBehaviour.FindObjectsOfType(); + + // Wait 5 seconds before caching objects again. + yield return new WaitForSeconds(5f); + } + } + + public static IEnumerator GetDemons() + { + while (isRunning) + { + Demons = Il2Cpp.SurvivalDemonBehaviour.FindObjectsOfType(); + + // Wait 5 seconds before caching objects again. + yield return new WaitForSeconds(5f); + } + } + + public static IEnumerator GetSpiders() + { + while (isRunning) + { + Spiders = Il2Cpp.SpiderBehaviour.FindObjectsOfType(); + + // Wait 5 seconds before caching objects again. + yield return new WaitForSeconds(5f); + } + } + + public static IEnumerator GetGhosts() + { + while (isRunning) + { + Ghosts = Il2Cpp.GhostBehaviour.FindObjectsOfType(); + + // Wait 5 seconds before caching objects again. + yield return new WaitForSeconds(5f); + } + } + + public static IEnumerator GetBoars() + { + while (isRunning) + { + Boars = Il2Cpp.BoarBehaviour.FindObjectsOfType(); + + // Wait 5 seconds before caching objects again. + yield return new WaitForSeconds(5f); + } + } + + public static IEnumerator GetCorpses() + { + while (isRunning) + { + Corpses = Il2Cpp.CorpseBehaviour.FindObjectsOfType(); + + // Wait 5 seconds before caching objects again. + yield return new WaitForSeconds(5f); + } + } + + public static IEnumerator GetCrows() + { + while (isRunning) + { + Crows = Il2Cpp.CrowBehaviour.FindObjectsOfType(); + + // Wait 5 seconds before caching objects again. + yield return new WaitForSeconds(5f); + } + } + + public static IEnumerator GetLumps() + { + while (isRunning) + { + Lumps = Il2Cpp.ManorLumpController.FindObjectsOfType(); + + // Wait 5 seconds before caching objects again. + yield return new WaitForSeconds(5f); + } + } + + public static IEnumerator GetMonkeys() + { + while (isRunning) + { + Monkeys = Il2Cpp.MonkeyBehaviour.FindObjectsOfType(); + + // Wait 5 seconds before caching objects again. + yield return new WaitForSeconds(5f); + } + } + + public static IEnumerator GetAzazels() + { + /* + * ikr AzazelS, because in case we spawn multiple we want the esp to render all of them + */ + while (isRunning) + { + Azazels = Il2Cpp.SurvivalAzazelBehaviour.FindObjectsOfType(); + + // Wait 5 seconds before caching objects again. + yield return new WaitForSeconds(5f); + } + } + + /// + /// 启动所有协程 + /// + public static void StartAllCoroutines() + { + isRunning = true; + } + + /// + /// 停止所有协程并清理协程引用 + /// + public static void StopAllCoroutines() + { + try + { + // 设置标志,让所有协程循环自然退出 + isRunning = false; + + // 停止所有记录的协程 + foreach (var coroutine in activeCoroutines) + { + if (coroutine != null) + { + MelonCoroutines.Stop(coroutine); + } + } + + // 清空协程引用列表 + activeCoroutines.Clear(); + + // 清理缓存对象 + CleanupCachedObjects(); + + MelonLogger.Msg("All coroutines stopped and cleaned up successfully."); + } + catch (System.Exception ex) + { + MelonLogger.Error($"Error stopping coroutines: {ex.Message}"); + } + } + + /// + /// 清理所有缓存的游戏对象引用 + /// + public static void CleanupCachedObjects() + { + try + { + // 清理玩家对象引用 + if (Players != null) + { + foreach (var player in Players) + { + if (player != null) + { + player.p_GameObject = null; + } + } + } + + // 将所有实体数组设为null,释放对游戏对象的引用 + Players = null; + GoatsAndRats = null; + SurvivalInteractables = null; + Keys = null; + Demons = null; + Spiders = null; + Ghosts = null; + Azazels = null; + Boars = null; + Corpses = null; + Crows = null; + Lumps = null; + Monkeys = null; + + // 清理本地玩家引用 + if (LocalPlayer_ != null) + { + LocalPlayer_.p_GameObject = null; + } + + MelonLogger.Msg("Cached objects cleaned up successfully."); + } + catch (System.Exception ex) + { + MelonLogger.Error($"Error cleaning up cached objects: {ex.Message}"); + } + } + + /// + /// 注册协程引用用于后续管理 + /// + public static void RegisterCoroutine(object coroutine) + { + if (coroutine != null && !activeCoroutines.Contains(coroutine)) + { + activeCoroutines.Add(coroutine); + } + } + } +} diff --git a/README.md b/README.md index 8892167..b236913 100644 --- a/README.md +++ b/README.md @@ -25,8 +25,6 @@ Everything about spoofing ehre (steam name, server name, level...) will persist * Doors unlocker (should work fine, though it doesn't seem to work sometimes) * Keys teleporter * LV spoofer -* Steam name spoofer (sets it to "patate", again no input text :/) -* Server name spoofer (sets it to "patate on top !", again no input text :/) * Fly * Unlock all, including flashlights, perks, outfits. Active by default, can't be turned off, no persistance. * Instant Win (allows you to win instantaniously on any map, works in singleplayer, but not as a client. May be working as host) @@ -47,9 +45,9 @@ Everything about spoofing ehre (steam name, server name, level...) will persist * Walk in the lobby * Change the player's speed * Fullbright -* Create a lobby with no player limit * Infinite mirrors (Manor update) * Switch between realms (Manor update) +* Due to the game update, I deleted "Steam name spoofer", "Server name spoofer" and "Create a lobby with no player limit" these three functions.For "steam name spoofer", even changed your name by this function, your teamates can still see your name by steam profile, escape button, and your message in game. For "create a lobby with no player limit", if create a lobby with more than four players, the ghost will be stuck or some of the players will not be able to move. So I have to delete this function.(by manafeng) ## English Installation Tutorial @@ -70,6 +68,23 @@ In order to get all of this working you need to generate the DevourClient.dll fi 2. Put the DevourClient.dll file located in `DevourClient\bin\Release\net6.0` inside `C:\Program Files (x86)\Steam\steamapps\common\Devour\Mods` folder. 3. Start the game, now you have successfully installed DevourClient. Use INSERT to open the menu +## 中文安装指南 +如果你只是想要安装这个插件,直接在游戏里使用的话 + +1、安装 .net 6 的运行环境 → (https://dotnet.microsoft.com/en-us/download/dotnet/6.0) + +2、安装melonloader → (https://github.com/LavaGang/MelonLoader/releases) + 版本无限制,尽量选择新版即可。打开melonloader页面后,点击devour进入安装界面,全部默认即可,无需勾选或修改其他选项,点击install进行安装(安装过程中可能需要vpn支持) + +3、安装dll文件 → 从本项目的release中下载最新的dll文件,然后将此文件添加到你的devour的安装目录中的mods文件夹里(不知道目录的情况下,可以在steam中右键devour,选择“管理”-“浏览本地文件”即可) + +4、运行devour → 如果安装成功,你会看到一个windows窗口进行各类安装提示后,自动进入游戏。点击insert键即可打开和关闭devourclient窗口 + +ps:有些电脑在安装melonloader之后,会出现fatal error的提示,这个我目前并没有碰到过。但是出现这个提示的主要原因,基本是melonloader安装过程中,提取到devour根目录的melonloader文件夹里的文件出现了问题,比较简单的解决办法就是(1)在别人的同系统同位宽(x86,x32)的电脑里拷贝出来他的melonloader文件夹,然后直接粘贴到自己的电脑里。(2)将melonloader文件夹完全删除,然后重装。 + +如果你想要对代码进行修改和开发,请按照下面的”building from source“的步骤,逐步进行 + + ## Uninstallation 0. Delete the folders `MelonLoader`, `Mods`, `Plugins`, `UserData`, and the file `version.dll` from `C:\Program Files (x86)\Steam\steamapps\common\Devour` @@ -107,6 +122,7 @@ In order to get all of this working you need to generate the DevourClient.dll fi * `C:\Program Files (x86)\Steam\steamapps\common\Devour\MelonLoader\Il2CppAssemblies\UnityEngine.AnimationModule.dll` * `C:\Program Files (x86)\Steam\steamapps\common\Devour\MelonLoader\Il2CppAssemblies\UnityEngine.PhysicsModule.dll` * `C:\Program Files (x86)\Steam\steamapps\common\Devour\MelonLoader\Il2CppAssemblies\Il2Cppcom.rlabrecque.steamworks.net.dll` +* `C:\Program Files (x86)\Steam\steamapps\common\Devour\MelonLoader\Il2CppAssemblies\unity.TextMeshPro.dll` 8. Build the solutions in Release | Any CPU ## Contact @@ -141,3 +157,4 @@ Open an [issue](https://github.com/ALittlePatate/DevourClient/issues/new) or mak ## License [GPL 3.0](https://www.gnu.org/licenses/gpl-3.0.md) +