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);
}
}
}