using System; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using GameNetcodeStuff; using HarmonyLib; using Unity.Netcode; using UnityEngine; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("DozerEntity")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("DozerEntity")] [assembly: AssemblyCopyright("Copyright © 2026")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("707b5311-bc50-4ec1-ac25-901818a7c6a1")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyVersion("1.0.0.0")] namespace DozerEntity; public class DozerBehaviour : MonoBehaviour { private enum DozerState { Hidden, ClosedEyes, OpenEyes, Screamer } private DozerState currentState = DozerState.Hidden; private float timer = 0f; private float nextAppearTime = 0f; private float cooldownTimer = 0f; private float cooldownTime = 0f; private bool isOnCooldown = false; private float previousVolume = 1f; private GameObject overlayObject; private Image overlayImage; private Image blackBackground; private GameObject textObject; private Image textImage; private Sprite[] textSprites = (Sprite[])(object)new Sprite[25]; private float textAnimTimer = 0f; private int textAnimFrame = 0; private bool textAnimStarted = false; private AudioClip openSound; private AudioClip killSound; private AudioSource audioSource; private AudioClip closedSound; private Sprite[] closedSprites = (Sprite[])(object)new Sprite[14]; private Sprite[] openSprites = (Sprite[])(object)new Sprite[14]; private Sprite[] screamerSprites = (Sprite[])(object)new Sprite[50]; private float animTimer = 0f; private int animFrame = 0; private float animSpeed = 0.0667f; private string modFolder; private AudioClip LoadAudioClip(string filename) { //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Expected O, but got Unknown string text = Path.Combine(modFolder, filename); if (!File.Exists(text)) { Debug.LogError((object)("Dozer Entity: звук не найден — " + text)); return null; } WWW val = new WWW("file://" + text); try { while (!val.isDone) { } return val.GetAudioClip(false, false, (AudioType)20); } finally { ((IDisposable)val)?.Dispose(); } } private void Start() { string pluginPath = Paths.PluginPath; string[] directories = Directory.GetDirectories(pluginPath, "DozerEntity", SearchOption.AllDirectories); if (directories.Length != 0) { modFolder = directories[0]; } else { modFolder = Path.Combine(pluginPath, "DozerEntity"); } Debug.Log((object)("Dozer Entity: папка мода — " + modFolder)); LoadSprites(); closedSound = LoadAudioClip("closed_sound.wav"); openSound = LoadAudioClip("open_sound.wav"); killSound = LoadAudioClip("kill_sound.wav"); audioSource = ((Component)this).gameObject.AddComponent(); audioSource.loop = true; audioSource.volume = 1f; CreateOverlay(); nextAppearTime = Random.Range(Plugin.MinSpawnTime.Value, Plugin.MaxSpawnTime.Value); } private void LoadSprites() { for (int i = 0; i < 14; i++) { closedSprites[i] = LoadSprite("Closed_eyes" + (i + 1).ToString("D4") + ".png"); } for (int j = 0; j < 14; j++) { openSprites[j] = LoadSprite("Opened_eyes" + (j + 1).ToString("D4") + ".png"); } for (int k = 0; k < 50; k++) { screamerSprites[k] = LoadSprite("Kill" + (k + 1).ToString("D4") + ".png"); } for (int l = 0; l < 25; l++) { textSprites[l] = LoadSprite($"text{l + 1}.png"); } } public void ForceHide() { currentState = DozerState.Hidden; timer = 0f; overlayObject.SetActive(false); ((Component)blackBackground).gameObject.SetActive(false); AudioListener.volume = previousVolume; isOnCooldown = false; audioSource.Stop(); } private Sprite LoadSprite(string filename) { //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Expected O, but got Unknown //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) string text = Path.Combine(modFolder, filename); if (!File.Exists(text)) { Debug.LogError((object)("Dozer Entity: файл не найден — " + text)); return null; } byte[] array = File.ReadAllBytes(text); Texture2D val = new Texture2D(2, 2); ImageConversion.LoadImage(val, array); return Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f)); } private void Update() { PlayerControllerB val = GameNetworkManager.Instance?.localPlayerController; if ((Object)(object)val == (Object)null) { return; } if (currentState == DozerState.Hidden || currentState == DozerState.ClosedEyes || currentState == DozerState.OpenEyes) { previousVolume = AudioListener.volume; } if (isOnCooldown) { cooldownTimer += Time.deltaTime; if (cooldownTimer >= cooldownTime) { isOnCooldown = false; cooldownTimer = 0f; timer = 0f; nextAppearTime = Random.Range(Plugin.MinSpawnTime.Value, Plugin.MaxSpawnTime.Value); } } else if (val.isPlayerDead) { if (currentState != 0) { overlayObject.SetActive(false); ((Component)blackBackground).gameObject.SetActive(false); audioSource.Stop(); currentState = DozerState.Hidden; timer = 0f; isOnCooldown = false; } } else { if (!IsPlayerInGame()) { return; } if (val.quickMenuManager.isMenuOpen) { overlayObject.SetActive(false); ((Component)blackBackground).gameObject.SetActive(false); return; } timer += Time.deltaTime; switch (currentState) { case DozerState.Hidden: if (isOnCooldown) { cooldownTimer += Time.deltaTime; if (cooldownTimer >= cooldownTime) { isOnCooldown = false; cooldownTimer = 0f; timer = 0f; nextAppearTime = Random.Range(Plugin.MinSpawnTime.Value, Plugin.MaxSpawnTime.Value); } } else if (timer >= nextAppearTime) { ShowClosedEyes(); } break; case DozerState.ClosedEyes: AnimateClosed(); if (timer >= Plugin.EyeOpenDelay.Value) { OpenEyes(); } break; case DozerState.OpenEyes: AnimateOpen(); if (timer >= 0.1f && !IsPlayerSafe()) { TriggerScreamer(); } else if (timer >= Plugin.OpenEyesDuration.Value) { Hide(); } break; case DozerState.Screamer: AnimateScreamer(); AnimateText(); if (timer >= 2.05f) { KillPlayer(); } break; } } } private void AnimateClosed() { if (currentState != DozerState.ClosedEyes) { return; } animTimer += Time.deltaTime; if (animTimer >= animSpeed) { animTimer = 0f; animFrame = (animFrame + 1) % 14; if ((Object)(object)closedSprites[animFrame] != (Object)null) { overlayImage.sprite = closedSprites[animFrame]; } } } private void AnimateScreamer() { animTimer += Time.deltaTime; if (animTimer >= 0.05f) { animTimer = 0f; animFrame++; if (animFrame >= 50) { overlayObject.SetActive(false); } else if ((Object)(object)screamerSprites[animFrame] != (Object)null) { overlayImage.sprite = screamerSprites[animFrame]; } } } private void AnimateOpen() { animTimer += Time.deltaTime; if (animTimer >= 0.05f) { animTimer = 0f; animFrame = (animFrame + 1) % 14; if ((Object)(object)openSprites[animFrame] != (Object)null) { overlayImage.sprite = openSprites[animFrame]; } } } private void ShowClosedEyes() { currentState = DozerState.ClosedEyes; timer = 0f; animFrame = 0; animTimer = 0f; overlayObject.SetActive(true); if ((Object)(object)closedSprites[0] != (Object)null) { overlayImage.sprite = closedSprites[0]; } if ((Object)(object)closedSound != (Object)null) { audioSource.loop = true; audioSource.clip = closedSound; audioSource.Play(); } } private void OpenEyes() { currentState = DozerState.OpenEyes; timer = 0f; animFrame = 0; animTimer = 0f; if ((Object)(object)openSound != (Object)null) { audioSource.loop = false; audioSource.clip = openSound; audioSource.Play(); } if ((Object)(object)openSprites[0] != (Object)null) { overlayImage.sprite = openSprites[0]; } } private void TriggerScreamer() { currentState = DozerState.Screamer; timer = 0f; animFrame = 0; animTimer = 0f; textAnimFrame = 0; textAnimTimer = 0f; textAnimStarted = false; if ((Object)(object)textSprites[0] != (Object)null) { textImage.sprite = textSprites[0]; } textObject.SetActive(true); AudioSource val = ((Component)this).gameObject.AddComponent(); val.loop = false; val.volume = 1f; if ((Object)(object)killSound != (Object)null) { val.clip = killSound; val.Play(); } AudioSource[] array = Object.FindObjectsOfType(); AudioSource[] array2 = array; foreach (AudioSource val2 in array2) { if ((Object)(object)val2 != (Object)(object)val && (Object)(object)val2 != (Object)(object)audioSource) { val2.mute = true; } } ((Component)blackBackground).gameObject.SetActive(true); overlayObject.SetActive(false); overlayObject.SetActive(true); if ((Object)(object)screamerSprites[0] != (Object)null) { overlayImage.sprite = screamerSprites[0]; } } private void AnimateText() { textAnimTimer += Time.deltaTime; if (!textAnimStarted && textAnimTimer >= 1.5f) { textAnimStarted = true; textAnimTimer = 0f; textAnimFrame = 1; } if (!textAnimStarted) { return; } textAnimTimer += Time.deltaTime; if (textAnimTimer >= 0.0667f) { textAnimTimer = 0f; textAnimFrame++; if (textAnimFrame < 25 && (Object)(object)textSprites[textAnimFrame] != (Object)null) { textImage.sprite = textSprites[textAnimFrame]; } } } public void ResetDozer() { currentState = DozerState.Hidden; timer = 0f; nextAppearTime = Random.Range(Plugin.MinSpawnTime.Value, Plugin.MaxSpawnTime.Value); overlayObject.SetActive(false); } private void Hide() { currentState = DozerState.Hidden; timer = 0f; overlayObject.SetActive(false); ((Component)blackBackground).gameObject.SetActive(false); isOnCooldown = true; cooldownTimer = 0f; nextAppearTime = Random.Range(Plugin.MinSpawnTime.Value, Plugin.MaxSpawnTime.Value); audioSource.Stop(); } private void KillPlayer() { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) PlayerControllerB localPlayerController = GameNetworkManager.Instance.localPlayerController; if ((Object)(object)localPlayerController != (Object)null) { localPlayerController.KillPlayer(Vector3.zero, true, (CauseOfDeath)0, 1, default(Vector3), false); } AudioListener.volume = previousVolume; overlayObject.SetActive(false); ((Component)blackBackground).gameObject.SetActive(false); audioSource.Stop(); textObject.SetActive(false); currentState = DozerState.Hidden; timer = 0f; isOnCooldown = false; AudioSource[] array = Object.FindObjectsOfType(); AudioSource[] array2 = array; foreach (AudioSource val in array2) { val.mute = false; } } private bool IsPlayerSafe() { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) PlayerControllerB val = GameNetworkManager.Instance?.localPlayerController; if ((Object)(object)val == (Object)null) { return true; } bool isCrouching = val.isCrouching; Vector3 velocity = val.thisController.velocity; bool flag = ((Vector3)(ref velocity)).magnitude > 0.1f; return isCrouching && !flag; } private bool IsPlayerInGame() { PlayerControllerB val = GameNetworkManager.Instance?.localPlayerController; if ((Object)(object)val == (Object)null) { return false; } if (val.isPlayerDead) { return false; } if (StartOfRound.Instance?.currentLevel?.sceneName == "CompanyBuilding") { return false; } return !val.isInHangarShipRoom && (Object)(object)StartOfRound.Instance != (Object)null && StartOfRound.Instance.shipHasLanded; } private void CreateOverlay() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected O, but got Unknown //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Expected O, but got Unknown //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Expected O, but got Unknown //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Expected O, but got Unknown //IL_0187: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Unknown result type (might be due to invalid IL or missing references) //IL_01b5: Unknown result type (might be due to invalid IL or missing references) //IL_01cc: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("DozerCanvas"); Canvas val2 = val.AddComponent(); val2.renderMode = (RenderMode)0; val2.sortingOrder = 100; Object.DontDestroyOnLoad((Object)(object)val); GameObject val3 = new GameObject("DozerBlackBg"); val3.transform.SetParent(val.transform, false); blackBackground = val3.AddComponent(); ((Graphic)blackBackground).color = new Color(0f, 0f, 0f, 1f); RectTransform component = val3.GetComponent(); component.anchorMin = Vector2.zero; component.anchorMax = Vector2.one; component.sizeDelta = Vector2.zero; val3.SetActive(false); overlayObject = new GameObject("DozerImage"); overlayObject.transform.SetParent(val.transform, false); overlayImage = overlayObject.AddComponent(); RectTransform component2 = overlayObject.GetComponent(); component2.anchorMin = new Vector2(0.5f, 0.5f); component2.anchorMax = new Vector2(0.5f, 0.5f); component2.sizeDelta = new Vector2(600f, 600f); component2.anchoredPosition = Vector2.zero; GameObject val4 = new GameObject("DozerText"); val4.transform.SetParent(val.transform, false); textImage = val4.AddComponent(); RectTransform component3 = val4.GetComponent(); component3.anchorMin = new Vector2(0.5f, 0.5f); component3.anchorMax = new Vector2(0.5f, 0.5f); component3.sizeDelta = new Vector2(1000f, 1000f); component3.anchoredPosition = new Vector2(-320f, -60f); textObject = val4; textObject.SetActive(false); overlayObject.SetActive(false); } } [HarmonyPatch(typeof(PlayerControllerB), "Start")] public class DozerPatch { private static void Postfix(PlayerControllerB __instance) { //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Expected O, but got Unknown if (((NetworkBehaviour)__instance).IsOwner && !((Object)(object)Object.FindObjectOfType() != (Object)null)) { int num = Random.Range(0, 100); if (num >= Plugin.SpawnChance.Value) { Debug.Log((object)$"Dozer Entity: не появится в этом раунде (бросок {num}, нужно < {Plugin.SpawnChance.Value})"); return; } GameObject val = new GameObject("DozerManager"); val.AddComponent(); Object.DontDestroyOnLoad((Object)(object)val); Debug.Log((object)$"Dozer Entity: менеджер создан! (бросок {num})"); } } } [HarmonyPatch(typeof(PlayerControllerB), "SpawnDeadAnimation")] public class DozerRespawnPatch { private static void Postfix(PlayerControllerB __instance) { if (((NetworkBehaviour)__instance).IsOwner) { DozerBehaviour dozerBehaviour = Object.FindObjectOfType(); if ((Object)(object)dozerBehaviour != (Object)null) { dozerBehaviour.ResetDozer(); Debug.Log((object)"Dozer Entity: сброс после возрождения!"); } } } } [BepInPlugin("com.yourname.dozerentity", "Dozer Entity", "1.0.1")] public class Plugin : BaseUnityPlugin { [HarmonyPatch(typeof(PlayerControllerB), "KillPlayer")] public class DozerDeathPatch { private static void Postfix(PlayerControllerB __instance) { if (((NetworkBehaviour)__instance).IsOwner) { DozerBehaviour dozerBehaviour = Object.FindObjectOfType(); if ((Object)(object)dozerBehaviour != (Object)null) { dozerBehaviour.ForceHide(); } } } } private readonly Harmony harmony = new Harmony("com.yourname.dozerentity"); public static ConfigEntry SpawnChance; public static ConfigEntry EyeOpenDelay; public static ConfigEntry OpenEyesDuration; public static ConfigEntry MinSpawnTime; public static ConfigEntry MaxSpawnTime; private void Awake() { SpawnChance = ((BaseUnityPlugin)this).Config.Bind("General", "SpawnChance", 35, "Dozer appear chance each round (0-100)"); EyeOpenDelay = ((BaseUnityPlugin)this).Config.Bind("Timing", "EyeOpenDelay", 1.5f, "Time in seconds before Dozer opens it's eyes"); OpenEyesDuration = ((BaseUnityPlugin)this).Config.Bind("Timing", "OpenEyesDuration", 3f, "How long Dozer stays with open eyes in seconds"); MinSpawnTime = ((BaseUnityPlugin)this).Config.Bind("Timing", "MinSpawnTime", 10f, "Minimum time in seconds before Dozer appears"); MaxSpawnTime = ((BaseUnityPlugin)this).Config.Bind("Timing", "MaxSpawnTime", 30f, "Maximum time in seconds before Dozer appears"); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Dozer Entity загружен!"); harmony.PatchAll(); } }