Decompiled source of LonelyDeath v1.0.0

LonelyDeath.dll

Decompiled 2 months ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using Microsoft.CodeAnalysis;
using Photon.Pun;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: IgnoresAccessChecksTo("")]
[assembly: AssemblyCompany("REPOJP")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("zabuMod")]
[assembly: AssemblyTitle("zabuMod")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace REPOJP.LonelyDeath
{
	[BepInPlugin("REPOJP.LonelyDeath", "LonelyDeath", "1.0.0")]
	public sealed class LonelyDeathPlugin : BaseUnityPlugin
	{
		public const string PluginGuid = "REPOJP.LonelyDeath";

		public const string PluginName = "LonelyDeath";

		public const string PluginVersion = "1.0.0";

		internal static ManualLogSource Log;

		internal static LonelyDeathConfig ModConfig;

		private void Awake()
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Expected O, but got Unknown
			try
			{
				Log = ((BaseUnityPlugin)this).Logger;
				ModConfig = new LonelyDeathConfig(((BaseUnityPlugin)this).Config);
				GameObject val = new GameObject("REPOJP_LonelyDeath_Manager");
				val.transform.parent = null;
				((Object)val).hideFlags = (HideFlags)61;
				Object.DontDestroyOnLoad((Object)(object)val);
				val.AddComponent<LonelyDeathManager>();
				Log.LogInfo((object)"LonelyDeath loaded.");
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)("Failure: LonelyDeath Awake\n" + ex));
			}
		}
	}
	internal sealed class LonelyDeathConfig
	{
		internal readonly ConfigEntry<bool> EnableMod;

		internal readonly ConfigEntry<float> Radius;

		internal readonly ConfigEntry<float> CheckInterval;

		internal readonly ConfigEntry<float> KillDelay;

		internal readonly ConfigEntry<int> DamagePerSecond;

		internal readonly ConfigEntry<float> DamageStartDelay;

		internal readonly ConfigEntry<bool> TruckSafeZone;

		internal readonly ConfigEntry<string> OutsideChatMessage;

		internal readonly ConfigEntry<string> SafeChatMessage;

		internal readonly ConfigEntry<bool> EnableDebugLog;

		internal LonelyDeathConfig(ConfigFile config)
		{
			EnableMod = config.Bind<bool>("General", "EnableMod", true, "Enable this mod.このMODを有効化");
			Radius = config.Bind<float>("General", "Radius", 25f, "Safe sphere radius from the center point.中心点からの安全球半径");
			CheckInterval = config.Bind<float>("General", "CheckInterval", 1f, "Position check interval in seconds.位置判定間隔 秒");
			KillDelay = config.Bind<float>("General", "KillDelay", 10f, "Seconds from leaving the safe sphere until death.安全球外に出てから死亡までの秒数");
			DamagePerSecond = config.Bind<int>("General", "DamagePerSecond", 1, "Damage applied every second while outside after the delay.猶予後に球外で毎秒受けるダメージ量");
			DamageStartDelay = config.Bind<float>("General", "DamageStartDelay", 0f, "Seconds before periodic damage starts after leaving the safe sphere.球外に出てから継続ダメージ開始までの猶予秒数");
			TruckSafeZone = config.Bind<bool>("General", "TruckSafeZone", true, "Treat the truck as a safe zone.トラック内をセーフティーゾーン扱い");
			OutsideChatMessage = config.Bind<string>("Chat", "OutsideChatMessage", "I'm too far away from everyone. I'm lonely. I'm going to die.", "Forced public chat when a player leaves the safe sphere.安全球外に出た時の強制公開チャット");
			SafeChatMessage = config.Bind<string>("Chat", "SafeChatMessage", "safe", "Forced public chat when a player returns to safety.安全圏に戻った時の強制公開チャット");
			EnableDebugLog = config.Bind<bool>("Debug", "EnableDebugLog", false, "Enable debug logs.デバッグログを有効化");
		}
	}
	internal sealed class LonelyDeathManager : MonoBehaviour
	{
		private readonly Dictionary<string, PlayerLonelyState> playerStates = new Dictionary<string, PlayerLonelyState>();

		private float nextCheckTime;

		private void Update()
		{
			try
			{
				LonelyDeathConfig modConfig = LonelyDeathPlugin.ModConfig;
				if (modConfig == null || !modConfig.EnableMod.Value)
				{
					ClearAllStates(sendSafeChat: false);
					return;
				}
				float num = Mathf.Max(0.1f, modConfig.CheckInterval.Value);
				if (!(Time.time < nextCheckTime))
				{
					nextCheckTime = Time.time + num;
					RunCheck(modConfig);
				}
			}
			catch (Exception ex)
			{
				LonelyDeathPlugin.Log.LogError((object)("Failure: LonelyDeath Update\n" + ex));
			}
		}

		private void RunCheck(LonelyDeathConfig config)
		{
			//IL_00cb: 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_014c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0151: Unknown result type (might be due to invalid IL or missing references)
			if (!IsMasterClient())
			{
				ClearAllStates(sendSafeChat: false);
				return;
			}
			if (!IsValidRunState())
			{
				ClearAllStates(sendSafeChat: false);
				return;
			}
			List<PlayerAvatar> alivePlayers = GetAlivePlayers();
			if (alivePlayers.Count < 2)
			{
				ClearAllStates(sendSafeChat: false);
				return;
			}
			List<PlayerAvatar> list = new List<PlayerAvatar>();
			foreach (PlayerAvatar item in alivePlayers)
			{
				if (!IsPlayerInTruck(item))
				{
					list.Add(item);
				}
			}
			if (list.Count < 2)
			{
				ClearAllStates(sendSafeChat: false);
				return;
			}
			Vector3 val = CalculateCenter(list);
			float num = Mathf.Max(0.1f, config.Radius.Value);
			foreach (PlayerAvatar item2 in alivePlayers)
			{
				string playerKey = GetPlayerKey(item2);
				if (string.IsNullOrEmpty(playerKey))
				{
					continue;
				}
				bool flag = IsPlayerInTruck(item2);
				if (config.TruckSafeZone.Value && flag)
				{
					SetSafe(item2, playerKey, config, sendSafeChat: true);
					continue;
				}
				float num2 = Vector3.Distance(((Component)item2).transform.position, val);
				if (num2 > num)
				{
					SetOutside(item2, playerKey, config, num2, num);
				}
				else
				{
					SetSafe(item2, playerKey, config, sendSafeChat: true);
				}
			}
			RemoveInvalidStates(alivePlayers);
		}

		private static bool IsMasterClient()
		{
			try
			{
				if (!SemiFunc.IsMultiplayer())
				{
					return false;
				}
				return SemiFunc.IsMasterClient();
			}
			catch
			{
				return PhotonNetwork.IsMasterClient;
			}
		}

		private static bool IsValidRunState()
		{
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Invalid comparison between Unknown and I4
			try
			{
				if (!SemiFunc.IsMultiplayer())
				{
					return false;
				}
				if (!SemiFunc.RunIsLevel())
				{
					return false;
				}
				if (SemiFunc.RunIsShop() || SemiFunc.RunIsLobby() || SemiFunc.RunIsLobbyMenu() || SemiFunc.RunIsTutorial())
				{
					return false;
				}
				if ((Object)(object)GameDirector.instance == (Object)null || (int)GameDirector.instance.currentState != 2)
				{
					return false;
				}
				return true;
			}
			catch
			{
				return false;
			}
		}

		private static List<PlayerAvatar> GetAlivePlayers()
		{
			List<PlayerAvatar> list = new List<PlayerAvatar>();
			List<PlayerAvatar> list2 = null;
			try
			{
				list2 = SemiFunc.PlayerGetList();
			}
			catch
			{
				if ((Object)(object)GameDirector.instance != (Object)null)
				{
					list2 = GameDirector.instance.PlayerList;
				}
			}
			if (list2 == null)
			{
				return list;
			}
			foreach (PlayerAvatar item in list2)
			{
				if (IsAlivePlayer(item))
				{
					list.Add(item);
				}
			}
			return list;
		}

		private static bool IsAlivePlayer(PlayerAvatar player)
		{
			if ((Object)(object)player == (Object)null)
			{
				return false;
			}
			if (player.isDisabled || player.deadSet)
			{
				return false;
			}
			if ((Object)(object)player.playerHealth == (Object)null)
			{
				return false;
			}
			if (player.playerHealth.health <= 0)
			{
				return false;
			}
			return true;
		}

		private static bool IsPlayerInTruck(PlayerAvatar player)
		{
			try
			{
				return (Object)(object)player != (Object)null && (Object)(object)player.RoomVolumeCheck != (Object)null && player.RoomVolumeCheck.inTruck;
			}
			catch
			{
				return false;
			}
		}

		private static Vector3 CalculateCenter(List<PlayerAvatar> players)
		{
			//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_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = Vector3.zero;
			foreach (PlayerAvatar player in players)
			{
				val += ((Component)player).transform.position;
			}
			return val / (float)players.Count;
		}

		private void SetOutside(PlayerAvatar player, string key, LonelyDeathConfig config, float distance, float radius)
		{
			if (!playerStates.TryGetValue(key, out PlayerLonelyState value))
			{
				value = new PlayerLonelyState();
				value.OutsideStartTime = Time.time;
				value.NextDamageTime = Time.time + Mathf.Max(0f, config.DamageStartDelay.Value);
				value.OutsideChatSent = false;
				playerStates[key] = value;
			}
			if (!value.OutsideChatSent)
			{
				SendForcedChat(player, config.OutsideChatMessage.Value);
				value.OutsideChatSent = true;
			}
			ApplyRedEyes(player);
			int num = Mathf.Max(0, config.DamagePerSecond.Value);
			if (num > 0 && Time.time >= value.NextDamageTime)
			{
				DamagePlayer(player, num);
				value.NextDamageTime = Time.time + 1f;
			}
			float num2 = Mathf.Max(0.1f, config.KillDelay.Value);
			if (Time.time - value.OutsideStartTime >= num2)
			{
				KillPlayer(player);
				playerStates.Remove(key);
			}
			else if (config.EnableDebugLog.Value)
			{
				LonelyDeathPlugin.Log.LogInfo((object)("Outside: " + GetPlayerName(player) + " distance=" + distance.ToString("0.00") + " radius=" + radius.ToString("0.00")));
			}
		}

		private void SetSafe(PlayerAvatar player, string key, LonelyDeathConfig config, bool sendSafeChat)
		{
			if (playerStates.ContainsKey(key))
			{
				playerStates.Remove(key);
				ClearRedEyes(player);
				if (sendSafeChat && !string.IsNullOrEmpty(config.SafeChatMessage.Value))
				{
					SendForcedChat(player, config.SafeChatMessage.Value);
				}
			}
		}

		private void ClearAllStates(bool sendSafeChat)
		{
			if (playerStates.Count == 0)
			{
				return;
			}
			List<PlayerAvatar> alivePlayers = GetAlivePlayers();
			foreach (PlayerAvatar item in alivePlayers)
			{
				string playerKey = GetPlayerKey(item);
				if (!string.IsNullOrEmpty(playerKey) && playerStates.ContainsKey(playerKey))
				{
					ClearRedEyes(item);
					if (sendSafeChat && LonelyDeathPlugin.ModConfig != null && !string.IsNullOrEmpty(LonelyDeathPlugin.ModConfig.SafeChatMessage.Value))
					{
						SendForcedChat(item, LonelyDeathPlugin.ModConfig.SafeChatMessage.Value);
					}
				}
			}
			playerStates.Clear();
		}

		private void RemoveInvalidStates(List<PlayerAvatar> alivePlayers)
		{
			HashSet<string> hashSet = new HashSet<string>();
			foreach (PlayerAvatar alivePlayer in alivePlayers)
			{
				string playerKey = GetPlayerKey(alivePlayer);
				if (!string.IsNullOrEmpty(playerKey))
				{
					hashSet.Add(playerKey);
				}
			}
			List<string> list = new List<string>();
			foreach (string key in playerStates.Keys)
			{
				if (!hashSet.Contains(key))
				{
					list.Add(key);
				}
			}
			foreach (string item in list)
			{
				playerStates.Remove(item);
			}
		}

		private static void SendForcedChat(PlayerAvatar player, string message)
		{
			if ((Object)(object)player == (Object)null || string.IsNullOrEmpty(message))
			{
				return;
			}
			try
			{
				player.ChatMessageSend(message);
			}
			catch (Exception ex)
			{
				LonelyDeathPlugin.Log.LogWarning((object)("Failure: SendForcedChat " + GetPlayerName(player) + "\n" + ex));
			}
		}

		private static void DamagePlayer(PlayerAvatar player, int damage)
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)player == (Object)null || (Object)(object)player.playerHealth == (Object)null || damage <= 0)
			{
				return;
			}
			try
			{
				player.playerHealth.HurtOther(damage, Vector3.zero, false, -1);
			}
			catch (Exception ex)
			{
				LonelyDeathPlugin.Log.LogWarning((object)("Failure: DamagePlayer " + GetPlayerName(player) + "\n" + ex));
			}
		}

		private static void KillPlayer(PlayerAvatar player)
		{
			if ((Object)(object)player == (Object)null || player.deadSet)
			{
				return;
			}
			try
			{
				player.PlayerDeath(-1);
			}
			catch (Exception ex)
			{
				LonelyDeathPlugin.Log.LogWarning((object)("Failure: KillPlayer " + GetPlayerName(player) + "\n" + ex));
			}
		}

		private static void ApplyRedEyes(PlayerAvatar player)
		{
			if ((Object)(object)player == (Object)null || (Object)(object)player.playerHealth == (Object)null)
			{
				return;
			}
			try
			{
				if (GameManager.Multiplayer() && (Object)(object)player.playerHealth.photonView != (Object)null)
				{
					player.playerHealth.photonView.RPC("EyeMaterialOverrideRPC", (RpcTarget)0, new object[2]
					{
						(object)(EyeOverrideState)1,
						true
					});
				}
				else
				{
					player.playerHealth.EyeMaterialOverride((EyeOverrideState)1, 1.25f, 50);
				}
			}
			catch (Exception ex)
			{
				LonelyDeathPlugin.Log.LogWarning((object)("Failure: ApplyRedEyes " + GetPlayerName(player) + "\n" + ex));
			}
		}

		private static void ClearRedEyes(PlayerAvatar player)
		{
			if ((Object)(object)player == (Object)null || (Object)(object)player.playerHealth == (Object)null)
			{
				return;
			}
			try
			{
				if (GameManager.Multiplayer() && (Object)(object)player.playerHealth.photonView != (Object)null)
				{
					player.playerHealth.photonView.RPC("EyeMaterialOverrideRPC", (RpcTarget)0, new object[2]
					{
						(object)(EyeOverrideState)1,
						false
					});
				}
			}
			catch (Exception ex)
			{
				LonelyDeathPlugin.Log.LogWarning((object)("Failure: ClearRedEyes " + GetPlayerName(player) + "\n" + ex));
			}
		}

		private static string GetPlayerKey(PlayerAvatar player)
		{
			if ((Object)(object)player == (Object)null)
			{
				return string.Empty;
			}
			try
			{
				if (!string.IsNullOrEmpty(player.steamID))
				{
					return player.steamID;
				}
			}
			catch
			{
			}
			try
			{
				if ((Object)(object)player.photonView != (Object)null && player.photonView.Owner != null)
				{
					return player.photonView.Owner.ActorNumber.ToString();
				}
			}
			catch
			{
			}
			return ((Object)player).GetInstanceID().ToString();
		}

		private static string GetPlayerName(PlayerAvatar player)
		{
			if ((Object)(object)player == (Object)null)
			{
				return "Unknown";
			}
			try
			{
				return SemiFunc.PlayerGetName(player);
			}
			catch
			{
				return ((Object)player).name;
			}
		}
	}
	internal sealed class PlayerLonelyState
	{
		internal float OutsideStartTime;

		internal float NextDamageTime;

		internal bool OutsideChatSent;
	}
}