Decompiled source of Zombie Survival World v1.2.3

BepInEx/plugins/Zombie_Survival_World/Zombie_Survival_World.dll

Decompiled 2 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using AK_Gun;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using ExitGames.Client.Photon;
using HarmonyLib;
using Photon.Pun;
using Photon.Realtime;
using UnityEngine;
using UnityEngine.Networking;
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("좀비서바이벌")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("좀비서바이벌")]
[assembly: AssemblyCopyright("Copyright ©  2026")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("36367a36-a880-4ba0-9250-87e7bd78aa73")]
[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 ZombieNoBones
{
	[BepInPlugin("com.Sapphire009.zombienobones", "Zombie No Bones", "1.1.0")]
	public class Plugin : BaseUnityPlugin
	{
		internal static ManualLogSource Log;

		private Harmony _harmony;

		internal const float DeadCleanupDelaySeconds = 3f;

		internal static FieldInfo TimeDiedAtField;

		private void Awake()
		{
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			TimeDiedAtField = AccessTools.Field(typeof(MushroomZombie), "timeDiedAt");
			if (TimeDiedAtField == null)
			{
				Log.LogWarning((object)"Could not find MushroomZombie.timeDiedAt field.");
			}
			_harmony = new Harmony("com.Sapphire009.zombienobones");
			_harmony.PatchAll();
			Log.LogInfo((object)$"Zombie No Bones loaded. Dead cleanup delay = {3f}s");
		}

		private void OnDestroy()
		{
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}
	}
	[HarmonyPatch(typeof(MushroomZombie), "ReadyToDisable")]
	internal static class Patch_MushroomZombie_ReadyToDisable
	{
		[HarmonyPrefix]
		private static bool Prefix(MushroomZombie __instance, ref bool __result)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Invalid comparison between Unknown and I4
			if ((Object)(object)__instance == (Object)null)
			{
				__result = false;
				return false;
			}
			try
			{
				if ((int)__instance.currentState == 6)
				{
					if (Plugin.TimeDiedAtField == null)
					{
						__result = false;
						return false;
					}
					object value = Plugin.TimeDiedAtField.GetValue(__instance);
					float num = 0f;
					if (value is float num2)
					{
						num = num2;
					}
					__result = num + 3f < Time.time;
					return false;
				}
				return true;
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"[Patch_MushroomZombie_ReadyToDisable] {arg}");
				return true;
			}
		}
	}
	[HarmonyPatch(typeof(MushroomZombie), "DestroyZombie")]
	internal static class Patch_MushroomZombie_DestroyZombie
	{
		[HarmonyPrefix]
		private static bool Prefix(MushroomZombie __instance)
		{
			if ((Object)(object)__instance == (Object)null)
			{
				return false;
			}
			if (!PhotonNetwork.IsMasterClient)
			{
				return false;
			}
			try
			{
				if ((Object)(object)ZombieManager.Instance != (Object)null)
				{
					ZombieManager.Instance.DeRegisterZombie(__instance);
				}
				if ((Object)(object)__instance.spawner != (Object)null)
				{
					__instance.spawner.spawnedZombie = null;
					Object.Destroy((Object)(object)((Component)__instance.spawner).gameObject);
				}
				PhotonView component = ((Component)__instance).GetComponent<PhotonView>();
				if ((Object)(object)component != (Object)null)
				{
					PhotonNetwork.Destroy(((Component)__instance).gameObject);
				}
				else
				{
					Object.Destroy((Object)(object)((Component)__instance).gameObject);
				}
				Plugin.Log.LogInfo((object)"Destroyed zombie without original DestroyZombie flow.");
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"[Patch_MushroomZombie_DestroyZombie] {arg}");
			}
			return false;
		}
	}
}
namespace ZombieBase
{
	[BepInPlugin("com.Sapphire009.peakzombieruntimeoverride", "좀비 기본 스텟", "1.1.1")]
	public class Plugin : BaseUnityPlugin, IInRoomCallbacks
	{
		internal static ManualLogSource Log;

		private static Type _peakType;

		private static FieldInfo _instanceField;

		private static FieldInfo _reachForceField;

		private static FieldInfo _distanceBeforeWakeupField;

		private static FieldInfo _lookAngleBeforeWakeupField;

		private static FieldInfo _initialWakeUpTimeField;

		private static FieldInfo _distanceBeforeChaseField;

		private static FieldInfo _zombieSprintDistanceField;

		private static FieldInfo _chaseTimeBeforeSprintField;

		private static FieldInfo _zombieLungeDistanceField;

		private static FieldInfo _lungeTimeField;

		private static FieldInfo _lungeRecoveryTimeField;

		private static FieldInfo _biteStunTimeField;

		private static FieldInfo _biteInitialInjuryField;

		private static FieldInfo _biteInitialSporesField;

		private static FieldInfo _biteDelayBeforeSporesField;

		private static FieldInfo _biteSporesPerSecondField;

		private static FieldInfo _totalBiteSporesTimeField;

		private static FieldInfo _distanceToEnableField;

		private static FieldInfo _zombieGruntWaitMinField;

		private static FieldInfo _zombieGruntWaitMaxField;

		private static FieldInfo _mushroomGrowTimeMinField;

		private static FieldInfo _mushroomGrowTimeMaxField;

		private static FieldInfo _attackHeightDeltaField;

		private float _nextApplyTime;

		private float _nextPublishTime;

		private static ZombieStatSet _activeStats;

		private static ZombieStatSet _hostStats;

		private static ConfigEntry<float> _넉백;

		private static ConfigEntry<float> _일어나는거리;

		private static ConfigEntry<float> _일어나는반경;

		private static ConfigEntry<float> _좀비리스폰후일어나는시간;

		private static ConfigEntry<float> _추격전거리;

		private static ConfigEntry<float> _nM내에서달리기;

		private static ConfigEntry<float> _일어나고n초후물기;

		private static ConfigEntry<float> _점프최소거리;

		private static ConfigEntry<float> _점프시간;

		private static ConfigEntry<float> _점프후회복시간;

		private static ConfigEntry<float> _플레이어스턴시간;

		private static ConfigEntry<float> _BiteInitialInjury;

		private static ConfigEntry<float> _BiteInitialSpores;

		private static ConfigEntry<float> _BiteDelayBeforeSpores;

		private static ConfigEntry<float> _BiteSporesPerSecond;

		private static ConfigEntry<float> _TotalBiteSporesTime;

		private static ConfigEntry<float> _DistanceToEnable;

		private static ConfigEntry<float> _좀비하울링소리최소;

		private static ConfigEntry<float> _좀비하울링소리최대;

		private static ConfigEntry<float> _MushroomGrowTimeMin;

		private static ConfigEntry<float> _MushroomGrowTimeMax;

		private static ConfigEntry<float> _공격높이;

		private const string ROOM_KEY_VERSION = "szw_stats_version";

		private const string ROOM_KEY_REACH_FORCE = "szw_reachForce";

		private const string ROOM_KEY_DISTANCE_BEFORE_WAKEUP = "szw_distWake";

		private const string ROOM_KEY_LOOK_ANGLE_BEFORE_WAKEUP = "szw_lookWake";

		private const string ROOM_KEY_INITIAL_WAKEUP_TIME = "szw_initWake";

		private const string ROOM_KEY_DISTANCE_BEFORE_CHASE = "szw_distChase";

		private const string ROOM_KEY_ZOMBIE_SPRINT_DISTANCE = "szw_sprintDist";

		private const string ROOM_KEY_CHASE_TIME_BEFORE_SPRINT = "szw_chaseSprint";

		private const string ROOM_KEY_ZOMBIE_LUNGE_DISTANCE = "szw_lungeDist";

		private const string ROOM_KEY_LUNGE_TIME = "szw_lungeTime";

		private const string ROOM_KEY_LUNGE_RECOVERY_TIME = "szw_lungeRecover";

		private const string ROOM_KEY_BITE_STUN_TIME = "szw_biteStun";

		private const string ROOM_KEY_BITE_INITIAL_INJURY = "szw_biteInjury";

		private const string ROOM_KEY_BITE_INITIAL_SPORES = "szw_biteSpores0";

		private const string ROOM_KEY_BITE_DELAY_BEFORE_SPORES = "szw_biteDelay";

		private const string ROOM_KEY_BITE_SPORES_PER_SECOND = "szw_bitePerSec";

		private const string ROOM_KEY_TOTAL_BITE_SPORES_TIME = "szw_biteTotal";

		private const string ROOM_KEY_DISTANCE_TO_ENABLE = "szw_distEnable";

		private const string ROOM_KEY_ZOMBIE_GRUNT_WAIT_MIN = "szw_gruntMin";

		private const string ROOM_KEY_ZOMBIE_GRUNT_WAIT_MAX = "szw_gruntMax";

		private const string ROOM_KEY_MUSHROOM_GROW_TIME_MIN = "szw_growMin";

		private const string ROOM_KEY_MUSHROOM_GROW_TIME_MAX = "szw_growMax";

		private const string ROOM_KEY_ATTACK_HEIGHT_DELTA = "szw_attackHeight";

		private void Awake()
		{
			Log = ((BaseUnityPlugin)this).Logger;
			((BaseUnityPlugin)this).Config.SaveOnConfigSet = true;
			BindConfigs();
			_hostStats = CreateStatsFromConfig();
			_activeStats = _hostStats;
			CacheReflection();
			SceneManager.sceneLoaded += OnSceneLoaded;
			PhotonNetwork.AddCallbackTarget((object)this);
			if (PhotonNetwork.InRoom)
			{
				if (PhotonNetwork.IsMasterClient)
				{
					PublishHostStatsToRoom(force: true);
				}
				else
				{
					TryPullStatsFromRoom();
				}
			}
			ApplyAll(forceLog: true);
			Log.LogInfo((object)"좀비 기본 스텟 loaded.");
		}

		private void OnDestroy()
		{
			SceneManager.sceneLoaded -= OnSceneLoaded;
			PhotonNetwork.RemoveCallbackTarget((object)this);
		}

		private void Update()
		{
			if (PhotonNetwork.InRoom)
			{
				if (PhotonNetwork.IsMasterClient)
				{
					_hostStats = CreateStatsFromConfig();
					_activeStats = _hostStats;
					if (Time.time >= _nextPublishTime)
					{
						_nextPublishTime = Time.time + 2f;
						PublishHostStatsToRoom(force: false);
					}
				}
				else
				{
					TryPullStatsFromRoom();
				}
			}
			else
			{
				_hostStats = CreateStatsFromConfig();
				_activeStats = _hostStats;
			}
			if (!(Time.time < _nextApplyTime))
			{
				_nextApplyTime = Time.time + 1f;
				ApplyAll(forceLog: false);
			}
		}

		private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
		{
			if (PhotonNetwork.InRoom)
			{
				if (PhotonNetwork.IsMasterClient)
				{
					_hostStats = CreateStatsFromConfig();
					PublishHostStatsToRoom(force: true);
				}
				else
				{
					TryPullStatsFromRoom();
				}
			}
			ApplyAll(forceLog: true);
		}

		private void BindConfigs()
		{
			_넉백 = ((BaseUnityPlugin)this).Config.Bind<float>("좀비 기본 스텟", "넉백", -1f, "ReachForce");
			_일어나는거리 = ((BaseUnityPlugin)this).Config.Bind<float>("좀비 기본 스텟", "일어나는 거리", 50f, "DistanceBeforeWakeup");
			_일어나는반경 = ((BaseUnityPlugin)this).Config.Bind<float>("좀비 기본 스텟", "일어나는 반경", 360f, "LookAngleBeforeWakeup");
			_좀비리스폰후일어나는시간 = ((BaseUnityPlugin)this).Config.Bind<float>("좀비 기본 스텟", "좀비 리스폰 후 일어나는 시간", 0f, "InitialWakeUpTime");
			_추격전거리 = ((BaseUnityPlugin)this).Config.Bind<float>("좀비 기본 스텟", "추격 전 거리", 0f, "DistanceBeforeChase");
			_nM내에서달리기 = ((BaseUnityPlugin)this).Config.Bind<float>("좀비 기본 스텟", "nM내에서 달리기", 300000f, "ZombieSprintDistance");
			_일어나고n초후물기 = ((BaseUnityPlugin)this).Config.Bind<float>("좀비 기본 스텟", "일어나고 n초 후 물기", 0f, "ChaseTimeBeforeSprint");
			_점프최소거리 = ((BaseUnityPlugin)this).Config.Bind<float>("좀비 기본 스텟", "점프 최소거리", 3f, "ZombieLungeDistance");
			_점프시간 = ((BaseUnityPlugin)this).Config.Bind<float>("좀비 기본 스텟", "점프 시간", 1.5f, "LungeTime");
			_점프후회복시간 = ((BaseUnityPlugin)this).Config.Bind<float>("좀비 기본 스텟", "점프 후 회복시간", 1f, "LungeRecoveryTime");
			_플레이어스턴시간 = ((BaseUnityPlugin)this).Config.Bind<float>("좀비 기본 스텟", "플레이어 스턴시간", 2f, "BiteStunTime");
			_BiteInitialInjury = ((BaseUnityPlugin)this).Config.Bind<float>("좀비 기본 스텟", "BiteInitialInjury", 0.1f, "BiteInitialInjury");
			_BiteInitialSpores = ((BaseUnityPlugin)this).Config.Bind<float>("좀비 기본 스텟", "BiteInitialSpores", 0.1f, "BiteInitialSpores");
			_BiteDelayBeforeSpores = ((BaseUnityPlugin)this).Config.Bind<float>("좀비 기본 스텟", "BiteDelayBeforeSpores", -1f, "BiteDelayBeforeSpores");
			_BiteSporesPerSecond = ((BaseUnityPlugin)this).Config.Bind<float>("좀비 기본 스텟", "BiteSporesPerSecond", -1f, "BiteSporesPerSecond");
			_TotalBiteSporesTime = ((BaseUnityPlugin)this).Config.Bind<float>("좀비 기본 스텟", "TotalBiteSporesTime", -1f, "TotalBiteSporesTime");
			_DistanceToEnable = ((BaseUnityPlugin)this).Config.Bind<float>("좀비 기본 스텟", "DistanceToEnable", -1f, "DistanceToEnable");
			_좀비하울링소리최소 = ((BaseUnityPlugin)this).Config.Bind<float>("좀비 기본 스텟", "좀비 하울링 소리 최소", 10f, "ZombieGruntWaitMin");
			_좀비하울링소리최대 = ((BaseUnityPlugin)this).Config.Bind<float>("좀비 기본 스텟", "좀비 하울링 소리 최대", 20f, "ZombieGruntWaitMax");
			_MushroomGrowTimeMin = ((BaseUnityPlugin)this).Config.Bind<float>("좀비 기본 스텟", "MushroomGrowTimeMin", -1f, "MushroomGrowTimeMin");
			_MushroomGrowTimeMax = ((BaseUnityPlugin)this).Config.Bind<float>("좀비 기본 스텟", "MushroomGrowTimeMax", -1f, "MushroomGrowTimeMax");
			_공격높이 = ((BaseUnityPlugin)this).Config.Bind<float>("좀비 기본 스텟", "공격 높이", 5f, "AttackHeightDelta");
		}

		private static ZombieStatSet CreateStatsFromConfig()
		{
			ZombieStatSet result = default(ZombieStatSet);
			result.ReachForce = ((_넉백 != null) ? _넉백.Value : (-1f));
			result.DistanceBeforeWakeup = ((_일어나는거리 != null) ? _일어나는거리.Value : 50f);
			result.LookAngleBeforeWakeup = ((_일어나는반경 != null) ? _일어나는반경.Value : 360f);
			result.InitialWakeUpTime = ((_좀비리스폰후일어나는시간 != null) ? _좀비리스폰후일어나는시간.Value : 0f);
			result.DistanceBeforeChase = ((_추격전거리 != null) ? _추격전거리.Value : 0f);
			result.ZombieSprintDistance = ((_nM내에서달리기 != null) ? _nM내에서달리기.Value : 300000f);
			result.ChaseTimeBeforeSprint = ((_일어나고n초후물기 != null) ? _일어나고n초후물기.Value : 0f);
			result.ZombieLungeDistance = ((_점프최소거리 != null) ? _점프최소거리.Value : 3f);
			result.LungeTime = ((_점프시간 != null) ? _점프시간.Value : 1.5f);
			result.LungeRecoveryTime = ((_점프후회복시간 != null) ? _점프후회복시간.Value : 1f);
			result.BiteStunTime = ((_플레이어스턴시간 != null) ? _플레이어스턴시간.Value : 2f);
			result.BiteInitialInjury = ((_BiteInitialInjury != null) ? _BiteInitialInjury.Value : 0.1f);
			result.BiteInitialSpores = ((_BiteInitialSpores != null) ? _BiteInitialSpores.Value : 0.1f);
			result.BiteDelayBeforeSpores = ((_BiteDelayBeforeSpores != null) ? _BiteDelayBeforeSpores.Value : (-1f));
			result.BiteSporesPerSecond = ((_BiteSporesPerSecond != null) ? _BiteSporesPerSecond.Value : (-1f));
			result.TotalBiteSporesTime = ((_TotalBiteSporesTime != null) ? _TotalBiteSporesTime.Value : (-1f));
			result.DistanceToEnable = ((_DistanceToEnable != null) ? _DistanceToEnable.Value : (-1f));
			result.ZombieGruntWaitMin = ((_좀비하울링소리최소 != null) ? _좀비하울링소리최소.Value : 10f);
			result.ZombieGruntWaitMax = ((_좀비하울링소리최대 != null) ? _좀비하울링소리최대.Value : 20f);
			result.MushroomGrowTimeMin = ((_MushroomGrowTimeMin != null) ? _MushroomGrowTimeMin.Value : (-1f));
			result.MushroomGrowTimeMax = ((_MushroomGrowTimeMax != null) ? _MushroomGrowTimeMax.Value : (-1f));
			result.AttackHeightDelta = ((_공격높이 != null) ? _공격높이.Value : 5f);
			return result;
		}

		private static void CacheReflection()
		{
			_peakType = AccessTools.TypeByName("Zombies_Anywhere.ZombiesAnywhereMod");
			if (_peakType == null)
			{
				Log.LogWarning((object)"Zombies_Anywhere.ZombiesAnywhereMod not found.");
				return;
			}
			_instanceField = AccessTools.Field(_peakType, "_instance");
			_reachForceField = AccessTools.Field(_peakType, "reachForce");
			_distanceBeforeWakeupField = AccessTools.Field(_peakType, "distanceBeforeWakeup");
			_lookAngleBeforeWakeupField = AccessTools.Field(_peakType, "lookAngleBeforeWakeup");
			_initialWakeUpTimeField = AccessTools.Field(_peakType, "initialWakeUpTime");
			_distanceBeforeChaseField = AccessTools.Field(_peakType, "distanceBeforeChase");
			_zombieSprintDistanceField = AccessTools.Field(_peakType, "zombieSprintDistance");
			_chaseTimeBeforeSprintField = AccessTools.Field(_peakType, "chaseTimeBeforeSprint");
			_zombieLungeDistanceField = AccessTools.Field(_peakType, "zombieLungeDistance");
			_lungeTimeField = AccessTools.Field(_peakType, "lungeTime");
			_lungeRecoveryTimeField = AccessTools.Field(_peakType, "lungeRecoveryTime");
			_biteStunTimeField = AccessTools.Field(_peakType, "biteStunTime");
			_biteInitialInjuryField = AccessTools.Field(_peakType, "biteInitialInjury");
			_biteInitialSporesField = AccessTools.Field(_peakType, "biteInitialSpores");
			_biteDelayBeforeSporesField = AccessTools.Field(_peakType, "biteDelayBeforeSpores");
			_biteSporesPerSecondField = AccessTools.Field(_peakType, "biteSporesPerSecond");
			_totalBiteSporesTimeField = AccessTools.Field(_peakType, "totalBiteSporesTime");
			_distanceToEnableField = AccessTools.Field(_peakType, "distanceToEnable");
			_zombieGruntWaitMinField = AccessTools.Field(_peakType, "zombieGruntWaitMin");
			_zombieGruntWaitMaxField = AccessTools.Field(_peakType, "zombieGruntWaitMax");
			_mushroomGrowTimeMinField = AccessTools.Field(_peakType, "mushroomGrowTimeMin");
			_mushroomGrowTimeMaxField = AccessTools.Field(_peakType, "mushroomGrowTimeMax");
			_attackHeightDeltaField = AccessTools.Field(_peakType, "attackHeightDelta");
		}

		private static object GetPeakInstance()
		{
			try
			{
				return (_instanceField != null) ? _instanceField.GetValue(null) : null;
			}
			catch
			{
				return null;
			}
		}

		private static void SetFloatEntry(FieldInfo field, object instance, float value)
		{
			if (field == null || instance == null)
			{
				return;
			}
			try
			{
				if (field.GetValue(instance) is ConfigEntry<float> val)
				{
					val.Value = value;
				}
			}
			catch (Exception ex)
			{
				Log.LogError((object)("SetFloatEntry failed: " + ex));
			}
		}

		private static void ApplyToPeakConfig(object instance, ZombieStatSet stats)
		{
			SetFloatEntry(_reachForceField, instance, stats.ReachForce);
			SetFloatEntry(_distanceBeforeWakeupField, instance, stats.DistanceBeforeWakeup);
			SetFloatEntry(_lookAngleBeforeWakeupField, instance, stats.LookAngleBeforeWakeup);
			SetFloatEntry(_initialWakeUpTimeField, instance, stats.InitialWakeUpTime);
			SetFloatEntry(_distanceBeforeChaseField, instance, stats.DistanceBeforeChase);
			SetFloatEntry(_zombieSprintDistanceField, instance, stats.ZombieSprintDistance);
			SetFloatEntry(_chaseTimeBeforeSprintField, instance, stats.ChaseTimeBeforeSprint);
			SetFloatEntry(_zombieLungeDistanceField, instance, stats.ZombieLungeDistance);
			SetFloatEntry(_lungeTimeField, instance, stats.LungeTime);
			SetFloatEntry(_lungeRecoveryTimeField, instance, stats.LungeRecoveryTime);
			SetFloatEntry(_biteStunTimeField, instance, stats.BiteStunTime);
			SetFloatEntry(_biteInitialInjuryField, instance, stats.BiteInitialInjury);
			SetFloatEntry(_biteInitialSporesField, instance, stats.BiteInitialSpores);
			SetFloatEntry(_biteDelayBeforeSporesField, instance, stats.BiteDelayBeforeSpores);
			SetFloatEntry(_biteSporesPerSecondField, instance, stats.BiteSporesPerSecond);
			SetFloatEntry(_totalBiteSporesTimeField, instance, stats.TotalBiteSporesTime);
			SetFloatEntry(_distanceToEnableField, instance, stats.DistanceToEnable);
			SetFloatEntry(_zombieGruntWaitMinField, instance, stats.ZombieGruntWaitMin);
			SetFloatEntry(_zombieGruntWaitMaxField, instance, stats.ZombieGruntWaitMax);
			SetFloatEntry(_mushroomGrowTimeMinField, instance, stats.MushroomGrowTimeMin);
			SetFloatEntry(_mushroomGrowTimeMaxField, instance, stats.MushroomGrowTimeMax);
			SetFloatEntry(_attackHeightDeltaField, instance, stats.AttackHeightDelta);
		}

		private static void ApplyToLiveZombie(MushroomZombie zombie, ZombieStatSet stats)
		{
			if (!((Object)(object)zombie == (Object)null))
			{
				zombie.reachForce = stats.ReachForce;
				zombie.distanceBeforeWakeup = stats.DistanceBeforeWakeup;
				zombie.lookAngleBeforeWakeup = stats.LookAngleBeforeWakeup;
				zombie.initialWakeUpTime = stats.InitialWakeUpTime;
				zombie.distanceBeforeChase = stats.DistanceBeforeChase;
				zombie.zombieSprintDistance = stats.ZombieSprintDistance;
				zombie.chaseTimeBeforeSprint = stats.ChaseTimeBeforeSprint;
				zombie.zombieLungeDistance = stats.ZombieLungeDistance;
				zombie.lungeTime = stats.LungeTime;
				zombie.lungeRecoveryTime = stats.LungeRecoveryTime;
				zombie.biteStunTime = stats.BiteStunTime;
				zombie.biteInitialInjury = stats.BiteInitialInjury;
				zombie.biteInitialSpores = stats.BiteInitialSpores;
				zombie.biteDelayBeforeSpores = stats.BiteDelayBeforeSpores;
				zombie.biteSporesPerSecond = stats.BiteSporesPerSecond;
				zombie.totalBiteSporesTime = stats.TotalBiteSporesTime;
				if (stats.DistanceToEnable >= 0f)
				{
					zombie.distanceToEnable = stats.DistanceToEnable;
				}
			}
		}

		private static void ApplyAll(bool forceLog)
		{
			try
			{
				object peakInstance = GetPeakInstance();
				if (peakInstance != null)
				{
					ApplyToPeakConfig(peakInstance, _activeStats);
				}
				MushroomZombie[] array = Object.FindObjectsByType<MushroomZombie>((FindObjectsInactive)1, (FindObjectsSortMode)0);
				MushroomZombie[] array2 = array;
				foreach (MushroomZombie zombie in array2)
				{
					ApplyToLiveZombie(zombie, _activeStats);
				}
				if (forceLog)
				{
					string text = ((!PhotonNetwork.InRoom) ? "Local(host defaults)" : (PhotonNetwork.IsMasterClient ? "Host(local+room)" : "RoomProperties"));
					Log.LogInfo((object)("Applied zombie stats. Source = " + text));
				}
			}
			catch (Exception ex)
			{
				Log.LogError((object)("ApplyAll failed: " + ex));
			}
		}

		private void PublishHostStatsToRoom(bool force)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Expected O, but got Unknown
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Expected O, but got Unknown
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Expected O, but got Unknown
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Expected O, but got Unknown
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Expected O, but got Unknown
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Expected O, but got Unknown
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Expected O, but got Unknown
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Expected O, but got Unknown
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Expected O, but got Unknown
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: Expected O, but got Unknown
			//IL_012f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0149: Expected O, but got Unknown
			//IL_014a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0164: Expected O, but got Unknown
			//IL_0165: Unknown result type (might be due to invalid IL or missing references)
			//IL_017f: Expected O, but got Unknown
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			//IL_019a: Expected O, but got Unknown
			//IL_019b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b5: Expected O, but got Unknown
			//IL_01b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d0: Expected O, but got Unknown
			//IL_01d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01eb: Expected O, but got Unknown
			//IL_01ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_0206: Expected O, but got Unknown
			//IL_0207: Unknown result type (might be due to invalid IL or missing references)
			//IL_0221: Expected O, but got Unknown
			//IL_0222: Unknown result type (might be due to invalid IL or missing references)
			//IL_023c: Expected O, but got Unknown
			//IL_023d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0257: Expected O, but got Unknown
			//IL_0258: Unknown result type (might be due to invalid IL or missing references)
			//IL_0272: Expected O, but got Unknown
			//IL_0273: Unknown result type (might be due to invalid IL or missing references)
			//IL_028d: Expected O, but got Unknown
			//IL_028f: Expected O, but got Unknown
			if (!PhotonNetwork.InRoom || !PhotonNetwork.IsMasterClient || PhotonNetwork.CurrentRoom == null)
			{
				return;
			}
			try
			{
				Hashtable val = new Hashtable();
				((Dictionary<object, object>)val).Add((object)"szw_stats_version", (object)1);
				((Dictionary<object, object>)val).Add((object)"szw_reachForce", (object)_hostStats.ReachForce);
				((Dictionary<object, object>)val).Add((object)"szw_distWake", (object)_hostStats.DistanceBeforeWakeup);
				((Dictionary<object, object>)val).Add((object)"szw_lookWake", (object)_hostStats.LookAngleBeforeWakeup);
				((Dictionary<object, object>)val).Add((object)"szw_initWake", (object)_hostStats.InitialWakeUpTime);
				((Dictionary<object, object>)val).Add((object)"szw_distChase", (object)_hostStats.DistanceBeforeChase);
				((Dictionary<object, object>)val).Add((object)"szw_sprintDist", (object)_hostStats.ZombieSprintDistance);
				((Dictionary<object, object>)val).Add((object)"szw_chaseSprint", (object)_hostStats.ChaseTimeBeforeSprint);
				((Dictionary<object, object>)val).Add((object)"szw_lungeDist", (object)_hostStats.ZombieLungeDistance);
				((Dictionary<object, object>)val).Add((object)"szw_lungeTime", (object)_hostStats.LungeTime);
				((Dictionary<object, object>)val).Add((object)"szw_lungeRecover", (object)_hostStats.LungeRecoveryTime);
				((Dictionary<object, object>)val).Add((object)"szw_biteStun", (object)_hostStats.BiteStunTime);
				((Dictionary<object, object>)val).Add((object)"szw_biteInjury", (object)_hostStats.BiteInitialInjury);
				((Dictionary<object, object>)val).Add((object)"szw_biteSpores0", (object)_hostStats.BiteInitialSpores);
				((Dictionary<object, object>)val).Add((object)"szw_biteDelay", (object)_hostStats.BiteDelayBeforeSpores);
				((Dictionary<object, object>)val).Add((object)"szw_bitePerSec", (object)_hostStats.BiteSporesPerSecond);
				((Dictionary<object, object>)val).Add((object)"szw_biteTotal", (object)_hostStats.TotalBiteSporesTime);
				((Dictionary<object, object>)val).Add((object)"szw_distEnable", (object)_hostStats.DistanceToEnable);
				((Dictionary<object, object>)val).Add((object)"szw_gruntMin", (object)_hostStats.ZombieGruntWaitMin);
				((Dictionary<object, object>)val).Add((object)"szw_gruntMax", (object)_hostStats.ZombieGruntWaitMax);
				((Dictionary<object, object>)val).Add((object)"szw_growMin", (object)_hostStats.MushroomGrowTimeMin);
				((Dictionary<object, object>)val).Add((object)"szw_growMax", (object)_hostStats.MushroomGrowTimeMax);
				((Dictionary<object, object>)val).Add((object)"szw_attackHeight", (object)_hostStats.AttackHeightDelta);
				Hashtable val2 = val;
				PhotonNetwork.CurrentRoom.SetCustomProperties(val2, (Hashtable)null, (WebFlags)null);
				if (force)
				{
					Log.LogInfo((object)"Published host zombie stats to room properties.");
				}
			}
			catch (Exception ex)
			{
				Log.LogError((object)("PublishHostStatsToRoom failed: " + ex));
			}
		}

		private void TryPullStatsFromRoom()
		{
			if (!PhotonNetwork.InRoom || PhotonNetwork.CurrentRoom == null)
			{
				return;
			}
			Hashtable customProperties = ((RoomInfo)PhotonNetwork.CurrentRoom).CustomProperties;
			if (customProperties == null || !((Dictionary<object, object>)(object)customProperties).ContainsKey((object)"szw_stats_version"))
			{
				return;
			}
			try
			{
				ZombieStatSet activeStats = default(ZombieStatSet);
				activeStats.ReachForce = ReadFloat(customProperties, "szw_reachForce", _hostStats.ReachForce);
				activeStats.DistanceBeforeWakeup = ReadFloat(customProperties, "szw_distWake", _hostStats.DistanceBeforeWakeup);
				activeStats.LookAngleBeforeWakeup = ReadFloat(customProperties, "szw_lookWake", _hostStats.LookAngleBeforeWakeup);
				activeStats.InitialWakeUpTime = ReadFloat(customProperties, "szw_initWake", _hostStats.InitialWakeUpTime);
				activeStats.DistanceBeforeChase = ReadFloat(customProperties, "szw_distChase", _hostStats.DistanceBeforeChase);
				activeStats.ZombieSprintDistance = ReadFloat(customProperties, "szw_sprintDist", _hostStats.ZombieSprintDistance);
				activeStats.ChaseTimeBeforeSprint = ReadFloat(customProperties, "szw_chaseSprint", _hostStats.ChaseTimeBeforeSprint);
				activeStats.ZombieLungeDistance = ReadFloat(customProperties, "szw_lungeDist", _hostStats.ZombieLungeDistance);
				activeStats.LungeTime = ReadFloat(customProperties, "szw_lungeTime", _hostStats.LungeTime);
				activeStats.LungeRecoveryTime = ReadFloat(customProperties, "szw_lungeRecover", _hostStats.LungeRecoveryTime);
				activeStats.BiteStunTime = ReadFloat(customProperties, "szw_biteStun", _hostStats.BiteStunTime);
				activeStats.BiteInitialInjury = ReadFloat(customProperties, "szw_biteInjury", _hostStats.BiteInitialInjury);
				activeStats.BiteInitialSpores = ReadFloat(customProperties, "szw_biteSpores0", _hostStats.BiteInitialSpores);
				activeStats.BiteDelayBeforeSpores = ReadFloat(customProperties, "szw_biteDelay", _hostStats.BiteDelayBeforeSpores);
				activeStats.BiteSporesPerSecond = ReadFloat(customProperties, "szw_bitePerSec", _hostStats.BiteSporesPerSecond);
				activeStats.TotalBiteSporesTime = ReadFloat(customProperties, "szw_biteTotal", _hostStats.TotalBiteSporesTime);
				activeStats.DistanceToEnable = ReadFloat(customProperties, "szw_distEnable", _hostStats.DistanceToEnable);
				activeStats.ZombieGruntWaitMin = ReadFloat(customProperties, "szw_gruntMin", _hostStats.ZombieGruntWaitMin);
				activeStats.ZombieGruntWaitMax = ReadFloat(customProperties, "szw_gruntMax", _hostStats.ZombieGruntWaitMax);
				activeStats.MushroomGrowTimeMin = ReadFloat(customProperties, "szw_growMin", _hostStats.MushroomGrowTimeMin);
				activeStats.MushroomGrowTimeMax = ReadFloat(customProperties, "szw_growMax", _hostStats.MushroomGrowTimeMax);
				activeStats.AttackHeightDelta = ReadFloat(customProperties, "szw_attackHeight", _hostStats.AttackHeightDelta);
				_activeStats = activeStats;
			}
			catch (Exception ex)
			{
				Log.LogError((object)("TryPullStatsFromRoom failed: " + ex));
			}
		}

		private static float ReadFloat(Hashtable props, string key, float fallback)
		{
			if (props == null || !((Dictionary<object, object>)(object)props).ContainsKey((object)key))
			{
				return fallback;
			}
			object obj = props[(object)key];
			if (obj is float result)
			{
				return result;
			}
			if (obj is double num)
			{
				return (float)num;
			}
			if (obj is int num2)
			{
				return num2;
			}
			try
			{
				return Convert.ToSingle(obj);
			}
			catch
			{
				return fallback;
			}
		}

		public void OnRoomPropertiesUpdate(Hashtable propertiesThatChanged)
		{
			if (!PhotonNetwork.IsMasterClient && propertiesThatChanged != null && ((Dictionary<object, object>)(object)propertiesThatChanged).ContainsKey((object)"szw_stats_version"))
			{
				TryPullStatsFromRoom();
				ApplyAll(forceLog: true);
			}
		}

		public void OnPlayerEnteredRoom(Player newPlayer)
		{
			if (PhotonNetwork.IsMasterClient)
			{
				PublishHostStatsToRoom(force: true);
			}
		}

		public void OnPlayerLeftRoom(Player otherPlayer)
		{
		}

		public void OnPlayerPropertiesUpdate(Player targetPlayer, Hashtable changedProps)
		{
		}

		public void OnMasterClientSwitched(Player newMasterClient)
		{
			if (PhotonNetwork.LocalPlayer != null && newMasterClient != null && PhotonNetwork.LocalPlayer.ActorNumber == newMasterClient.ActorNumber)
			{
				_hostStats = CreateStatsFromConfig();
				_activeStats = _hostStats;
				PublishHostStatsToRoom(force: true);
				ApplyAll(forceLog: true);
			}
		}
	}
	internal struct ZombieStatSet
	{
		public float ReachForce;

		public float DistanceBeforeWakeup;

		public float LookAngleBeforeWakeup;

		public float InitialWakeUpTime;

		public float DistanceBeforeChase;

		public float ZombieSprintDistance;

		public float ChaseTimeBeforeSprint;

		public float ZombieLungeDistance;

		public float LungeTime;

		public float LungeRecoveryTime;

		public float BiteStunTime;

		public float BiteInitialInjury;

		public float BiteInitialSpores;

		public float BiteDelayBeforeSpores;

		public float BiteSporesPerSecond;

		public float TotalBiteSporesTime;

		public float DistanceToEnable;

		public float ZombieGruntWaitMin;

		public float ZombieGruntWaitMax;

		public float MushroomGrowTimeMin;

		public float MushroomGrowTimeMax;

		public float AttackHeightDelta;

		public static ZombieStatSet CreateHostDefaults()
		{
			ZombieStatSet result = default(ZombieStatSet);
			result.ReachForce = -1f;
			result.DistanceBeforeWakeup = 50f;
			result.LookAngleBeforeWakeup = 360f;
			result.InitialWakeUpTime = 0f;
			result.DistanceBeforeChase = 0f;
			result.ZombieSprintDistance = 300000f;
			result.ChaseTimeBeforeSprint = 0f;
			result.ZombieLungeDistance = 3f;
			result.LungeTime = 1.5f;
			result.LungeRecoveryTime = 1f;
			result.BiteStunTime = 2f;
			result.BiteInitialInjury = 0.1f;
			result.BiteInitialSpores = 0.1f;
			result.BiteDelayBeforeSpores = -1f;
			result.BiteSporesPerSecond = -1f;
			result.TotalBiteSporesTime = -1f;
			result.DistanceToEnable = -1f;
			result.ZombieGruntWaitMin = 10f;
			result.ZombieGruntWaitMax = 20f;
			result.MushroomGrowTimeMin = -1f;
			result.MushroomGrowTimeMax = -1f;
			result.AttackHeightDelta = 5f;
			return result;
		}
	}
}
namespace Reload
{
	[BepInPlugin("Reload", "장전", "4.0.0")]
	public class Plugin : BaseUnityPlugin, IOnEventCallback
	{
		[CompilerGenerated]
		private sealed class <>c__DisplayClass40_0
		{
			public bool success;

			internal void <UseThenRefillRoutine>b__0(bool result)
			{
				success = result;
			}
		}

		[CompilerGenerated]
		private sealed class <LoadReloadSoundCoroutine>d__35 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			public Plugin <>4__this;

			private string <fileName>5__1;

			private string <pluginDir>5__2;

			private string <candidate>5__3;

			private string <url>5__4;

			private UnityWebRequest <req>5__5;

			private DownloadHandlerAudioClip <dl>5__6;

			private AudioClip <clip>5__7;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <LoadReloadSoundCoroutine>d__35(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				int num = <>1__state;
				if (num == -3 || num == 1)
				{
					try
					{
					}
					finally
					{
						<>m__Finally1();
					}
				}
				<fileName>5__1 = null;
				<pluginDir>5__2 = null;
				<candidate>5__3 = null;
				<url>5__4 = null;
				<req>5__5 = null;
				<dl>5__6 = null;
				<clip>5__7 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_0158: Unknown result type (might be due to invalid IL or missing references)
				//IL_015e: Invalid comparison between Unknown and I4
				bool result;
				try
				{
					switch (<>1__state)
					{
					default:
						result = false;
						break;
					case 0:
					{
						<>1__state = -1;
						<>4__this._reloadSoundLoadTried = true;
						<fileName>5__1 = <>4__this.GetReloadSoundFileName();
						<pluginDir>5__2 = Path.GetDirectoryName(((BaseUnityPlugin)<>4__this).Info.Location);
						<candidate>5__3 = Path.Combine(<pluginDir>5__2 ?? "", <fileName>5__1);
						<>4__this._resolvedReloadSoundPath = <candidate>5__3;
						if (!File.Exists(<candidate>5__3))
						{
							<>4__this.WRN("재장전 사운드 파일을 찾지 못함: " + <candidate>5__3);
							result = false;
							break;
						}
						<url>5__4 = new Uri(<candidate>5__3).AbsoluteUri;
						<req>5__5 = UnityWebRequestMultimedia.GetAudioClip(<url>5__4, (AudioType)14);
						<>1__state = -3;
						ref DownloadHandlerAudioClip reference = ref <dl>5__6;
						DownloadHandler downloadHandler = <req>5__5.downloadHandler;
						reference = (DownloadHandlerAudioClip)(object)((downloadHandler is DownloadHandlerAudioClip) ? downloadHandler : null);
						if (<dl>5__6 != null)
						{
							<dl>5__6.streamAudio = false;
						}
						<>2__current = <req>5__5.SendWebRequest();
						<>1__state = 1;
						result = true;
						break;
					}
					case 1:
						<>1__state = -3;
						if ((int)<req>5__5.result != 1)
						{
							<>4__this.ERR("장전 사운드 로드 실패: " + <req>5__5.error);
							result = false;
						}
						else
						{
							<clip>5__7 = DownloadHandlerAudioClip.GetContent(<req>5__5);
							if (!((Object)(object)<clip>5__7 == (Object)null))
							{
								((Object)<clip>5__7).name = "CustomReloadSound";
								<>4__this._reloadSoundClip = <clip>5__7;
								<>4__this.DBG("장전 사운드 로드 성공: " + <candidate>5__3 + " / length=" + <clip>5__7.length);
								<dl>5__6 = null;
								<clip>5__7 = null;
								<>m__Finally1();
								<req>5__5 = null;
								result = false;
								break;
							}
							<>4__this.ERR("장전 사운드 AudioClip 생성 실패");
							result = false;
						}
						<>m__Finally1();
						break;
					}
				}
				catch
				{
					//try-fault
					((IDisposable)this).Dispose();
					throw;
				}
				return result;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			private void <>m__Finally1()
			{
				<>1__state = -1;
				if (<req>5__5 != null)
				{
					((IDisposable)<req>5__5).Dispose();
				}
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		[CompilerGenerated]
		private sealed class <RefillCurrentHeldAKRoutine>d__47 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			public Action<bool> done;

			public Plugin <>4__this;

			private Component <heldAK>5__1;

			private int <totalUses>5__2;

			private bool <hasData>5__3;

			private int <usesValue>5__4;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <RefillCurrentHeldAKRoutine>d__47(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<heldAK>5__1 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>4__this.DBG("RefillCurrentHeldAKRoutine 진입");
					if (!<>4__this.TryGetHeldAK(out <heldAK>5__1) || (Object)(object)<heldAK>5__1 == (Object)null)
					{
						<>4__this.ERR("현재 장착된 AK를 찾지 못함");
						done(obj: false);
						return false;
					}
					<totalUses>5__2 = <>4__this.ReadIntMember(<heldAK>5__1, "totalUses");
					if (<totalUses>5__2 <= 0)
					{
						<>4__this.ERR("AK totalUses 값을 읽지 못했거나 0 이하임");
						done(obj: false);
						return false;
					}
					if (!<>4__this.TrySetItemUsesToMax(<heldAK>5__1, <totalUses>5__2))
					{
						<>4__this.ERR("현재 들고 있는 AK의 ItemUses 최대치 복원 실패");
						done(obj: false);
						return false;
					}
					<>4__this.TryRefreshUseBar(<heldAK>5__1, <totalUses>5__2);
					<>4__this.TrySyncItemInstanceData(<heldAK>5__1);
					<>2__current = null;
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					if ((<>4__this.TryReadItemUses(<heldAK>5__1, out <hasData>5__3, out <usesValue>5__4) & <hasData>5__3) && <usesValue>5__4 == <totalUses>5__2)
					{
						<>4__this.DBG("현재 들고 있는 AK 재장전 성공: " + <usesValue>5__4 + "/" + <totalUses>5__2);
						done(obj: true);
						return false;
					}
					<>4__this.ERR("재장전 후 검증 실패");
					done(obj: false);
					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 <TryMoveUseProgressUIRoutine>d__36 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			public Plugin <>4__this;

			private float <timeout>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 <TryMoveUseProgressUIRoutine>d__36(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<timeout>5__1 = 10f;
					<elapsed>5__2 = 0f;
					break;
				case 1:
					<>1__state = -1;
					break;
				}
				if (<elapsed>5__2 < <timeout>5__1)
				{
					if (<>4__this.TryMoveUseProgressUI())
					{
						return false;
					}
					<elapsed>5__2 += Time.unscaledDeltaTime;
					<>2__current = null;
					<>1__state = 1;
					return true;
				}
				<>4__this.WRN("UI_UseItemProgress를 끝내 찾지 못함");
				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 <UseThenRefillRoutine>d__40 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			public Plugin <>4__this;

			private Component <heldAK>5__1;

			private bool <prevShowUseProgress>5__2;

			private bool <prevOverrideForceProgress>5__3;

			private float <prevOverrideProgress>5__4;

			private float <reloadTime>5__5;

			private <>c__DisplayClass40_0 <>8__6;

			private float <elapsed>5__7;

			private Component <currentHeld>5__8;

			private float <progress>5__9;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <UseThenRefillRoutine>d__40(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				int num = <>1__state;
				if (num == -3 || (uint)(num - 1) <= 3u)
				{
					try
					{
					}
					finally
					{
						<>m__Finally1();
					}
				}
				<heldAK>5__1 = null;
				<>8__6 = null;
				<currentHeld>5__8 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_0326: Unknown result type (might be due to invalid IL or missing references)
				//IL_0330: Expected O, but got Unknown
				//IL_0160: Unknown result type (might be due to invalid IL or missing references)
				bool result2;
				try
				{
					switch (<>1__state)
					{
					default:
						result2 = false;
						goto end_IL_0000;
					case 0:
						<>1__state = -1;
						<>4__this._isUsing = true;
						<>4__this.DBG("UseThenRefillRoutine 시작");
						<heldAK>5__1 = null;
						<prevShowUseProgress>5__2 = true;
						<prevOverrideForceProgress>5__3 = false;
						<prevOverrideProgress>5__4 = 0f;
						<reloadTime>5__5 = <>4__this.GetReloadUseTime();
						<>1__state = -3;
						<>8__6 = new <>c__DisplayClass40_0();
						if (!<>4__this.TryGetHeldAK(out <heldAK>5__1) || (Object)(object)<heldAK>5__1 == (Object)null)
						{
							<>4__this.ERR("재장전 시작 시 현재 AK를 찾지 못함");
							result2 = false;
							break;
						}
						<prevShowUseProgress>5__2 = <>4__this.ReadBoolMember(<heldAK>5__1, "showUseProgress");
						<prevOverrideForceProgress>5__3 = <>4__this.ReadBoolMember(<heldAK>5__1, "overrideForceProgress");
						<prevOverrideProgress>5__4 = <>4__this.ReadFloatMember(<heldAK>5__1, "overrideProgress");
						<>4__this.StartNativeUseProgress(<heldAK>5__1);
						<>4__this.BroadcastReloadSound(<heldAK>5__1.transform.position);
						if (<reloadTime>5__5 > 0f)
						{
							<elapsed>5__7 = 0f;
							goto IL_024c;
						}
						goto IL_0264;
					case 1:
						<>1__state = -3;
						<currentHeld>5__8 = null;
						goto IL_024c;
					case 2:
						<>1__state = -3;
						<>8__6.success = false;
						<>2__current = ((MonoBehaviour)<>4__this).StartCoroutine(<>4__this.RefillCurrentHeldAKRoutine(delegate(bool result)
						{
							<>8__6.success = result;
						}));
						<>1__state = 3;
						result2 = true;
						goto end_IL_0000;
					case 3:
						<>1__state = -3;
						if (<>8__6.success)
						{
							<>4__this.DBG("장전 성공");
						}
						else
						{
							<>4__this.ERR("장전 실패");
						}
						<>2__current = (object)new WaitForSecondsRealtime(0.05f);
						<>1__state = 4;
						result2 = true;
						goto end_IL_0000;
					case 4:
						{
							<>1__state = -3;
							<>8__6 = null;
							<>m__Finally1();
							result2 = false;
							goto end_IL_0000;
						}
						IL_0264:
						<>4__this.UpdateNativeUseProgress(<heldAK>5__1, 1f);
						<>2__current = null;
						<>1__state = 2;
						result2 = true;
						goto end_IL_0000;
						IL_024c:
						if (!(<elapsed>5__7 < <reloadTime>5__5))
						{
							goto IL_0264;
						}
						if (!<>4__this.TryGetHeldAK(out <currentHeld>5__8) || (Object)(object)<currentHeld>5__8 == (Object)null || (Object)(object)<currentHeld>5__8 != (Object)(object)<heldAK>5__1)
						{
							<>4__this.WRN("재장전 중 손에 든 AK가 바뀌어서 취소");
							result2 = false;
							break;
						}
						<elapsed>5__7 += Time.unscaledDeltaTime;
						<progress>5__9 = Mathf.Clamp01(<elapsed>5__7 / <reloadTime>5__5);
						<>4__this.UpdateNativeUseProgress(<heldAK>5__1, <progress>5__9);
						<>2__current = null;
						<>1__state = 1;
						result2 = true;
						goto end_IL_0000;
					}
					<>m__Finally1();
					end_IL_0000:;
				}
				catch
				{
					//try-fault
					((IDisposable)this).Dispose();
					throw;
				}
				return result2;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			private void <>m__Finally1()
			{
				<>1__state = -1;
				if ((Object)(object)<heldAK>5__1 != (Object)null)
				{
					<>4__this.RestoreNativeUseProgress(<heldAK>5__1, <prevShowUseProgress>5__2, <prevOverrideForceProgress>5__3, <prevOverrideProgress>5__4);
				}
				<>4__this._isUsing = false;
				<>4__this.DBG("UseThenRefillRoutine 종료");
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		internal static Plugin Instance;

		private const int AK_ITEM_ID = 9351;

		private const byte RELOAD_SFX_EVENT_CODE = 143;

		private Harmony _harmony;

		private bool _runActionPatched;

		private float _lastBlockLogTime;

		private bool _useProgressUiMoved;

		private bool _isUsing;

		private Type _cachedCharacterType;

		private Type _cachedDataEntryKeyType;

		private Type _cachedOptionableIntItemDataType;

		private ConfigEntry<float> _reloadUseTime;

		private ConfigEntry<KeyCode> _reloadKey;

		private ConfigEntry<string> _reloadSoundFileName;

		private ConfigEntry<float> _reloadSoundVolume;

		private ConfigEntry<float> _reloadSoundStartOffset;

		private ConfigEntry<float> _reloadSoundMinDistance;

		private ConfigEntry<float> _reloadSoundMaxDistance;

		private ConfigEntry<bool> _verboseLogging;

		private AudioClip _reloadSoundClip;

		private string _resolvedReloadSoundPath;

		private bool _reloadSoundLoadTried;

		private void Awake()
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Expected O, but got Unknown
			Instance = this;
			((BaseUnityPlugin)this).Config.SaveOnConfigSet = true;
			BindConfigEntries();
			DBG("Plugin Awake()");
			_harmony = new Harmony("reload.akhotkey.spawninhand");
			TryPatchRunAction();
			SceneManager.sceneLoaded += OnSceneLoaded;
			PhotonNetwork.AddCallbackTarget((object)this);
			_useProgressUiMoved = false;
			((MonoBehaviour)this).StartCoroutine(TryMoveUseProgressUIRoutine());
			((MonoBehaviour)this).StartCoroutine(LoadReloadSoundCoroutine());
		}

		private void OnDestroy()
		{
			SceneManager.sceneLoaded -= OnSceneLoaded;
			PhotonNetwork.RemoveCallbackTarget((object)this);
		}

		public void OnEvent(EventData photonEvent)
		{
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (photonEvent != null && photonEvent.Code == 143 && photonEvent.CustomData is object[] array && array.Length >= 3)
				{
					float num = Convert.ToSingle(array[0]);
					float num2 = Convert.ToSingle(array[1]);
					float num3 = Convert.ToSingle(array[2]);
					PlayReloadSoundLocal(new Vector3(num, num2, num3));
				}
			}
			catch (Exception ex)
			{
				ERR("OnEvent 예외: " + ex);
			}
		}

		private void BindConfigEntries()
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Expected O, but got Unknown
			_reloadUseTime = ((BaseUnityPlugin)this).Config.Bind<float>("장전", "장전 시간", 3f, new ConfigDescription("AK 재장전 시간(초). 0이면 즉시 재장전.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 60f), Array.Empty<object>()));
			_reloadKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("장전", "장전 키", (KeyCode)114, "재장전 키");
			_reloadSoundFileName = ((BaseUnityPlugin)this).Config.Bind<string>("장전소리", "장전 사운드 파일", "장전소리.ogg", "재장전 사운드 파일명. DLL과 같은 폴더에 둔다.");
		}

		private float GetReloadUseTime()
		{
			if (_reloadUseTime == null)
			{
				return 3f;
			}
			if (_reloadUseTime.Value < 0f)
			{
				return 0f;
			}
			return _reloadUseTime.Value;
		}

		private KeyCode GetReloadKey()
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: 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_0021: Unknown result type (might be due to invalid IL or missing references)
			if (_reloadKey == null)
			{
				return (KeyCode)114;
			}
			return _reloadKey.Value;
		}

		private string GetReloadSoundFileName()
		{
			if (_reloadSoundFileName == null || string.IsNullOrWhiteSpace(_reloadSoundFileName.Value))
			{
				return "장전소리.ogg";
			}
			return _reloadSoundFileName.Value.Trim();
		}

		private float GetReloadSoundVolume()
		{
			if (_reloadSoundVolume == null)
			{
				return 1f;
			}
			return Mathf.Clamp(_reloadSoundVolume.Value, 0f, 30f);
		}

		private float GetReloadSoundStartOffset()
		{
			if (_reloadSoundStartOffset == null)
			{
				return 0f;
			}
			return Mathf.Max(0f, _reloadSoundStartOffset.Value);
		}

		private float GetReloadSoundMinDistance()
		{
			if (_reloadSoundMinDistance == null)
			{
				return 3f;
			}
			return Mathf.Max(0f, _reloadSoundMinDistance.Value);
		}

		private float GetReloadSoundMaxDistance()
		{
			if (_reloadSoundMaxDistance == null)
			{
				return 25f;
			}
			return Mathf.Max(1f, _reloadSoundMaxDistance.Value);
		}

		private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
		{
			DBG("Scene loaded: " + ((Scene)(ref scene)).name);
			_useProgressUiMoved = false;
			((MonoBehaviour)this).StartCoroutine(TryMoveUseProgressUIRoutine());
			if ((Object)(object)_reloadSoundClip == (Object)null && !_reloadSoundLoadTried)
			{
				((MonoBehaviour)this).StartCoroutine(LoadReloadSoundCoroutine());
			}
		}

		private void Update()
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			if (!_runActionPatched)
			{
				TryPatchRunAction();
			}
			if (Input.GetKeyDown(GetReloadKey()) && !_isUsing)
			{
				if (!TryGetHeldAK(out var _))
				{
					WRN("현재 손에 든 AK가 없어서 재장전을 시작하지 않음");
					return;
				}
				KeyCode reloadKey = GetReloadKey();
				DBG("HOTKEY 입력 감지: " + ((object)(KeyCode)(ref reloadKey)).ToString() + " / ReloadTime = " + GetReloadUseTime());
				((MonoBehaviour)this).StartCoroutine(UseThenRefillRoutine());
			}
		}

		[IteratorStateMachine(typeof(<LoadReloadSoundCoroutine>d__35))]
		private IEnumerator LoadReloadSoundCoroutine()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <LoadReloadSoundCoroutine>d__35(0)
			{
				<>4__this = this
			};
		}

		[IteratorStateMachine(typeof(<TryMoveUseProgressUIRoutine>d__36))]
		private IEnumerator TryMoveUseProgressUIRoutine()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <TryMoveUseProgressUIRoutine>d__36(0)
			{
				<>4__this = this
			};
		}

		private bool TryMoveUseProgressUI()
		{
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: 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_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			if (_useProgressUiMoved)
			{
				return true;
			}
			Type type = FindTypeByName("UI_UseItemProgress");
			if (type == null)
			{
				return false;
			}
			Object[] array = Resources.FindObjectsOfTypeAll(type);
			if (array == null || array.Length == 0)
			{
				return false;
			}
			Object[] array2 = array;
			foreach (Object val in array2)
			{
				Component val2 = (Component)(object)((val is Component) ? val : null);
				if ((Object)(object)val2 == (Object)null || (Object)(object)val2.gameObject == (Object)null)
				{
					continue;
				}
				Scene scene = val2.gameObject.scene;
				if (((Scene)(ref scene)).IsValid())
				{
					RectTransform component = val2.GetComponent<RectTransform>();
					if (!((Object)(object)component == (Object)null))
					{
						component.anchoredPosition += new Vector2(180f, 0f);
						_useProgressUiMoved = true;
						Vector2 anchoredPosition = component.anchoredPosition;
						DBG("UI_UseItemProgress 위치 이동 완료: " + ((object)(Vector2)(ref anchoredPosition)).ToString());
						return true;
					}
				}
			}
			return false;
		}

		private void TryPatchRunAction()
		{
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Expected O, but got Unknown
			if (_runActionPatched)
			{
				return;
			}
			try
			{
				Type type = FindTypeByFullName("AK_Gun.Action_Gun");
				if (type == null)
				{
					WRN("AK_Gun.Action_Gun 타입을 아직 찾지 못함");
					return;
				}
				MethodInfo method = type.GetMethod("RunAction", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (method == null)
				{
					ERR("AK_Gun.Action_Gun.RunAction 메서드를 찾지 못함");
					return;
				}
				MethodInfo method2 = typeof(Plugin).GetMethod("Prefix_BlockRunActionWhileReloading", BindingFlags.Static | BindingFlags.NonPublic);
				if (method2 == null)
				{
					ERR("Prefix_BlockRunActionWhileReloading 메서드를 찾지 못함");
					return;
				}
				_harmony.Patch((MethodBase)method, new HarmonyMethod(method2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				_runActionPatched = true;
				DBG("Harmony Patch 성공: AK_Gun.Action_Gun.RunAction");
			}
			catch (Exception ex)
			{
				ERR("TryPatchRunAction 예외: " + ex);
			}
		}

		private static bool Prefix_BlockRunActionWhileReloading()
		{
			try
			{
				if ((Object)(object)Instance == (Object)null)
				{
					return true;
				}
				if (!Instance._isUsing)
				{
					return true;
				}
				if (Time.unscaledTime - Instance._lastBlockLogTime >= 0.25f)
				{
					Instance._lastBlockLogTime = Time.unscaledTime;
					((BaseUnityPlugin)Instance).Logger.LogInfo((object)"[AKReloadDBG] 재장전 중 발사 차단: RunAction 스킵");
				}
				return false;
			}
			catch
			{
				return true;
			}
		}

		[IteratorStateMachine(typeof(<UseThenRefillRoutine>d__40))]
		private IEnumerator UseThenRefillRoutine()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <UseThenRefillRoutine>d__40(0)
			{
				<>4__this = this
			};
		}

		private void StartNativeUseProgress(Component itemComponent)
		{
			try
			{
				WriteMemberValue(itemComponent, "showUseProgress", true);
				WriteMemberValue(itemComponent, "overrideForceProgress", true);
				WriteMemberValue(itemComponent, "overrideProgress", 0f);
				DBG("UI-only reload progress 시작");
			}
			catch (Exception ex)
			{
				WRN("StartNativeUseProgress 예외: " + ex.Message);
			}
		}

		private void UpdateNativeUseProgress(Component itemComponent, float progress)
		{
			try
			{
				float num = Mathf.Clamp01(progress);
				WriteMemberValue(itemComponent, "showUseProgress", true);
				WriteMemberValue(itemComponent, "overrideForceProgress", true);
				WriteMemberValue(itemComponent, "overrideProgress", num);
				TryRefreshUseBar(itemComponent, ReadCurrentUsesSafe(itemComponent));
			}
			catch (Exception ex)
			{
				WRN("UpdateNativeUseProgress 예외: " + ex.Message);
			}
		}

		private void RestoreNativeUseProgress(Component itemComponent, bool prevShowUseProgress, bool prevOverrideForceProgress, float prevOverrideProgress)
		{
			try
			{
				WriteMemberValue(itemComponent, "showUseProgress", prevShowUseProgress);
				WriteMemberValue(itemComponent, "overrideForceProgress", prevOverrideForceProgress);
				WriteMemberValue(itemComponent, "overrideProgress", prevOverrideProgress);
				DBG("UI-only reload progress 상태 복원");
			}
			catch (Exception ex)
			{
				WRN("RestoreNativeUseProgress 예외: " + ex.Message);
			}
		}

		private void BroadcastReloadSound(Vector3 position)
		{
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Expected O, but got Unknown
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if ((Object)(object)_reloadSoundClip == (Object)null)
				{
					WRN("장전 사운드가 아직 로드되지 않아 재생하지 못함");
					return;
				}
				if (!PhotonNetwork.InRoom)
				{
					PlayReloadSoundLocal(position);
					return;
				}
				object[] array = new object[3] { position.x, position.y, position.z };
				RaiseEventOptions val = new RaiseEventOptions
				{
					Receivers = (ReceiverGroup)1
				};
				PhotonNetwork.RaiseEvent((byte)143, (object)array, val, SendOptions.SendReliable);
			}
			catch (Exception ex)
			{
				WRN("BroadcastReloadSound 예외: " + ex.Message);
				try
				{
					PlayReloadSoundLocal(position);
				}
				catch
				{
				}
			}
		}

		private void PlayReloadSoundLocal(Vector3 position)
		{
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Expected O, but got Unknown
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if ((Object)(object)_reloadSoundClip == (Object)null)
				{
					WRN("재장전 사운드 클립이 null임");
					return;
				}
				float reloadSoundStartOffset = GetReloadSoundStartOffset();
				float num = Mathf.Max(0.01f, _reloadSoundClip.length - reloadSoundStartOffset);
				GameObject val = new GameObject("AKReloadCustomSFX");
				val.transform.position = position;
				AudioSource val2 = val.AddComponent<AudioSource>();
				val2.playOnAwake = false;
				val2.loop = false;
				val2.spatialBlend = 1f;
				val2.rolloffMode = (AudioRolloffMode)1;
				val2.minDistance = GetReloadSoundMinDistance();
				val2.maxDistance = GetReloadSoundMaxDistance();
				val2.volume = GetReloadSoundVolume();
				val2.clip = _reloadSoundClip;
				if (reloadSoundStartOffset > 0f && reloadSoundStartOffset < _reloadSoundClip.length - 0.01f)
				{
					val2.time = reloadSoundStartOffset;
				}
				val2.Play();
				Object.Destroy((Object)(object)val, num + 0.5f);
				Vector3 val3 = position;
				DBG("커스텀 장전 사운드 재생 / pos=" + ((object)(Vector3)(ref val3)).ToString() + " / offset=" + reloadSoundStartOffset);
			}
			catch (Exception ex)
			{
				WRN("PlayReloadSoundLocal 예외: " + ex.Message);
			}
		}

		private int ReadCurrentUsesSafe(Component itemComponent)
		{
			try
			{
				if (TryReadItemUses(itemComponent, out var hasData, out var value) && hasData)
				{
					return value;
				}
			}
			catch
			{
			}
			return 0;
		}

		[IteratorStateMachine(typeof(<RefillCurrentHeldAKRoutine>d__47))]
		private IEnumerator RefillCurrentHeldAKRoutine(Action<bool> done)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <RefillCurrentHeldAKRoutine>d__47(0)
			{
				<>4__this = this,
				done = done
			};
		}

		private bool TryGetHeldAK(out Component heldAK)
		{
			heldAK = null;
			try
			{
				if (!TryGetLocalCharacter(out var localCharacter) || localCharacter == null)
				{
					return false;
				}
				heldAK = GetCurrentItemComponentFromCharacter(localCharacter);
				if ((Object)(object)heldAK == (Object)null)
				{
					return false;
				}
				return IsAKItem(heldAK);
			}
			catch (Exception ex)
			{
				WRN("TryGetHeldAK 예외: " + ex.Message);
				heldAK = null;
				return false;
			}
		}

		private Type GetCharacterType()
		{
			if (_cachedCharacterType != null)
			{
				return _cachedCharacterType;
			}
			Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
			foreach (Assembly assembly in assemblies)
			{
				Type[] array;
				try
				{
					array = assembly.GetTypes();
				}
				catch (ReflectionTypeLoadException ex)
				{
					array = ex.Types.Where((Type t) => t != null).ToArray();
				}
				catch
				{
					continue;
				}
				Type[] array2 = array;
				foreach (Type type in array2)
				{
					if (type == null || type.Name != "Character")
					{
						continue;
					}
					string text = type.Namespace ?? "";
					if (!text.StartsWith("UnityEngine.TextCore.Text", StringComparison.OrdinalIgnoreCase))
					{
						BindingFlags bindingAttr = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
						if (type.GetField("localCharacter", bindingAttr) != null || type.GetProperty("localCharacter", bindingAttr) != null || type.GetField("LocalCharacter", bindingAttr) != null || type.GetProperty("LocalCharacter", bindingAttr) != null)
						{
							_cachedCharacterType = type;
							DBG("게임 Character 타입 확정 = " + (_cachedCharacterType.FullName ?? _cachedCharacterType.Name));
							return _cachedCharacterType;
						}
					}
				}
			}
			WRN("게임 Character 타입을 찾지 못함");
			return null;
		}

		private Type GetDataEntryKeyType()
		{
			if (_cachedDataEntryKeyType != null)
			{
				return _cachedDataEntryKeyType;
			}
			_cachedDataEntryKeyType = FindTypeByName("DataEntryKey");
			if (_cachedDataEntryKeyType == null)
			{
				WRN("DataEntryKey 타입을 찾지 못함");
			}
			return _cachedDataEntryKeyType;
		}

		private Type GetOptionableIntItemDataType()
		{
			if (_cachedOptionableIntItemDataType != null)
			{
				return _cachedOptionableIntItemDataType;
			}
			_cachedOptionableIntItemDataType = FindTypeByName("OptionableIntItemData");
			if (_cachedOptionableIntItemDataType == null)
			{
				WRN("OptionableIntItemData 타입을 찾지 못함");
			}
			return _cachedOptionableIntItemDataType;
		}

		private Type FindTypeByName(string typeName)
		{
			Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
			foreach (Assembly assembly in assemblies)
			{
				Type[] array;
				try
				{
					array = assembly.GetTypes();
				}
				catch (ReflectionTypeLoadException ex)
				{
					array = ex.Types.Where((Type t) => t != null).ToArray();
				}
				catch
				{
					continue;
				}
				Type[] array2 = array;
				foreach (Type type in array2)
				{
					if (type != null && type.Name == typeName)
					{
						return type;
					}
				}
			}
			return null;
		}

		private Type FindTypeByFullName(string fullName)
		{
			Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
			foreach (Assembly assembly in assemblies)
			{
				Type[] array;
				try
				{
					array = assembly.GetTypes();
				}
				catch (ReflectionTypeLoadException ex)
				{
					array = ex.Types.Where((Type t) => t != null).ToArray();
				}
				catch
				{
					continue;
				}
				Type[] array2 = array;
				foreach (Type type in array2)
				{
					if (!(type == null) && string.Equals(type.FullName, fullName, StringComparison.Ordinal))
					{
						return type;
					}
				}
			}
			return null;
		}

		private bool TryGetLocalCharacter(out object localCharacter)
		{
			localCharacter = null;
			try
			{
				Type characterType = GetCharacterType();
				if (characterType == null)
				{
					return false;
				}
				BindingFlags bindingAttr = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
				FieldInfo field = characterType.GetField("localCharacter", bindingAttr);
				if (field != null)
				{
					localCharacter = field.GetValue(null);
					if (localCharacter != null)
					{
						DBG("localCharacter 필드로 찾음");
						return true;
					}
				}
				PropertyInfo property = characterType.GetProperty("localCharacter", bindingAttr);
				if (property != null)
				{
					localCharacter = property.GetValue(null, null);
					if (localCharacter != null)
					{
						DBG("localCharacter 프로퍼티로 찾음");
						return true;
					}
				}
				field = characterType.GetField("LocalCharacter", bindingAttr);
				if (field != null)
				{
					localCharacter = field.GetValue(null);
					if (localCharacter != null)
					{
						DBG("LocalCharacter 필드로 찾음");
						return true;
					}
				}
				property = characterType.GetProperty("LocalCharacter", bindingAttr);
				if (property != null)
				{
					localCharacter = property.GetValue(null, null);
					if (localCharacter != null)
					{
						DBG("LocalCharacter 프로퍼티로 찾음");
						return true;
					}
				}
			}
			catch (Exception ex)
			{
				WRN("TryGetLocalCharacter 예외: " + ex.Message);
			}
			return false;
		}

		private Component GetCurrentItemComponentFromCharacter(object characterObj)
		{
			try
			{
				if (characterObj == null)
				{
					return null;
				}
				object memberValue = GetMemberValue(characterObj, "data");
				if (memberValue == null)
				{
					return null;
				}
				object memberValue2 = GetMemberValue(memberValue, "currentItem");
				return (Component)((memberValue2 is Component) ? memberValue2 : null);
			}
			catch (Exception ex)
			{
				WRN("GetCurrentItemComponentFromCharacter 예외: " + ex.Message);
				return null;
			}
		}

		private bool IsAKItem(Component itemComponent)
		{
			if ((Object)(object)itemComponent == (Object)null)
			{
				return false;
			}
			try
			{
				object memberValue = GetMemberValue(itemComponent, "itemID");
				if (memberValue != null)
				{
					int num = Convert.ToInt32(memberValue);
					if (num == 9351)
					{
						return true;
					}
				}
			}
			catch
			{
			}
			string text = ((Object)itemComponent).name ?? "";
			if (text.IndexOf("AK", StringComparison.OrdinalIgnoreCase) >= 0)
			{
				return true;
			}
			if (text.IndexOf("com.github.TheCodinPro.AK_Gun", StringComparison.OrdinalIgnoreCase) >= 0)
			{
				return true;
			}
			return false;
		}

		private bool TryReadItemUses(Component itemComponent, out bool hasData, out int value)
		{
			hasData = false;
			value = 0;
			try
			{
				Type type = ((object)itemComponent).GetType();
				Type keyType = GetDataEntryKeyType();
				Type optionableIntItemDataType = GetOptionableIntItemDataType();
				if (type == null || keyType == null || optionableIntItemDataType == null)
				{
					return false;
				}
				object obj = Enum.Parse(keyType, "ItemUses");
				MethodInfo methodInfo = type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault((MethodInfo m) => m.Name == "GetData" && m.IsGenericMethodDefinition && m.GetParameters().Length == 1 && m.GetParameters()[0].ParameterType == keyType);
				if (methodInfo == null)
				{
					WRN("GetData<T>(DataEntryKey) 메서드를 찾지 못함");
					return false;
				}
				MethodInfo methodInfo2 = methodInfo.MakeGenericMethod(optionableIntItemDataType);
				object obj2 = methodInfo2.Invoke(itemComponent, new object[1] { obj });
				if (obj2 == null)
				{
					return false;
				}
				hasData = ReadBoolMember(obj2, "HasData");
				value = ReadIntMember(obj2, "Value");
				return true;
			}
			catch (Exception ex)
			{
				WRN("TryReadItemUses 예외: " + ex.Message);
				return false;
			}
		}

		private bool TrySetItemUsesToMax(Component itemComponent, int totalUses)
		{
			try
			{
				Type keyType = GetDataEntryKeyType();
				Type optionableIntItemDataType = GetOptionableIntItemDataType();
				if (keyType == null || optionableIntItemDataType == null)
				{
					return false;
				}
				object obj = Enum.Parse(keyType, "ItemUses");
				object obj2 = null;
				MethodInfo methodInfo = ((object)itemComponent).GetType().GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault((MethodInfo m) => m.Name == "GetData" && m.IsGenericMethodDefinition && m.GetParameters().Length == 1 && m.GetParameters()[0].ParameterType == keyType);
				if (methodInfo != null)
				{
					MethodInfo methodInfo2 = methodInfo.MakeGenericMethod(optionableIntItemDataType);
					obj2 = methodInfo2.Invoke(itemComponent, new object[1] { obj });
				}
				if (obj2 == null)
				{
					try
					{
						obj2 = Activator.CreateInstance(optionableIntItemDataType);
					}
					catch (Exception ex)
					{
						ERR("OptionableIntItemData 인스턴스 생성 실패: " + ex.Message);
						return false;
					}
				}
				WriteMemberValue(obj2, "HasData", true);
				WriteMemberValue(obj2, "Value", totalUses);
				bool flag = false;
				object memberValue = GetMemberValue(itemComponent, "data");
				flag |= TrySetDataEntryViaDictionary(memberValue, obj, obj2);
				flag |= TryInvokePossibleSetter(memberValue, keyType, obj, optionableIntItemDataType, obj2);
				flag |= TryInvokePossibleSetter(itemComponent, keyType, obj, optionableIntItemDataType, obj2);
				if (TryReadItemUses(itemComponent, out var hasData, out var value) && hasData && value == totalUses)
				{
					DBG("ItemUses 최대치 설정 성공: " + value);
					return true;
				}
				if (!flag)
				{
					WRN("ItemUses 엔트리 쓰기 경로를 명시적으로 찾지 못함");
				}
				return TryReadItemUses(itemComponent, out hasData, out value) && hasData && value == totalUses;
			}
			catch (Exception ex2)
			{
				ERR("TrySetItemUsesToMax 예외: " + ex2);
				return false;
			}
		}

		private bool TrySetDataEntryViaDictionary(object itemDataObj, object key, object value)
		{
			try
			{
				if (itemDataObj == null)
				{
					return false;
				}
				object memberValue = GetMemberValue(itemDataObj, "data");
				if (!(memberValue is IDictionary dictionary))
				{
					return false;
				}
				if (dictionary.Contains(key))
				{
					dictionary[key] = value;
				}
				else
				{
					dictionary.Add(key, value);
				}
				return true;
			}
			catch
			{
				return false;
			}
		}

		private bool TryInvokePossibleSetter(object target, Type keyType, object itemUsesKey, Type dataType, object entryObj)
		{
			if (target == null)
			{
				return false;
			}
			string[] array = new string[5] { "SetDataEntry", "AddDataEntry", "SetData", "AddData", "Set" };
			MethodInfo[] methods = target.GetType().GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			string[] array2 = array;
			foreach (string text in array2)
			{
				MethodInfo[] array3 = methods;
				foreach (MethodInfo methodInfo in array3)
				{
					if (methodInfo.Name != text)
					{
						continue;
					}
					MethodInfo methodInfo2 = methodInfo;
					try
					{
						if (!methodInfo.IsGenericMethodDefinition)
						{
							goto IL_00d4;
						}
						Type[] genericArguments = methodInfo.GetGenericArguments();
						if (genericArguments.Length != 1)
						{
							continue;
						}
						methodInfo2 = methodInfo.MakeGenericMethod(dataType);
						goto IL_00d4;
						IL_00d4:
						ParameterInfo[] parameters = methodInfo2.GetParameters();
						if (parameters.Length == 2)
						{
							if (parameters[0].ParameterType == keyType && parameters[1].ParameterType.IsAssignableFrom(dataType))
							{
								methodInfo2.Invoke(target, new object[2] { itemUsesKey, entryObj });
								return true;
							}
							if (parameters[1].ParameterType == keyType && parameters[0].ParameterType.IsAssignableFrom(dataType))
							{
								methodInfo2.Invoke(target, new object[2] { entryObj, itemUsesKey });
								return true;
							}
						}
						if (parameters.Length == 1 && parameters[0].ParameterType.IsAssignableFrom(dataType))
						{
							methodInfo2.Invoke(target, new object[1] { entryObj });
							return true;
						}
					}
					catch
					{
					}
				}
			}
			return false;
		}

		private void TryRefreshUseBar(Component itemComponent, int currentUses)
		{
			try
			{
				int num = ReadIntMember(itemComponent, "totalUses");
				if (num > 0)
				{
					MethodInfo method = ((object)itemComponent).GetType().GetMethod("SetUseRemainingPercentage", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { typeof(float) }, null);
					if (method != null)
					{
						float num2 = Mathf.Clamp01((float)currentUses / (float)num);
						method.Invoke(itemComponent, new object[1] { num2 });
					}
				}
			}
			catch (Exception ex)
			{
				WRN("TryRefreshUseBar 예외: " + ex.Message);
			}
		}

		private bool TrySyncItemInstanceData(Component itemComponent)
		{
			try
			{
				MethodInfo method = ((object)itemComponent).GetType().GetMethod("ForceSyncForFrames", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { typeof(int) }, null);
				if (method != null)
				{
					method.Invoke(itemComponent, new object[1] { 10 });
				}
				if (!PhotonNetwork.InRoom)
				{
					DBG("Photon 룸 밖 상태. 로컬 갱신만 수행");
					return true;
				}
				PhotonView component = itemComponent.GetComponent<PhotonView>();
				if ((Object)(object)component == (Object)null)
				{
					WRN("PhotonView를 찾지 못해 동기화 스킵");
					return false;
				}
				object memberValue = GetMemberValue(itemComponent, "data");
				if (memberValue == null)
				{
					WRN("item.data가 null이라 동기화 스킵");
					return false;
				}
				component.RPC("SetItemInstanceDataRPC", (RpcTarget)1, new object[1] { memberValue });
				DBG("현재 AK ItemInstanceData 동기화 완료");
				return true;
			}
			catch (Exception ex)
			{
				WRN("TrySyncItemInstanceData 예외: " + ex.Message);
				return false;
			}
		}

		private object GetMemberValue(object target, string memberName)
		{
			if (target == null)
			{
				return null;
			}
			BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
			PropertyInfo property = target.GetType().GetProperty(memberName, bindingAttr);
			if (property != null)
			{
				return property.GetValue(target, null);
			}
			FieldInfo field = target.GetType().GetField(memberName, bindingAttr);
			if (field != null)
			{
				return field.GetValue(target);
			}
			FieldInfo field2 = target.GetType().GetField("<" + memberName + ">k__BackingField", bindingAttr);
			if (field2 != null)
			{
				return field2.GetValue(target);
			}
			return null;
		}

		private void WriteMemberValue(object target, string memberName, object value)
		{
			if (target == null)
			{
				return;
			}
			BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
			PropertyInfo property = target.GetType().GetProperty(memberName, bindingAttr);
			if (property != null)
			{
				MethodInfo setMethod = property.GetSetMethod(nonPublic: true);
				if (setMethod != null)
				{
					setMethod.Invoke(target, new object[1] { value });
					return;
				}
			}
			FieldInfo field = target.GetType().GetField(memberName, bindingAttr);
			if (field != null)
			{
				field.SetValue(target, value);
				return;
			}
			FieldInfo field2 = target.GetType().GetField("<" + memberName + ">k__BackingField", bindingAttr);
			if (field2 != null)
			{
				field2.SetValue(target, value);
			}
		}

		private bool ReadBoolMember(object target, string memberName)
		{
			object memberValue = GetMemberValue(target, memberName);
			if (memberValue == null)
			{
				return false;
			}
			try
			{
				return Convert.ToBoolean(memberValue);
			}
			catch
			{
				return false;
			}
		}

		private int ReadIntMember(object target, string memberName)
		{
			object memberValue = GetMemberValue(target, memberName);
			if (memberValue == null)
			{
				return 0;
			}
			try
			{
				return Convert.ToInt32(memberValue);
			}
			catch
			{
				return 0;
			}
		}

		private float ReadFloatMember(object target, string memberName)
		{
			object memberValue = GetMemberValue(target, memberName);
			if (memberValue == null)
			{
				return 0f;
			}
			try
			{
				return Convert.ToSingle(memberValue);
			}
			catch
			{
				return 0f;
			}
		}

		private void DBG(string msg)
		{
			if (_verboseLogging == null || _verboseLogging.Value)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)("[AKReloadDBG] " + msg));
			}
		}

		private void WRN(string msg)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)("[AKReloadDBG] " + msg));
		}

		private void ERR(string msg)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)("[AKReloadDBG] " + msg));
		}
	}
}
namespace AutoSpawn
{
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInPlugin("com.Sapphire009.AutoSpawn", "최대좀비수 및 타격횟수", "1.3.0")]
	public class Plugin : BaseUnityPlugin
	{
		[CompilerGenerated]
		private sealed class <HandleSegmentChangedRoutine>d__64 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			public Segment targetSegment;

			public Plugin <>4__this;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <HandleSegmentChangedRoutine>d__64(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_0057: Unknown result type (might be due to invalid IL or missing references)
				//IL_0061: Expected O, but got Unknown
				//IL_0085: Unknown result type (might be due to invalid IL or missing references)
				//IL_008f: Expected O, but got Unknown
				//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
				//IL_00bd: Expected O, but got Unknown
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>2__current = null;
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					<>2__current = (object)new WaitForSeconds(0.35f);
					<>1__state = 2;
					return true;
				case 2:
					<>1__state = -1;
					SyncExternalZombieCaps(forceLog: true);
					DestroyAllOwnedZombies(forceLog: true);
					<>2__current = (object)new WaitForSeconds(0.25f);
					<>1__state = 3;
					return true;
				case 3:
					<>1__state = -1;
					SyncExternalZombieCaps(forceLog: true);
					RestartPeakZombiesSpawningForCurrentSegment(forceLog: true);
					<>2__current = (object)new WaitForSeconds(0.25f);
					<>1__state = 4;
					return true;
				case 4:
					<>1__state = -1;
					SyncExternalZombieCaps(forceLog: true);
					TrimZombieCountToSegmentCap(forceLog: true);
					<>4__this._segmentTransitionRoutine = null;
					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();
			}
		}

		internal static ManualLogSource Log;

		internal static Plugin Instance;

		private Harmony _harmony;

		private static ConfigEntry<int> _해변좀비수;

		private static ConfigEntry<int> _해변모닥불좀비수;

		private static ConfigEntry<int> _열대뿌리숲좀비수;

		private static ConfigEntry<int> _메사고산지대좀비수;

		private static ConfigEntry<int> _칼데라좀비수;

		private static ConfigEntry<int> _가마좀비수;

		private static ConfigEntry<int> _정상좀비수;

		private static ConfigEntry<float> _해변좀비타격횟수;

		private static ConfigEntry<float> _해변모닥불좀비타격횟수;

		private static ConfigEntry<float> _열대뿌리숲좀비타격횟수;

		private static ConfigEntry<float> _메사고산지대좀비타격횟수;

		private static ConfigEntry<float> _칼데라좀비타격횟수;

		private static ConfigEntry<float> _가마좀비타격횟수;

		private static ConfigEntry<float> _정상좀비타격횟수;

		private static ConfigEntry<bool> _verboseLogging;

		private static FieldInfo _akCharacterGettingShotField;

		private static FieldInfo _akShotTimeField;

		private static FieldInfo _akShotDirectionField;

		private static FieldInfo _mushroomZombieAchievementTestTickField;

		private static MethodInfo _mushroomZombieDieMethod;

		private static Type _peakZombiesType;

		private static FieldInfo _peakZombiesInstanceField;

		private static FieldInfo _peakZombiesCustomMaxZombiesField;

		private static FieldInfo _peakZombiesBypassMaxZombieLimitField;

		private static FieldInfo _peakZombiesInitialSpawnCountField;

		private static FieldInfo _peakZombiesAutoSpawnIntervalField;

		private static FieldInfo _peakZombiesAutoSpawnRadiusField;

		private static MethodInfo _peakZombiesGetSpawnCenterMethod;

		private static MethodInfo _peakZombiesSpawnZombiesAroundMethod;

		private static MethodInfo _peakZombiesStartAutoSpawningMethod;

		private static MethodInfo _peakZombiesStopAutoSpawningMethod;

		private static MethodInfo _peakZombiesSpawnInitialZombiesMethod;

		private static object _lastPeakZombiesInstance;

		private static int _lastAppliedExternalCap = -1;

		private static Segment? _lastAppliedSegment = null;

		private static int _beachVisitCount = 0;

		private float _nextExternalSyncTime;

		private Segment? _lastObservedSegment;

		private Coroutine _segmentTransitionRoutine;

		private void Awake()
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Expected O, but got Unknown
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Expected O, but got Unknown
			//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c6: Expected O, but got Unknown
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			((BaseUnityPlugin)this).Config.SaveOnConfigSet = true;
			BindConfigs();
			_harmony = new Harmony("com.Sapphire009.AutoSpawn");
			try
			{
				_mushroomZombieAchievementTestTickField = AccessTools.Field(typeof(MushroomZombie), "achievementTestTick");
				_mushroomZombieDieMethod = AccessTools.Method(typeof(MushroomZombie), "Die", (Type[])null, (Type[])null);
				if (_mushroomZombieAchievementTestTickField != null)
				{
					Log.LogInfo((object)"Found MushroomZombie.achievementTestTick");
				}
				else
				{
					Log.LogWarning((object)"Could not find MushroomZombie.achievementTestTick");
				}
				if (_mushroomZombieDieMethod != null)
				{
					Log.LogInfo((object)"Found MushroomZombie.Die()");
				}
				else
				{
					Log.LogWarning((object)"Could not find MushroomZombie.Die()");
				}
				CachePeakZombiesReflection();
				MethodInfo methodInfo = AccessTools.Method(typeof(MushroomZombieSpawner), "Spawn", (Type[])null, (Type[])null);
				if (methodInfo != null)
				{
					_harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(Plugin), "MushroomZombieSpawner_Spawn_Prefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
					Log.LogInfo((object)"Patched MushroomZombieSpawner.Spawn");
				}
				else
				{
					Log.LogWarning((object)"Could not find MushroomZombieSpawner.Spawn");
				}
				MethodInfo methodInfo2 = AccessTools.Method(typeof(MapHandler), "JumpToSegmentLogic", new Type[4]
				{
					typeof(Segment),
					typeof(HashSet<int>),
					typeof(bool),
					typeof(bool)
				}, (Type[])null);
				if (methodInfo2 != null)
				{
					_harmony.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, new HarmonyMethod(typeof(Plugin), "MapHandler_JumpToSegmentLogic_Postfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
					Log.LogInfo((object)"Patched MapHandler.JumpToSegmentLogic");
				}
				else
				{
					Log.LogWarning((object)"Could not find MapHandler.JumpToSegmentLogic");
				}
				PatchExternalMethod("Zombies_Anywhere.ZombiesAnywhereMod", "SpawnZombieAt", new Type[3]
				{
					typeof(Vector3),
					typeof(Quaternion),
					typeof(MushroomZombie)
				}, "PeakZombies_SpawnZombieAt_Prefix");
				PatchExternalMethod("Zombies_Anywhere.ZombiesAnywhereMod", "SpawnZombiesAround", new Type[3]
				{
					typeof(Vector3),
					typeof(float),
					typeof(int)
				}, "PeakZombies_SpawnZombiesAround_Prefix");
				PatchExternalMethod("Zombies_Anywhere.ZombiesAnywhereMod", "SpawnInitialZombies", Type.EmptyTypes, "PeakZombies_SpawnInitialZombies_Prefix");
				PatchExternalMethod("AK_Gun.GunCharacterLaunch", "RPC_ShootSelfT", new Type[3]
				{
					typeof(float),
					typeof(int),
					typeof(Vector3)
				}, "AKGun_RPC_ShootSelfT_Prefix");
				Log.LogInfo((object)"========================================");
				Log.LogInfo((object)"Segment Zombie Rules loaded");
				Log.LogInfo((object)"Config-driven zombie cap enabled");
				Log.LogInfo((object)"Fixed hit progression enabled");
				Log.LogInfo((object)"Map transition zombie resync enabled");
				Log.LogInfo((object)"PEAK_Zombies auto-spawn restart on segment change enabled");
				LogCurrentConfigValues();
				Log.LogInfo((object)"========================================");
			}
			catch (Exception ex)
			{
				Log.LogError((object)("Plugin Awake exception: " + ex));
			}
		}

		private void Update()
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (!PhotonNetwork.IsMasterClient)
				{
					return;
				}
				if (MapHandler.Exists)
				{
					Segment currentSegmentNumber = MapHandler.CurrentSegmentNumber;
					if (!_lastObservedSegment.HasValue)
					{
						_lastObservedSegment = currentSegmentNumber;
					}
					else if (_lastObservedSegment.Value != currentSegmentNumber)
					{
						_lastObservedSegment = currentSegmentNumber;
						HandleSegmentChanged(currentSegmentNumber, "UpdateFallback");
					}
				}
				if (!(Time.time < _nextExternalSyncTime))
				{
					_nextExternalSyncTime = Time.time + 0.5f;
					SyncExternalZombieCaps(forceLog: false);
					TrimZombieCountToSegmentCap(forceLog: false);
				}
			}
			catch (Exception ex)
			{
				Log.LogError((object)("Plugin Update exception: " + ex));
			}
		}

		private void OnDestroy()
		{
			try
			{
				if (_segmentTransitionRoutine != null)
				{
					((MonoBehaviour)this).StopCoroutine(_segmentTransitionRoutine);
					_segmentTransitionRoutine = null;
				}
				Harmony harmony = _harmony;
				if (harmony != null)
				{
					harmony.UnpatchSelf();
				}
			}
			catch (Exception ex)
			{
				Log.LogError((object)("Plugin OnDestroy exception: " + ex));
			}
		}

		private void BindConfigs()
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Expected O, but got Unknown
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Expected O, but got Unknown
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Expected O, but got Unknown
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Expected O, but got Unknown
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Expected O, but got Unknown
			//IL_0133: Unknown result type (might be due to invalid IL or missing references)
			//IL_013d: Expected O, but got Unknown
			//IL_0169: Unknown result type (might be due to invalid IL or missing references)
			//IL_0173: Expected O, but got Unknown
			//IL_01a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b0: Expected O, but got Unknown
			//IL_01e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ed: Expected O, but got Unknown
			//IL_0220: Unknown result type (might be due to invalid IL or missing references)
			//IL_022a: Expected O, but got Unknown
			//IL_025d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0267: Expected O, but got Unknown
			//IL_029a: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a4: Expected O, but got Unknown
			//IL_02d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e1: Expected O, but got Unknown
			//IL_0314: Unknown result type (might be due to invalid IL or missing references)
			//IL_031e: Expected O, but got Unknown
			_해변좀비수 = ((BaseUnityPlugin)this).Config.Bind<int>("좀비 수 제한", "해변 좀비 수", 3, new ConfigDescription("해변 세그먼트 최대 좀비 수", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 200), Array.Empty<object>()));
			_해변모닥불좀비수 = ((BaseUnityPlugin)this).Config.Bind<int>("좀비 수 제한", "해변 모닥불 좀비 수", 5, new ConfigDescription("해변 모닥불 구간 최대 좀비 수", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 200), Array.Empty<object>()));
			_열대뿌리숲좀비수 = ((BaseUnityPlugin)this).Config.Bind<int>("좀비 수 제한", "열대뿌리숲 좀비 수", 7, new ConfigDescription("열대뿌리숲 세그먼트 최대 좀비 수", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 200), Array.Empty<object>()));
			_메사고산지대좀비수 = ((BaseUnityPlugin)this).Config.Bind<int>("좀비 수 제한", "메사고산지대 좀비 수", 9, new ConfigDescription("메사고산지대 세그먼트 최대 좀비 수", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 200), Array.Empty<object>()));
			_칼데라좀비수 = ((BaseUnityPlugin)this).Config.Bind<int>("좀비 수 제한", "칼데라 좀비 수", 11, new ConfigDescription("칼데라 세그먼트 최대 좀비 수", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 200), Array.Empty<object>()));
			_가마좀비수 = ((BaseUnityPlugin)this).Config.Bind<int>("좀비 수 제한", "가마 좀비 수", 13, new ConfigDescription("가마 세그먼트 최대 좀비 수", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 200), Array.Empty<object>()));
			_정상좀비수 = ((BaseUnityPlugin)this).Config.Bind<int>("좀비 수 제한", "정상 좀비 수", 15, new ConfigDescription("정상 세그먼트 최대 좀비 수", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 200), Array.Empty<object>()));
			_해변좀비타격횟수 = ((BaseUnityPlugin)this).Config.Bind<float>("좀비 타격 횟수", "해변 좀비 타격 횟수", 5f, new ConfigDescription("해변 첫 방문 시 좀비 처치까지 필요한 타격 횟수", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 200f), Array.Empty<object>()));
			_해변모닥불좀비타격횟수 = ((BaseUnityPlugin)this).Config.Bind<float>("좀비 타격 횟수", "해변 모닥불 좀비 타격 횟수", 8f, new ConfigDescription("해변 모닥불 구간 좀비 처치까지 필요한 타격 횟수", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 200f), Array.Empty<object>()));
			_열대뿌리숲좀비타격횟수 = ((BaseUnityPlugin)this).Config.Bind<float>("좀비 타격 횟수", "열대뿌리숲 좀비 타격 횟수", 10f, new ConfigDescription("열대뿌리숲 좀비 처치까지 필요한 타격 횟수", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 200f), Array.Empty<object>()));
			_메사고산지대좀비타격횟수 = ((BaseUnityPlugin)this).Config.Bind<float>("좀비 타격 횟수", "메사고산지대 좀비 타격 횟수", 13f, new ConfigDescription("메사고산지대 좀비 처치까지 필요한 타격 횟수", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 200f), Array.Empty<object>()));
			_칼데라좀비타격횟수 = ((BaseUnityPlugin)this).Config.Bind<float>("좀비 타격 횟수", "칼데라 좀비 타격 횟수", 15f, new ConfigDescription("칼데라 좀비 처치까지 필요한 타격 횟수", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 200f), Array.Empty<object>()));
			_가마좀비타격횟수 = ((BaseUnityPlugin)this).Config.Bind<float>("좀비 타격 횟수", "가마 좀비 타격 횟수", 18f, new ConfigDescription("가마 좀비 처치까지 필요한 타격 횟수", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 200f), Array.Empty<object>()));
			_정상좀비타격횟수 = ((BaseUnityPlugin)this).Config.Bind<float>("좀비 타격 횟수", "정상 좀비 타격 횟수", 20f, new ConfigDescription("정상 좀비 처치까지 필요한 타격 횟수", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 200f), Array.Empty<object>()));
		}

		private static void LogCurrentConfigValues()
		{
			Log.LogInfo((object)"Zombie max by segment:");
			Log.LogInfo((object)$"Beach={ReadMaxZombieValue(_해변좀비수, 3)}, BeachCampfire={ReadMaxZombieValue(_해변모닥불좀비수, 5)}, Tropics={ReadMaxZombieValue(_열대뿌리숲좀비수, 7)}, Alpine={ReadMaxZombieValue(_메사고산지대좀비수, 9)}, Caldera={ReadMaxZombieValue(_칼데라좀비수, 11)}, TheKiln={ReadMaxZombieValue(_가마좀비수, 13)}, Peak={ReadMaxZombieValue(_정상좀비수, 15)}");
			Log.LogInfo((object)$"Hits-to-kill: Beach={ReadHitsValue(_해변좀비타격횟수, 5f)}, BeachCampfire={ReadHitsValue(_해변모닥불좀비타격횟수, 8f)}, Tropics={ReadHitsValue(_열대뿌리숲좀비타격횟수, 1f)}, Alpine={ReadHitsValue(_메사고산지대좀비타격횟수, 13f)}, Caldera={ReadHitsValue(_칼데라좀비타격횟수, 15f)}, TheKiln={ReadHitsValue(_가마좀비타격횟수, 18f)}, Peak={ReadHitsValue(_정상좀비타격횟수, 20f)}");
		}

		private void PatchExternalMethod(string typeName, string methodName, Type[] argTypes, string prefixMethodName)
		{
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Expected O, but got Unknown
			try
			{
				Type type = AccessTools.TypeByName(typeName);
				if (type == null)
				{
					Log.LogWarning((object)("Type not found: " + typeName));
					return;
				}
				MethodInfo methodInfo = AccessTools.Method(type, methodName, argTypes, (Type[])null);
				if (methodInfo == null)
				{
					Log.LogWarning((object)("Method not found: " + typeName + "." + methodName));
					return;
				}
				MethodInfo methodInfo2 = AccessTools.Method(typeof(Plugin), prefixMethodName, (Type[])null, (Type[])null);
				if (methodInfo2 == null)
				{
					Log.LogWarning((object)("Prefix method not found: " + prefixMethodName));
					return;
				}
				_harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				Log.LogInfo((object)("Patched " + typeName + "." + methodName));
			}
			catch (Exception ex)
			{
				Log.LogError((object)("PatchExternalMethod exception for " + typeName + "." + methodName + ": " + ex));
			}
		}

		private static void CachePeakZombiesReflection()
		{
			try
			{
				_peakZombiesType = AccessTools.TypeByName("Zombies_Anywhere.ZombiesAnywhereMod");
				if (_peakZombiesType == null)
				{
					Log.LogWarning((object)"PEAK_Zombies type not found: Zombies_Anywhere.ZombiesAnywhereMod");
					return;
				}
				_peakZombiesInstanceField = AccessTools.Field(_peakZombiesType, "_instance");
				_peakZombiesCustomMaxZombiesField = AccessTools.Field(_peakZombiesType, "customMaxZombies");
				_peakZombiesBypassMaxZombieLimitField = AccessTools.Field(_peakZombiesType, "bypassMaxZombieLimit");
				_peakZombiesInitialSpawnCountField = AccessTools.Field(_peakZombiesType, "initialSpawnCount");
				_peakZombiesAutoSpawnIntervalField = AccessTools.Field(_peakZombiesType, "autoSpawnInterval");
				_peakZombiesAutoSpawnRadiusField = AccessTools.Field(_peakZombiesType, "autoSpawnRadius");
				_peakZombiesGetSpawnCenterMethod = AccessTools.Method(_peakZombiesType, "GetSpawnCenter", Type.EmptyTypes, (Type[])null);
				_peakZombiesSpawnZombiesAroundMethod = AccessTools.Method(_peakZombiesType, "SpawnZombiesAround", new Type[3]
				{
					typeof(Vector3),
					typeof(float),
					typeof(int)
				}, (Type[])null);
				_peakZombiesStartAutoSpawningMethod = AccessTools.Method(_peakZombiesType, "StartAutoSpawning", new Type[2]
				{
					typeof(float),
					typeof(float)
				}, (Type[])null);
				_peakZombiesStopAutoSpawningMethod = AccessTools.Method(_peakZombiesType, "StopAutoSpawning", Type.EmptyTypes, (Type[])null);
				_peakZombiesSpawnInitialZombiesMethod = AccessTools.Method(_peakZombiesType, "SpawnInitialZombies", Type.EmptyTypes, (Type[])null);
			}
			catch (Exception ex)
			{
				Log.LogError((object)("CachePeakZombiesReflection exception: " + ex));
			}
		}

		private static bool IsBeachCampfirePhase()
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Invalid comparison between Unknown and I4
			if (!MapHandler.Exists || (int)MapHandler.CurrentSegmentNumber > 0)
			{
				re