Merge pull request #85 from mana-feng/MelonLoader

fix crashed issue
This commit was merged in pull request #85.
This commit is contained in:
ALittlePatate
2025-10-13 21:28:44 +02:00
committed by GitHub
8 changed files with 1526 additions and 1079 deletions

View File

@@ -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<Il2CppOpsive.UltimateCharacterController.Character.UltimateCharacterLocomotion>().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}");
}
}
}
}

View File

@@ -12,4 +12,78 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<WarningLevel>0</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="0Harmony">
<HintPath>E:\SteamLibrary\steamapps\common\Devour\MelonLoader\net6\0Harmony.dll</HintPath>
</Reference>
<Reference Include="Assembly-CSharp">
<HintPath>E:\SteamLibrary\steamapps\common\Devour\MelonLoader\Il2CppAssemblies\Assembly-CSharp.dll</HintPath>
</Reference>
<Reference Include="Il2CppBehaviorDesigner.Runtime">
<HintPath>E:\SteamLibrary\steamapps\common\Devour\MelonLoader\Il2CppAssemblies\Il2CppBehaviorDesigner.Runtime.dll</HintPath>
</Reference>
<Reference Include="Il2Cppbolt">
<HintPath>E:\SteamLibrary\steamapps\common\Devour\MelonLoader\Il2CppAssemblies\Il2Cppbolt.dll</HintPath>
</Reference>
<Reference Include="Il2Cppbolt.user">
<HintPath>E:\SteamLibrary\steamapps\common\Devour\MelonLoader\Il2CppAssemblies\Il2Cppbolt.user.dll</HintPath>
</Reference>
<Reference Include="Il2Cppcom.rlabrecque.steamworks.net">
<HintPath>E:\SteamLibrary\steamapps\common\Devour\MelonLoader\Il2CppAssemblies\Il2Cppcom.rlabrecque.steamworks.net.dll</HintPath>
</Reference>
<Reference Include="Il2CppInterop.Runtime">
<HintPath>E:\SteamLibrary\steamapps\common\Devour\MelonLoader\net6\Il2CppInterop.Runtime.dll</HintPath>
</Reference>
<Reference Include="Il2Cppmscorlib">
<HintPath>E:\SteamLibrary\steamapps\common\Devour\MelonLoader\Il2CppAssemblies\Il2Cppmscorlib.dll</HintPath>
</Reference>
<Reference Include="Il2CppOpsive.UltimateCharacterController">
<HintPath>E:\SteamLibrary\steamapps\common\Devour\MelonLoader\Il2CppAssemblies\Il2CppOpsive.UltimateCharacterController.dll</HintPath>
</Reference>
<Reference Include="Il2Cppudpkit">
<HintPath>E:\SteamLibrary\steamapps\common\Devour\MelonLoader\Il2CppAssemblies\Il2Cppudpkit.dll</HintPath>
</Reference>
<Reference Include="Il2Cppudpkit.common">
<HintPath>E:\SteamLibrary\steamapps\common\Devour\MelonLoader\Il2CppAssemblies\Il2Cppudpkit.common.dll</HintPath>
</Reference>
<Reference Include="Il2Cppudpkit.platform.photon">
<HintPath>E:\SteamLibrary\steamapps\common\Devour\MelonLoader\Il2CppAssemblies\Il2Cppudpkit.platform.photon.dll</HintPath>
</Reference>
<Reference Include="MelonLoader">
<HintPath>E:\SteamLibrary\steamapps\common\Devour\MelonLoader\net6\MelonLoader.dll</HintPath>
</Reference>
<Reference Include="UnityEngine">
<HintPath>E:\SteamLibrary\steamapps\common\Devour\MelonLoader\Il2CppAssemblies\UnityEngine.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.AnimationModule">
<HintPath>E:\SteamLibrary\steamapps\common\Devour\MelonLoader\Il2CppAssemblies\UnityEngine.AnimationModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.CoreModule">
<HintPath>E:\SteamLibrary\steamapps\common\Devour\MelonLoader\Il2CppAssemblies\UnityEngine.CoreModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.HotReloadModule">
<HintPath>E:\SteamLibrary\steamapps\common\Devour\MelonLoader\Il2CppAssemblies\UnityEngine.HotReloadModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.IMGUIModule">
<HintPath>E:\SteamLibrary\steamapps\common\Devour\MelonLoader\Il2CppAssemblies\UnityEngine.IMGUIModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.InputLegacyModule">
<HintPath>E:\SteamLibrary\steamapps\common\Devour\MelonLoader\Il2CppAssemblies\UnityEngine.InputLegacyModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.InputModule">
<HintPath>E:\SteamLibrary\steamapps\common\Devour\MelonLoader\Il2CppAssemblies\UnityEngine.InputModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.PhysicsModule">
<HintPath>E:\SteamLibrary\steamapps\common\Devour\MelonLoader\Il2CppAssemblies\UnityEngine.PhysicsModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.UI">
<HintPath>E:\SteamLibrary\steamapps\common\Devour\MelonLoader\Il2CppAssemblies\UnityEngine.UI.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.UIModule">
<HintPath>E:\SteamLibrary\steamapps\common\Devour\MelonLoader\Il2CppAssemblies\UnityEngine.UIModule.dll</HintPath>
</Reference>
<Reference Include="Unity.TextMeshPro">
<HintPath>E:\SteamLibrary\steamapps\common\Devour\MelonLoader\Il2CppAssemblies\Unity.TextMeshPro.dll</HintPath>
</Reference>
</ItemGroup>
</Project>

File diff suppressed because it is too large Load Diff

View File

@@ -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<Color, Texture2D> colorTextureCache = new Dictionary<Color, Texture2D>();
private static Dictionary<int, Texture2D> circularTextureCache = new Dictionary<int, Texture2D>();
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();
}
}
}

View File

@@ -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";
}

View File

@@ -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<string, Vector2> sizeCache = new Dictionary<string, Vector2>();
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;
}

View File

@@ -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<Il2Cpp.SurvivalAzazelBehaviour>();
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.NolanBehaviour>();
Il2Cpp.SurvivalReviveInteractable _reviveInteractable = UnityEngine.Object.FindObjectOfType<Il2Cpp.SurvivalReviveInteractable>();
_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<Il2Cpp.SurvivalAzazelBehaviour>();
if (sab == null)
{
return;
}
sab.OnPickedUpPlayer(sab.gameObject, p_GameObject, false);
/*
MelonLogger.Msg(Name);
Il2Cpp.JumpScare _jumpscare = UnityEngine.Object.FindObjectOfType<Il2Cpp.JumpScare>();
_jumpscare.player = p_GameObject;
_jumpscare.Activate(p_GameObject.GetComponent<BoltEntity>());
*/
}
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<UltimateCharacterLocomotion>();
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<Il2Cpp.AzazelSamBehaviour>();
if (_azazelSam)
{
_azazelSam.OnShootPlayer(p_GameObject, true);
}
}
}
public class Player
{
public static bool IsInGame()
{
Il2Cpp.OptionsHelpers optionsHelpers = UnityEngine.Object.FindObjectOfType<Il2Cpp.OptionsHelpers>();
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<Il2Cpp.NolanBehaviour>();
}
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<Il2Cpp.NolanBehaviour>().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<Il2Cpp.DissonancePlayerTracking>();
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<Il2Cpp.GoatBehaviour>();
// Wait 5 seconds before caching objects again.
yield return new WaitForSeconds(5f);
}
}
public static IEnumerator GetSurvivalInteractables()
{
while (true)
{
SurvivalInteractables = Il2Cpp.SurvivalInteractable.FindObjectsOfType<Il2Cpp.SurvivalInteractable>();
// Wait 5 seconds before caching objects again.
yield return new WaitForSeconds(5f);
}
}
public static IEnumerator GetKeys()
{
while (true)
{
Keys = Il2Cpp.KeyBehaviour.FindObjectsOfType<Il2Cpp.KeyBehaviour>();
// Wait 5 seconds before caching objects again.
yield return new WaitForSeconds(5f);
}
}
public static IEnumerator GetDemons()
{
while (true)
{
Demons = Il2Cpp.SurvivalDemonBehaviour.FindObjectsOfType<Il2Cpp.SurvivalDemonBehaviour>();
// Wait 5 seconds before caching objects again.
yield return new WaitForSeconds(5f);
}
}
public static IEnumerator GetSpiders()
{
while (true)
{
Spiders = Il2Cpp.SpiderBehaviour.FindObjectsOfType<Il2Cpp.SpiderBehaviour>();
// Wait 5 seconds before caching objects again.
yield return new WaitForSeconds(5f);
}
}
public static IEnumerator GetGhosts()
{
while (true)
{
Ghosts = Il2Cpp.GhostBehaviour.FindObjectsOfType<Il2Cpp.GhostBehaviour>();
// Wait 5 seconds before caching objects again.
yield return new WaitForSeconds(5f);
}
}
public static IEnumerator GetBoars()
{
while (true)
{
Boars = Il2Cpp.BoarBehaviour.FindObjectsOfType<Il2Cpp.BoarBehaviour>();
// Wait 5 seconds before caching objects again.
yield return new WaitForSeconds(5f);
}
}
public static IEnumerator GetCorpses()
{
while (true)
{
Corpses = Il2Cpp.CorpseBehaviour.FindObjectsOfType<Il2Cpp.CorpseBehaviour>();
// Wait 5 seconds before caching objects again.
yield return new WaitForSeconds(5f);
}
}
public static IEnumerator GetCrows()
{
while (true)
{
Crows = Il2Cpp.CrowBehaviour.FindObjectsOfType<Il2Cpp.CrowBehaviour>();
// Wait 5 seconds before caching objects again.
yield return new WaitForSeconds(5f);
}
}
public static IEnumerator GetLumps()
{
while (true)
{
Lumps = Il2Cpp.ManorLumpController.FindObjectsOfType<Il2Cpp.ManorLumpController>();
// 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<Il2Cpp.SurvivalAzazelBehaviour>();
// 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<Il2Cpp.SurvivalAzazelBehaviour>();
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.NolanBehaviour>();
Il2Cpp.SurvivalReviveInteractable _reviveInteractable = UnityEngine.Object.FindObjectOfType<Il2Cpp.SurvivalReviveInteractable>();
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<Il2Cpp.SurvivalAzazelBehaviour>();
if (sab == null)
{
return;
}
sab.OnPickedUpPlayer(sab.gameObject, p_GameObject, false);
/*
MelonLogger.Msg(Name);
Il2Cpp.JumpScare _jumpscare = UnityEngine.Object.FindObjectOfType<Il2Cpp.JumpScare>();
_jumpscare.player = p_GameObject;
_jumpscare.Activate(p_GameObject.GetComponent<BoltEntity>());
*/
}
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<UltimateCharacterLocomotion>();
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<Il2Cpp.AzazelSamBehaviour>();
if (_azazelSam)
{
_azazelSam.OnShootPlayer(p_GameObject, true);
}
}
}
public class Player
{
public static bool IsInGame()
{
Il2Cpp.OptionsHelpers optionsHelpers = UnityEngine.Object.FindObjectOfType<Il2Cpp.OptionsHelpers>();
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<Il2Cpp.NolanBehaviour>();
}
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<object> activeCoroutines = new List<object>();
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<Il2Cpp.NolanBehaviour>().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<Il2Cpp.DissonancePlayerTracking>();
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<Il2Cpp.GoatBehaviour>();
// Wait 5 seconds before caching objects again.
yield return new WaitForSeconds(5f);
}
}
public static IEnumerator GetSurvivalInteractables()
{
while (isRunning)
{
SurvivalInteractables = Il2Cpp.SurvivalInteractable.FindObjectsOfType<Il2Cpp.SurvivalInteractable>();
// Wait 5 seconds before caching objects again.
yield return new WaitForSeconds(5f);
}
}
public static IEnumerator GetKeys()
{
while (isRunning)
{
Keys = Il2Cpp.KeyBehaviour.FindObjectsOfType<Il2Cpp.KeyBehaviour>();
// Wait 5 seconds before caching objects again.
yield return new WaitForSeconds(5f);
}
}
public static IEnumerator GetDemons()
{
while (isRunning)
{
Demons = Il2Cpp.SurvivalDemonBehaviour.FindObjectsOfType<Il2Cpp.SurvivalDemonBehaviour>();
// Wait 5 seconds before caching objects again.
yield return new WaitForSeconds(5f);
}
}
public static IEnumerator GetSpiders()
{
while (isRunning)
{
Spiders = Il2Cpp.SpiderBehaviour.FindObjectsOfType<Il2Cpp.SpiderBehaviour>();
// Wait 5 seconds before caching objects again.
yield return new WaitForSeconds(5f);
}
}
public static IEnumerator GetGhosts()
{
while (isRunning)
{
Ghosts = Il2Cpp.GhostBehaviour.FindObjectsOfType<Il2Cpp.GhostBehaviour>();
// Wait 5 seconds before caching objects again.
yield return new WaitForSeconds(5f);
}
}
public static IEnumerator GetBoars()
{
while (isRunning)
{
Boars = Il2Cpp.BoarBehaviour.FindObjectsOfType<Il2Cpp.BoarBehaviour>();
// Wait 5 seconds before caching objects again.
yield return new WaitForSeconds(5f);
}
}
public static IEnumerator GetCorpses()
{
while (isRunning)
{
Corpses = Il2Cpp.CorpseBehaviour.FindObjectsOfType<Il2Cpp.CorpseBehaviour>();
// Wait 5 seconds before caching objects again.
yield return new WaitForSeconds(5f);
}
}
public static IEnumerator GetCrows()
{
while (isRunning)
{
Crows = Il2Cpp.CrowBehaviour.FindObjectsOfType<Il2Cpp.CrowBehaviour>();
// Wait 5 seconds before caching objects again.
yield return new WaitForSeconds(5f);
}
}
public static IEnumerator GetLumps()
{
while (isRunning)
{
Lumps = Il2Cpp.ManorLumpController.FindObjectsOfType<Il2Cpp.ManorLumpController>();
// Wait 5 seconds before caching objects again.
yield return new WaitForSeconds(5f);
}
}
public static IEnumerator GetMonkeys()
{
while (isRunning)
{
Monkeys = Il2Cpp.MonkeyBehaviour.FindObjectsOfType<Il2Cpp.MonkeyBehaviour>();
// 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<Il2Cpp.SurvivalAzazelBehaviour>();
// Wait 5 seconds before caching objects again.
yield return new WaitForSeconds(5f);
}
}
/// <summary>
/// 启动所有协程
/// </summary>
public static void StartAllCoroutines()
{
isRunning = true;
}
/// <summary>
/// 停止所有协程并清理协程引用
/// </summary>
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}");
}
}
/// <summary>
/// 清理所有缓存的游戏对象引用
/// </summary>
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}");
}
}
/// <summary>
/// 注册协程引用用于后续管理
/// </summary>
public static void RegisterCoroutine(object coroutine)
{
if (coroutine != null && !activeCoroutines.Contains(coroutine))
{
activeCoroutines.Add(coroutine);
}
}
}
}

View File

@@ -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在别人的同系统同位宽x86x32的电脑里拷贝出来他的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)