Decompiled source of ItWasAllADream v1.0.0

plugins/ItWasAllADream.dll

Decompiled 3 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("ItWasAllADream")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("ItWasAllADream")]
[assembly: AssemblyTitle("ItWasAllADream")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace ItWasAllADream;

[BepInPlugin("itwasalladream", "ItWasAllADream", "1.0.0")]
public class Plugin : BaseUnityPlugin
{
	private enum DreamPhase
	{
		Idle,
		Collecting,
		Active,
		Resetting
	}

	[HarmonyPatch(/*Could not decode attribute arguments.*/)]
	private static class Patch_ZRoutedRpc_Ctor
	{
		private static void Postfix()
		{
			ZRoutedRpc.instance.Register<ZPackage>("ItWasAllADream_RequestInventory", (Action<long, ZPackage>)RPC_RequestInventory);
			ZRoutedRpc.instance.Register<ZPackage>("ItWasAllADream_UploadInventory", (Action<long, ZPackage>)RPC_UploadInventory);
			ZRoutedRpc.instance.Register<ZPackage>("ItWasAllADream_RestoreInventory", (Action<long, ZPackage>)RPC_RestoreInventory);
			ZRoutedRpc.instance.Register<ZPackage>("ItWasAllADream_PlayerDied", (Action<long, ZPackage>)RPC_PlayerDied);
		}
	}

	[HarmonyPatch(typeof(EnvMan), "SkipToMorning")]
	private static class Patch_EnvMan_SkipToMorning
	{
		private static bool Prefix()
		{
			if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer())
			{
				return true;
			}
			if (_phase != 0)
			{
				return true;
			}
			Instance.TriggerDream();
			return false;
		}
	}

	[HarmonyPatch(typeof(Player), "OnDeath")]
	private static class Patch_Player_OnDeath
	{
		private static bool Prefix(Player __instance)
		{
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Expected O, but got Unknown
			if (!IsEventActive && !IsEventStarting)
			{
				return true;
			}
			if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer)
			{
				return false;
			}
			Log.LogInfo((object)"[ItWasAllADream] Local player died in dream.");
			if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer())
			{
				_hostDied = true;
				Log.LogInfo((object)("[ItWasAllADream] Host died. " + $"{_deadPeers.Count + 1}/{_totalPlayers} dead."));
			}
			else
			{
				ZRoutedRpc.instance.InvokeRoutedRPC("ItWasAllADream_PlayerDied", new object[1] { (object)new ZPackage() });
			}
			return false;
		}
	}

	[HarmonyPatch(typeof(SleepText), "ShowDreamText")]
	private static class Patch_SuppressDreamText
	{
		private static bool Prefix()
		{
			if (!IsEventActive)
			{
				return !IsEventStarting;
			}
			return false;
		}
	}

	[HarmonyPatch(typeof(Player), "AddKnownItem")]
	private static class Patch_SuppressNewItem
	{
		private static bool Prefix()
		{
			if (!IsEventActive)
			{
				return !IsEventStarting;
			}
			return false;
		}
	}

	[HarmonyPatch(typeof(Player), "AddKnownBiome")]
	private static class Patch_SuppressNewBiome
	{
		private static bool Prefix()
		{
			if (!IsEventActive)
			{
				return !IsEventStarting;
			}
			return false;
		}
	}

	public const string PluginGUID = "itwasalladream";

	public const string PluginName = "ItWasAllADream";

	public const string PluginVersion = "1.0.0";

	internal static Plugin Instance;

	internal static ManualLogSource Log;

	private Harmony _harmony;

	private static DreamPhase _phase = DreamPhase.Idle;

	private static readonly Dictionary<long, byte[]> _savedInventories = new Dictionary<long, byte[]>();

	private static readonly Dictionary<long, Vector3> _bedPositions = new Dictionary<long, Vector3>();

	private static readonly HashSet<long> _deadPeers = new HashSet<long>();

	private static bool _hostDied = false;

	private static byte[] _hostInventory = null;

	private static Vector3 _hostBedPosition = Vector3.zero;

	private static bool _hostIsPlayer = false;

	private static int _totalPlayers = 0;

	private ConfigEntry<int> _cfgMonstersPerWave;

	private ConfigEntry<string> _cfgWaveMonsters;

	private ConfigEntry<float> _cfgWaveDuration;

	private ConfigEntry<int> _cfgWaveCount;

	public static bool IsEventActive => _phase == DreamPhase.Active;

	public static bool IsEventStarting => _phase == DreamPhase.Collecting;

	private void Awake()
	{
		//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ad: Expected O, but got Unknown
		Log = ((BaseUnityPlugin)this).Logger;
		Instance = this;
		_cfgMonstersPerWave = ((BaseUnityPlugin)this).Config.Bind<int>("Dream", "MonstersPerWave", 4, "Number of monsters spawned near each player per wave.");
		_cfgWaveMonsters = ((BaseUnityPlugin)this).Config.Bind<string>("Dream", "WaveMonsters", "Greyling,Greydwarf,Greydwarf_Elite,Skeleton,Draugr,Draugr_Elite,Troll,Fuling", "Comma-separated prefab names. Waves escalate from left (easy) to right (hard).");
		_cfgWaveDuration = ((BaseUnityPlugin)this).Config.Bind<float>("Dream", "WaveDuration", 30f, "Seconds between monster waves.");
		_cfgWaveCount = ((BaseUnityPlugin)this).Config.Bind<int>("Dream", "WaveCount", 5, "Total number of monster waves before the dream ends itself.");
		_harmony = new Harmony("itwasalladream");
		_harmony.PatchAll();
		Log.LogInfo((object)"ItWasAllADream v1.0.0 loaded.");
	}

	private void OnDestroy()
	{
		Harmony harmony = _harmony;
		if (harmony != null)
		{
			harmony.UnpatchSelf();
		}
	}

	private void TriggerDream()
	{
		if (_phase == DreamPhase.Idle)
		{
			_phase = DreamPhase.Collecting;
			((MonoBehaviour)this).StartCoroutine(DreamSequence());
		}
	}

	private IEnumerator DreamSequence()
	{
		Log.LogInfo((object)"[ItWasAllADream] Dream sequence starting — collecting inventories...");
		_savedInventories.Clear();
		_bedPositions.Clear();
		_deadPeers.Clear();
		_hostDied = false;
		_hostInventory = null;
		_hostIsPlayer = (Object)(object)Player.m_localPlayer != (Object)null;
		List<ZNetPeer> peers = (from p in ZNet.instance.GetPeers()
			where p.m_uid != 0
			select p).ToList();
		foreach (ZNetPeer item in peers)
		{
			_bedPositions[item.m_uid] = item.m_refPos;
		}
		if (_hostIsPlayer)
		{
			_hostBedPosition = ((Component)Player.m_localPlayer).transform.position;
			ZPackage val = new ZPackage();
			((Humanoid)Player.m_localPlayer).GetInventory().Save(val);
			_hostInventory = val.GetArray();
		}
		_totalPlayers = peers.Count + (_hostIsPlayer ? 1 : 0);
		if (_totalPlayers == 0)
		{
			_phase = DreamPhase.Idle;
			yield break;
		}
		ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.Everybody, "ItWasAllADream_RequestInventory", new object[1] { (object)new ZPackage() });
		yield return (object)new WaitForSeconds(2.2f);
		_phase = DreamPhase.Active;
		Log.LogInfo((object)$"[ItWasAllADream] Dream active. Players: {_totalPlayers}");
		ShowMessageAll((MessageType)2, "A terrible dream grips you...");
		string[] monsterList = (from s in _cfgWaveMonsters.Value.Split(',')
			select s.Trim() into s
			where !string.IsNullOrEmpty(s)
			select s).ToArray();
		int waves = _cfgWaveCount.Value;
		for (int wave = 0; wave < waves; wave++)
		{
			if (_phase != DreamPhase.Active)
			{
				yield break;
			}
			SpawnWave(monsterList, wave, waves, peers);
			if (wave == 0)
			{
				ShowMessageAll((MessageType)2, "They come for you in the dark...");
			}
			else if (wave == waves - 1)
			{
				ShowMessageAll((MessageType)2, "There is no escape from the dream...");
			}
			float elapsed = 0f;
			while (elapsed < _cfgWaveDuration.Value)
			{
				if (_phase != DreamPhase.Active)
				{
					yield break;
				}
				elapsed += 2f;
				yield return (object)new WaitForSeconds(2f);
				if (IsCatastrophe())
				{
					((MonoBehaviour)this).StartCoroutine(ResetSequence());
					yield break;
				}
			}
		}
		while (_phase == DreamPhase.Active)
		{
			yield return (object)new WaitForSeconds(2f);
			if (IsCatastrophe())
			{
				((MonoBehaviour)this).StartCoroutine(ResetSequence());
				break;
			}
		}
	}

	private bool IsCatastrophe()
	{
		return _deadPeers.Count + (_hostDied ? 1 : 0) >= _totalPlayers;
	}

	private void SpawnWave(string[] monsters, int waveIndex, int totalWaves, List<ZNetPeer> peers)
	{
		//IL_003a: Unknown result type (might be due to invalid IL or missing references)
		//IL_007e: Unknown result type (might be due to invalid IL or missing references)
		if (monsters.Length == 0)
		{
			return;
		}
		int baseIdx = Mathf.FloorToInt(((totalWaves <= 1) ? 1f : ((float)waveIndex / (float)(totalWaves - 1))) * (float)(monsters.Length - 1));
		foreach (ZNetPeer peer in peers)
		{
			SpawnMonstersAround(monsters, baseIdx, peer.m_refPos);
		}
		if (_hostIsPlayer && (Object)(object)Player.m_localPlayer != (Object)null)
		{
			SpawnMonstersAround(monsters, baseIdx, ((Component)Player.m_localPlayer).transform.position);
		}
	}

	private void SpawnMonstersAround(string[] monsters, int baseIdx, Vector3 centre)
	{
		//IL_0047: Unknown result type (might be due to invalid IL or missing references)
		//IL_005f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0064: Unknown result type (might be due to invalid IL or missing references)
		//IL_0069: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a8: 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_0079: Unknown result type (might be due to invalid IL or missing references)
		//IL_0080: Unknown result type (might be due to invalid IL or missing references)
		for (int i = 0; i < _cfgMonstersPerWave.Value; i++)
		{
			int num = Mathf.Clamp(baseIdx + Random.Range(0, 2), 0, monsters.Length - 1);
			string str = monsters[num];
			float num2 = Random.Range(0f, 360f) * (MathF.PI / 180f);
			float num3 = Random.Range(6f, 22f);
			Vector3 val = centre + new Vector3(Mathf.Cos(num2) * num3, 0f, Mathf.Sin(num2) * num3);
			if (WorldGenerator.instance != null)
			{
				val.y = WorldGenerator.instance.GetHeight(val.x, val.z);
			}
			ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.Everybody, "SpawnObject", new object[3]
			{
				val,
				Quaternion.identity,
				StableHash(str)
			});
		}
	}

	private IEnumerator ResetSequence()
	{
		if (_phase != DreamPhase.Active)
		{
			yield break;
		}
		_phase = DreamPhase.Resetting;
		Log.LogInfo((object)"[ItWasAllADream] Catastrophe! Triggering dream reset...");
		yield return (object)new WaitForSeconds(1.5f);
		ShowMessageAll((MessageType)2, "It was all a dream...");
		yield return (object)new WaitForSeconds(1f);
		foreach (ZNetPeer item in from p in ZNet.instance.GetPeers()
			where p.m_uid != 0
			select p)
		{
			if (_savedInventories.TryGetValue(item.m_uid, out var value))
			{
				ZRoutedRpc.instance.InvokeRoutedRPC(item.m_uid, "ItWasAllADream_RestoreInventory", new object[1] { (object)new ZPackage(value) });
			}
			if (_bedPositions.TryGetValue(item.m_uid, out var value2))
			{
				ZRoutedRpc.instance.InvokeRoutedRPC(item.m_uid, "RPC_TeleportPlayer", new object[3]
				{
					value2,
					Quaternion.identity,
					false
				});
			}
		}
		if (_hostIsPlayer && (Object)(object)Player.m_localPlayer != (Object)null)
		{
			if (_hostInventory != null)
			{
				((Humanoid)Player.m_localPlayer).UnequipAllItems();
				((Humanoid)Player.m_localPlayer).GetInventory().Load(new ZPackage(_hostInventory));
			}
			((Character)Player.m_localPlayer).SetHealth(((Character)Player.m_localPlayer).GetMaxHealth());
			((Character)Player.m_localPlayer).TeleportTo(_hostBedPosition, Quaternion.identity, false);
		}
		yield return (object)new WaitForSeconds(2f);
		_phase = DreamPhase.Idle;
		Log.LogInfo((object)"[ItWasAllADream] Dream reset complete. Returning to Idle.");
	}

	private static void RPC_UploadInventory(long sender, ZPackage pkg)
	{
		if (!((Object)(object)ZNet.instance == (Object)null) && ZNet.instance.IsServer())
		{
			_savedInventories[sender] = pkg.GetArray();
			Log.LogInfo((object)$"[ItWasAllADream] Stored inventory for peer {sender}.");
		}
	}

	private static void RPC_RestoreInventory(long sender, ZPackage pkg)
	{
		//IL_0028: Unknown result type (might be due to invalid IL or missing references)
		//IL_0032: Expected O, but got Unknown
		if (!((Object)(object)Player.m_localPlayer == (Object)null))
		{
			((Humanoid)Player.m_localPlayer).UnequipAllItems();
			((Humanoid)Player.m_localPlayer).GetInventory().Load(new ZPackage(pkg.GetArray()));
			((Character)Player.m_localPlayer).SetHealth(((Character)Player.m_localPlayer).GetMaxHealth());
			Log.LogInfo((object)"[ItWasAllADream] Inventory restored and player healed.");
		}
	}

	private static void RPC_RequestInventory(long sender, ZPackage _pkg)
	{
		//IL_0028: Unknown result type (might be due to invalid IL or missing references)
		//IL_002e: Expected O, but got Unknown
		if (!((Object)(object)Player.m_localPlayer == (Object)null) && (!((Object)(object)ZNet.instance != (Object)null) || !ZNet.instance.IsServer()))
		{
			ZPackage val = new ZPackage();
			((Humanoid)Player.m_localPlayer).GetInventory().Save(val);
			ZRoutedRpc.instance.InvokeRoutedRPC("ItWasAllADream_UploadInventory", new object[1] { val });
		}
	}

	private static void RPC_PlayerDied(long sender, ZPackage _pkg)
	{
		if (!((Object)(object)ZNet.instance == (Object)null) && ZNet.instance.IsServer() && _phase == DreamPhase.Active)
		{
			_deadPeers.Add(sender);
			Log.LogInfo((object)($"[ItWasAllADream] Peer {sender} died. " + $"{_deadPeers.Count + (_hostDied ? 1 : 0)}/{_totalPlayers} dead."));
		}
	}

	private static int StableHash(string str)
	{
		int num = 5381;
		int num2 = num;
		for (int i = 0; i < str.Length && str[i] != 0; i += 2)
		{
			num = ((num << 5) + num) ^ str[i];
			if (i == str.Length - 1 || str[i + 1] == '\0')
			{
				break;
			}
			num2 = ((num2 << 5) + num2) ^ str[i + 1];
		}
		return num + num2 * 1566083941;
	}

	private static void ShowMessageAll(MessageType type, string text)
	{
		//IL_0027: Unknown result type (might be due to invalid IL or missing references)
		//IL_002d: Expected I4, but got Unknown
		if (!string.IsNullOrWhiteSpace(text) && ZRoutedRpc.instance != null)
		{
			ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.Everybody, "ShowMessage", new object[2]
			{
				(int)type,
				text
			});
		}
	}
}