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