Decompiled source of ZombieCrisis v1.0.0

plugins\ZombieCrisis.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Photon.Pun;
using UnityEngine;

[assembly: AssemblyTitle("ZombieCrisis")]
[assembly: AssemblyDescription("PEAK zombie crisis gameplay mod")]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = "")]
[assembly: ComVisible(false)]
[assembly: AssemblyCompany("PeakMods")]
[assembly: AssemblyProduct("ZombieCrisis")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: CompilationRelaxations(8)]
[assembly: Guid("A04AA9C8-CDE7-4D03-9197-4D29DA4E9BB9")]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyVersion("1.0.0.0")]
namespace ZombieCrisis;

[BepInPlugin("com.peakmods.zombiecrisis", "丧尸危机", "1.0.0")]
public sealed class ZombieCrisisPlugin : BaseUnityPlugin
{
	[HarmonyPatch(typeof(MushroomZombieSpawner), "Start")]
	private static class MushroomZombieSpawnerStartPatch
	{
		private static void Prefix(MushroomZombieSpawner __instance)
		{
			if ((Object)(object)_instance != (Object)null && (Object)(object)__instance != (Object)null)
			{
				_instance.CapturePrefab(__instance.mushroomZombiePrefab);
			}
		}
	}

	[HarmonyPatch(typeof(MushroomZombie), "Start")]
	private static class MushroomZombieStartPatch
	{
		private static void Postfix(MushroomZombie __instance)
		{
			TryAttachMarker(__instance);
		}
	}

	[HarmonyPatch(typeof(MushroomZombie), "Die")]
	private static class MushroomZombieDiePatch
	{
		private static bool Prefix(MushroomZombie __instance)
		{
			return !IsCrisisZombie(__instance);
		}
	}

	[HarmonyPatch(typeof(MushroomZombie), "set_currentState")]
	private static class MushroomZombieStatePatch
	{
		private static bool Prefix(MushroomZombie __instance, State value)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Invalid comparison between Unknown and I4
			if ((int)value == 6)
			{
				return !IsCrisisZombie(__instance);
			}
			return true;
		}
	}

	[HarmonyPatch(typeof(MushroomZombie), "ReadyToDisable")]
	private static class MushroomZombieReadyToDisablePatch
	{
		private static bool Prefix(MushroomZombie __instance, ref bool __result)
		{
			if (!IsCrisisZombie(__instance))
			{
				return true;
			}
			__result = false;
			return false;
		}
	}

	[HarmonyPatch(typeof(MushroomZombie), "DestroyZombie")]
	private static class MushroomZombieDestroyPatch
	{
		private static bool Prefix(MushroomZombie __instance)
		{
			return !IsCrisisZombie(__instance);
		}
	}

	public const string PluginGuid = "com.peakmods.zombiecrisis";

	public const string PluginName = "丧尸危机";

	public const string PluginVersion = "1.0.0";

	internal const string NetworkMarker = "ZombieCrisis:1";

	private const float MinimumSpawnRadius = 10f;

	private const float MaximumSpawnRadius = 16f;

	private const float GroundRayHeight = 14f;

	private const float GroundRayDistance = 36f;

	private const float SpawnRetryDelay = 2f;

	private const float PrefabSearchInterval = 2f;

	private static ZombieCrisisPlugin _instance;

	private readonly List<Character> _spawnTargets = new List<Character>();

	private Harmony _harmony;

	private ConfigEntry<int> _zombieCount;

	private ConfigEntry<float> _spawnDelay;

	private ConfigEntry<float> _sprintSpeedMultiplier;

	private string _zombiePrefabName;

	private int _activeRunInstanceId = int.MinValue;

	private int _spawnedCountForRun;

	private bool _spawnCompletedForRun;

	private bool _waitingForPrefabLogged;

	private float _nextPrefabSearchTime;

	private float _nextSpawnAttemptTime;

	private void Awake()
	{
		//IL_0012: Unknown result type (might be due to invalid IL or missing references)
		//IL_001c: Expected O, but got Unknown
		_instance = this;
		BindConfiguration();
		_harmony = new Harmony("com.peakmods.zombiecrisis");
		_harmony.PatchAll(typeof(ZombieCrisisPlugin).Assembly);
		((BaseUnityPlugin)this).Logger.LogInfo((object)"丧尸危机 1.0.0 已加载。丧尸将由房主按配置生成。");
	}

	private void BindConfiguration()
	{
		//IL_0025: Unknown result type (might be due to invalid IL or missing references)
		//IL_002f: Expected O, but got Unknown
		//IL_0064: Unknown result type (might be due to invalid IL or missing references)
		//IL_006e: Expected O, but got Unknown
		//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ad: Expected O, but got Unknown
		_zombieCount = ((BaseUnityPlugin)this).Config.Bind<int>("丧尸危机", "丧尸数量", 5, new ConfigDescription("每轮在玩家附近生成的模组丧尸总数。设为 0 可关闭本轮生成。", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 50), new object[0]));
		_spawnDelay = ((BaseUnityPlugin)this).Config.Bind<float>("丧尸危机", "生成延迟(秒)", 30f, new ConfigDescription("从本轮攀登开始到丧尸出现的等待时间,单位为秒。", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 900f), new object[0]));
		_sprintSpeedMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("丧尸危机", "奔跑速度倍率", 1.5f, new ConfigDescription("模组丧尸相对于原版丧尸的奔跑速度倍率。1.0 为原版速度。", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.25f, 5f), new object[0]));
	}

	private void Update()
	{
		TryFindZombiePrefab();
		if (!GameHandler.IsOnIslandAndInitialized || (Object)(object)RunManager.Instance == (Object)null)
		{
			return;
		}
		int instanceID = ((Object)RunManager.Instance).GetInstanceID();
		if (instanceID != _activeRunInstanceId)
		{
			BeginRun(instanceID);
		}
		if (_spawnCompletedForRun || !PhotonNetwork.IsMasterClient)
		{
			return;
		}
		int num = Mathf.Clamp(_zombieCount.Value, 0, 50);
		if (num == 0)
		{
			_spawnCompletedForRun = true;
			((BaseUnityPlugin)this).Logger.LogInfo((object)"本轮丧尸数量为 0,不生成丧尸。");
			return;
		}
		_spawnedCountForRun = Math.Max(_spawnedCountForRun, CrisisZombieMarker.ActiveCount);
		if (_spawnedCountForRun >= num)
		{
			_spawnCompletedForRun = true;
		}
		else
		{
			if (RunManager.Instance.TimeSinceRunStarted < Mathf.Max(0f, _spawnDelay.Value) || Time.unscaledTime < _nextSpawnAttemptTime)
			{
				return;
			}
			if (string.IsNullOrEmpty(_zombiePrefabName))
			{
				if (!_waitingForPrefabLogged)
				{
					((BaseUnityPlugin)this).Logger.LogWarning((object)"尚未找到原版 MushroomZombie Photon 预制体,将继续等待而不会破坏本轮游戏。");
					_waitingForPrefabLogged = true;
				}
				_nextSpawnAttemptTime = Time.unscaledTime + 2f;
				return;
			}
			RefreshSpawnTargets();
			if (_spawnTargets.Count == 0)
			{
				_nextSpawnAttemptTime = Time.unscaledTime + 2f;
				return;
			}
			int count = num - _spawnedCountForRun;
			int num2 = SpawnZombies(count);
			_spawnedCountForRun += num2;
			_nextSpawnAttemptTime = Time.unscaledTime + 2f;
			if (_spawnedCountForRun >= num)
			{
				_spawnCompletedForRun = true;
				((BaseUnityPlugin)this).Logger.LogInfo((object)("本轮丧尸危机已生成 " + _spawnedCountForRun + " 只不死丧尸。"));
			}
			else if (num2 == 0)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("本次未能生成丧尸,将在 " + 2f + " 秒后重试。"));
			}
		}
	}

	private void BeginRun(int runInstanceId)
	{
		_activeRunInstanceId = runInstanceId;
		_spawnedCountForRun = CrisisZombieMarker.ActiveCount;
		_spawnCompletedForRun = false;
		_waitingForPrefabLogged = false;
		_nextSpawnAttemptTime = 0f;
		((BaseUnityPlugin)this).Logger.LogInfo((object)("新一轮丧尸危机已待命:数量=" + _zombieCount.Value + ",延迟=" + _spawnDelay.Value.ToString("0.##") + " 秒,奔跑速度倍率=" + _sprintSpeedMultiplier.Value.ToString("0.##") + "。"));
	}

	private void TryFindZombiePrefab()
	{
		if (!string.IsNullOrEmpty(_zombiePrefabName) || Time.unscaledTime < _nextPrefabSearchTime)
		{
			return;
		}
		_nextPrefabSearchTime = Time.unscaledTime + 2f;
		MushroomZombieSpawner[] array = Resources.FindObjectsOfTypeAll<MushroomZombieSpawner>();
		foreach (MushroomZombieSpawner val in array)
		{
			if ((Object)(object)val != (Object)null && (Object)(object)val.mushroomZombiePrefab != (Object)null)
			{
				CapturePrefab(val.mushroomZombiePrefab);
				break;
			}
		}
	}

	private void CapturePrefab(MushroomZombie prefab)
	{
		if (!((Object)(object)prefab == (Object)null) && !((Object)(object)((Component)prefab).gameObject == (Object)null) && !string.IsNullOrEmpty(((Object)((Component)prefab).gameObject).name) && string.IsNullOrEmpty(_zombiePrefabName))
		{
			_zombiePrefabName = ((Object)((Component)prefab).gameObject).name;
			_waitingForPrefabLogged = false;
			((BaseUnityPlugin)this).Logger.LogInfo((object)("已捕获原版丧尸预制体:" + _zombiePrefabName));
		}
	}

	private void RefreshSpawnTargets()
	{
		_spawnTargets.Clear();
		List<Character> allPlayerCharacters = PlayerHandler.GetAllPlayerCharacters();
		if (allPlayerCharacters == null)
		{
			return;
		}
		for (int i = 0; i < allPlayerCharacters.Count; i++)
		{
			Character val = allPlayerCharacters[i];
			if (!((Object)(object)val == (Object)null) && val.IsPlayerControlled && !((Object)(object)val.data == (Object)null) && !val.data.dead && !val.IsGhost)
			{
				_spawnTargets.Add(val);
			}
		}
	}

	private int SpawnZombies(int count)
	{
		//IL_0084: Unknown result type (might be due to invalid IL or missing references)
		//IL_0086: Unknown result type (might be due to invalid IL or missing references)
		int num = 0;
		float num2 = Mathf.Clamp(_sprintSpeedMultiplier.Value, 0.25f, 5f);
		for (int i = 0; i < count; i++)
		{
			Character target = _spawnTargets[(_spawnedCountForRun + i) % _spawnTargets.Count];
			FindSpawnPose(target, _spawnedCountForRun + i, out var position, out var rotation);
			object[] array = new object[3] { "ZombieCrisis:1", "1.0.0", num2 };
			try
			{
				GameObject val = PhotonNetwork.Instantiate(_zombiePrefabName, position, rotation, (byte)0, array);
				MushroomZombie val2 = (((Object)(object)val != (Object)null) ? val.GetComponent<MushroomZombie>() : null);
				if ((Object)(object)val2 == (Object)null)
				{
					((BaseUnityPlugin)this).Logger.LogWarning((object)"Photon 已创建对象,但对象上没有 MushroomZombie 组件。");
					continue;
				}
				TryAttachMarker(val2);
				num++;
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)("生成丧尸失败:" + ex));
				break;
			}
		}
		return num;
	}

	private static void FindSpawnPose(Character target, int index, out Vector3 position, out Quaternion rotation)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_003b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0040: Unknown result type (might be due to invalid IL or missing references)
		//IL_0045: Unknown result type (might be due to invalid IL or missing references)
		//IL_004a: Unknown result type (might be due to invalid IL or missing references)
		//IL_004b: Unknown result type (might be due to invalid IL or missing references)
		//IL_004c: Unknown result type (might be due to invalid IL or missing references)
		//IL_004e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0053: Unknown result type (might be due to invalid IL or missing references)
		//IL_0058: Unknown result type (might be due to invalid IL or missing references)
		//IL_0062: Unknown result type (might be due to invalid IL or missing references)
		//IL_0067: Unknown result type (might be due to invalid IL or missing references)
		//IL_006c: Unknown result type (might be due to invalid IL or missing references)
		//IL_006e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0070: Unknown result type (might be due to invalid IL or missing references)
		//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
		//IL_0089: 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_0098: Unknown result type (might be due to invalid IL or missing references)
		//IL_009d: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
		//IL_0102: Unknown result type (might be due to invalid IL or missing references)
		//IL_0107: Unknown result type (might be due to invalid IL or missing references)
		//IL_010c: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
		//IL_0111: Unknown result type (might be due to invalid IL or missing references)
		Vector3 center = target.Center;
		float num = 51.42857f * (float)index + Random.Range(-18f, 18f);
		float num2 = Random.Range(10f, 16f);
		Vector3 val = Quaternion.Euler(0f, num, 0f) * Vector3.forward;
		Vector3 val2 = center + val * num2 + Vector3.up * 14f;
		RaycastHit val3 = default(RaycastHit);
		if (Physics.Raycast(val2, Vector3.down, ref val3, 36f, -5, (QueryTriggerInteraction)1))
		{
			position = ((RaycastHit)(ref val3)).point + Vector3.up * 0.35f;
		}
		else
		{
			position = center + val * num2 + Vector3.up * 0.5f;
		}
		Vector3 val4 = center - position;
		val4.y = 0f;
		rotation = ((((Vector3)(ref val4)).sqrMagnitude > 0.01f) ? Quaternion.LookRotation(((Vector3)(ref val4)).normalized, Vector3.up) : Quaternion.identity);
	}

	internal static bool IsCrisisZombie(MushroomZombie zombie)
	{
		if ((Object)(object)zombie == (Object)null)
		{
			return false;
		}
		CrisisZombieMarker component = ((Component)zombie).GetComponent<CrisisZombieMarker>();
		if ((Object)(object)component != (Object)null)
		{
			return true;
		}
		if (!TryReadNetworkMarker(zombie, out var speedMultiplier))
		{
			return false;
		}
		AttachMarker(zombie, speedMultiplier);
		return true;
	}

	private static void TryAttachMarker(MushroomZombie zombie)
	{
		if (TryReadNetworkMarker(zombie, out var speedMultiplier))
		{
			AttachMarker(zombie, speedMultiplier);
		}
	}

	private static void AttachMarker(MushroomZombie zombie, float speedMultiplier)
	{
		CrisisZombieMarker crisisZombieMarker = ((Component)zombie).GetComponent<CrisisZombieMarker>();
		if ((Object)(object)crisisZombieMarker == (Object)null)
		{
			crisisZombieMarker = ((Component)zombie).gameObject.AddComponent<CrisisZombieMarker>();
		}
		crisisZombieMarker.Initialize(zombie, speedMultiplier);
	}

	private static bool TryReadNetworkMarker(MushroomZombie zombie, out float speedMultiplier)
	{
		speedMultiplier = 1f;
		try
		{
			PhotonView photonView = ((MonoBehaviourPun)zombie).photonView;
			object[] array = (((Object)(object)photonView != (Object)null) ? photonView.InstantiationData : null);
			if (array == null || array.Length < 3 || !string.Equals(array[0] as string, "ZombieCrisis:1", StringComparison.Ordinal))
			{
				return false;
			}
			speedMultiplier = Convert.ToSingle(array[2]);
			speedMultiplier = Mathf.Clamp(speedMultiplier, 0.25f, 5f);
			return true;
		}
		catch (Exception ex)
		{
			if ((Object)(object)_instance != (Object)null)
			{
				((BaseUnityPlugin)_instance).Logger.LogWarning((object)("读取丧尸危机网络标记失败:" + ex.Message));
			}
			return false;
		}
	}

	private void OnDestroy()
	{
		if (_harmony != null)
		{
			_harmony.UnpatchSelf();
		}
		if ((Object)(object)_instance == (Object)(object)this)
		{
			_instance = null;
		}
	}
}
internal sealed class CrisisZombieMarker : MonoBehaviour
{
	private static readonly List<CrisisZombieMarker> ActiveMarkers = new List<CrisisZombieMarker>();

	private static readonly int BaseColorProperty = Shader.PropertyToID("_BaseColor");

	private static readonly int ColorProperty = Shader.PropertyToID("_Color");

	private static readonly int EmissionColorProperty = Shader.PropertyToID("_EmissionColor");

	private static readonly Color CrisisColor = new Color(0.82f, 0.035f, 0.025f, 1f);

	private static readonly Color CrisisEmission = new Color(1f, 0.015f, 0.005f, 1f) * 1.4f;

	private readonly HashSet<Material> _ownedMaterials = new HashSet<Material>();

	private MushroomZombie _zombie;

	private CharacterMovementZombie _movement;

	private float _targetSprintMultiplier;

	private float _nextVisualRefresh;

	private int _visualRefreshesRemaining;

	private bool _initialized;

	internal static int ActiveCount
	{
		get
		{
			for (int num = ActiveMarkers.Count - 1; num >= 0; num--)
			{
				if ((Object)(object)ActiveMarkers[num] == (Object)null)
				{
					ActiveMarkers.RemoveAt(num);
				}
			}
			return ActiveMarkers.Count;
		}
	}

	internal void Initialize(MushroomZombie zombie, float speedMultiplier)
	{
		if (!_initialized)
		{
			_initialized = true;
			_zombie = zombie;
			_zombie.lifetime = float.PositiveInfinity;
			_movement = ((Component)this).GetComponent<CharacterMovementZombie>();
			if ((Object)(object)_movement != (Object)null)
			{
				_targetSprintMultiplier = ((CharacterMovement)_movement).sprintMultiplier * Mathf.Clamp(speedMultiplier, 0.25f, 5f);
				((CharacterMovement)_movement).sprintMultiplier = _targetSprintMultiplier;
			}
			ActiveMarkers.Add(this);
			CreateWarningLight();
			ApplyCrisisAppearance();
			_visualRefreshesRemaining = 3;
			_nextVisualRefresh = Time.unscaledTime + 0.5f;
		}
	}

	private void LateUpdate()
	{
		if (_initialized && !((Object)(object)_zombie == (Object)null))
		{
			_zombie.lifetime = float.PositiveInfinity;
			if ((Object)(object)_movement != (Object)null && !Mathf.Approximately(((CharacterMovement)_movement).sprintMultiplier, _targetSprintMultiplier))
			{
				((CharacterMovement)_movement).sprintMultiplier = _targetSprintMultiplier;
			}
			if (_visualRefreshesRemaining > 0 && Time.unscaledTime >= _nextVisualRefresh)
			{
				ApplyCrisisAppearance();
				_visualRefreshesRemaining--;
				_nextVisualRefresh = Time.unscaledTime + 1f;
			}
		}
	}

	private void ApplyCrisisAppearance()
	{
		//IL_0050: Unknown result type (might be due to invalid IL or missing references)
		//IL_0061: Unknown result type (might be due to invalid IL or missing references)
		//IL_008c: Unknown result type (might be due to invalid IL or missing references)
		Renderer[] componentsInChildren = ((Component)this).GetComponentsInChildren<Renderer>(true);
		foreach (Renderer val in componentsInChildren)
		{
			if ((Object)(object)val == (Object)null)
			{
				continue;
			}
			Material[] materials = val.materials;
			foreach (Material val2 in materials)
			{
				if (!((Object)(object)val2 == (Object)null))
				{
					_ownedMaterials.Add(val2);
					SetTint(val2, BaseColorProperty, CrisisColor);
					SetTint(val2, ColorProperty, CrisisColor);
					if (val2.HasProperty(EmissionColorProperty))
					{
						val2.EnableKeyword("_EMISSION");
						val2.SetColor(EmissionColorProperty, CrisisEmission);
					}
				}
			}
		}
	}

	private static void SetTint(Material material, int property, Color color)
	{
		//IL_000c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0011: 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)
		if (material.HasProperty(property))
		{
			color.a = material.GetColor(property).a;
			material.SetColor(property, color);
		}
	}

	private void CreateWarningLight()
	{
		//IL_0005: Unknown result type (might be due to invalid IL or missing references)
		//IL_000b: Expected O, but got Unknown
		//IL_0032: Unknown result type (might be due to invalid IL or missing references)
		//IL_004b: Unknown result type (might be due to invalid IL or missing references)
		GameObject val = new GameObject("ZombieCrisis.CrimsonGlow");
		val.transform.SetParent(((Component)this).transform, false);
		val.transform.localPosition = new Vector3(0f, 1.65f, 0f);
		Light val2 = val.AddComponent<Light>();
		val2.type = (LightType)2;
		val2.color = CrisisColor;
		val2.intensity = 2.2f;
		val2.range = 5.5f;
		val2.shadows = (LightShadows)0;
	}

	private void OnDestroy()
	{
		ActiveMarkers.Remove(this);
		foreach (Material ownedMaterial in _ownedMaterials)
		{
			if ((Object)(object)ownedMaterial != (Object)null)
			{
				Object.Destroy((Object)(object)ownedMaterial);
			}
		}
		_ownedMaterials.Clear();
	}
}