Decompiled source of Dozer v1.0.2

BepInEx/plugins/DozerEntity.dll

Decompiled 6 months ago
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 AudioSource audioSource;

	private AudioClip closedSound;

	private Sprite[] closedSprites = (Sprite[])(object)new Sprite[2];

	private Sprite openSprite;

	private Sprite[] screamerSprites = (Sprite[])(object)new Sprite[6];

	private float animTimer = 0f;

	private int animFrame = 0;

	private float animSpeed = 0.3f;

	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");
		audioSource = ((Component)this).gameObject.AddComponent<AudioSource>();
		audioSource.loop = true;
		audioSource.volume = 1f;
		CreateOverlay();
		nextAppearTime = Random.Range(Plugin.MinSpawnTime.Value, Plugin.MaxSpawnTime.Value);
	}

	private void LoadSprites()
	{
		closedSprites[0] = LoadSprite("closed_1.png");
		closedSprites[1] = LoadSprite("closed_2.png");
		openSprite = LoadSprite("open.png");
		for (int i = 0; i < 6; i++)
		{
			screamerSprites[i] = LoadSprite($"screamer_{i + 1}.png");
		}
	}

	private 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:
				if (!IsPlayerSafe())
				{
					TriggerScreamer();
				}
				else if (timer >= Plugin.OpenEyesDuration.Value)
				{
					Hide();
				}
				break;
			case DozerState.Screamer:
				AnimateScreamer();
				if (timer >= 1.5f)
				{
					KillPlayer();
				}
				break;
			}
		}
	}

	private void AnimateClosed()
	{
		if (currentState != DozerState.ClosedEyes)
		{
			return;
		}
		animTimer += Time.deltaTime;
		if (animTimer >= animSpeed)
		{
			animTimer = 0f;
			animFrame = (animFrame + 1) % 2;
			if ((Object)(object)closedSprites[animFrame] != (Object)null)
			{
				overlayImage.sprite = closedSprites[animFrame];
			}
		}
	}

	private void AnimateScreamer()
	{
		animTimer += Time.deltaTime;
		if (animTimer >= 0.1f)
		{
			animTimer = 0f;
			animFrame++;
			if (animFrame >= 6)
			{
				overlayObject.SetActive(false);
			}
			else if ((Object)(object)screamerSprites[animFrame] != (Object)null)
			{
				overlayImage.sprite = screamerSprites[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.clip = closedSound;
			audioSource.Play();
		}
	}

	private void OpenEyes()
	{
		currentState = DozerState.OpenEyes;
		timer = 0f;
		animFrame = 0;
		animTimer = 0f;
		if ((Object)(object)openSprite != (Object)null)
		{
			overlayImage.sprite = openSprite;
		}
		audioSource.Stop();
	}

	private void TriggerScreamer()
	{
		currentState = DozerState.Screamer;
		timer = 0f;
		animFrame = 0;
		animTimer = 0f;
		previousVolume = AudioListener.volume;
		AudioListener.volume = 0f;
		((Component)blackBackground).gameObject.SetActive(true);
		overlayObject.SetActive(false);
		overlayObject.SetActive(true);
		if ((Object)(object)screamerSprites[0] != (Object)null)
		{
			overlayImage.sprite = screamerSprites[0];
		}
	}

	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));
		}
		AudioListener.volume = previousVolume;
		overlayObject.SetActive(false);
		((Component)blackBackground).gameObject.SetActive(false);
		audioSource.Stop();
		currentState = DozerState.Hidden;
		timer = 0f;
		isOnCooldown = 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;
		}
		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)
		GameObject val = new GameObject("DozerCanvas");
		Canvas val2 = val.AddComponent<Canvas>();
		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<Image>();
		((Graphic)blackBackground).color = new Color(0f, 0f, 0f, 1f);
		RectTransform component = val3.GetComponent<RectTransform>();
		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<Image>();
		RectTransform component2 = overlayObject.GetComponent<RectTransform>();
		component2.anchorMin = new Vector2(0.5f, 0.5f);
		component2.anchorMax = new Vector2(0.5f, 0.5f);
		component2.sizeDelta = new Vector2(400f, 400f);
		component2.anchoredPosition = Vector2.zero;
		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<DozerBehaviour>() != (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<DozerBehaviour>();
			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<DozerBehaviour>();
			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
{
	private readonly Harmony harmony = new Harmony("com.yourname.dozerentity");

	public static ConfigEntry<int> SpawnChance;

	public static ConfigEntry<float> EyeOpenDelay;

	public static ConfigEntry<float> OpenEyesDuration;

	public static ConfigEntry<float> MinSpawnTime;

	public static ConfigEntry<float> MaxSpawnTime;

	private void Awake()
	{
		SpawnChance = ((BaseUnityPlugin)this).Config.Bind<int>("General", "SpawnChance", 35, "Dozer appear chance each round (0-100)");
		EyeOpenDelay = ((BaseUnityPlugin)this).Config.Bind<float>("Timing", "EyeOpenDelay", 1.5f, "Time in seconds before Dozer opens it's eyes");
		OpenEyesDuration = ((BaseUnityPlugin)this).Config.Bind<float>("Timing", "OpenEyesDuration", 3f, "How long Dozer stays with open eyes in seconds");
		MinSpawnTime = ((BaseUnityPlugin)this).Config.Bind<float>("Timing", "MinSpawnTime", 10f, "Minimum time in seconds before Dozer appears");
		MaxSpawnTime = ((BaseUnityPlugin)this).Config.Bind<float>("Timing", "MaxSpawnTime", 30f, "Maximum time in seconds before Dozer appears");
		((BaseUnityPlugin)this).Logger.LogInfo((object)"Dozer Entity загружен!");
		harmony.PatchAll();
	}
}