Decompiled source of PlaneCrash v1.0.0

PlaneCrash.dll

Decompiled 2 days ago
using System;
using System.Collections;
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 Photon.Realtime;
using UnityEngine;
using UnityEngine.SceneManagement;

[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: AssemblyCompany("PlaneCrash")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+066f553d411e5cf6ee8adc4e6da956bea5fcd584")]
[assembly: AssemblyProduct("PlaneCrash")]
[assembly: AssemblyTitle("PlaneCrash")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[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 PlaneCrash
{
	[BepInPlugin("com.jill920.planecrash", "Plane Crash", "1.0.0")]
	public class Plugin : BaseUnityPlugin
	{
		internal sealed class PlaneCrashListener : MonoBehaviourPunCallbacks
		{
			private bool _isInAirport = true;

			private bool _crashWindowActive = false;

			private float _crashTimer = 0f;

			private HashSet<int> _damagedPlayers = new HashSet<int>();

			private void Start()
			{
				SceneManager.sceneLoaded += OnSceneLoaded;
				PlayerHandler.CharacterRegistered = (Action<Character>)Delegate.Combine(PlayerHandler.CharacterRegistered, new Action<Character>(OnCharacterRegistered));
			}

			private void OnDestroy()
			{
				SceneManager.sceneLoaded -= OnSceneLoaded;
				PlayerHandler.CharacterRegistered = (Action<Character>)Delegate.Remove(PlayerHandler.CharacterRegistered, new Action<Character>(OnCharacterRegistered));
			}

			private void Update()
			{
				if (_crashWindowActive)
				{
					_crashTimer -= Time.deltaTime;
					if (_crashTimer <= 0f)
					{
						_crashWindowActive = false;
						LogInfo("[PlaneCrash] Crash window closed. No more players will receive crash damage.");
					}
				}
			}

			private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
			{
				string name = ((Scene)(ref scene)).name;
				LogInfo("[PlaneCrash] Scene loaded: " + name);
				if (name == "Airport")
				{
					_isInAirport = true;
					_crashWindowActive = false;
					_damagedPlayers.Clear();
					LogInfo("[PlaneCrash] Reset state at Airport");
				}
				else if (name.StartsWith("Level") && _isInAirport)
				{
					_isInAirport = false;
					_crashWindowActive = true;
					_crashTimer = CrashWindowDuration.Value;
					_damagedPlayers.Clear();
					if (PhotonNetwork.IsMasterClient)
					{
						LogInfo($"[PlaneCrash] Plane crash! Crash window open for {_crashTimer:F0}s (host only)");
						ApplyDamageToExistingPlayers();
					}
					else
					{
						LogInfo("[PlaneCrash] Plane crash detected but not host - waiting for damage from host");
					}
				}
				else if (name.StartsWith("Biome_1") && !_isInAirport)
				{
					LogInfo("[PlaneCrash] Loaded into level from non-airport - no crash damage");
				}
			}

			private void ApplyDamageToExistingPlayers()
			{
				if (!PhotonNetwork.IsMasterClient || !_crashWindowActive)
				{
					return;
				}
				foreach (Character allCharacter in Character.AllCharacters)
				{
					if ((Object)(object)allCharacter == (Object)null || (Object)(object)allCharacter.data == (Object)null || allCharacter.isBot)
					{
						continue;
					}
					PhotonView photonView = ((MonoBehaviourPun)allCharacter).photonView;
					Player val = ((photonView != null) ? photonView.Owner : null);
					if (val == null)
					{
						continue;
					}
					int viewID = ((MonoBehaviourPun)allCharacter).photonView.ViewID;
					if (!_damagedPlayers.Contains(viewID))
					{
						if (allCharacter.refs == null || (Object)(object)allCharacter.refs.afflictions == (Object)null)
						{
							LogInfo("[PlaneCrash] Afflictions not ready for " + val.NickName + ", will apply on registration");
							continue;
						}
						float num = GenerateDamage();
						ApplyInjury(allCharacter, num);
						_damagedPlayers.Add(viewID);
						LogInfo($"[PlaneCrash] Applied crash damage to existing player: {val.NickName} ({num:F2} injury)");
					}
				}
			}

			private void OnCharacterRegistered(Character character)
			{
				if ((Object)(object)character == (Object)null || (Object)(object)((MonoBehaviourPun)character).photonView == (Object)null || character.isBot)
				{
					return;
				}
				if (!_crashWindowActive)
				{
					LogInfo("[PlaneCrash] Character registered after crash window: " + character.characterName + " - no damage");
				}
				else
				{
					if (!PhotonNetwork.IsMasterClient)
					{
						return;
					}
					Player owner = ((MonoBehaviourPun)character).photonView.Owner;
					if (owner != null)
					{
						int viewID = ((MonoBehaviourPun)character).photonView.ViewID;
						if (_damagedPlayers.Contains(viewID))
						{
							LogInfo("[PlaneCrash] Player already damaged: " + owner.NickName);
						}
						else
						{
							((MonoBehaviour)this).StartCoroutine(ApplyDamageWhenReady(character, owner, viewID));
						}
					}
				}
			}

			private IEnumerator ApplyDamageWhenReady(Character character, Player owner, int viewID)
			{
				float timeout = 5f;
				while (timeout > 0f && ((Object)(object)character == (Object)null || character.refs == null || (Object)(object)character.refs.afflictions == (Object)null))
				{
					yield return (object)new WaitForSeconds(0.1f);
					timeout -= 0.1f;
				}
				if ((Object)(object)character == (Object)null)
				{
					LogWarning("[PlaneCrash] Character became null while waiting for afflictions");
					yield break;
				}
				if (character.refs == null || (Object)(object)character.refs.afflictions == (Object)null)
				{
					LogWarning("[PlaneCrash] Afflictions never initialized for " + owner.NickName + ", cannot apply damage");
					yield break;
				}
				if (!_crashWindowActive)
				{
					LogInfo("[PlaneCrash] Crash window closed while waiting for " + owner.NickName + " - no damage");
					yield break;
				}
				float damage = GenerateDamage();
				ApplyInjury(character, damage);
				_damagedPlayers.Add(viewID);
				LogInfo($"[PlaneCrash] Applied crash damage to {owner.NickName} on join ({damage:F2} injury, {_crashTimer:F1}s remaining in window)");
			}

			private float GenerateDamage()
			{
				float value = MaxDamage.Value;
				Random random = new Random(DateTime.Now.Millisecond + (int)(Time.time * 1000f) % 1000 + Random.Range(0, 9999));
				double num = random.NextDouble();
				float num2 = ((num < 0.15) ? (0.05f + (float)random.NextDouble() * 0.15f) : ((num < 0.45) ? (0.2f + (float)random.NextDouble() * 0.3f) : ((num < 0.75) ? (0.5f + (float)random.NextDouble() * 0.3f) : ((!(num < 0.92)) ? (0.95f + (float)random.NextDouble() * 0.05f) : (0.8f + (float)random.NextDouble() * 0.2f)))));
				if (num2 >= 0.99f)
				{
					num2 = 0.95f + (float)random.NextDouble() * 0.04f;
				}
				return value * num2;
			}

			private void ApplyInjury(Character character, float damageAmount)
			{
				if ((Object)(object)character == (Object)null || (Object)(object)character.data == (Object)null)
				{
					return;
				}
				try
				{
					CharacterAfflictions val = character.refs?.afflictions;
					if ((Object)(object)val == (Object)null)
					{
						LogWarning("[PlaneCrash] No afflictions found for " + character.characterName);
						return;
					}
					float currentStatus = val.GetCurrentStatus((STATUSTYPE)0);
					float num = Mathf.Min(currentStatus + damageAmount, 1f);
					float num2 = num - currentStatus;
					if (Mathf.Abs(num2) < 0.001f)
					{
						LogInfo($"[PlaneCrash] {character.characterName} already at {currentStatus:F2} injury, no change needed");
						return;
					}
					float[] array = new float[CharacterAfflictions.NumStatusTypes];
					array[0] = num2;
					((MonoBehaviourPun)character).photonView.RPC("RPC_ApplyStatusesFromFloatArray", (RpcTarget)0, new object[1] { array });
					LogInfo($"[PlaneCrash] Applied {damageAmount:F2} injury to {character.characterName} (total: {num:F2})");
				}
				catch (Exception ex)
				{
					LogError("[PlaneCrash] Failed to apply injury to " + character.characterName + ": " + ex.Message);
				}
			}

			public override void OnPlayerEnteredRoom(Player newPlayer)
			{
				if (_crashWindowActive && PhotonNetwork.IsMasterClient)
				{
					LogInfo("[PlaneCrash] Player entered room during crash window: " + newPlayer.NickName + " - will get damage when character registers");
				}
			}

			private static string GetStablePlayerKey(Player player)
			{
				if (player == null)
				{
					return string.Empty;
				}
				if (!string.IsNullOrEmpty(player.UserId))
				{
					return "USERID:" + player.UserId;
				}
				if (!string.IsNullOrEmpty(player.NickName))
				{
					return "NICK:" + player.NickName;
				}
				return "ACTOR:" + player.ActorNumber;
			}
		}

		internal static ManualLogSource Log;

		internal static ConfigEntry<float> MaxDamage;

		internal static ConfigEntry<float> CrashWindowDuration;

		private PlaneCrashListener _listener;

		private void Awake()
		{
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Expected O, but got Unknown
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			MaxDamage = ((BaseUnityPlugin)this).Config.Bind<float>("General", "MaxDamage", 0.7f, new ConfigDescription("Maximum injury damage a player can receive from the crash (0-1)", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.01f, 1f), Array.Empty<object>()));
			CrashWindowDuration = ((BaseUnityPlugin)this).Config.Bind<float>("General", "CrashWindowDuration", 180f, new ConfigDescription("How long the crash window stays open for late joiners (seconds)", (AcceptableValueBase)(object)new AcceptableValueRange<float>(30f, 300f), Array.Empty<object>()));
			_listener = ((Component)this).gameObject.AddComponent<PlaneCrashListener>();
			LogInfo("========================================");
			LogInfo("[PlaneCrash] LOADED v1.0.0");
			LogInfo($"  MaxDamage: {MaxDamage.Value:F2}");
			LogInfo($"  CrashWindowDuration: {CrashWindowDuration.Value:F0}s");
			LogInfo("========================================");
		}

		private void OnDestroy()
		{
			if ((Object)(object)_listener != (Object)null)
			{
				Object.Destroy((Object)(object)_listener);
			}
		}

		internal static void LogInfo(string msg)
		{
			Log.LogInfo((object)msg);
		}

		internal static void LogWarning(string msg)
		{
			Log.LogWarning((object)msg);
		}

		internal static void LogError(string msg)
		{
			Log.LogError((object)msg);
		}
	}
}