The BepInEx console will not appear when launching like it does for other games on Thunderstore (you can turn it back on in your BepInEx.cfg file). If your PEAK crashes on startup, add -dx12 to your launch parameters.
Decompiled source of Hikers Hunger v2.0.0
tony4twentys-Hikers Hunger.dll
Decompiled 2 months agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using ExitGames.Client.Photon; using HarmonyLib; using Photon.Pun; using Photon.Realtime; using PhotonCustomPropsUtils; using UnityEngine; using UnityEngine.SceneManagement; using Zorro.Core; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("Hikers Hunger")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("Hikers Hunger")] [assembly: AssemblyCopyright("Copyright © 2025")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("99b406ad-6d25-4637-9908-9ab308ceb06e")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyVersion("1.0.0.0")] namespace HikersHunger; [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInPlugin("tony4twentys.Hikers_Hunger", "Hikers Hunger", "2.0.0")] public class HikersHungerPlugin : BaseUnityPlugin, IInRoomCallbacks, IMatchmakingCallbacks, IOnEventCallback { [Serializable] public struct HostCfg { public bool manualCannibalSelection; public int initialSelectionDelay; public int postSelectionDelay; public bool enableCustomEatTime; public float customEatTime; public bool constantCannibal; public float safeZoneDelay; } [HarmonyPatch(typeof(Action_RestoreHunger), "RunAction")] public class RestoreHungerPatch { private static bool Prefix(Action_RestoreHunger __instance) { if ((Object)(object)((Component)__instance).GetComponent<Character>() != (Object)null) { int cannibalViewID = Instance.cannibalViewID; Character localCharacter = Character.localCharacter; int? obj; if (localCharacter == null) { obj = null; } else { PhotonView photonView = ((MonoBehaviourPun)localCharacter).photonView; obj = ((photonView != null) ? new int?(photonView.ViewID) : null); } if (cannibalViewID == obj) { return true; } } else { int cannibalViewID2 = Instance.cannibalViewID; Character localCharacter2 = Character.localCharacter; int? obj2; if (localCharacter2 == null) { obj2 = null; } else { PhotonView photonView2 = ((MonoBehaviourPun)localCharacter2).photonView; obj2 = ((photonView2 != null) ? new int?(photonView2.ViewID) : null); } if (cannibalViewID2 == obj2) { return false; } } return true; } } [HarmonyPatch(typeof(RunManager), "StartRun")] public class StartRunPatch { private static void Postfix() { if (!((Object)(object)Singleton<MapHandler>.Instance == (Object)null)) { ((BaseUnityPlugin)Instance).Logger.LogInfo((object)"[HikersHunger] Run started!"); ((MonoBehaviour)Instance).StartCoroutine(Instance.SelectRandomCannibalAfterDelay()); } } } [HarmonyPatch(typeof(Campfire), "Light_Rpc")] public class CampfireLight_RpcPatch { private static void Postfix(Campfire __instance) { Instance.fireCount++; ((BaseUnityPlugin)Instance).Logger.LogInfo((object)$"[HikersHunger] Campfire lit! Total fires: {Instance.fireCount}"); foreach (Character allCharacter in Character.AllCharacters) { if (!allCharacter.isBot && !allCharacter.data.dead && (Object)(object)allCharacter.refs?.customization != (Object)null && allCharacter.IsLocal) { allCharacter.refs.customization.BecomeHuman(); } } ((BaseUnityPlugin)Instance).Logger.LogInfo((object)"[HikersHunger] All players restored to human appearance"); Instance.ForceRefreshSafeZoneStatus(); Instance.SelectNewCannibalAtCampfire(); } } [HarmonyPatch(typeof(CharacterInteractible), "GetInteractTime")] public class CharacterInteractible_GetInteractTime_Patch { private static void Postfix(CharacterInteractible __instance, Character interactor, ref float __result) { if (Synced.enableCustomEatTime && Instance.cannibalViewID == ((MonoBehaviourPun)interactor).photonView.ViewID) { if (IsCharacterNearCampfire(interactor)) { __result = 999f; } else if (Instance.inSafeZoneDelay) { ((BaseUnityPlugin)Instance).Logger.LogDebug((object)"[HikersHunger] Blocking eating during safe zone delay period"); __result = 999f; } else { __result = Synced.customEatTime; } } } } [HarmonyPatch(typeof(CharacterInteractible), "GetEaten")] public class CharacterInteractible_GetEaten_Patch { private static bool Prefix(CharacterInteractible __instance, Character eater) { if (Instance.cannibalViewID == ((MonoBehaviourPun)eater).photonView.ViewID) { if (IsCharacterNearCampfire(eater)) { ((BaseUnityPlugin)Instance).Logger.LogWarning((object)"[HikersHunger] BLOCKED: Cannibal attempted to eat player in safe zone!"); return false; } if (Instance.inSafeZoneDelay) { ((BaseUnityPlugin)Instance).Logger.LogWarning((object)"[HikersHunger] BLOCKED: Cannibal attempted to eat player during safe zone delay!"); ((BaseUnityPlugin)Instance).Logger.LogDebug((object)$"[HikersHunger] Safe zone delay state: inSafeZoneDelay={Instance.inSafeZoneDelay}, inSafeZone={Instance.inSafeZone}"); return false; } } return true; } private static void Postfix(CharacterInteractible __instance, Character eater) { if (Instance.cannibalViewID == ((MonoBehaviourPun)eater).photonView.ViewID) { eater.refs.afflictions.SetStatus((STATUSTYPE)5, 0f); ((BaseUnityPlugin)Instance).Logger.LogInfo((object)"[HikersHunger] Removed curse from cannibal after eating player"); } } } [HarmonyPatch(typeof(CharacterInteractible), "IsConstantlyInteractable")] public class CharacterInteractible_IsConstantlyInteractable_Patch { private static bool Postfix(bool __result, CharacterInteractible __instance, Character interactor) { if (__result && Instance.cannibalViewID == ((MonoBehaviourPun)interactor).photonView.ViewID) { if (IsCharacterNearCampfire(interactor)) { return false; } if (Instance.inSafeZoneDelay) { ((BaseUnityPlugin)Instance).Logger.LogDebug((object)"[HikersHunger] Blocking interaction during safe zone delay period"); return false; } } return __result; } } [CompilerGenerated] private sealed class <DelayCannibalPowers>d__74 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public int viewID; public HikersHungerPlugin <>4__this; private float <delay>5__1; private float <elapsed>5__2; private Exception <ex>5__3; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <DelayCannibalPowers>d__74(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <ex>5__3 = null; <>1__state = -2; } private bool MoveNext() { //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <delay>5__1 = Synced.postSelectionDelay; <elapsed>5__2 = 0f; ((BaseUnityPlugin)<>4__this).Logger.LogInfo((object)$"[HikersHunger] Waiting {<delay>5__1} seconds before granting powers..."); break; case 1: <>1__state = -1; <elapsed>5__2 += 1f; break; } if (<elapsed>5__2 < <delay>5__1) { <>2__current = (object)new WaitForSeconds(1f); <>1__state = 1; return true; } try { <>4__this.manager.SetRoomProperty("cannibalViewId", (object)viewID); ((BaseUnityPlugin)<>4__this).Logger.LogInfo((object)"[HikersHunger] Cannibal powers now active!"); } catch (Exception ex) { <ex>5__3 = ex; ((BaseUnityPlugin)<>4__this).Logger.LogError((object)("[HikersHunger] Failed to set room property: " + <ex>5__3.Message)); } return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <RestorePowersAfterDelay>d__37 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public HikersHungerPlugin <>4__this; private float <delay>5__1; private float <elapsed>5__2; private Exception <ex>5__3; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <RestorePowersAfterDelay>d__37(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <ex>5__3 = null; <>1__state = -2; } private bool MoveNext() { //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <delay>5__1 = Synced.safeZoneDelay; <elapsed>5__2 = 0f; ((BaseUnityPlugin)<>4__this).Logger.LogInfo((object)$"[HikersHunger] Starting {<delay>5__1}s safe zone delay before restoring powers..."); break; case 1: <>1__state = -1; <elapsed>5__2 += 0.5f; if (IsCharacterNearCampfire(Character.localCharacter)) { <>4__this.inSafeZone = true; ((BaseUnityPlugin)<>4__this).Logger.LogInfo((object)"[HikersHunger] Re-entered safe zone during delay - powers remain revoked"); return false; } if (Mathf.FloorToInt(<elapsed>5__2) % 5 == 0) { ((BaseUnityPlugin)<>4__this).Logger.LogInfo((object)$"[HikersHunger] Safe zone delay: {<elapsed>5__2:F1}s / {<delay>5__1}s remaining"); } break; } if (<elapsed>5__2 < <delay>5__1 && !<>4__this.inSafeZone) { <>2__current = (object)new WaitForSeconds(0.5f); <>1__state = 1; return true; } if (!<>4__this.inSafeZone && <>4__this.IsLocalPlayerCannibal()) { <>4__this.inSafeZoneDelay = false; ((BaseUnityPlugin)<>4__this).Logger.LogInfo((object)"[HikersHunger] Safe zone delay completed - powers restored"); if (<>4__this.cannibalViewID != -1) { int cannibalViewID = <>4__this.cannibalViewID; Character localCharacter = Character.localCharacter; int? obj; if (localCharacter == null) { obj = null; } else { PhotonView photonView = ((MonoBehaviourPun)localCharacter).photonView; obj = ((photonView != null) ? new int?(photonView.ViewID) : null); } if (cannibalViewID == obj) { ((BaseUnityPlugin)<>4__this).Logger.LogInfo((object)$"[HikersHunger] Cannibal was reselected during delay (ViewID: {<>4__this.cannibalViewID}) - updating room property"); try { <>4__this.manager.SetRoomProperty("cannibalViewId", (object)<>4__this.cannibalViewID); ((BaseUnityPlugin)<>4__this).Logger.LogInfo((object)"[HikersHunger] Room property updated after safe zone delay completion"); } catch (Exception ex) { <ex>5__3 = ex; ((BaseUnityPlugin)<>4__this).Logger.LogError((object)("[HikersHunger] Failed to update room property after delay: " + <ex>5__3.Message)); } goto IL_02a8; } } ((BaseUnityPlugin)<>4__this).Logger.LogInfo((object)"[HikersHunger] No room property update needed - cannibal not reselected during delay"); goto IL_02a8; } goto IL_02b5; IL_02a8: <>4__this.GrantCannibalPowers(); goto IL_02b5; IL_02b5: return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <SafeZoneMonitoringLoop>d__38 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public HikersHungerPlugin <>4__this; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <SafeZoneMonitoringLoop>d__38(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; break; case 1: <>1__state = -1; break; } <>4__this.CheckAllPlayersSafeZoneStatus(); <>2__current = (object)new WaitForSeconds(1f); <>1__state = 1; return true; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <SelectRandomCannibalAfterDelay>d__75 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public HikersHungerPlugin <>4__this; private float <delay>5__1; private float <elapsed>5__2; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <SelectRandomCannibalAfterDelay>d__75(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <delay>5__1 = Synced.initialSelectionDelay; <elapsed>5__2 = 0f; ((BaseUnityPlugin)<>4__this).Logger.LogInfo((object)$"[HikersHunger] Waiting {<delay>5__1} seconds before selecting cannibal..."); break; case 1: <>1__state = -1; <elapsed>5__2 += 1f; break; } if (<elapsed>5__2 < <delay>5__1) { <>2__current = (object)new WaitForSeconds(1f); <>1__state = 1; return true; } if (!PhotonNetwork.IsMasterClient) { return false; } if (Synced.manualCannibalSelection) { <>4__this.isWaitingForCannibalSelection = true; <>4__this.showCannibalSelectionGUI = true; } else { <>4__this.SelectRandomCannibal(); } return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private const string ROOM_CFG_KEY = "HIKERS_HUNGER_CFG_V1"; private const float CAMPFIRE_SAFE_RADIUS = 15f; private const float DEFAULT_SAFE_ZONE_DELAY = 30f; public static HikersHungerPlugin Instance; private int cannibalViewID = -1; private int fireCount = 0; private bool showCannibalSelectionGUI = false; private bool isWaitingForCannibalSelection = false; private bool cannibalPowersActive = false; private float safeZoneExitTime = 0f; private bool inSafeZone = false; private bool inSafeZoneDelay = false; private ConfigEntry<bool> manualCannibalSelection; private ConfigEntry<int> initialSelectionDelay; private ConfigEntry<int> postSelectionDelay; private ConfigEntry<bool> enableCustomEatTime; private ConfigEntry<float> customEatTime; private ConfigEntry<bool> constantCannibal; private ConfigEntry<float> safeZoneDelay; public static HostCfg Synced; private PhotonScopedManager manager; private Harmony harmony; private Coroutine safeZoneCheckCoroutine; private Coroutine powerRestorationCoroutine; private void Awake() { Instance = this; InitializeConfiguration(); InitializeHarmony(); InitializePhotonManager(); StartSafeZoneMonitoring(); SceneManager.activeSceneChanged += OnSceneChanged; UIPlayerNames.CANNIBAL_HUNGER_THRESHOLD = 2f; ((BaseUnityPlugin)this).Logger.LogInfo((object)"[HikersHunger] Plugin initialized successfully"); } private void InitializeConfiguration() { manualCannibalSelection = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ManualCannibalSelection", false, "When enabled, the host can manually select who becomes the cannibal using a GUI instead of random selection."); initialSelectionDelay = ((BaseUnityPlugin)this).Config.Bind<int>("General", "InitialSelectionDelay", 20, "The initial delay (in seconds) before the game starts attempting to select a cannibal."); postSelectionDelay = ((BaseUnityPlugin)this).Config.Bind<int>("General", "PostSelectionDelay", 120, "The delay (in seconds) after selecting a cannibal before actually giving them cannibal powers."); enableCustomEatTime = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "EnableCustomEatTime", false, "When enabled, allows hosts to customize how long it takes to eat players."); customEatTime = ((BaseUnityPlugin)this).Config.Bind<float>("General", "CustomEatTime", 0.01f, "The time (in seconds) it takes to eat a player. Lower values = faster eating. 0.01 = almost instant."); constantCannibal = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ConstantCannibal", false, "When enabled, the first person chosen as cannibal remains cannibal for the entire game until a new run starts."); safeZoneDelay = ((BaseUnityPlugin)this).Config.Bind<float>("General", "SafeZoneDelay", 30f, "The delay (in seconds) after leaving a safe zone before cannibal powers are restored."); Synced = BuildFromHostConfig(); manualCannibalSelection.SettingChanged += delegate { OnHostConfigChanged(); }; initialSelectionDelay.SettingChanged += delegate { OnHostConfigChanged(); }; postSelectionDelay.SettingChanged += delegate { OnHostConfigChanged(); }; enableCustomEatTime.SettingChanged += delegate { OnHostConfigChanged(); }; customEatTime.SettingChanged += delegate { OnHostConfigChanged(); }; constantCannibal.SettingChanged += delegate { OnHostConfigChanged(); }; safeZoneDelay.SettingChanged += delegate { OnHostConfigChanged(); }; } private void InitializeHarmony() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown harmony = new Harmony("tony4twentys.Hikers_Hunger"); harmony.PatchAll(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"[HikersHunger] Harmony patches applied"); } private void InitializePhotonManager() { manager = PhotonCustomPropsUtilsPlugin.GetManager("tony4twentys.Hikers_Hunger"); manager.RegisterRoomProperty<int>("cannibalViewId", (RoomEventType)2, (Action<int>)delegate(int value) { cannibalViewID = value; OnCannibalChanged(); }); } private void StartSafeZoneMonitoring() { if (safeZoneCheckCoroutine != null) { ((MonoBehaviour)this).StopCoroutine(safeZoneCheckCoroutine); } safeZoneCheckCoroutine = ((MonoBehaviour)this).StartCoroutine(SafeZoneMonitoringLoop()); } private void OnCannibalChanged() { if (cannibalViewID == -1) { return; } Character characterByViewID = GetCharacterByViewID(cannibalViewID); if ((Object)(object)characterByViewID != (Object)null) { ManualLogSource logger = ((BaseUnityPlugin)this).Logger; Player owner = characterByViewID.refs.view.Owner; logger.LogInfo((object)("[HikersHunger] " + (((owner != null) ? owner.NickName : null) ?? "Unknown") + " is now the cannibal")); } if (IsLocalPlayerCannibal()) { ((BaseUnityPlugin)this).Logger.LogInfo((object)$"[HikersHunger] Local player is now cannibal - checking safe zone delay state: inSafeZoneDelay={inSafeZoneDelay}"); if (inSafeZoneDelay) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"[HikersHunger] Local player is cannibal but still in safe zone delay - powers will be granted when delay completes"); return; } ((BaseUnityPlugin)this).Logger.LogInfo((object)"[HikersHunger] No safe zone delay active - granting powers immediately"); GrantCannibalPowers(); } } private Character GetCharacterByViewID(int viewID) { foreach (Character allCharacter in Character.AllCharacters) { if (allCharacter != null) { CharacterRefs refs = allCharacter.refs; int? obj; if (refs == null) { obj = null; } else { PhotonView view = refs.view; obj = ((view != null) ? new int?(view.ViewID) : null); } if (obj == viewID) { return allCharacter; } } } return null; } private bool IsLocalPlayerCannibal() { int num = cannibalViewID; Character localCharacter = Character.localCharacter; int? obj; if (localCharacter == null) { obj = null; } else { PhotonView photonView = ((MonoBehaviourPun)localCharacter).photonView; obj = ((photonView != null) ? new int?(photonView.ViewID) : null); } return num == obj; } private void GrantCannibalPowers() { if (IsLocalPlayerCannibal()) { UIPlayerNames.CANNIBAL_HUNGER_THRESHOLD = -1f; cannibalPowersActive = true; ((BaseUnityPlugin)this).Logger.LogInfo((object)"[HikersHunger] Local player cannibal powers granted"); CheckSafeZoneStatus(); } } private void RevokeCannibalPowers() { if (IsLocalPlayerCannibal()) { UIPlayerNames.CANNIBAL_HUNGER_THRESHOLD = 2f; cannibalPowersActive = false; ((BaseUnityPlugin)this).Logger.LogInfo((object)"[HikersHunger] Local player cannibal powers revoked"); } } private void StripCannibalPowers() { ((BaseUnityPlugin)this).Logger.LogInfo((object)"[HikersHunger] Stripping cannibal powers from all players"); UIPlayerNames.CANNIBAL_HUNGER_THRESHOLD = 2f; if (IsLocalPlayerCannibal()) { cannibalPowersActive = false; inSafeZone = false; safeZoneExitTime = 0f; if (powerRestorationCoroutine != null) { ((MonoBehaviour)this).StopCoroutine(powerRestorationCoroutine); } ((BaseUnityPlugin)this).Logger.LogInfo((object)$"[HikersHunger] Local cannibal powers stripped (inSafeZoneDelay={inSafeZoneDelay})"); } } private void CheckSafeZoneStatus() { if (!IsLocalPlayerCannibal()) { return; } bool flag = IsCharacterNearCampfire(Character.localCharacter); ((BaseUnityPlugin)this).Logger.LogDebug((object)$"[HikersHunger] Safe zone check: currentlyInSafeZone={flag}, inSafeZone={inSafeZone}"); if (flag && !inSafeZone) { inSafeZone = true; RevokeCannibalPowers(); safeZoneExitTime = 0f; if (powerRestorationCoroutine != null) { ((MonoBehaviour)this).StopCoroutine(powerRestorationCoroutine); } ((BaseUnityPlugin)this).Logger.LogInfo((object)"[HikersHunger] Entered campfire safe zone - powers revoked"); ((BaseUnityPlugin)this).Logger.LogInfo((object)$"[HikersHunger] Safe zone state: inSafeZone={inSafeZone}, inSafeZoneDelay={inSafeZoneDelay}"); } else if (!flag && inSafeZone) { inSafeZone = false; inSafeZoneDelay = true; safeZoneExitTime = Time.time; if (powerRestorationCoroutine != null) { ((MonoBehaviour)this).StopCoroutine(powerRestorationCoroutine); } powerRestorationCoroutine = ((MonoBehaviour)this).StartCoroutine(RestorePowersAfterDelay()); ((BaseUnityPlugin)this).Logger.LogInfo((object)"[HikersHunger] Exited campfire safe zone - starting power restoration timer"); ((BaseUnityPlugin)this).Logger.LogInfo((object)$"[HikersHunger] Safe zone state: inSafeZone={inSafeZone}, inSafeZoneDelay={inSafeZoneDelay}"); } } [IteratorStateMachine(typeof(<RestorePowersAfterDelay>d__37))] private IEnumerator RestorePowersAfterDelay() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <RestorePowersAfterDelay>d__37(0) { <>4__this = this }; } [IteratorStateMachine(typeof(<SafeZoneMonitoringLoop>d__38))] private IEnumerator SafeZoneMonitoringLoop() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <SafeZoneMonitoringLoop>d__38(0) { <>4__this = this }; } private void CheckAllPlayersSafeZoneStatus() { foreach (Character allCharacter in Character.AllCharacters) { if ((Object)(object)allCharacter == (Object)null || allCharacter.isBot || allCharacter.data.dead) { continue; } CharacterRefs refs = allCharacter.refs; int? obj; if (refs == null) { obj = null; } else { PhotonView view = refs.view; obj = ((view != null) ? new int?(view.ViewID) : null); } if (obj == cannibalViewID) { if (allCharacter.IsLocal) { CheckSafeZoneStatus(); } else { CheckRemoteCannibalSafeZoneStatus(allCharacter); } } } } private void CheckRemoteCannibalSafeZoneStatus(Character remoteCannibal) { bool flag = IsCharacterNearCampfire(remoteCannibal); } private void ForceRefreshSafeZoneStatus() { ((BaseUnityPlugin)this).Logger.LogInfo((object)"[HikersHunger] Force refreshing safe zone status for all players"); CheckAllPlayersSafeZoneStatus(); if (IsLocalPlayerCannibal()) { CheckSafeZoneStatus(); } } public static bool IsCharacterNearCampfire(Character character) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //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_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)character == (Object)null) { return false; } Vector3 center = character.Center; float num = 225f; try { Campfire[] array = Object.FindObjectsOfType<Campfire>(); if (array != null && array.Length != 0) { HikersHungerPlugin instance = Instance; if (instance != null) { ManualLogSource logger = ((BaseUnityPlugin)instance).Logger; if (logger != null) { object arg = array.Length; CharacterRefs refs = character.refs; object obj; if (refs == null) { obj = null; } else { PhotonView view = refs.view; if (view == null) { obj = null; } else { Player owner = view.Owner; obj = ((owner != null) ? owner.NickName : null); } } if (obj == null) { obj = "Unknown"; } logger.LogDebug((object)$"[HikersHunger] Found {arg} campfires, checking proximity for {obj}"); } } for (int i = 0; i < array.Length; i++) { Campfire val = array[i]; if ((Object)(object)val == (Object)null) { continue; } Vector3 val2 = ((Component)val).transform.position - center; float sqrMagnitude = ((Vector3)(ref val2)).sqrMagnitude; if (!(sqrMagnitude <= num)) { continue; } HikersHungerPlugin instance2 = Instance; if (instance2 != null) { ManualLogSource logger2 = ((BaseUnityPlugin)instance2).Logger; if (logger2 != null) { CharacterRefs refs2 = character.refs; object obj2; if (refs2 == null) { obj2 = null; } else { PhotonView view2 = refs2.view; if (view2 == null) { obj2 = null; } else { Player owner2 = view2.Owner; obj2 = ((owner2 != null) ? owner2.NickName : null); } } if (obj2 == null) { obj2 = "Unknown"; } logger2.LogDebug((object)$"[HikersHunger] {obj2} is within {Mathf.Sqrt(sqrMagnitude):F1}m of campfire {i + 1}"); } } return true; } HikersHungerPlugin instance3 = Instance; if (instance3 != null) { ManualLogSource logger3 = ((BaseUnityPlugin)instance3).Logger; if (logger3 != null) { CharacterRefs refs3 = character.refs; object obj3; if (refs3 == null) { obj3 = null; } else { PhotonView view3 = refs3.view; if (view3 == null) { obj3 = null; } else { Player owner3 = view3.Owner; obj3 = ((owner3 != null) ? owner3.NickName : null); } } if (obj3 == null) { obj3 = "Unknown"; } logger3.LogDebug((object)("[HikersHunger] " + (string?)obj3 + " is not near any campfires")); } } } else { HikersHungerPlugin instance4 = Instance; if (instance4 != null) { ManualLogSource logger4 = ((BaseUnityPlugin)instance4).Logger; if (logger4 != null) { logger4.LogDebug((object)"[HikersHunger] No campfires found in scene"); } } } } catch (Exception ex) { HikersHungerPlugin instance5 = Instance; if (instance5 != null) { ManualLogSource logger5 = ((BaseUnityPlugin)instance5).Logger; if (logger5 != null) { logger5.LogWarning((object)("[HikersHunger] Campfire search failed: " + ex.Message)); } } } return false; } private void OnEnable() { PhotonNetwork.AddCallbackTarget((object)this); } private void OnDisable() { PhotonNetwork.RemoveCallbackTarget((object)this); } private void OnDestroy() { if (safeZoneCheckCoroutine != null) { ((MonoBehaviour)this).StopCoroutine(safeZoneCheckCoroutine); } if (powerRestorationCoroutine != null) { ((MonoBehaviour)this).StopCoroutine(powerRestorationCoroutine); } PhotonNetwork.RemoveCallbackTarget((object)this); } private void OnSceneChanged(Scene oldScene, Scene newScene) { if (((Scene)(ref newScene)).name == "Airport") { ResetPluginState(); } TryReadConfigFromRoom(); } private void ResetPluginState() { ((BaseUnityPlugin)this).Logger.LogInfo((object)"[HikersHunger] Returned to Airport - resetting plugin state"); cannibalViewID = -1; fireCount = 0; showCannibalSelectionGUI = false; isWaitingForCannibalSelection = false; cannibalPowersActive = false; inSafeZone = false; inSafeZoneDelay = false; safeZoneExitTime = 0f; UIPlayerNames.CANNIBAL_HUNGER_THRESHOLD = 2f; foreach (Character allCharacter in Character.AllCharacters) { if ((Object)(object)allCharacter?.refs?.customization != (Object)null) { allCharacter.refs.customization.BecomeHuman(); } } } public void OnJoinedRoom() { if (PhotonNetwork.IsMasterClient) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"[HikersHunger] Joined room as HOST"); PublishConfig(); } else { ((BaseUnityPlugin)this).Logger.LogInfo((object)"[HikersHunger] Joined room as CLIENT; reading config"); TryReadConfigFromRoom(); } } public void OnCreatedRoom() { } public void OnCreateRoomFailed(short returnCode, string message) { } public void OnFriendListUpdate(List<FriendInfo> friendList) { } public void OnJoinRandomFailed(short returnCode, string message) { } public void OnJoinRoomFailed(short returnCode, string message) { } public void OnLeftRoom() { } public void OnPlayerEnteredRoom(Player newPlayer) { if (PhotonNetwork.IsMasterClient) { PublishConfig(); } } public void OnPlayerLeftRoom(Player otherPlayer) { if (cannibalViewID == -1 || otherPlayer == null) { return; } foreach (Character allCharacter in Character.AllCharacters) { object obj; if (allCharacter == null) { obj = null; } else { CharacterRefs refs = allCharacter.refs; if (refs == null) { obj = null; } else { PhotonView view = refs.view; obj = ((view != null) ? view.Owner : null); } } if (obj == otherPlayer && allCharacter.refs.view.ViewID == cannibalViewID) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("[HikersHunger] The cannibal (" + otherPlayer.NickName + ") has left the game!")); cannibalViewID = -1; cannibalPowersActive = false; inSafeZone = false; inSafeZoneDelay = false; UIPlayerNames.CANNIBAL_HUNGER_THRESHOLD = 2f; break; } } } public void OnRoomPropertiesUpdate(Hashtable propertiesThatChanged) { if (propertiesThatChanged != null && ((Dictionary<object, object>)(object)propertiesThatChanged).ContainsKey((object)"HIKERS_HUNGER_CFG_V1") && propertiesThatChanged[(object)"HIKERS_HUNGER_CFG_V1"] is string s) { HostCfg synced = Synced; Synced = UnpackCfg(s); if (ConfigChanged(synced, Synced)) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"[HikersHunger] Config updated from room"); } } } public void OnPlayerPropertiesUpdate(Player targetPlayer, Hashtable changedProps) { } public void OnMasterClientSwitched(Player newMasterClient) { if (PhotonNetwork.IsMasterClient) { PublishConfig(); } } public void OnEvent(EventData photonEvent) { } private HostCfg BuildFromHostConfig() { HostCfg result = default(HostCfg); result.manualCannibalSelection = manualCannibalSelection.Value; result.initialSelectionDelay = initialSelectionDelay.Value; result.postSelectionDelay = postSelectionDelay.Value; result.enableCustomEatTime = enableCustomEatTime.Value; result.customEatTime = customEatTime.Value; result.constantCannibal = constantCannibal.Value; result.safeZoneDelay = safeZoneDelay.Value; return result; } private static string PackCfg(HostCfg c) { CultureInfo invariantCulture = CultureInfo.InvariantCulture; return $"{c.manualCannibalSelection}|{c.initialSelectionDelay}|{c.postSelectionDelay}|{c.enableCustomEatTime}|{c.customEatTime}|{c.constantCannibal}|{c.safeZoneDelay}"; } private static HostCfg UnpackCfg(string s) { CultureInfo invariantCulture = CultureInfo.InvariantCulture; string[] array = (s ?? string.Empty).Split(new char[1] { '|' }); HostCfg hostCfg = default(HostCfg); hostCfg.manualCannibalSelection = false; hostCfg.initialSelectionDelay = 20; hostCfg.postSelectionDelay = 120; hostCfg.enableCustomEatTime = false; hostCfg.customEatTime = 0.01f; hostCfg.constantCannibal = false; hostCfg.safeZoneDelay = 30f; HostCfg result = hostCfg; if (array.Length >= 7) { bool.TryParse(array[0], out result.manualCannibalSelection); int.TryParse(array[1], NumberStyles.Integer, invariantCulture, out result.initialSelectionDelay); int.TryParse(array[2], NumberStyles.Integer, invariantCulture, out result.postSelectionDelay); bool.TryParse(array[3], out result.enableCustomEatTime); float.TryParse(array[4], NumberStyles.Float, invariantCulture, out result.customEatTime); bool.TryParse(array[5], out result.constantCannibal); float.TryParse(array[6], NumberStyles.Float, invariantCulture, out result.safeZoneDelay); } return result; } private bool ConfigChanged(HostCfg old, HostCfg newCfg) { return old.manualCannibalSelection != newCfg.manualCannibalSelection || old.initialSelectionDelay != newCfg.initialSelectionDelay || old.postSelectionDelay != newCfg.postSelectionDelay || old.enableCustomEatTime != newCfg.enableCustomEatTime || old.customEatTime != newCfg.customEatTime || old.constantCannibal != newCfg.constantCannibal || old.safeZoneDelay != newCfg.safeZoneDelay; } private void TryReadConfigFromRoom() { Room currentRoom = PhotonNetwork.CurrentRoom; object value = default(object); if (currentRoom != null && (((Dictionary<object, object>)(object)((RoomInfo)currentRoom).CustomProperties)?.TryGetValue((object)"HIKERS_HUNGER_CFG_V1", out value)).GetValueOrDefault() && value is string s) { Synced = UnpackCfg(s); } } private void OnHostConfigChanged() { if (PhotonNetwork.IsMasterClient) { PublishConfig(); } } private void PublishConfig() { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Expected O, but got Unknown Room currentRoom = PhotonNetwork.CurrentRoom; if (currentRoom != null) { Synced = BuildFromHostConfig(); string text = PackCfg(Synced); Hashtable val = new Hashtable { [(object)"HIKERS_HUNGER_CFG_V1"] = text }; currentRoom.SetCustomProperties(val, (Hashtable)null, (WebFlags)null); ((BaseUnityPlugin)this).Logger.LogInfo((object)"[HikersHunger] Host published config to room"); } } private void OnGUI() { if (showCannibalSelectionGUI && PhotonNetwork.IsMasterClient && isWaitingForCannibalSelection) { DrawCannibalSelectionGUI(); } } private void DrawCannibalSelectionGUI() { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: 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_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Expected O, but got Unknown //IL_01f1: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Unknown result type (might be due to invalid IL or missing references) HandleMenuInput(); GUI.color = new Color(0f, 0f, 0f, 0.8f); GUI.Box(new Rect(0f, 0f, (float)Screen.width, (float)Screen.height), ""); GUI.color = Color.white; float num = 400f; float num2 = 300f; float num3 = ((float)Screen.width - num) / 2f; float num4 = ((float)Screen.height - num2) / 2f; GUI.Box(new Rect(num3, num4, num, num2), "Select Cannibal"); GUI.Label(new Rect(num3 + 10f, num4 + 20f, num - 20f, 30f), "Choose who will become the cannibal:", new GUIStyle(GUI.skin.label) { fontSize = 16, alignment = (TextAnchor)4 }); float num5 = num4 + 60f; float num6 = 40f; float num7 = 5f; List<Character> validCandidates = GetValidCandidates(); foreach (Character item in validCandidates) { if (num5 + num6 > num4 + num2 - 60f) { break; } Player owner = item.refs.view.Owner; string text = ((owner != null) ? owner.NickName : null) ?? "Unknown Player"; if (GUI.Button(new Rect(num3 + 20f, num5, num - 40f, num6), text)) { if (cannibalViewID != -1) { StripCannibalPowers(); } SelectCannibal(item, isInitialSelection: true); CloseGUI(); } num5 += num6 + num7; } if (GUI.Button(new Rect(num3 + 20f, num4 + num2 - 40f, num - 40f, 30f), "Cancel (Random Selection)")) { CloseGUI(); ((MonoBehaviour)this).StartCoroutine(SelectRandomCannibalAfterDelay()); } } private void HandleMenuInput() { Cursor.lockState = (CursorLockMode)0; Cursor.visible = true; } private void CloseGUI() { showCannibalSelectionGUI = false; isWaitingForCannibalSelection = false; Cursor.lockState = (CursorLockMode)1; Cursor.visible = false; } private List<Character> GetValidCandidates() { List<Character> list = new List<Character>(); foreach (Character allCharacter in Character.AllCharacters) { object obj; if (allCharacter == null) { obj = null; } else { CharacterRefs refs = allCharacter.refs; if (refs == null) { obj = null; } else { PhotonView view = refs.view; obj = ((view != null) ? view.Owner : null); } } if (obj != null && !allCharacter.isBot && !allCharacter.data.dead) { list.Add(allCharacter); } } return list; } private void SelectCannibal(Character character, bool isInitialSelection = false) { if ((Object)(object)character?.refs?.view == (Object)null) { return; } int viewID = character.refs.view.ViewID; bool flag = cannibalViewID == viewID; string text = (isInitialSelection ? "initial" : "campfire"); ManualLogSource logger = ((BaseUnityPlugin)this).Logger; Player owner = character.refs.view.Owner; logger.LogInfo((object)("[HikersHunger] " + text + " cannibal selected: " + (((owner != null) ? owner.NickName : null) ?? "Unknown"))); if (isInitialSelection) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"[HikersHunger] Applying initial selection delay..."); cannibalViewID = viewID; ((MonoBehaviour)this).StartCoroutine(DelayCannibalPowers(viewID)); return; } if (flag && inSafeZoneDelay) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"[HikersHunger] Reselecting same cannibal who was in safe zone delay - powers will be granted when delay completes"); cannibalViewID = viewID; return; } ((BaseUnityPlugin)this).Logger.LogInfo((object)"[HikersHunger] Granting campfire selection powers immediately..."); cannibalViewID = viewID; try { manager.SetRoomProperty("cannibalViewId", (object)viewID); ((BaseUnityPlugin)this).Logger.LogInfo((object)"[HikersHunger] Cannibal powers now active!"); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("[HikersHunger] Failed to set room property: " + ex.Message)); } } [IteratorStateMachine(typeof(<DelayCannibalPowers>d__74))] private IEnumerator DelayCannibalPowers(int viewID) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <DelayCannibalPowers>d__74(0) { <>4__this = this, viewID = viewID }; } [IteratorStateMachine(typeof(<SelectRandomCannibalAfterDelay>d__75))] private IEnumerator SelectRandomCannibalAfterDelay() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <SelectRandomCannibalAfterDelay>d__75(0) { <>4__this = this }; } private void SelectRandomCannibal() { if (PhotonNetwork.IsMasterClient) { List<Character> validCandidates = GetValidCandidates(); if (validCandidates.Count > 0) { int index = Random.Range(0, validCandidates.Count); SelectCannibal(validCandidates[index], isInitialSelection: true); } } } private void SelectNewCannibalAtCampfire() { if (!PhotonNetwork.IsMasterClient) { return; } if (Synced.constantCannibal) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"[HikersHunger] Constant cannibal mode - keeping current cannibal"); return; } if (cannibalViewID != -1 && inSafeZoneDelay) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"[HikersHunger] Current cannibal is in safe zone delay - will be reselected but powers delayed"); ManualLogSource logger = ((BaseUnityPlugin)this).Logger; object arg = cannibalViewID; Character localCharacter = Character.localCharacter; int? obj; if (localCharacter == null) { obj = null; } else { PhotonView photonView = ((MonoBehaviourPun)localCharacter).photonView; obj = ((photonView != null) ? new int?(photonView.ViewID) : null); } logger.LogInfo((object)$"[HikersHunger] Current cannibal ViewID: {arg}, Local player ViewID: {obj}"); } if (cannibalViewID != -1) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"[HikersHunger] Stripping powers from current cannibal before selecting new one"); StripCannibalPowers(); } if (Synced.manualCannibalSelection) { isWaitingForCannibalSelection = true; showCannibalSelectionGUI = true; } else { SelectRandomCannibalAtCampfire(); } } private void SelectRandomCannibalAtCampfire() { if (PhotonNetwork.IsMasterClient) { List<Character> validCandidates = GetValidCandidates(); if (validCandidates.Count > 0) { int index = Random.Range(0, validCandidates.Count); Character val = validCandidates[index]; ManualLogSource logger = ((BaseUnityPlugin)this).Logger; Player owner = val.refs.view.Owner; logger.LogInfo((object)("[HikersHunger] Randomly selecting " + (((owner != null) ? owner.NickName : null) ?? "Unknown") + " as cannibal at campfire")); ((BaseUnityPlugin)this).Logger.LogInfo((object)$"[HikersHunger] Selected character ViewID: {val.refs.view.ViewID}, Current cannibal ViewID: {cannibalViewID}"); ((BaseUnityPlugin)this).Logger.LogInfo((object)$"[HikersHunger] Safe zone delay state: inSafeZoneDelay={inSafeZoneDelay}"); SelectCannibal(val); } } } }