Decompiled source of CampfireRespawn v2.0.1

plugins/Peak_NoEndGame.dll

Decompiled 2 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.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Peak;
using Photon.Pun;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("Peak_NoEndGame")]
[assembly: AssemblyDescription("Current-game campfire party respawn and inventory recovery for PEAK")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Peak_NoEndGame")]
[assembly: AssemblyCopyright("Copyright © 2025-2026")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("b253a047-7de8-4c49-8e85-524405e8513d")]
[assembly: AssemblyFileVersion("2.0.1.0")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyVersion("2.0.1.0")]
namespace Peak_NoEndGame;

public sealed class ReviewHandler : MonoBehaviourPun
{
	private const float RespawnCooldown = 5f;

	private const float DeathCheckInterval = 0.2f;

	private const float StatusClearInterval = 3f;

	private readonly InventoryCheckpoint _checkpoint = new InventoryCheckpoint();

	private bool _runActive;

	private bool _respawning;

	private bool _warnedMissingSpawn;

	private float _lastRespawnTime = float.NegativeInfinity;

	private float _nextDeathCheck;

	private float _nextStatusClear;

	private float _fogResetSize = 300f;

	public static ReviewHandler Instance { get; private set; }

	public int reviveTimes { get; private set; }

	private void Awake()
	{
		Instance = this;
	}

	private void OnDestroy()
	{
		if ((Object)(object)Instance == (Object)(object)this)
		{
			Instance = null;
			ReviewUI.Hide();
		}
	}

	private void Update()
	{
		//IL_0034: Unknown result type (might be due to invalid IL or missing references)
		if (!_runActive || (Object)(object)Plugin.Instance == (Object)null)
		{
			return;
		}
		TryClearLocalCampfireStatuses();
		TryCaptureInitialCheckpoint();
		if (!PhotonNetwork.IsMasterClient)
		{
			return;
		}
		if (Input.GetKeyUp(Plugin.Instance.RespawnHotkey.Value))
		{
			TryStartRespawn(forced: true);
		}
		if (!(Time.unscaledTime < _nextDeathCheck))
		{
			_nextDeathCheck = Time.unscaledTime + 0.2f;
			if (AllPlayersDead())
			{
				TryStartRespawn(forced: false);
			}
		}
	}

	internal void BeginRun()
	{
		_runActive = true;
		_respawning = false;
		_warnedMissingSpawn = false;
		_lastRespawnTime = float.NegativeInfinity;
		_nextDeathCheck = 0f;
		_nextStatusClear = 0f;
		reviveTimes = 0;
		_checkpoint.Clear();
		ReviewUI.Show((!((Object)(object)Plugin.Instance == (Object)null)) ? Plugin.Instance.MaximumRespawns : 0);
		if ((Object)(object)Plugin.Instance != (Object)null && PhotonNetwork.IsMasterClient)
		{
			SetReviveTimesNetworked(0);
		}
	}

	internal void EndRun()
	{
		_runActive = false;
		_respawning = false;
		_checkpoint.Clear();
		ReviewUI.Hide();
	}

	internal void RememberFogOrigin(FogSphereOrigin origin)
	{
		if ((Object)(object)origin != (Object)null)
		{
			_fogResetSize = origin.size;
		}
	}

	internal void CaptureCampfireCheckpoint()
	{
		if (_runActive && !((Object)(object)Plugin.Instance == (Object)null) && Plugin.Instance.RecordItemsAtCampfire.Value)
		{
			CaptureCheckpoint("campfire");
		}
	}

	internal bool ShouldSuppressEndGame()
	{
		if (!_runActive || (Object)(object)Plugin.Instance == (Object)null || !PhotonNetwork.IsMasterClient || reviveTimes >= Plugin.Instance.MaximumRespawns || !AllPlayersDead())
		{
			return false;
		}
		if (!TryGetRespawnPosition(out var _))
		{
			WarnMissingSpawnOnce();
			return false;
		}
		if (!_respawning && Time.time - _lastRespawnTime >= 5f)
		{
			TryStartRespawn(forced: false);
		}
		return true;
	}

	private void TryCaptureInitialCheckpoint()
	{
		//IL_0032: 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)
		if (!_checkpoint.IsCaptured && !((Object)(object)Plugin.Instance == (Object)null) && Plugin.Instance.RecordItemsAtCampfire.Value && MapHandler.ExistsAndInitialized && (int)MapHandler.CurrentSegmentNumber == 0)
		{
			Character localCharacter = Character.localCharacter;
			if (!((Object)(object)localCharacter == (Object)null) && TryGetRespawnPosition(out var position) && !(Vector3.Distance(localCharacter.Center, position) <= 120f))
			{
				CaptureCheckpoint("shore departure");
				ShowTitleNetworked("已记录玩家物品!", "Items Recorded");
			}
		}
	}

	private void CaptureCheckpoint(string reason)
	{
		int num = _checkpoint.Capture(Character.AllCharacters.ToArray());
		Plugin.Log.LogInfo((object)$"Inventory checkpoint captured ({reason}), {num} item(s).");
	}

	private bool TryStartRespawn(bool forced)
	{
		//IL_0083: Unknown result type (might be due to invalid IL or missing references)
		if (!_runActive || _respawning || (Object)(object)Plugin.Instance == (Object)null || !PhotonNetwork.IsMasterClient || reviveTimes >= Plugin.Instance.MaximumRespawns || Time.time - _lastRespawnTime < 5f)
		{
			return false;
		}
		if (!TryGetRespawnPosition(out var position))
		{
			WarnMissingSpawnOnce();
			return false;
		}
		if (!forced && !AllPlayersDead())
		{
			return false;
		}
		_warnedMissingSpawn = false;
		_respawning = true;
		_lastRespawnTime = Time.time;
		((MonoBehaviour)this).StartCoroutine(RespawnRoutine(position));
		return true;
	}

	private IEnumerator RespawnRoutine(Vector3 spawnPosition)
	{
		//IL_000e: Unknown result type (might be due to invalid IL or missing references)
		//IL_000f: Unknown result type (might be due to invalid IL or missing references)
		IEnumerator routine = RespawnRoutineCore(spawnPosition);
		try
		{
			while (true)
			{
				object current;
				try
				{
					if (!routine.MoveNext())
					{
						break;
					}
					current = routine.Current;
				}
				catch (Exception ex)
				{
					Plugin.Log.LogError((object)("Respawn routine failed: " + ex));
					break;
				}
				yield return current;
			}
		}
		finally
		{
			_respawning = false;
		}
	}

	private IEnumerator RespawnRoutineCore(Vector3 spawnPosition)
	{
		//IL_000e: Unknown result type (might be due to invalid IL or missing references)
		//IL_000f: Unknown result type (might be due to invalid IL or missing references)
		List<Character> characters = Character.AllCharacters.Where((Character character) => (Object)(object)character != (Object)null).ToList();
		HashSet<int> revivedActors = new HashSet<int>();
		VoidBiome voidBiome = (((int)MapHandler.CurrentSegmentNumber == 6) ? VoidBiome.instance : null);
		int voidSpawnIndex = 0;
		IEnumerator resetHazards = ResetHazards();
		while (resetHazards.MoveNext())
		{
			yield return resetHazards.Current;
		}
		foreach (Character item in characters)
		{
			if ((Object)(object)item == (Object)null || (Object)(object)item.data == (Object)null || (Object)(object)((MonoBehaviourPun)item).photonView == (Object)null)
			{
				continue;
			}
			Vector3 val = (((Object)(object)voidBiome != (Object)null) ? (voidBiome.GetSpawnPosition(voidSpawnIndex++) + Vector3.up) : (spawnPosition + new Vector3(Random.Range(-3f, 3f), 1f, Random.Range(-3f, 3f))));
			if (item.data.dead || item.data.fullyPassedOut)
			{
				if (InventoryCheckpoint.TryGetActorNumber(item, out var actorNumber))
				{
					revivedActors.Add(actorNumber);
				}
				((MonoBehaviourPun)item).photonView.RPC("RPCA_ReviveAtPosition", (RpcTarget)0, new object[3]
				{
					val,
					Plugin.Instance.ReviveAddCurse.Value,
					-1
				});
			}
			else
			{
				((MonoBehaviourPun)item).photonView.RPC("WarpPlayerRPC", (RpcTarget)0, new object[2] { val, true });
				((MonoBehaviourPun)this).photonView.RPC("RPCA_ClearLocalStatuses", (RpcTarget)0, new object[1] { ((MonoBehaviourPun)item).photonView.ViewID });
			}
		}
		Plugin.Log.LogInfo((object)$"Respawning party at {spawnPosition}; affected players: {revivedActors.Count}.");
		ShowTitleNetworked("继续加油", "Nice Try");
		SetReviveTimesNetworked(reviveTimes + 1);
		float deadline = Time.realtimeSinceStartup + 5f;
		while ((AnyActorStillDeadOrDown(revivedActors) || AnyDroppableItemsRemain(revivedActors)) && Time.realtimeSinceStartup < deadline)
		{
			yield return null;
		}
		if (AnyDroppableItemsRemain(revivedActors))
		{
			Plugin.Log.LogWarning((object)"Timed out waiting for one or more players to finish dropping their inventory.");
		}
		yield return null;
		if (Plugin.Instance.RecordItemsAtCampfire.Value && _checkpoint.IsCaptured)
		{
			CleanupDroppedItems(revivedActors);
			yield return null;
			RestoreCheckpointItems(revivedActors);
		}
		else
		{
			RestoreDroppedItems(revivedActors);
		}
	}

	private IEnumerator ResetHazards()
	{
		OrbFogHandler val = Object.FindObjectOfType<OrbFogHandler>();
		PhotonView val2 = (((Object)(object)val == (Object)null) ? null : ((Component)val).GetComponent<PhotonView>());
		if ((Object)(object)val != (Object)null && (Object)(object)val2 != (Object)null)
		{
			val.currentSize = _fogResetSize;
			val2.RPC("RPCA_SyncFog", (RpcTarget)0, new object[2] { _fogResetSize, val.isMoving });
		}
		Segment currentSegment = (Segment)(MapHandler.Exists ? ((int)MapHandler.CurrentSegmentNumber) : 0);
		List<LavaRising> lavaFields = LavaRising.ALL_LAVA.Where((LavaRising lava) => (Object)(object)lava != (Object)null && lava.requiredSegment == currentSegment && (Object)(object)((MonoBehaviourPun)lava).photonView != (Object)null).ToList();
		foreach (LavaRising item in lavaFields)
		{
			((MonoBehaviourPun)item).photonView.RPC("RPC_SyncLava", (RpcTarget)0, new object[4] { true, false, 0f, 0f });
		}
		if (lavaFields.Count <= 0)
		{
			yield break;
		}
		yield return null;
		foreach (LavaRising item2 in lavaFields)
		{
			if ((Object)(object)item2 != (Object)null && (Object)(object)((MonoBehaviourPun)item2).photonView != (Object)null)
			{
				((MonoBehaviourPun)item2).photonView.RPC("RPC_SyncLava", (RpcTarget)0, new object[4] { false, false, 0f, 0f });
			}
		}
	}

	private void RestoreCheckpointItems(IEnumerable<int> actorNumbers)
	{
		int num = 0;
		ItemSlot val3 = default(ItemSlot);
		foreach (int actorNumber in actorNumbers)
		{
			Character val = FindCharacter(actorNumber);
			if ((Object)(object)val == (Object)null || (Object)(object)val.player == (Object)null)
			{
				continue;
			}
			List<RecordedInventoryItem> list = new List<RecordedInventoryItem>(_checkpoint.GetItems(actorNumber));
			RemoveItemsAlreadyCarried(val.player, list);
			foreach (RecordedInventoryItem item in list)
			{
				if (RollItemRestore())
				{
					ItemInstanceData val2 = ((item.Data == null) ? null : item.Data.Copy());
					if (val2 != null)
					{
						ItemInstanceDataHandler.AddInstanceData(val2);
					}
					if (val.player.AddItem(item.ItemId, val2, ref val3))
					{
						num++;
						continue;
					}
					Plugin.Log.LogWarning((object)("Could not restore item " + item.ItemName + " to " + val.characterName + "."));
				}
			}
			val.refs.items.RefreshAllCharacterCarryWeight();
		}
		Plugin.Log.LogInfo((object)("Restored " + num + " checkpoint item(s)."));
	}

	private static void RemoveItemsAlreadyCarried(Player player, IList<RecordedInventoryItem> missingItems)
	{
		for (byte b = 0; b <= 3; b++)
		{
			ItemSlot itemSlot = player.GetItemSlot(b);
			if (itemSlot != null && !itemSlot.IsEmpty() && !((Object)(object)itemSlot.prefab == (Object)null))
			{
				for (int i = 0; i < missingItems.Count; i++)
				{
					if (missingItems[i].ItemId == itemSlot.prefab.itemID)
					{
						missingItems.RemoveAt(i);
						break;
					}
				}
			}
		}
	}

	private void RestoreDroppedItems(IEnumerable<int> actorNumbers)
	{
		int num = 0;
		foreach (int actorNumber in actorNumbers)
		{
			Character val = FindCharacter(actorNumber);
			if ((Object)(object)val == (Object)null || val.refs == null || (Object)(object)val.refs.items == (Object)null)
			{
				continue;
			}
			List<PhotonView> list = val.refs.items.droppedItems.ToList();
			val.refs.items.droppedItems.Clear();
			foreach (PhotonView item in list)
			{
				if (!((Object)(object)item == (Object)null) && RollItemRestore())
				{
					Item component = ((Component)item).GetComponent<Item>();
					if ((Object)(object)component != (Object)null)
					{
						component.RequestPickup(((MonoBehaviourPun)val).photonView);
						num++;
					}
				}
			}
		}
		Plugin.Log.LogInfo((object)("Recovered " + num + " dropped item(s)."));
	}

	private static void CleanupDroppedItems(IEnumerable<int> actorNumbers)
	{
		foreach (int actorNumber in actorNumbers)
		{
			Character val = FindCharacter(actorNumber);
			if ((Object)(object)val == (Object)null || val.refs == null || (Object)(object)val.refs.items == (Object)null)
			{
				continue;
			}
			List<PhotonView> list = val.refs.items.droppedItems.ToList();
			val.refs.items.droppedItems.Clear();
			foreach (PhotonView item in list)
			{
				if ((Object)(object)item != (Object)null)
				{
					PhotonNetwork.Destroy(((Component)item).gameObject);
				}
			}
		}
	}

	private bool RollItemRestore()
	{
		return Random.Range(0, 100) < Plugin.Instance.ItemRestoreChance;
	}

	private void TryClearLocalCampfireStatuses()
	{
		//IL_008f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0094: Unknown result type (might be due to invalid IL or missing references)
		//IL_0095: Unknown result type (might be due to invalid IL or missing references)
		//IL_0097: Invalid comparison between Unknown and I4
		//IL_0099: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e8: Expected I4, but got Unknown
		if (!Plugin.Instance.CampfireClearStatus.Value || Time.unscaledTime < _nextStatusClear || !MapHandler.ExistsAndInitialized)
		{
			return;
		}
		_nextStatusClear = Time.unscaledTime + 3f;
		Character localCharacter = Character.localCharacter;
		if ((Object)(object)localCharacter == (Object)null || (Object)(object)localCharacter.data == (Object)null || localCharacter.data.dead || localCharacter.refs == null || (Object)(object)localCharacter.refs.afflictions == (Object)null || localCharacter.refs.afflictions.currentStatuses == null)
		{
			return;
		}
		Segment currentSegmentNumber = MapHandler.CurrentSegmentNumber;
		int num = (((int)currentSegmentNumber == 6) ? (-1) : ((int)currentSegmentNumber));
		Campfire campfire = GetCampfire(num);
		if (!IsInsideCampfire(localCharacter, campfire))
		{
			campfire = GetCampfire(num - 1);
		}
		if (!IsInsideCampfire(localCharacter, campfire))
		{
			return;
		}
		foreach (STATUSTYPE value in Enum.GetValues(typeof(STATUSTYPE)))
		{
			int num2 = (int)value;
			if (ShouldClearAtCampfire(value) && num2 >= 0 && num2 < localCharacter.refs.afflictions.currentStatuses.Length && localCharacter.refs.afflictions.currentStatuses[num2] > 0f)
			{
				localCharacter.refs.afflictions.ClearAllStatus(true, true);
				break;
			}
		}
	}

	private static bool ShouldClearAtCampfire(STATUSTYPE status)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0002: Unknown result type (might be due to invalid IL or missing references)
		//IL_0030: Expected I4, but got Unknown
		switch (status - 4)
		{
		case 0:
		case 1:
		case 3:
		case 5:
		case 8:
		case 9:
			return false;
		default:
			return true;
		}
	}

	private static bool IsInsideCampfire(Character character, Campfire campfire)
	{
		//IL_0012: Unknown result type (might be due to invalid IL or missing references)
		//IL_001d: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)campfire != (Object)null && campfire.Lit)
		{
			return Vector3.Distance(character.Center, ((Component)campfire).transform.position) <= campfire.moraleBoostRadius;
		}
		return false;
	}

	private static Campfire GetCampfire(int segmentIndex)
	{
		GameObject val = ((segmentIndex < 0) ? null : MapHandler.GetCampfireRoot(segmentIndex));
		if (!((Object)(object)val == (Object)null))
		{
			return val.GetComponentInChildren<Campfire>(true);
		}
		return null;
	}

	private static bool TryGetRespawnPosition(out Vector3 position)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		//IL_0015: Unknown result type (might be due to invalid IL or missing references)
		//IL_0016: Unknown result type (might be due to invalid IL or missing references)
		//IL_0018: Invalid comparison between Unknown and I4
		//IL_0056: Unknown result type (might be due to invalid IL or missing references)
		//IL_0058: Invalid comparison between Unknown and I4
		//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c4: 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_00a7: Unknown result type (might be due to invalid IL or missing references)
		//IL_0078: Unknown result type (might be due to invalid IL or missing references)
		//IL_007d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0042: 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_00e9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
		position = default(Vector3);
		if (!MapHandler.ExistsAndInitialized)
		{
			return false;
		}
		Segment currentSegmentNumber = MapHandler.CurrentSegmentNumber;
		if ((int)currentSegmentNumber == 6)
		{
			VoidBiome instance = VoidBiome.instance;
			if ((Object)(object)instance != (Object)null && instance.spawnPoints != null && instance.spawnPoints.Length != 0)
			{
				position = instance.GetSpawnPosition(0);
				return true;
			}
			return false;
		}
		MapHandler val = Object.FindObjectOfType<MapHandler>();
		if ((int)currentSegmentNumber == 5 && (Object)(object)val != (Object)null && (Object)(object)val.respawnThePeak != (Object)null)
		{
			position = val.respawnThePeak.position;
			return true;
		}
		MapSegment currentMapSegment = MapHandler.CurrentMapSegment;
		if (currentMapSegment != null && (Object)(object)currentMapSegment.reconnectSpawnPos != (Object)null)
		{
			position = currentMapSegment.reconnectSpawnPos.position;
			return true;
		}
		Transform currentBaseCampSpawnPoint = MapHandler.CurrentBaseCampSpawnPoint;
		if ((Object)(object)currentBaseCampSpawnPoint != (Object)null)
		{
			position = currentBaseCampSpawnPoint.position;
			return true;
		}
		if ((Object)(object)val != (Object)null && (Object)(object)val.respawnThePeak != (Object)null)
		{
			position = val.respawnThePeak.position;
			return true;
		}
		return false;
	}

	private static Character FindCharacter(int actorNumber)
	{
		foreach (Character allCharacter in Character.AllCharacters)
		{
			if (InventoryCheckpoint.TryGetActorNumber(allCharacter, out var actorNumber2) && actorNumber2 == actorNumber)
			{
				return allCharacter;
			}
		}
		return null;
	}

	private static bool AllPlayersDead()
	{
		bool result = false;
		foreach (Character allCharacter in Character.AllCharacters)
		{
			if (!((Object)(object)allCharacter == (Object)null) && !((Object)(object)allCharacter.data == (Object)null))
			{
				result = true;
				if (!allCharacter.data.dead)
				{
					return false;
				}
			}
		}
		return result;
	}

	private static bool AnyActorStillDeadOrDown(IEnumerable<int> actorNumbers)
	{
		foreach (int actorNumber in actorNumbers)
		{
			Character val = FindCharacter(actorNumber);
			if ((Object)(object)val != (Object)null && (Object)(object)val.data != (Object)null && (val.data.dead || val.data.fullyPassedOut))
			{
				return true;
			}
		}
		return false;
	}

	private static bool AnyDroppableItemsRemain(IEnumerable<int> actorNumbers)
	{
		foreach (int actorNumber in actorNumbers)
		{
			Character val = FindCharacter(actorNumber);
			if ((Object)(object)val == (Object)null || (Object)(object)val.player == (Object)null)
			{
				continue;
			}
			for (byte b = 0; b <= 3; b++)
			{
				ItemSlot itemSlot = val.player.GetItemSlot(b);
				if (itemSlot != null && !itemSlot.IsEmpty() && (Object)(object)itemSlot.prefab != (Object)null && itemSlot.prefab.UIData.canDrop)
				{
					return true;
				}
			}
		}
		return false;
	}

	private void SetReviveTimesNetworked(int times)
	{
		int num = Mathf.Max(0, Plugin.Instance.MaximumRespawns - times);
		((MonoBehaviourPun)this).photonView.RPC("RPCA_SetReviveTimes", (RpcTarget)0, new object[2] { times, num });
	}

	private void ShowTitleNetworked(string chinese, string english)
	{
		((MonoBehaviourPun)this).photonView.RPC("RPCA_ShowTitle", (RpcTarget)0, new object[2] { chinese, english });
	}

	private void WarnMissingSpawnOnce()
	{
		if (!_warnedMissingSpawn)
		{
			_warnedMissingSpawn = true;
			Plugin.Log.LogWarning((object)"No valid campfire respawn point is available; allowing the normal game-over flow.");
		}
	}

	[PunRPC]
	public void RPCA_SetReviveTimes(int times, int remaining)
	{
		reviveTimes = times;
		ReviewUI.Show(Mathf.Max(0, remaining));
	}

	[PunRPC]
	public void RPCA_ShowTitle(string chinese, string english)
	{
		//IL_0055: Unknown result type (might be due to invalid IL or missing references)
		//IL_005c: Invalid comparison between Unknown and I4
		if (!((Object)(object)GUIManager.instance == (Object)null))
		{
			AudioClip val = null;
			MountainProgressHandler val2 = Object.FindObjectOfType<MountainProgressHandler>();
			if ((Object)(object)val2 != (Object)null && val2.progressPoints != null && val2.progressPoints.Length != 0)
			{
				int num = Mathf.Clamp(val2.maxProgressPointReached, 0, val2.progressPoints.Length - 1);
				val = val2.progressPoints[num].clip;
			}
			string text = (((int)LocalizedText.CURRENT_LANGUAGE == 9) ? chinese : english);
			GUIManager.instance.SetHeroTitle(text, val, false);
		}
	}

	[PunRPC]
	public void RPCA_ClearLocalStatuses(int characterViewId)
	{
		PhotonView photonView = PhotonNetwork.GetPhotonView(characterViewId);
		Character val = (((Object)(object)photonView == (Object)null) ? null : ((Component)photonView).GetComponent<Character>());
		if ((Object)(object)val != (Object)null && val.IsLocal && val.refs != null && (Object)(object)val.refs.afflictions != (Object)null)
		{
			val.refs.afflictions.ClearAllStatus(true, true);
		}
	}
}
internal sealed class RecordedInventoryItem
{
	internal ushort ItemId { get; private set; }

	internal string ItemName { get; private set; }

	internal ItemInstanceData Data { get; private set; }

	internal RecordedInventoryItem(ushort itemId, string itemName, ItemInstanceData data)
	{
		ItemId = itemId;
		ItemName = itemName;
		Data = data;
	}
}
internal sealed class InventoryCheckpoint
{
	private readonly Dictionary<int, List<RecordedInventoryItem>> _itemsByActor = new Dictionary<int, List<RecordedInventoryItem>>();

	internal bool IsCaptured { get; private set; }

	internal void Clear()
	{
		_itemsByActor.Clear();
		IsCaptured = false;
	}

	internal int Capture(IEnumerable<Character> characters)
	{
		_itemsByActor.Clear();
		int num = 0;
		foreach (Character character in characters)
		{
			if (!TryGetActorNumber(character, out var actorNumber) || (Object)(object)character.player == (Object)null)
			{
				continue;
			}
			List<RecordedInventoryItem> list = new List<RecordedInventoryItem>();
			ItemSlot[] itemSlots = character.player.itemSlots;
			if (itemSlots != null)
			{
				ItemSlot[] array = itemSlots;
				foreach (ItemSlot slot in array)
				{
					num += TryCaptureSlot(slot, list);
				}
			}
			num += TryCaptureSlot(character.player.GetItemSlot((byte)3), list);
			_itemsByActor[actorNumber] = list;
		}
		IsCaptured = true;
		return num;
	}

	internal IList<RecordedInventoryItem> GetItems(int actorNumber)
	{
		if (_itemsByActor.TryGetValue(actorNumber, out var value))
		{
			return value;
		}
		return new RecordedInventoryItem[0];
	}

	internal static bool TryGetActorNumber(Character character, out int actorNumber)
	{
		actorNumber = 0;
		if ((Object)(object)character == (Object)null || (Object)(object)((MonoBehaviourPun)character).photonView == (Object)null || ((MonoBehaviourPun)character).photonView.Owner == null)
		{
			return false;
		}
		actorNumber = ((MonoBehaviourPun)character).photonView.Owner.ActorNumber;
		return true;
	}

	private static int TryCaptureSlot(ItemSlot slot, ICollection<RecordedInventoryItem> destination)
	{
		if (slot == null || slot.IsEmpty() || (Object)(object)slot.prefab == (Object)null)
		{
			return 0;
		}
		ItemInstanceData data = ((slot.data == null) ? null : slot.data.Copy());
		destination.Add(new RecordedInventoryItem(slot.prefab.itemID, ((Object)slot.prefab).name, data));
		return 1;
	}
}
[HarmonyPatch]
internal static class Patches
{
	[HarmonyPatch(typeof(RunManager), "Awake")]
	[HarmonyPostfix]
	private static void RunManagerAwakePostfix(RunManager __instance)
	{
		if ((Object)(object)__instance != (Object)null && (Object)(object)((Component)__instance).GetComponent<ReviewHandler>() == (Object)null)
		{
			((Component)__instance).gameObject.AddComponent<ReviewHandler>();
			PhotonView component = ((Component)__instance).GetComponent<PhotonView>();
			if ((Object)(object)component != (Object)null)
			{
				component.RefreshRpcMonoBehaviourCache();
			}
			Plugin.Log.LogInfo((object)"Attached the campfire respawn controller to RunManager.");
		}
	}

	[HarmonyPatch(typeof(RunManager), "StartRun")]
	[HarmonyPostfix]
	private static void RunManagerStartRunPostfix()
	{
		if ((Object)(object)ReviewHandler.Instance != (Object)null)
		{
			ReviewHandler.Instance.BeginRun();
		}
	}

	[HarmonyPatch(typeof(Character), "RPCEndGame")]
	[HarmonyPostfix]
	private static void CharacterEndGamePostfix()
	{
		if ((Object)(object)ReviewHandler.Instance != (Object)null)
		{
			ReviewHandler.Instance.EndRun();
		}
	}

	[HarmonyPatch(typeof(Character), "CheckEndGame")]
	[HarmonyPrefix]
	private static bool CharacterCheckEndGamePrefix()
	{
		if (!((Object)(object)ReviewHandler.Instance == (Object)null))
		{
			return !ReviewHandler.Instance.ShouldSuppressEndGame();
		}
		return true;
	}

	[HarmonyPatch(typeof(Campfire), "Light_Rpc")]
	[HarmonyPostfix]
	private static void CampfireLightPostfix(bool updateSegment)
	{
		if (updateSegment && (Object)(object)ReviewHandler.Instance != (Object)null)
		{
			ReviewHandler.Instance.CaptureCampfireCheckpoint();
		}
	}

	[HarmonyPatch(typeof(OrbFogHandler), "InitNewSphere")]
	[HarmonyPostfix]
	private static void OrbFogInitPostfix(FogSphereOrigin newOrigin)
	{
		if ((Object)(object)ReviewHandler.Instance != (Object)null)
		{
			ReviewHandler.Instance.RememberFogOrigin(newOrigin);
		}
	}

	[HarmonyPatch(typeof(GUIManager), "Awake")]
	[HarmonyPostfix]
	private static void GuiManagerAwakePostfix(GUIManager __instance)
	{
		//IL_0092: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)__instance == (Object)null || (Object)(object)((Component)__instance).GetComponentInChildren<ReviewUI>(true) != (Object)null)
		{
			return;
		}
		AscentUI componentInChildren = ((Component)__instance).GetComponentInChildren<AscentUI>(true);
		if ((Object)(object)componentInChildren == (Object)null)
		{
			Plugin.Log.LogWarning((object)"AscentUI was not found; the remaining-respawn counter is unavailable in this scene.");
			return;
		}
		GameObject obj = Object.Instantiate<GameObject>(((Component)componentInChildren).gameObject, ((Component)componentInChildren).transform.parent, false);
		((Object)obj).name = "CampfireRespawnUI";
		AscentUI component = obj.GetComponent<AscentUI>();
		if ((Object)(object)component != (Object)null)
		{
			Object.Destroy((Object)(object)component);
		}
		Transform transform = obj.transform;
		RectTransform val = (RectTransform)(object)((transform is RectTransform) ? transform : null);
		if ((Object)(object)val != (Object)null)
		{
			val.anchorMin = new Vector2(0.5f, 0f);
			val.anchorMax = new Vector2(0.5f, 0f);
			val.pivot = new Vector2(0.5f, 0f);
			val.anchoredPosition = new Vector2(0f, 10f);
			val.sizeDelta = new Vector2(400f, 120f);
		}
		TMP_Text componentInChildren2 = obj.GetComponentInChildren<TMP_Text>(true);
		if ((Object)(object)componentInChildren2 != (Object)null)
		{
			componentInChildren2.text = string.Empty;
		}
		obj.AddComponent<ReviewUI>();
	}
}
[BepInPlugin("com.Xiaohai.CampfireRespawn", "Campfire Respawn", "2.0.1")]
public sealed class Plugin : BaseUnityPlugin
{
	public const string GUID = "com.Xiaohai.CampfireRespawn";

	public const string NAME = "Campfire Respawn";

	public const string VERSION = "2.0.1";

	private Harmony _harmony;

	internal static Plugin Instance { get; private set; }

	internal static ManualLogSource Log { get; private set; }

	internal ConfigEntry<bool> CampfireClearStatus { get; private set; }

	internal ConfigEntry<bool> ReviveAddCurse { get; private set; }

	internal ConfigEntry<int> RespawnItemChance { get; private set; }

	internal ConfigEntry<KeyCode> RespawnHotkey { get; private set; }

	internal ConfigEntry<int> RespawnMaxTimes { get; private set; }

	internal ConfigEntry<bool> RecordItemsAtCampfire { get; private set; }

	internal int MaximumRespawns => Mathf.Max(0, RespawnMaxTimes.Value);

	internal int ItemRestoreChance => Mathf.Clamp(RespawnItemChance.Value, 0, 100);

	private void Awake()
	{
		//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00aa: Expected O, but got Unknown
		//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ff: Expected O, but got Unknown
		//IL_010a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0114: Expected O, but got Unknown
		Instance = this;
		Log = ((BaseUnityPlugin)this).Logger;
		CampfireClearStatus = ((BaseUnityPlugin)this).Config.Bind<bool>("Settings", "CampfireClearStatus", false, "Clear curable negative status effects while resting at a campfire. 在营火旁休息时清除可治愈的负面状态。");
		ReviveAddCurse = ((BaseUnityPlugin)this).Config.Bind<bool>("Settings", "ReviveClearStatus", false, "Apply the normal post-revive curse and hunger penalties. 复活时施加游戏原生的诅咒与饥饿惩罚。");
		RespawnHotkey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Settings", "RespawnHotkey", (KeyCode)292, "Force a campfire respawn (host only). 强制触发篝火复活(仅房主)。");
		RespawnMaxTimes = ((BaseUnityPlugin)this).Config.Bind<int>("Settings", "RespawnMaxTimes", 99, new ConfigDescription("Maximum respawns per run. 每局允许的最大复活次数。", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 999), Array.Empty<object>()));
		RecordItemsAtCampfire = ((BaseUnityPlugin)this).Config.Bind<bool>("Settings", "recordItemsAtCampfire", true, "TRUE restores the last campfire inventory; FALSE recovers items dropped during the wipe. TRUE:恢复最后一次篝火记录;FALSE:找回团灭时掉落的物品。");
		RespawnItemChance = ((BaseUnityPlugin)this).Config.Bind<int>("Settings", "RespawnItemChance", 88, new ConfigDescription("Chance (0-100) to restore each item. 每件物品被恢复的概率(0-100)。", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>()));
		_harmony = new Harmony("com.Xiaohai.CampfireRespawn");
		_harmony.PatchAll(typeof(Plugin).Assembly);
		((BaseUnityPlugin)this).Logger.LogInfo((object)"Campfire Respawn v2.0.1 loaded / 篝火复活 MOD 已加载");
	}

	private void OnDestroy()
	{
		if (_harmony != null)
		{
			_harmony.UnpatchSelf();
			_harmony = null;
		}
		Instance = null;
		Log = null;
	}
}
public sealed class ReviewUI : MonoBehaviour
{
	private const float DisplayDuration = 10f;

	private static ReviewUI _instance;

	private static bool _visible;

	private static int _remainingRespawns;

	private TMP_Text _text;

	private float _hideAt;

	private int _lastRenderedValue = int.MinValue;

	private void Awake()
	{
		//IL_0053: Unknown result type (might be due to invalid IL or missing references)
		_instance = this;
		_text = ((Component)this).GetComponentInChildren<TMP_Text>(true);
		if ((Object)(object)_text != (Object)null)
		{
			_text.richText = true;
			_text.alignment = (TextAlignmentOptions)257;
			_text.fontSize = 40f;
			((Graphic)_text).color = Color.white;
		}
		if (_visible)
		{
			_hideAt = Time.unscaledTime + 10f;
		}
		ApplyVisibility();
		RenderValueIfNeeded();
	}

	private void OnDestroy()
	{
		if ((Object)(object)_instance == (Object)(object)this)
		{
			_instance = null;
		}
	}

	private void Update()
	{
		if (_visible)
		{
			if (Time.unscaledTime >= _hideAt)
			{
				Hide();
			}
			else
			{
				RenderValueIfNeeded();
			}
		}
	}

	internal static void Show(int remainingRespawns)
	{
		_remainingRespawns = remainingRespawns;
		_visible = true;
		if ((Object)(object)_instance != (Object)null)
		{
			_instance._lastRenderedValue = int.MinValue;
			_instance._hideAt = Time.unscaledTime + 10f;
			_instance.ApplyVisibility();
			_instance.RenderValueIfNeeded();
		}
	}

	internal static void Hide()
	{
		_visible = false;
		if ((Object)(object)_instance != (Object)null)
		{
			_instance._lastRenderedValue = int.MinValue;
			_instance.ApplyVisibility();
		}
	}

	private void ApplyVisibility()
	{
		if ((Object)(object)_text != (Object)null)
		{
			_text.text = (_visible ? _text.text : string.Empty);
		}
	}

	private void RenderValueIfNeeded()
	{
		if (!((Object)(object)_text == (Object)null) && _lastRenderedValue != _remainingRespawns)
		{
			_lastRenderedValue = _remainingRespawns;
			_text.text = "<color=red><size=45>♥</size></color>" + _remainingRespawns;
		}
	}
}